dijit-all.js.uncompressed.js 1.1 MB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680186811868218683186841868518686186871868818689186901869118692186931869418695186961869718698186991870018701187021870318704187051870618707187081870918710187111871218713187141871518716187171871818719187201872118722187231872418725187261872718728187291873018731187321873318734187351873618737187381873918740187411874218743187441874518746187471874818749187501875118752187531875418755187561875718758187591876018761187621876318764187651876618767187681876918770187711877218773187741877518776187771877818779187801878118782187831878418785187861878718788187891879018791187921879318794187951879618797187981879918800188011880218803188041880518806188071880818809188101881118812188131881418815188161881718818188191882018821188221882318824188251882618827188281882918830188311883218833188341883518836188371883818839188401884118842188431884418845188461884718848188491885018851188521885318854188551885618857188581885918860188611886218863188641886518866188671886818869188701887118872188731887418875188761887718878188791888018881188821888318884188851888618887188881888918890188911889218893188941889518896188971889818899189001890118902189031890418905189061890718908189091891018911189121891318914189151891618917189181891918920189211892218923189241892518926189271892818929189301893118932189331893418935189361893718938189391894018941189421894318944189451894618947189481894918950189511895218953189541895518956189571895818959189601896118962189631896418965189661896718968189691897018971189721897318974189751897618977189781897918980189811898218983189841898518986189871898818989189901899118992189931899418995189961899718998189991900019001190021900319004190051900619007190081900919010190111901219013190141901519016190171901819019190201902119022190231902419025190261902719028190291903019031190321903319034190351903619037190381903919040190411904219043190441904519046190471904819049190501905119052190531905419055190561905719058190591906019061190621906319064190651906619067190681906919070190711907219073190741907519076190771907819079190801908119082190831908419085190861908719088190891909019091190921909319094190951909619097190981909919100191011910219103191041910519106191071910819109191101911119112191131911419115191161911719118191191912019121191221912319124191251912619127191281912919130191311913219133191341913519136191371913819139191401914119142191431914419145191461914719148191491915019151191521915319154191551915619157191581915919160191611916219163191641916519166191671916819169191701917119172191731917419175191761917719178191791918019181191821918319184191851918619187191881918919190191911919219193191941919519196191971919819199192001920119202192031920419205192061920719208192091921019211192121921319214192151921619217192181921919220192211922219223192241922519226192271922819229192301923119232192331923419235192361923719238192391924019241192421924319244192451924619247192481924919250192511925219253192541925519256192571925819259192601926119262192631926419265192661926719268192691927019271192721927319274192751927619277192781927919280192811928219283192841928519286192871928819289192901929119292192931929419295192961929719298192991930019301193021930319304193051930619307193081930919310193111931219313193141931519316193171931819319193201932119322193231932419325193261932719328193291933019331193321933319334193351933619337193381933919340193411934219343193441934519346193471934819349193501935119352193531935419355193561935719358193591936019361193621936319364193651936619367193681936919370193711937219373193741937519376193771937819379193801938119382193831938419385193861938719388193891939019391193921939319394193951939619397193981939919400194011940219403194041940519406194071940819409194101941119412194131941419415194161941719418194191942019421194221942319424194251942619427194281942919430194311943219433194341943519436194371943819439194401944119442194431944419445194461944719448194491945019451194521945319454194551945619457194581945919460194611946219463194641946519466194671946819469194701947119472194731947419475194761947719478194791948019481194821948319484194851948619487194881948919490194911949219493194941949519496194971949819499195001950119502195031950419505195061950719508195091951019511195121951319514195151951619517195181951919520195211952219523195241952519526195271952819529195301953119532195331953419535195361953719538195391954019541195421954319544195451954619547195481954919550195511955219553195541955519556195571955819559195601956119562195631956419565195661956719568195691957019571195721957319574195751957619577195781957919580195811958219583195841958519586195871958819589195901959119592195931959419595195961959719598195991960019601196021960319604196051960619607196081960919610196111961219613196141961519616196171961819619196201962119622196231962419625196261962719628196291963019631196321963319634196351963619637196381963919640196411964219643196441964519646196471964819649196501965119652196531965419655196561965719658196591966019661196621966319664196651966619667196681966919670196711967219673196741967519676196771967819679196801968119682196831968419685196861968719688196891969019691196921969319694196951969619697196981969919700197011970219703197041970519706197071970819709197101971119712197131971419715197161971719718197191972019721197221972319724197251972619727197281972919730197311973219733197341973519736197371973819739197401974119742197431974419745197461974719748197491975019751197521975319754197551975619757197581975919760197611976219763197641976519766197671976819769197701977119772197731977419775197761977719778197791978019781197821978319784197851978619787197881978919790197911979219793197941979519796197971979819799198001980119802198031980419805198061980719808198091981019811198121981319814198151981619817198181981919820198211982219823198241982519826198271982819829198301983119832198331983419835198361983719838198391984019841198421984319844198451984619847198481984919850198511985219853198541985519856198571985819859198601986119862198631986419865198661986719868198691987019871198721987319874198751987619877198781987919880198811988219883198841988519886198871988819889198901989119892198931989419895198961989719898198991990019901199021990319904199051990619907199081990919910199111991219913199141991519916199171991819919199201992119922199231992419925199261992719928199291993019931199321993319934199351993619937199381993919940199411994219943199441994519946199471994819949199501995119952199531995419955199561995719958199591996019961199621996319964199651996619967199681996919970199711997219973199741997519976199771997819979199801998119982199831998419985199861998719988199891999019991199921999319994199951999619997199981999920000200012000220003200042000520006200072000820009200102001120012200132001420015200162001720018200192002020021200222002320024200252002620027200282002920030200312003220033200342003520036200372003820039200402004120042200432004420045200462004720048200492005020051200522005320054200552005620057200582005920060200612006220063200642006520066200672006820069200702007120072200732007420075200762007720078200792008020081200822008320084200852008620087200882008920090200912009220093200942009520096200972009820099201002010120102201032010420105201062010720108201092011020111201122011320114201152011620117201182011920120201212012220123201242012520126201272012820129201302013120132201332013420135201362013720138201392014020141201422014320144201452014620147201482014920150201512015220153201542015520156201572015820159201602016120162201632016420165201662016720168201692017020171201722017320174201752017620177201782017920180201812018220183201842018520186201872018820189201902019120192201932019420195201962019720198201992020020201202022020320204202052020620207202082020920210202112021220213202142021520216202172021820219202202022120222202232022420225202262022720228202292023020231202322023320234202352023620237202382023920240202412024220243202442024520246202472024820249202502025120252202532025420255202562025720258202592026020261202622026320264202652026620267202682026920270202712027220273202742027520276202772027820279202802028120282202832028420285202862028720288202892029020291202922029320294202952029620297202982029920300203012030220303203042030520306203072030820309203102031120312203132031420315203162031720318203192032020321203222032320324203252032620327203282032920330203312033220333203342033520336203372033820339203402034120342203432034420345203462034720348203492035020351203522035320354203552035620357203582035920360203612036220363203642036520366203672036820369203702037120372203732037420375203762037720378203792038020381203822038320384203852038620387203882038920390203912039220393203942039520396203972039820399204002040120402204032040420405204062040720408204092041020411204122041320414204152041620417204182041920420204212042220423204242042520426204272042820429204302043120432204332043420435204362043720438204392044020441204422044320444204452044620447204482044920450204512045220453204542045520456204572045820459204602046120462204632046420465204662046720468204692047020471204722047320474204752047620477204782047920480204812048220483204842048520486204872048820489204902049120492204932049420495204962049720498204992050020501205022050320504205052050620507205082050920510205112051220513205142051520516205172051820519205202052120522205232052420525205262052720528205292053020531205322053320534205352053620537205382053920540205412054220543205442054520546205472054820549205502055120552205532055420555205562055720558205592056020561205622056320564205652056620567205682056920570205712057220573205742057520576205772057820579205802058120582205832058420585205862058720588205892059020591205922059320594205952059620597205982059920600206012060220603206042060520606206072060820609206102061120612206132061420615206162061720618206192062020621206222062320624206252062620627206282062920630206312063220633206342063520636206372063820639206402064120642206432064420645206462064720648206492065020651206522065320654206552065620657206582065920660206612066220663206642066520666206672066820669206702067120672206732067420675206762067720678206792068020681206822068320684206852068620687206882068920690206912069220693206942069520696206972069820699207002070120702207032070420705207062070720708207092071020711207122071320714207152071620717207182071920720207212072220723207242072520726207272072820729207302073120732207332073420735207362073720738207392074020741207422074320744207452074620747207482074920750207512075220753207542075520756207572075820759207602076120762207632076420765207662076720768207692077020771207722077320774207752077620777207782077920780207812078220783207842078520786207872078820789207902079120792207932079420795207962079720798207992080020801208022080320804208052080620807208082080920810208112081220813208142081520816208172081820819208202082120822208232082420825208262082720828208292083020831208322083320834208352083620837208382083920840208412084220843208442084520846208472084820849208502085120852208532085420855208562085720858208592086020861208622086320864208652086620867208682086920870208712087220873208742087520876208772087820879208802088120882208832088420885208862088720888208892089020891208922089320894208952089620897208982089920900209012090220903209042090520906209072090820909209102091120912209132091420915209162091720918209192092020921209222092320924209252092620927209282092920930209312093220933209342093520936209372093820939209402094120942209432094420945209462094720948209492095020951209522095320954209552095620957209582095920960209612096220963209642096520966209672096820969209702097120972209732097420975209762097720978209792098020981209822098320984209852098620987209882098920990209912099220993209942099520996209972099820999210002100121002210032100421005210062100721008210092101021011210122101321014210152101621017210182101921020210212102221023210242102521026210272102821029210302103121032210332103421035210362103721038210392104021041210422104321044210452104621047210482104921050210512105221053210542105521056210572105821059210602106121062210632106421065210662106721068210692107021071210722107321074210752107621077210782107921080210812108221083210842108521086210872108821089210902109121092210932109421095210962109721098210992110021101211022110321104211052110621107211082110921110211112111221113211142111521116211172111821119211202112121122211232112421125211262112721128211292113021131211322113321134211352113621137211382113921140211412114221143211442114521146211472114821149211502115121152211532115421155211562115721158211592116021161211622116321164211652116621167211682116921170211712117221173211742117521176211772117821179211802118121182211832118421185211862118721188211892119021191211922119321194211952119621197211982119921200212012120221203212042120521206212072120821209212102121121212212132121421215212162121721218212192122021221212222122321224212252122621227212282122921230212312123221233212342123521236212372123821239212402124121242212432124421245212462124721248212492125021251212522125321254212552125621257212582125921260212612126221263212642126521266212672126821269212702127121272212732127421275212762127721278212792128021281212822128321284212852128621287212882128921290212912129221293212942129521296212972129821299213002130121302213032130421305213062130721308213092131021311213122131321314213152131621317213182131921320213212132221323213242132521326213272132821329213302133121332213332133421335213362133721338213392134021341213422134321344213452134621347213482134921350213512135221353213542135521356213572135821359213602136121362213632136421365213662136721368213692137021371213722137321374213752137621377213782137921380213812138221383213842138521386213872138821389213902139121392213932139421395213962139721398213992140021401214022140321404214052140621407214082140921410214112141221413214142141521416214172141821419214202142121422214232142421425214262142721428214292143021431214322143321434214352143621437214382143921440214412144221443214442144521446214472144821449214502145121452214532145421455214562145721458214592146021461214622146321464214652146621467214682146921470214712147221473214742147521476214772147821479214802148121482214832148421485214862148721488214892149021491214922149321494214952149621497214982149921500215012150221503215042150521506215072150821509215102151121512215132151421515215162151721518215192152021521215222152321524215252152621527215282152921530215312153221533215342153521536215372153821539215402154121542215432154421545215462154721548215492155021551215522155321554215552155621557215582155921560215612156221563215642156521566215672156821569215702157121572215732157421575215762157721578215792158021581215822158321584215852158621587215882158921590215912159221593215942159521596215972159821599216002160121602216032160421605216062160721608216092161021611216122161321614216152161621617216182161921620216212162221623216242162521626216272162821629216302163121632216332163421635216362163721638216392164021641216422164321644216452164621647216482164921650216512165221653216542165521656216572165821659216602166121662216632166421665216662166721668216692167021671216722167321674216752167621677216782167921680216812168221683216842168521686216872168821689216902169121692216932169421695216962169721698216992170021701217022170321704217052170621707217082170921710217112171221713217142171521716217172171821719217202172121722217232172421725217262172721728217292173021731217322173321734217352173621737217382173921740217412174221743217442174521746217472174821749217502175121752217532175421755217562175721758217592176021761217622176321764217652176621767217682176921770217712177221773217742177521776217772177821779217802178121782217832178421785217862178721788217892179021791217922179321794217952179621797217982179921800218012180221803218042180521806218072180821809218102181121812218132181421815218162181721818218192182021821218222182321824218252182621827218282182921830218312183221833218342183521836218372183821839218402184121842218432184421845218462184721848218492185021851218522185321854218552185621857218582185921860218612186221863218642186521866218672186821869218702187121872218732187421875218762187721878218792188021881218822188321884218852188621887218882188921890218912189221893218942189521896218972189821899219002190121902219032190421905219062190721908219092191021911219122191321914219152191621917219182191921920219212192221923219242192521926219272192821929219302193121932219332193421935219362193721938219392194021941219422194321944219452194621947219482194921950219512195221953219542195521956219572195821959219602196121962219632196421965219662196721968219692197021971219722197321974219752197621977219782197921980219812198221983219842198521986219872198821989219902199121992219932199421995219962199721998219992200022001220022200322004220052200622007220082200922010220112201222013220142201522016220172201822019220202202122022220232202422025220262202722028220292203022031220322203322034220352203622037220382203922040220412204222043220442204522046220472204822049220502205122052220532205422055220562205722058220592206022061220622206322064220652206622067220682206922070220712207222073220742207522076220772207822079220802208122082220832208422085220862208722088220892209022091220922209322094220952209622097220982209922100221012210222103221042210522106221072210822109221102211122112221132211422115221162211722118221192212022121221222212322124221252212622127221282212922130221312213222133221342213522136221372213822139221402214122142221432214422145221462214722148221492215022151221522215322154221552215622157221582215922160221612216222163221642216522166221672216822169221702217122172221732217422175221762217722178221792218022181221822218322184221852218622187221882218922190221912219222193221942219522196221972219822199222002220122202222032220422205222062220722208222092221022211222122221322214222152221622217222182221922220222212222222223222242222522226222272222822229222302223122232222332223422235222362223722238222392224022241222422224322244222452224622247222482224922250222512225222253222542225522256222572225822259222602226122262222632226422265222662226722268222692227022271222722227322274222752227622277222782227922280222812228222283222842228522286222872228822289222902229122292222932229422295222962229722298222992230022301223022230322304223052230622307223082230922310223112231222313223142231522316223172231822319223202232122322223232232422325223262232722328223292233022331223322233322334223352233622337223382233922340223412234222343223442234522346223472234822349223502235122352223532235422355223562235722358223592236022361223622236322364223652236622367223682236922370223712237222373223742237522376223772237822379223802238122382223832238422385223862238722388223892239022391223922239322394223952239622397223982239922400224012240222403224042240522406224072240822409224102241122412224132241422415224162241722418224192242022421224222242322424224252242622427224282242922430224312243222433224342243522436224372243822439224402244122442224432244422445224462244722448224492245022451224522245322454224552245622457224582245922460224612246222463224642246522466224672246822469224702247122472224732247422475224762247722478224792248022481224822248322484224852248622487224882248922490224912249222493224942249522496224972249822499225002250122502225032250422505225062250722508225092251022511225122251322514225152251622517225182251922520225212252222523225242252522526225272252822529225302253122532225332253422535225362253722538225392254022541225422254322544225452254622547225482254922550225512255222553225542255522556225572255822559225602256122562225632256422565225662256722568225692257022571225722257322574225752257622577225782257922580225812258222583225842258522586225872258822589225902259122592225932259422595225962259722598225992260022601226022260322604226052260622607226082260922610226112261222613226142261522616226172261822619226202262122622226232262422625226262262722628226292263022631226322263322634226352263622637226382263922640226412264222643226442264522646226472264822649226502265122652226532265422655226562265722658226592266022661226622266322664226652266622667226682266922670226712267222673226742267522676226772267822679226802268122682226832268422685226862268722688226892269022691226922269322694226952269622697226982269922700227012270222703227042270522706227072270822709227102271122712227132271422715227162271722718227192272022721227222272322724227252272622727227282272922730227312273222733227342273522736227372273822739227402274122742227432274422745227462274722748227492275022751227522275322754227552275622757227582275922760227612276222763227642276522766227672276822769227702277122772227732277422775227762277722778227792278022781227822278322784227852278622787227882278922790227912279222793227942279522796227972279822799228002280122802228032280422805228062280722808228092281022811228122281322814228152281622817228182281922820228212282222823228242282522826228272282822829228302283122832228332283422835228362283722838228392284022841228422284322844228452284622847228482284922850228512285222853228542285522856228572285822859228602286122862228632286422865228662286722868228692287022871228722287322874228752287622877228782287922880228812288222883228842288522886228872288822889228902289122892228932289422895228962289722898228992290022901229022290322904229052290622907229082290922910229112291222913229142291522916229172291822919229202292122922229232292422925229262292722928229292293022931229322293322934229352293622937229382293922940229412294222943229442294522946229472294822949229502295122952229532295422955229562295722958229592296022961229622296322964229652296622967229682296922970229712297222973229742297522976229772297822979229802298122982229832298422985229862298722988229892299022991229922299322994229952299622997229982299923000230012300223003230042300523006230072300823009230102301123012230132301423015230162301723018230192302023021230222302323024230252302623027230282302923030230312303223033230342303523036230372303823039230402304123042230432304423045230462304723048230492305023051230522305323054230552305623057230582305923060230612306223063230642306523066230672306823069230702307123072230732307423075230762307723078230792308023081230822308323084230852308623087230882308923090230912309223093230942309523096230972309823099231002310123102231032310423105231062310723108231092311023111231122311323114231152311623117231182311923120231212312223123231242312523126231272312823129231302313123132231332313423135231362313723138231392314023141231422314323144231452314623147231482314923150231512315223153231542315523156231572315823159231602316123162231632316423165231662316723168231692317023171231722317323174231752317623177231782317923180231812318223183231842318523186231872318823189231902319123192231932319423195231962319723198231992320023201232022320323204232052320623207232082320923210232112321223213232142321523216232172321823219232202322123222232232322423225232262322723228232292323023231232322323323234232352323623237232382323923240232412324223243232442324523246232472324823249232502325123252232532325423255232562325723258232592326023261232622326323264232652326623267232682326923270232712327223273232742327523276232772327823279232802328123282232832328423285232862328723288232892329023291232922329323294232952329623297232982329923300233012330223303233042330523306233072330823309233102331123312233132331423315233162331723318233192332023321233222332323324233252332623327233282332923330233312333223333233342333523336233372333823339233402334123342233432334423345233462334723348233492335023351233522335323354233552335623357233582335923360233612336223363233642336523366233672336823369233702337123372233732337423375233762337723378233792338023381233822338323384233852338623387233882338923390233912339223393233942339523396233972339823399234002340123402234032340423405234062340723408234092341023411234122341323414234152341623417234182341923420234212342223423234242342523426234272342823429234302343123432234332343423435234362343723438234392344023441234422344323444234452344623447234482344923450234512345223453234542345523456234572345823459234602346123462234632346423465234662346723468234692347023471234722347323474234752347623477234782347923480234812348223483234842348523486234872348823489234902349123492234932349423495234962349723498234992350023501235022350323504235052350623507235082350923510235112351223513235142351523516235172351823519235202352123522235232352423525235262352723528235292353023531235322353323534235352353623537235382353923540235412354223543235442354523546235472354823549235502355123552235532355423555235562355723558235592356023561235622356323564235652356623567235682356923570235712357223573235742357523576235772357823579235802358123582235832358423585235862358723588235892359023591235922359323594235952359623597235982359923600236012360223603236042360523606236072360823609236102361123612236132361423615236162361723618236192362023621236222362323624236252362623627236282362923630236312363223633236342363523636236372363823639236402364123642236432364423645236462364723648236492365023651236522365323654236552365623657236582365923660236612366223663236642366523666236672366823669236702367123672236732367423675236762367723678236792368023681236822368323684236852368623687236882368923690236912369223693236942369523696236972369823699237002370123702237032370423705237062370723708237092371023711237122371323714237152371623717237182371923720237212372223723237242372523726237272372823729237302373123732237332373423735237362373723738237392374023741237422374323744237452374623747237482374923750237512375223753237542375523756237572375823759237602376123762237632376423765237662376723768237692377023771237722377323774237752377623777237782377923780237812378223783237842378523786237872378823789237902379123792237932379423795237962379723798237992380023801238022380323804238052380623807238082380923810238112381223813238142381523816238172381823819238202382123822238232382423825238262382723828238292383023831238322383323834238352383623837238382383923840238412384223843238442384523846238472384823849238502385123852238532385423855238562385723858238592386023861238622386323864238652386623867238682386923870238712387223873238742387523876238772387823879238802388123882238832388423885238862388723888238892389023891238922389323894238952389623897238982389923900239012390223903239042390523906239072390823909239102391123912239132391423915239162391723918239192392023921239222392323924239252392623927239282392923930239312393223933239342393523936239372393823939239402394123942239432394423945239462394723948239492395023951239522395323954239552395623957239582395923960239612396223963239642396523966239672396823969239702397123972239732397423975239762397723978239792398023981239822398323984239852398623987239882398923990239912399223993239942399523996239972399823999240002400124002240032400424005240062400724008240092401024011240122401324014240152401624017240182401924020240212402224023240242402524026240272402824029240302403124032240332403424035240362403724038240392404024041240422404324044240452404624047240482404924050240512405224053240542405524056240572405824059240602406124062240632406424065240662406724068240692407024071240722407324074240752407624077240782407924080240812408224083240842408524086240872408824089240902409124092240932409424095240962409724098240992410024101241022410324104241052410624107241082410924110241112411224113241142411524116241172411824119241202412124122241232412424125241262412724128241292413024131241322413324134241352413624137241382413924140241412414224143241442414524146241472414824149241502415124152241532415424155241562415724158241592416024161241622416324164241652416624167241682416924170241712417224173241742417524176241772417824179241802418124182241832418424185241862418724188241892419024191241922419324194241952419624197241982419924200242012420224203242042420524206242072420824209242102421124212242132421424215242162421724218242192422024221242222422324224242252422624227242282422924230242312423224233242342423524236242372423824239242402424124242242432424424245242462424724248242492425024251242522425324254242552425624257242582425924260242612426224263242642426524266242672426824269242702427124272242732427424275242762427724278242792428024281242822428324284242852428624287242882428924290242912429224293242942429524296242972429824299243002430124302243032430424305243062430724308243092431024311243122431324314243152431624317243182431924320243212432224323243242432524326243272432824329243302433124332243332433424335243362433724338243392434024341243422434324344243452434624347243482434924350243512435224353243542435524356243572435824359243602436124362243632436424365243662436724368243692437024371243722437324374243752437624377243782437924380243812438224383243842438524386243872438824389243902439124392243932439424395243962439724398243992440024401244022440324404244052440624407244082440924410244112441224413244142441524416244172441824419244202442124422244232442424425244262442724428244292443024431244322443324434244352443624437244382443924440244412444224443244442444524446244472444824449244502445124452244532445424455244562445724458244592446024461244622446324464244652446624467244682446924470244712447224473244742447524476244772447824479244802448124482244832448424485244862448724488244892449024491244922449324494244952449624497244982449924500245012450224503245042450524506245072450824509245102451124512245132451424515245162451724518245192452024521245222452324524245252452624527245282452924530245312453224533245342453524536245372453824539245402454124542245432454424545245462454724548245492455024551245522455324554245552455624557245582455924560245612456224563245642456524566245672456824569245702457124572245732457424575245762457724578245792458024581245822458324584245852458624587245882458924590245912459224593245942459524596245972459824599246002460124602246032460424605246062460724608246092461024611246122461324614246152461624617246182461924620246212462224623246242462524626246272462824629246302463124632246332463424635246362463724638246392464024641246422464324644246452464624647246482464924650246512465224653246542465524656246572465824659246602466124662246632466424665246662466724668246692467024671246722467324674246752467624677246782467924680246812468224683246842468524686246872468824689246902469124692246932469424695246962469724698246992470024701247022470324704247052470624707247082470924710247112471224713247142471524716247172471824719247202472124722247232472424725247262472724728247292473024731247322473324734247352473624737247382473924740247412474224743247442474524746247472474824749247502475124752247532475424755247562475724758247592476024761247622476324764247652476624767247682476924770247712477224773247742477524776247772477824779247802478124782247832478424785247862478724788247892479024791247922479324794247952479624797247982479924800248012480224803248042480524806248072480824809248102481124812248132481424815248162481724818248192482024821248222482324824248252482624827248282482924830248312483224833248342483524836248372483824839248402484124842248432484424845248462484724848248492485024851248522485324854248552485624857248582485924860248612486224863248642486524866248672486824869248702487124872248732487424875248762487724878248792488024881248822488324884248852488624887248882488924890248912489224893248942489524896248972489824899249002490124902249032490424905249062490724908249092491024911249122491324914249152491624917249182491924920249212492224923249242492524926249272492824929249302493124932249332493424935249362493724938249392494024941249422494324944249452494624947249482494924950249512495224953249542495524956249572495824959249602496124962249632496424965249662496724968249692497024971249722497324974249752497624977249782497924980249812498224983249842498524986249872498824989249902499124992249932499424995249962499724998249992500025001250022500325004250052500625007250082500925010250112501225013250142501525016250172501825019250202502125022250232502425025250262502725028250292503025031250322503325034250352503625037250382503925040250412504225043250442504525046250472504825049250502505125052250532505425055250562505725058250592506025061250622506325064250652506625067250682506925070250712507225073250742507525076250772507825079250802508125082250832508425085250862508725088250892509025091250922509325094250952509625097250982509925100251012510225103251042510525106251072510825109251102511125112251132511425115251162511725118251192512025121251222512325124251252512625127251282512925130251312513225133251342513525136251372513825139251402514125142251432514425145251462514725148251492515025151251522515325154251552515625157251582515925160251612516225163251642516525166251672516825169251702517125172251732517425175251762517725178251792518025181251822518325184251852518625187251882518925190251912519225193251942519525196251972519825199252002520125202252032520425205252062520725208252092521025211252122521325214252152521625217252182521925220252212522225223252242522525226252272522825229252302523125232252332523425235252362523725238252392524025241252422524325244252452524625247252482524925250252512525225253252542525525256252572525825259252602526125262252632526425265252662526725268252692527025271252722527325274252752527625277252782527925280252812528225283252842528525286252872528825289252902529125292252932529425295252962529725298252992530025301253022530325304253052530625307253082530925310253112531225313253142531525316253172531825319253202532125322253232532425325253262532725328253292533025331253322533325334253352533625337253382533925340253412534225343253442534525346253472534825349253502535125352253532535425355253562535725358253592536025361253622536325364253652536625367253682536925370253712537225373253742537525376253772537825379253802538125382253832538425385253862538725388253892539025391253922539325394253952539625397253982539925400254012540225403254042540525406254072540825409254102541125412254132541425415254162541725418254192542025421254222542325424254252542625427254282542925430254312543225433254342543525436254372543825439254402544125442254432544425445254462544725448254492545025451254522545325454254552545625457254582545925460254612546225463254642546525466254672546825469254702547125472254732547425475254762547725478254792548025481254822548325484254852548625487254882548925490254912549225493254942549525496254972549825499255002550125502255032550425505255062550725508255092551025511255122551325514255152551625517255182551925520255212552225523255242552525526255272552825529255302553125532255332553425535255362553725538255392554025541255422554325544255452554625547255482554925550255512555225553255542555525556255572555825559255602556125562255632556425565255662556725568255692557025571255722557325574255752557625577255782557925580255812558225583255842558525586255872558825589255902559125592255932559425595255962559725598255992560025601256022560325604256052560625607256082560925610256112561225613256142561525616256172561825619256202562125622256232562425625256262562725628256292563025631256322563325634256352563625637256382563925640256412564225643256442564525646256472564825649256502565125652256532565425655256562565725658256592566025661256622566325664256652566625667256682566925670256712567225673256742567525676256772567825679256802568125682256832568425685256862568725688256892569025691256922569325694256952569625697256982569925700257012570225703257042570525706257072570825709257102571125712257132571425715257162571725718257192572025721257222572325724257252572625727257282572925730257312573225733257342573525736257372573825739257402574125742257432574425745257462574725748257492575025751257522575325754257552575625757257582575925760257612576225763257642576525766257672576825769257702577125772257732577425775257762577725778257792578025781257822578325784257852578625787257882578925790257912579225793257942579525796257972579825799258002580125802258032580425805258062580725808258092581025811258122581325814258152581625817258182581925820258212582225823258242582525826258272582825829258302583125832258332583425835258362583725838258392584025841258422584325844258452584625847258482584925850258512585225853258542585525856258572585825859258602586125862258632586425865258662586725868258692587025871258722587325874258752587625877258782587925880258812588225883258842588525886258872588825889258902589125892258932589425895258962589725898258992590025901259022590325904259052590625907259082590925910259112591225913259142591525916259172591825919259202592125922259232592425925259262592725928259292593025931259322593325934259352593625937259382593925940259412594225943259442594525946259472594825949259502595125952259532595425955259562595725958259592596025961259622596325964259652596625967259682596925970259712597225973259742597525976259772597825979259802598125982259832598425985259862598725988259892599025991259922599325994259952599625997259982599926000260012600226003260042600526006260072600826009260102601126012260132601426015260162601726018260192602026021260222602326024260252602626027260282602926030260312603226033260342603526036260372603826039260402604126042260432604426045260462604726048260492605026051260522605326054260552605626057260582605926060260612606226063260642606526066260672606826069260702607126072260732607426075260762607726078260792608026081260822608326084260852608626087260882608926090260912609226093260942609526096260972609826099261002610126102261032610426105261062610726108261092611026111261122611326114261152611626117261182611926120261212612226123261242612526126261272612826129261302613126132261332613426135261362613726138261392614026141261422614326144261452614626147261482614926150261512615226153261542615526156261572615826159261602616126162261632616426165261662616726168261692617026171261722617326174261752617626177261782617926180261812618226183261842618526186261872618826189261902619126192261932619426195261962619726198261992620026201262022620326204262052620626207262082620926210262112621226213262142621526216262172621826219262202622126222262232622426225262262622726228262292623026231262322623326234262352623626237262382623926240262412624226243262442624526246262472624826249262502625126252262532625426255262562625726258262592626026261262622626326264262652626626267262682626926270262712627226273262742627526276262772627826279262802628126282262832628426285262862628726288262892629026291262922629326294262952629626297262982629926300263012630226303263042630526306263072630826309263102631126312263132631426315263162631726318263192632026321263222632326324263252632626327263282632926330263312633226333263342633526336263372633826339263402634126342263432634426345263462634726348263492635026351263522635326354263552635626357263582635926360263612636226363263642636526366263672636826369263702637126372263732637426375263762637726378263792638026381263822638326384263852638626387263882638926390263912639226393263942639526396263972639826399264002640126402264032640426405264062640726408264092641026411264122641326414264152641626417264182641926420264212642226423264242642526426264272642826429264302643126432264332643426435264362643726438264392644026441264422644326444264452644626447264482644926450264512645226453264542645526456264572645826459264602646126462264632646426465264662646726468264692647026471264722647326474264752647626477264782647926480264812648226483264842648526486264872648826489264902649126492264932649426495264962649726498264992650026501265022650326504265052650626507265082650926510265112651226513265142651526516265172651826519265202652126522265232652426525265262652726528265292653026531265322653326534265352653626537265382653926540265412654226543265442654526546265472654826549265502655126552265532655426555265562655726558265592656026561265622656326564265652656626567265682656926570265712657226573265742657526576265772657826579265802658126582265832658426585265862658726588265892659026591265922659326594265952659626597265982659926600266012660226603266042660526606266072660826609266102661126612266132661426615266162661726618266192662026621266222662326624266252662626627266282662926630266312663226633266342663526636266372663826639266402664126642266432664426645266462664726648266492665026651266522665326654266552665626657266582665926660266612666226663266642666526666266672666826669266702667126672266732667426675266762667726678266792668026681266822668326684266852668626687266882668926690266912669226693266942669526696266972669826699267002670126702267032670426705267062670726708267092671026711267122671326714267152671626717267182671926720267212672226723267242672526726267272672826729267302673126732267332673426735267362673726738267392674026741267422674326744267452674626747267482674926750267512675226753267542675526756267572675826759267602676126762267632676426765267662676726768267692677026771267722677326774267752677626777267782677926780267812678226783267842678526786267872678826789267902679126792267932679426795267962679726798267992680026801268022680326804268052680626807268082680926810268112681226813268142681526816268172681826819268202682126822268232682426825268262682726828268292683026831268322683326834268352683626837268382683926840268412684226843268442684526846268472684826849268502685126852268532685426855268562685726858268592686026861268622686326864268652686626867268682686926870268712687226873268742687526876268772687826879268802688126882268832688426885268862688726888268892689026891268922689326894268952689626897268982689926900269012690226903269042690526906269072690826909269102691126912269132691426915269162691726918269192692026921269222692326924269252692626927269282692926930269312693226933269342693526936269372693826939269402694126942269432694426945269462694726948269492695026951269522695326954269552695626957269582695926960269612696226963269642696526966269672696826969269702697126972269732697426975269762697726978269792698026981269822698326984269852698626987269882698926990269912699226993269942699526996269972699826999270002700127002270032700427005270062700727008270092701027011270122701327014270152701627017270182701927020270212702227023270242702527026270272702827029270302703127032270332703427035270362703727038270392704027041270422704327044270452704627047270482704927050270512705227053270542705527056270572705827059270602706127062270632706427065270662706727068270692707027071270722707327074270752707627077270782707927080270812708227083270842708527086270872708827089270902709127092270932709427095270962709727098270992710027101271022710327104271052710627107271082710927110271112711227113271142711527116271172711827119271202712127122271232712427125271262712727128271292713027131271322713327134271352713627137271382713927140271412714227143271442714527146271472714827149271502715127152271532715427155271562715727158271592716027161271622716327164271652716627167271682716927170271712717227173271742717527176271772717827179271802718127182271832718427185271862718727188271892719027191271922719327194271952719627197271982719927200272012720227203272042720527206272072720827209272102721127212272132721427215272162721727218272192722027221272222722327224272252722627227272282722927230272312723227233272342723527236272372723827239272402724127242272432724427245272462724727248272492725027251272522725327254272552725627257272582725927260272612726227263272642726527266272672726827269272702727127272272732727427275272762727727278272792728027281272822728327284272852728627287272882728927290272912729227293272942729527296272972729827299273002730127302273032730427305273062730727308273092731027311273122731327314273152731627317273182731927320273212732227323273242732527326273272732827329273302733127332273332733427335273362733727338273392734027341273422734327344273452734627347273482734927350273512735227353273542735527356273572735827359273602736127362273632736427365273662736727368273692737027371273722737327374273752737627377273782737927380273812738227383273842738527386273872738827389273902739127392273932739427395273962739727398273992740027401274022740327404274052740627407274082740927410274112741227413274142741527416274172741827419274202742127422274232742427425274262742727428274292743027431274322743327434274352743627437274382743927440274412744227443274442744527446274472744827449274502745127452274532745427455274562745727458274592746027461274622746327464274652746627467274682746927470274712747227473274742747527476274772747827479274802748127482274832748427485274862748727488274892749027491274922749327494274952749627497274982749927500275012750227503275042750527506275072750827509275102751127512275132751427515275162751727518275192752027521275222752327524275252752627527275282752927530275312753227533275342753527536275372753827539275402754127542275432754427545275462754727548275492755027551275522755327554275552755627557275582755927560275612756227563275642756527566275672756827569275702757127572275732757427575275762757727578275792758027581275822758327584275852758627587275882758927590275912759227593275942759527596275972759827599276002760127602276032760427605276062760727608276092761027611276122761327614276152761627617276182761927620276212762227623276242762527626276272762827629276302763127632276332763427635276362763727638276392764027641276422764327644276452764627647276482764927650276512765227653276542765527656276572765827659276602766127662276632766427665276662766727668276692767027671276722767327674276752767627677276782767927680276812768227683276842768527686276872768827689276902769127692276932769427695276962769727698276992770027701277022770327704277052770627707277082770927710277112771227713277142771527716277172771827719277202772127722277232772427725277262772727728277292773027731277322773327734277352773627737277382773927740277412774227743277442774527746277472774827749277502775127752277532775427755277562775727758277592776027761277622776327764277652776627767277682776927770277712777227773277742777527776277772777827779277802778127782277832778427785277862778727788277892779027791277922779327794277952779627797277982779927800278012780227803278042780527806278072780827809278102781127812278132781427815278162781727818278192782027821278222782327824278252782627827278282782927830278312783227833278342783527836278372783827839278402784127842278432784427845278462784727848278492785027851278522785327854278552785627857278582785927860278612786227863278642786527866278672786827869278702787127872278732787427875278762787727878278792788027881278822788327884278852788627887278882788927890278912789227893278942789527896278972789827899279002790127902279032790427905279062790727908279092791027911279122791327914279152791627917279182791927920279212792227923279242792527926279272792827929279302793127932279332793427935279362793727938279392794027941279422794327944279452794627947279482794927950279512795227953279542795527956279572795827959279602796127962279632796427965279662796727968279692797027971279722797327974279752797627977279782797927980279812798227983279842798527986279872798827989279902799127992279932799427995279962799727998279992800028001280022800328004280052800628007280082800928010280112801228013280142801528016280172801828019280202802128022280232802428025280262802728028280292803028031280322803328034280352803628037280382803928040280412804228043280442804528046280472804828049280502805128052280532805428055280562805728058280592806028061280622806328064280652806628067280682806928070280712807228073280742807528076280772807828079280802808128082280832808428085280862808728088280892809028091280922809328094280952809628097280982809928100281012810228103281042810528106281072810828109281102811128112281132811428115281162811728118281192812028121281222812328124281252812628127281282812928130281312813228133281342813528136281372813828139281402814128142281432814428145281462814728148281492815028151281522815328154281552815628157281582815928160281612816228163281642816528166281672816828169281702817128172281732817428175281762817728178281792818028181281822818328184281852818628187281882818928190281912819228193281942819528196281972819828199282002820128202282032820428205282062820728208282092821028211282122821328214282152821628217282182821928220282212822228223282242822528226282272822828229282302823128232282332823428235282362823728238282392824028241282422824328244282452824628247282482824928250282512825228253282542825528256282572825828259282602826128262282632826428265282662826728268282692827028271282722827328274282752827628277282782827928280282812828228283282842828528286282872828828289282902829128292282932829428295282962829728298282992830028301283022830328304283052830628307283082830928310283112831228313283142831528316283172831828319283202832128322283232832428325283262832728328283292833028331283322833328334283352833628337283382833928340283412834228343283442834528346283472834828349283502835128352283532835428355283562835728358283592836028361283622836328364283652836628367283682836928370283712837228373283742837528376283772837828379283802838128382283832838428385283862838728388283892839028391283922839328394283952839628397283982839928400284012840228403284042840528406284072840828409284102841128412284132841428415284162841728418284192842028421284222842328424284252842628427284282842928430284312843228433284342843528436284372843828439284402844128442284432844428445284462844728448284492845028451284522845328454284552845628457284582845928460284612846228463284642846528466284672846828469284702847128472284732847428475284762847728478284792848028481284822848328484284852848628487284882848928490284912849228493284942849528496284972849828499285002850128502285032850428505285062850728508285092851028511285122851328514285152851628517285182851928520285212852228523285242852528526285272852828529285302853128532285332853428535285362853728538285392854028541285422854328544285452854628547285482854928550285512855228553285542855528556285572855828559285602856128562285632856428565285662856728568285692857028571285722857328574285752857628577285782857928580285812858228583285842858528586285872858828589285902859128592285932859428595285962859728598285992860028601286022860328604286052860628607286082860928610286112861228613286142861528616286172861828619286202862128622286232862428625286262862728628286292863028631286322863328634286352863628637286382863928640286412864228643286442864528646286472864828649286502865128652286532865428655286562865728658286592866028661286622866328664286652866628667286682866928670286712867228673286742867528676286772867828679286802868128682286832868428685286862868728688286892869028691286922869328694286952869628697286982869928700287012870228703287042870528706287072870828709287102871128712287132871428715287162871728718287192872028721287222872328724287252872628727287282872928730287312873228733287342873528736287372873828739287402874128742287432874428745287462874728748287492875028751287522875328754287552875628757287582875928760287612876228763287642876528766287672876828769287702877128772287732877428775287762877728778287792878028781287822878328784287852878628787287882878928790287912879228793287942879528796287972879828799288002880128802288032880428805288062880728808288092881028811288122881328814288152881628817288182881928820288212882228823288242882528826288272882828829288302883128832288332883428835288362883728838288392884028841288422884328844288452884628847288482884928850288512885228853288542885528856288572885828859288602886128862288632886428865288662886728868288692887028871288722887328874288752887628877288782887928880288812888228883288842888528886288872888828889288902889128892288932889428895288962889728898288992890028901289022890328904289052890628907289082890928910289112891228913289142891528916289172891828919289202892128922289232892428925289262892728928289292893028931289322893328934289352893628937289382893928940289412894228943289442894528946289472894828949289502895128952289532895428955289562895728958289592896028961289622896328964289652896628967289682896928970289712897228973289742897528976289772897828979289802898128982289832898428985289862898728988289892899028991289922899328994289952899628997289982899929000290012900229003290042900529006290072900829009290102901129012290132901429015290162901729018290192902029021290222902329024290252902629027290282902929030290312903229033290342903529036290372903829039290402904129042290432904429045290462904729048290492905029051290522905329054290552905629057290582905929060290612906229063290642906529066290672906829069290702907129072290732907429075290762907729078290792908029081290822908329084290852908629087290882908929090290912909229093290942909529096290972909829099291002910129102291032910429105291062910729108291092911029111291122911329114291152911629117291182911929120291212912229123291242912529126291272912829129291302913129132291332913429135291362913729138291392914029141291422914329144291452914629147291482914929150291512915229153291542915529156291572915829159291602916129162291632916429165291662916729168291692917029171291722917329174291752917629177291782917929180291812918229183291842918529186291872918829189291902919129192291932919429195291962919729198291992920029201292022920329204292052920629207292082920929210292112921229213292142921529216292172921829219292202922129222292232922429225292262922729228292292923029231292322923329234292352923629237292382923929240292412924229243292442924529246292472924829249292502925129252292532925429255292562925729258292592926029261292622926329264292652926629267292682926929270292712927229273292742927529276292772927829279292802928129282292832928429285292862928729288292892929029291292922929329294292952929629297292982929929300293012930229303293042930529306293072930829309293102931129312293132931429315293162931729318293192932029321293222932329324293252932629327293282932929330293312933229333293342933529336293372933829339293402934129342293432934429345293462934729348293492935029351293522935329354293552935629357293582935929360293612936229363293642936529366293672936829369293702937129372293732937429375293762937729378293792938029381293822938329384293852938629387293882938929390293912939229393293942939529396293972939829399294002940129402294032940429405294062940729408294092941029411294122941329414294152941629417294182941929420294212942229423294242942529426294272942829429294302943129432294332943429435294362943729438294392944029441294422944329444294452944629447294482944929450294512945229453294542945529456294572945829459294602946129462294632946429465294662946729468294692947029471294722947329474294752947629477294782947929480294812948229483294842948529486294872948829489294902949129492294932949429495294962949729498294992950029501295022950329504295052950629507295082950929510295112951229513295142951529516295172951829519295202952129522295232952429525295262952729528295292953029531295322953329534295352953629537295382953929540295412954229543295442954529546295472954829549295502955129552295532955429555295562955729558295592956029561295622956329564295652956629567295682956929570295712957229573295742957529576295772957829579295802958129582295832958429585295862958729588295892959029591295922959329594295952959629597295982959929600296012960229603296042960529606296072960829609296102961129612296132961429615296162961729618296192962029621296222962329624296252962629627296282962929630296312963229633296342963529636296372963829639296402964129642296432964429645296462964729648296492965029651296522965329654296552965629657296582965929660296612966229663296642966529666296672966829669296702967129672296732967429675296762967729678296792968029681296822968329684296852968629687296882968929690296912969229693296942969529696296972969829699297002970129702297032970429705297062970729708297092971029711297122971329714297152971629717297182971929720297212972229723297242972529726297272972829729297302973129732297332973429735297362973729738297392974029741297422974329744297452974629747297482974929750297512975229753297542975529756297572975829759297602976129762297632976429765297662976729768297692977029771297722977329774297752977629777297782977929780297812978229783297842978529786297872978829789297902979129792297932979429795297962979729798297992980029801298022980329804298052980629807298082980929810298112981229813298142981529816298172981829819298202982129822298232982429825298262982729828298292983029831298322983329834298352983629837298382983929840298412984229843298442984529846298472984829849298502985129852298532985429855298562985729858298592986029861298622986329864298652986629867298682986929870298712987229873298742987529876298772987829879298802988129882298832988429885298862988729888298892989029891298922989329894298952989629897298982989929900299012990229903299042990529906299072990829909299102991129912299132991429915299162991729918299192992029921299222992329924299252992629927299282992929930299312993229933299342993529936299372993829939299402994129942299432994429945299462994729948299492995029951299522995329954299552995629957299582995929960299612996229963299642996529966299672996829969299702997129972299732997429975299762997729978299792998029981299822998329984299852998629987299882998929990299912999229993299942999529996299972999829999300003000130002300033000430005300063000730008300093001030011300123001330014300153001630017300183001930020300213002230023300243002530026300273002830029300303003130032300333003430035300363003730038300393004030041300423004330044300453004630047300483004930050300513005230053300543005530056300573005830059300603006130062300633006430065300663006730068300693007030071300723007330074300753007630077300783007930080300813008230083300843008530086300873008830089300903009130092300933009430095300963009730098300993010030101301023010330104301053010630107301083010930110301113011230113301143011530116301173011830119301203012130122301233012430125301263012730128301293013030131301323013330134301353013630137301383013930140301413014230143301443014530146301473014830149301503015130152301533015430155301563015730158301593016030161301623016330164301653016630167301683016930170301713017230173301743017530176301773017830179301803018130182301833018430185301863018730188301893019030191301923019330194301953019630197301983019930200302013020230203302043020530206302073020830209302103021130212302133021430215302163021730218302193022030221302223022330224302253022630227302283022930230302313023230233302343023530236302373023830239302403024130242302433024430245302463024730248302493025030251302523025330254302553025630257302583025930260302613026230263302643026530266302673026830269302703027130272302733027430275302763027730278302793028030281302823028330284302853028630287302883028930290302913029230293302943029530296302973029830299303003030130302303033030430305303063030730308303093031030311303123031330314303153031630317303183031930320303213032230323303243032530326303273032830329303303033130332303333033430335303363033730338303393034030341303423034330344303453034630347303483034930350303513035230353303543035530356303573035830359303603036130362303633036430365303663036730368303693037030371303723037330374303753037630377303783037930380303813038230383303843038530386303873038830389303903039130392303933039430395303963039730398303993040030401304023040330404304053040630407304083040930410304113041230413304143041530416304173041830419304203042130422304233042430425304263042730428304293043030431304323043330434304353043630437304383043930440304413044230443304443044530446304473044830449304503045130452304533045430455304563045730458304593046030461304623046330464304653046630467304683046930470304713047230473304743047530476304773047830479304803048130482304833048430485304863048730488304893049030491304923049330494304953049630497304983049930500305013050230503305043050530506305073050830509305103051130512305133051430515305163051730518305193052030521305223052330524305253052630527305283052930530305313053230533305343053530536305373053830539305403054130542305433054430545305463054730548305493055030551305523055330554305553055630557305583055930560305613056230563305643056530566305673056830569305703057130572305733057430575305763057730578305793058030581305823058330584305853058630587305883058930590305913059230593305943059530596305973059830599306003060130602306033060430605306063060730608306093061030611306123061330614306153061630617306183061930620306213062230623306243062530626306273062830629306303063130632306333063430635306363063730638306393064030641306423064330644306453064630647306483064930650306513065230653306543065530656306573065830659306603066130662306633066430665306663066730668306693067030671306723067330674306753067630677306783067930680306813068230683306843068530686306873068830689306903069130692306933069430695306963069730698306993070030701307023070330704307053070630707307083070930710307113071230713307143071530716307173071830719307203072130722307233072430725307263072730728307293073030731307323073330734307353073630737307383073930740307413074230743307443074530746307473074830749307503075130752307533075430755307563075730758307593076030761307623076330764307653076630767307683076930770307713077230773307743077530776307773077830779307803078130782307833078430785307863078730788307893079030791307923079330794307953079630797307983079930800308013080230803308043080530806308073080830809308103081130812308133081430815308163081730818308193082030821308223082330824308253082630827308283082930830308313083230833308343083530836308373083830839308403084130842308433084430845308463084730848308493085030851308523085330854308553085630857308583085930860308613086230863308643086530866308673086830869308703087130872308733087430875308763087730878308793088030881308823088330884308853088630887308883088930890308913089230893308943089530896308973089830899309003090130902309033090430905309063090730908309093091030911309123091330914309153091630917309183091930920309213092230923309243092530926309273092830929309303093130932309333093430935309363093730938309393094030941309423094330944309453094630947309483094930950309513095230953309543095530956309573095830959309603096130962309633096430965309663096730968309693097030971309723097330974309753097630977309783097930980309813098230983309843098530986309873098830989309903099130992309933099430995309963099730998309993100031001310023100331004310053100631007310083100931010310113101231013310143101531016310173101831019310203102131022310233102431025310263102731028310293103031031310323103331034310353103631037310383103931040310413104231043310443104531046310473104831049310503105131052310533105431055310563105731058310593106031061310623106331064310653106631067310683106931070310713107231073310743107531076310773107831079310803108131082310833108431085310863108731088310893109031091310923109331094310953109631097310983109931100311013110231103311043110531106311073110831109311103111131112311133111431115311163111731118311193112031121311223112331124311253112631127311283112931130311313113231133311343113531136311373113831139311403114131142311433114431145311463114731148311493115031151311523115331154311553115631157311583115931160311613116231163311643116531166311673116831169311703117131172311733117431175311763117731178311793118031181311823118331184311853118631187311883118931190311913119231193311943119531196311973119831199312003120131202312033120431205312063120731208312093121031211312123121331214312153121631217312183121931220312213122231223312243122531226312273122831229312303123131232312333123431235312363123731238312393124031241312423124331244312453124631247312483124931250312513125231253312543125531256312573125831259312603126131262312633126431265312663126731268312693127031271312723127331274312753127631277312783127931280312813128231283312843128531286312873128831289312903129131292312933129431295312963129731298312993130031301313023130331304313053130631307313083130931310313113131231313313143131531316313173131831319313203132131322313233132431325313263132731328313293133031331313323133331334313353133631337313383133931340313413134231343313443134531346313473134831349313503135131352313533135431355313563135731358313593136031361313623136331364313653136631367313683136931370313713137231373313743137531376313773137831379313803138131382313833138431385313863138731388313893139031391313923139331394313953139631397313983139931400314013140231403314043140531406314073140831409314103141131412314133141431415314163141731418314193142031421314223142331424314253142631427314283142931430314313143231433314343143531436314373143831439314403144131442314433144431445314463144731448314493145031451314523145331454314553145631457314583145931460314613146231463314643146531466314673146831469314703147131472314733147431475314763147731478314793148031481314823148331484314853148631487314883148931490314913149231493314943149531496314973149831499315003150131502315033150431505315063150731508315093151031511315123151331514315153151631517315183151931520315213152231523315243152531526315273152831529315303153131532315333153431535315363153731538315393154031541315423154331544315453154631547315483154931550315513155231553315543155531556315573155831559315603156131562315633156431565315663156731568315693157031571315723157331574315753157631577315783157931580315813158231583315843158531586315873158831589315903159131592315933159431595315963159731598315993160031601316023160331604316053160631607316083160931610316113161231613316143161531616316173161831619316203162131622316233162431625316263162731628316293163031631316323163331634316353163631637316383163931640316413164231643316443164531646316473164831649316503165131652316533165431655316563165731658316593166031661316623166331664316653166631667316683166931670316713167231673316743167531676316773167831679316803168131682316833168431685316863168731688316893169031691316923169331694316953169631697316983169931700317013170231703317043170531706317073170831709317103171131712317133171431715317163171731718317193172031721317223172331724317253172631727317283172931730317313173231733317343173531736317373173831739317403174131742317433174431745317463174731748317493175031751317523175331754317553175631757317583175931760317613176231763317643176531766317673176831769317703177131772317733177431775317763177731778317793178031781317823178331784317853178631787317883178931790317913179231793317943179531796317973179831799318003180131802318033180431805318063180731808318093181031811318123181331814318153181631817318183181931820318213182231823318243182531826318273182831829318303183131832318333183431835318363183731838318393184031841318423184331844318453184631847318483184931850318513185231853318543185531856318573185831859318603186131862318633186431865318663186731868318693187031871318723187331874318753187631877318783187931880318813188231883318843188531886318873188831889318903189131892318933189431895318963189731898318993190031901319023190331904319053190631907319083190931910319113191231913319143191531916319173191831919319203192131922319233192431925319263192731928319293193031931319323193331934319353193631937319383193931940319413194231943319443194531946319473194831949319503195131952319533195431955319563195731958319593196031961319623196331964319653196631967319683196931970319713197231973319743197531976319773197831979319803198131982319833198431985319863198731988319893199031991319923199331994319953199631997319983199932000320013200232003320043200532006320073200832009320103201132012320133201432015320163201732018320193202032021320223202332024320253202632027320283202932030320313203232033320343203532036320373203832039320403204132042320433204432045320463204732048320493205032051320523205332054320553205632057320583205932060320613206232063320643206532066320673206832069320703207132072320733207432075320763207732078320793208032081320823208332084320853208632087320883208932090320913209232093320943209532096320973209832099321003210132102321033210432105321063210732108321093211032111321123211332114321153211632117321183211932120321213212232123321243212532126321273212832129321303213132132321333213432135321363213732138321393214032141321423214332144321453214632147321483214932150321513215232153321543215532156321573215832159321603216132162321633216432165321663216732168321693217032171321723217332174321753217632177321783217932180321813218232183321843218532186321873218832189321903219132192321933219432195321963219732198321993220032201322023220332204322053220632207322083220932210322113221232213322143221532216322173221832219322203222132222322233222432225322263222732228322293223032231322323223332234322353223632237322383223932240322413224232243322443224532246322473224832249322503225132252322533225432255322563225732258322593226032261322623226332264322653226632267322683226932270322713227232273322743227532276322773227832279322803228132282322833228432285322863228732288322893229032291322923229332294322953229632297322983229932300323013230232303323043230532306323073230832309323103231132312323133231432315323163231732318323193232032321323223232332324323253232632327323283232932330323313233232333323343233532336323373233832339323403234132342323433234432345323463234732348323493235032351323523235332354323553235632357323583235932360323613236232363323643236532366323673236832369323703237132372323733237432375323763237732378323793238032381323823238332384323853238632387323883238932390323913239232393323943239532396323973239832399324003240132402324033240432405324063240732408324093241032411324123241332414324153241632417324183241932420324213242232423324243242532426324273242832429324303243132432324333243432435324363243732438324393244032441324423244332444324453244632447324483244932450324513245232453324543245532456324573245832459324603246132462324633246432465324663246732468324693247032471324723247332474324753247632477324783247932480324813248232483324843248532486324873248832489324903249132492324933249432495324963249732498324993250032501325023250332504325053250632507325083250932510325113251232513325143251532516325173251832519325203252132522325233252432525325263252732528325293253032531325323253332534325353253632537325383253932540325413254232543325443254532546325473254832549325503255132552325533255432555325563255732558325593256032561325623256332564325653256632567325683256932570325713257232573325743257532576325773257832579325803258132582325833258432585325863258732588325893259032591325923259332594325953259632597325983259932600326013260232603326043260532606326073260832609326103261132612326133261432615326163261732618326193262032621326223262332624326253262632627326283262932630326313263232633326343263532636326373263832639326403264132642326433264432645326463264732648326493265032651326523265332654326553265632657326583265932660326613266232663326643266532666326673266832669326703267132672326733267432675326763267732678326793268032681326823268332684326853268632687326883268932690326913269232693326943269532696326973269832699327003270132702327033270432705327063270732708327093271032711327123271332714327153271632717327183271932720327213272232723327243272532726327273272832729327303273132732327333273432735327363273732738327393274032741327423274332744327453274632747327483274932750327513275232753327543275532756327573275832759327603276132762327633276432765327663276732768327693277032771327723277332774327753277632777327783277932780327813278232783327843278532786327873278832789327903279132792327933279432795327963279732798327993280032801328023280332804328053280632807328083280932810328113281232813328143281532816328173281832819328203282132822328233282432825328263282732828328293283032831328323283332834328353283632837328383283932840328413284232843328443284532846328473284832849328503285132852328533285432855328563285732858328593286032861328623286332864328653286632867328683286932870328713287232873328743287532876328773287832879328803288132882328833288432885328863288732888328893289032891328923289332894328953289632897328983289932900329013290232903329043290532906329073290832909329103291132912329133291432915329163291732918329193292032921329223292332924329253292632927329283292932930329313293232933329343293532936329373293832939329403294132942329433294432945329463294732948329493295032951329523295332954329553295632957329583295932960329613296232963329643296532966329673296832969329703297132972329733297432975329763297732978329793298032981329823298332984329853298632987329883298932990329913299232993329943299532996329973299832999330003300133002330033300433005330063300733008330093301033011330123301333014330153301633017330183301933020330213302233023330243302533026330273302833029330303303133032330333303433035330363303733038330393304033041330423304333044330453304633047330483304933050330513305233053330543305533056330573305833059330603306133062330633306433065330663306733068330693307033071330723307333074330753307633077330783307933080330813308233083330843308533086330873308833089330903309133092330933309433095330963309733098330993310033101331023310333104331053310633107331083310933110331113311233113331143311533116331173311833119331203312133122331233312433125331263312733128331293313033131331323313333134331353313633137331383313933140331413314233143331443314533146331473314833149331503315133152331533315433155331563315733158331593316033161331623316333164331653316633167331683316933170331713317233173331743317533176331773317833179331803318133182331833318433185331863318733188331893319033191
  1. require({cache:{
  2. 'dijit/_editor/plugins/FontChoice':function(){
  3. define([
  4. "dojo/_base/array", // array.indexOf array.map
  5. "dojo/_base/declare", // declare
  6. "dojo/dom-construct", // domConstruct.place
  7. "dojo/i18n", // i18n.getLocalization
  8. "dojo/_base/lang", // lang.delegate lang.hitch lang.isString
  9. "dojo/store/Memory", // MemoryStore
  10. "dojo/_base/window", // win.withGlobal
  11. "../../registry", // registry.getUniqueId
  12. "../../_Widget",
  13. "../../_TemplatedMixin",
  14. "../../_WidgetsInTemplateMixin",
  15. "../../form/FilteringSelect",
  16. "../_Plugin",
  17. "../range",
  18. "../selection",
  19. "dojo/i18n!../nls/FontChoice"
  20. ], function(array, declare, domConstruct, i18n, lang, MemoryStore, win,
  21. registry, _Widget, _TemplatedMixin, _WidgetsInTemplateMixin, FilteringSelect, _Plugin, rangeapi, selectionapi){
  22. /*=====
  23. var _Plugin = dijit._editor._Plugin;
  24. var _Widget = dijit._Widget;
  25. var _TemplatedMixin = dijit._TemplatedMixin;
  26. var _WidgetsInTemplateMixin = dijit._WidgetsInTemplateMixin;
  27. var FilteringSelect = dijit.form.FilteringSelect;
  28. =====*/
  29. // module:
  30. // dijit/_editor/plugins/FontChoice
  31. // summary:
  32. // fontchoice, fontsize, and formatblock editor plugins
  33. var _FontDropDown = declare("dijit._editor.plugins._FontDropDown",
  34. [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin], {
  35. // summary:
  36. // Base class for widgets that contains a label (like "Font:")
  37. // and a FilteringSelect drop down to pick a value.
  38. // Used as Toolbar entry.
  39. // label: [public] String
  40. // The label to apply to this particular FontDropDown.
  41. label: "",
  42. // plainText: [public] boolean
  43. // Flag to indicate that the returned label should be plain text
  44. // instead of an example.
  45. plainText: false,
  46. // templateString: [public] String
  47. // The template used to construct the labeled dropdown.
  48. templateString:
  49. "<span style='white-space: nowrap' class='dijit dijitReset dijitInline'>" +
  50. "<label class='dijitLeft dijitInline' for='${selectId}'>${label}</label>" +
  51. "<input data-dojo-type='dijit.form.FilteringSelect' required='false' " +
  52. "data-dojo-props='labelType:\"html\", labelAttr:\"label\", searchAttr:\"name\"' " +
  53. "tabIndex='-1' id='${selectId}' data-dojo-attach-point='select' value=''/>" +
  54. "</span>",
  55. postMixInProperties: function(){
  56. // summary:
  57. // Over-ride to set specific properties.
  58. this.inherited(arguments);
  59. this.strings = i18n.getLocalization("dijit._editor", "FontChoice");
  60. // Set some substitution variables used in the template
  61. this.label = this.strings[this.command];
  62. this.id = registry.getUniqueId(this.declaredClass.replace(/\./g,"_")); // TODO: unneeded??
  63. this.selectId = this.id + "_select"; // used in template
  64. this.inherited(arguments);
  65. },
  66. postCreate: function(){
  67. // summary:
  68. // Over-ride for the default postCreate action
  69. // This establishes the filtering selects and the like.
  70. // Initialize the list of items in the drop down by creating data store with items like:
  71. // {value: 1, name: "xx-small", label: "<font size=1>xx-small</font-size>" }
  72. this.select.set("store", new MemoryStore({
  73. idProperty: "value",
  74. data: array.map(this.values, function(value){
  75. var name = this.strings[value] || value;
  76. return {
  77. label: this.getLabel(value, name),
  78. name: name,
  79. value: value
  80. };
  81. }, this)
  82. }));
  83. this.select.set("value", "", false);
  84. this.disabled = this.select.get("disabled");
  85. },
  86. _setValueAttr: function(value, priorityChange){
  87. // summary:
  88. // Over-ride for the default action of setting the
  89. // widget value, maps the input to known values
  90. // value: Object|String
  91. // The value to set in the select.
  92. // priorityChange:
  93. // Optional parameter used to tell the select whether or not to fire
  94. // onChange event.
  95. // if the value is not a permitted value, just set empty string to prevent showing the warning icon
  96. priorityChange = priorityChange !== false;
  97. this.select.set('value', array.indexOf(this.values,value) < 0 ? "" : value, priorityChange);
  98. if(!priorityChange){
  99. // Clear the last state in case of updateState calls. Ref: #10466
  100. this.select._lastValueReported=null;
  101. }
  102. },
  103. _getValueAttr: function(){
  104. // summary:
  105. // Allow retrieving the value from the composite select on
  106. // call to button.get("value");
  107. return this.select.get('value');
  108. },
  109. focus: function(){
  110. // summary:
  111. // Over-ride for focus control of this widget. Delegates focus down to the
  112. // filtering select.
  113. this.select.focus();
  114. },
  115. _setDisabledAttr: function(value){
  116. // summary:
  117. // Over-ride for the button's 'disabled' attribute so that it can be
  118. // disabled programmatically.
  119. // Save off ths disabled state so the get retrieves it correctly
  120. //without needing to have a function proxy it.
  121. this.disabled = value;
  122. this.select.set("disabled", value);
  123. }
  124. });
  125. var _FontNameDropDown = declare("dijit._editor.plugins._FontNameDropDown", _FontDropDown, {
  126. // summary:
  127. // Dropdown to select a font; goes in editor toolbar.
  128. // generic: Boolean
  129. // Use generic (web standard) font names
  130. generic: false,
  131. // command: [public] String
  132. // The editor 'command' implemented by this plugin.
  133. command: "fontName",
  134. postMixInProperties: function(){
  135. // summary:
  136. // Over-ride for the default posr mixin control
  137. if(!this.values){
  138. this.values = this.generic ?
  139. ["serif", "sans-serif", "monospace", "cursive", "fantasy"] : // CSS font-family generics
  140. ["Arial", "Times New Roman", "Comic Sans MS", "Courier New"];
  141. }
  142. this.inherited(arguments);
  143. },
  144. getLabel: function(value, name){
  145. // summary:
  146. // Function used to generate the labels of the format dropdown
  147. // will return a formatted, or plain label based on the value
  148. // of the plainText option.
  149. // value: String
  150. // The 'insert value' associated with a name
  151. // name: String
  152. // The text name of the value
  153. if(this.plainText){
  154. return name;
  155. }else{
  156. return "<div style='font-family: "+value+"'>" + name + "</div>";
  157. }
  158. },
  159. _setValueAttr: function(value, priorityChange){
  160. // summary:
  161. // Over-ride for the default action of setting the
  162. // widget value, maps the input to known values
  163. priorityChange = priorityChange !== false;
  164. if(this.generic){
  165. var map = {
  166. "Arial": "sans-serif",
  167. "Helvetica": "sans-serif",
  168. "Myriad": "sans-serif",
  169. "Times": "serif",
  170. "Times New Roman": "serif",
  171. "Comic Sans MS": "cursive",
  172. "Apple Chancery": "cursive",
  173. "Courier": "monospace",
  174. "Courier New": "monospace",
  175. "Papyrus": "fantasy",
  176. "Estrangelo Edessa": "cursive", // Windows 7
  177. "Gabriola": "fantasy" // Windows 7
  178. };
  179. value = map[value] || value;
  180. }
  181. this.inherited(arguments, [value, priorityChange]);
  182. }
  183. });
  184. var _FontSizeDropDown = declare("dijit._editor.plugins._FontSizeDropDown", _FontDropDown, {
  185. // summary:
  186. // Dropdown to select a font size; goes in editor toolbar.
  187. // command: [public] String
  188. // The editor 'command' implemented by this plugin.
  189. command: "fontSize",
  190. // values: [public] Number[]
  191. // The HTML font size values supported by this plugin
  192. values: [1,2,3,4,5,6,7], // sizes according to the old HTML FONT SIZE
  193. getLabel: function(value, name){
  194. // summary:
  195. // Function used to generate the labels of the format dropdown
  196. // will return a formatted, or plain label based on the value
  197. // of the plainText option.
  198. // We're stuck using the deprecated FONT tag to correspond
  199. // with the size measurements used by the editor
  200. // value: String
  201. // The 'insert value' associated with a name
  202. // name: String
  203. // The text name of the value
  204. if(this.plainText){
  205. return name;
  206. }else{
  207. return "<font size=" + value + "'>" + name + "</font>";
  208. }
  209. },
  210. _setValueAttr: function(value, priorityChange){
  211. // summary:
  212. // Over-ride for the default action of setting the
  213. // widget value, maps the input to known values
  214. priorityChange = priorityChange !== false;
  215. if(value.indexOf && value.indexOf("px") != -1){
  216. var pixels = parseInt(value, 10);
  217. value = {10:1, 13:2, 16:3, 18:4, 24:5, 32:6, 48:7}[pixels] || value;
  218. }
  219. this.inherited(arguments, [value, priorityChange]);
  220. }
  221. });
  222. var _FormatBlockDropDown = declare("dijit._editor.plugins._FormatBlockDropDown", _FontDropDown, {
  223. // summary:
  224. // Dropdown to select a format (like paragraph or heading); goes in editor toolbar.
  225. // command: [public] String
  226. // The editor 'command' implemented by this plugin.
  227. command: "formatBlock",
  228. // values: [public] Array
  229. // The HTML format tags supported by this plugin
  230. values: ["noFormat", "p", "h1", "h2", "h3", "pre"],
  231. postCreate: function(){
  232. // Init and set the default value to no formatting. Update state will adjust it
  233. // as needed.
  234. this.inherited(arguments);
  235. this.set("value", "noFormat", false);
  236. },
  237. getLabel: function(value, name){
  238. // summary:
  239. // Function used to generate the labels of the format dropdown
  240. // will return a formatted, or plain label based on the value
  241. // of the plainText option.
  242. // value: String
  243. // The 'insert value' associated with a name
  244. // name: String
  245. // The text name of the value
  246. if(this.plainText || value == "noFormat"){
  247. return name;
  248. }else{
  249. return "<" + value + ">" + name + "</" + value + ">";
  250. }
  251. },
  252. _execCommand: function(editor, command, choice){
  253. // summary:
  254. // Over-ride for default exec-command label.
  255. // Allows us to treat 'none' as special.
  256. if(choice === "noFormat"){
  257. var start;
  258. var end;
  259. var sel = rangeapi.getSelection(editor.window);
  260. if(sel && sel.rangeCount > 0){
  261. var range = sel.getRangeAt(0);
  262. var node, tag;
  263. if(range){
  264. start = range.startContainer;
  265. end = range.endContainer;
  266. // find containing nodes of start/end.
  267. while(start && start !== editor.editNode &&
  268. start !== editor.document.body &&
  269. start.nodeType !== 1){
  270. start = start.parentNode;
  271. }
  272. while(end && end !== editor.editNode &&
  273. end !== editor.document.body &&
  274. end.nodeType !== 1){
  275. end = end.parentNode;
  276. }
  277. var processChildren = lang.hitch(this, function(node, ary){
  278. if(node.childNodes && node.childNodes.length){
  279. var i;
  280. for(i = 0; i < node.childNodes.length; i++){
  281. var c = node.childNodes[i];
  282. if(c.nodeType == 1){
  283. if(win.withGlobal(editor.window, "inSelection", selectionapi, [c])){
  284. var tag = c.tagName? c.tagName.toLowerCase(): "";
  285. if(array.indexOf(this.values, tag) !== -1){
  286. ary.push(c);
  287. }
  288. processChildren(c, ary);
  289. }
  290. }
  291. }
  292. }
  293. });
  294. var unformatNodes = lang.hitch(this, function(nodes){
  295. // summary:
  296. // Internal function to clear format nodes.
  297. // nodes:
  298. // The array of nodes to strip formatting from.
  299. if(nodes && nodes.length){
  300. editor.beginEditing();
  301. while(nodes.length){
  302. this._removeFormat(editor, nodes.pop());
  303. }
  304. editor.endEditing();
  305. }
  306. });
  307. var clearNodes = [];
  308. if(start == end){
  309. //Contained within the same block, may be collapsed, but who cares, see if we
  310. // have a block element to remove.
  311. var block;
  312. node = start;
  313. while(node && node !== editor.editNode && node !== editor.document.body){
  314. if(node.nodeType == 1){
  315. tag = node.tagName? node.tagName.toLowerCase(): "";
  316. if(array.indexOf(this.values, tag) !== -1){
  317. block = node;
  318. break;
  319. }
  320. }
  321. node = node.parentNode;
  322. }
  323. //Also look for all child nodes in the selection that may need to be
  324. //cleared of formatting
  325. processChildren(start, clearNodes);
  326. if(block){ clearNodes = [block].concat(clearNodes); }
  327. unformatNodes(clearNodes);
  328. }else{
  329. // Probably a multi select, so we have to process it. Whee.
  330. node = start;
  331. while(win.withGlobal(editor.window, "inSelection", selectionapi, [node])){
  332. if(node.nodeType == 1){
  333. tag = node.tagName? node.tagName.toLowerCase(): "";
  334. if(array.indexOf(this.values, tag) !== -1){
  335. clearNodes.push(node);
  336. }
  337. processChildren(node,clearNodes);
  338. }
  339. node = node.nextSibling;
  340. }
  341. unformatNodes(clearNodes);
  342. }
  343. editor.onDisplayChanged();
  344. }
  345. }
  346. }else{
  347. editor.execCommand(command, choice);
  348. }
  349. },
  350. _removeFormat: function(editor, node){
  351. // summary:
  352. // function to remove the block format node.
  353. // node:
  354. // The block format node to remove (and leave the contents behind)
  355. if(editor.customUndo){
  356. // So of course IE doesn't work right with paste-overs.
  357. // We have to do this manually, which is okay since IE already uses
  358. // customUndo and we turned it on for WebKit. WebKit pasted funny,
  359. // so couldn't use the execCommand approach
  360. while(node.firstChild){
  361. domConstruct.place(node.firstChild, node, "before");
  362. }
  363. node.parentNode.removeChild(node);
  364. }else{
  365. // Everyone else works fine this way, a paste-over and is native
  366. // undo friendly.
  367. win.withGlobal(editor.window,
  368. "selectElementChildren", selectionapi, [node]);
  369. var html = win.withGlobal(editor.window,
  370. "getSelectedHtml", selectionapi, [null]);
  371. win.withGlobal(editor.window,
  372. "selectElement", selectionapi, [node]);
  373. editor.execCommand("inserthtml", html||"");
  374. }
  375. }
  376. });
  377. // TODO: for 2.0, split into FontChoice plugin into three separate classes,
  378. // one for each command (and change registry below)
  379. var FontChoice = declare("dijit._editor.plugins.FontChoice", _Plugin,{
  380. // summary:
  381. // This plugin provides three drop downs for setting style in the editor
  382. // (font, font size, and format block), as controlled by command.
  383. //
  384. // description:
  385. // The commands provided by this plugin are:
  386. //
  387. // * fontName
  388. // | Provides a drop down to select from a list of font names
  389. // * fontSize
  390. // | Provides a drop down to select from a list of font sizes
  391. // * formatBlock
  392. // | Provides a drop down to select from a list of block styles
  393. // |
  394. //
  395. // which can easily be added to an editor by including one or more of the above commands
  396. // in the `plugins` attribute as follows:
  397. //
  398. // | plugins="['fontName','fontSize',...]"
  399. //
  400. // It is possible to override the default dropdown list by providing an Array for the `custom` property when
  401. // instantiating this plugin, e.g.
  402. //
  403. // | plugins="[{name:'dijit._editor.plugins.FontChoice', command:'fontName', custom:['Verdana','Myriad','Garamond']},...]"
  404. //
  405. // Alternatively, for `fontName` only, `generic:true` may be specified to provide a dropdown with
  406. // [CSS generic font families](http://www.w3.org/TR/REC-CSS2/fonts.html#generic-font-families)
  407. //
  408. // Note that the editor is often unable to properly handle font styling information defined outside
  409. // the context of the current editor instance, such as pre-populated HTML.
  410. // useDefaultCommand: [protected] Boolean
  411. // Override _Plugin.useDefaultCommand...
  412. // processing is handled by this plugin, not by dijit.Editor.
  413. useDefaultCommand: false,
  414. _initButton: function(){
  415. // summary:
  416. // Overrides _Plugin._initButton(), to initialize the FilteringSelect+label in toolbar,
  417. // rather than a simple button.
  418. // tags:
  419. // protected
  420. // Create the widget to go into the toolbar (the so-called "button")
  421. var clazz = {
  422. fontName: _FontNameDropDown,
  423. fontSize: _FontSizeDropDown,
  424. formatBlock: _FormatBlockDropDown
  425. }[this.command],
  426. params = this.params;
  427. // For back-compat reasons support setting custom values via "custom" parameter
  428. // rather than "values" parameter
  429. if(this.params.custom){
  430. params.values = this.params.custom;
  431. }
  432. var editor = this.editor;
  433. this.button = new clazz(lang.delegate({dir: editor.dir, lang: editor.lang}, params));
  434. // Reflect changes to the drop down in the editor
  435. this.connect(this.button.select, "onChange", function(choice){
  436. // User invoked change, since all internal updates set priorityChange to false and will
  437. // not trigger an onChange event.
  438. if(this.editor.focused){
  439. // put focus back in the iframe, unless focus has somehow been shifted out of the editor completely
  440. this.editor.focus();
  441. }
  442. if(this.command == "fontName" && choice.indexOf(" ") != -1){ choice = "'" + choice + "'"; }
  443. // Invoke, the editor already normalizes commands called through its
  444. // execCommand.
  445. if(this.button._execCommand){
  446. this.button._execCommand(this.editor, this.command, choice);
  447. }else{
  448. this.editor.execCommand(this.command, choice);
  449. }
  450. });
  451. },
  452. updateState: function(){
  453. // summary:
  454. // Overrides _Plugin.updateState(). This controls updating the menu
  455. // options to the right values on state changes in the document (that trigger a
  456. // test of the actions.)
  457. // It set value of drop down in toolbar to reflect font/font size/format block
  458. // of text at current caret position.
  459. // tags:
  460. // protected
  461. var _e = this.editor;
  462. var _c = this.command;
  463. if(!_e || !_e.isLoaded || !_c.length){ return; }
  464. if(this.button){
  465. var disabled = this.get("disabled");
  466. this.button.set("disabled", disabled);
  467. if(disabled){ return; }
  468. var value;
  469. try{
  470. value = _e.queryCommandValue(_c) || "";
  471. }catch(e){
  472. //Firefox may throw error above if the editor is just loaded, ignore it
  473. value = "";
  474. }
  475. // strip off single quotes, if any
  476. var quoted = lang.isString(value) && (value.match(/'([^']*)'/) || value.match(/"([^"]*)"/));
  477. if(quoted){ value = quoted[1]; }
  478. if(_c === "formatBlock"){
  479. if(!value || value == "p"){
  480. // Some browsers (WebKit) doesn't actually get the tag info right.
  481. // and IE returns paragraph when in a DIV!, so incorrect a lot,
  482. // so we have double-check it.
  483. value = null;
  484. var elem;
  485. // Try to find the current element where the caret is.
  486. var sel = rangeapi.getSelection(this.editor.window);
  487. if(sel && sel.rangeCount > 0){
  488. var range = sel.getRangeAt(0);
  489. if(range){
  490. elem = range.endContainer;
  491. }
  492. }
  493. // Okay, now see if we can find one of the formatting types we're in.
  494. while(elem && elem !== _e.editNode && elem !== _e.document){
  495. var tg = elem.tagName?elem.tagName.toLowerCase():"";
  496. if(tg && array.indexOf(this.button.values, tg) > -1){
  497. value = tg;
  498. break;
  499. }
  500. elem = elem.parentNode;
  501. }
  502. if(!value){
  503. // Still no value, so lets select 'none'.
  504. value = "noFormat";
  505. }
  506. }else{
  507. // Check that the block format is one allowed, if not,
  508. // null it so that it gets set to empty.
  509. if(array.indexOf(this.button.values, value) < 0){
  510. value = "noFormat";
  511. }
  512. }
  513. }
  514. if(value !== this.button.get("value")){
  515. // Set the value, but denote it is not a priority change, so no
  516. // onchange fires.
  517. this.button.set('value', value, false);
  518. }
  519. }
  520. }
  521. });
  522. // Register these plugins
  523. array.forEach(["fontName", "fontSize", "formatBlock"], function(name){
  524. _Plugin.registry[name] = function(args){
  525. return new FontChoice({
  526. command: name,
  527. plainText: args.plainText
  528. });
  529. };
  530. });
  531. });
  532. },
  533. 'url:dijit/templates/CheckedMenuItem.html':"<tr class=\"dijitReset dijitMenuItem\" data-dojo-attach-point=\"focusNode\" role=\"menuitemcheckbox\" tabIndex=\"-1\"\n\t\tdata-dojo-attach-event=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuItemIcon dijitCheckedMenuItemIcon\" data-dojo-attach-point=\"iconNode\"/>\n\t\t<span class=\"dijitCheckedMenuItemIconChar\">&#10003;</span>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" data-dojo-attach-point=\"containerNode,labelNode\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" data-dojo-attach-point=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">&#160;</td>\n</tr>\n",
  534. 'dijit/form/TextBox':function(){
  535. define([
  536. "dojo/_base/declare", // declare
  537. "dojo/dom-construct", // domConstruct.create
  538. "dojo/dom-style", // domStyle.getComputedStyle
  539. "dojo/_base/kernel", // kernel.deprecated
  540. "dojo/_base/lang", // lang.hitch
  541. "dojo/_base/sniff", // has("ie") has("mozilla")
  542. "dojo/_base/window", // win.doc.selection.createRange
  543. "./_FormValueWidget",
  544. "./_TextBoxMixin",
  545. "dojo/text!./templates/TextBox.html",
  546. ".." // to export dijit._setSelectionRange, remove in 2.0
  547. ], function(declare, domConstruct, domStyle, kernel, lang, has, win,
  548. _FormValueWidget, _TextBoxMixin, template, dijit){
  549. /*=====
  550. var _FormValueWidget = dijit.form._FormValueWidget;
  551. var _TextBoxMixin = dijit.form._TextBoxMixin;
  552. =====*/
  553. // module:
  554. // dijit/form/TextBox
  555. // summary:
  556. // A base class for textbox form inputs
  557. var TextBox = declare(/*====="dijit.form.TextBox", =====*/ [_FormValueWidget, _TextBoxMixin], {
  558. // summary:
  559. // A base class for textbox form inputs
  560. templateString: template,
  561. _singleNodeTemplate: '<input class="dijit dijitReset dijitLeft dijitInputField" data-dojo-attach-point="textbox,focusNode" autocomplete="off" type="${type}" ${!nameAttrSetting} />',
  562. _buttonInputDisabled: has("ie") ? "disabled" : "", // allows IE to disallow focus, but Firefox cannot be disabled for mousedown events
  563. baseClass: "dijitTextBox",
  564. postMixInProperties: function(){
  565. var type = this.type.toLowerCase();
  566. if(this.templateString && this.templateString.toLowerCase() == "input" || ((type == "hidden" || type == "file") && this.templateString == this.constructor.prototype.templateString)){
  567. this.templateString = this._singleNodeTemplate;
  568. }
  569. this.inherited(arguments);
  570. },
  571. _onInput: function(e){
  572. this.inherited(arguments);
  573. if(this.intermediateChanges){ // _TextBoxMixin uses onInput
  574. var _this = this;
  575. // the setTimeout allows the key to post to the widget input box
  576. setTimeout(function(){ _this._handleOnChange(_this.get('value'), false); }, 0);
  577. }
  578. },
  579. _setPlaceHolderAttr: function(v){
  580. this._set("placeHolder", v);
  581. if(!this._phspan){
  582. this._attachPoints.push('_phspan');
  583. // dijitInputField class gives placeHolder same padding as the input field
  584. // parent node already has dijitInputField class but it doesn't affect this <span>
  585. // since it's position: absolute.
  586. this._phspan = domConstruct.create('span',{ onmousedown:function(e){ e.preventDefault(); }, className:'dijitPlaceHolder dijitInputField'},this.textbox,'after');
  587. }
  588. this._phspan.innerHTML="";
  589. this._phspan.appendChild(document.createTextNode(v));
  590. this._updatePlaceHolder();
  591. },
  592. _updatePlaceHolder: function(){
  593. if(this._phspan){
  594. this._phspan.style.display=(this.placeHolder&&!this.focused&&!this.textbox.value)?"":"none";
  595. }
  596. },
  597. _setValueAttr: function(value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
  598. this.inherited(arguments);
  599. this._updatePlaceHolder();
  600. },
  601. getDisplayedValue: function(){
  602. // summary:
  603. // Deprecated. Use get('displayedValue') instead.
  604. // tags:
  605. // deprecated
  606. kernel.deprecated(this.declaredClass+"::getDisplayedValue() is deprecated. Use set('displayedValue') instead.", "", "2.0");
  607. return this.get('displayedValue');
  608. },
  609. setDisplayedValue: function(/*String*/ value){
  610. // summary:
  611. // Deprecated. Use set('displayedValue', ...) instead.
  612. // tags:
  613. // deprecated
  614. kernel.deprecated(this.declaredClass+"::setDisplayedValue() is deprecated. Use set('displayedValue', ...) instead.", "", "2.0");
  615. this.set('displayedValue', value);
  616. },
  617. _onBlur: function(e){
  618. if(this.disabled){ return; }
  619. this.inherited(arguments);
  620. this._updatePlaceHolder();
  621. },
  622. _onFocus: function(/*String*/ by){
  623. if(this.disabled || this.readOnly){ return; }
  624. this.inherited(arguments);
  625. this._updatePlaceHolder();
  626. }
  627. });
  628. if(has("ie") < 9){
  629. TextBox = declare(/*===== "dijit.form.TextBox.IEMixin", =====*/ TextBox, {
  630. declaredClass: "dijit.form.TextBox", // for user code referencing declaredClass
  631. _isTextSelected: function(){
  632. var range = win.doc.selection.createRange();
  633. var parent = range.parentElement();
  634. return parent == this.textbox && range.text.length == 0;
  635. },
  636. postCreate: function(){
  637. this.inherited(arguments);
  638. // IE INPUT tag fontFamily has to be set directly using STYLE
  639. // the setTimeout gives IE a chance to render the TextBox and to deal with font inheritance
  640. setTimeout(lang.hitch(this, function(){
  641. try{
  642. var s = domStyle.getComputedStyle(this.domNode); // can throw an exception if widget is immediately destroyed
  643. if(s){
  644. var ff = s.fontFamily;
  645. if(ff){
  646. var inputs = this.domNode.getElementsByTagName("INPUT");
  647. if(inputs){
  648. for(var i=0; i < inputs.length; i++){
  649. inputs[i].style.fontFamily = ff;
  650. }
  651. }
  652. }
  653. }
  654. }catch(e){/*when used in a Dialog, and this is called before the dialog is
  655. shown, s.fontFamily would trigger "Invalid Argument" error.*/}
  656. }), 0);
  657. }
  658. });
  659. // Overrides definition of _setSelectionRange from _TextBoxMixin (TODO: move to _TextBoxMixin.js?)
  660. dijit._setSelectionRange = _TextBoxMixin._setSelectionRange = function(/*DomNode*/ element, /*Number?*/ start, /*Number?*/ stop){
  661. if(element.createTextRange){
  662. var r = element.createTextRange();
  663. r.collapse(true);
  664. r.moveStart("character", -99999); // move to 0
  665. r.moveStart("character", start); // delta from 0 is the correct position
  666. r.moveEnd("character", stop-start);
  667. r.select();
  668. }
  669. }
  670. }else if(has("mozilla")){
  671. TextBox = declare(/*===== "dijit.form.TextBox.MozMixin", =====*/TextBox, {
  672. declaredClass: "dijit.form.TextBox", // for user code referencing declaredClass
  673. _onBlur: function(e){
  674. this.inherited(arguments);
  675. if(this.selectOnClick){
  676. // clear selection so that the next mouse click doesn't reselect
  677. this.textbox.selectionStart = this.textbox.selectionEnd = undefined;
  678. }
  679. }
  680. });
  681. }else{
  682. TextBox.prototype.declaredClass = "dijit.form.TextBox";
  683. }
  684. lang.setObject("dijit.form.TextBox", TextBox); // don't do direct assignment, it confuses API doc parser
  685. return TextBox;
  686. });
  687. },
  688. 'dojo/currency':function(){
  689. define(["./_base/kernel", "./_base/lang", "./_base/array", "./number", "./i18n", "./i18n!./cldr/nls/currency", "./cldr/monetary"], function(dojo, lang, darray, dnumber, i18n, nlsCurrency, cldrMonetary) {
  690. // module:
  691. // dojo/currency
  692. // summary:
  693. // TODOC
  694. lang.getObject("currency", true, dojo);
  695. /*=====
  696. dojo.currency = {
  697. // summary: localized formatting and parsing routines for currencies
  698. //
  699. // description: extends dojo.number to provide culturally-appropriate formatting of values
  700. // in various world currencies, including use of a currency symbol. The currencies are specified
  701. // by a three-letter international symbol in all uppercase, and support for the currencies is
  702. // provided by the data in `dojo.cldr`. The scripts generating dojo.cldr specify which
  703. // currency support is included. A fixed number of decimal places is determined based
  704. // on the currency type and is not determined by the 'pattern' argument. The fractional
  705. // portion is optional, by default, and variable length decimals are not supported.
  706. }
  707. =====*/
  708. dojo.currency._mixInDefaults = function(options){
  709. options = options || {};
  710. options.type = "currency";
  711. // Get locale-dependent currency data, like the symbol
  712. var bundle = i18n.getLocalization("dojo.cldr", "currency", options.locale) || {};
  713. // Mixin locale-independent currency data, like # of places
  714. var iso = options.currency;
  715. var data = cldrMonetary.getData(iso);
  716. darray.forEach(["displayName","symbol","group","decimal"], function(prop){
  717. data[prop] = bundle[iso+"_"+prop];
  718. });
  719. data.fractional = [true, false];
  720. // Mixin with provided options
  721. return lang.mixin(data, options);
  722. };
  723. /*=====
  724. dojo.declare("dojo.currency.__FormatOptions", [dojo.number.__FormatOptions], {
  725. // type: String?
  726. // Should not be set. Value is assumed to be "currency".
  727. // symbol: String?
  728. // localized currency symbol. The default will be looked up in table of supported currencies in `dojo.cldr`
  729. // A [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code will be used if not found.
  730. // currency: String?
  731. // an [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code, a three letter sequence like "USD".
  732. // For use with dojo.currency only.
  733. // places: Number?
  734. // number of decimal places to show. Default is defined based on which currency is used.
  735. type: "",
  736. symbol: "",
  737. currency: "",
  738. places: ""
  739. });
  740. =====*/
  741. dojo.currency.format = function(/*Number*/value, /*dojo.currency.__FormatOptions?*/options){
  742. // summary:
  743. // Format a Number as a currency, using locale-specific settings
  744. //
  745. // description:
  746. // Create a string from a Number using a known, localized pattern.
  747. // [Formatting patterns](http://www.unicode.org/reports/tr35/#Number_Elements)
  748. // appropriate to the locale are chosen from the [CLDR](http://unicode.org/cldr)
  749. // as well as the appropriate symbols and delimiters and number of decimal places.
  750. //
  751. // value:
  752. // the number to be formatted.
  753. return dnumber.format(value, dojo.currency._mixInDefaults(options));
  754. };
  755. dojo.currency.regexp = function(/*dojo.number.__RegexpOptions?*/options){
  756. //
  757. // summary:
  758. // Builds the regular needed to parse a currency value
  759. //
  760. // description:
  761. // Returns regular expression with positive and negative match, group and decimal separators
  762. // Note: the options.places default, the number of decimal places to accept, is defined by the currency type.
  763. return dnumber.regexp(dojo.currency._mixInDefaults(options)); // String
  764. };
  765. /*=====
  766. dojo.declare("dojo.currency.__ParseOptions", [dojo.number.__ParseOptions], {
  767. // type: String?
  768. // Should not be set. Value is assumed to be currency.
  769. // currency: String?
  770. // an [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code, a three letter sequence like "USD".
  771. // For use with dojo.currency only.
  772. // symbol: String?
  773. // localized currency symbol. The default will be looked up in table of supported currencies in `dojo.cldr`
  774. // A [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code will be used if not found.
  775. // places: Number?
  776. // fixed number of decimal places to accept. The default is determined based on which currency is used.
  777. // fractional: Boolean?|Array?
  778. // Whether to include the fractional portion, where the number of decimal places are implied by the currency
  779. // or explicit 'places' parameter. The value [true,false] makes the fractional portion optional.
  780. // By default for currencies, it the fractional portion is optional.
  781. type: "",
  782. currency: "",
  783. symbol: "",
  784. places: "",
  785. fractional: ""
  786. });
  787. =====*/
  788. dojo.currency.parse = function(/*String*/expression, /*dojo.currency.__ParseOptions?*/options){
  789. //
  790. // summary:
  791. // Convert a properly formatted currency string to a primitive Number,
  792. // using locale-specific settings.
  793. //
  794. // description:
  795. // Create a Number from a string using a known, localized pattern.
  796. // [Formatting patterns](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  797. // are chosen appropriate to the locale, as well as the appropriate symbols and delimiters
  798. // and number of decimal places.
  799. //
  800. // expression: A string representation of a currency value
  801. return dnumber.parse(expression, dojo.currency._mixInDefaults(options));
  802. };
  803. return dojo.currency;
  804. });
  805. },
  806. 'dijit/DialogUnderlay':function(){
  807. define([
  808. "dojo/_base/declare", // declare
  809. "dojo/dom-attr", // domAttr.set
  810. "dojo/_base/window", // win.body
  811. "dojo/window", // winUtils.getBox
  812. "./_Widget",
  813. "./_TemplatedMixin",
  814. "./BackgroundIframe"
  815. ], function(declare, domAttr, win, winUtils, _Widget, _TemplatedMixin, BackgroundIframe){
  816. /*=====
  817. var _Widget = dijit._Widget;
  818. var _TemplatedMixin = dijit._TemplatedMixin;
  819. =====*/
  820. // module:
  821. // dijit/DialogUnderlay
  822. // summary:
  823. // The component that blocks the screen behind a `dijit.Dialog`
  824. return declare("dijit.DialogUnderlay", [_Widget, _TemplatedMixin], {
  825. // summary:
  826. // The component that blocks the screen behind a `dijit.Dialog`
  827. //
  828. // description:
  829. // A component used to block input behind a `dijit.Dialog`. Only a single
  830. // instance of this widget is created by `dijit.Dialog`, and saved as
  831. // a reference to be shared between all Dialogs as `dijit._underlay`
  832. //
  833. // The underlay itself can be styled based on and id:
  834. // | #myDialog_underlay { background-color:red; }
  835. //
  836. // In the case of `dijit.Dialog`, this id is based on the id of the Dialog,
  837. // suffixed with _underlay.
  838. // Template has two divs; outer div is used for fade-in/fade-out, and also to hold background iframe.
  839. // Inner div has opacity specified in CSS file.
  840. templateString: "<div class='dijitDialogUnderlayWrapper'><div class='dijitDialogUnderlay' data-dojo-attach-point='node'></div></div>",
  841. // Parameters on creation or updatable later
  842. // dialogId: String
  843. // Id of the dialog.... DialogUnderlay's id is based on this id
  844. dialogId: "",
  845. // class: String
  846. // This class name is used on the DialogUnderlay node, in addition to dijitDialogUnderlay
  847. "class": "",
  848. _setDialogIdAttr: function(id){
  849. domAttr.set(this.node, "id", id + "_underlay");
  850. this._set("dialogId", id);
  851. },
  852. _setClassAttr: function(clazz){
  853. this.node.className = "dijitDialogUnderlay " + clazz;
  854. this._set("class", clazz);
  855. },
  856. postCreate: function(){
  857. // summary:
  858. // Append the underlay to the body
  859. win.body().appendChild(this.domNode);
  860. },
  861. layout: function(){
  862. // summary:
  863. // Sets the background to the size of the viewport
  864. //
  865. // description:
  866. // Sets the background to the size of the viewport (rather than the size
  867. // of the document) since we need to cover the whole browser window, even
  868. // if the document is only a few lines long.
  869. // tags:
  870. // private
  871. var is = this.node.style,
  872. os = this.domNode.style;
  873. // hide the background temporarily, so that the background itself isn't
  874. // causing scrollbars to appear (might happen when user shrinks browser
  875. // window and then we are called to resize)
  876. os.display = "none";
  877. // then resize and show
  878. var viewport = winUtils.getBox();
  879. os.top = viewport.t + "px";
  880. os.left = viewport.l + "px";
  881. is.width = viewport.w + "px";
  882. is.height = viewport.h + "px";
  883. os.display = "block";
  884. },
  885. show: function(){
  886. // summary:
  887. // Show the dialog underlay
  888. this.domNode.style.display = "block";
  889. this.layout();
  890. this.bgIframe = new BackgroundIframe(this.domNode);
  891. },
  892. hide: function(){
  893. // summary:
  894. // Hides the dialog underlay
  895. this.bgIframe.destroy();
  896. delete this.bgIframe;
  897. this.domNode.style.display = "none";
  898. }
  899. });
  900. });
  901. },
  902. 'url:dijit/form/templates/ComboButton.html':"<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tcellspacing='0' cellpadding='0' role=\"presentation\"\n\t><tbody role=\"presentation\"><tr role=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonNode\" data-dojo-attach-point=\"buttonNode\" data-dojo-attach-event=\"ondijitclick:_onClick,onkeypress:_onButtonKeyPress\"\n\t\t><div id=\"${id}_button\" class=\"dijitReset dijitButtonContents\"\n\t\t\tdata-dojo-attach-point=\"titleNode\"\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\n\t\t\t><div class=\"dijitReset dijitInline dijitIcon\" data-dojo-attach-point=\"iconNode\" role=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitInline dijitButtonText\" id=\"${id}_label\" data-dojo-attach-point=\"containerNode\" role=\"presentation\"></div\n\t\t></div\n\t\t></td\n\t\t><td id=\"${id}_arrow\" class='dijitReset dijitRight dijitButtonNode dijitArrowButton'\n\t\t\tdata-dojo-attach-point=\"_popupStateNode,focusNode,_buttonNode\"\n\t\t\tdata-dojo-attach-event=\"onkeypress:_onArrowKeyPress\"\n\t\t\ttitle=\"${optionsTitle}\"\n\t\t\trole=\"button\" aria-haspopup=\"true\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" role=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" role=\"presentation\">&#9660;</div\n\t\t></td\n\t\t><td style=\"display:none !important;\"\n\t\t\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" data-dojo-attach-point=\"valueNode\"\n\t\t/></td></tr></tbody\n></table>\n",
  903. 'dijit/layout/ScrollingTabController':function(){
  904. define([
  905. "dojo/_base/array", // array.forEach
  906. "dojo/_base/declare", // declare
  907. "dojo/dom-class", // domClass.add domClass.contains
  908. "dojo/dom-geometry", // domGeometry.contentBox
  909. "dojo/dom-style", // domStyle.style
  910. "dojo/_base/fx", // Animation
  911. "dojo/_base/lang", // lang.hitch
  912. "dojo/query", // query
  913. "dojo/_base/sniff", // has("ie"), has("webkit"), has("quirks")
  914. "../registry", // registry.byId()
  915. "dojo/text!./templates/ScrollingTabController.html",
  916. "dojo/text!./templates/_ScrollingTabControllerButton.html",
  917. "./TabController",
  918. "./utils", // marginBox2contextBox, layoutChildren
  919. "../_WidgetsInTemplateMixin",
  920. "../Menu",
  921. "../MenuItem",
  922. "../form/Button",
  923. "../_HasDropDown",
  924. "dojo/NodeList-dom" // NodeList.style
  925. ], function(array, declare, domClass, domGeometry, domStyle, fx, lang, query, has,
  926. registry, tabControllerTemplate, buttonTemplate, TabController, layoutUtils, _WidgetsInTemplateMixin,
  927. Menu, MenuItem, Button, _HasDropDown){
  928. /*=====
  929. var _WidgetsInTemplateMixin = dijit._WidgetsInTemplateMixin;
  930. var Menu = dijit.Menu;
  931. var _HasDropDown = dijit._HasDropDown;
  932. var TabController = dijit.layout.TabController;
  933. =====*/
  934. // module:
  935. // dijit/layout/ScrollingTabController
  936. // summary:
  937. // Set of tabs with left/right arrow keys and a menu to switch between tabs not
  938. // all fitting on a single row.
  939. var ScrollingTabController = declare("dijit.layout.ScrollingTabController", [TabController, _WidgetsInTemplateMixin], {
  940. // summary:
  941. // Set of tabs with left/right arrow keys and a menu to switch between tabs not
  942. // all fitting on a single row.
  943. // Works only for horizontal tabs (either above or below the content, not to the left
  944. // or right).
  945. // tags:
  946. // private
  947. baseClass: "dijitTabController dijitScrollingTabController",
  948. templateString: tabControllerTemplate,
  949. // useMenu: [const] Boolean
  950. // True if a menu should be used to select tabs when they are too
  951. // wide to fit the TabContainer, false otherwise.
  952. useMenu: true,
  953. // useSlider: [const] Boolean
  954. // True if a slider should be used to select tabs when they are too
  955. // wide to fit the TabContainer, false otherwise.
  956. useSlider: true,
  957. // tabStripClass: [const] String
  958. // The css class to apply to the tab strip, if it is visible.
  959. tabStripClass: "",
  960. widgetsInTemplate: true,
  961. // _minScroll: Number
  962. // The distance in pixels from the edge of the tab strip which,
  963. // if a scroll animation is less than, forces the scroll to
  964. // go all the way to the left/right.
  965. _minScroll: 5,
  966. // Override default behavior mapping class to DOMNode
  967. _setClassAttr: { node: "containerNode", type: "class" },
  968. buildRendering: function(){
  969. this.inherited(arguments);
  970. var n = this.domNode;
  971. this.scrollNode = this.tablistWrapper;
  972. this._initButtons();
  973. if(!this.tabStripClass){
  974. this.tabStripClass = "dijitTabContainer" +
  975. this.tabPosition.charAt(0).toUpperCase() +
  976. this.tabPosition.substr(1).replace(/-.*/, "") +
  977. "None";
  978. domClass.add(n, "tabStrip-disabled")
  979. }
  980. domClass.add(this.tablistWrapper, this.tabStripClass);
  981. },
  982. onStartup: function(){
  983. this.inherited(arguments);
  984. // TabController is hidden until it finishes drawing, to give
  985. // a less visually jumpy instantiation. When it's finished, set visibility to ""
  986. // to that the tabs are hidden/shown depending on the container's visibility setting.
  987. domStyle.set(this.domNode, "visibility", "");
  988. this._postStartup = true;
  989. },
  990. onAddChild: function(page, insertIndex){
  991. this.inherited(arguments);
  992. // changes to the tab button label or iconClass will have changed the width of the
  993. // buttons, so do a resize
  994. array.forEach(["label", "iconClass"], function(attr){
  995. this.pane2watches[page.id].push(
  996. this.pane2button[page.id].watch(attr, lang.hitch(this, function(){
  997. if(this._postStartup && this._dim){
  998. this.resize(this._dim);
  999. }
  1000. }))
  1001. );
  1002. }, this);
  1003. // Increment the width of the wrapper when a tab is added
  1004. // This makes sure that the buttons never wrap.
  1005. // The value 200 is chosen as it should be bigger than most
  1006. // Tab button widths.
  1007. domStyle.set(this.containerNode, "width",
  1008. (domStyle.get(this.containerNode, "width") + 200) + "px");
  1009. },
  1010. onRemoveChild: function(page, insertIndex){
  1011. // null out _selectedTab because we are about to delete that dom node
  1012. var button = this.pane2button[page.id];
  1013. if(this._selectedTab === button.domNode){
  1014. this._selectedTab = null;
  1015. }
  1016. this.inherited(arguments);
  1017. },
  1018. _initButtons: function(){
  1019. // summary:
  1020. // Creates the buttons used to scroll to view tabs that
  1021. // may not be visible if the TabContainer is too narrow.
  1022. // Make a list of the buttons to display when the tab labels become
  1023. // wider than the TabContainer, and hide the other buttons.
  1024. // Also gets the total width of the displayed buttons.
  1025. this._btnWidth = 0;
  1026. this._buttons = query("> .tabStripButton", this.domNode).filter(function(btn){
  1027. if((this.useMenu && btn == this._menuBtn.domNode) ||
  1028. (this.useSlider && (btn == this._rightBtn.domNode || btn == this._leftBtn.domNode))){
  1029. this._btnWidth += domGeometry.getMarginSize(btn).w;
  1030. return true;
  1031. }else{
  1032. domStyle.set(btn, "display", "none");
  1033. return false;
  1034. }
  1035. }, this);
  1036. },
  1037. _getTabsWidth: function(){
  1038. var children = this.getChildren();
  1039. if(children.length){
  1040. var leftTab = children[this.isLeftToRight() ? 0 : children.length - 1].domNode,
  1041. rightTab = children[this.isLeftToRight() ? children.length - 1 : 0].domNode;
  1042. return rightTab.offsetLeft + domStyle.get(rightTab, "width") - leftTab.offsetLeft;
  1043. }else{
  1044. return 0;
  1045. }
  1046. },
  1047. _enableBtn: function(width){
  1048. // summary:
  1049. // Determines if the tabs are wider than the width of the TabContainer, and
  1050. // thus that we need to display left/right/menu navigation buttons.
  1051. var tabsWidth = this._getTabsWidth();
  1052. width = width || domStyle.get(this.scrollNode, "width");
  1053. return tabsWidth > 0 && width < tabsWidth;
  1054. },
  1055. resize: function(dim){
  1056. // summary:
  1057. // Hides or displays the buttons used to scroll the tab list and launch the menu
  1058. // that selects tabs.
  1059. // Save the dimensions to be used when a child is renamed.
  1060. this._dim = dim;
  1061. // Set my height to be my natural height (tall enough for one row of tab labels),
  1062. // and my content-box width based on margin-box width specified in dim parameter.
  1063. // But first reset scrollNode.height in case it was set by layoutChildren() call
  1064. // in a previous run of this method.
  1065. this.scrollNode.style.height = "auto";
  1066. var cb = this._contentBox = layoutUtils.marginBox2contentBox(this.domNode, {h: 0, w: dim.w});
  1067. cb.h = this.scrollNode.offsetHeight;
  1068. domGeometry.setContentSize(this.domNode, cb);
  1069. // Show/hide the left/right/menu navigation buttons depending on whether or not they
  1070. // are needed.
  1071. var enable = this._enableBtn(this._contentBox.w);
  1072. this._buttons.style("display", enable ? "" : "none");
  1073. // Position and size the navigation buttons and the tablist
  1074. this._leftBtn.layoutAlign = "left";
  1075. this._rightBtn.layoutAlign = "right";
  1076. this._menuBtn.layoutAlign = this.isLeftToRight() ? "right" : "left";
  1077. layoutUtils.layoutChildren(this.domNode, this._contentBox,
  1078. [this._menuBtn, this._leftBtn, this._rightBtn, {domNode: this.scrollNode, layoutAlign: "client"}]);
  1079. // set proper scroll so that selected tab is visible
  1080. if(this._selectedTab){
  1081. if(this._anim && this._anim.status() == "playing"){
  1082. this._anim.stop();
  1083. }
  1084. this.scrollNode.scrollLeft = this._convertToScrollLeft(this._getScrollForSelectedTab());
  1085. }
  1086. // Enable/disabled left right buttons depending on whether or not user can scroll to left or right
  1087. this._setButtonClass(this._getScroll());
  1088. this._postResize = true;
  1089. // Return my size so layoutChildren() can use it.
  1090. // Also avoids IE9 layout glitch on browser resize when scroll buttons present
  1091. return {h: this._contentBox.h, w: dim.w};
  1092. },
  1093. _getScroll: function(){
  1094. // summary:
  1095. // Returns the current scroll of the tabs where 0 means
  1096. // "scrolled all the way to the left" and some positive number, based on #
  1097. // of pixels of possible scroll (ex: 1000) means "scrolled all the way to the right"
  1098. return (this.isLeftToRight() || has("ie") < 8 || (has("ie") && has("quirks")) || has("webkit")) ? this.scrollNode.scrollLeft :
  1099. domStyle.get(this.containerNode, "width") - domStyle.get(this.scrollNode, "width")
  1100. + (has("ie") == 8 ? -1 : 1) * this.scrollNode.scrollLeft;
  1101. },
  1102. _convertToScrollLeft: function(val){
  1103. // summary:
  1104. // Given a scroll value where 0 means "scrolled all the way to the left"
  1105. // and some positive number, based on # of pixels of possible scroll (ex: 1000)
  1106. // means "scrolled all the way to the right", return value to set this.scrollNode.scrollLeft
  1107. // to achieve that scroll.
  1108. //
  1109. // This method is to adjust for RTL funniness in various browsers and versions.
  1110. if(this.isLeftToRight() || has("ie") < 8 || (has("ie") && has("quirks")) || has("webkit")){
  1111. return val;
  1112. }else{
  1113. var maxScroll = domStyle.get(this.containerNode, "width") - domStyle.get(this.scrollNode, "width");
  1114. return (has("ie") == 8 ? -1 : 1) * (val - maxScroll);
  1115. }
  1116. },
  1117. onSelectChild: function(/*dijit._Widget*/ page){
  1118. // summary:
  1119. // Smoothly scrolls to a tab when it is selected.
  1120. var tab = this.pane2button[page.id];
  1121. if(!tab || !page){return;}
  1122. var node = tab.domNode;
  1123. // Save the selection
  1124. if(node != this._selectedTab){
  1125. this._selectedTab = node;
  1126. // Scroll to the selected tab, except on startup, when scrolling is handled in resize()
  1127. if(this._postResize){
  1128. var sl = this._getScroll();
  1129. if(sl > node.offsetLeft ||
  1130. sl + domStyle.get(this.scrollNode, "width") <
  1131. node.offsetLeft + domStyle.get(node, "width")){
  1132. this.createSmoothScroll().play();
  1133. }
  1134. }
  1135. }
  1136. this.inherited(arguments);
  1137. },
  1138. _getScrollBounds: function(){
  1139. // summary:
  1140. // Returns the minimum and maximum scroll setting to show the leftmost and rightmost
  1141. // tabs (respectively)
  1142. var children = this.getChildren(),
  1143. scrollNodeWidth = domStyle.get(this.scrollNode, "width"), // about 500px
  1144. containerWidth = domStyle.get(this.containerNode, "width"), // 50,000px
  1145. maxPossibleScroll = containerWidth - scrollNodeWidth, // scrolling until right edge of containerNode visible
  1146. tabsWidth = this._getTabsWidth();
  1147. if(children.length && tabsWidth > scrollNodeWidth){
  1148. // Scrolling should happen
  1149. return {
  1150. min: this.isLeftToRight() ? 0 : children[children.length-1].domNode.offsetLeft,
  1151. max: this.isLeftToRight() ?
  1152. (children[children.length-1].domNode.offsetLeft + domStyle.get(children[children.length-1].domNode, "width")) - scrollNodeWidth :
  1153. maxPossibleScroll
  1154. };
  1155. }else{
  1156. // No scrolling needed, all tabs visible, we stay either scrolled to far left or far right (depending on dir)
  1157. var onlyScrollPosition = this.isLeftToRight() ? 0 : maxPossibleScroll;
  1158. return {
  1159. min: onlyScrollPosition,
  1160. max: onlyScrollPosition
  1161. };
  1162. }
  1163. },
  1164. _getScrollForSelectedTab: function(){
  1165. // summary:
  1166. // Returns the scroll value setting so that the selected tab
  1167. // will appear in the center
  1168. var w = this.scrollNode,
  1169. n = this._selectedTab,
  1170. scrollNodeWidth = domStyle.get(this.scrollNode, "width"),
  1171. scrollBounds = this._getScrollBounds();
  1172. // TODO: scroll minimal amount (to either right or left) so that
  1173. // selected tab is fully visible, and just return if it's already visible?
  1174. var pos = (n.offsetLeft + domStyle.get(n, "width")/2) - scrollNodeWidth/2;
  1175. pos = Math.min(Math.max(pos, scrollBounds.min), scrollBounds.max);
  1176. // TODO:
  1177. // If scrolling close to the left side or right side, scroll
  1178. // all the way to the left or right. See this._minScroll.
  1179. // (But need to make sure that doesn't scroll the tab out of view...)
  1180. return pos;
  1181. },
  1182. createSmoothScroll: function(x){
  1183. // summary:
  1184. // Creates a dojo._Animation object that smoothly scrolls the tab list
  1185. // either to a fixed horizontal pixel value, or to the selected tab.
  1186. // description:
  1187. // If an number argument is passed to the function, that horizontal
  1188. // pixel position is scrolled to. Otherwise the currently selected
  1189. // tab is scrolled to.
  1190. // x: Integer?
  1191. // An optional pixel value to scroll to, indicating distance from left.
  1192. // Calculate position to scroll to
  1193. if(arguments.length > 0){
  1194. // position specified by caller, just make sure it's within bounds
  1195. var scrollBounds = this._getScrollBounds();
  1196. x = Math.min(Math.max(x, scrollBounds.min), scrollBounds.max);
  1197. }else{
  1198. // scroll to center the current tab
  1199. x = this._getScrollForSelectedTab();
  1200. }
  1201. if(this._anim && this._anim.status() == "playing"){
  1202. this._anim.stop();
  1203. }
  1204. var self = this,
  1205. w = this.scrollNode,
  1206. anim = new fx.Animation({
  1207. beforeBegin: function(){
  1208. if(this.curve){ delete this.curve; }
  1209. var oldS = w.scrollLeft,
  1210. newS = self._convertToScrollLeft(x);
  1211. anim.curve = new fx._Line(oldS, newS);
  1212. },
  1213. onAnimate: function(val){
  1214. w.scrollLeft = val;
  1215. }
  1216. });
  1217. this._anim = anim;
  1218. // Disable/enable left/right buttons according to new scroll position
  1219. this._setButtonClass(x);
  1220. return anim; // dojo._Animation
  1221. },
  1222. _getBtnNode: function(/*Event*/ e){
  1223. // summary:
  1224. // Gets a button DOM node from a mouse click event.
  1225. // e:
  1226. // The mouse click event.
  1227. var n = e.target;
  1228. while(n && !domClass.contains(n, "tabStripButton")){
  1229. n = n.parentNode;
  1230. }
  1231. return n;
  1232. },
  1233. doSlideRight: function(/*Event*/ e){
  1234. // summary:
  1235. // Scrolls the menu to the right.
  1236. // e:
  1237. // The mouse click event.
  1238. this.doSlide(1, this._getBtnNode(e));
  1239. },
  1240. doSlideLeft: function(/*Event*/ e){
  1241. // summary:
  1242. // Scrolls the menu to the left.
  1243. // e:
  1244. // The mouse click event.
  1245. this.doSlide(-1,this._getBtnNode(e));
  1246. },
  1247. doSlide: function(/*Number*/ direction, /*DomNode*/ node){
  1248. // summary:
  1249. // Scrolls the tab list to the left or right by 75% of the widget width.
  1250. // direction:
  1251. // If the direction is 1, the widget scrolls to the right, if it is
  1252. // -1, it scrolls to the left.
  1253. if(node && domClass.contains(node, "dijitTabDisabled")){return;}
  1254. var sWidth = domStyle.get(this.scrollNode, "width");
  1255. var d = (sWidth * 0.75) * direction;
  1256. var to = this._getScroll() + d;
  1257. this._setButtonClass(to);
  1258. this.createSmoothScroll(to).play();
  1259. },
  1260. _setButtonClass: function(/*Number*/ scroll){
  1261. // summary:
  1262. // Disables the left scroll button if the tabs are scrolled all the way to the left,
  1263. // or the right scroll button in the opposite case.
  1264. // scroll: Integer
  1265. // amount of horizontal scroll
  1266. var scrollBounds = this._getScrollBounds();
  1267. this._leftBtn.set("disabled", scroll <= scrollBounds.min);
  1268. this._rightBtn.set("disabled", scroll >= scrollBounds.max);
  1269. }
  1270. });
  1271. var ScrollingTabControllerButtonMixin = declare("dijit.layout._ScrollingTabControllerButtonMixin", null, {
  1272. baseClass: "dijitTab tabStripButton",
  1273. templateString: buttonTemplate,
  1274. // Override inherited tabIndex: 0 from dijit.form.Button, because user shouldn't be
  1275. // able to tab to the left/right/menu buttons
  1276. tabIndex: "",
  1277. // Similarly, override FormWidget.isFocusable() because clicking a button shouldn't focus it
  1278. // either (this override avoids focus() call in FormWidget.js)
  1279. isFocusable: function(){ return false; }
  1280. });
  1281. /*=====
  1282. ScrollingTabControllerButtonMixin = dijit.layout._ScrollingTabControllerButtonMixin;
  1283. =====*/
  1284. // Class used in template
  1285. declare("dijit.layout._ScrollingTabControllerButton",
  1286. [Button, ScrollingTabControllerButtonMixin]);
  1287. // Class used in template
  1288. declare(
  1289. "dijit.layout._ScrollingTabControllerMenuButton",
  1290. [Button, _HasDropDown, ScrollingTabControllerButtonMixin],
  1291. {
  1292. // id of the TabContainer itself
  1293. containerId: "",
  1294. // -1 so user can't tab into the button, but so that button can still be focused programatically.
  1295. // Because need to move focus to the button (or somewhere) before the menu is hidden or IE6 will crash.
  1296. tabIndex: "-1",
  1297. isLoaded: function(){
  1298. // recreate menu every time, in case the TabContainer's list of children (or their icons/labels) have changed
  1299. return false;
  1300. },
  1301. loadDropDown: function(callback){
  1302. this.dropDown = new Menu({
  1303. id: this.containerId + "_menu",
  1304. dir: this.dir,
  1305. lang: this.lang,
  1306. textDir: this.textDir
  1307. });
  1308. var container = registry.byId(this.containerId);
  1309. array.forEach(container.getChildren(), function(page){
  1310. var menuItem = new MenuItem({
  1311. id: page.id + "_stcMi",
  1312. label: page.title,
  1313. iconClass: page.iconClass,
  1314. dir: page.dir,
  1315. lang: page.lang,
  1316. textDir: page.textDir,
  1317. onClick: function(){
  1318. container.selectChild(page);
  1319. }
  1320. });
  1321. this.dropDown.addChild(menuItem);
  1322. }, this);
  1323. callback();
  1324. },
  1325. closeDropDown: function(/*Boolean*/ focus){
  1326. this.inherited(arguments);
  1327. if(this.dropDown){
  1328. this.dropDown.destroyRecursive();
  1329. delete this.dropDown;
  1330. }
  1331. }
  1332. });
  1333. return ScrollingTabController;
  1334. });
  1335. },
  1336. 'dijit/_editor/html':function(){
  1337. define([
  1338. "dojo/_base/array",
  1339. "dojo/_base/lang", // lang.getObject
  1340. "dojo/_base/sniff", // has("ie")
  1341. ".." // for exporting symbols to dijit._editor (remove for 2.0)
  1342. ], function(array, lang, has, dijit){
  1343. // module:
  1344. // dijit/_editor/html
  1345. // summary:
  1346. // Utility functions used by editor
  1347. // Tests for DOMNode.attributes[] behavior:
  1348. // - dom-attributes-explicit - attributes[] only lists explicitly user specified attributes
  1349. // - dom-attributes-specified-flag (IE8) - need to check attr.specified flag to skip attributes user didn't specify
  1350. // - Otherwise, in IE6-7. attributes[] will list hundreds of values, so need to do outerHTML to get attrs instead.
  1351. var form = document.createElement("form");
  1352. has.add("dom-attributes-explicit", form.attributes.length == 0); // W3C
  1353. has.add("dom-attributes-specified-flag", form.attributes.length > 0 && form.attributes.length < 40); // IE8
  1354. lang.getObject("_editor", true, dijit);
  1355. dijit._editor.escapeXml=function(/*String*/str, /*Boolean?*/noSingleQuotes){
  1356. // summary:
  1357. // Adds escape sequences for special characters in XML: &<>"'
  1358. // Optionally skips escapes for single quotes
  1359. str = str.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;");
  1360. if(!noSingleQuotes){
  1361. str = str.replace(/'/gm, "&#39;");
  1362. }
  1363. return str; // string
  1364. };
  1365. dijit._editor.getNodeHtml=function(/* DomNode */node){
  1366. var output;
  1367. switch(node.nodeType){
  1368. case 1: //element node
  1369. var lName = node.nodeName.toLowerCase();
  1370. if(!lName || lName.charAt(0) == "/"){
  1371. // IE does some strange things with malformed HTML input, like
  1372. // treating a close tag </span> without an open tag <span>, as
  1373. // a new tag with tagName of /span. Corrupts output HTML, remove
  1374. // them. Other browsers don't prefix tags that way, so will
  1375. // never show up.
  1376. return "";
  1377. }
  1378. output = '<' + lName;
  1379. //store the list of attributes and sort it to have the
  1380. //attributes appear in the dictionary order
  1381. var attrarray = [], attrhash = {};
  1382. var attr;
  1383. if(has("dom-attributes-explicit") || has("dom-attributes-specified-flag")){
  1384. // IE8+ and all other browsers.
  1385. var i = 0;
  1386. while((attr = node.attributes[i++])){
  1387. // ignore all attributes starting with _dj which are
  1388. // internal temporary attributes used by the editor
  1389. var n = attr.name;
  1390. if(n.substr(0,3) !== '_dj' &&
  1391. (!has("dom-attributes-specified-flag") || attr.specified) &&
  1392. !(n in attrhash)){ // workaround repeated attributes bug in IE8 (LinkDialog test)
  1393. var v = attr.value;
  1394. if(n == 'src' || n == 'href'){
  1395. if(node.getAttribute('_djrealurl')){
  1396. v = node.getAttribute('_djrealurl');
  1397. }
  1398. }
  1399. if(has("ie") === 8 && n === "style"){
  1400. v = v.replace("HEIGHT:", "height:").replace("WIDTH:", "width:");
  1401. }
  1402. attrarray.push([n,v]);
  1403. attrhash[n] = v;
  1404. }
  1405. }
  1406. }else{
  1407. // IE6-7 code path
  1408. var clone = /^input$|^img$/i.test(node.nodeName) ? node : node.cloneNode(false);
  1409. var s = clone.outerHTML;
  1410. // Split up and manage the attrs via regexp
  1411. // similar to prettyPrint attr logic.
  1412. var rgxp_attrsMatch = /[\w-]+=("[^"]*"|'[^']*'|\S*)/gi
  1413. var attrSplit = s.match(rgxp_attrsMatch);
  1414. s = s.substr(0, s.indexOf('>'));
  1415. array.forEach(attrSplit, function(attr){
  1416. if(attr){
  1417. var idx = attr.indexOf("=");
  1418. if(idx > 0){
  1419. var key = attr.substring(0,idx);
  1420. if(key.substr(0,3) != '_dj'){
  1421. if(key == 'src' || key == 'href'){
  1422. if(node.getAttribute('_djrealurl')){
  1423. attrarray.push([key,node.getAttribute('_djrealurl')]);
  1424. return;
  1425. }
  1426. }
  1427. var val, match;
  1428. switch(key){
  1429. case 'style':
  1430. val = node.style.cssText.toLowerCase();
  1431. break;
  1432. case 'class':
  1433. val = node.className;
  1434. break;
  1435. case 'width':
  1436. if(lName === "img"){
  1437. // This somehow gets lost on IE for IMG tags and the like
  1438. // and we have to find it in outerHTML, known IE oddity.
  1439. match=/width=(\S+)/i.exec(s);
  1440. if(match){
  1441. val = match[1];
  1442. }
  1443. break;
  1444. }
  1445. case 'height':
  1446. if(lName === "img"){
  1447. // This somehow gets lost on IE for IMG tags and the like
  1448. // and we have to find it in outerHTML, known IE oddity.
  1449. match=/height=(\S+)/i.exec(s);
  1450. if(match){
  1451. val = match[1];
  1452. }
  1453. break;
  1454. }
  1455. default:
  1456. val = node.getAttribute(key);
  1457. }
  1458. if(val != null){
  1459. attrarray.push([key, val.toString()]);
  1460. }
  1461. }
  1462. }
  1463. }
  1464. }, this);
  1465. }
  1466. attrarray.sort(function(a,b){
  1467. return a[0] < b[0] ? -1 : (a[0] == b[0] ? 0 : 1);
  1468. });
  1469. var j = 0;
  1470. while((attr = attrarray[j++])){
  1471. output += ' ' + attr[0] + '="' +
  1472. (lang.isString(attr[1]) ? dijit._editor.escapeXml(attr[1], true) : attr[1]) + '"';
  1473. }
  1474. if(lName === "script"){
  1475. // Browsers handle script tags differently in how you get content,
  1476. // but innerHTML always seems to work, so insert its content that way
  1477. // Yes, it's bad to allow script tags in the editor code, but some people
  1478. // seem to want to do it, so we need to at least return them right.
  1479. // other plugins/filters can strip them.
  1480. output += '>' + node.innerHTML +'</' + lName + '>';
  1481. }else{
  1482. if(node.childNodes.length){
  1483. output += '>' + dijit._editor.getChildrenHtml(node)+'</' + lName +'>';
  1484. }else{
  1485. switch(lName){
  1486. case 'br':
  1487. case 'hr':
  1488. case 'img':
  1489. case 'input':
  1490. case 'base':
  1491. case 'meta':
  1492. case 'area':
  1493. case 'basefont':
  1494. // These should all be singly closed
  1495. output += ' />';
  1496. break;
  1497. default:
  1498. // Assume XML style separate closure for everything else.
  1499. output += '></' + lName + '>';
  1500. }
  1501. }
  1502. }
  1503. break;
  1504. case 4: // cdata
  1505. case 3: // text
  1506. // FIXME:
  1507. output = dijit._editor.escapeXml(node.nodeValue, true);
  1508. break;
  1509. case 8: //comment
  1510. // FIXME:
  1511. output = '<!--' + dijit._editor.escapeXml(node.nodeValue, true) + '-->';
  1512. break;
  1513. default:
  1514. output = "<!-- Element not recognized - Type: " + node.nodeType + " Name: " + node.nodeName + "-->";
  1515. }
  1516. return output;
  1517. };
  1518. dijit._editor.getChildrenHtml = function(/* DomNode */dom){
  1519. // summary:
  1520. // Returns the html content of a DomNode and children
  1521. var out = "";
  1522. if(!dom){ return out; }
  1523. var nodes = dom["childNodes"] || dom;
  1524. //IE issue.
  1525. //If we have an actual node we can check parent relationships on for IE,
  1526. //We should check, as IE sometimes builds invalid DOMS. If no parent, we can't check
  1527. //And should just process it and hope for the best.
  1528. var checkParent = !has("ie") || nodes !== dom;
  1529. var node, i = 0;
  1530. while((node = nodes[i++])){
  1531. //IE is broken. DOMs are supposed to be a tree. But in the case of malformed HTML, IE generates a graph
  1532. //meaning one node ends up with multiple references (multiple parents). This is totally wrong and invalid, but
  1533. //such is what it is. We have to keep track and check for this because otherise the source output HTML will have dups.
  1534. //No other browser generates a graph. Leave it to IE to break a fundamental DOM rule. So, we check the parent if we can
  1535. //If we can't, nothing more we can do other than walk it.
  1536. if(!checkParent || node.parentNode == dom){
  1537. out += dijit._editor.getNodeHtml(node);
  1538. }
  1539. }
  1540. return out; // String
  1541. };
  1542. return dijit._editor;
  1543. });
  1544. },
  1545. 'dijit/_HasDropDown':function(){
  1546. define([
  1547. "dojo/_base/declare", // declare
  1548. "dojo/_base/Deferred",
  1549. "dojo/_base/event", // event.stop
  1550. "dojo/dom", // dom.isDescendant
  1551. "dojo/dom-attr", // domAttr.set
  1552. "dojo/dom-class", // domClass.add domClass.contains domClass.remove
  1553. "dojo/dom-geometry", // domGeometry.marginBox domGeometry.position
  1554. "dojo/dom-style", // domStyle.set
  1555. "dojo/has",
  1556. "dojo/keys", // keys.DOWN_ARROW keys.ENTER keys.ESCAPE
  1557. "dojo/_base/lang", // lang.hitch lang.isFunction
  1558. "dojo/touch",
  1559. "dojo/_base/window", // win.doc
  1560. "./registry", // registry.byNode()
  1561. "./focus",
  1562. "./popup",
  1563. "./_FocusMixin",
  1564. "./Viewport"
  1565. ], function(declare, Deferred, event,dom, domAttr, domClass, domGeometry, domStyle, has, keys, lang, touch,
  1566. win, registry, focus, popup, _FocusMixin, Viewport){
  1567. /*=====
  1568. var _FocusMixin = dijit._FocusMixin;
  1569. =====*/
  1570. // module:
  1571. // dijit/_HasDropDown
  1572. // summary:
  1573. // Mixin for widgets that need drop down ability.
  1574. return declare("dijit._HasDropDown", _FocusMixin, {
  1575. // summary:
  1576. // Mixin for widgets that need drop down ability.
  1577. // _buttonNode: [protected] DomNode
  1578. // The button/icon/node to click to display the drop down.
  1579. // Can be set via a data-dojo-attach-point assignment.
  1580. // If missing, then either focusNode or domNode (if focusNode is also missing) will be used.
  1581. _buttonNode: null,
  1582. // _arrowWrapperNode: [protected] DomNode
  1583. // Will set CSS class dijitUpArrow, dijitDownArrow, dijitRightArrow etc. on this node depending
  1584. // on where the drop down is set to be positioned.
  1585. // Can be set via a data-dojo-attach-point assignment.
  1586. // If missing, then _buttonNode will be used.
  1587. _arrowWrapperNode: null,
  1588. // _popupStateNode: [protected] DomNode
  1589. // The node to set the popupActive class on.
  1590. // Can be set via a data-dojo-attach-point assignment.
  1591. // If missing, then focusNode or _buttonNode (if focusNode is missing) will be used.
  1592. _popupStateNode: null,
  1593. // _aroundNode: [protected] DomNode
  1594. // The node to display the popup around.
  1595. // Can be set via a data-dojo-attach-point assignment.
  1596. // If missing, then domNode will be used.
  1597. _aroundNode: null,
  1598. // dropDown: [protected] Widget
  1599. // The widget to display as a popup. This widget *must* be
  1600. // defined before the startup function is called.
  1601. dropDown: null,
  1602. // autoWidth: [protected] Boolean
  1603. // Set to true to make the drop down at least as wide as this
  1604. // widget. Set to false if the drop down should just be its
  1605. // default width
  1606. autoWidth: true,
  1607. // forceWidth: [protected] Boolean
  1608. // Set to true to make the drop down exactly as wide as this
  1609. // widget. Overrides autoWidth.
  1610. forceWidth: false,
  1611. // maxHeight: [protected] Integer
  1612. // The max height for our dropdown.
  1613. // Any dropdown taller than this will have scrollbars.
  1614. // Set to 0 for no max height, or -1 to limit height to available space in viewport
  1615. maxHeight: 0,
  1616. // dropDownPosition: [const] String[]
  1617. // This variable controls the position of the drop down.
  1618. // It's an array of strings with the following values:
  1619. //
  1620. // * before: places drop down to the left of the target node/widget, or to the right in
  1621. // the case of RTL scripts like Hebrew and Arabic
  1622. // * after: places drop down to the right of the target node/widget, or to the left in
  1623. // the case of RTL scripts like Hebrew and Arabic
  1624. // * above: drop down goes above target node
  1625. // * below: drop down goes below target node
  1626. //
  1627. // The list is positions is tried, in order, until a position is found where the drop down fits
  1628. // within the viewport.
  1629. //
  1630. dropDownPosition: ["below","above"],
  1631. // _stopClickEvents: Boolean
  1632. // When set to false, the click events will not be stopped, in
  1633. // case you want to use them in your subwidget
  1634. _stopClickEvents: true,
  1635. _onDropDownMouseDown: function(/*Event*/ e){
  1636. // summary:
  1637. // Callback when the user mousedown's on the arrow icon
  1638. if(this.disabled || this.readOnly){ return; }
  1639. // Prevent default to stop things like text selection, but don't stop propogation, so that:
  1640. // 1. TimeTextBox etc. can focusthe <input> on mousedown
  1641. // 2. dropDownButtonActive class applied by _CssStateMixin (on button depress)
  1642. // 3. user defined onMouseDown handler fires
  1643. //
  1644. // Also, don't call preventDefault() on MSPointerDown event (on IE10) because that prevents the button
  1645. // from getting focus, and then the focus manager doesn't know what's going on (#17262)
  1646. if(e.type != "MSPointerDown" && e.type != "pointerdown"){
  1647. e.preventDefault();
  1648. }
  1649. this._docHandler = this.connect(win.doc, touch.release, "_onDropDownMouseUp");
  1650. this.toggleDropDown();
  1651. },
  1652. _onDropDownMouseUp: function(/*Event?*/ e){
  1653. // summary:
  1654. // Callback when the user lifts their mouse after mouse down on the arrow icon.
  1655. // If the drop down is a simple menu and the mouse is over the menu, we execute it, otherwise, we focus our
  1656. // drop down widget. If the event is missing, then we are not
  1657. // a mouseup event.
  1658. //
  1659. // This is useful for the common mouse movement pattern
  1660. // with native browser <select> nodes:
  1661. // 1. mouse down on the select node (probably on the arrow)
  1662. // 2. move mouse to a menu item while holding down the mouse button
  1663. // 3. mouse up. this selects the menu item as though the user had clicked it.
  1664. if(e && this._docHandler){
  1665. this.disconnect(this._docHandler);
  1666. }
  1667. var dropDown = this.dropDown, overMenu = false;
  1668. if(e && this._opened){
  1669. // This code deals with the corner-case when the drop down covers the original widget,
  1670. // because it's so large. In that case mouse-up shouldn't select a value from the menu.
  1671. // Find out if our target is somewhere in our dropdown widget,
  1672. // but not over our _buttonNode (the clickable node)
  1673. var c = domGeometry.position(this._buttonNode, true);
  1674. if(!(e.pageX >= c.x && e.pageX <= c.x + c.w) ||
  1675. !(e.pageY >= c.y && e.pageY <= c.y + c.h)){
  1676. var t = e.target;
  1677. while(t && !overMenu){
  1678. if(domClass.contains(t, "dijitPopup")){
  1679. overMenu = true;
  1680. }else{
  1681. t = t.parentNode;
  1682. }
  1683. }
  1684. if(overMenu){
  1685. t = e.target;
  1686. if(dropDown.onItemClick){
  1687. var menuItem;
  1688. while(t && !(menuItem = registry.byNode(t))){
  1689. t = t.parentNode;
  1690. }
  1691. if(menuItem && menuItem.onClick && menuItem.getParent){
  1692. menuItem.getParent().onItemClick(menuItem, e);
  1693. }
  1694. }
  1695. return;
  1696. }
  1697. }
  1698. }
  1699. if(this._opened){
  1700. if(dropDown.focus && dropDown.autoFocus !== false){
  1701. // Focus the dropdown widget - do it on a delay so that we
  1702. // don't steal our own focus.
  1703. window.setTimeout(lang.hitch(dropDown, "focus"), 1);
  1704. }
  1705. }else{
  1706. // The drop down arrow icon probably can't receive focus, but widget itself should get focus.
  1707. // setTimeout() needed to make it work on IE (test DateTextBox)
  1708. setTimeout(lang.hitch(this, "focus"), 0);
  1709. }
  1710. if(has("ios")){
  1711. this._justGotMouseUp = true;
  1712. setTimeout(lang.hitch(this, function(){
  1713. this._justGotMouseUp = false;
  1714. }), 0);
  1715. }
  1716. },
  1717. _onDropDownClick: function(/*Event*/ e){
  1718. if(has("ios") && !this._justGotMouseUp){
  1719. // This branch fires on iPhone for ComboBox, because the button node is an <input> and doesn't
  1720. // generate touchstart/touchend events. Pretend we just got a mouse down / mouse up.
  1721. // The if(has("ios") is necessary since IE and desktop safari get spurious onclick events
  1722. // when there are nested tables (specifically, clicking on a table that holds a dijit.form.Select,
  1723. // but not on the Select itself, causes an onclick event on the Select)
  1724. this._onDropDownMouseDown(e);
  1725. this._onDropDownMouseUp(e);
  1726. }
  1727. // The drop down was already opened on mousedown/keydown; just need to call stopEvent().
  1728. if(this._stopClickEvents){
  1729. event.stop(e);
  1730. }
  1731. },
  1732. buildRendering: function(){
  1733. this.inherited(arguments);
  1734. this._buttonNode = this._buttonNode || this.focusNode || this.domNode;
  1735. this._popupStateNode = this._popupStateNode || this.focusNode || this._buttonNode;
  1736. // Add a class to the "dijitDownArrowButton" type class to _buttonNode so theme can set direction of arrow
  1737. // based on where drop down will normally appear
  1738. var defaultPos = {
  1739. "after" : this.isLeftToRight() ? "Right" : "Left",
  1740. "before" : this.isLeftToRight() ? "Left" : "Right",
  1741. "above" : "Up",
  1742. "below" : "Down",
  1743. "left" : "Left",
  1744. "right" : "Right"
  1745. }[this.dropDownPosition[0]] || this.dropDownPosition[0] || "Down";
  1746. domClass.add(this._arrowWrapperNode || this._buttonNode, "dijit" + defaultPos + "ArrowButton");
  1747. },
  1748. postCreate: function(){
  1749. // summary:
  1750. // set up nodes and connect our mouse and keyboard events
  1751. this.inherited(arguments);
  1752. this.connect(this._buttonNode, touch.press, "_onDropDownMouseDown");
  1753. this.connect(this._buttonNode, "onclick", "_onDropDownClick");
  1754. this.connect(this.focusNode, "onkeydown", "_onKey");
  1755. this.connect(this.focusNode, "onkeyup", "_onKeyUp");
  1756. },
  1757. destroy: function(){
  1758. if(this.dropDown){
  1759. // Destroy the drop down, unless it's already been destroyed. This can happen because
  1760. // the drop down is a direct child of <body> even though it's logically my child.
  1761. if(!this.dropDown._destroyed){
  1762. this.dropDown.destroyRecursive();
  1763. }
  1764. delete this.dropDown;
  1765. }
  1766. this.inherited(arguments);
  1767. },
  1768. _onKey: function(/*Event*/ e){
  1769. // summary:
  1770. // Callback when the user presses a key while focused on the button node
  1771. if(this.disabled || this.readOnly){ return; }
  1772. var d = this.dropDown, target = e.target;
  1773. if(d && this._opened && d.handleKey){
  1774. if(d.handleKey(e) === false){
  1775. /* false return code means that the drop down handled the key */
  1776. event.stop(e);
  1777. return;
  1778. }
  1779. }
  1780. if(d && this._opened && e.keyCode == keys.ESCAPE){
  1781. this.closeDropDown();
  1782. event.stop(e);
  1783. }else if(!this._opened &&
  1784. (e.keyCode == keys.DOWN_ARROW ||
  1785. ( (e.keyCode == keys.ENTER || e.keyCode == dojo.keys.SPACE) &&
  1786. //ignore enter and space if the event is for a text input
  1787. ((target.tagName || "").toLowerCase() !== 'input' ||
  1788. (target.type && target.type.toLowerCase() !== 'text'))))){
  1789. // Toggle the drop down, but wait until keyup so that the drop down doesn't
  1790. // get a stray keyup event, or in the case of key-repeat (because user held
  1791. // down key for too long), stray keydown events
  1792. this._toggleOnKeyUp = true;
  1793. event.stop(e);
  1794. }
  1795. },
  1796. _onKeyUp: function(){
  1797. if(this._toggleOnKeyUp){
  1798. delete this._toggleOnKeyUp;
  1799. this.toggleDropDown();
  1800. var d = this.dropDown; // drop down may not exist until toggleDropDown() call
  1801. if(d && d.focus){
  1802. setTimeout(lang.hitch(d, "focus"), 1);
  1803. }
  1804. }
  1805. },
  1806. _onBlur: function(){
  1807. // summary:
  1808. // Called magically when focus has shifted away from this widget and it's dropdown
  1809. // Don't focus on button if the user has explicitly focused on something else (happens
  1810. // when user clicks another control causing the current popup to close)..
  1811. // But if focus is inside of the drop down then reset focus to me, because IE doesn't like
  1812. // it when you display:none a node with focus.
  1813. var focusMe = focus.curNode && this.dropDown && dom.isDescendant(focus.curNode, this.dropDown.domNode);
  1814. this.closeDropDown(focusMe);
  1815. this.inherited(arguments);
  1816. },
  1817. isLoaded: function(){
  1818. // summary:
  1819. // Returns true if the dropdown exists and it's data is loaded. This can
  1820. // be overridden in order to force a call to loadDropDown().
  1821. // tags:
  1822. // protected
  1823. return true;
  1824. },
  1825. loadDropDown: function(/*Function*/ loadCallback){
  1826. // summary:
  1827. // Creates the drop down if it doesn't exist, loads the data
  1828. // if there's an href and it hasn't been loaded yet, and then calls
  1829. // the given callback.
  1830. // tags:
  1831. // protected
  1832. // TODO: for 2.0, change API to return a Deferred, instead of calling loadCallback?
  1833. loadCallback();
  1834. },
  1835. loadAndOpenDropDown: function(){
  1836. // summary:
  1837. // Creates the drop down if it doesn't exist, loads the data
  1838. // if there's an href and it hasn't been loaded yet, and
  1839. // then opens the drop down. This is basically a callback when the
  1840. // user presses the down arrow button to open the drop down.
  1841. // returns: Deferred
  1842. // Deferred for the drop down widget that
  1843. // fires when drop down is created and loaded
  1844. // tags:
  1845. // protected
  1846. var d = new Deferred(),
  1847. afterLoad = lang.hitch(this, function(){
  1848. this.openDropDown();
  1849. d.resolve(this.dropDown);
  1850. });
  1851. if(!this.isLoaded()){
  1852. this.loadDropDown(afterLoad);
  1853. }else{
  1854. afterLoad();
  1855. }
  1856. return d;
  1857. },
  1858. toggleDropDown: function(){
  1859. // summary:
  1860. // Callback when the user presses the down arrow button or presses
  1861. // the down arrow key to open/close the drop down.
  1862. // Toggle the drop-down widget; if it is up, close it, if not, open it
  1863. // tags:
  1864. // protected
  1865. if(this.disabled || this.readOnly){ return; }
  1866. if(!this._opened){
  1867. this.loadAndOpenDropDown();
  1868. }else{
  1869. this.closeDropDown();
  1870. }
  1871. },
  1872. openDropDown: function(){
  1873. // summary:
  1874. // Opens the dropdown for this widget. To be called only when this.dropDown
  1875. // has been created and is ready to display (ie, it's data is loaded).
  1876. // returns:
  1877. // return value of dijit.popup.open()
  1878. // tags:
  1879. // protected
  1880. var dropDown = this.dropDown,
  1881. ddNode = dropDown.domNode,
  1882. aroundNode = this._aroundNode || this.domNode,
  1883. self = this;
  1884. // Prepare our popup's height and honor maxHeight if it exists.
  1885. // TODO: isn't maxHeight dependent on the return value from dijit.popup.open(),
  1886. // ie, dependent on how much space is available (BK)
  1887. if(!this._preparedNode){
  1888. this._preparedNode = true;
  1889. // Check if we have explicitly set width and height on the dropdown widget dom node
  1890. if(ddNode.style.width){
  1891. this._explicitDDWidth = true;
  1892. }
  1893. if(ddNode.style.height){
  1894. this._explicitDDHeight = true;
  1895. }
  1896. }
  1897. // Code for resizing dropdown (height limitation, or increasing width to match my width)
  1898. if(this.maxHeight || this.forceWidth || this.autoWidth){
  1899. var myStyle = {
  1900. display: "",
  1901. visibility: "hidden"
  1902. };
  1903. if(!this._explicitDDWidth){
  1904. myStyle.width = "";
  1905. }
  1906. if(!this._explicitDDHeight){
  1907. myStyle.height = "";
  1908. }
  1909. domStyle.set(ddNode, myStyle);
  1910. // Figure out maximum height allowed (if there is a height restriction)
  1911. var maxHeight = this.maxHeight;
  1912. if(maxHeight == -1){
  1913. // limit height to space available in viewport either above or below my domNode
  1914. // (whichever side has more room)
  1915. var viewport = Viewport.getEffectiveBox(this.ownerDocument),
  1916. position = domGeometry.position(aroundNode, false);
  1917. maxHeight = Math.floor(Math.max(position.y, viewport.h - (position.y + position.h)));
  1918. }
  1919. // Attach dropDown to DOM and make make visibility:hidden rather than display:none
  1920. // so we call startup() and also get the size
  1921. popup.moveOffScreen(dropDown);
  1922. if(dropDown.startup && !dropDown._started){
  1923. dropDown.startup(); // this has to be done after being added to the DOM
  1924. }
  1925. // Get size of drop down, and determine if vertical scroll bar needed
  1926. var mb = domGeometry.getMarginSize(ddNode);
  1927. var overHeight = (maxHeight && mb.h > maxHeight);
  1928. domStyle.set(ddNode, {
  1929. overflow: overHeight ? "auto" : "visible"
  1930. });
  1931. if(overHeight){
  1932. mb.h = maxHeight;
  1933. if("w" in mb){
  1934. mb.w += 16; // room for vertical scrollbar
  1935. }
  1936. }else{
  1937. delete mb.h;
  1938. }
  1939. // Adjust dropdown width to match or be larger than my width
  1940. if(this.forceWidth){
  1941. mb.w = aroundNode.offsetWidth;
  1942. }else if(this.autoWidth){
  1943. mb.w = Math.max(mb.w, aroundNode.offsetWidth);
  1944. }else{
  1945. delete mb.w;
  1946. }
  1947. // And finally, resize the dropdown to calculated height and width
  1948. if(lang.isFunction(dropDown.resize)){
  1949. dropDown.resize(mb);
  1950. }else{
  1951. domGeometry.setMarginBox(ddNode, mb);
  1952. }
  1953. }
  1954. var retVal = popup.open({
  1955. parent: this,
  1956. popup: dropDown,
  1957. around: aroundNode,
  1958. orient: this.dropDownPosition,
  1959. onExecute: function(){
  1960. self.closeDropDown(true);
  1961. },
  1962. onCancel: function(){
  1963. self.closeDropDown(true);
  1964. },
  1965. onClose: function(){
  1966. domAttr.set(self._popupStateNode, "popupActive", false);
  1967. domClass.remove(self._popupStateNode, "dijitHasDropDownOpen");
  1968. self._opened = false;
  1969. }
  1970. });
  1971. domAttr.set(this._popupStateNode, "popupActive", "true");
  1972. domClass.add(self._popupStateNode, "dijitHasDropDownOpen");
  1973. this._opened=true;
  1974. // TODO: set this.checked and call setStateClass(), to affect button look while drop down is shown
  1975. return retVal;
  1976. },
  1977. closeDropDown: function(/*Boolean*/ focus){
  1978. // summary:
  1979. // Closes the drop down on this widget
  1980. // focus:
  1981. // If true, refocuses the button widget
  1982. // tags:
  1983. // protected
  1984. if(this._opened){
  1985. if(focus){ this.focus(); }
  1986. popup.close(this.dropDown);
  1987. this._opened = false;
  1988. }
  1989. }
  1990. });
  1991. });
  1992. },
  1993. 'dijit/tree/TreeStoreModel':function(){
  1994. define([
  1995. "dojo/_base/array", // array.filter array.forEach array.indexOf array.some
  1996. "dojo/aspect", // aspect.after
  1997. "dojo/_base/declare", // declare
  1998. "dojo/_base/json", // json.stringify
  1999. "dojo/_base/lang" // lang.hitch
  2000. ], function(array, aspect, declare, json, lang){
  2001. // module:
  2002. // dijit/tree/TreeStoreModel
  2003. // summary:
  2004. // Implements dijit.Tree.model connecting to a dojo.data store with a single
  2005. // root item.
  2006. return declare("dijit.tree.TreeStoreModel", null, {
  2007. // summary:
  2008. // Implements dijit.Tree.model connecting to a dojo.data store with a single
  2009. // root item. Any methods passed into the constructor will override
  2010. // the ones defined here.
  2011. // store: dojo.data.Store
  2012. // Underlying store
  2013. store: null,
  2014. // childrenAttrs: String[]
  2015. // One or more attribute names (attributes in the dojo.data item) that specify that item's children
  2016. childrenAttrs: ["children"],
  2017. // newItemIdAttr: String
  2018. // Name of attribute in the Object passed to newItem() that specifies the id.
  2019. //
  2020. // If newItemIdAttr is set then it's used when newItem() is called to see if an
  2021. // item with the same id already exists, and if so just links to the old item
  2022. // (so that the old item ends up with two parents).
  2023. //
  2024. // Setting this to null or "" will make every drop create a new item.
  2025. newItemIdAttr: "id",
  2026. // labelAttr: String
  2027. // If specified, get label for tree node from this attribute, rather
  2028. // than by calling store.getLabel()
  2029. labelAttr: "",
  2030. // root: [readonly] dojo.data.Item
  2031. // Pointer to the root item (read only, not a parameter)
  2032. root: null,
  2033. // query: anything
  2034. // Specifies datastore query to return the root item for the tree.
  2035. // Must only return a single item. Alternately can just pass in pointer
  2036. // to root item.
  2037. // example:
  2038. // | {id:'ROOT'}
  2039. query: null,
  2040. // deferItemLoadingUntilExpand: Boolean
  2041. // Setting this to true will cause the TreeStoreModel to defer calling loadItem on nodes
  2042. // until they are expanded. This allows for lazying loading where only one
  2043. // loadItem (and generally one network call, consequently) per expansion
  2044. // (rather than one for each child).
  2045. // This relies on partial loading of the children items; each children item of a
  2046. // fully loaded item should contain the label and info about having children.
  2047. deferItemLoadingUntilExpand: false,
  2048. constructor: function(/* Object */ args){
  2049. // summary:
  2050. // Passed the arguments listed above (store, etc)
  2051. // tags:
  2052. // private
  2053. lang.mixin(this, args);
  2054. this.connects = [];
  2055. var store = this.store;
  2056. if(!store.getFeatures()['dojo.data.api.Identity']){
  2057. throw new Error("dijit.Tree: store must support dojo.data.Identity");
  2058. }
  2059. // if the store supports Notification, subscribe to the notification events
  2060. if(store.getFeatures()['dojo.data.api.Notification']){
  2061. this.connects = this.connects.concat([
  2062. aspect.after(store, "onNew", lang.hitch(this, "onNewItem"), true),
  2063. aspect.after(store, "onDelete", lang.hitch(this, "onDeleteItem"), true),
  2064. aspect.after(store, "onSet", lang.hitch(this, "onSetItem"), true)
  2065. ]);
  2066. }
  2067. },
  2068. destroy: function(){
  2069. var h;
  2070. while(h = this.connects.pop()){ h.remove(); }
  2071. // TODO: should cancel any in-progress processing of getRoot(), getChildren()
  2072. },
  2073. // =======================================================================
  2074. // Methods for traversing hierarchy
  2075. getRoot: function(onItem, onError){
  2076. // summary:
  2077. // Calls onItem with the root item for the tree, possibly a fabricated item.
  2078. // Calls onError on error.
  2079. if(this.root){
  2080. onItem(this.root);
  2081. }else{
  2082. this.store.fetch({
  2083. query: this.query,
  2084. onComplete: lang.hitch(this, function(items){
  2085. if(items.length != 1){
  2086. throw new Error(this.declaredClass + ": query " + json.stringify(this.query) + " returned " + items.length +
  2087. " items, but must return exactly one item");
  2088. }
  2089. this.root = items[0];
  2090. onItem(this.root);
  2091. }),
  2092. onError: onError
  2093. });
  2094. }
  2095. },
  2096. mayHaveChildren: function(/*dojo.data.Item*/ item){
  2097. // summary:
  2098. // Tells if an item has or may have children. Implementing logic here
  2099. // avoids showing +/- expando icon for nodes that we know don't have children.
  2100. // (For efficiency reasons we may not want to check if an element actually
  2101. // has children until user clicks the expando node)
  2102. return array.some(this.childrenAttrs, function(attr){
  2103. return this.store.hasAttribute(item, attr);
  2104. }, this);
  2105. },
  2106. getChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ onComplete, /*function*/ onError){
  2107. // summary:
  2108. // Calls onComplete() with array of child items of given parent item, all loaded.
  2109. var store = this.store;
  2110. if(!store.isItemLoaded(parentItem)){
  2111. // The parent is not loaded yet, we must be in deferItemLoadingUntilExpand
  2112. // mode, so we will load it and just return the children (without loading each
  2113. // child item)
  2114. var getChildren = lang.hitch(this, arguments.callee);
  2115. store.loadItem({
  2116. item: parentItem,
  2117. onItem: function(parentItem){
  2118. getChildren(parentItem, onComplete, onError);
  2119. },
  2120. onError: onError
  2121. });
  2122. return;
  2123. }
  2124. // get children of specified item
  2125. var childItems = [];
  2126. for(var i=0; i<this.childrenAttrs.length; i++){
  2127. var vals = store.getValues(parentItem, this.childrenAttrs[i]);
  2128. childItems = childItems.concat(vals);
  2129. }
  2130. // count how many items need to be loaded
  2131. var _waitCount = 0;
  2132. if(!this.deferItemLoadingUntilExpand){
  2133. array.forEach(childItems, function(item){ if(!store.isItemLoaded(item)){ _waitCount++; } });
  2134. }
  2135. if(_waitCount == 0){
  2136. // all items are already loaded (or we aren't loading them). proceed...
  2137. onComplete(childItems);
  2138. }else{
  2139. // still waiting for some or all of the items to load
  2140. array.forEach(childItems, function(item, idx){
  2141. if(!store.isItemLoaded(item)){
  2142. store.loadItem({
  2143. item: item,
  2144. onItem: function(item){
  2145. childItems[idx] = item;
  2146. if(--_waitCount == 0){
  2147. // all nodes have been loaded, send them to the tree
  2148. onComplete(childItems);
  2149. }
  2150. },
  2151. onError: onError
  2152. });
  2153. }
  2154. });
  2155. }
  2156. },
  2157. // =======================================================================
  2158. // Inspecting items
  2159. isItem: function(/* anything */ something){
  2160. return this.store.isItem(something); // Boolean
  2161. },
  2162. fetchItemByIdentity: function(/* object */ keywordArgs){
  2163. this.store.fetchItemByIdentity(keywordArgs);
  2164. },
  2165. getIdentity: function(/* item */ item){
  2166. return this.store.getIdentity(item); // Object
  2167. },
  2168. getLabel: function(/*dojo.data.Item*/ item){
  2169. // summary:
  2170. // Get the label for an item
  2171. if(this.labelAttr){
  2172. return this.store.getValue(item,this.labelAttr); // String
  2173. }else{
  2174. return this.store.getLabel(item); // String
  2175. }
  2176. },
  2177. // =======================================================================
  2178. // Write interface
  2179. newItem: function(/* dojo.dnd.Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
  2180. // summary:
  2181. // Creates a new item. See `dojo.data.api.Write` for details on args.
  2182. // Used in drag & drop when item from external source dropped onto tree.
  2183. // description:
  2184. // Developers will need to override this method if new items get added
  2185. // to parents with multiple children attributes, in order to define which
  2186. // children attribute points to the new item.
  2187. var pInfo = {parent: parent, attribute: this.childrenAttrs[0]}, LnewItem;
  2188. if(this.newItemIdAttr && args[this.newItemIdAttr]){
  2189. // Maybe there's already a corresponding item in the store; if so, reuse it.
  2190. this.fetchItemByIdentity({identity: args[this.newItemIdAttr], scope: this, onItem: function(item){
  2191. if(item){
  2192. // There's already a matching item in store, use it
  2193. this.pasteItem(item, null, parent, true, insertIndex);
  2194. }else{
  2195. // Create new item in the tree, based on the drag source.
  2196. LnewItem=this.store.newItem(args, pInfo);
  2197. if(LnewItem && (insertIndex!=undefined)){
  2198. // Move new item to desired position
  2199. this.pasteItem(LnewItem, parent, parent, false, insertIndex);
  2200. }
  2201. }
  2202. }});
  2203. }else{
  2204. // [as far as we know] there is no id so we must assume this is a new item
  2205. LnewItem=this.store.newItem(args, pInfo);
  2206. if(LnewItem && (insertIndex!=undefined)){
  2207. // Move new item to desired position
  2208. this.pasteItem(LnewItem, parent, parent, false, insertIndex);
  2209. }
  2210. }
  2211. },
  2212. pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){
  2213. // summary:
  2214. // Move or copy an item from one parent item to another.
  2215. // Used in drag & drop
  2216. var store = this.store,
  2217. parentAttr = this.childrenAttrs[0]; // name of "children" attr in parent item
  2218. // remove child from source item, and record the attribute that child occurred in
  2219. if(oldParentItem){
  2220. array.forEach(this.childrenAttrs, function(attr){
  2221. if(store.containsValue(oldParentItem, attr, childItem)){
  2222. if(!bCopy){
  2223. var values = array.filter(store.getValues(oldParentItem, attr), function(x){
  2224. return x != childItem;
  2225. });
  2226. store.setValues(oldParentItem, attr, values);
  2227. }
  2228. parentAttr = attr;
  2229. }
  2230. });
  2231. }
  2232. // modify target item's children attribute to include this item
  2233. if(newParentItem){
  2234. if(typeof insertIndex == "number"){
  2235. // call slice() to avoid modifying the original array, confusing the data store
  2236. var childItems = store.getValues(newParentItem, parentAttr).slice();
  2237. childItems.splice(insertIndex, 0, childItem);
  2238. store.setValues(newParentItem, parentAttr, childItems);
  2239. }else{
  2240. store.setValues(newParentItem, parentAttr,
  2241. store.getValues(newParentItem, parentAttr).concat(childItem));
  2242. }
  2243. }
  2244. },
  2245. // =======================================================================
  2246. // Callbacks
  2247. onChange: function(/*dojo.data.Item*/ /*===== item =====*/){
  2248. // summary:
  2249. // Callback whenever an item has changed, so that Tree
  2250. // can update the label, icon, etc. Note that changes
  2251. // to an item's children or parent(s) will trigger an
  2252. // onChildrenChange() so you can ignore those changes here.
  2253. // tags:
  2254. // callback
  2255. },
  2256. onChildrenChange: function(/*===== parent, newChildrenList =====*/){
  2257. // summary:
  2258. // Callback to do notifications about new, updated, or deleted items.
  2259. // parent: dojo.data.Item
  2260. // newChildrenList: dojo.data.Item[]
  2261. // tags:
  2262. // callback
  2263. },
  2264. onDelete: function(/*dojo.data.Item*/ /*===== item =====*/){
  2265. // summary:
  2266. // Callback when an item has been deleted.
  2267. // description:
  2268. // Note that there will also be an onChildrenChange() callback for the parent
  2269. // of this item.
  2270. // tags:
  2271. // callback
  2272. },
  2273. // =======================================================================
  2274. // Events from data store
  2275. onNewItem: function(/* dojo.data.Item */ item, /* Object */ parentInfo){
  2276. // summary:
  2277. // Handler for when new items appear in the store, either from a drop operation
  2278. // or some other way. Updates the tree view (if necessary).
  2279. // description:
  2280. // If the new item is a child of an existing item,
  2281. // calls onChildrenChange() with the new list of children
  2282. // for that existing item.
  2283. //
  2284. // tags:
  2285. // extension
  2286. // We only care about the new item if it has a parent that corresponds to a TreeNode
  2287. // we are currently displaying
  2288. if(!parentInfo){
  2289. return;
  2290. }
  2291. // Call onChildrenChange() on parent (ie, existing) item with new list of children
  2292. // In the common case, the new list of children is simply parentInfo.newValue or
  2293. // [ parentInfo.newValue ], although if items in the store has multiple
  2294. // child attributes (see `childrenAttr`), then it's a superset of parentInfo.newValue,
  2295. // so call getChildren() to be sure to get right answer.
  2296. this.getChildren(parentInfo.item, lang.hitch(this, function(children){
  2297. this.onChildrenChange(parentInfo.item, children);
  2298. }));
  2299. },
  2300. onDeleteItem: function(/*Object*/ item){
  2301. // summary:
  2302. // Handler for delete notifications from underlying store
  2303. this.onDelete(item);
  2304. },
  2305. onSetItem: function(item, attribute /*===== , oldValue, newValue =====*/){
  2306. // summary:
  2307. // Updates the tree view according to changes in the data store.
  2308. // description:
  2309. // Handles updates to an item's children by calling onChildrenChange(), and
  2310. // other updates to an item by calling onChange().
  2311. //
  2312. // See `onNewItem` for more details on handling updates to an item's children.
  2313. // item: Item
  2314. // attribute: attribute-name-string
  2315. // oldValue: object | array
  2316. // newValue: object | array
  2317. // tags:
  2318. // extension
  2319. if(array.indexOf(this.childrenAttrs, attribute) != -1){
  2320. // item's children list changed
  2321. this.getChildren(item, lang.hitch(this, function(children){
  2322. // See comments in onNewItem() about calling getChildren()
  2323. this.onChildrenChange(item, children);
  2324. }));
  2325. }else{
  2326. // item's label/icon/etc. changed.
  2327. this.onChange(item);
  2328. }
  2329. }
  2330. });
  2331. });
  2332. },
  2333. 'dijit/_editor/plugins/EnterKeyHandling':function(){
  2334. define([
  2335. "dojo/_base/declare", // declare
  2336. "dojo/dom-construct", // domConstruct.destroy domConstruct.place
  2337. "dojo/_base/event", // event.stop
  2338. "dojo/keys", // keys.ENTER
  2339. "dojo/_base/lang",
  2340. "dojo/_base/sniff", // has("ie") has("mozilla") has("webkit")
  2341. "dojo/_base/window", // win.global win.withGlobal
  2342. "dojo/window", // winUtils.scrollIntoView
  2343. "../_Plugin",
  2344. "../RichText",
  2345. "../range",
  2346. "../selection"
  2347. ], function(declare, domConstruct, event, keys, lang, has, win, winUtils, _Plugin, RichText, rangeapi, selectionapi){
  2348. /*=====
  2349. var _Plugin = dijit._editor._Plugin;
  2350. =====*/
  2351. // module:
  2352. // dijit/_editor/plugins/EnterKeyHandling
  2353. // summary:
  2354. // This plugin tries to make all browsers behave consistently with regard to
  2355. // how ENTER behaves in the editor window. It traps the ENTER key and alters
  2356. // the way DOM is constructed in certain cases to try to commonize the generated
  2357. // DOM and behaviors across browsers.
  2358. return declare("dijit._editor.plugins.EnterKeyHandling", _Plugin, {
  2359. // summary:
  2360. // This plugin tries to make all browsers behave consistently with regard to
  2361. // how ENTER behaves in the editor window. It traps the ENTER key and alters
  2362. // the way DOM is constructed in certain cases to try to commonize the generated
  2363. // DOM and behaviors across browsers.
  2364. //
  2365. // description:
  2366. // This plugin has three modes:
  2367. //
  2368. // * blockNodeForEnter=BR
  2369. // * blockNodeForEnter=DIV
  2370. // * blockNodeForEnter=P
  2371. //
  2372. // In blockNodeForEnter=P, the ENTER key starts a new
  2373. // paragraph, and shift-ENTER starts a new line in the current paragraph.
  2374. // For example, the input:
  2375. //
  2376. // | first paragraph <shift-ENTER>
  2377. // | second line of first paragraph <ENTER>
  2378. // | second paragraph
  2379. //
  2380. // will generate:
  2381. //
  2382. // | <p>
  2383. // | first paragraph
  2384. // | <br/>
  2385. // | second line of first paragraph
  2386. // | </p>
  2387. // | <p>
  2388. // | second paragraph
  2389. // | </p>
  2390. //
  2391. // In BR and DIV mode, the ENTER key conceptually goes to a new line in the
  2392. // current paragraph, and users conceptually create a new paragraph by pressing ENTER twice.
  2393. // For example, if the user enters text into an editor like this:
  2394. //
  2395. // | one <ENTER>
  2396. // | two <ENTER>
  2397. // | three <ENTER>
  2398. // | <ENTER>
  2399. // | four <ENTER>
  2400. // | five <ENTER>
  2401. // | six <ENTER>
  2402. //
  2403. // It will appear on the screen as two 'paragraphs' of three lines each. Markupwise, this generates:
  2404. //
  2405. // BR:
  2406. // | one<br/>
  2407. // | two<br/>
  2408. // | three<br/>
  2409. // | <br/>
  2410. // | four<br/>
  2411. // | five<br/>
  2412. // | six<br/>
  2413. //
  2414. // DIV:
  2415. // | <div>one</div>
  2416. // | <div>two</div>
  2417. // | <div>three</div>
  2418. // | <div>&nbsp;</div>
  2419. // | <div>four</div>
  2420. // | <div>five</div>
  2421. // | <div>six</div>
  2422. // blockNodeForEnter: String
  2423. // This property decides the behavior of Enter key. It can be either P,
  2424. // DIV, BR, or empty (which means disable this feature). Anything else
  2425. // will trigger errors. The default is 'BR'
  2426. //
  2427. // See class description for more details.
  2428. blockNodeForEnter: 'BR',
  2429. constructor: function(args){
  2430. if(args){
  2431. if("blockNodeForEnter" in args){
  2432. args.blockNodeForEnter = args.blockNodeForEnter.toUpperCase();
  2433. }
  2434. lang.mixin(this,args);
  2435. }
  2436. },
  2437. setEditor: function(editor){
  2438. // Overrides _Plugin.setEditor().
  2439. if(this.editor === editor){ return; }
  2440. this.editor = editor;
  2441. if(this.blockNodeForEnter == 'BR'){
  2442. // While Moz has a mode tht mostly works, it's still a little different,
  2443. // So, try to just have a common mode and be consistent. Which means
  2444. // we need to enable customUndo, if not already enabled.
  2445. this.editor.customUndo = true;
  2446. editor.onLoadDeferred.then(lang.hitch(this,function(d){
  2447. this.connect(editor.document, "onkeypress", function(e){
  2448. if(e.charOrCode == keys.ENTER){
  2449. // Just do it manually. The handleEnterKey has a shift mode that
  2450. // Always acts like <br>, so just use it.
  2451. var ne = lang.mixin({},e);
  2452. ne.shiftKey = true;
  2453. if(!this.handleEnterKey(ne)){
  2454. event.stop(e);
  2455. }
  2456. }
  2457. });
  2458. if(has("ie") >= 9){
  2459. this.connect(editor.document, "onpaste", function(e){
  2460. setTimeout(dojo.hitch(this, function(){
  2461. // Use the old range/selection code to kick IE 9 into updating
  2462. // its range by moving it back, then forward, one 'character'.
  2463. var r = this.editor.document.selection.createRange();
  2464. r.move('character',-1);
  2465. r.select();
  2466. r.move('character',1);
  2467. r.select();
  2468. }),0);
  2469. });
  2470. }
  2471. return d;
  2472. }));
  2473. }else if(this.blockNodeForEnter){
  2474. // add enter key handler
  2475. // FIXME: need to port to the new event code!!
  2476. var h = lang.hitch(this,this.handleEnterKey);
  2477. editor.addKeyHandler(13, 0, 0, h); //enter
  2478. editor.addKeyHandler(13, 0, 1, h); //shift+enter
  2479. this.connect(this.editor,'onKeyPressed','onKeyPressed');
  2480. }
  2481. },
  2482. onKeyPressed: function(){
  2483. // summary:
  2484. // Handler for keypress events.
  2485. // tags:
  2486. // private
  2487. if(this._checkListLater){
  2488. if(win.withGlobal(this.editor.window, 'isCollapsed', dijit)){
  2489. var liparent=win.withGlobal(this.editor.window, 'getAncestorElement', selectionapi, ['LI']);
  2490. if(!liparent){
  2491. // circulate the undo detection code by calling RichText::execCommand directly
  2492. RichText.prototype.execCommand.call(this.editor, 'formatblock',this.blockNodeForEnter);
  2493. // set the innerHTML of the new block node
  2494. var block = win.withGlobal(this.editor.window, 'getAncestorElement', selectionapi, [this.blockNodeForEnter]);
  2495. if(block){
  2496. block.innerHTML=this.bogusHtmlContent;
  2497. if(has("ie") <= 9){
  2498. // move to the start by moving backwards one char
  2499. var r = this.editor.document.selection.createRange();
  2500. r.move('character',-1);
  2501. r.select();
  2502. }
  2503. }else{
  2504. console.error('onKeyPressed: Cannot find the new block node'); // FIXME
  2505. }
  2506. }else{
  2507. if(has("mozilla")){
  2508. if(liparent.parentNode.parentNode.nodeName == 'LI'){
  2509. liparent=liparent.parentNode.parentNode;
  2510. }
  2511. }
  2512. var fc=liparent.firstChild;
  2513. if(fc && fc.nodeType == 1 && (fc.nodeName == 'UL' || fc.nodeName == 'OL')){
  2514. liparent.insertBefore(fc.ownerDocument.createTextNode('\xA0'),fc);
  2515. var newrange = rangeapi.create(this.editor.window);
  2516. newrange.setStart(liparent.firstChild,0);
  2517. var selection = rangeapi.getSelection(this.editor.window, true);
  2518. selection.removeAllRanges();
  2519. selection.addRange(newrange);
  2520. }
  2521. }
  2522. }
  2523. this._checkListLater = false;
  2524. }
  2525. if(this._pressedEnterInBlock){
  2526. // the new created is the original current P, so we have previousSibling below
  2527. if(this._pressedEnterInBlock.previousSibling){
  2528. this.removeTrailingBr(this._pressedEnterInBlock.previousSibling);
  2529. }
  2530. delete this._pressedEnterInBlock;
  2531. }
  2532. },
  2533. // bogusHtmlContent: [private] String
  2534. // HTML to stick into a new empty block
  2535. bogusHtmlContent: '&#160;', // &nbsp;
  2536. // blockNodes: [private] Regex
  2537. // Regex for testing if a given tag is a block level (display:block) tag
  2538. blockNodes: /^(?:P|H1|H2|H3|H4|H5|H6|LI)$/,
  2539. handleEnterKey: function(e){
  2540. // summary:
  2541. // Handler for enter key events when blockNodeForEnter is DIV or P.
  2542. // description:
  2543. // Manually handle enter key event to make the behavior consistent across
  2544. // all supported browsers. See class description for details.
  2545. // tags:
  2546. // private
  2547. var selection, range, newrange, startNode, endNode, brNode, doc=this.editor.document,br,rs,txt;
  2548. if(e.shiftKey){ // shift+enter always generates <br>
  2549. var parent = win.withGlobal(this.editor.window, "getParentElement", selectionapi);
  2550. var header = rangeapi.getAncestor(parent,this.blockNodes);
  2551. if(header){
  2552. if(header.tagName == 'LI'){
  2553. return true; // let browser handle
  2554. }
  2555. selection = rangeapi.getSelection(this.editor.window);
  2556. range = selection.getRangeAt(0);
  2557. if(!range.collapsed){
  2558. range.deleteContents();
  2559. selection = rangeapi.getSelection(this.editor.window);
  2560. range = selection.getRangeAt(0);
  2561. }
  2562. if(rangeapi.atBeginningOfContainer(header, range.startContainer, range.startOffset)){
  2563. br=doc.createElement('br');
  2564. newrange = rangeapi.create(this.editor.window);
  2565. header.insertBefore(br,header.firstChild);
  2566. newrange.setStartAfter(br);
  2567. selection.removeAllRanges();
  2568. selection.addRange(newrange);
  2569. }else if(rangeapi.atEndOfContainer(header, range.startContainer, range.startOffset)){
  2570. newrange = rangeapi.create(this.editor.window);
  2571. br=doc.createElement('br');
  2572. header.appendChild(br);
  2573. header.appendChild(doc.createTextNode('\xA0'));
  2574. newrange.setStart(header.lastChild,0);
  2575. selection.removeAllRanges();
  2576. selection.addRange(newrange);
  2577. }else{
  2578. rs = range.startContainer;
  2579. if(rs && rs.nodeType == 3){
  2580. // Text node, we have to split it.
  2581. txt = rs.nodeValue;
  2582. win.withGlobal(this.editor.window, function(){
  2583. startNode = doc.createTextNode(txt.substring(0, range.startOffset));
  2584. endNode = doc.createTextNode(txt.substring(range.startOffset));
  2585. brNode = doc.createElement("br");
  2586. if(endNode.nodeValue == "" && has("webkit")){
  2587. endNode = doc.createTextNode('\xA0')
  2588. }
  2589. domConstruct.place(startNode, rs, "after");
  2590. domConstruct.place(brNode, startNode, "after");
  2591. domConstruct.place(endNode, brNode, "after");
  2592. domConstruct.destroy(rs);
  2593. newrange = rangeapi.create();
  2594. newrange.setStart(endNode,0);
  2595. selection.removeAllRanges();
  2596. selection.addRange(newrange);
  2597. });
  2598. return false;
  2599. }
  2600. return true; // let browser handle
  2601. }
  2602. }else{
  2603. selection = rangeapi.getSelection(this.editor.window);
  2604. if(selection.rangeCount){
  2605. range = selection.getRangeAt(0);
  2606. if(range && range.startContainer){
  2607. if(!range.collapsed){
  2608. range.deleteContents();
  2609. selection = rangeapi.getSelection(this.editor.window);
  2610. range = selection.getRangeAt(0);
  2611. }
  2612. rs = range.startContainer;
  2613. if(rs && rs.nodeType == 3){
  2614. // Text node, we have to split it.
  2615. win.withGlobal(this.editor.window, lang.hitch(this, function(){
  2616. var endEmpty = false;
  2617. var offset = range.startOffset;
  2618. if(rs.length < offset){
  2619. //We are not splitting the right node, try to locate the correct one
  2620. ret = this._adjustNodeAndOffset(rs, offset);
  2621. rs = ret.node;
  2622. offset = ret.offset;
  2623. }
  2624. txt = rs.nodeValue;
  2625. startNode = doc.createTextNode(txt.substring(0, offset));
  2626. endNode = doc.createTextNode(txt.substring(offset));
  2627. brNode = doc.createElement("br");
  2628. if(!endNode.length){
  2629. endNode = doc.createTextNode('\xA0');
  2630. endEmpty = true;
  2631. }
  2632. if(startNode.length){
  2633. domConstruct.place(startNode, rs, "after");
  2634. }else{
  2635. startNode = rs;
  2636. }
  2637. domConstruct.place(brNode, startNode, "after");
  2638. domConstruct.place(endNode, brNode, "after");
  2639. domConstruct.destroy(rs);
  2640. newrange = rangeapi.create();
  2641. newrange.setStart(endNode,0);
  2642. newrange.setEnd(endNode, endNode.length);
  2643. selection.removeAllRanges();
  2644. selection.addRange(newrange);
  2645. if(endEmpty && !has("webkit")){
  2646. selectionapi.remove();
  2647. }else{
  2648. selectionapi.collapse(true);
  2649. }
  2650. }));
  2651. }else{
  2652. var targetNode;
  2653. if(range.startOffset >= 0){
  2654. targetNode = rs.childNodes[range.startOffset];
  2655. }
  2656. win.withGlobal(this.editor.window, lang.hitch(this, function(){
  2657. var brNode = doc.createElement("br");
  2658. var endNode = doc.createTextNode('\xA0');
  2659. if(!targetNode){
  2660. rs.appendChild(brNode);
  2661. rs.appendChild(endNode);
  2662. }else{
  2663. domConstruct.place(brNode, targetNode, "before");
  2664. domConstruct.place(endNode, brNode, "after");
  2665. }
  2666. newrange = rangeapi.create(win.global);
  2667. newrange.setStart(endNode,0);
  2668. newrange.setEnd(endNode, endNode.length);
  2669. selection.removeAllRanges();
  2670. selection.addRange(newrange);
  2671. selectionapi.collapse(true);
  2672. }));
  2673. }
  2674. }
  2675. }else{
  2676. // don't change this: do not call this.execCommand, as that may have other logic in subclass
  2677. RichText.prototype.execCommand.call(this.editor, 'inserthtml', '<br>');
  2678. }
  2679. }
  2680. return false;
  2681. }
  2682. var _letBrowserHandle = true;
  2683. // first remove selection
  2684. selection = rangeapi.getSelection(this.editor.window);
  2685. range = selection.getRangeAt(0);
  2686. if(!range.collapsed){
  2687. range.deleteContents();
  2688. selection = rangeapi.getSelection(this.editor.window);
  2689. range = selection.getRangeAt(0);
  2690. }
  2691. var block = rangeapi.getBlockAncestor(range.endContainer, null, this.editor.editNode);
  2692. var blockNode = block.blockNode;
  2693. // if this is under a LI or the parent of the blockNode is LI, just let browser to handle it
  2694. if((this._checkListLater = (blockNode && (blockNode.nodeName == 'LI' || blockNode.parentNode.nodeName == 'LI')))){
  2695. if(has("mozilla")){
  2696. // press enter in middle of P may leave a trailing <br/>, let's remove it later
  2697. this._pressedEnterInBlock = blockNode;
  2698. }
  2699. // if this li only contains spaces, set the content to empty so the browser will outdent this item
  2700. if(/^(\s|&nbsp;|&#160;|\xA0|<span\b[^>]*\bclass=['"]Apple-style-span['"][^>]*>(\s|&nbsp;|&#160;|\xA0)<\/span>)?(<br>)?$/.test(blockNode.innerHTML)){
  2701. // empty LI node
  2702. blockNode.innerHTML = '';
  2703. if(has("webkit")){ // WebKit tosses the range when innerHTML is reset
  2704. newrange = rangeapi.create(this.editor.window);
  2705. newrange.setStart(blockNode, 0);
  2706. selection.removeAllRanges();
  2707. selection.addRange(newrange);
  2708. }
  2709. this._checkListLater = false; // nothing to check since the browser handles outdent
  2710. }
  2711. return true;
  2712. }
  2713. // text node directly under body, let's wrap them in a node
  2714. if(!block.blockNode || block.blockNode===this.editor.editNode){
  2715. try{
  2716. RichText.prototype.execCommand.call(this.editor, 'formatblock',this.blockNodeForEnter);
  2717. }catch(e2){ /*squelch FF3 exception bug when editor content is a single BR*/ }
  2718. // get the newly created block node
  2719. // FIXME
  2720. block = {blockNode:win.withGlobal(this.editor.window, "getAncestorElement", selectionapi, [this.blockNodeForEnter]),
  2721. blockContainer: this.editor.editNode};
  2722. if(block.blockNode){
  2723. if(block.blockNode != this.editor.editNode &&
  2724. (!(block.blockNode.textContent || block.blockNode.innerHTML).replace(/^\s+|\s+$/g, "").length)){
  2725. this.removeTrailingBr(block.blockNode);
  2726. return false;
  2727. }
  2728. }else{ // we shouldn't be here if formatblock worked
  2729. block.blockNode = this.editor.editNode;
  2730. }
  2731. selection = rangeapi.getSelection(this.editor.window);
  2732. range = selection.getRangeAt(0);
  2733. }
  2734. var newblock = doc.createElement(this.blockNodeForEnter);
  2735. newblock.innerHTML=this.bogusHtmlContent;
  2736. this.removeTrailingBr(block.blockNode);
  2737. var endOffset = range.endOffset;
  2738. var node = range.endContainer;
  2739. if(node.length < endOffset){
  2740. //We are not checking the right node, try to locate the correct one
  2741. var ret = this._adjustNodeAndOffset(node, endOffset);
  2742. node = ret.node;
  2743. endOffset = ret.offset;
  2744. }
  2745. if(rangeapi.atEndOfContainer(block.blockNode, node, endOffset)){
  2746. if(block.blockNode === block.blockContainer){
  2747. block.blockNode.appendChild(newblock);
  2748. }else{
  2749. domConstruct.place(newblock, block.blockNode, "after");
  2750. }
  2751. _letBrowserHandle = false;
  2752. // lets move caret to the newly created block
  2753. newrange = rangeapi.create(this.editor.window);
  2754. newrange.setStart(newblock, 0);
  2755. selection.removeAllRanges();
  2756. selection.addRange(newrange);
  2757. if(this.editor.height){
  2758. winUtils.scrollIntoView(newblock);
  2759. }
  2760. }else if(rangeapi.atBeginningOfContainer(block.blockNode,
  2761. range.startContainer, range.startOffset)){
  2762. domConstruct.place(newblock, block.blockNode, block.blockNode === block.blockContainer ? "first" : "before");
  2763. if(newblock.nextSibling && this.editor.height){
  2764. // position input caret - mostly WebKit needs this
  2765. newrange = rangeapi.create(this.editor.window);
  2766. newrange.setStart(newblock.nextSibling, 0);
  2767. selection.removeAllRanges();
  2768. selection.addRange(newrange);
  2769. // browser does not scroll the caret position into view, do it manually
  2770. winUtils.scrollIntoView(newblock.nextSibling);
  2771. }
  2772. _letBrowserHandle = false;
  2773. }else{ //press enter in the middle of P/DIV/Whatever/
  2774. if(block.blockNode === block.blockContainer){
  2775. block.blockNode.appendChild(newblock);
  2776. }else{
  2777. domConstruct.place(newblock, block.blockNode, "after");
  2778. }
  2779. _letBrowserHandle = false;
  2780. // Clone any block level styles.
  2781. if(block.blockNode.style){
  2782. if(newblock.style){
  2783. if(block.blockNode.style.cssText){
  2784. newblock.style.cssText = block.blockNode.style.cssText;
  2785. }
  2786. }
  2787. }
  2788. // Okay, we probably have to split.
  2789. rs = range.startContainer;
  2790. var firstNodeMoved;
  2791. if(rs && rs.nodeType == 3){
  2792. // Text node, we have to split it.
  2793. var nodeToMove, tNode;
  2794. endOffset = range.endOffset;
  2795. if(rs.length < endOffset){
  2796. //We are not splitting the right node, try to locate the correct one
  2797. ret = this._adjustNodeAndOffset(rs, endOffset);
  2798. rs = ret.node;
  2799. endOffset = ret.offset;
  2800. }
  2801. txt = rs.nodeValue;
  2802. startNode = doc.createTextNode(txt.substring(0, endOffset));
  2803. endNode = doc.createTextNode(txt.substring(endOffset, txt.length));
  2804. // Place the split, then remove original nodes.
  2805. domConstruct.place(startNode, rs, "before");
  2806. domConstruct.place(endNode, rs, "after");
  2807. domConstruct.destroy(rs);
  2808. // Okay, we split the text. Now we need to see if we're
  2809. // parented to the block element we're splitting and if
  2810. // not, we have to split all the way up. Ugh.
  2811. var parentC = startNode.parentNode;
  2812. while(parentC !== block.blockNode){
  2813. var tg = parentC.tagName;
  2814. var newTg = doc.createElement(tg);
  2815. // Clone over any 'style' data.
  2816. if(parentC.style){
  2817. if(newTg.style){
  2818. if(parentC.style.cssText){
  2819. newTg.style.cssText = parentC.style.cssText;
  2820. }
  2821. }
  2822. }
  2823. // If font also need to clone over any font data.
  2824. if(parentC.tagName === "FONT"){
  2825. if(parentC.color){
  2826. newTg.color = parentC.color;
  2827. }
  2828. if(parentC.face){
  2829. newTg.face = parentC.face;
  2830. }
  2831. if(parentC.size){ // this check was necessary on IE
  2832. newTg.size = parentC.size;
  2833. }
  2834. }
  2835. nodeToMove = endNode;
  2836. while(nodeToMove){
  2837. tNode = nodeToMove.nextSibling;
  2838. newTg.appendChild(nodeToMove);
  2839. nodeToMove = tNode;
  2840. }
  2841. domConstruct.place(newTg, parentC, "after");
  2842. startNode = parentC;
  2843. endNode = newTg;
  2844. parentC = parentC.parentNode;
  2845. }
  2846. // Lastly, move the split out tags to the new block.
  2847. // as they should now be split properly.
  2848. nodeToMove = endNode;
  2849. if(nodeToMove.nodeType == 1 || (nodeToMove.nodeType == 3 && nodeToMove.nodeValue)){
  2850. // Non-blank text and non-text nodes need to clear out that blank space
  2851. // before moving the contents.
  2852. newblock.innerHTML = "";
  2853. }
  2854. firstNodeMoved = nodeToMove;
  2855. while(nodeToMove){
  2856. tNode = nodeToMove.nextSibling;
  2857. newblock.appendChild(nodeToMove);
  2858. nodeToMove = tNode;
  2859. }
  2860. }
  2861. //lets move caret to the newly created block
  2862. newrange = rangeapi.create(this.editor.window);
  2863. var nodeForCursor;
  2864. var innerMostFirstNodeMoved = firstNodeMoved;
  2865. if(this.blockNodeForEnter !== 'BR'){
  2866. while(innerMostFirstNodeMoved){
  2867. nodeForCursor = innerMostFirstNodeMoved;
  2868. tNode = innerMostFirstNodeMoved.firstChild;
  2869. innerMostFirstNodeMoved = tNode;
  2870. }
  2871. if(nodeForCursor && nodeForCursor.parentNode){
  2872. newblock = nodeForCursor.parentNode;
  2873. newrange.setStart(newblock, 0);
  2874. selection.removeAllRanges();
  2875. selection.addRange(newrange);
  2876. if(this.editor.height){
  2877. winUtils.scrollIntoView(newblock);
  2878. }
  2879. if(has("mozilla")){
  2880. // press enter in middle of P may leave a trailing <br/>, let's remove it later
  2881. this._pressedEnterInBlock = block.blockNode;
  2882. }
  2883. }else{
  2884. _letBrowserHandle = true;
  2885. }
  2886. }else{
  2887. newrange.setStart(newblock, 0);
  2888. selection.removeAllRanges();
  2889. selection.addRange(newrange);
  2890. if(this.editor.height){
  2891. winUtils.scrollIntoView(newblock);
  2892. }
  2893. if(has("mozilla")){
  2894. // press enter in middle of P may leave a trailing <br/>, let's remove it later
  2895. this._pressedEnterInBlock = block.blockNode;
  2896. }
  2897. }
  2898. }
  2899. return _letBrowserHandle;
  2900. },
  2901. _adjustNodeAndOffset: function(/*DomNode*/node, /*Int*/offset){
  2902. // summary:
  2903. // In the case there are multiple text nodes in a row the offset may not be within the node. If the offset is larger than the node length, it will attempt to find
  2904. // the next text sibling until it locates the text node in which the offset refers to
  2905. // node:
  2906. // The node to check.
  2907. // offset:
  2908. // The position to find within the text node
  2909. // tags:
  2910. // private.
  2911. while(node.length < offset && node.nextSibling && node.nextSibling.nodeType==3){
  2912. //Adjust the offset and node in the case of multiple text nodes in a row
  2913. offset = offset - node.length;
  2914. node = node.nextSibling;
  2915. }
  2916. return {"node": node, "offset": offset};
  2917. },
  2918. removeTrailingBr: function(container){
  2919. // summary:
  2920. // If last child of container is a <br>, then remove it.
  2921. // tags:
  2922. // private
  2923. var para = /P|DIV|LI/i.test(container.tagName) ?
  2924. container : selectionapi.getParentOfType(container,['P','DIV','LI']);
  2925. if(!para){ return; }
  2926. if(para.lastChild){
  2927. if((para.childNodes.length > 1 && para.lastChild.nodeType == 3 && /^[\s\xAD]*$/.test(para.lastChild.nodeValue)) ||
  2928. para.lastChild.tagName=='BR'){
  2929. domConstruct.destroy(para.lastChild);
  2930. }
  2931. }
  2932. if(!para.childNodes.length){
  2933. para.innerHTML=this.bogusHtmlContent;
  2934. }
  2935. }
  2936. });
  2937. });
  2938. },
  2939. 'dijit/_MenuBase':function(){
  2940. define([
  2941. "./popup",
  2942. "dojo/window",
  2943. "./_Widget",
  2944. "./_KeyNavContainer",
  2945. "./_TemplatedMixin",
  2946. "dojo/_base/declare", // declare
  2947. "dojo/dom", // dom.isDescendant domClass.replace
  2948. "dojo/dom-attr",
  2949. "dojo/dom-class", // domClass.replace
  2950. "dojo/_base/lang", // lang.hitch
  2951. "dojo/_base/array" // array.indexOf
  2952. ], function(pm, winUtils, _Widget, _KeyNavContainer, _TemplatedMixin,
  2953. declare, dom, domAttr, domClass, lang, array){
  2954. /*=====
  2955. var _Widget = dijit._Widget;
  2956. var _TemplatedMixin = dijit._TemplatedMixin;
  2957. var _KeyNavContainer = dijit._KeyNavContainer;
  2958. =====*/
  2959. // module:
  2960. // dijit/_MenuBase
  2961. // summary:
  2962. // Base class for Menu and MenuBar
  2963. return declare("dijit._MenuBase",
  2964. [_Widget, _TemplatedMixin, _KeyNavContainer],
  2965. {
  2966. // summary:
  2967. // Base class for Menu and MenuBar
  2968. // parentMenu: [readonly] Widget
  2969. // pointer to menu that displayed me
  2970. parentMenu: null,
  2971. // popupDelay: Integer
  2972. // number of milliseconds before hovering (without clicking) causes the popup to automatically open.
  2973. popupDelay: 500,
  2974. onExecute: function(){
  2975. // summary:
  2976. // Attach point for notification about when a menu item has been executed.
  2977. // This is an internal mechanism used for Menus to signal to their parent to
  2978. // close them, because they are about to execute the onClick handler. In
  2979. // general developers should not attach to or override this method.
  2980. // tags:
  2981. // protected
  2982. },
  2983. onCancel: function(/*Boolean*/ /*===== closeAll =====*/){
  2984. // summary:
  2985. // Attach point for notification about when the user cancels the current menu
  2986. // This is an internal mechanism used for Menus to signal to their parent to
  2987. // close them. In general developers should not attach to or override this method.
  2988. // tags:
  2989. // protected
  2990. },
  2991. _moveToPopup: function(/*Event*/ evt){
  2992. // summary:
  2993. // This handles the right arrow key (left arrow key on RTL systems),
  2994. // which will either open a submenu, or move to the next item in the
  2995. // ancestor MenuBar
  2996. // tags:
  2997. // private
  2998. if(this.focusedChild && this.focusedChild.popup && !this.focusedChild.disabled){
  2999. this.focusedChild._onClick(evt);
  3000. }else{
  3001. var topMenu = this._getTopMenu();
  3002. if(topMenu && topMenu._isMenuBar){
  3003. topMenu.focusNext();
  3004. }
  3005. }
  3006. },
  3007. _onPopupHover: function(/*Event*/ /*===== evt =====*/){
  3008. // summary:
  3009. // This handler is called when the mouse moves over the popup.
  3010. // tags:
  3011. // private
  3012. // if the mouse hovers over a menu popup that is in pending-close state,
  3013. // then stop the close operation.
  3014. // This can't be done in onItemHover since some popup targets don't have MenuItems (e.g. ColorPicker)
  3015. if(this.currentPopup && this.currentPopup._pendingClose_timer){
  3016. var parentMenu = this.currentPopup.parentMenu;
  3017. // highlight the parent menu item pointing to this popup
  3018. if(parentMenu.focusedChild){
  3019. parentMenu.focusedChild._setSelected(false);
  3020. }
  3021. parentMenu.focusedChild = this.currentPopup.from_item;
  3022. parentMenu.focusedChild._setSelected(true);
  3023. // cancel the pending close
  3024. this._stopPendingCloseTimer(this.currentPopup);
  3025. }
  3026. },
  3027. onItemHover: function(/*MenuItem*/ item){
  3028. // summary:
  3029. // Called when cursor is over a MenuItem.
  3030. // tags:
  3031. // protected
  3032. // Don't do anything unless user has "activated" the menu by:
  3033. // 1) clicking it
  3034. // 2) opening it from a parent menu (which automatically focuses it)
  3035. if(this.isActive){
  3036. this.focusChild(item);
  3037. if(this.focusedChild.popup && !this.focusedChild.disabled && !this.hover_timer){
  3038. this.hover_timer = setTimeout(lang.hitch(this, "_openPopup"), this.popupDelay);
  3039. }
  3040. }
  3041. // if the user is mixing mouse and keyboard navigation,
  3042. // then the menu may not be active but a menu item has focus,
  3043. // but it's not the item that the mouse just hovered over.
  3044. // To avoid both keyboard and mouse selections, use the latest.
  3045. if(this.focusedChild){
  3046. this.focusChild(item);
  3047. }
  3048. this._hoveredChild = item;
  3049. },
  3050. _onChildBlur: function(item){
  3051. // summary:
  3052. // Called when a child MenuItem becomes inactive because focus
  3053. // has been removed from the MenuItem *and* it's descendant menus.
  3054. // tags:
  3055. // private
  3056. this._stopPopupTimer();
  3057. item._setSelected(false);
  3058. // Close all popups that are open and descendants of this menu
  3059. var itemPopup = item.popup;
  3060. if(itemPopup){
  3061. this._stopPendingCloseTimer(itemPopup);
  3062. itemPopup._pendingClose_timer = setTimeout(function(){
  3063. itemPopup._pendingClose_timer = null;
  3064. if(itemPopup.parentMenu){
  3065. itemPopup.parentMenu.currentPopup = null;
  3066. }
  3067. pm.close(itemPopup); // this calls onClose
  3068. }, this.popupDelay);
  3069. }
  3070. },
  3071. onItemUnhover: function(/*MenuItem*/ item){
  3072. // summary:
  3073. // Callback fires when mouse exits a MenuItem
  3074. // tags:
  3075. // protected
  3076. if(this.isActive){
  3077. this._stopPopupTimer();
  3078. }
  3079. if(this._hoveredChild == item){ this._hoveredChild = null; }
  3080. },
  3081. _stopPopupTimer: function(){
  3082. // summary:
  3083. // Cancels the popup timer because the user has stop hovering
  3084. // on the MenuItem, etc.
  3085. // tags:
  3086. // private
  3087. if(this.hover_timer){
  3088. clearTimeout(this.hover_timer);
  3089. this.hover_timer = null;
  3090. }
  3091. },
  3092. _stopPendingCloseTimer: function(/*dijit._Widget*/ popup){
  3093. // summary:
  3094. // Cancels the pending-close timer because the close has been preempted
  3095. // tags:
  3096. // private
  3097. if(popup._pendingClose_timer){
  3098. clearTimeout(popup._pendingClose_timer);
  3099. popup._pendingClose_timer = null;
  3100. }
  3101. },
  3102. _stopFocusTimer: function(){
  3103. // summary:
  3104. // Cancels the pending-focus timer because the menu was closed before focus occured
  3105. // tags:
  3106. // private
  3107. if(this._focus_timer){
  3108. clearTimeout(this._focus_timer);
  3109. this._focus_timer = null;
  3110. }
  3111. },
  3112. _getTopMenu: function(){
  3113. // summary:
  3114. // Returns the top menu in this chain of Menus
  3115. // tags:
  3116. // private
  3117. for(var top=this; top.parentMenu; top=top.parentMenu);
  3118. return top;
  3119. },
  3120. onItemClick: function(/*dijit._Widget*/ item, /*Event*/ evt){
  3121. // summary:
  3122. // Handle clicks on an item.
  3123. // tags:
  3124. // private
  3125. // this can't be done in _onFocus since the _onFocus events occurs asynchronously
  3126. if(typeof this.isShowingNow == 'undefined'){ // non-popup menu
  3127. this._markActive();
  3128. }
  3129. this.focusChild(item);
  3130. if(item.disabled){ return false; }
  3131. if(item.popup){
  3132. this._openPopup();
  3133. }else{
  3134. // before calling user defined handler, close hierarchy of menus
  3135. // and restore focus to place it was when menu was opened
  3136. this.onExecute();
  3137. // user defined handler for click
  3138. item.onClick(evt);
  3139. }
  3140. },
  3141. _openPopup: function(){
  3142. // summary:
  3143. // Open the popup to the side of/underneath the current menu item
  3144. // tags:
  3145. // protected
  3146. this._stopPopupTimer();
  3147. var from_item = this.focusedChild;
  3148. if(!from_item){ return; } // the focused child lost focus since the timer was started
  3149. var popup = from_item.popup;
  3150. if(popup.isShowingNow){ return; }
  3151. if(this.currentPopup){
  3152. this._stopPendingCloseTimer(this.currentPopup);
  3153. pm.close(this.currentPopup);
  3154. }
  3155. popup.parentMenu = this;
  3156. popup.from_item = from_item; // helps finding the parent item that should be focused for this popup
  3157. var self = this;
  3158. pm.open({
  3159. parent: this,
  3160. popup: popup,
  3161. around: from_item.domNode,
  3162. orient: this._orient || ["after", "before"],
  3163. onCancel: function(){ // called when the child menu is canceled
  3164. // set isActive=false (_closeChild vs _cleanUp) so that subsequent hovering will NOT open child menus
  3165. // which seems aligned with the UX of most applications (e.g. notepad, wordpad, paint shop pro)
  3166. self.focusChild(from_item); // put focus back on my node
  3167. self._cleanUp(); // close the submenu (be sure this is done _after_ focus is moved)
  3168. from_item._setSelected(true); // oops, _cleanUp() deselected the item
  3169. self.focusedChild = from_item; // and unset focusedChild
  3170. },
  3171. onExecute: lang.hitch(this, "_cleanUp")
  3172. });
  3173. this.currentPopup = popup;
  3174. // detect mouseovers to handle lazy mouse movements that temporarily focus other menu items
  3175. if(this.popupHoverHandle){
  3176. this.disconnect(this.popupHoverHandle);
  3177. }
  3178. this.popupHoverHandle = this.connect(popup.domNode, "onmouseenter", "_onPopupHover");
  3179. if(popup.focus){
  3180. // If user is opening the popup via keyboard (right arrow, or down arrow for MenuBar),
  3181. // if the cursor happens to collide with the popup, it will generate an onmouseover event
  3182. // even though the mouse wasn't moved. Use a setTimeout() to call popup.focus so that
  3183. // our focus() call overrides the onmouseover event, rather than vice-versa. (#8742)
  3184. popup._focus_timer = setTimeout(lang.hitch(popup, function(){
  3185. this._focus_timer = null;
  3186. this.focus();
  3187. }), 0);
  3188. }
  3189. },
  3190. _markActive: function(){
  3191. // summary:
  3192. // Mark this menu's state as active.
  3193. // Called when this Menu gets focus from:
  3194. // 1) clicking it (mouse or via space/arrow key)
  3195. // 2) being opened by a parent menu.
  3196. // This is not called just from mouse hover.
  3197. // Focusing a menu via TAB does NOT automatically set isActive
  3198. // since TAB is a navigation operation and not a selection one.
  3199. // For Windows apps, pressing the ALT key focuses the menubar
  3200. // menus (similar to TAB navigation) but the menu is not active
  3201. // (ie no dropdown) until an item is clicked.
  3202. this.isActive = true;
  3203. domClass.replace(this.domNode, "dijitMenuActive", "dijitMenuPassive");
  3204. },
  3205. onOpen: function(/*Event*/ /*===== e =====*/){
  3206. // summary:
  3207. // Callback when this menu is opened.
  3208. // This is called by the popup manager as notification that the menu
  3209. // was opened.
  3210. // tags:
  3211. // private
  3212. this.isShowingNow = true;
  3213. this._markActive();
  3214. },
  3215. _markInactive: function(){
  3216. // summary:
  3217. // Mark this menu's state as inactive.
  3218. this.isActive = false; // don't do this in _onBlur since the state is pending-close until we get here
  3219. domClass.replace(this.domNode, "dijitMenuPassive", "dijitMenuActive");
  3220. },
  3221. onClose: function(){
  3222. // summary:
  3223. // Callback when this menu is closed.
  3224. // This is called by the popup manager as notification that the menu
  3225. // was closed.
  3226. // tags:
  3227. // private
  3228. this._stopFocusTimer();
  3229. this._markInactive();
  3230. this.isShowingNow = false;
  3231. this.parentMenu = null;
  3232. },
  3233. _closeChild: function(){
  3234. // summary:
  3235. // Called when submenu is clicked or focus is lost. Close hierarchy of menus.
  3236. // tags:
  3237. // private
  3238. this._stopPopupTimer();
  3239. if(this.currentPopup){
  3240. // If focus is on a descendant MenuItem then move focus to me,
  3241. // because IE doesn't like it when you display:none a node with focus,
  3242. // and also so keyboard users don't lose control.
  3243. // Likely, immediately after a user defined onClick handler will move focus somewhere
  3244. // else, like a Dialog.
  3245. if(array.indexOf(this._focusManager.activeStack, this.id) >= 0){
  3246. domAttr.set(this.focusedChild.focusNode, "tabIndex", this.tabIndex);
  3247. this.focusedChild.focusNode.focus();
  3248. }
  3249. // Close all popups that are open and descendants of this menu
  3250. pm.close(this.currentPopup);
  3251. this.currentPopup = null;
  3252. }
  3253. if(this.focusedChild){ // unhighlight the focused item
  3254. this.focusedChild._setSelected(false);
  3255. this.focusedChild._onUnhover();
  3256. this.focusedChild = null;
  3257. }
  3258. },
  3259. _onItemFocus: function(/*MenuItem*/ item){
  3260. // summary:
  3261. // Called when child of this Menu gets focus from:
  3262. // 1) clicking it
  3263. // 2) tabbing into it
  3264. // 3) being opened by a parent menu.
  3265. // This is not called just from mouse hover.
  3266. if(this._hoveredChild && this._hoveredChild != item){
  3267. this._hoveredChild._onUnhover(); // any previous mouse movement is trumped by focus selection
  3268. }
  3269. },
  3270. _onBlur: function(){
  3271. // summary:
  3272. // Called when focus is moved away from this Menu and it's submenus.
  3273. // tags:
  3274. // protected
  3275. this._cleanUp();
  3276. this.inherited(arguments);
  3277. },
  3278. _cleanUp: function(){
  3279. // summary:
  3280. // Called when the user is done with this menu. Closes hierarchy of menus.
  3281. // tags:
  3282. // private
  3283. this._closeChild(); // don't call this.onClose since that's incorrect for MenuBar's that never close
  3284. if(typeof this.isShowingNow == 'undefined'){ // non-popup menu doesn't call onClose
  3285. this._markInactive();
  3286. }
  3287. }
  3288. });
  3289. });
  3290. },
  3291. 'dijit/PopupMenuBarItem':function(){
  3292. define([
  3293. "dojo/_base/declare", // declare
  3294. "./PopupMenuItem",
  3295. "./MenuBarItem"
  3296. ], function(declare, PopupMenuItem, MenuBarItem){
  3297. // module:
  3298. // dijit/PopupMenuBarItem
  3299. // summary:
  3300. // Item in a MenuBar like "File" or "Edit", that spawns a submenu when pressed (or hovered)
  3301. var _MenuBarItemMixin = MenuBarItem._MenuBarItemMixin;
  3302. /*=====
  3303. var PopupMenuItem = dijit.PopupMenuItem;
  3304. var _MenuBarItemMixin = dijit._MenuBarItemMixin;
  3305. =====*/
  3306. return declare("dijit.PopupMenuBarItem", [PopupMenuItem, _MenuBarItemMixin], {
  3307. // summary:
  3308. // Item in a MenuBar like "File" or "Edit", that spawns a submenu when pressed (or hovered)
  3309. });
  3310. });
  3311. },
  3312. 'dijit/tree/ForestStoreModel':function(){
  3313. define("dijit/tree/ForestStoreModel", [
  3314. "dojo/_base/array", // array.indexOf array.some
  3315. "dojo/_base/declare", // declare
  3316. "dojo/_base/lang", // lang.hitch
  3317. "dojo/_base/window", // win.global
  3318. "./TreeStoreModel"
  3319. ], function(array, declare, lang, win, TreeStoreModel){
  3320. /*=====
  3321. var TreeStoreModel = dijit.tree.TreeStoreModel;
  3322. =====*/
  3323. // module:
  3324. // dijit/tree/ForestStoreModel
  3325. // summary:
  3326. // Interface between a dijit.Tree and a dojo.data store that doesn't have a root item,
  3327. // a.k.a. a store that has multiple "top level" items.
  3328. return declare("dijit.tree.ForestStoreModel", TreeStoreModel, {
  3329. // summary:
  3330. // Interface between a dijit.Tree and a dojo.data store that doesn't have a root item,
  3331. // a.k.a. a store that has multiple "top level" items.
  3332. //
  3333. // description
  3334. // Use this class to wrap a dojo.data store, making all the items matching the specified query
  3335. // appear as children of a fabricated "root item". If no query is specified then all the
  3336. // items returned by fetch() on the underlying store become children of the root item.
  3337. // This class allows dijit.Tree to assume a single root item, even if the store doesn't have one.
  3338. //
  3339. // When using this class the developer must override a number of methods according to their app and
  3340. // data, including:
  3341. // - onNewRootItem
  3342. // - onAddToRoot
  3343. // - onLeaveRoot
  3344. // - onNewItem
  3345. // - onSetItem
  3346. // Parameters to constructor
  3347. // rootId: String
  3348. // ID of fabricated root item
  3349. rootId: "$root$",
  3350. // rootLabel: String
  3351. // Label of fabricated root item
  3352. rootLabel: "ROOT",
  3353. // query: String
  3354. // Specifies the set of children of the root item.
  3355. // example:
  3356. // | {type:'continent'}
  3357. query: null,
  3358. // End of parameters to constructor
  3359. constructor: function(params){
  3360. // summary:
  3361. // Sets up variables, etc.
  3362. // tags:
  3363. // private
  3364. // Make dummy root item
  3365. this.root = {
  3366. store: this,
  3367. root: true,
  3368. id: params.rootId,
  3369. label: params.rootLabel,
  3370. children: params.rootChildren // optional param
  3371. };
  3372. },
  3373. // =======================================================================
  3374. // Methods for traversing hierarchy
  3375. mayHaveChildren: function(/*dojo.data.Item*/ item){
  3376. // summary:
  3377. // Tells if an item has or may have children. Implementing logic here
  3378. // avoids showing +/- expando icon for nodes that we know don't have children.
  3379. // (For efficiency reasons we may not want to check if an element actually
  3380. // has children until user clicks the expando node)
  3381. // tags:
  3382. // extension
  3383. return item === this.root || this.inherited(arguments);
  3384. },
  3385. getChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ callback, /*function*/ onError){
  3386. // summary:
  3387. // Calls onComplete() with array of child items of given parent item, all loaded.
  3388. if(parentItem === this.root){
  3389. if(this.root.children){
  3390. // already loaded, just return
  3391. callback(this.root.children);
  3392. }else{
  3393. this.store.fetch({
  3394. query: this.query,
  3395. onComplete: lang.hitch(this, function(items){
  3396. this.root.children = items;
  3397. callback(items);
  3398. }),
  3399. onError: onError
  3400. });
  3401. }
  3402. }else{
  3403. this.inherited(arguments);
  3404. }
  3405. },
  3406. // =======================================================================
  3407. // Inspecting items
  3408. isItem: function(/* anything */ something){
  3409. return (something === this.root) ? true : this.inherited(arguments);
  3410. },
  3411. fetchItemByIdentity: function(/* object */ keywordArgs){
  3412. if(keywordArgs.identity == this.root.id){
  3413. var scope = keywordArgs.scope?keywordArgs.scope:win.global;
  3414. if(keywordArgs.onItem){
  3415. keywordArgs.onItem.call(scope, this.root);
  3416. }
  3417. }else{
  3418. this.inherited(arguments);
  3419. }
  3420. },
  3421. getIdentity: function(/* item */ item){
  3422. return (item === this.root) ? this.root.id : this.inherited(arguments);
  3423. },
  3424. getLabel: function(/* item */ item){
  3425. return (item === this.root) ? this.root.label : this.inherited(arguments);
  3426. },
  3427. // =======================================================================
  3428. // Write interface
  3429. newItem: function(/* dojo.dnd.Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
  3430. // summary:
  3431. // Creates a new item. See dojo.data.api.Write for details on args.
  3432. // Used in drag & drop when item from external source dropped onto tree.
  3433. if(parent === this.root){
  3434. this.onNewRootItem(args);
  3435. return this.store.newItem(args);
  3436. }else{
  3437. return this.inherited(arguments);
  3438. }
  3439. },
  3440. onNewRootItem: function(/* dojo.dnd.Item */ /*===== args =====*/){
  3441. // summary:
  3442. // User can override this method to modify a new element that's being
  3443. // added to the root of the tree, for example to add a flag like root=true
  3444. },
  3445. pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){
  3446. // summary:
  3447. // Move or copy an item from one parent item to another.
  3448. // Used in drag & drop
  3449. if(oldParentItem === this.root){
  3450. if(!bCopy){
  3451. // It's onLeaveRoot()'s responsibility to modify the item so it no longer matches
  3452. // this.query... thus triggering an onChildrenChange() event to notify the Tree
  3453. // that this element is no longer a child of the root node
  3454. this.onLeaveRoot(childItem);
  3455. }
  3456. }
  3457. this.inherited(arguments, [childItem,
  3458. oldParentItem === this.root ? null : oldParentItem,
  3459. newParentItem === this.root ? null : newParentItem,
  3460. bCopy,
  3461. insertIndex
  3462. ]);
  3463. if(newParentItem === this.root){
  3464. // It's onAddToRoot()'s responsibility to modify the item so it matches
  3465. // this.query... thus triggering an onChildrenChange() event to notify the Tree
  3466. // that this element is now a child of the root node
  3467. this.onAddToRoot(childItem);
  3468. }
  3469. },
  3470. // =======================================================================
  3471. // Handling for top level children
  3472. onAddToRoot: function(/* item */ item){
  3473. // summary:
  3474. // Called when item added to root of tree; user must override this method
  3475. // to modify the item so that it matches the query for top level items
  3476. // example:
  3477. // | store.setValue(item, "root", true);
  3478. // tags:
  3479. // extension
  3480. console.log(this, ": item ", item, " added to root");
  3481. },
  3482. onLeaveRoot: function(/* item */ item){
  3483. // summary:
  3484. // Called when item removed from root of tree; user must override this method
  3485. // to modify the item so it doesn't match the query for top level items
  3486. // example:
  3487. // | store.unsetAttribute(item, "root");
  3488. // tags:
  3489. // extension
  3490. console.log(this, ": item ", item, " removed from root");
  3491. },
  3492. // =======================================================================
  3493. // Events from data store
  3494. _requeryTop: function(){
  3495. // reruns the query for the children of the root node,
  3496. // sending out an onSet notification if those children have changed
  3497. var oldChildren = this.root.children || [];
  3498. this.store.fetch({
  3499. query: this.query,
  3500. onComplete: lang.hitch(this, function(newChildren){
  3501. this.root.children = newChildren;
  3502. // If the list of children or the order of children has changed...
  3503. if(oldChildren.length != newChildren.length ||
  3504. array.some(oldChildren, function(item, idx){ return newChildren[idx] != item;})){
  3505. this.onChildrenChange(this.root, newChildren);
  3506. }
  3507. })
  3508. });
  3509. },
  3510. onNewItem: function(/* dojo.data.Item */ item, /* Object */ parentInfo){
  3511. // summary:
  3512. // Handler for when new items appear in the store. Developers should override this
  3513. // method to be more efficient based on their app/data.
  3514. // description:
  3515. // Note that the default implementation requeries the top level items every time
  3516. // a new item is created, since any new item could be a top level item (even in
  3517. // addition to being a child of another item, since items can have multiple parents).
  3518. //
  3519. // If developers can detect which items are possible top level items (based on the item and the
  3520. // parentInfo parameters), they should override this method to only call _requeryTop() for top
  3521. // level items. Often all top level items have parentInfo==null, but
  3522. // that will depend on which store you use and what your data is like.
  3523. // tags:
  3524. // extension
  3525. this._requeryTop();
  3526. this.inherited(arguments);
  3527. },
  3528. onDeleteItem: function(/*Object*/ item){
  3529. // summary:
  3530. // Handler for delete notifications from underlying store
  3531. // check if this was a child of root, and if so send notification that root's children
  3532. // have changed
  3533. if(array.indexOf(this.root.children, item) != -1){
  3534. this._requeryTop();
  3535. }
  3536. this.inherited(arguments);
  3537. },
  3538. onSetItem: function(/* item */ item,
  3539. /* attribute-name-string */ attribute,
  3540. /* object | array */ oldValue,
  3541. /* object | array */ newValue){
  3542. // summary:
  3543. // Updates the tree view according to changes to an item in the data store.
  3544. // Developers should override this method to be more efficient based on their app/data.
  3545. // description:
  3546. // Handles updates to an item's children by calling onChildrenChange(), and
  3547. // other updates to an item by calling onChange().
  3548. //
  3549. // Also, any change to any item re-executes the query for the tree's top-level items,
  3550. // since this modified item may have started/stopped matching the query for top level items.
  3551. //
  3552. // If possible, developers should override this function to only call _requeryTop() when
  3553. // the change to the item has caused it to stop/start being a top level item in the tree.
  3554. // tags:
  3555. // extension
  3556. this._requeryTop();
  3557. this.inherited(arguments);
  3558. }
  3559. });
  3560. });
  3561. },
  3562. 'url:dijit/layout/templates/AccordionButton.html':"<div data-dojo-attach-event='onclick:_onTitleClick' class='dijitAccordionTitle' role=\"presentation\">\n\t<div data-dojo-attach-point='titleNode,focusNode' data-dojo-attach-event='onkeypress:_onTitleKeyPress'\n\t\t\tclass='dijitAccordionTitleFocus' role=\"tab\" aria-expanded=\"false\"\n\t\t><span class='dijitInline dijitAccordionArrow' role=\"presentation\"></span\n\t\t><span class='arrowTextUp' role=\"presentation\">+</span\n\t\t><span class='arrowTextDown' role=\"presentation\">-</span\n\t\t><img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" data-dojo-attach-point='iconNode' style=\"vertical-align: middle\" role=\"presentation\"/>\n\t\t<span role=\"presentation\" data-dojo-attach-point='titleTextNode' class='dijitAccordionText'></span>\n\t</div>\n</div>\n",
  3563. 'dijit/TitlePane':function(){
  3564. define([
  3565. "dojo/_base/array", // array.forEach
  3566. "dojo/_base/declare", // declare
  3567. "dojo/dom", // dom.setSelectable
  3568. "dojo/dom-attr", // domAttr.set or get domAttr.remove
  3569. "dojo/dom-class", // domClass.replace
  3570. "dojo/dom-geometry", // domGeometry.setMarginBox domGeometry.getMarginBox
  3571. "dojo/_base/event", // event.stop
  3572. "dojo/fx", // fxUtils.wipeIn fxUtils.wipeOut
  3573. "dojo/_base/kernel", // kernel.deprecated
  3574. "dojo/keys", // keys.DOWN_ARROW keys.ENTER
  3575. "./_CssStateMixin",
  3576. "./_TemplatedMixin",
  3577. "./layout/ContentPane",
  3578. "dojo/text!./templates/TitlePane.html",
  3579. "./_base/manager" // defaultDuration
  3580. ], function(array, declare, dom, domAttr, domClass, domGeometry, event, fxUtils, kernel, keys,
  3581. _CssStateMixin, _TemplatedMixin, ContentPane, template, manager){
  3582. /*=====
  3583. var _Widget = dijit._Widget;
  3584. var _TemplatedMixin = dijit._TemplatedMixin;
  3585. var _CssStateMixin = dijit._CssStateMixin;
  3586. var ContentPane = dijit.layout.ContentPane;
  3587. =====*/
  3588. // module:
  3589. // dijit/TitlePane
  3590. // summary:
  3591. // A pane with a title on top, that can be expanded or collapsed.
  3592. return declare("dijit.TitlePane", [ContentPane, _TemplatedMixin, _CssStateMixin], {
  3593. // summary:
  3594. // A pane with a title on top, that can be expanded or collapsed.
  3595. //
  3596. // description:
  3597. // An accessible container with a title Heading, and a content
  3598. // section that slides open and closed. TitlePane is an extension to
  3599. // `dijit.layout.ContentPane`, providing all the useful content-control aspects from it.
  3600. //
  3601. // example:
  3602. // | // load a TitlePane from remote file:
  3603. // | var foo = new dijit.TitlePane({ href: "foobar.html", title:"Title" });
  3604. // | foo.startup();
  3605. //
  3606. // example:
  3607. // | <!-- markup href example: -->
  3608. // | <div data-dojo-type="dijit.TitlePane" data-dojo-props="href: 'foobar.html', title: 'Title'"></div>
  3609. //
  3610. // example:
  3611. // | <!-- markup with inline data -->
  3612. // | <div data-dojo-type="dijit.TitlePane" title="Title">
  3613. // | <p>I am content</p>
  3614. // | </div>
  3615. // title: String
  3616. // Title of the pane
  3617. title: "",
  3618. _setTitleAttr: { node: "titleNode", type: "innerHTML" }, // override default where title becomes a hover tooltip
  3619. // open: Boolean
  3620. // Whether pane is opened or closed.
  3621. open: true,
  3622. // toggleable: Boolean
  3623. // Whether pane can be opened or closed by clicking the title bar.
  3624. toggleable: true,
  3625. // tabIndex: String
  3626. // Tabindex setting for the title (so users can tab to the title then
  3627. // use space/enter to open/close the title pane)
  3628. tabIndex: "0",
  3629. // duration: Integer
  3630. // Time in milliseconds to fade in/fade out
  3631. duration: manager.defaultDuration,
  3632. // baseClass: [protected] String
  3633. // The root className to be placed on this widget's domNode.
  3634. baseClass: "dijitTitlePane",
  3635. templateString: template,
  3636. // doLayout: [protected] Boolean
  3637. // Don't change this parameter from the default value.
  3638. // This ContentPane parameter doesn't make sense for TitlePane, since TitlePane
  3639. // is never a child of a layout container, nor should TitlePane try to control
  3640. // the size of an inner widget.
  3641. doLayout: false,
  3642. // Tooltip is defined in _WidgetBase but we need to handle the mapping to DOM here
  3643. _setTooltipAttr: {node: "focusNode", type: "attribute", attribute: "title"}, // focusNode spans the entire width, titleNode doesn't
  3644. buildRendering: function(){
  3645. this.inherited(arguments);
  3646. dom.setSelectable(this.titleNode, false);
  3647. },
  3648. postCreate: function(){
  3649. this.inherited(arguments);
  3650. // Hover and focus effect on title bar, except for non-toggleable TitlePanes
  3651. // This should really be controlled from _setToggleableAttr() but _CssStateMixin
  3652. // doesn't provide a way to disconnect a previous _trackMouseState() call
  3653. if(this.toggleable){
  3654. this._trackMouseState(this.titleBarNode, "dijitTitlePaneTitle");
  3655. }
  3656. // setup open/close animations
  3657. var hideNode = this.hideNode, wipeNode = this.wipeNode;
  3658. this._wipeIn = fxUtils.wipeIn({
  3659. node: wipeNode,
  3660. duration: this.duration,
  3661. beforeBegin: function(){
  3662. hideNode.style.display="";
  3663. }
  3664. });
  3665. this._wipeOut = fxUtils.wipeOut({
  3666. node: wipeNode,
  3667. duration: this.duration,
  3668. onEnd: function(){
  3669. hideNode.style.display="none";
  3670. }
  3671. });
  3672. },
  3673. _setOpenAttr: function(/*Boolean*/ open, /*Boolean*/ animate){
  3674. // summary:
  3675. // Hook to make set("open", boolean) control the open/closed state of the pane.
  3676. // open: Boolean
  3677. // True if you want to open the pane, false if you want to close it.
  3678. array.forEach([this._wipeIn, this._wipeOut], function(animation){
  3679. if(animation && animation.status() == "playing"){
  3680. animation.stop();
  3681. }
  3682. });
  3683. if(animate){
  3684. var anim = this[open ? "_wipeIn" : "_wipeOut"];
  3685. anim.play();
  3686. }else{
  3687. this.hideNode.style.display = this.wipeNode.style.display = open ? "" : "none";
  3688. }
  3689. // load content (if this is the first time we are opening the TitlePane
  3690. // and content is specified as an href, or href was set when hidden)
  3691. if(this._started){
  3692. if(open){
  3693. this._onShow();
  3694. }else{
  3695. this.onHide();
  3696. }
  3697. }
  3698. this.arrowNodeInner.innerHTML = open ? "-" : "+";
  3699. this.containerNode.setAttribute("aria-hidden", open ? "false" : "true");
  3700. this.focusNode.setAttribute("aria-pressed", open ? "true" : "false");
  3701. this._set("open", open);
  3702. this._setCss();
  3703. },
  3704. _setToggleableAttr: function(/*Boolean*/ canToggle){
  3705. // summary:
  3706. // Hook to make set("toggleable", boolean) work.
  3707. // canToggle: Boolean
  3708. // True to allow user to open/close pane by clicking title bar.
  3709. this.focusNode.setAttribute("role", canToggle ? "button" : "heading");
  3710. if(canToggle){
  3711. // TODO: if canToggle is switched from true to false shouldn't we remove this setting?
  3712. this.focusNode.setAttribute("aria-controls", this.id+"_pane");
  3713. domAttr.set(this.focusNode, "tabIndex", this.tabIndex);
  3714. }else{
  3715. domAttr.remove(this.focusNode, "tabIndex");
  3716. }
  3717. this._set("toggleable", canToggle);
  3718. this._setCss();
  3719. },
  3720. _setContentAttr: function(/*String|DomNode|Nodelist*/ content){
  3721. // summary:
  3722. // Hook to make set("content", ...) work.
  3723. // Typically called when an href is loaded. Our job is to make the animation smooth.
  3724. if(!this.open || !this._wipeOut || this._wipeOut.status() == "playing"){
  3725. // we are currently *closing* the pane (or the pane is closed), so just let that continue
  3726. this.inherited(arguments);
  3727. }else{
  3728. if(this._wipeIn && this._wipeIn.status() == "playing"){
  3729. this._wipeIn.stop();
  3730. }
  3731. // freeze container at current height so that adding new content doesn't make it jump
  3732. domGeometry.setMarginBox(this.wipeNode, { h: domGeometry.getMarginBox(this.wipeNode).h });
  3733. // add the new content (erasing the old content, if any)
  3734. this.inherited(arguments);
  3735. // call _wipeIn.play() to animate from current height to new height
  3736. if(this._wipeIn){
  3737. this._wipeIn.play();
  3738. }else{
  3739. this.hideNode.style.display = "";
  3740. }
  3741. }
  3742. },
  3743. toggle: function(){
  3744. // summary:
  3745. // Switches between opened and closed state
  3746. // tags:
  3747. // private
  3748. this._setOpenAttr(!this.open, true);
  3749. },
  3750. _setCss: function(){
  3751. // summary:
  3752. // Set the open/close css state for the TitlePane
  3753. // tags:
  3754. // private
  3755. var node = this.titleBarNode || this.focusNode;
  3756. var oldCls = this._titleBarClass;
  3757. this._titleBarClass = "dijit" + (this.toggleable ? "" : "Fixed") + (this.open ? "Open" : "Closed");
  3758. domClass.replace(node, this._titleBarClass, oldCls || "");
  3759. this.arrowNodeInner.innerHTML = this.open ? "-" : "+";
  3760. },
  3761. _onTitleKey: function(/*Event*/ e){
  3762. // summary:
  3763. // Handler for when user hits a key
  3764. // tags:
  3765. // private
  3766. if(e.keyCode == keys.ENTER || e.keyCode == keys.SPACE){
  3767. if(this.toggleable){
  3768. this.toggle();
  3769. event.stop(e);
  3770. }
  3771. }else if(e.keyCode == keys.DOWN_ARROW && this.open){
  3772. this.containerNode.focus();
  3773. e.preventDefault();
  3774. }
  3775. },
  3776. _onTitleClick: function(){
  3777. // summary:
  3778. // Handler when user clicks the title bar
  3779. // tags:
  3780. // private
  3781. if(this.toggleable){
  3782. this.toggle();
  3783. }
  3784. },
  3785. setTitle: function(/*String*/ title){
  3786. // summary:
  3787. // Deprecated. Use set('title', ...) instead.
  3788. // tags:
  3789. // deprecated
  3790. kernel.deprecated("dijit.TitlePane.setTitle() is deprecated. Use set('title', ...) instead.", "", "2.0");
  3791. this.set("title", title);
  3792. }
  3793. });
  3794. });
  3795. },
  3796. 'dijit/form/_ComboBoxMenuMixin':function(){
  3797. define([
  3798. "dojo/_base/array", // array.forEach
  3799. "dojo/_base/declare", // declare
  3800. "dojo/dom-attr", // domAttr.set
  3801. "dojo/i18n", // i18n.getLocalization
  3802. "dojo/_base/window", // win.doc.createTextNode
  3803. "dojo/i18n!./nls/ComboBox"
  3804. ], function(array, declare, domAttr, i18n, win){
  3805. // module:
  3806. // dijit/form/_ComboBoxMenuMixin
  3807. // summary:
  3808. // Focus-less menu for internal use in `dijit.form.ComboBox`
  3809. return declare( "dijit.form._ComboBoxMenuMixin", null, {
  3810. // summary:
  3811. // Focus-less menu for internal use in `dijit.form.ComboBox`
  3812. // tags:
  3813. // private
  3814. // _messages: Object
  3815. // Holds "next" and "previous" text for paging buttons on drop down
  3816. _messages: null,
  3817. postMixInProperties: function(){
  3818. this.inherited(arguments);
  3819. this._messages = i18n.getLocalization("dijit.form", "ComboBox", this.lang);
  3820. },
  3821. buildRendering: function(){
  3822. this.inherited(arguments);
  3823. // fill in template with i18n messages
  3824. this.previousButton.innerHTML = this._messages["previousMessage"];
  3825. this.nextButton.innerHTML = this._messages["nextMessage"];
  3826. },
  3827. _setValueAttr: function(/*Object*/ value){
  3828. this.value = value;
  3829. this.onChange(value);
  3830. },
  3831. onClick: function(/*DomNode*/ node){
  3832. if(node == this.previousButton){
  3833. this._setSelectedAttr(null);
  3834. this.onPage(-1);
  3835. }else if(node == this.nextButton){
  3836. this._setSelectedAttr(null);
  3837. this.onPage(1);
  3838. }else{
  3839. this.onChange(node);
  3840. }
  3841. },
  3842. // stubs
  3843. onChange: function(/*Number*/ /*===== direction =====*/){
  3844. // summary:
  3845. // Notifies ComboBox/FilteringSelect that user selected an option.
  3846. // tags:
  3847. // callback
  3848. },
  3849. onPage: function(/*Number*/ /*===== direction =====*/){
  3850. // summary:
  3851. // Notifies ComboBox/FilteringSelect that user clicked to advance to next/previous page.
  3852. // tags:
  3853. // callback
  3854. },
  3855. onClose: function(){
  3856. // summary:
  3857. // Callback from dijit.popup code to this widget, notifying it that it closed
  3858. // tags:
  3859. // private
  3860. this._setSelectedAttr(null);
  3861. },
  3862. _createOption: function(/*Object*/ item, labelFunc){
  3863. // summary:
  3864. // Creates an option to appear on the popup menu subclassed by
  3865. // `dijit.form.FilteringSelect`.
  3866. var menuitem = this._createMenuItem();
  3867. var labelObject = labelFunc(item);
  3868. if(labelObject.html){
  3869. menuitem.innerHTML = labelObject.label;
  3870. }else{
  3871. menuitem.appendChild(
  3872. win.doc.createTextNode(labelObject.label)
  3873. );
  3874. }
  3875. // #3250: in blank options, assign a normal height
  3876. if(menuitem.innerHTML == ""){
  3877. menuitem.innerHTML = "&#160;"; // &nbsp;
  3878. }
  3879. // update menuitem.dir if BidiSupport was required
  3880. this.applyTextDir(menuitem, (menuitem.innerText || menuitem.textContent || ""));
  3881. menuitem.item=item;
  3882. return menuitem;
  3883. },
  3884. createOptions: function(results, options, labelFunc){
  3885. // summary:
  3886. // Fills in the items in the drop down list
  3887. // results:
  3888. // Array of items
  3889. // options:
  3890. // The options to the query function of the store
  3891. //
  3892. // labelFunc:
  3893. // Function to produce a label in the drop down list from a dojo.data item
  3894. this.items = results;
  3895. // display "Previous . . ." button
  3896. this.previousButton.style.display = (options.start == 0) ? "none" : "";
  3897. domAttr.set(this.previousButton, "id", this.id + "_prev");
  3898. // create options using _createOption function defined by parent
  3899. // ComboBox (or FilteringSelect) class
  3900. // #2309:
  3901. // iterate over cache nondestructively
  3902. array.forEach(results, function(item, i){
  3903. var menuitem = this._createOption(item, labelFunc);
  3904. menuitem.setAttribute("item", i); // index to this.items; use indirection to avoid mem leak
  3905. domAttr.set(menuitem, "id", this.id + i);
  3906. this.nextButton.parentNode.insertBefore(menuitem, this.nextButton);
  3907. }, this);
  3908. // display "Next . . ." button
  3909. var displayMore = false;
  3910. // Try to determine if we should show 'more'...
  3911. if(results.total && !results.total.then && results.total != -1){
  3912. if((options.start + options.count) < results.total){
  3913. displayMore = true;
  3914. }else if((options.start + options.count) > results.total && options.count == results.length){
  3915. // Weird return from a data store, where a start + count > maxOptions
  3916. // implies maxOptions isn't really valid and we have to go into faking it.
  3917. // And more or less assume more if count == results.length
  3918. displayMore = true;
  3919. }
  3920. }else if(options.count == results.length){
  3921. //Don't know the size, so we do the best we can based off count alone.
  3922. //So, if we have an exact match to count, assume more.
  3923. displayMore = true;
  3924. }
  3925. this.nextButton.style.display = displayMore ? "" : "none";
  3926. domAttr.set(this.nextButton,"id", this.id + "_next");
  3927. },
  3928. clearResultList: function(){
  3929. // summary:
  3930. // Clears the entries in the drop down list, but of course keeps the previous and next buttons.
  3931. var container = this.containerNode;
  3932. while(container.childNodes.length > 2){
  3933. container.removeChild(container.childNodes[container.childNodes.length-2]);
  3934. }
  3935. this._setSelectedAttr(null);
  3936. },
  3937. highlightFirstOption: function(){
  3938. // summary:
  3939. // Highlight the first real item in the list (not Previous Choices).
  3940. this.selectFirstNode();
  3941. },
  3942. highlightLastOption: function(){
  3943. // summary:
  3944. // Highlight the last real item in the list (not More Choices).
  3945. this.selectLastNode();
  3946. },
  3947. selectFirstNode: function(){
  3948. this.inherited(arguments);
  3949. if(this.getHighlightedOption() == this.previousButton){
  3950. this.selectNextNode();
  3951. }
  3952. },
  3953. selectLastNode: function(){
  3954. this.inherited(arguments);
  3955. if(this.getHighlightedOption() == this.nextButton){
  3956. this.selectPreviousNode();
  3957. }
  3958. },
  3959. getHighlightedOption: function(){
  3960. return this._getSelectedAttr();
  3961. }
  3962. });
  3963. });
  3964. },
  3965. 'url:dijit/form/templates/DropDownButton.html':"<span class=\"dijit dijitReset dijitInline\"\n\t><span class='dijitReset dijitInline dijitButtonNode'\n\t\tdata-dojo-attach-event=\"ondijitclick:_onClick\" data-dojo-attach-point=\"_buttonNode\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdata-dojo-attach-point=\"focusNode,titleNode,_arrowWrapperNode\"\n\t\t\trole=\"button\" aria-haspopup=\"true\" aria-labelledby=\"${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\"\n\t\t\t\tdata-dojo-attach-point=\"iconNode\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tdata-dojo-attach-point=\"containerNode,_popupStateNode\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonInner\"></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonChar\">&#9660;</span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\" tabIndex=\"-1\"\n\t\tdata-dojo-attach-point=\"valueNode\" role=\"presentation\"\n/></span>\n",
  3966. 'dijit/form/ToggleButton':function(){
  3967. define("dijit/form/ToggleButton", [
  3968. "dojo/_base/declare", // declare
  3969. "dojo/_base/kernel", // kernel.deprecated
  3970. "./Button",
  3971. "./_ToggleButtonMixin"
  3972. ], function(declare, kernel, Button, _ToggleButtonMixin){
  3973. /*=====
  3974. var Button = dijit.form.Button;
  3975. var _ToggleButtonMixin = dijit.form._ToggleButtonMixin;
  3976. =====*/
  3977. // module:
  3978. // dijit/form/ToggleButton
  3979. // summary:
  3980. // A templated button widget that can be in two states (checked or not).
  3981. return declare("dijit.form.ToggleButton", [Button, _ToggleButtonMixin], {
  3982. // summary:
  3983. // A templated button widget that can be in two states (checked or not).
  3984. // Can be base class for things like tabs or checkbox or radio buttons
  3985. baseClass: "dijitToggleButton",
  3986. setChecked: function(/*Boolean*/ checked){
  3987. // summary:
  3988. // Deprecated. Use set('checked', true/false) instead.
  3989. kernel.deprecated("setChecked("+checked+") is deprecated. Use set('checked',"+checked+") instead.", "", "2.0");
  3990. this.set('checked', checked);
  3991. }
  3992. });
  3993. });
  3994. },
  3995. 'dijit/form/NumberSpinner':function(){
  3996. define([
  3997. "dojo/_base/declare", // declare
  3998. "dojo/_base/event", // event.stop
  3999. "dojo/keys", // keys.END keys.HOME
  4000. "./_Spinner",
  4001. "./NumberTextBox"
  4002. ], function(declare, event, keys, _Spinner, NumberTextBox){
  4003. /*=====
  4004. var _Spinner = dijit.form._Spinner;
  4005. var NumberTextBox = dijit.form.NumberTextBox;
  4006. =====*/
  4007. // module:
  4008. // dijit/form/NumberSpinner
  4009. // summary:
  4010. // Extends NumberTextBox to add up/down arrows and pageup/pagedown for incremental change to the value
  4011. return declare("dijit.form.NumberSpinner", [_Spinner, NumberTextBox.Mixin], {
  4012. // summary:
  4013. // Extends NumberTextBox to add up/down arrows and pageup/pagedown for incremental change to the value
  4014. //
  4015. // description:
  4016. // A `dijit.form.NumberTextBox` extension to provide keyboard accessible value selection
  4017. // as well as icons for spinning direction. When using the keyboard, the typematic rules
  4018. // apply, meaning holding the key will gradually increase or decrease the value and
  4019. // accelerate.
  4020. //
  4021. // example:
  4022. // | new dijit.form.NumberSpinner({ constraints:{ max:300, min:100 }}, "someInput");
  4023. adjust: function(/*Object*/ val, /*Number*/ delta){
  4024. // summary:
  4025. // Change Number val by the given amount
  4026. // tags:
  4027. // protected
  4028. var tc = this.constraints,
  4029. v = isNaN(val),
  4030. gotMax = !isNaN(tc.max),
  4031. gotMin = !isNaN(tc.min)
  4032. ;
  4033. if(v && delta != 0){ // blank or invalid value and they want to spin, so create defaults
  4034. val = (delta > 0) ?
  4035. gotMin ? tc.min : gotMax ? tc.max : 0 :
  4036. gotMax ? this.constraints.max : gotMin ? tc.min : 0
  4037. ;
  4038. }
  4039. var newval = val + delta;
  4040. if(v || isNaN(newval)){ return val; }
  4041. if(gotMax && (newval > tc.max)){
  4042. newval = tc.max;
  4043. }
  4044. if(gotMin && (newval < tc.min)){
  4045. newval = tc.min;
  4046. }
  4047. return newval;
  4048. },
  4049. _onKeyPress: function(e){
  4050. if((e.charOrCode == keys.HOME || e.charOrCode == keys.END) && !(e.ctrlKey || e.altKey || e.metaKey)
  4051. && typeof this.get('value') != 'undefined' /* gibberish, so HOME and END are default editing keys*/){
  4052. var value = this.constraints[(e.charOrCode == keys.HOME ? "min" : "max")];
  4053. if(typeof value == "number"){
  4054. this._setValueAttr(value, false);
  4055. }
  4056. // eat home or end key whether we change the value or not
  4057. event.stop(e);
  4058. }
  4059. }
  4060. });
  4061. });
  4062. },
  4063. 'dijit/form/Textarea':function(){
  4064. define([
  4065. "dojo/_base/declare", // declare
  4066. "dojo/dom-style", // domStyle.set
  4067. "./_ExpandingTextAreaMixin",
  4068. "./SimpleTextarea"
  4069. ], function(declare, domStyle, _ExpandingTextAreaMixin, SimpleTextarea){
  4070. /*=====
  4071. var _ExpandingTextAreaMixin = dijit.form._ExpandingTextAreaMixin;
  4072. var SimpleTextarea = dijit.form.SimpleTextarea;
  4073. =====*/
  4074. // module:
  4075. // dijit/form/Textarea
  4076. // summary:
  4077. // A textarea widget that adjusts it's height according to the amount of data.
  4078. return declare("dijit.form.Textarea", [SimpleTextarea, _ExpandingTextAreaMixin], {
  4079. // summary:
  4080. // A textarea widget that adjusts it's height according to the amount of data.
  4081. //
  4082. // description:
  4083. // A textarea that dynamically expands/contracts (changing it's height) as
  4084. // the user types, to display all the text without requiring a scroll bar.
  4085. //
  4086. // Takes nearly all the parameters (name, value, etc.) that a vanilla textarea takes.
  4087. // Rows is not supported since this widget adjusts the height.
  4088. //
  4089. // example:
  4090. // | <textarea data-dojo-type="dijit.form.TextArea">...</textarea>
  4091. // TODO: for 2.0, rename this to ExpandingTextArea, and rename SimpleTextarea to TextArea
  4092. baseClass: "dijitTextBox dijitTextArea dijitExpandingTextArea",
  4093. // Override SimpleTextArea.cols to default to width:100%, for backward compatibility
  4094. cols: "",
  4095. buildRendering: function(){
  4096. this.inherited(arguments);
  4097. // tweak textarea style to reduce browser differences
  4098. domStyle.set(this.textbox, { overflowY: 'hidden', overflowX: 'auto', boxSizing: 'border-box', MsBoxSizing: 'border-box', WebkitBoxSizing: 'border-box', MozBoxSizing: 'border-box' });
  4099. }
  4100. });
  4101. });
  4102. },
  4103. 'dijit/form/DateTextBox':function(){
  4104. define([
  4105. "dojo/_base/declare", // declare
  4106. "../Calendar",
  4107. "./_DateTimeTextBox"
  4108. ], function(declare, Calendar, _DateTimeTextBox){
  4109. /*=====
  4110. var Calendar = dijit.Calendar;
  4111. var _DateTimeTextBox = dijit.form._DateTimeTextBox;
  4112. =====*/
  4113. // module:
  4114. // dijit/form/DateTextBox
  4115. // summary:
  4116. // A validating, serializable, range-bound date text box with a drop down calendar
  4117. return declare("dijit.form.DateTextBox", _DateTimeTextBox, {
  4118. // summary:
  4119. // A validating, serializable, range-bound date text box with a drop down calendar
  4120. //
  4121. // Example:
  4122. // | new dijit.form.DateTextBox({value: new Date(2009, 0, 20)})
  4123. //
  4124. // Example:
  4125. // | <input data-dojo-type='dijit.form.DateTextBox' value='2009-01-20'>
  4126. baseClass: "dijitTextBox dijitComboBox dijitDateTextBox",
  4127. popupClass: Calendar,
  4128. _selector: "date",
  4129. // value: Date
  4130. // The value of this widget as a JavaScript Date object, with only year/month/day specified.
  4131. // If specified in markup, use the format specified in `stamp.fromISOString`.
  4132. // set("value", ...) accepts either a Date object or a string.
  4133. value: new Date("") // value.toString()="NaN"
  4134. });
  4135. });
  4136. },
  4137. 'dijit/form/ComboButton':function(){
  4138. define([
  4139. "dojo/_base/declare", // declare
  4140. "dojo/_base/event", // event.stop
  4141. "dojo/keys", // keys
  4142. "../focus", // focus.focus()
  4143. "./DropDownButton",
  4144. "dojo/text!./templates/ComboButton.html"
  4145. ], function(declare, event, keys, focus, DropDownButton, template){
  4146. /*=====
  4147. var DropDownButton = dijit.form.DropDownButton;
  4148. =====*/
  4149. // module:
  4150. // dijit/form/ComboButton
  4151. // summary:
  4152. // A combination button and drop-down button.
  4153. return declare("dijit.form.ComboButton", DropDownButton, {
  4154. // summary:
  4155. // A combination button and drop-down button.
  4156. // Users can click one side to "press" the button, or click an arrow
  4157. // icon to display the drop down.
  4158. //
  4159. // example:
  4160. // | <button data-dojo-type="dijit.form.ComboButton" onClick="...">
  4161. // | <span>Hello world</span>
  4162. // | <div data-dojo-type="dijit.Menu">...</div>
  4163. // | </button>
  4164. //
  4165. // example:
  4166. // | var button1 = new dijit.form.ComboButton({label: "hello world", onClick: foo, dropDown: "myMenu"});
  4167. // | dojo.body().appendChild(button1.domNode);
  4168. //
  4169. templateString: template,
  4170. // Map widget attributes to DOMNode attributes.
  4171. _setIdAttr: "", // override _FormWidgetMixin which puts id on the focusNode
  4172. _setTabIndexAttr: ["focusNode", "titleNode"],
  4173. _setTitleAttr: "titleNode",
  4174. // optionsTitle: String
  4175. // Text that describes the options menu (accessibility)
  4176. optionsTitle: "",
  4177. baseClass: "dijitComboButton",
  4178. // Set classes like dijitButtonContentsHover or dijitArrowButtonActive depending on
  4179. // mouse action over specified node
  4180. cssStateNodes: {
  4181. "buttonNode": "dijitButtonNode",
  4182. "titleNode": "dijitButtonContents",
  4183. "_popupStateNode": "dijitDownArrowButton"
  4184. },
  4185. _focusedNode: null,
  4186. _onButtonKeyPress: function(/*Event*/ evt){
  4187. // summary:
  4188. // Handler for right arrow key when focus is on left part of button
  4189. if(evt.charOrCode == keys[this.isLeftToRight() ? "RIGHT_ARROW" : "LEFT_ARROW"]){
  4190. focus.focus(this._popupStateNode);
  4191. event.stop(evt);
  4192. }
  4193. },
  4194. _onArrowKeyPress: function(/*Event*/ evt){
  4195. // summary:
  4196. // Handler for left arrow key when focus is on right part of button
  4197. if(evt.charOrCode == keys[this.isLeftToRight() ? "LEFT_ARROW" : "RIGHT_ARROW"]){
  4198. focus.focus(this.titleNode);
  4199. event.stop(evt);
  4200. }
  4201. },
  4202. focus: function(/*String*/ position){
  4203. // summary:
  4204. // Focuses this widget to according to position, if specified,
  4205. // otherwise on arrow node
  4206. // position:
  4207. // "start" or "end"
  4208. if(!this.disabled){
  4209. focus.focus(position == "start" ? this.titleNode : this._popupStateNode);
  4210. }
  4211. }
  4212. });
  4213. });
  4214. },
  4215. 'dijit/layout/AccordionContainer':function(){
  4216. require({cache:{
  4217. 'url:dijit/layout/templates/AccordionButton.html':"<div data-dojo-attach-event='onclick:_onTitleClick' class='dijitAccordionTitle' role=\"presentation\">\n\t<div data-dojo-attach-point='titleNode,focusNode' data-dojo-attach-event='onkeypress:_onTitleKeyPress'\n\t\t\tclass='dijitAccordionTitleFocus' role=\"tab\" aria-expanded=\"false\"\n\t\t><span class='dijitInline dijitAccordionArrow' role=\"presentation\"></span\n\t\t><span class='arrowTextUp' role=\"presentation\">+</span\n\t\t><span class='arrowTextDown' role=\"presentation\">-</span\n\t\t><img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" data-dojo-attach-point='iconNode' style=\"vertical-align: middle\" role=\"presentation\"/>\n\t\t<span role=\"presentation\" data-dojo-attach-point='titleTextNode' class='dijitAccordionText'></span>\n\t</div>\n</div>\n"}});
  4218. define("dijit/layout/AccordionContainer", [
  4219. "require",
  4220. "dojo/_base/array", // array.forEach array.map
  4221. "dojo/_base/declare", // declare
  4222. "dojo/_base/event", // event.stop
  4223. "dojo/_base/fx", // fx.Animation
  4224. "dojo/dom", // dom.setSelectable
  4225. "dojo/dom-attr", // domAttr.attr
  4226. "dojo/dom-class", // domClass.remove
  4227. "dojo/dom-construct", // domConstruct.place
  4228. "dojo/dom-geometry",
  4229. "dojo/_base/kernel",
  4230. "dojo/keys", // keys
  4231. "dojo/_base/lang", // lang.getObject lang.hitch
  4232. "dojo/_base/sniff", // has("ie")
  4233. "dojo/topic", // publish
  4234. "../focus", // focus.focus()
  4235. "../_base/manager", // manager.defaultDuration
  4236. "dojo/ready",
  4237. "../_Widget",
  4238. "../_Container",
  4239. "../_TemplatedMixin",
  4240. "../_CssStateMixin",
  4241. "./StackContainer",
  4242. "./ContentPane",
  4243. "dojo/text!./templates/AccordionButton.html"
  4244. ], function(require, array, declare, event, fx, dom, domAttr, domClass, domConstruct, domGeometry,
  4245. kernel, keys, lang, has, topic, focus, manager, ready,
  4246. _Widget, _Container, _TemplatedMixin, _CssStateMixin, StackContainer, ContentPane, template){
  4247. /*=====
  4248. var _Widget = dijit._Widget;
  4249. var _Container = dijit._Container;
  4250. var _TemplatedMixin = dijit._TemplatedMixin;
  4251. var _CssStateMixin = dijit._CssStateMixin;
  4252. var StackContainer = dijit.layout.StackContainer;
  4253. var ContentPane = dijit.layout.ContentPane;
  4254. =====*/
  4255. // module:
  4256. // dijit/layout/AccordionContainer
  4257. // summary:
  4258. // Holds a set of panes where every pane's title is visible, but only one pane's content is visible at a time,
  4259. // and switching between panes is visualized by sliding the other panes up/down.
  4260. // Design notes:
  4261. //
  4262. // An AccordionContainer is a StackContainer, but each child (typically ContentPane)
  4263. // is wrapped in a _AccordionInnerContainer. This is hidden from the caller.
  4264. //
  4265. // The resulting markup will look like:
  4266. //
  4267. // <div class=dijitAccordionContainer>
  4268. // <div class=dijitAccordionInnerContainer> (one pane)
  4269. // <div class=dijitAccordionTitle> (title bar) ... </div>
  4270. // <div class=dijtAccordionChildWrapper> (content pane) </div>
  4271. // </div>
  4272. // </div>
  4273. //
  4274. // Normally the dijtAccordionChildWrapper is hidden for all but one child (the shown
  4275. // child), so the space for the content pane is all the title bars + the one dijtAccordionChildWrapper,
  4276. // which on claro has a 1px border plus a 2px bottom margin.
  4277. //
  4278. // During animation there are two dijtAccordionChildWrapper's shown, so we need
  4279. // to compensate for that.
  4280. var AccordionButton = declare("dijit.layout._AccordionButton", [_Widget, _TemplatedMixin, _CssStateMixin], {
  4281. // summary:
  4282. // The title bar to click to open up an accordion pane.
  4283. // Internal widget used by AccordionContainer.
  4284. // tags:
  4285. // private
  4286. templateString: template,
  4287. // label: String
  4288. // Title of the pane
  4289. label: "",
  4290. _setLabelAttr: {node: "titleTextNode", type: "innerHTML" },
  4291. // title: String
  4292. // Tooltip that appears on hover
  4293. title: "",
  4294. _setTitleAttr: {node: "titleTextNode", type: "attribute", attribute: "title"},
  4295. // iconClassAttr: String
  4296. // CSS class for icon to left of label
  4297. iconClassAttr: "",
  4298. _setIconClassAttr: { node: "iconNode", type: "class" },
  4299. baseClass: "dijitAccordionTitle",
  4300. getParent: function(){
  4301. // summary:
  4302. // Returns the AccordionContainer parent.
  4303. // tags:
  4304. // private
  4305. return this.parent;
  4306. },
  4307. buildRendering: function(){
  4308. this.inherited(arguments);
  4309. var titleTextNodeId = this.id.replace(' ','_');
  4310. domAttr.set(this.titleTextNode, "id", titleTextNodeId+"_title");
  4311. this.focusNode.setAttribute("aria-labelledby", domAttr.get(this.titleTextNode, "id"));
  4312. dom.setSelectable(this.domNode, false);
  4313. },
  4314. getTitleHeight: function(){
  4315. // summary:
  4316. // Returns the height of the title dom node.
  4317. return domGeometry.getMarginSize(this.domNode).h; // Integer
  4318. },
  4319. // TODO: maybe the parent should set these methods directly rather than forcing the code
  4320. // into the button widget?
  4321. _onTitleClick: function(){
  4322. // summary:
  4323. // Callback when someone clicks my title.
  4324. var parent = this.getParent();
  4325. parent.selectChild(this.contentWidget, true);
  4326. focus.focus(this.focusNode);
  4327. },
  4328. _onTitleKeyPress: function(/*Event*/ evt){
  4329. return this.getParent()._onKeyPress(evt, this.contentWidget);
  4330. },
  4331. _setSelectedAttr: function(/*Boolean*/ isSelected){
  4332. this._set("selected", isSelected);
  4333. this.focusNode.setAttribute("aria-expanded", isSelected);
  4334. this.focusNode.setAttribute("aria-selected", isSelected);
  4335. this.focusNode.setAttribute("tabIndex", isSelected ? "0" : "-1");
  4336. }
  4337. });
  4338. var AccordionInnerContainer = declare("dijit.layout._AccordionInnerContainer", [_Widget, _CssStateMixin], {
  4339. // summary:
  4340. // Internal widget placed as direct child of AccordionContainer.containerNode.
  4341. // When other widgets are added as children to an AccordionContainer they are wrapped in
  4342. // this widget.
  4343. /*=====
  4344. // buttonWidget: Function || String
  4345. // Class to use to instantiate title
  4346. // (Wish we didn't have a separate widget for just the title but maintaining it
  4347. // for backwards compatibility, is it worth it?)
  4348. buttonWidget: null,
  4349. =====*/
  4350. /*=====
  4351. // contentWidget: dijit._Widget
  4352. // Pointer to the real child widget
  4353. contentWidget: null,
  4354. =====*/
  4355. baseClass: "dijitAccordionInnerContainer",
  4356. // tell nested layout widget that we will take care of sizing
  4357. isLayoutContainer: true,
  4358. buildRendering: function(){
  4359. // Builds a template like:
  4360. // <div class=dijitAccordionInnerContainer>
  4361. // Button
  4362. // <div class=dijitAccordionChildWrapper>
  4363. // ContentPane
  4364. // </div>
  4365. // </div>
  4366. // Create wrapper div, placed where the child is now
  4367. this.domNode = domConstruct.place("<div class='" + this.baseClass +
  4368. "' role='presentation'>", this.contentWidget.domNode, "after");
  4369. // wrapper div's first child is the button widget (ie, the title bar)
  4370. var child = this.contentWidget,
  4371. cls = lang.isString(this.buttonWidget) ? lang.getObject(this.buttonWidget) : this.buttonWidget;
  4372. this.button = child._buttonWidget = (new cls({
  4373. contentWidget: child,
  4374. label: child.title,
  4375. title: child.tooltip,
  4376. dir: child.dir,
  4377. lang: child.lang,
  4378. textDir: child.textDir,
  4379. iconClass: child.iconClass,
  4380. id: child.id + "_button",
  4381. parent: this.parent
  4382. })).placeAt(this.domNode);
  4383. // and then the actual content widget (changing it from prior-sibling to last-child),
  4384. // wrapped by a <div class=dijitAccordionChildWrapper>
  4385. this.containerNode = domConstruct.place("<div class='dijitAccordionChildWrapper' style='display:none'>", this.domNode);
  4386. domConstruct.place(this.contentWidget.domNode, this.containerNode);
  4387. },
  4388. postCreate: function(){
  4389. this.inherited(arguments);
  4390. // Map changes in content widget's title etc. to changes in the button
  4391. var button = this.button;
  4392. this._contentWidgetWatches = [
  4393. this.contentWidget.watch('title', lang.hitch(this, function(name, oldValue, newValue){
  4394. button.set("label", newValue);
  4395. })),
  4396. this.contentWidget.watch('tooltip', lang.hitch(this, function(name, oldValue, newValue){
  4397. button.set("title", newValue);
  4398. })),
  4399. this.contentWidget.watch('iconClass', lang.hitch(this, function(name, oldValue, newValue){
  4400. button.set("iconClass", newValue);
  4401. }))
  4402. ];
  4403. },
  4404. _setSelectedAttr: function(/*Boolean*/ isSelected){
  4405. this._set("selected", isSelected);
  4406. this.button.set("selected", isSelected);
  4407. if(isSelected){
  4408. var cw = this.contentWidget;
  4409. if(cw.onSelected){ cw.onSelected(); }
  4410. }
  4411. },
  4412. startup: function(){
  4413. // Called by _Container.addChild()
  4414. this.contentWidget.startup();
  4415. },
  4416. destroy: function(){
  4417. this.button.destroyRecursive();
  4418. array.forEach(this._contentWidgetWatches || [], function(w){ w.unwatch(); });
  4419. delete this.contentWidget._buttonWidget;
  4420. delete this.contentWidget._wrapperWidget;
  4421. this.inherited(arguments);
  4422. },
  4423. destroyDescendants: function(/*Boolean*/ preserveDom){
  4424. // since getChildren isn't working for me, have to code this manually
  4425. this.contentWidget.destroyRecursive(preserveDom);
  4426. }
  4427. });
  4428. var AccordionContainer = declare("dijit.layout.AccordionContainer", StackContainer, {
  4429. // summary:
  4430. // Holds a set of panes where every pane's title is visible, but only one pane's content is visible at a time,
  4431. // and switching between panes is visualized by sliding the other panes up/down.
  4432. // example:
  4433. // | <div data-dojo-type="dijit.layout.AccordionContainer">
  4434. // | <div data-dojo-type="dijit.layout.ContentPane" title="pane 1">
  4435. // | </div>
  4436. // | <div data-dojo-type="dijit.layout.ContentPane" title="pane 2">
  4437. // | <p>This is some text</p>
  4438. // | </div>
  4439. // | </div>
  4440. // duration: Integer
  4441. // Amount of time (in ms) it takes to slide panes
  4442. duration: manager.defaultDuration,
  4443. // buttonWidget: [const] String
  4444. // The name of the widget used to display the title of each pane
  4445. buttonWidget: AccordionButton,
  4446. /*=====
  4447. // _verticalSpace: Number
  4448. // Pixels of space available for the open pane
  4449. // (my content box size minus the cumulative size of all the title bars)
  4450. _verticalSpace: 0,
  4451. =====*/
  4452. baseClass: "dijitAccordionContainer",
  4453. buildRendering: function(){
  4454. this.inherited(arguments);
  4455. this.domNode.style.overflow = "hidden"; // TODO: put this in dijit.css
  4456. this.domNode.setAttribute("role", "tablist"); // TODO: put this in template
  4457. },
  4458. startup: function(){
  4459. if(this._started){ return; }
  4460. this.inherited(arguments);
  4461. if(this.selectedChildWidget){
  4462. var style = this.selectedChildWidget.containerNode.style;
  4463. style.display = "";
  4464. style.overflow = "auto";
  4465. this.selectedChildWidget._wrapperWidget.set("selected", true);
  4466. }
  4467. },
  4468. layout: function(){
  4469. // Implement _LayoutWidget.layout() virtual method.
  4470. // Set the height of the open pane based on what room remains.
  4471. var openPane = this.selectedChildWidget;
  4472. if(!openPane){ return;}
  4473. // space taken up by title, plus wrapper div (with border/margin) for open pane
  4474. var wrapperDomNode = openPane._wrapperWidget.domNode,
  4475. wrapperDomNodeMargin = domGeometry.getMarginExtents(wrapperDomNode),
  4476. wrapperDomNodePadBorder = domGeometry.getPadBorderExtents(wrapperDomNode),
  4477. wrapperContainerNode = openPane._wrapperWidget.containerNode,
  4478. wrapperContainerNodeMargin = domGeometry.getMarginExtents(wrapperContainerNode),
  4479. wrapperContainerNodePadBorder = domGeometry.getPadBorderExtents(wrapperContainerNode),
  4480. mySize = this._contentBox;
  4481. // get cumulative height of all the unselected title bars
  4482. var totalCollapsedHeight = 0;
  4483. array.forEach(this.getChildren(), function(child){
  4484. if(child != openPane){
  4485. // Using domGeometry.getMarginSize() rather than domGeometry.position() since claro has 1px bottom margin
  4486. // to separate accordion panes. Not sure that works perfectly, it's probably putting a 1px
  4487. // margin below the bottom pane (even though we don't want one).
  4488. totalCollapsedHeight += domGeometry.getMarginSize(child._wrapperWidget.domNode).h;
  4489. }
  4490. });
  4491. this._verticalSpace = mySize.h - totalCollapsedHeight - wrapperDomNodeMargin.h
  4492. - wrapperDomNodePadBorder.h - wrapperContainerNodeMargin.h - wrapperContainerNodePadBorder.h
  4493. - openPane._buttonWidget.getTitleHeight();
  4494. // Memo size to make displayed child
  4495. this._containerContentBox = {
  4496. h: this._verticalSpace,
  4497. w: this._contentBox.w - wrapperDomNodeMargin.w - wrapperDomNodePadBorder.w
  4498. - wrapperContainerNodeMargin.w - wrapperContainerNodePadBorder.w
  4499. };
  4500. if(openPane){
  4501. openPane.resize(this._containerContentBox);
  4502. }
  4503. },
  4504. _setupChild: function(child){
  4505. // Overrides _LayoutWidget._setupChild().
  4506. // Put wrapper widget around the child widget, showing title
  4507. child._wrapperWidget = AccordionInnerContainer({
  4508. contentWidget: child,
  4509. buttonWidget: this.buttonWidget,
  4510. id: child.id + "_wrapper",
  4511. dir: child.dir,
  4512. lang: child.lang,
  4513. textDir: child.textDir,
  4514. parent: this
  4515. });
  4516. this.inherited(arguments);
  4517. },
  4518. addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
  4519. if(this._started){
  4520. // Adding a child to a started Accordion is complicated because children have
  4521. // wrapper widgets. Default code path (calling this.inherited()) would add
  4522. // the new child inside another child's wrapper.
  4523. // First add in child as a direct child of this AccordionContainer
  4524. var refNode = this.containerNode;
  4525. if(insertIndex && typeof insertIndex == "number"){
  4526. var children = _Widget.prototype.getChildren.call(this); // get wrapper panes
  4527. if(children && children.length >= insertIndex){
  4528. refNode = children[insertIndex-1].domNode;
  4529. insertIndex = "after";
  4530. }
  4531. }
  4532. domConstruct.place(child.domNode, refNode, insertIndex);
  4533. if(!child._started){
  4534. child.startup();
  4535. }
  4536. // Then stick the wrapper widget around the child widget
  4537. this._setupChild(child);
  4538. // Code below copied from StackContainer
  4539. topic.publish(this.id+"-addChild", child, insertIndex); // publish
  4540. this.layout();
  4541. if(!this.selectedChildWidget){
  4542. this.selectChild(child);
  4543. }
  4544. }else{
  4545. // We haven't been started yet so just add in the child widget directly,
  4546. // and the wrapper will be created on startup()
  4547. this.inherited(arguments);
  4548. }
  4549. },
  4550. removeChild: function(child){
  4551. // Overrides _LayoutWidget.removeChild().
  4552. // Destroy wrapper widget first, before StackContainer.getChildren() call.
  4553. // Replace wrapper widget with true child widget (ContentPane etc.).
  4554. // This step only happens if the AccordionContainer has been started; otherwise there's no wrapper.
  4555. if(child._wrapperWidget){
  4556. domConstruct.place(child.domNode, child._wrapperWidget.domNode, "after");
  4557. child._wrapperWidget.destroy();
  4558. delete child._wrapperWidget;
  4559. }
  4560. domClass.remove(child.domNode, "dijitHidden");
  4561. this.inherited(arguments);
  4562. },
  4563. getChildren: function(){
  4564. // Overrides _Container.getChildren() to return content panes rather than internal AccordionInnerContainer panes
  4565. return array.map(this.inherited(arguments), function(child){
  4566. return child.declaredClass == "dijit.layout._AccordionInnerContainer" ? child.contentWidget : child;
  4567. }, this);
  4568. },
  4569. destroy: function(){
  4570. if(this._animation){
  4571. this._animation.stop();
  4572. }
  4573. array.forEach(this.getChildren(), function(child){
  4574. // If AccordionContainer has been started, then each child has a wrapper widget which
  4575. // also needs to be destroyed.
  4576. if(child._wrapperWidget){
  4577. child._wrapperWidget.destroy();
  4578. }else{
  4579. child.destroyRecursive();
  4580. }
  4581. });
  4582. this.inherited(arguments);
  4583. },
  4584. _showChild: function(child){
  4585. // Override StackContainer._showChild() to set visibility of _wrapperWidget.containerNode
  4586. child._wrapperWidget.containerNode.style.display="block";
  4587. return this.inherited(arguments);
  4588. },
  4589. _hideChild: function(child){
  4590. // Override StackContainer._showChild() to set visibility of _wrapperWidget.containerNode
  4591. child._wrapperWidget.containerNode.style.display="none";
  4592. this.inherited(arguments);
  4593. },
  4594. _transition: function(/*dijit._Widget?*/ newWidget, /*dijit._Widget?*/ oldWidget, /*Boolean*/ animate){
  4595. // Overrides StackContainer._transition() to provide sliding of title bars etc.
  4596. if(has("ie") < 8){
  4597. // workaround animation bugs by not animating; not worth supporting animation for IE6 & 7
  4598. animate = false;
  4599. }
  4600. if(this._animation){
  4601. // there's an in-progress animation. speedily end it so we can do the newly requested one
  4602. this._animation.stop(true);
  4603. delete this._animation;
  4604. }
  4605. var self = this;
  4606. if(newWidget){
  4607. newWidget._wrapperWidget.set("selected", true);
  4608. var d = this._showChild(newWidget); // prepare widget to be slid in
  4609. // Size the new widget, in case this is the first time it's being shown,
  4610. // or I have been resized since the last time it was shown.
  4611. // Note that page must be visible for resizing to work.
  4612. if(this.doLayout && newWidget.resize){
  4613. newWidget.resize(this._containerContentBox);
  4614. }
  4615. }
  4616. if(oldWidget){
  4617. oldWidget._wrapperWidget.set("selected", false);
  4618. if(!animate){
  4619. this._hideChild(oldWidget);
  4620. }
  4621. }
  4622. if(animate){
  4623. var newContents = newWidget._wrapperWidget.containerNode,
  4624. oldContents = oldWidget._wrapperWidget.containerNode;
  4625. // During the animation we will be showing two dijitAccordionChildWrapper nodes at once,
  4626. // which on claro takes up 4px extra space (compared to stable AccordionContainer).
  4627. // Have to compensate for that by immediately shrinking the pane being closed.
  4628. var wrapperContainerNode = newWidget._wrapperWidget.containerNode,
  4629. wrapperContainerNodeMargin = domGeometry.getMarginExtents(wrapperContainerNode),
  4630. wrapperContainerNodePadBorder = domGeometry.getPadBorderExtents(wrapperContainerNode),
  4631. animationHeightOverhead = wrapperContainerNodeMargin.h + wrapperContainerNodePadBorder.h;
  4632. oldContents.style.height = (self._verticalSpace - animationHeightOverhead) + "px";
  4633. this._animation = new fx.Animation({
  4634. node: newContents,
  4635. duration: this.duration,
  4636. curve: [1, this._verticalSpace - animationHeightOverhead - 1],
  4637. onAnimate: function(value){
  4638. value = Math.floor(value); // avoid fractional values
  4639. newContents.style.height = value + "px";
  4640. oldContents.style.height = (self._verticalSpace - animationHeightOverhead - value) + "px";
  4641. },
  4642. onEnd: function(){
  4643. delete self._animation;
  4644. newContents.style.height = "auto";
  4645. oldWidget._wrapperWidget.containerNode.style.display = "none";
  4646. oldContents.style.height = "auto";
  4647. self._hideChild(oldWidget);
  4648. }
  4649. });
  4650. this._animation.onStop = this._animation.onEnd;
  4651. this._animation.play();
  4652. }
  4653. return d; // If child has an href, promise that fires when the widget has finished loading
  4654. },
  4655. // note: we are treating the container as controller here
  4656. _onKeyPress: function(/*Event*/ e, /*dijit._Widget*/ fromTitle){
  4657. // summary:
  4658. // Handle keypress events
  4659. // description:
  4660. // This is called from a handler on AccordionContainer.domNode
  4661. // (setup in StackContainer), and is also called directly from
  4662. // the click handler for accordion labels
  4663. if(this.disabled || e.altKey || !(fromTitle || e.ctrlKey)){
  4664. return;
  4665. }
  4666. var c = e.charOrCode;
  4667. if((fromTitle && (c == keys.LEFT_ARROW || c == keys.UP_ARROW)) ||
  4668. (e.ctrlKey && c == keys.PAGE_UP)){
  4669. this._adjacent(false)._buttonWidget._onTitleClick();
  4670. event.stop(e);
  4671. }else if((fromTitle && (c == keys.RIGHT_ARROW || c == keys.DOWN_ARROW)) ||
  4672. (e.ctrlKey && (c == keys.PAGE_DOWN || c == keys.TAB))){
  4673. this._adjacent(true)._buttonWidget._onTitleClick();
  4674. event.stop(e);
  4675. }
  4676. }
  4677. });
  4678. // Back compat w/1.6, remove for 2.0
  4679. if(!kernel.isAsync){
  4680. ready(0, function(){
  4681. var requires = ["dijit/layout/AccordionPane"];
  4682. require(requires); // use indirection so modules not rolled into a build
  4683. });
  4684. }
  4685. // For monkey patching
  4686. AccordionContainer._InnerContainer = AccordionInnerContainer;
  4687. AccordionContainer._Button = AccordionButton;
  4688. return AccordionContainer;
  4689. });
  4690. },
  4691. 'dijit/layout/SplitContainer':function(){
  4692. define("dijit/layout/SplitContainer", [
  4693. "dojo/_base/array", // array.forEach array.indexOf array.some
  4694. "dojo/cookie", // cookie
  4695. "dojo/_base/declare", // declare
  4696. "dojo/dom", // dom.setSelectable
  4697. "dojo/dom-class", // domClass.add
  4698. "dojo/dom-construct", // domConstruct.create domConstruct.destroy
  4699. "dojo/dom-geometry", // domGeometry.marginBox domGeometry.position
  4700. "dojo/dom-style", // domStyle.style
  4701. "dojo/_base/event", // event.stop
  4702. "dojo/_base/kernel", // kernel.deprecated
  4703. "dojo/_base/lang", // lang.extend lang.hitch
  4704. "dojo/on",
  4705. "dojo/_base/sniff", // has("mozilla")
  4706. "dojo/_base/window", // win.doc.createElement win.doc.documentElement
  4707. "../registry", // registry.getUniqueId()
  4708. "../_WidgetBase",
  4709. "./_LayoutWidget"
  4710. ], function(array, cookie, declare, dom, domClass, domConstruct, domGeometry, domStyle,
  4711. event, kernel, lang, on, has, win, registry, _WidgetBase, _LayoutWidget){
  4712. /*=====
  4713. var _WidgetBase = dijit._WidgetBase;
  4714. var _LayoutWidget = dijit.layout._LayoutWidget;
  4715. =====*/
  4716. // module:
  4717. // dijit/layout/SplitContainer
  4718. // summary:
  4719. // Deprecated. Use `dijit.layout.BorderContainer` instead.
  4720. //
  4721. // FIXME: make it prettier
  4722. // FIXME: active dragging upwards doesn't always shift other bars (direction calculation is wrong in this case)
  4723. // FIXME: sizeWidth should be a CSS attribute (at 7 because css wants it to be 7 until we fix to css)
  4724. //
  4725. // These arguments can be specified for the children of a SplitContainer.
  4726. // Since any widget can be specified as a SplitContainer child, mix them
  4727. // into the base widget class. (This is a hack, but it's effective.)
  4728. lang.extend(_WidgetBase, {
  4729. // sizeMin: [deprecated] Integer
  4730. // Deprecated. Parameter for children of `dijit.layout.SplitContainer`.
  4731. // Minimum size (width or height) of a child of a SplitContainer.
  4732. // The value is relative to other children's sizeShare properties.
  4733. sizeMin: 10,
  4734. // sizeShare: [deprecated] Integer
  4735. // Deprecated. Parameter for children of `dijit.layout.SplitContainer`.
  4736. // Size (width or height) of a child of a SplitContainer.
  4737. // The value is relative to other children's sizeShare properties.
  4738. // For example, if there are two children and each has sizeShare=10, then
  4739. // each takes up 50% of the available space.
  4740. sizeShare: 10
  4741. });
  4742. return declare("dijit.layout.SplitContainer", _LayoutWidget, {
  4743. // summary:
  4744. // Deprecated. Use `dijit.layout.BorderContainer` instead.
  4745. // description:
  4746. // A Container widget with sizing handles in-between each child.
  4747. // Contains multiple children widgets, all of which are displayed side by side
  4748. // (either horizontally or vertically); there's a bar between each of the children,
  4749. // and you can adjust the relative size of each child by dragging the bars.
  4750. //
  4751. // You must specify a size (width and height) for the SplitContainer.
  4752. // tags:
  4753. // deprecated
  4754. constructor: function(){
  4755. kernel.deprecated("dijit.layout.SplitContainer is deprecated", "use BorderContainer with splitter instead", 2.0);
  4756. },
  4757. // activeSizing: Boolean
  4758. // If true, the children's size changes as you drag the bar;
  4759. // otherwise, the sizes don't change until you drop the bar (by mouse-up)
  4760. activeSizing: false,
  4761. // sizerWidth: Integer
  4762. // Size in pixels of the bar between each child
  4763. sizerWidth: 7,
  4764. // orientation: String
  4765. // either 'horizontal' or vertical; indicates whether the children are
  4766. // arranged side-by-side or up/down.
  4767. orientation: 'horizontal',
  4768. // persist: Boolean
  4769. // Save splitter positions in a cookie
  4770. persist: true,
  4771. baseClass: "dijitSplitContainer",
  4772. postMixInProperties: function(){
  4773. this.inherited("postMixInProperties",arguments);
  4774. this.isHorizontal = (this.orientation == 'horizontal');
  4775. },
  4776. postCreate: function(){
  4777. this.inherited(arguments);
  4778. this.sizers = [];
  4779. // overflow has to be explicitly hidden for splitContainers using gekko (trac #1435)
  4780. // to keep other combined css classes from inadvertantly making the overflow visible
  4781. if(has("mozilla")){
  4782. this.domNode.style.overflow = '-moz-scrollbars-none'; // hidden doesn't work
  4783. }
  4784. // create the fake dragger
  4785. if(typeof this.sizerWidth == "object"){
  4786. try{ //FIXME: do this without a try/catch
  4787. this.sizerWidth = parseInt(this.sizerWidth.toString());
  4788. }catch(e){ this.sizerWidth = 7; }
  4789. }
  4790. var sizer = win.doc.createElement('div');
  4791. this.virtualSizer = sizer;
  4792. sizer.style.position = 'relative';
  4793. // #1681: work around the dreaded 'quirky percentages in IE' layout bug
  4794. // If the splitcontainer's dimensions are specified in percentages, it
  4795. // will be resized when the virtualsizer is displayed in _showSizingLine
  4796. // (typically expanding its bounds unnecessarily). This happens because
  4797. // we use position: relative for .dijitSplitContainer.
  4798. // The workaround: instead of changing the display style attribute,
  4799. // switch to changing the zIndex (bring to front/move to back)
  4800. sizer.style.zIndex = 10;
  4801. sizer.className = this.isHorizontal ? 'dijitSplitContainerVirtualSizerH' : 'dijitSplitContainerVirtualSizerV';
  4802. this.domNode.appendChild(sizer);
  4803. dom.setSelectable(sizer, false);
  4804. },
  4805. destroy: function(){
  4806. delete this.virtualSizer;
  4807. if(this._ownconnects){
  4808. var h;
  4809. while(h = this._ownconnects.pop()){ h.remove(); }
  4810. }
  4811. this.inherited(arguments);
  4812. },
  4813. startup: function(){
  4814. if(this._started){ return; }
  4815. array.forEach(this.getChildren(), function(child, i, children){
  4816. // attach the children and create the draggers
  4817. this._setupChild(child);
  4818. if(i < children.length-1){
  4819. this._addSizer();
  4820. }
  4821. }, this);
  4822. if(this.persist){
  4823. this._restoreState();
  4824. }
  4825. this.inherited(arguments);
  4826. },
  4827. _setupChild: function(/*dijit._Widget*/ child){
  4828. this.inherited(arguments);
  4829. child.domNode.style.position = "absolute";
  4830. domClass.add(child.domNode, "dijitSplitPane");
  4831. },
  4832. _onSizerMouseDown: function(e){
  4833. if(e.target.id){
  4834. for(var i=0;i<this.sizers.length;i++){
  4835. if(this.sizers[i].id == e.target.id){
  4836. break;
  4837. }
  4838. }
  4839. if(i<this.sizers.length){
  4840. this.beginSizing(e,i);
  4841. }
  4842. }
  4843. },
  4844. _addSizer: function(index){
  4845. index = index === undefined ? this.sizers.length : index;
  4846. // TODO: use a template for this!!!
  4847. var sizer = win.doc.createElement('div');
  4848. sizer.id=registry.getUniqueId('dijit_layout_SplitterContainer_Splitter');
  4849. this.sizers.splice(index,0,sizer);
  4850. this.domNode.appendChild(sizer);
  4851. sizer.className = this.isHorizontal ? 'dijitSplitContainerSizerH' : 'dijitSplitContainerSizerV';
  4852. // add the thumb div
  4853. var thumb = win.doc.createElement('div');
  4854. thumb.className = 'thumb';
  4855. sizer.appendChild(thumb);
  4856. // FIXME: are you serious? why aren't we using mover start/stop combo?
  4857. this.connect(sizer, "onmousedown", '_onSizerMouseDown');
  4858. dom.setSelectable(sizer, false);
  4859. },
  4860. removeChild: function(widget){
  4861. // summary:
  4862. // Remove sizer, but only if widget is really our child and
  4863. // we have at least one sizer to throw away
  4864. if(this.sizers.length){
  4865. var i = array.indexOf(this.getChildren(), widget);
  4866. if(i != -1){
  4867. if(i == this.sizers.length){
  4868. i--;
  4869. }
  4870. domConstruct.destroy(this.sizers[i]);
  4871. this.sizers.splice(i,1);
  4872. }
  4873. }
  4874. // Remove widget and repaint
  4875. this.inherited(arguments);
  4876. if(this._started){
  4877. this.layout();
  4878. }
  4879. },
  4880. addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
  4881. // summary:
  4882. // Add a child widget to the container
  4883. // child:
  4884. // a widget to add
  4885. // insertIndex:
  4886. // postion in the "stack" to add the child widget
  4887. this.inherited(arguments);
  4888. if(this._started){
  4889. // Do the stuff that startup() does for each widget
  4890. var children = this.getChildren();
  4891. if(children.length > 1){
  4892. this._addSizer(insertIndex);
  4893. }
  4894. // and then reposition (ie, shrink) every pane to make room for the new guy
  4895. this.layout();
  4896. }
  4897. },
  4898. layout: function(){
  4899. // summary:
  4900. // Do layout of panels
  4901. // base class defines this._contentBox on initial creation and also
  4902. // on resize
  4903. this.paneWidth = this._contentBox.w;
  4904. this.paneHeight = this._contentBox.h;
  4905. var children = this.getChildren();
  4906. if(!children.length){ return; }
  4907. //
  4908. // calculate space
  4909. //
  4910. var space = this.isHorizontal ? this.paneWidth : this.paneHeight;
  4911. if(children.length > 1){
  4912. space -= this.sizerWidth * (children.length - 1);
  4913. }
  4914. //
  4915. // calculate total of SizeShare values
  4916. //
  4917. var outOf = 0;
  4918. array.forEach(children, function(child){
  4919. outOf += child.sizeShare;
  4920. });
  4921. //
  4922. // work out actual pixels per sizeshare unit
  4923. //
  4924. var pixPerUnit = space / outOf;
  4925. //
  4926. // set the SizeActual member of each pane
  4927. //
  4928. var totalSize = 0;
  4929. array.forEach(children.slice(0, children.length - 1), function(child){
  4930. var size = Math.round(pixPerUnit * child.sizeShare);
  4931. child.sizeActual = size;
  4932. totalSize += size;
  4933. });
  4934. children[children.length-1].sizeActual = space - totalSize;
  4935. //
  4936. // make sure the sizes are ok
  4937. //
  4938. this._checkSizes();
  4939. //
  4940. // now loop, positioning each pane and letting children resize themselves
  4941. //
  4942. var pos = 0;
  4943. var size = children[0].sizeActual;
  4944. this._movePanel(children[0], pos, size);
  4945. children[0].position = pos;
  4946. pos += size;
  4947. // if we don't have any sizers, our layout method hasn't been called yet
  4948. // so bail until we are called..TODO: REVISIT: need to change the startup
  4949. // algorithm to guaranteed the ordering of calls to layout method
  4950. if(!this.sizers){
  4951. return;
  4952. }
  4953. array.some(children.slice(1), function(child, i){
  4954. // error-checking
  4955. if(!this.sizers[i]){
  4956. return true;
  4957. }
  4958. // first we position the sizing handle before this pane
  4959. this._moveSlider(this.sizers[i], pos, this.sizerWidth);
  4960. this.sizers[i].position = pos;
  4961. pos += this.sizerWidth;
  4962. size = child.sizeActual;
  4963. this._movePanel(child, pos, size);
  4964. child.position = pos;
  4965. pos += size;
  4966. }, this);
  4967. },
  4968. _movePanel: function(panel, pos, size){
  4969. var box;
  4970. if(this.isHorizontal){
  4971. panel.domNode.style.left = pos + 'px'; // TODO: resize() takes l and t parameters too, don't need to set manually
  4972. panel.domNode.style.top = 0;
  4973. box = {w: size, h: this.paneHeight};
  4974. if(panel.resize){
  4975. panel.resize(box);
  4976. }else{
  4977. domGeometry.setMarginBox(panel.domNode, box);
  4978. }
  4979. }else{
  4980. panel.domNode.style.left = 0; // TODO: resize() takes l and t parameters too, don't need to set manually
  4981. panel.domNode.style.top = pos + 'px';
  4982. box = {w: this.paneWidth, h: size};
  4983. if(panel.resize){
  4984. panel.resize(box);
  4985. }else{
  4986. domGeometry.setMarginBox(panel.domNode, box);
  4987. }
  4988. }
  4989. },
  4990. _moveSlider: function(slider, pos, size){
  4991. if(this.isHorizontal){
  4992. slider.style.left = pos + 'px';
  4993. slider.style.top = 0;
  4994. domGeometry.setMarginBox(slider, { w: size, h: this.paneHeight });
  4995. }else{
  4996. slider.style.left = 0;
  4997. slider.style.top = pos + 'px';
  4998. domGeometry.setMarginBox(slider, { w: this.paneWidth, h: size });
  4999. }
  5000. },
  5001. _growPane: function(growth, pane){
  5002. if(growth > 0){
  5003. if(pane.sizeActual > pane.sizeMin){
  5004. if((pane.sizeActual - pane.sizeMin) > growth){
  5005. // stick all the growth in this pane
  5006. pane.sizeActual = pane.sizeActual - growth;
  5007. growth = 0;
  5008. }else{
  5009. // put as much growth in here as we can
  5010. growth -= pane.sizeActual - pane.sizeMin;
  5011. pane.sizeActual = pane.sizeMin;
  5012. }
  5013. }
  5014. }
  5015. return growth;
  5016. },
  5017. _checkSizes: function(){
  5018. var totalMinSize = 0;
  5019. var totalSize = 0;
  5020. var children = this.getChildren();
  5021. array.forEach(children, function(child){
  5022. totalSize += child.sizeActual;
  5023. totalMinSize += child.sizeMin;
  5024. });
  5025. // only make adjustments if we have enough space for all the minimums
  5026. if(totalMinSize <= totalSize){
  5027. var growth = 0;
  5028. array.forEach(children, function(child){
  5029. if(child.sizeActual < child.sizeMin){
  5030. growth += child.sizeMin - child.sizeActual;
  5031. child.sizeActual = child.sizeMin;
  5032. }
  5033. });
  5034. if(growth > 0){
  5035. var list = this.isDraggingLeft ? children.reverse() : children;
  5036. array.forEach(list, function(child){
  5037. growth = this._growPane(growth, child);
  5038. }, this);
  5039. }
  5040. }else{
  5041. array.forEach(children, function(child){
  5042. child.sizeActual = Math.round(totalSize * (child.sizeMin / totalMinSize));
  5043. });
  5044. }
  5045. },
  5046. beginSizing: function(e, i){
  5047. var children = this.getChildren();
  5048. this.paneBefore = children[i];
  5049. this.paneAfter = children[i+1];
  5050. this.isSizing = true;
  5051. this.sizingSplitter = this.sizers[i];
  5052. if(!this.cover){
  5053. this.cover = domConstruct.create('div', {
  5054. style: {
  5055. position:'absolute',
  5056. zIndex:5,
  5057. top: 0,
  5058. left: 0,
  5059. width: "100%",
  5060. height: "100%"
  5061. }
  5062. }, this.domNode);
  5063. }else{
  5064. this.cover.style.zIndex = 5;
  5065. }
  5066. this.sizingSplitter.style.zIndex = 6;
  5067. // TODO: REVISIT - we want MARGIN_BOX and core hasn't exposed that yet (but can't we use it anyway if we pay attention? we do elsewhere.)
  5068. this.originPos = domGeometry.position(children[0].domNode, true);
  5069. var client, screen;
  5070. if(this.isHorizontal){
  5071. client = e.layerX || e.offsetX || 0;
  5072. screen = e.pageX;
  5073. this.originPos = this.originPos.x;
  5074. }else{
  5075. client = e.layerY || e.offsetY || 0;
  5076. screen = e.pageY;
  5077. this.originPos = this.originPos.y;
  5078. }
  5079. this.startPoint = this.lastPoint = screen;
  5080. this.screenToClientOffset = screen - client;
  5081. this.dragOffset = this.lastPoint - this.paneBefore.sizeActual - this.originPos - this.paneBefore.position;
  5082. if(!this.activeSizing){
  5083. this._showSizingLine();
  5084. }
  5085. //
  5086. // attach mouse events
  5087. //
  5088. this._ownconnects = [
  5089. on(win.doc.documentElement, "mousemove", lang.hitch(this, "changeSizing")),
  5090. on(win.doc.documentElement, "mouseup", lang.hitch(this, "endSizing"))
  5091. ];
  5092. event.stop(e);
  5093. },
  5094. changeSizing: function(e){
  5095. if(!this.isSizing){ return; }
  5096. this.lastPoint = this.isHorizontal ? e.pageX : e.pageY;
  5097. this.movePoint();
  5098. if(this.activeSizing){
  5099. this._updateSize();
  5100. }else{
  5101. this._moveSizingLine();
  5102. }
  5103. event.stop(e);
  5104. },
  5105. endSizing: function(){
  5106. if(!this.isSizing){ return; }
  5107. if(this.cover){
  5108. this.cover.style.zIndex = -1;
  5109. }
  5110. if(!this.activeSizing){
  5111. this._hideSizingLine();
  5112. }
  5113. this._updateSize();
  5114. this.isSizing = false;
  5115. if(this.persist){
  5116. this._saveState(this);
  5117. }
  5118. var h;
  5119. while(h = this._ownconnects.pop()){ h.remove(); }
  5120. },
  5121. movePoint: function(){
  5122. // make sure lastPoint is a legal point to drag to
  5123. var p = this.lastPoint - this.screenToClientOffset;
  5124. var a = p - this.dragOffset;
  5125. a = this.legaliseSplitPoint(a);
  5126. p = a + this.dragOffset;
  5127. this.lastPoint = p + this.screenToClientOffset;
  5128. },
  5129. legaliseSplitPoint: function(a){
  5130. a += this.sizingSplitter.position;
  5131. this.isDraggingLeft = !!(a > 0);
  5132. if(!this.activeSizing){
  5133. var min = this.paneBefore.position + this.paneBefore.sizeMin;
  5134. if(a < min){
  5135. a = min;
  5136. }
  5137. var max = this.paneAfter.position + (this.paneAfter.sizeActual - (this.sizerWidth + this.paneAfter.sizeMin));
  5138. if(a > max){
  5139. a = max;
  5140. }
  5141. }
  5142. a -= this.sizingSplitter.position;
  5143. this._checkSizes();
  5144. return a;
  5145. },
  5146. _updateSize: function(){
  5147. //FIXME: sometimes this.lastPoint is NaN
  5148. var pos = this.lastPoint - this.dragOffset - this.originPos;
  5149. var start_region = this.paneBefore.position;
  5150. var end_region = this.paneAfter.position + this.paneAfter.sizeActual;
  5151. this.paneBefore.sizeActual = pos - start_region;
  5152. this.paneAfter.position = pos + this.sizerWidth;
  5153. this.paneAfter.sizeActual = end_region - this.paneAfter.position;
  5154. array.forEach(this.getChildren(), function(child){
  5155. child.sizeShare = child.sizeActual;
  5156. });
  5157. if(this._started){
  5158. this.layout();
  5159. }
  5160. },
  5161. _showSizingLine: function(){
  5162. this._moveSizingLine();
  5163. domGeometry.setMarginBox(this.virtualSizer,
  5164. this.isHorizontal ? { w: this.sizerWidth, h: this.paneHeight } : { w: this.paneWidth, h: this.sizerWidth });
  5165. this.virtualSizer.style.display = 'block';
  5166. },
  5167. _hideSizingLine: function(){
  5168. this.virtualSizer.style.display = 'none';
  5169. },
  5170. _moveSizingLine: function(){
  5171. var pos = (this.lastPoint - this.startPoint) + this.sizingSplitter.position;
  5172. domStyle.set(this.virtualSizer,(this.isHorizontal ? "left" : "top"),pos+"px");
  5173. // this.virtualSizer.style[ this.isHorizontal ? "left" : "top" ] = pos + 'px'; // FIXME: remove this line if the previous is better
  5174. },
  5175. _getCookieName: function(i){
  5176. return this.id + "_" + i;
  5177. },
  5178. _restoreState: function(){
  5179. array.forEach(this.getChildren(), function(child, i){
  5180. var cookieName = this._getCookieName(i);
  5181. var cookieValue = cookie(cookieName);
  5182. if(cookieValue){
  5183. var pos = parseInt(cookieValue);
  5184. if(typeof pos == "number"){
  5185. child.sizeShare = pos;
  5186. }
  5187. }
  5188. }, this);
  5189. },
  5190. _saveState: function(){
  5191. if(!this.persist){
  5192. return;
  5193. }
  5194. array.forEach(this.getChildren(), function(child, i){
  5195. cookie(this._getCookieName(i), child.sizeShare, {expires:365});
  5196. }, this);
  5197. }
  5198. });
  5199. });
  5200. },
  5201. 'url:dijit/templates/Calendar.html':"<table cellspacing=\"0\" cellpadding=\"0\" class=\"dijitCalendarContainer\" role=\"grid\" aria-labelledby=\"${id}_mddb ${id}_year\">\n\t<thead>\n\t\t<tr class=\"dijitReset dijitCalendarMonthContainer\" valign=\"top\">\n\t\t\t<th class='dijitReset dijitCalendarArrow' data-dojo-attach-point=\"decrementMonth\">\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarDecrease\" role=\"presentation\"/>\n\t\t\t\t<span data-dojo-attach-point=\"decreaseArrowNode\" class=\"dijitA11ySideArrow\">-</span>\n\t\t\t</th>\n\t\t\t<th class='dijitReset' colspan=\"5\">\n\t\t\t\t<div data-dojo-attach-point=\"monthNode\">\n\t\t\t\t</div>\n\t\t\t</th>\n\t\t\t<th class='dijitReset dijitCalendarArrow' data-dojo-attach-point=\"incrementMonth\">\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarIncrease\" role=\"presentation\"/>\n\t\t\t\t<span data-dojo-attach-point=\"increaseArrowNode\" class=\"dijitA11ySideArrow\">+</span>\n\t\t\t</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t${!dayCellsHtml}\n\t\t</tr>\n\t</thead>\n\t<tbody data-dojo-attach-point=\"dateRowsNode\" data-dojo-attach-event=\"onclick: _onDayClick\" class=\"dijitReset dijitCalendarBodyContainer\">\n\t\t\t${!dateRowsHtml}\n\t</tbody>\n\t<tfoot class=\"dijitReset dijitCalendarYearContainer\">\n\t\t<tr>\n\t\t\t<td class='dijitReset' valign=\"top\" colspan=\"7\" role=\"presentation\">\n\t\t\t\t<div class=\"dijitCalendarYearLabel\">\n\t\t\t\t\t<span data-dojo-attach-point=\"previousYearLabelNode\" class=\"dijitInline dijitCalendarPreviousYear\" role=\"button\"></span>\n\t\t\t\t\t<span data-dojo-attach-point=\"currentYearLabelNode\" class=\"dijitInline dijitCalendarSelectedYear\" role=\"button\" id=\"${id}_year\"></span>\n\t\t\t\t\t<span data-dojo-attach-point=\"nextYearLabelNode\" class=\"dijitInline dijitCalendarNextYear\" role=\"button\"></span>\n\t\t\t\t</div>\n\t\t\t</td>\n\t\t</tr>\n\t</tfoot>\n</table>\n",
  5202. 'dijit/form/_AutoCompleterMixin':function(){
  5203. define([
  5204. "dojo/_base/connect", // keys keys.SHIFT
  5205. "dojo/data/util/filter", // patternToRegExp
  5206. "dojo/_base/declare", // declare
  5207. "dojo/_base/Deferred", // Deferred.when
  5208. "dojo/dom-attr", // domAttr.get
  5209. "dojo/_base/event", // event.stop
  5210. "dojo/keys",
  5211. "dojo/_base/lang", // lang.clone lang.hitch
  5212. "dojo/on",
  5213. "dojo/query", // query
  5214. "dojo/regexp", // regexp.escapeString
  5215. "dojo/_base/sniff", // has("ie")
  5216. "dojo/string", // string.substitute
  5217. "dojo/_base/window", // win.doc.selection.createRange
  5218. "./DataList",
  5219. "../registry", // registry.byId
  5220. "./_TextBoxMixin" // defines _TextBoxMixin.selectInputText
  5221. ], function(connect, filter, declare, Deferred, domAttr, event, keys, lang, on, query, regexp, has, string, win,
  5222. DataList, registry, _TextBoxMixin){
  5223. // module:
  5224. // dijit/form/_AutoCompleterMixin
  5225. // summary:
  5226. // A mixin that implements the base functionality for `dijit.form.ComboBox`/`dijit.form.FilteringSelect`
  5227. return declare("dijit.form._AutoCompleterMixin", null, {
  5228. // summary:
  5229. // A mixin that implements the base functionality for `dijit.form.ComboBox`/`dijit.form.FilteringSelect`
  5230. // description:
  5231. // All widgets that mix in dijit.form._AutoCompleterMixin must extend `dijit.form._FormValueWidget`.
  5232. // tags:
  5233. // protected
  5234. // item: Object
  5235. // This is the item returned by the dojo.data.store implementation that
  5236. // provides the data for this ComboBox, it's the currently selected item.
  5237. item: null,
  5238. // pageSize: Integer
  5239. // Argument to data provider.
  5240. // Specifies number of search results per page (before hitting "next" button)
  5241. pageSize: Infinity,
  5242. // store: [const] dojo.store.api.Store
  5243. // Reference to data provider object used by this ComboBox
  5244. store: null,
  5245. // fetchProperties: Object
  5246. // Mixin to the store's fetch.
  5247. // For example, to set the sort order of the ComboBox menu, pass:
  5248. // | { sort: [{attribute:"name",descending: true}] }
  5249. // To override the default queryOptions so that deep=false, do:
  5250. // | { queryOptions: {ignoreCase: true, deep: false} }
  5251. fetchProperties:{},
  5252. // query: Object
  5253. // A query that can be passed to 'store' to initially filter the items,
  5254. // before doing further filtering based on `searchAttr` and the key.
  5255. // Any reference to the `searchAttr` is ignored.
  5256. query: {},
  5257. // list: [const] String
  5258. // Alternate to specifying a store. Id of a dijit/form/DataList widget.
  5259. list: "",
  5260. _setListAttr: function(list){
  5261. // Avoid having list applied to the DOM node, since it has native meaning in modern browsers
  5262. this._set("list", list);
  5263. },
  5264. // autoComplete: Boolean
  5265. // If user types in a partial string, and then tab out of the `<input>` box,
  5266. // automatically copy the first entry displayed in the drop down list to
  5267. // the `<input>` field
  5268. autoComplete: true,
  5269. // highlightMatch: String
  5270. // One of: "first", "all" or "none".
  5271. //
  5272. // If the ComboBox/FilteringSelect opens with the search results and the searched
  5273. // string can be found, it will be highlighted. If set to "all"
  5274. // then will probably want to change `queryExpr` parameter to '*${0}*'
  5275. //
  5276. // Highlighting is only performed when `labelType` is "text", so as to not
  5277. // interfere with any HTML markup an HTML label might contain.
  5278. highlightMatch: "first",
  5279. // searchDelay: Integer
  5280. // Delay in milliseconds between when user types something and we start
  5281. // searching based on that value
  5282. searchDelay: 100,
  5283. // searchAttr: String
  5284. // Search for items in the data store where this attribute (in the item)
  5285. // matches what the user typed
  5286. searchAttr: "name",
  5287. // labelAttr: String?
  5288. // The entries in the drop down list come from this attribute in the
  5289. // dojo.data items.
  5290. // If not specified, the searchAttr attribute is used instead.
  5291. labelAttr: "",
  5292. // labelType: String
  5293. // Specifies how to interpret the labelAttr in the data store items.
  5294. // Can be "html" or "text".
  5295. labelType: "text",
  5296. // queryExpr: String
  5297. // This specifies what query ComboBox/FilteringSelect sends to the data store,
  5298. // based on what the user has typed. Changing this expression will modify
  5299. // whether the drop down shows only exact matches, a "starting with" match,
  5300. // etc. Use it in conjunction with highlightMatch.
  5301. // dojo.data query expression pattern.
  5302. // `${0}` will be substituted for the user text.
  5303. // `*` is used for wildcards.
  5304. // `${0}*` means "starts with", `*${0}*` means "contains", `${0}` means "is"
  5305. queryExpr: "${0}*",
  5306. // ignoreCase: Boolean
  5307. // Set true if the ComboBox/FilteringSelect should ignore case when matching possible items
  5308. ignoreCase: true,
  5309. // Flags to _HasDropDown to limit height of drop down to make it fit in viewport
  5310. maxHeight: -1,
  5311. // For backwards compatibility let onClick events propagate, even clicks on the down arrow button
  5312. _stopClickEvents: false,
  5313. _getCaretPos: function(/*DomNode*/ element){
  5314. // khtml 3.5.2 has selection* methods as does webkit nightlies from 2005-06-22
  5315. var pos = 0;
  5316. if(typeof(element.selectionStart) == "number"){
  5317. // FIXME: this is totally borked on Moz < 1.3. Any recourse?
  5318. pos = element.selectionStart;
  5319. }else if(has("ie")){
  5320. // in the case of a mouse click in a popup being handled,
  5321. // then the win.doc.selection is not the textarea, but the popup
  5322. // var r = win.doc.selection.createRange();
  5323. // hack to get IE 6 to play nice. What a POS browser.
  5324. var tr = win.doc.selection.createRange().duplicate();
  5325. var ntr = element.createTextRange();
  5326. tr.move("character",0);
  5327. ntr.move("character",0);
  5328. try{
  5329. // If control doesn't have focus, you get an exception.
  5330. // Seems to happen on reverse-tab, but can also happen on tab (seems to be a race condition - only happens sometimes).
  5331. // There appears to be no workaround for this - googled for quite a while.
  5332. ntr.setEndPoint("EndToEnd", tr);
  5333. pos = String(ntr.text).replace(/\r/g,"").length;
  5334. }catch(e){
  5335. // If focus has shifted, 0 is fine for caret pos.
  5336. }
  5337. }
  5338. return pos;
  5339. },
  5340. _setCaretPos: function(/*DomNode*/ element, /*Number*/ location){
  5341. location = parseInt(location);
  5342. _TextBoxMixin.selectInputText(element, location, location);
  5343. },
  5344. _setDisabledAttr: function(/*Boolean*/ value){
  5345. // Additional code to set disabled state of ComboBox node.
  5346. // Overrides _FormValueWidget._setDisabledAttr() or ValidationTextBox._setDisabledAttr().
  5347. this.inherited(arguments);
  5348. this.domNode.setAttribute("aria-disabled", value);
  5349. },
  5350. _abortQuery: function(){
  5351. // stop in-progress query
  5352. if(this.searchTimer){
  5353. clearTimeout(this.searchTimer);
  5354. this.searchTimer = null;
  5355. }
  5356. if(this._fetchHandle){
  5357. if(this._fetchHandle.cancel){
  5358. this._cancelingQuery = true;
  5359. this._fetchHandle.cancel();
  5360. this._cancelingQuery = false;
  5361. }
  5362. this._fetchHandle = null;
  5363. }
  5364. },
  5365. _onInput: function(/*Event*/ evt){
  5366. // summary:
  5367. // Handles paste events.
  5368. this.inherited(arguments);
  5369. if(evt.charOrCode == 229){ // IME or cut/paste event
  5370. this._onKeyPress(evt);
  5371. }
  5372. },
  5373. _onKey: function(/*Event*/ evt){
  5374. // summary:
  5375. // Handles keyboard events from synthetic dojo/_base/connect._keypress event
  5376. if(this.disabled || this.readOnly){ return; }
  5377. var key = evt.keyCode;
  5378. // except for cutting/pasting case - ctrl + x/v
  5379. if(evt.altKey || ((evt.ctrlKey || evt.metaKey) && (key != 86 && key != 88)) || key == keys.SHIFT){
  5380. return; // throw out weird key combinations and spurious events
  5381. }
  5382. var doSearch = false;
  5383. var pw = this.dropDown;
  5384. var highlighted = null;
  5385. this._prev_key_backspace = false;
  5386. this._abortQuery();
  5387. // _HasDropDown will do some of the work:
  5388. // 1. when drop down is not yet shown:
  5389. // - if user presses the down arrow key, call loadDropDown()
  5390. // 2. when drop down is already displayed:
  5391. // - on ESC key, call closeDropDown()
  5392. // - otherwise, call dropDown.handleKey() to process the keystroke
  5393. this.inherited(arguments);
  5394. if(this._opened){
  5395. highlighted = pw.getHighlightedOption();
  5396. }
  5397. switch(key){
  5398. case keys.PAGE_DOWN:
  5399. case keys.DOWN_ARROW:
  5400. case keys.PAGE_UP:
  5401. case keys.UP_ARROW:
  5402. // Keystroke caused ComboBox_menu to move to a different item.
  5403. // Copy new item to <input> box.
  5404. if(this._opened){
  5405. this._announceOption(highlighted);
  5406. }
  5407. event.stop(evt);
  5408. break;
  5409. case keys.ENTER:
  5410. // prevent submitting form if user presses enter. Also
  5411. // prevent accepting the value if either Next or Previous
  5412. // are selected
  5413. if(highlighted){
  5414. // only stop event on prev/next
  5415. if(highlighted == pw.nextButton){
  5416. this._nextSearch(1);
  5417. event.stop(evt);
  5418. break;
  5419. }else if(highlighted == pw.previousButton){
  5420. this._nextSearch(-1);
  5421. event.stop(evt);
  5422. break;
  5423. }
  5424. }else{
  5425. // Update 'value' (ex: KY) according to currently displayed text
  5426. this._setBlurValue(); // set value if needed
  5427. this._setCaretPos(this.focusNode, this.focusNode.value.length); // move cursor to end and cancel highlighting
  5428. }
  5429. // default case:
  5430. // if enter pressed while drop down is open, or for FilteringSelect,
  5431. // if we are in the middle of a query to convert a directly typed in value to an item,
  5432. // prevent submit
  5433. if(this._opened || this._fetchHandle){
  5434. event.stop(evt);
  5435. }
  5436. // fall through
  5437. case keys.TAB:
  5438. var newvalue = this.get('displayedValue');
  5439. // if the user had More Choices selected fall into the
  5440. // _onBlur handler
  5441. if(pw && (
  5442. newvalue == pw._messages["previousMessage"] ||
  5443. newvalue == pw._messages["nextMessage"])
  5444. ){
  5445. break;
  5446. }
  5447. if(highlighted){
  5448. this._selectOption(highlighted);
  5449. }
  5450. // fall through
  5451. case keys.ESCAPE:
  5452. if(this._opened){
  5453. this._lastQuery = null; // in case results come back later
  5454. this.closeDropDown();
  5455. }
  5456. break;
  5457. case ' ':
  5458. if(highlighted){
  5459. // user is effectively clicking a choice in the drop down menu
  5460. event.stop(evt);
  5461. this._selectOption(highlighted);
  5462. this.closeDropDown();
  5463. }else{
  5464. // user typed a space into the input box, treat as normal character
  5465. doSearch = true;
  5466. }
  5467. break;
  5468. case keys.DELETE:
  5469. case keys.BACKSPACE:
  5470. this._prev_key_backspace = true;
  5471. doSearch = true;
  5472. break;
  5473. }
  5474. if(doSearch){
  5475. // need to wait a tad before start search so that the event
  5476. // bubbles through DOM and we have value visible
  5477. this.item = undefined; // undefined means item needs to be set
  5478. this.searchTimer = setTimeout(lang.hitch(this, "_startSearchFromInput"),1);
  5479. }
  5480. },
  5481. _onKeyPress: function(evt){
  5482. // Non char keys (F1-F12 etc..) shouldn't open list.
  5483. // Ascii characters and IME input (Chinese, Japanese etc.) should.
  5484. if(typeof evt.charOrCode == "string" || evt.charOrCode == 229){
  5485. // need to wait a tad before start search so that the event
  5486. // bubbles through DOM and we have value visible
  5487. this.item = undefined; // undefined means item needs to be set
  5488. this.searchTimer = setTimeout(lang.hitch(this, "_startSearchFromInput"),1);
  5489. }
  5490. },
  5491. _autoCompleteText: function(/*String*/ text){
  5492. // summary:
  5493. // Fill in the textbox with the first item from the drop down
  5494. // list, and highlight the characters that were
  5495. // auto-completed. For example, if user typed "CA" and the
  5496. // drop down list appeared, the textbox would be changed to
  5497. // "California" and "ifornia" would be highlighted.
  5498. var fn = this.focusNode;
  5499. // IE7: clear selection so next highlight works all the time
  5500. _TextBoxMixin.selectInputText(fn, fn.value.length);
  5501. // does text autoComplete the value in the textbox?
  5502. var caseFilter = this.ignoreCase? 'toLowerCase' : 'substr';
  5503. if(text[caseFilter](0).indexOf(this.focusNode.value[caseFilter](0)) == 0){
  5504. var cpos = this.autoComplete ? this._getCaretPos(fn) : fn.value.length;
  5505. // only try to extend if we added the last character at the end of the input
  5506. if((cpos+1) > fn.value.length){
  5507. // only add to input node as we would overwrite Capitalisation of chars
  5508. // actually, that is ok
  5509. fn.value = text;//.substr(cpos);
  5510. // visually highlight the autocompleted characters
  5511. _TextBoxMixin.selectInputText(fn, cpos);
  5512. }
  5513. }else{
  5514. // text does not autoComplete; replace the whole value and highlight
  5515. fn.value = text;
  5516. _TextBoxMixin.selectInputText(fn);
  5517. }
  5518. },
  5519. _openResultList: function(/*Object*/ results, /*Object*/ query, /*Object*/ options){
  5520. // summary:
  5521. // Callback when a search completes.
  5522. // description:
  5523. // 1. generates drop-down list and calls _showResultList() to display it
  5524. // 2. if this result list is from user pressing "more choices"/"previous choices"
  5525. // then tell screen reader to announce new option
  5526. this._fetchHandle = null;
  5527. if( this.disabled ||
  5528. this.readOnly ||
  5529. (query[this.searchAttr] !== this._lastQuery) // TODO: better way to avoid getting unwanted notify
  5530. ){
  5531. return;
  5532. }
  5533. var wasSelected = this.dropDown.getHighlightedOption();
  5534. this.dropDown.clearResultList();
  5535. if(!results.length && options.start == 0){ // if no results and not just the previous choices button
  5536. this.closeDropDown();
  5537. return;
  5538. }
  5539. // Fill in the textbox with the first item from the drop down list,
  5540. // and highlight the characters that were auto-completed. For
  5541. // example, if user typed "CA" and the drop down list appeared, the
  5542. // textbox would be changed to "California" and "ifornia" would be
  5543. // highlighted.
  5544. this.dropDown.createOptions(
  5545. results,
  5546. options,
  5547. lang.hitch(this, "_getMenuLabelFromItem")
  5548. );
  5549. // show our list (only if we have content, else nothing)
  5550. this._showResultList();
  5551. // #4091:
  5552. // tell the screen reader that the paging callback finished by
  5553. // shouting the next choice
  5554. if(options.direction){
  5555. if(1 == options.direction){
  5556. this.dropDown.highlightFirstOption();
  5557. }else if(-1 == options.direction){
  5558. this.dropDown.highlightLastOption();
  5559. }
  5560. if(wasSelected){
  5561. this._announceOption(this.dropDown.getHighlightedOption());
  5562. }
  5563. }else if(this.autoComplete && !this._prev_key_backspace
  5564. // when the user clicks the arrow button to show the full list,
  5565. // startSearch looks for "*".
  5566. // it does not make sense to autocomplete
  5567. // if they are just previewing the options available.
  5568. && !/^[*]+$/.test(query[this.searchAttr].toString())){
  5569. this._announceOption(this.dropDown.containerNode.firstChild.nextSibling); // 1st real item
  5570. }
  5571. },
  5572. _showResultList: function(){
  5573. // summary:
  5574. // Display the drop down if not already displayed, or if it is displayed, then
  5575. // reposition it if necessary (reposition may be necessary if drop down's height changed).
  5576. this.closeDropDown(true);
  5577. this.openDropDown();
  5578. this.domNode.setAttribute("aria-expanded", "true");
  5579. },
  5580. loadDropDown: function(/*Function*/ /*===== callback =====*/){
  5581. // Overrides _HasDropDown.loadDropDown().
  5582. // This is called when user has pressed button icon or pressed the down arrow key
  5583. // to open the drop down.
  5584. this._startSearchAll();
  5585. },
  5586. isLoaded: function(){
  5587. // signal to _HasDropDown that it needs to call loadDropDown() to load the
  5588. // drop down asynchronously before displaying it
  5589. return false;
  5590. },
  5591. closeDropDown: function(){
  5592. // Overrides _HasDropDown.closeDropDown(). Closes the drop down (assuming that it's open).
  5593. // This method is the callback when the user types ESC or clicking
  5594. // the button icon while the drop down is open. It's also called by other code.
  5595. this._abortQuery();
  5596. if(this._opened){
  5597. this.inherited(arguments);
  5598. this.domNode.setAttribute("aria-expanded", "false");
  5599. this.focusNode.removeAttribute("aria-activedescendant");
  5600. }
  5601. },
  5602. _setBlurValue: function(){
  5603. // if the user clicks away from the textbox OR tabs away, set the
  5604. // value to the textbox value
  5605. // #4617:
  5606. // if value is now more choices or previous choices, revert
  5607. // the value
  5608. var newvalue = this.get('displayedValue');
  5609. var pw = this.dropDown;
  5610. if(pw && (
  5611. newvalue == pw._messages["previousMessage"] ||
  5612. newvalue == pw._messages["nextMessage"]
  5613. )
  5614. ){
  5615. this._setValueAttr(this._lastValueReported, true);
  5616. }else if(typeof this.item == "undefined"){
  5617. // Update 'value' (ex: KY) according to currently displayed text
  5618. this.item = null;
  5619. this.set('displayedValue', newvalue);
  5620. }else{
  5621. if(this.value != this._lastValueReported){
  5622. this._handleOnChange(this.value, true);
  5623. }
  5624. this._refreshState();
  5625. }
  5626. },
  5627. _setItemAttr: function(/*item*/ item, /*Boolean?*/ priorityChange, /*String?*/ displayedValue){
  5628. // summary:
  5629. // Set the displayed valued in the input box, and the hidden value
  5630. // that gets submitted, based on a dojo.data store item.
  5631. // description:
  5632. // Users shouldn't call this function; they should be calling
  5633. // set('item', value)
  5634. // tags:
  5635. // private
  5636. var value = '';
  5637. if(item){
  5638. if(!displayedValue){
  5639. displayedValue = this.store._oldAPI ? // remove getValue() for 2.0 (old dojo.data API)
  5640. this.store.getValue(item, this.searchAttr) : item[this.searchAttr];
  5641. }
  5642. value = this._getValueField() != this.searchAttr ? this.store.getIdentity(item) : displayedValue;
  5643. }
  5644. this.set('value', value, priorityChange, displayedValue, item);
  5645. },
  5646. _announceOption: function(/*Node*/ node){
  5647. // summary:
  5648. // a11y code that puts the highlighted option in the textbox.
  5649. // This way screen readers will know what is happening in the
  5650. // menu.
  5651. if(!node){
  5652. return;
  5653. }
  5654. // pull the text value from the item attached to the DOM node
  5655. var newValue;
  5656. if(node == this.dropDown.nextButton ||
  5657. node == this.dropDown.previousButton){
  5658. newValue = node.innerHTML;
  5659. this.item = undefined;
  5660. this.value = '';
  5661. }else{
  5662. var item = this.dropDown.items[node.getAttribute("item")];
  5663. newValue = (this.store._oldAPI ? // remove getValue() for 2.0 (old dojo.data API)
  5664. this.store.getValue(item, this.searchAttr) : item[this.searchAttr]).toString();
  5665. this.set('item', item, false, newValue);
  5666. }
  5667. // get the text that the user manually entered (cut off autocompleted text)
  5668. this.focusNode.value = this.focusNode.value.substring(0, this._lastInput.length);
  5669. // set up ARIA activedescendant
  5670. this.focusNode.setAttribute("aria-activedescendant", domAttr.get(node, "id"));
  5671. // autocomplete the rest of the option to announce change
  5672. this._autoCompleteText(newValue);
  5673. },
  5674. _selectOption: function(/*DomNode*/ target){
  5675. // summary:
  5676. // Menu callback function, called when an item in the menu is selected.
  5677. this.closeDropDown();
  5678. if(target){
  5679. this._announceOption(target);
  5680. }
  5681. this._setCaretPos(this.focusNode, this.focusNode.value.length);
  5682. this._handleOnChange(this.value, true);
  5683. },
  5684. _startSearchAll: function(){
  5685. this._startSearch('');
  5686. },
  5687. _startSearchFromInput: function(){
  5688. this._startSearch(this.focusNode.value.replace(/([\\\*\?])/g, "\\$1"));
  5689. },
  5690. _getQueryString: function(/*String*/ text){
  5691. return string.substitute(this.queryExpr, [text]);
  5692. },
  5693. _startSearch: function(/*String*/ key){
  5694. // summary:
  5695. // Starts a search for elements matching key (key=="" means to return all items),
  5696. // and calls _openResultList() when the search completes, to display the results.
  5697. if(!this.dropDown){
  5698. var popupId = this.id + "_popup",
  5699. dropDownConstructor = lang.isString(this.dropDownClass) ?
  5700. lang.getObject(this.dropDownClass, false) : this.dropDownClass;
  5701. this.dropDown = new dropDownConstructor({
  5702. onChange: lang.hitch(this, this._selectOption),
  5703. id: popupId,
  5704. dir: this.dir,
  5705. textDir: this.textDir
  5706. });
  5707. this.focusNode.removeAttribute("aria-activedescendant");
  5708. this.textbox.setAttribute("aria-owns",popupId); // associate popup with textbox
  5709. }
  5710. this._lastInput = key; // Store exactly what was entered by the user.
  5711. // Setup parameters to be passed to store.query().
  5712. // Create a new query to prevent accidentally querying for a hidden
  5713. // value from FilteringSelect's keyField
  5714. var query = lang.clone(this.query); // #5970
  5715. var options = {
  5716. start: 0,
  5717. count: this.pageSize,
  5718. queryOptions: { // remove for 2.0
  5719. ignoreCase: this.ignoreCase,
  5720. deep: true
  5721. }
  5722. };
  5723. lang.mixin(options, this.fetchProperties);
  5724. // Generate query
  5725. var qs = this._getQueryString(key), q;
  5726. if(this.store._oldAPI){
  5727. // remove this branch for 2.0
  5728. q = qs;
  5729. }else{
  5730. // Query on searchAttr is a regex for benefit of dojo.store.Memory,
  5731. // but with a toString() method to help dojo.store.JsonRest.
  5732. // Search string like "Co*" converted to regex like /^Co.*$/i.
  5733. q = filter.patternToRegExp(qs, this.ignoreCase);
  5734. q.toString = function(){ return qs; };
  5735. }
  5736. this._lastQuery = query[this.searchAttr] = q;
  5737. // Function to run the query, wait for the results, and then call _openResultList()
  5738. var _this = this,
  5739. startQuery = function(){
  5740. var resPromise = _this._fetchHandle = _this.store.query(query, options);
  5741. Deferred.when(resPromise, function(res){
  5742. _this._fetchHandle = null;
  5743. res.total = resPromise.total;
  5744. _this._openResultList(res, query, options);
  5745. }, function(err){
  5746. _this._fetchHandle = null;
  5747. if(!_this._cancelingQuery){ // don't treat canceled query as an error
  5748. console.error(_this.declaredClass + ' ' + err.toString());
  5749. _this.closeDropDown();
  5750. }
  5751. });
  5752. };
  5753. // #5970: set _lastQuery, *then* start the timeout
  5754. // otherwise, if the user types and the last query returns before the timeout,
  5755. // _lastQuery won't be set and their input gets rewritten
  5756. this.searchTimer = setTimeout(lang.hitch(this, function(query, _this){
  5757. this.searchTimer = null;
  5758. startQuery();
  5759. // Setup method to handle clicking next/previous buttons to page through results
  5760. this._nextSearch = this.dropDown.onPage = function(direction){
  5761. options.start += options.count * direction;
  5762. // tell callback the direction of the paging so the screen
  5763. // reader knows which menu option to shout
  5764. options.direction = direction;
  5765. startQuery();
  5766. _this.focus();
  5767. };
  5768. }, query, this), this.searchDelay);
  5769. },
  5770. _getValueField: function(){
  5771. // summary:
  5772. // Helper for postMixInProperties() to set this.value based on data inlined into the markup.
  5773. // Returns the attribute name in the item (in dijit.form._ComboBoxDataStore) to use as the value.
  5774. return this.searchAttr;
  5775. },
  5776. //////////// INITIALIZATION METHODS ///////////////////////////////////////
  5777. constructor: function(){
  5778. this.query={};
  5779. this.fetchProperties={};
  5780. },
  5781. postMixInProperties: function(){
  5782. if(!this.store){
  5783. var srcNodeRef = this.srcNodeRef;
  5784. var list = this.list;
  5785. if(list){
  5786. this.store = registry.byId(list);
  5787. }else{
  5788. // if user didn't specify store, then assume there are option tags
  5789. this.store = new DataList({}, srcNodeRef);
  5790. }
  5791. // if there is no value set and there is an option list, set
  5792. // the value to the first value to be consistent with native Select
  5793. // Firefox and Safari set value
  5794. // IE6 and Opera set selectedIndex, which is automatically set
  5795. // by the selected attribute of an option tag
  5796. // IE6 does not set value, Opera sets value = selectedIndex
  5797. if(!("value" in this.params)){
  5798. var item = (this.item = this.store.fetchSelectedItem());
  5799. if(item){
  5800. var valueField = this._getValueField();
  5801. // remove getValue() for 2.0 (old dojo.data API)
  5802. this.value = this.store._oldAPI ? this.store.getValue(item, valueField) : item[valueField];
  5803. }
  5804. }
  5805. }
  5806. this.inherited(arguments);
  5807. },
  5808. postCreate: function(){
  5809. // summary:
  5810. // Subclasses must call this method from their postCreate() methods
  5811. // tags:
  5812. // protected
  5813. // find any associated label element and add to ComboBox node.
  5814. var label=query('label[for="'+this.id+'"]');
  5815. if(label.length){
  5816. label[0].id = (this.id+"_label");
  5817. this.domNode.setAttribute("aria-labelledby", label[0].id);
  5818. }
  5819. this.inherited(arguments);
  5820. // HasDropDown calls _onKey() on keydown but we want to be notified of the synthetic
  5821. // dojo/_base/connect._keypress event too.
  5822. this.connect(this.focusNode, "onkeypress", "_onKeyPress");
  5823. },
  5824. _getMenuLabelFromItem: function(/*Item*/ item){
  5825. var label = this.labelFunc(item, this.store),
  5826. labelType = this.labelType;
  5827. // If labelType is not "text" we don't want to screw any markup ot whatever.
  5828. if(this.highlightMatch != "none" && this.labelType == "text" && this._lastInput){
  5829. label = this.doHighlight(label, this._escapeHtml(this._lastInput));
  5830. labelType = "html";
  5831. }
  5832. return {html: labelType == "html", label: label};
  5833. },
  5834. doHighlight: function(/*String*/ label, /*String*/ find){
  5835. // summary:
  5836. // Highlights the string entered by the user in the menu. By default this
  5837. // highlights the first occurrence found. Override this method
  5838. // to implement your custom highlighting.
  5839. // tags:
  5840. // protected
  5841. var
  5842. // Add (g)lobal modifier when this.highlightMatch == "all" and (i)gnorecase when this.ignoreCase == true
  5843. modifiers = (this.ignoreCase ? "i" : "") + (this.highlightMatch == "all" ? "g" : ""),
  5844. i = this.queryExpr.indexOf("${0}");
  5845. find = regexp.escapeString(find); // escape regexp special chars
  5846. return this._escapeHtml(label).replace(
  5847. // prepend ^ when this.queryExpr == "${0}*" and append $ when this.queryExpr == "*${0}"
  5848. new RegExp((i == 0 ? "^" : "") + "("+ find +")" + (i == (this.queryExpr.length - 4) ? "$" : ""), modifiers),
  5849. '<span class="dijitComboBoxHighlightMatch">$1</span>'
  5850. ); // returns String, (almost) valid HTML (entities encoded)
  5851. },
  5852. _escapeHtml: function(/*String*/ str){
  5853. // TODO Should become dojo.html.entities(), when exists use instead
  5854. // summary:
  5855. // Adds escape sequences for special characters in XML: &<>"'
  5856. str = String(str).replace(/&/gm, "&amp;").replace(/</gm, "&lt;")
  5857. .replace(/>/gm, "&gt;").replace(/"/gm, "&quot;"); //balance"
  5858. return str; // string
  5859. },
  5860. reset: function(){
  5861. // Overrides the _FormWidget.reset().
  5862. // Additionally reset the .item (to clean up).
  5863. this.item = null;
  5864. this.inherited(arguments);
  5865. },
  5866. labelFunc: function(/*item*/ item, /*dojo.store.api.Store*/ store){
  5867. // summary:
  5868. // Computes the label to display based on the dojo.data store item.
  5869. // returns:
  5870. // The label that the ComboBox should display
  5871. // tags:
  5872. // private
  5873. // Use toString() because XMLStore returns an XMLItem whereas this
  5874. // method is expected to return a String (#9354).
  5875. // Remove getValue() for 2.0 (old dojo.data API)
  5876. return (store._oldAPI ? store.getValue(item, this.labelAttr || this.searchAttr) :
  5877. item[this.labelAttr || this.searchAttr]).toString(); // String
  5878. },
  5879. _setValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange, /*String?*/ displayedValue, /*item?*/ item){
  5880. // summary:
  5881. // Hook so set('value', value) works.
  5882. // description:
  5883. // Sets the value of the select.
  5884. this._set("item", item||null); // value not looked up in store
  5885. if(!value){ value = ''; } // null translates to blank
  5886. this.inherited(arguments);
  5887. },
  5888. _setTextDirAttr: function(/*String*/ textDir){
  5889. // summary:
  5890. // Setter for textDir, needed for the dropDown's textDir update.
  5891. // description:
  5892. // Users shouldn't call this function; they should be calling
  5893. // set('textDir', value)
  5894. // tags:
  5895. // private
  5896. this.inherited(arguments);
  5897. // update the drop down also (_ComboBoxMenuMixin)
  5898. if(this.dropDown){
  5899. this.dropDown._set("textDir", textDir);
  5900. }
  5901. }
  5902. });
  5903. });
  5904. },
  5905. 'url:dijit/templates/ColorPalette.html':"<div class=\"dijitInline dijitColorPalette\">\n\t<table dojoAttachPoint=\"paletteTableNode\" class=\"dijitPaletteTable\" cellSpacing=\"0\" cellPadding=\"0\" role=\"grid\">\n\t\t<tbody data-dojo-attach-point=\"gridNode\"></tbody>\n\t</table>\n</div>\n",
  5906. 'url:dijit/layout/templates/_ScrollingTabControllerButton.html':"<div data-dojo-attach-event=\"onclick:_onClick\">\n\t<div role=\"presentation\" class=\"dijitTabInnerDiv\" data-dojo-attach-point=\"innerDiv,focusNode\">\n\t\t<div role=\"presentation\" class=\"dijitTabContent dijitButtonContents\" data-dojo-attach-point=\"tabContent\">\n\t\t\t<img role=\"presentation\" alt=\"\" src=\"${_blankGif}\" class=\"dijitTabStripIcon\" data-dojo-attach-point=\"iconNode\"/>\n\t\t\t<span data-dojo-attach-point=\"containerNode,titleNode\" class=\"dijitButtonText\"></span>\n\t\t</div>\n\t</div>\n</div>",
  5907. 'dijit/form/MappedTextBox':function(){
  5908. define([
  5909. "dojo/_base/declare", // declare
  5910. "dojo/dom-construct", // domConstruct.place
  5911. "./ValidationTextBox"
  5912. ], function(declare, domConstruct, ValidationTextBox){
  5913. /*=====
  5914. var ValidationTextBox = dijit.form.ValidationTextBox;
  5915. =====*/
  5916. // module:
  5917. // dijit/form/MappedTextBox
  5918. // summary:
  5919. // A dijit.form.ValidationTextBox subclass which provides a base class for widgets that have
  5920. // a visible formatted display value, and a serializable
  5921. // value in a hidden input field which is actually sent to the server.
  5922. return declare("dijit.form.MappedTextBox", ValidationTextBox, {
  5923. // summary:
  5924. // A dijit.form.ValidationTextBox subclass which provides a base class for widgets that have
  5925. // a visible formatted display value, and a serializable
  5926. // value in a hidden input field which is actually sent to the server.
  5927. // description:
  5928. // The visible display may
  5929. // be locale-dependent and interactive. The value sent to the server is stored in a hidden
  5930. // input field which uses the `name` attribute declared by the original widget. That value sent
  5931. // to the server is defined by the dijit.form.MappedTextBox.serialize method and is typically
  5932. // locale-neutral.
  5933. // tags:
  5934. // protected
  5935. postMixInProperties: function(){
  5936. this.inherited(arguments);
  5937. // we want the name attribute to go to the hidden <input>, not the displayed <input>,
  5938. // so override _FormWidget.postMixInProperties() setting of nameAttrSetting
  5939. this.nameAttrSetting = "";
  5940. },
  5941. // Override default behavior to assign name to focusNode
  5942. _setNameAttr: null,
  5943. serialize: function(val /*=====, options =====*/){
  5944. // summary:
  5945. // Overridable function used to convert the get('value') result to a canonical
  5946. // (non-localized) string. For example, will print dates in ISO format, and
  5947. // numbers the same way as they are represented in javascript.
  5948. // val: anything
  5949. // options: Object?
  5950. // tags:
  5951. // protected extension
  5952. return val.toString ? val.toString() : ""; // String
  5953. },
  5954. toString: function(){
  5955. // summary:
  5956. // Returns widget as a printable string using the widget's value
  5957. // tags:
  5958. // protected
  5959. var val = this.filter(this.get('value')); // call filter in case value is nonstring and filter has been customized
  5960. return val != null ? (typeof val == "string" ? val : this.serialize(val, this.constraints)) : ""; // String
  5961. },
  5962. validate: function(){
  5963. // Overrides `dijit.form.TextBox.validate`
  5964. this.valueNode.value = this.toString();
  5965. return this.inherited(arguments);
  5966. },
  5967. buildRendering: function(){
  5968. // Overrides `dijit._TemplatedMixin.buildRendering`
  5969. this.inherited(arguments);
  5970. // Create a hidden <input> node with the serialized value used for submit
  5971. // (as opposed to the displayed value).
  5972. // Passing in name as markup rather than calling domConstruct.create() with an attrs argument
  5973. // to make query(input[name=...]) work on IE. (see #8660)
  5974. this.valueNode = domConstruct.place("<input type='hidden'" + (this.name ? " name='" + this.name.replace(/'/g, "&quot;") + "'" : "") + "/>", this.textbox, "after");
  5975. },
  5976. reset: function(){
  5977. // Overrides `dijit.form.ValidationTextBox.reset` to
  5978. // reset the hidden textbox value to ''
  5979. this.valueNode.value = '';
  5980. this.inherited(arguments);
  5981. }
  5982. });
  5983. });
  5984. },
  5985. 'dijit/form/ComboBoxMixin':function(){
  5986. define([
  5987. "dojo/_base/declare", // declare
  5988. "dojo/_base/Deferred",
  5989. "dojo/_base/kernel", // kernel.deprecated
  5990. "dojo/_base/lang", // lang.mixin
  5991. "dojo/store/util/QueryResults", // dojo.store.util.QueryResults
  5992. "./_AutoCompleterMixin",
  5993. "./_ComboBoxMenu",
  5994. "../_HasDropDown",
  5995. "dojo/text!./templates/DropDownBox.html"
  5996. ], function(declare, Deferred, kernel, lang, QueryResults, _AutoCompleterMixin, _ComboBoxMenu, _HasDropDown, template){
  5997. /*=====
  5998. var _AutoCompleterMixin = dijit.form._AutoCompleterMixin;
  5999. var _ComboBoxMenu = dijit.form._ComboBoxMenu;
  6000. var _HasDropDown = dijit._HasDropDown;
  6001. =====*/
  6002. // module:
  6003. // dijit/form/ComboBoxMixin
  6004. // summary:
  6005. // Provides main functionality of ComboBox widget
  6006. return declare("dijit.form.ComboBoxMixin", [_HasDropDown, _AutoCompleterMixin], {
  6007. // summary:
  6008. // Provides main functionality of ComboBox widget
  6009. // dropDownClass: [protected extension] Function String
  6010. // Dropdown widget class used to select a date/time.
  6011. // Subclasses should specify this.
  6012. dropDownClass: _ComboBoxMenu,
  6013. // hasDownArrow: Boolean
  6014. // Set this textbox to have a down arrow button, to display the drop down list.
  6015. // Defaults to true.
  6016. hasDownArrow: true,
  6017. templateString: template,
  6018. baseClass: "dijitTextBox dijitComboBox",
  6019. /*=====
  6020. // store: [const] dojo.store.api.Store || dojo.data.api.Read
  6021. // Reference to data provider object used by this ComboBox.
  6022. //
  6023. // Should be dojo.store.api.Store, but dojo.data.api.Read supported
  6024. // for backwards compatibility.
  6025. store: null,
  6026. =====*/
  6027. // Set classes like dijitDownArrowButtonHover depending on
  6028. // mouse action over button node
  6029. cssStateNodes: {
  6030. "_buttonNode": "dijitDownArrowButton"
  6031. },
  6032. _setHasDownArrowAttr: function(/*Boolean*/ val){
  6033. this._set("hasDownArrow", val);
  6034. this._buttonNode.style.display = val ? "" : "none";
  6035. },
  6036. _showResultList: function(){
  6037. // hide the tooltip
  6038. this.displayMessage("");
  6039. this.inherited(arguments);
  6040. },
  6041. _setStoreAttr: function(store){
  6042. // For backwards-compatibility, accept dojo.data store in addition to dojo.store.store. Remove in 2.0.
  6043. if(!store.get){
  6044. lang.mixin(store, {
  6045. _oldAPI: true,
  6046. get: function(id){
  6047. // summary:
  6048. // Retrieves an object by it's identity. This will trigger a fetchItemByIdentity.
  6049. // Like dojo.store.DataStore.get() except returns native item.
  6050. var deferred = new Deferred();
  6051. this.fetchItemByIdentity({
  6052. identity: id,
  6053. onItem: function(object){
  6054. deferred.resolve(object);
  6055. },
  6056. onError: function(error){
  6057. deferred.reject(error);
  6058. }
  6059. });
  6060. return deferred.promise;
  6061. },
  6062. query: function(query, options){
  6063. // summary:
  6064. // Queries the store for objects. Like dojo.store.DataStore.query()
  6065. // except returned Deferred contains array of native items.
  6066. var deferred = new Deferred(function(){ fetchHandle.abort && fetchHandle.abort(); });
  6067. var fetchHandle = this.fetch(lang.mixin({
  6068. query: query,
  6069. onBegin: function(count){
  6070. deferred.total = count;
  6071. },
  6072. onComplete: function(results){
  6073. deferred.resolve(results);
  6074. },
  6075. onError: function(error){
  6076. deferred.reject(error);
  6077. }
  6078. }, options));
  6079. return QueryResults(deferred);
  6080. }
  6081. });
  6082. }
  6083. this._set("store", store);
  6084. },
  6085. postMixInProperties: function(){
  6086. // Since _setValueAttr() depends on this.store, _setStoreAttr() needs to execute first.
  6087. // Unfortunately, without special code, it ends up executing second.
  6088. if(this.params.store){
  6089. this._setStoreAttr(this.params.store);
  6090. }
  6091. this.inherited(arguments);
  6092. // User may try to access this.store.getValue() etc. in a custom labelFunc() function.
  6093. // It's not available with the new data store for handling inline <option> tags, so add it.
  6094. if(!this.params.store){
  6095. var clazz = this.declaredClass;
  6096. lang.mixin(this.store, {
  6097. getValue: function(item, attr){
  6098. kernel.deprecated(clazz + ".store.getValue(item, attr) is deprecated for builtin store. Use item.attr directly", "", "2.0");
  6099. return item[attr];
  6100. },
  6101. getLabel: function(item){
  6102. kernel.deprecated(clazz + ".store.getLabel(item) is deprecated for builtin store. Use item.label directly", "", "2.0");
  6103. return item.name;
  6104. },
  6105. fetch: function(args){
  6106. kernel.deprecated(clazz + ".store.fetch() is deprecated for builtin store.", "Use store.query()", "2.0");
  6107. var shim = ["dojo/data/ObjectStore"]; // indirection so it doesn't get rolled into a build
  6108. require(shim, lang.hitch(this, function(ObjectStore){
  6109. new ObjectStore({objectStore: this}).fetch(args);
  6110. }));
  6111. }
  6112. });
  6113. }
  6114. }
  6115. });
  6116. });
  6117. },
  6118. 'dijit/form/_TextBoxMixin':function(){
  6119. define([
  6120. "dojo/_base/array", // array.forEach
  6121. "dojo/_base/declare", // declare
  6122. "dojo/dom", // dom.byId
  6123. "dojo/_base/event", // event.stop
  6124. "dojo/keys", // keys.ALT keys.CAPS_LOCK keys.CTRL keys.META keys.SHIFT
  6125. "dojo/_base/lang", // lang.mixin
  6126. ".." // for exporting dijit._setSelectionRange, dijit.selectInputText
  6127. ], function(array, declare, dom, event, keys, lang, dijit){
  6128. // module:
  6129. // dijit/form/_TextBoxMixin
  6130. // summary:
  6131. // A mixin for textbox form input widgets
  6132. var _TextBoxMixin = declare("dijit.form._TextBoxMixin", null, {
  6133. // summary:
  6134. // A mixin for textbox form input widgets
  6135. // trim: Boolean
  6136. // Removes leading and trailing whitespace if true. Default is false.
  6137. trim: false,
  6138. // uppercase: Boolean
  6139. // Converts all characters to uppercase if true. Default is false.
  6140. uppercase: false,
  6141. // lowercase: Boolean
  6142. // Converts all characters to lowercase if true. Default is false.
  6143. lowercase: false,
  6144. // propercase: Boolean
  6145. // Converts the first character of each word to uppercase if true.
  6146. propercase: false,
  6147. // maxLength: String
  6148. // HTML INPUT tag maxLength declaration.
  6149. maxLength: "",
  6150. // selectOnClick: [const] Boolean
  6151. // If true, all text will be selected when focused with mouse
  6152. selectOnClick: false,
  6153. // placeHolder: String
  6154. // Defines a hint to help users fill out the input field (as defined in HTML 5).
  6155. // This should only contain plain text (no html markup).
  6156. placeHolder: "",
  6157. _getValueAttr: function(){
  6158. // summary:
  6159. // Hook so get('value') works as we like.
  6160. // description:
  6161. // For `dijit.form.TextBox` this basically returns the value of the <input>.
  6162. //
  6163. // For `dijit.form.MappedTextBox` subclasses, which have both
  6164. // a "displayed value" and a separate "submit value",
  6165. // This treats the "displayed value" as the master value, computing the
  6166. // submit value from it via this.parse().
  6167. return this.parse(this.get('displayedValue'), this.constraints);
  6168. },
  6169. _setValueAttr: function(value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
  6170. // summary:
  6171. // Hook so set('value', ...) works.
  6172. //
  6173. // description:
  6174. // Sets the value of the widget to "value" which can be of
  6175. // any type as determined by the widget.
  6176. //
  6177. // value:
  6178. // The visual element value is also set to a corresponding,
  6179. // but not necessarily the same, value.
  6180. //
  6181. // formattedValue:
  6182. // If specified, used to set the visual element value,
  6183. // otherwise a computed visual value is used.
  6184. //
  6185. // priorityChange:
  6186. // If true, an onChange event is fired immediately instead of
  6187. // waiting for the next blur event.
  6188. var filteredValue;
  6189. if(value !== undefined){
  6190. // TODO: this is calling filter() on both the display value and the actual value.
  6191. // I added a comment to the filter() definition about this, but it should be changed.
  6192. filteredValue = this.filter(value);
  6193. if(typeof formattedValue != "string"){
  6194. if(filteredValue !== null && ((typeof filteredValue != "number") || !isNaN(filteredValue))){
  6195. formattedValue = this.filter(this.format(filteredValue, this.constraints));
  6196. }else{ formattedValue = ''; }
  6197. }
  6198. }
  6199. if(formattedValue != null && formattedValue != undefined && ((typeof formattedValue) != "number" || !isNaN(formattedValue)) && this.textbox.value != formattedValue){
  6200. this.textbox.value = formattedValue;
  6201. this._set("displayedValue", this.get("displayedValue"));
  6202. }
  6203. if(this.textDir == "auto"){
  6204. this.applyTextDir(this.focusNode, formattedValue);
  6205. }
  6206. this.inherited(arguments, [filteredValue, priorityChange]);
  6207. },
  6208. // displayedValue: String
  6209. // For subclasses like ComboBox where the displayed value
  6210. // (ex: Kentucky) and the serialized value (ex: KY) are different,
  6211. // this represents the displayed value.
  6212. //
  6213. // Setting 'displayedValue' through set('displayedValue', ...)
  6214. // updates 'value', and vice-versa. Otherwise 'value' is updated
  6215. // from 'displayedValue' periodically, like onBlur etc.
  6216. //
  6217. // TODO: move declaration to MappedTextBox?
  6218. // Problem is that ComboBox references displayedValue,
  6219. // for benefit of FilteringSelect.
  6220. displayedValue: "",
  6221. _getDisplayedValueAttr: function(){
  6222. // summary:
  6223. // Hook so get('displayedValue') works.
  6224. // description:
  6225. // Returns the displayed value (what the user sees on the screen),
  6226. // after filtering (ie, trimming spaces etc.).
  6227. //
  6228. // For some subclasses of TextBox (like ComboBox), the displayed value
  6229. // is different from the serialized value that's actually
  6230. // sent to the server (see dijit.form.ValidationTextBox.serialize)
  6231. // TODO: maybe we should update this.displayedValue on every keystroke so that we don't need
  6232. // this method
  6233. // TODO: this isn't really the displayed value when the user is typing
  6234. return this.filter(this.textbox.value);
  6235. },
  6236. _setDisplayedValueAttr: function(/*String*/ value){
  6237. // summary:
  6238. // Hook so set('displayedValue', ...) works.
  6239. // description:
  6240. // Sets the value of the visual element to the string "value".
  6241. // The widget value is also set to a corresponding,
  6242. // but not necessarily the same, value.
  6243. if(value === null || value === undefined){ value = '' }
  6244. else if(typeof value != "string"){ value = String(value) }
  6245. this.textbox.value = value;
  6246. // sets the serialized value to something corresponding to specified displayedValue
  6247. // (if possible), and also updates the textbox.value, for example converting "123"
  6248. // to "123.00"
  6249. this._setValueAttr(this.get('value'), undefined);
  6250. this._set("displayedValue", this.get('displayedValue'));
  6251. // textDir support
  6252. if(this.textDir == "auto"){
  6253. this.applyTextDir(this.focusNode, value);
  6254. }
  6255. },
  6256. format: function(value /*=====, constraints =====*/){
  6257. // summary:
  6258. // Replaceable function to convert a value to a properly formatted string.
  6259. // value: String
  6260. // constraints: Object
  6261. // tags:
  6262. // protected extension
  6263. return ((value == null || value == undefined) ? "" : (value.toString ? value.toString() : value));
  6264. },
  6265. parse: function(value /*=====, constraints =====*/){
  6266. // summary:
  6267. // Replaceable function to convert a formatted string to a value
  6268. // value: String
  6269. // constraints: Object
  6270. // tags:
  6271. // protected extension
  6272. return value; // String
  6273. },
  6274. _refreshState: function(){
  6275. // summary:
  6276. // After the user types some characters, etc., this method is
  6277. // called to check the field for validity etc. The base method
  6278. // in `dijit.form.TextBox` does nothing, but subclasses override.
  6279. // tags:
  6280. // protected
  6281. },
  6282. /*=====
  6283. onInput: function(event){
  6284. // summary:
  6285. // Connect to this function to receive notifications of various user data-input events.
  6286. // Return false to cancel the event and prevent it from being processed.
  6287. // event:
  6288. // keydown | keypress | cut | paste | input
  6289. // tags:
  6290. // callback
  6291. },
  6292. =====*/
  6293. onInput: function(){},
  6294. __skipInputEvent: false,
  6295. _onInput: function(){
  6296. // summary:
  6297. // Called AFTER the input event has happened
  6298. // set text direction according to textDir that was defined in creation
  6299. if(this.textDir == "auto"){
  6300. this.applyTextDir(this.focusNode, this.focusNode.value);
  6301. }
  6302. this._refreshState();
  6303. // In case someone is watch()'ing for changes to displayedValue
  6304. this._set("displayedValue", this.get("displayedValue"));
  6305. },
  6306. postCreate: function(){
  6307. // setting the value here is needed since value="" in the template causes "undefined"
  6308. // and setting in the DOM (instead of the JS object) helps with form reset actions
  6309. this.textbox.setAttribute("value", this.textbox.value); // DOM and JS values should be the same
  6310. this.inherited(arguments);
  6311. // normalize input events to reduce spurious event processing
  6312. // onkeydown: do not forward modifier keys
  6313. // set charOrCode to numeric keycode
  6314. // onkeypress: do not forward numeric charOrCode keys (already sent through onkeydown)
  6315. // onpaste & oncut: set charOrCode to 229 (IME)
  6316. // oninput: if primary event not already processed, set charOrCode to 229 (IME), else do not forward
  6317. var handleEvent = function(e){
  6318. var charCode = e.charOrCode || e.keyCode || 229;
  6319. if(e.type == "keydown"){
  6320. switch(charCode){ // ignore "state" keys
  6321. case keys.SHIFT:
  6322. case keys.ALT:
  6323. case keys.CTRL:
  6324. case keys.META:
  6325. case keys.CAPS_LOCK:
  6326. return;
  6327. default:
  6328. if(charCode >= 65 && charCode <= 90){ return; } // keydown for A-Z can be processed with keypress
  6329. }
  6330. }
  6331. if(e.type == "keypress" && typeof charCode != "string"){ return; }
  6332. if(e.type == "input"){
  6333. if(this.__skipInputEvent){ // duplicate event
  6334. this.__skipInputEvent = false;
  6335. return;
  6336. }
  6337. }else{
  6338. this.__skipInputEvent = true;
  6339. }
  6340. // create fake event to set charOrCode and to know if preventDefault() was called
  6341. var faux = lang.mixin({}, e, {
  6342. charOrCode: charCode,
  6343. wasConsumed: false,
  6344. preventDefault: function(){
  6345. faux.wasConsumed = true;
  6346. e.preventDefault();
  6347. },
  6348. stopPropagation: function(){ e.stopPropagation(); }
  6349. });
  6350. // give web page author a chance to consume the event
  6351. if(this.onInput(faux) === false){
  6352. event.stop(faux); // return false means stop
  6353. }
  6354. if(faux.wasConsumed){ return; } // if preventDefault was called
  6355. setTimeout(lang.hitch(this, "_onInput", faux), 0); // widget notification after key has posted
  6356. };
  6357. array.forEach([ "onkeydown", "onkeypress", "onpaste", "oncut", "oninput", "oncompositionend" ], function(event){
  6358. this.connect(this.textbox, event, handleEvent);
  6359. }, this);
  6360. },
  6361. _blankValue: '', // if the textbox is blank, what value should be reported
  6362. filter: function(val){
  6363. // summary:
  6364. // Auto-corrections (such as trimming) that are applied to textbox
  6365. // value on blur or form submit.
  6366. // description:
  6367. // For MappedTextBox subclasses, this is called twice
  6368. // - once with the display value
  6369. // - once the value as set/returned by set('value', ...)
  6370. // and get('value'), ex: a Number for NumberTextBox.
  6371. //
  6372. // In the latter case it does corrections like converting null to NaN. In
  6373. // the former case the NumberTextBox.filter() method calls this.inherited()
  6374. // to execute standard trimming code in TextBox.filter().
  6375. //
  6376. // TODO: break this into two methods in 2.0
  6377. //
  6378. // tags:
  6379. // protected extension
  6380. if(val === null){ return this._blankValue; }
  6381. if(typeof val != "string"){ return val; }
  6382. if(this.trim){
  6383. val = lang.trim(val);
  6384. }
  6385. if(this.uppercase){
  6386. val = val.toUpperCase();
  6387. }
  6388. if(this.lowercase){
  6389. val = val.toLowerCase();
  6390. }
  6391. if(this.propercase){
  6392. val = val.replace(/[^\s]+/g, function(word){
  6393. return word.substring(0,1).toUpperCase() + word.substring(1);
  6394. });
  6395. }
  6396. return val;
  6397. },
  6398. _setBlurValue: function(){
  6399. this._setValueAttr(this.get('value'), true);
  6400. },
  6401. _onBlur: function(e){
  6402. if(this.disabled){ return; }
  6403. this._setBlurValue();
  6404. this.inherited(arguments);
  6405. if(this._selectOnClickHandle){
  6406. this.disconnect(this._selectOnClickHandle);
  6407. }
  6408. },
  6409. _isTextSelected: function(){
  6410. return this.textbox.selectionStart == this.textbox.selectionEnd;
  6411. },
  6412. _onFocus: function(/*String*/ by){
  6413. if(this.disabled || this.readOnly){ return; }
  6414. // Select all text on focus via click if nothing already selected.
  6415. // Since mouse-up will clear the selection need to defer selection until after mouse-up.
  6416. // Don't do anything on focus by tabbing into the widget since there's no associated mouse-up event.
  6417. if(this.selectOnClick && by == "mouse"){
  6418. this._selectOnClickHandle = this.connect(this.domNode, "onmouseup", function(){
  6419. // Only select all text on first click; otherwise users would have no way to clear
  6420. // the selection.
  6421. this.disconnect(this._selectOnClickHandle);
  6422. // Check if the user selected some text manually (mouse-down, mouse-move, mouse-up)
  6423. // and if not, then select all the text
  6424. if(this._isTextSelected()){
  6425. _TextBoxMixin.selectInputText(this.textbox);
  6426. }
  6427. });
  6428. }
  6429. // call this.inherited() before refreshState(), since this.inherited() will possibly scroll the viewport
  6430. // (to scroll the TextBox into view), which will affect how _refreshState() positions the tooltip
  6431. this.inherited(arguments);
  6432. this._refreshState();
  6433. },
  6434. reset: function(){
  6435. // Overrides dijit._FormWidget.reset().
  6436. // Additionally resets the displayed textbox value to ''
  6437. this.textbox.value = '';
  6438. this.inherited(arguments);
  6439. },
  6440. _setTextDirAttr: function(/*String*/ textDir){
  6441. // summary:
  6442. // Setter for textDir.
  6443. // description:
  6444. // Users shouldn't call this function; they should be calling
  6445. // set('textDir', value)
  6446. // tags:
  6447. // private
  6448. // only if new textDir is different from the old one
  6449. // and on widgets creation.
  6450. if(!this._created
  6451. || this.textDir != textDir){
  6452. this._set("textDir", textDir);
  6453. // so the change of the textDir will take place immediately.
  6454. this.applyTextDir(this.focusNode, this.focusNode.value);
  6455. }
  6456. }
  6457. });
  6458. _TextBoxMixin._setSelectionRange = dijit._setSelectionRange = function(/*DomNode*/ element, /*Number?*/ start, /*Number?*/ stop){
  6459. if(element.setSelectionRange){
  6460. element.setSelectionRange(start, stop);
  6461. }
  6462. };
  6463. _TextBoxMixin.selectInputText = dijit.selectInputText = function(/*DomNode*/ element, /*Number?*/ start, /*Number?*/ stop){
  6464. // summary:
  6465. // Select text in the input element argument, from start (default 0), to stop (default end).
  6466. // TODO: use functions in _editor/selection.js?
  6467. element = dom.byId(element);
  6468. if(isNaN(start)){ start = 0; }
  6469. if(isNaN(stop)){ stop = element.value ? element.value.length : 0; }
  6470. try{
  6471. element.focus();
  6472. _TextBoxMixin._setSelectionRange(element, start, stop);
  6473. }catch(e){ /* squelch random errors (esp. on IE) from unexpected focus changes or DOM nodes being hidden */ }
  6474. };
  6475. return _TextBoxMixin;
  6476. });
  6477. },
  6478. 'dojo/_base/query':function(){
  6479. define(["./kernel", "../query", "./NodeList"], function(dojo){
  6480. return dojo.query;
  6481. });
  6482. },
  6483. 'dijit/form/SimpleTextarea':function(){
  6484. define("dijit/form/SimpleTextarea", [
  6485. "dojo/_base/declare", // declare
  6486. "dojo/dom-class", // domClass.add
  6487. "dojo/_base/sniff", // has("ie") has("opera")
  6488. "dojo/_base/window", // win.doc.selection win.doc.selection.createRange
  6489. "./TextBox"
  6490. ], function(declare, domClass, has, win, TextBox){
  6491. /*=====
  6492. var TextBox = dijit.form.TextBox;
  6493. =====*/
  6494. // module:
  6495. // dijit/form/SimpleTextarea
  6496. // summary:
  6497. // A simple textarea that degrades, and responds to
  6498. // minimal LayoutContainer usage, and works with dijit.form.Form.
  6499. // Doesn't automatically size according to input, like Textarea.
  6500. return declare("dijit.form.SimpleTextarea", TextBox, {
  6501. // summary:
  6502. // A simple textarea that degrades, and responds to
  6503. // minimal LayoutContainer usage, and works with dijit.form.Form.
  6504. // Doesn't automatically size according to input, like Textarea.
  6505. //
  6506. // example:
  6507. // | <textarea data-dojo-type="dijit.form.SimpleTextarea" name="foo" value="bar" rows=30 cols=40></textarea>
  6508. //
  6509. // example:
  6510. // | new dijit.form.SimpleTextarea({ rows:20, cols:30 }, "foo");
  6511. baseClass: "dijitTextBox dijitTextArea",
  6512. // rows: Number
  6513. // The number of rows of text.
  6514. rows: "3",
  6515. // rows: Number
  6516. // The number of characters per line.
  6517. cols: "20",
  6518. templateString: "<textarea ${!nameAttrSetting} data-dojo-attach-point='focusNode,containerNode,textbox' autocomplete='off'></textarea>",
  6519. postMixInProperties: function(){
  6520. // Copy value from srcNodeRef, unless user specified a value explicitly (or there is no srcNodeRef)
  6521. // TODO: parser will handle this in 2.0
  6522. if(!this.value && this.srcNodeRef){
  6523. this.value = this.srcNodeRef.value;
  6524. }
  6525. this.inherited(arguments);
  6526. },
  6527. buildRendering: function(){
  6528. this.inherited(arguments);
  6529. if(has("ie") && this.cols){ // attribute selectors is not supported in IE6
  6530. domClass.add(this.textbox, "dijitTextAreaCols");
  6531. }
  6532. },
  6533. filter: function(/*String*/ value){
  6534. // Override TextBox.filter to deal with newlines... specifically (IIRC) this is for IE which writes newlines
  6535. // as \r\n instead of just \n
  6536. if(value){
  6537. value = value.replace(/\r/g,"");
  6538. }
  6539. return this.inherited(arguments);
  6540. },
  6541. _onInput: function(/*Event?*/ e){
  6542. // Override TextBox._onInput() to enforce maxLength restriction
  6543. if(this.maxLength){
  6544. var maxLength = parseInt(this.maxLength);
  6545. var value = this.textbox.value.replace(/\r/g,'');
  6546. var overflow = value.length - maxLength;
  6547. if(overflow > 0){
  6548. var textarea = this.textbox;
  6549. if(textarea.selectionStart){
  6550. var pos = textarea.selectionStart;
  6551. var cr = 0;
  6552. if(has("opera")){
  6553. cr = (this.textbox.value.substring(0,pos).match(/\r/g) || []).length;
  6554. }
  6555. this.textbox.value = value.substring(0,pos-overflow-cr)+value.substring(pos-cr);
  6556. textarea.setSelectionRange(pos-overflow, pos-overflow);
  6557. }else if(win.doc.selection){ //IE
  6558. textarea.focus();
  6559. var range = win.doc.selection.createRange();
  6560. // delete overflow characters
  6561. range.moveStart("character", -overflow);
  6562. range.text = '';
  6563. // show cursor
  6564. range.select();
  6565. }
  6566. }
  6567. }
  6568. this.inherited(arguments);
  6569. }
  6570. });
  6571. });
  6572. },
  6573. 'url:dijit/layout/templates/_TabButton.html':"<div role=\"presentation\" data-dojo-attach-point=\"titleNode\" data-dojo-attach-event='onclick:onClick'>\n <div role=\"presentation\" class='dijitTabInnerDiv' data-dojo-attach-point='innerDiv'>\n <div role=\"presentation\" class='dijitTabContent' data-dojo-attach-point='tabContent'>\n \t<div role=\"presentation\" data-dojo-attach-point='focusNode'>\n\t\t <img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitTabButtonIcon\" data-dojo-attach-point='iconNode' />\n\t\t <span data-dojo-attach-point='containerNode' class='tabLabel'></span>\n\t\t <span class=\"dijitInline dijitTabCloseButton dijitTabCloseIcon\" data-dojo-attach-point='closeNode'\n\t\t \t\tdata-dojo-attach-event='onclick: onClickCloseButton' role=\"presentation\">\n\t\t <span data-dojo-attach-point='closeText' class='dijitTabCloseText'>[x]</span\n\t\t ></span>\n\t\t\t</div>\n </div>\n </div>\n</div>\n",
  6574. 'dijit/PopupMenuItem':function(){
  6575. define([
  6576. "dojo/_base/declare", // declare
  6577. "dojo/dom-style", // domStyle.set
  6578. "dojo/query", // query
  6579. "dojo/_base/window", // win.body
  6580. "./registry", // registry.byNode
  6581. "./MenuItem",
  6582. "./hccss"
  6583. ], function(declare, domStyle, query, win, registry, MenuItem){
  6584. /*=====
  6585. var MenuItem = dijit.MenuItem;
  6586. =====*/
  6587. // module:
  6588. // dijit/PopupMenuItem
  6589. // summary:
  6590. // An item in a Menu that spawn a drop down (usually a drop down menu)
  6591. return declare("dijit.PopupMenuItem", MenuItem, {
  6592. // summary:
  6593. // An item in a Menu that spawn a drop down (usually a drop down menu)
  6594. _fillContent: function(){
  6595. // summary:
  6596. // When Menu is declared in markup, this code gets the menu label and
  6597. // the popup widget from the srcNodeRef.
  6598. // description:
  6599. // srcNodeRefinnerHTML contains both the menu item text and a popup widget
  6600. // The first part holds the menu item text and the second part is the popup
  6601. // example:
  6602. // | <div data-dojo-type="dijit.PopupMenuItem">
  6603. // | <span>pick me</span>
  6604. // | <popup> ... </popup>
  6605. // | </div>
  6606. // tags:
  6607. // protected
  6608. if(this.srcNodeRef){
  6609. var nodes = query("*", this.srcNodeRef);
  6610. this.inherited(arguments, [nodes[0]]);
  6611. // save pointer to srcNode so we can grab the drop down widget after it's instantiated
  6612. this.dropDownContainer = this.srcNodeRef;
  6613. }
  6614. },
  6615. startup: function(){
  6616. if(this._started){ return; }
  6617. this.inherited(arguments);
  6618. // we didn't copy the dropdown widget from the this.srcNodeRef, so it's in no-man's
  6619. // land now. move it to win.doc.body.
  6620. if(!this.popup){
  6621. var node = query("[widgetId]", this.dropDownContainer)[0];
  6622. this.popup = registry.byNode(node);
  6623. }
  6624. win.body().appendChild(this.popup.domNode);
  6625. this.popup.startup();
  6626. this.popup.domNode.style.display="none";
  6627. if(this.arrowWrapper){
  6628. domStyle.set(this.arrowWrapper, "visibility", "");
  6629. }
  6630. this.focusNode.setAttribute("aria-haspopup", "true");
  6631. },
  6632. destroyDescendants: function(/*Boolean*/ preserveDom){
  6633. if(this.popup){
  6634. // Destroy the popup, unless it's already been destroyed. This can happen because
  6635. // the popup is a direct child of <body> even though it's logically my child.
  6636. if(!this.popup._destroyed){
  6637. this.popup.destroyRecursive(preserveDom);
  6638. }
  6639. delete this.popup;
  6640. }
  6641. this.inherited(arguments);
  6642. }
  6643. });
  6644. });
  6645. },
  6646. 'dijit/_TimePicker':function(){
  6647. define([
  6648. "dojo/_base/array", // array.forEach
  6649. "dojo/date", // date.compare
  6650. "dojo/date/locale", // locale.format
  6651. "dojo/date/stamp", // stamp.fromISOString stamp.toISOString
  6652. "dojo/_base/declare", // declare
  6653. "dojo/dom-class", // domClass.add domClass.contains domClass.toggle
  6654. "dojo/dom-construct", // domConstruct.create
  6655. "dojo/_base/event", // event.stop
  6656. "dojo/_base/kernel", // deprecated
  6657. "dojo/keys", // keys
  6658. "dojo/_base/lang", // lang.mixin
  6659. "dojo/_base/sniff", // has("ie")
  6660. "dojo/query", // query
  6661. "dijit/typematic",
  6662. "./_Widget",
  6663. "./_TemplatedMixin",
  6664. "./form/_FormValueWidget",
  6665. "dojo/text!./templates/TimePicker.html"
  6666. ], function(array, ddate, locale, stamp, declare, domClass, domConstruct, event, kernel, keys, lang, has, query,
  6667. typematic, _Widget, _TemplatedMixin, _FormValueWidget, template){
  6668. /*=====
  6669. var _Widget = dijit._Widget;
  6670. var _TemplatedMixin = dijit._TemplatedMixin;
  6671. var _FormValueWidget = dijit.form._FormValueWidget;
  6672. =====*/
  6673. // module:
  6674. // dijit/_TimePicker
  6675. // summary:
  6676. // A graphical time picker.
  6677. /*=====
  6678. declare(
  6679. "dijit._TimePicker.__Constraints",
  6680. locale.__FormatOptions,
  6681. {
  6682. // clickableIncrement: String
  6683. // See `dijit._TimePicker.clickableIncrement`
  6684. clickableIncrement: "T00:15:00",
  6685. // visibleIncrement: String
  6686. // See `dijit._TimePicker.visibleIncrement`
  6687. visibleIncrement: "T01:00:00",
  6688. // visibleRange: String
  6689. // See `dijit._TimePicker.visibleRange`
  6690. visibleRange: "T05:00:00"
  6691. }
  6692. );
  6693. =====*/
  6694. return declare("dijit._TimePicker", [_Widget, _TemplatedMixin], {
  6695. // summary:
  6696. // A graphical time picker.
  6697. // This widget is used internally by other widgets and is not available
  6698. // as a standalone widget due to lack of accessibility support.
  6699. templateString: template,
  6700. // baseClass: [protected] String
  6701. // The root className to use for the various states of this widget
  6702. baseClass: "dijitTimePicker",
  6703. // clickableIncrement: String
  6704. // ISO-8601 string representing the amount by which
  6705. // every clickable element in the time picker increases.
  6706. // Set in local time, without a time zone.
  6707. // Example: `T00:15:00` creates 15 minute increments
  6708. // Must divide dijit._TimePicker.visibleIncrement evenly
  6709. clickableIncrement: "T00:15:00",
  6710. // visibleIncrement: String
  6711. // ISO-8601 string representing the amount by which
  6712. // every element with a visible time in the time picker increases.
  6713. // Set in local time, without a time zone.
  6714. // Example: `T01:00:00` creates text in every 1 hour increment
  6715. visibleIncrement: "T01:00:00",
  6716. // visibleRange: String
  6717. // ISO-8601 string representing the range of this TimePicker.
  6718. // The TimePicker will only display times in this range.
  6719. // Example: `T05:00:00` displays 5 hours of options
  6720. visibleRange: "T05:00:00",
  6721. // value: String
  6722. // Date to display.
  6723. // Defaults to current time and date.
  6724. // Can be a Date object or an ISO-8601 string.
  6725. // If you specify the GMT time zone (`-01:00`),
  6726. // the time will be converted to the local time in the local time zone.
  6727. // Otherwise, the time is considered to be in the local time zone.
  6728. // If you specify the date and isDate is true, the date is used.
  6729. // Example: if your local time zone is `GMT -05:00`,
  6730. // `T10:00:00` becomes `T10:00:00-05:00` (considered to be local time),
  6731. // `T10:00:00-01:00` becomes `T06:00:00-05:00` (4 hour difference),
  6732. // `T10:00:00Z` becomes `T05:00:00-05:00` (5 hour difference between Zulu and local time)
  6733. // `yyyy-mm-ddThh:mm:ss` is the format to set the date and time
  6734. // Example: `2007-06-01T09:00:00`
  6735. value: new Date(),
  6736. _visibleIncrement:2,
  6737. _clickableIncrement:1,
  6738. _totalIncrements:10,
  6739. // constraints: dijit._TimePicker.__Constraints
  6740. // Specifies valid range of times (start time, end time)
  6741. constraints:{},
  6742. /*=====
  6743. serialize: function(val, options){
  6744. // summary:
  6745. // User overridable function used to convert the attr('value') result to a String
  6746. // val: Date
  6747. // The current value
  6748. // options: Object?
  6749. // tags:
  6750. // protected
  6751. },
  6752. =====*/
  6753. serialize: stamp.toISOString,
  6754. /*=====
  6755. // filterString: string
  6756. // The string to filter by
  6757. filterString: "",
  6758. =====*/
  6759. setValue: function(/*Date*/ value){
  6760. // summary:
  6761. // Deprecated. Used set('value') instead.
  6762. // tags:
  6763. // deprecated
  6764. kernel.deprecated("dijit._TimePicker:setValue() is deprecated. Use set('value', ...) instead.", "", "2.0");
  6765. this.set('value', value);
  6766. },
  6767. _setValueAttr: function(/*Date*/ date){
  6768. // summary:
  6769. // Hook so set('value', ...) works.
  6770. // description:
  6771. // Set the value of the TimePicker.
  6772. // Redraws the TimePicker around the new date.
  6773. // tags:
  6774. // protected
  6775. this._set("value", date);
  6776. this._showText();
  6777. },
  6778. _setFilterStringAttr: function(val){
  6779. // summary:
  6780. // Called by TimeTextBox to filter the values shown in my list
  6781. this._set("filterString", val);
  6782. this._showText();
  6783. },
  6784. isDisabledDate: function(/*===== dateObject, locale =====*/){
  6785. // summary:
  6786. // May be overridden to disable certain dates in the TimePicker e.g. `isDisabledDate=locale.isWeekend`
  6787. // dateObject: Date
  6788. // locale: String?
  6789. // type:
  6790. // extension
  6791. return false; // Boolean
  6792. },
  6793. _getFilteredNodes: function(/*number*/ start, /*number*/ maxNum, /*Boolean*/ before, /*DOMnode*/ lastNode){
  6794. // summary:
  6795. // Returns an array of nodes with the filter applied. At most maxNum nodes
  6796. // will be returned - but fewer may be returned as well. If the
  6797. // before parameter is set to true, then it will return the elements
  6798. // before the given index
  6799. // tags:
  6800. // private
  6801. var
  6802. nodes = [],
  6803. lastValue = lastNode ? lastNode.date : this._refDate,
  6804. n,
  6805. i = start,
  6806. max = this._maxIncrement + Math.abs(i),
  6807. chk = before ? -1 : 1,
  6808. dec = before ? 1 : 0,
  6809. inc = 1 - dec;
  6810. do{
  6811. i -= dec;
  6812. n = this._createOption(i);
  6813. if(n){
  6814. if((before && n.date > lastValue) || (!before && n.date < lastValue)){
  6815. break; // don't wrap
  6816. }
  6817. nodes[before ? "unshift" : "push"](n);
  6818. lastValue = n.date;
  6819. }
  6820. i += inc;
  6821. }while(nodes.length < maxNum && (i*chk) < max);
  6822. return nodes;
  6823. },
  6824. _showText: function(){
  6825. // summary:
  6826. // Displays the relevant choices in the drop down list
  6827. // tags:
  6828. // private
  6829. var fromIso = stamp.fromISOString;
  6830. this.timeMenu.innerHTML = "";
  6831. this._clickableIncrementDate=fromIso(this.clickableIncrement);
  6832. this._visibleIncrementDate=fromIso(this.visibleIncrement);
  6833. this._visibleRangeDate=fromIso(this.visibleRange);
  6834. // get the value of the increments and the range in seconds (since 00:00:00) to find out how many divs to create
  6835. var
  6836. sinceMidnight = function(/*Date*/ date){
  6837. return date.getHours() * 60 * 60 + date.getMinutes() * 60 + date.getSeconds();
  6838. },
  6839. clickableIncrementSeconds = sinceMidnight(this._clickableIncrementDate),
  6840. visibleIncrementSeconds = sinceMidnight(this._visibleIncrementDate),
  6841. visibleRangeSeconds = sinceMidnight(this._visibleRangeDate),
  6842. // round reference date to previous visible increment
  6843. time = (this.value || this.currentFocus).getTime();
  6844. this._refDate = new Date(time - time % (clickableIncrementSeconds*1000));
  6845. this._refDate.setFullYear(1970,0,1); // match parse defaults
  6846. // assume clickable increment is the smallest unit
  6847. this._clickableIncrement = 1;
  6848. // divide the visible range by the clickable increment to get the number of divs to create
  6849. // example: 10:00:00/00:15:00 -> display 40 divs
  6850. this._totalIncrements = visibleRangeSeconds / clickableIncrementSeconds;
  6851. // divide the visible increments by the clickable increments to get how often to display the time inline
  6852. // example: 01:00:00/00:15:00 -> display the time every 4 divs
  6853. this._visibleIncrement = visibleIncrementSeconds / clickableIncrementSeconds;
  6854. // divide the number of seconds in a day by the clickable increment in seconds to get the
  6855. // absolute max number of increments.
  6856. this._maxIncrement = (60 * 60 * 24) / clickableIncrementSeconds;
  6857. var
  6858. // Find the nodes we should display based on our filter.
  6859. // Limit to 10 nodes displayed as a half-hearted attempt to stop drop down from overlapping <input>.
  6860. count = Math.min(this._totalIncrements, 10),
  6861. after = this._getFilteredNodes(0, (count >> 1) + 1, false),
  6862. moreAfter = [],
  6863. estBeforeLength = count - after.length,
  6864. before = this._getFilteredNodes(0, estBeforeLength, true, after[0]);
  6865. if(before.length < estBeforeLength && after.length > 0){
  6866. moreAfter = this._getFilteredNodes(after.length, estBeforeLength - before.length, false, after[after.length-1]);
  6867. }
  6868. array.forEach(before.concat(after, moreAfter), function(n){ this.timeMenu.appendChild(n); }, this);
  6869. },
  6870. constructor: function(){
  6871. this.constraints = {}; // create instance object
  6872. },
  6873. postMixInProperties: function(){
  6874. this.inherited(arguments);
  6875. this._setConstraintsAttr(this.constraints); // this needs to happen now (and later) due to codependency on _set*Attr calls
  6876. },
  6877. _setConstraintsAttr: function(/* Object */ constraints){
  6878. // brings in visibleRange, increments, etc.
  6879. for (var key in { clickableIncrement: 1, visibleIncrement: 1, visibleRange: 1 }) {
  6880. if (key in constraints) {
  6881. this[key] = constraints[key];
  6882. }
  6883. }
  6884. // locale needs the lang in the constraints as locale
  6885. if(!constraints.locale){
  6886. constraints.locale = this.lang;
  6887. }
  6888. },
  6889. postCreate: function(){
  6890. // assign typematic mouse listeners to the arrow buttons
  6891. this.connect(this.timeMenu, has("ie") ? "onmousewheel" : 'DOMMouseScroll', "_mouseWheeled");
  6892. this._connects.push(typematic.addMouseListener(this.upArrow, this, "_onArrowUp", 33, 250));
  6893. this._connects.push(typematic.addMouseListener(this.downArrow, this, "_onArrowDown", 33, 250));
  6894. this.inherited(arguments);
  6895. },
  6896. _buttonMouse: function(/*Event*/ e){
  6897. // summary:
  6898. // Handler for hover (and unhover) on up/down arrows
  6899. // tags:
  6900. // private
  6901. // in non-IE browser the "mouseenter" event will become "mouseover",
  6902. // but in IE it's still "mouseenter"
  6903. domClass.toggle(e.currentTarget, e.currentTarget == this.upArrow ? "dijitUpArrowHover" : "dijitDownArrowHover",
  6904. e.type == "mouseenter" || e.type == "mouseover");
  6905. },
  6906. _createOption: function(/*Number*/ index){
  6907. // summary:
  6908. // Creates a clickable time option
  6909. // tags:
  6910. // private
  6911. var date = new Date(this._refDate);
  6912. var incrementDate = this._clickableIncrementDate;
  6913. date.setHours(date.getHours() + incrementDate.getHours() * index,
  6914. date.getMinutes() + incrementDate.getMinutes() * index,
  6915. date.getSeconds() + incrementDate.getSeconds() * index);
  6916. if(this.constraints.selector == "time"){
  6917. date.setFullYear(1970,0,1); // make sure each time is for the same date
  6918. }
  6919. var dateString = locale.format(date, this.constraints);
  6920. if(this.filterString && dateString.toLowerCase().indexOf(this.filterString) !== 0){
  6921. // Doesn't match the filter - return null
  6922. return null;
  6923. }
  6924. var div = domConstruct.create("div", {"class": this.baseClass+"Item"});
  6925. div.date = date;
  6926. div.index = index;
  6927. domConstruct.create('div',{
  6928. "class": this.baseClass + "ItemInner",
  6929. innerHTML: dateString
  6930. }, div);
  6931. if(index%this._visibleIncrement<1 && index%this._visibleIncrement>-1){
  6932. domClass.add(div, this.baseClass+"Marker");
  6933. }else if(!(index%this._clickableIncrement)){
  6934. domClass.add(div, this.baseClass+"Tick");
  6935. }
  6936. if(this.isDisabledDate(date)){
  6937. // set disabled
  6938. domClass.add(div, this.baseClass+"ItemDisabled");
  6939. }
  6940. if(this.value && !ddate.compare(this.value, date, this.constraints.selector)){
  6941. div.selected = true;
  6942. domClass.add(div, this.baseClass+"ItemSelected");
  6943. if(domClass.contains(div, this.baseClass+"Marker")){
  6944. domClass.add(div, this.baseClass+"MarkerSelected");
  6945. }else{
  6946. domClass.add(div, this.baseClass+"TickSelected");
  6947. }
  6948. // Initially highlight the current value. User can change highlight by up/down arrow keys
  6949. // or mouse movement.
  6950. this._highlightOption(div, true);
  6951. }
  6952. return div;
  6953. },
  6954. _onOptionSelected: function(/*Object*/ tgt){
  6955. // summary:
  6956. // Called when user clicks an option in the drop down list
  6957. // tags:
  6958. // private
  6959. var tdate = tgt.target.date || tgt.target.parentNode.date;
  6960. if(!tdate || this.isDisabledDate(tdate)){ return; }
  6961. this._highlighted_option = null;
  6962. this.set('value', tdate);
  6963. this.onChange(tdate);
  6964. },
  6965. onChange: function(/*Date*/ /*===== time =====*/){
  6966. // summary:
  6967. // Notification that a time was selected. It may be the same as the previous value.
  6968. // tags:
  6969. // public
  6970. },
  6971. _highlightOption: function(/*node*/ node, /*Boolean*/ highlight){
  6972. // summary:
  6973. // Turns on/off highlight effect on a node based on mouse out/over event
  6974. // tags:
  6975. // private
  6976. if(!node){return;}
  6977. if(highlight){
  6978. if(this._highlighted_option){
  6979. this._highlightOption(this._highlighted_option, false);
  6980. }
  6981. this._highlighted_option = node;
  6982. }else if(this._highlighted_option !== node){
  6983. return;
  6984. }else{
  6985. this._highlighted_option = null;
  6986. }
  6987. domClass.toggle(node, this.baseClass+"ItemHover", highlight);
  6988. if(domClass.contains(node, this.baseClass+"Marker")){
  6989. domClass.toggle(node, this.baseClass+"MarkerHover", highlight);
  6990. }else{
  6991. domClass.toggle(node, this.baseClass+"TickHover", highlight);
  6992. }
  6993. },
  6994. onmouseover: function(/*Event*/ e){
  6995. // summary:
  6996. // Handler for onmouseover event
  6997. // tags:
  6998. // private
  6999. this._keyboardSelected = null;
  7000. var tgr = (e.target.parentNode === this.timeMenu) ? e.target : e.target.parentNode;
  7001. // if we aren't targeting an item, then we return
  7002. if(!domClass.contains(tgr, this.baseClass+"Item")){return;}
  7003. this._highlightOption(tgr, true);
  7004. },
  7005. onmouseout: function(/*Event*/ e){
  7006. // summary:
  7007. // Handler for onmouseout event
  7008. // tags:
  7009. // private
  7010. this._keyboardSelected = null;
  7011. var tgr = (e.target.parentNode === this.timeMenu) ? e.target : e.target.parentNode;
  7012. this._highlightOption(tgr, false);
  7013. },
  7014. _mouseWheeled: function(/*Event*/ e){
  7015. // summary:
  7016. // Handle the mouse wheel events
  7017. // tags:
  7018. // private
  7019. this._keyboardSelected = null;
  7020. event.stop(e);
  7021. // we're not _measuring_ the scroll amount, just direction
  7022. var scrollAmount = (has("ie") ? e.wheelDelta : -e.detail);
  7023. this[(scrollAmount>0 ? "_onArrowUp" : "_onArrowDown")](); // yes, we're making a new dom node every time you mousewheel, or click
  7024. },
  7025. _onArrowUp: function(count){
  7026. // summary:
  7027. // Handler for up arrow key.
  7028. // description:
  7029. // Removes the bottom time and add one to the top
  7030. // tags:
  7031. // private
  7032. if(typeof count == "number" && count == -1){ return; } // typematic end
  7033. if(!this.timeMenu.childNodes.length){ return; }
  7034. var index = this.timeMenu.childNodes[0].index;
  7035. var divs = this._getFilteredNodes(index, 1, true, this.timeMenu.childNodes[0]);
  7036. if(divs.length){
  7037. this.timeMenu.removeChild(this.timeMenu.childNodes[this.timeMenu.childNodes.length - 1]);
  7038. this.timeMenu.insertBefore(divs[0], this.timeMenu.childNodes[0]);
  7039. }
  7040. },
  7041. _onArrowDown: function(count){
  7042. // summary:
  7043. // Handler for up arrow key.
  7044. // description:
  7045. // Remove the top time and add one to the bottom
  7046. // tags:
  7047. // private
  7048. if(typeof count == "number" && count == -1){ return; } // typematic end
  7049. if(!this.timeMenu.childNodes.length){ return; }
  7050. var index = this.timeMenu.childNodes[this.timeMenu.childNodes.length - 1].index + 1;
  7051. var divs = this._getFilteredNodes(index, 1, false, this.timeMenu.childNodes[this.timeMenu.childNodes.length - 1]);
  7052. if(divs.length){
  7053. this.timeMenu.removeChild(this.timeMenu.childNodes[0]);
  7054. this.timeMenu.appendChild(divs[0]);
  7055. }
  7056. },
  7057. handleKey: function(/*Event*/ e){
  7058. // summary:
  7059. // Called from `dijit.form._DateTimeTextBox` to pass a keypress event
  7060. // from the `dijit.form.TimeTextBox` to be handled in this widget
  7061. // tags:
  7062. // protected
  7063. if(e.keyCode == keys.DOWN_ARROW || e.keyCode == keys.UP_ARROW){
  7064. event.stop(e);
  7065. // Figure out which option to highlight now and then highlight it
  7066. if(this._highlighted_option && !this._highlighted_option.parentNode){
  7067. this._highlighted_option = null;
  7068. }
  7069. var timeMenu = this.timeMenu,
  7070. tgt = this._highlighted_option || query("." + this.baseClass + "ItemSelected", timeMenu)[0];
  7071. if(!tgt){
  7072. tgt = timeMenu.childNodes[0];
  7073. }else if(timeMenu.childNodes.length){
  7074. if(e.keyCode == keys.DOWN_ARROW && !tgt.nextSibling){
  7075. this._onArrowDown();
  7076. }else if(e.keyCode == keys.UP_ARROW && !tgt.previousSibling){
  7077. this._onArrowUp();
  7078. }
  7079. if(e.keyCode == keys.DOWN_ARROW){
  7080. tgt = tgt.nextSibling;
  7081. }else{
  7082. tgt = tgt.previousSibling;
  7083. }
  7084. }
  7085. this._highlightOption(tgt, true);
  7086. this._keyboardSelected = tgt;
  7087. return false;
  7088. }else if(e.keyCode == keys.ENTER || e.keyCode === keys.TAB){
  7089. // mouse hover followed by TAB is NO selection
  7090. if(!this._keyboardSelected && e.keyCode === keys.TAB){
  7091. return true; // true means don't call stopEvent()
  7092. }
  7093. // Accept the currently-highlighted option as the value
  7094. if(this._highlighted_option){
  7095. this._onOptionSelected({target: this._highlighted_option});
  7096. }
  7097. // Call stopEvent() for ENTER key so that form doesn't submit,
  7098. // but not for TAB, so that TAB does switch focus
  7099. return e.keyCode === keys.TAB;
  7100. }
  7101. return undefined;
  7102. }
  7103. });
  7104. });
  7105. },
  7106. 'dijit/form/RadioButton':function(){
  7107. define("dijit/form/RadioButton", [
  7108. "dojo/_base/declare", // declare
  7109. "./CheckBox",
  7110. "./_RadioButtonMixin"
  7111. ], function(declare, CheckBox, _RadioButtonMixin){
  7112. /*=====
  7113. var CheckBox = dijit.form.CheckBox;
  7114. var _RadioButtonMixin = dijit.form._RadioButtonMixin;
  7115. =====*/
  7116. // module:
  7117. // dijit/form/RadioButton
  7118. // summary:
  7119. // Radio button widget
  7120. return declare("dijit.form.RadioButton", [CheckBox, _RadioButtonMixin], {
  7121. // summary:
  7122. // Same as an HTML radio, but with fancy styling.
  7123. baseClass: "dijitRadio"
  7124. });
  7125. });
  7126. },
  7127. 'url:dijit/form/templates/HorizontalSlider.html':"<table class=\"dijit dijitReset dijitSlider dijitSliderH\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" rules=\"none\" data-dojo-attach-event=\"onkeypress:_onKeyPress,onkeyup:_onKeyUp\"\n\trole=\"presentation\"\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t\t><td data-dojo-attach-point=\"topDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationT dijitSliderDecorationH\"></td\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\n\t\t\t><div class=\"dijitSliderDecrementIconH\" style=\"display:none\" data-dojo-attach-point=\"decrementButton\"><span class=\"dijitSliderButtonInner\">-</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderLeftBumper\" data-dojo-attach-event=\"press:_onClkDecBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><input data-dojo-attach-point=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\n\t\t\t/><div class=\"dijitReset dijitSliderBarContainerH\" role=\"presentation\" data-dojo-attach-point=\"sliderBarContainer\"\n\t\t\t\t><div role=\"presentation\" data-dojo-attach-point=\"progressBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderProgressBar dijitSliderProgressBarH\" data-dojo-attach-event=\"press:_onBarClick\"\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableH\"\n\t\t\t\t\t\t><div data-dojo-attach-point=\"sliderHandle,focusNode\" class=\"dijitSliderImageHandle dijitSliderImageHandleH\" data-dojo-attach-event=\"press:_onHandleClick\" role=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"></div\n\t\t\t\t\t></div\n\t\t\t\t></div\n\t\t\t\t><div role=\"presentation\" data-dojo-attach-point=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderRemainingBar dijitSliderRemainingBarH\" data-dojo-attach-event=\"press:_onBarClick\"></div\n\t\t\t></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderRightBumper\" data-dojo-attach-event=\"press:_onClkIncBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\n\t\t\t><div class=\"dijitSliderIncrementIconH\" style=\"display:none\" data-dojo-attach-point=\"incrementButton\"><span class=\"dijitSliderButtonInner\">+</span></div\n\t\t></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t\t><td data-dojo-attach-point=\"containerNode,bottomDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationB dijitSliderDecorationH\"></td\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t></tr\n></table>\n",
  7128. 'url:dijit/templates/TimePicker.html':"<div id=\"widget_${id}\" class=\"dijitMenu\"\n ><div data-dojo-attach-point=\"upArrow\" class=\"dijitButtonNode dijitUpArrowButton\" data-dojo-attach-event=\"onmouseenter:_buttonMouse,onmouseleave:_buttonMouse\"\n\t\t><div class=\"dijitReset dijitInline dijitArrowButtonInner\" role=\"presentation\">&#160;</div\n\t\t><div class=\"dijitArrowButtonChar\">&#9650;</div></div\n ><div data-dojo-attach-point=\"timeMenu,focusNode\" data-dojo-attach-event=\"onclick:_onOptionSelected,onmouseover,onmouseout\"></div\n ><div data-dojo-attach-point=\"downArrow\" class=\"dijitButtonNode dijitDownArrowButton\" data-dojo-attach-event=\"onmouseenter:_buttonMouse,onmouseleave:_buttonMouse\"\n\t\t><div class=\"dijitReset dijitInline dijitArrowButtonInner\" role=\"presentation\">&#160;</div\n\t\t><div class=\"dijitArrowButtonChar\">&#9660;</div></div\n></div>\n",
  7129. 'dijit/InlineEditBox':function(){
  7130. define([
  7131. "dojo/_base/array", // array.forEach
  7132. "dojo/_base/declare", // declare
  7133. "dojo/_base/Deferred", // Deferred.when
  7134. "dojo/dom-attr", // domAttr.set domAttr.get
  7135. "dojo/dom-class", // domClass.add domClass.remove domClass.toggle
  7136. "dojo/dom-construct", // domConstruct.create domConstruct.destroy
  7137. "dojo/dom-style", // domStyle.getComputedStyle domStyle.set domStyle.get
  7138. "dojo/_base/event", // event.stop
  7139. "dojo/i18n", // i18n.getLocalization
  7140. "dojo/_base/kernel", // kernel.deprecated
  7141. "dojo/keys", // keys.ENTER keys.ESCAPE
  7142. "dojo/_base/lang", // lang.getObject
  7143. "dojo/_base/sniff", // has("ie")
  7144. "./focus",
  7145. "./_Widget",
  7146. "./_TemplatedMixin",
  7147. "./_WidgetsInTemplateMixin",
  7148. "./_Container",
  7149. "./form/Button",
  7150. "./form/_TextBoxMixin",
  7151. "./form/TextBox",
  7152. "dojo/text!./templates/InlineEditBox.html",
  7153. "dojo/i18n!./nls/common"
  7154. ], function(array, declare, Deferred, domAttr, domClass, domConstruct, domStyle, event, i18n, kernel, keys, lang, has,
  7155. fm, _Widget, _TemplatedMixin, _WidgetsInTemplateMixin, _Container, Button, _TextBoxMixin, TextBox, template){
  7156. /*=====
  7157. var _Widget = dijit._Widget;
  7158. var _TemplatedMixin = dijit._TemplatedMixin;
  7159. var _WidgetsInTemplateMixin = dijit._WidgetsInTemplateMixin;
  7160. var _Container = dijit._Container;
  7161. var Button = dijit.form.Button;
  7162. var TextBox = dijit.form.TextBox;
  7163. =====*/
  7164. // module:
  7165. // dijit/InlineEditBox
  7166. // summary:
  7167. // An element with in-line edit capabilities
  7168. var InlineEditor = declare("dijit._InlineEditor", [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin], {
  7169. // summary:
  7170. // Internal widget used by InlineEditBox, displayed when in editing mode
  7171. // to display the editor and maybe save/cancel buttons. Calling code should
  7172. // connect to save/cancel methods to detect when editing is finished
  7173. //
  7174. // Has mainly the same parameters as InlineEditBox, plus these values:
  7175. //
  7176. // style: Object
  7177. // Set of CSS attributes of display node, to replicate in editor
  7178. //
  7179. // value: String
  7180. // Value as an HTML string or plain text string, depending on renderAsHTML flag
  7181. templateString: template,
  7182. postMixInProperties: function(){
  7183. this.inherited(arguments);
  7184. this.messages = i18n.getLocalization("dijit", "common", this.lang);
  7185. array.forEach(["buttonSave", "buttonCancel"], function(prop){
  7186. if(!this[prop]){ this[prop] = this.messages[prop]; }
  7187. }, this);
  7188. },
  7189. buildRendering: function(){
  7190. this.inherited(arguments);
  7191. // Create edit widget in place in the template
  7192. var cls = typeof this.editor == "string" ? lang.getObject(this.editor) : this.editor;
  7193. // Copy the style from the source
  7194. // Don't copy ALL properties though, just the necessary/applicable ones.
  7195. // wrapperStyle/destStyle code is to workaround IE bug where getComputedStyle().fontSize
  7196. // is a relative value like 200%, rather than an absolute value like 24px, and
  7197. // the 200% can refer *either* to a setting on the node or it's ancestor (see #11175)
  7198. var srcStyle = this.sourceStyle,
  7199. editStyle = "line-height:" + srcStyle.lineHeight + ";",
  7200. destStyle = domStyle.getComputedStyle(this.domNode);
  7201. array.forEach(["Weight","Family","Size","Style"], function(prop){
  7202. var textStyle = srcStyle["font"+prop],
  7203. wrapperStyle = destStyle["font"+prop];
  7204. if(wrapperStyle != textStyle){
  7205. editStyle += "font-"+prop+":"+srcStyle["font"+prop]+";";
  7206. }
  7207. }, this);
  7208. array.forEach(["marginTop","marginBottom","marginLeft", "marginRight"], function(prop){
  7209. this.domNode.style[prop] = srcStyle[prop];
  7210. }, this);
  7211. var width = this.inlineEditBox.width;
  7212. if(width == "100%"){
  7213. // block mode
  7214. editStyle += "width:100%;";
  7215. this.domNode.style.display = "block";
  7216. }else{
  7217. // inline-block mode
  7218. editStyle += "width:" + (width + (Number(width) == width ? "px" : "")) + ";";
  7219. }
  7220. var editorParams = lang.delegate(this.inlineEditBox.editorParams, {
  7221. style: editStyle,
  7222. dir: this.dir,
  7223. lang: this.lang,
  7224. textDir: this.textDir
  7225. });
  7226. editorParams[ "displayedValue" in cls.prototype ? "displayedValue" : "value"] = this.value;
  7227. this.editWidget = new cls(editorParams, this.editorPlaceholder);
  7228. if(this.inlineEditBox.autoSave){
  7229. // Remove the save/cancel buttons since saving is done by simply tabbing away or
  7230. // selecting a value from the drop down list
  7231. domConstruct.destroy(this.buttonContainer);
  7232. }
  7233. },
  7234. postCreate: function(){
  7235. this.inherited(arguments);
  7236. var ew = this.editWidget;
  7237. if(this.inlineEditBox.autoSave){
  7238. // Selecting a value from a drop down list causes an onChange event and then we save
  7239. this.connect(ew, "onChange", "_onChange");
  7240. // ESC and TAB should cancel and save. Note that edit widgets do a stopEvent() on ESC key (to
  7241. // prevent Dialog from closing when the user just wants to revert the value in the edit widget),
  7242. // so this is the only way we can see the key press event.
  7243. this.connect(ew, "onKeyPress", "_onKeyPress");
  7244. }else{
  7245. // If possible, enable/disable save button based on whether the user has changed the value
  7246. if("intermediateChanges" in ew){
  7247. ew.set("intermediateChanges", true);
  7248. this.connect(ew, "onChange", "_onIntermediateChange");
  7249. this.saveButton.set("disabled", true);
  7250. }
  7251. }
  7252. },
  7253. _onIntermediateChange: function(/*===== val =====*/){
  7254. // summary:
  7255. // Called for editor widgets that support the intermediateChanges=true flag as a way
  7256. // to detect when to enable/disabled the save button
  7257. this.saveButton.set("disabled", (this.getValue() == this._resetValue) || !this.enableSave());
  7258. },
  7259. destroy: function(){
  7260. this.editWidget.destroy(true); // let the parent wrapper widget clean up the DOM
  7261. this.inherited(arguments);
  7262. },
  7263. getValue: function(){
  7264. // summary:
  7265. // Return the [display] value of the edit widget
  7266. var ew = this.editWidget;
  7267. return String(ew.get("displayedValue" in ew ? "displayedValue" : "value"));
  7268. },
  7269. _onKeyPress: function(e){
  7270. // summary:
  7271. // Handler for keypress in the edit box in autoSave mode.
  7272. // description:
  7273. // For autoSave widgets, if Esc/Enter, call cancel/save.
  7274. // tags:
  7275. // private
  7276. if(this.inlineEditBox.autoSave && this.inlineEditBox.editing){
  7277. if(e.altKey || e.ctrlKey){ return; }
  7278. // If Enter/Esc pressed, treat as save/cancel.
  7279. if(e.charOrCode == keys.ESCAPE){
  7280. event.stop(e);
  7281. this.cancel(true); // sets editing=false which short-circuits _onBlur processing
  7282. }else if(e.charOrCode == keys.ENTER && e.target.tagName == "INPUT"){
  7283. event.stop(e);
  7284. this._onChange(); // fire _onBlur and then save
  7285. }
  7286. // _onBlur will handle TAB automatically by allowing
  7287. // the TAB to change focus before we mess with the DOM: #6227
  7288. // Expounding by request:
  7289. // The current focus is on the edit widget input field.
  7290. // save() will hide and destroy this widget.
  7291. // We want the focus to jump from the currently hidden
  7292. // displayNode, but since it's hidden, it's impossible to
  7293. // unhide it, focus it, and then have the browser focus
  7294. // away from it to the next focusable element since each
  7295. // of these events is asynchronous and the focus-to-next-element
  7296. // is already queued.
  7297. // So we allow the browser time to unqueue the move-focus event
  7298. // before we do all the hide/show stuff.
  7299. }
  7300. },
  7301. _onBlur: function(){
  7302. // summary:
  7303. // Called when focus moves outside the editor
  7304. // tags:
  7305. // private
  7306. this.inherited(arguments);
  7307. if(this.inlineEditBox.autoSave && this.inlineEditBox.editing){
  7308. if(this.getValue() == this._resetValue){
  7309. this.cancel(false);
  7310. }else if(this.enableSave()){
  7311. this.save(false);
  7312. }
  7313. }
  7314. },
  7315. _onChange: function(){
  7316. // summary:
  7317. // Called when the underlying widget fires an onChange event,
  7318. // such as when the user selects a value from the drop down list of a ComboBox,
  7319. // which means that the user has finished entering the value and we should save.
  7320. // tags:
  7321. // private
  7322. if(this.inlineEditBox.autoSave && this.inlineEditBox.editing && this.enableSave()){
  7323. fm.focus(this.inlineEditBox.displayNode); // fires _onBlur which will save the formatted value
  7324. }
  7325. },
  7326. enableSave: function(){
  7327. // summary:
  7328. // User overridable function returning a Boolean to indicate
  7329. // if the Save button should be enabled or not - usually due to invalid conditions
  7330. // tags:
  7331. // extension
  7332. return (
  7333. this.editWidget.isValid
  7334. ? this.editWidget.isValid()
  7335. : true
  7336. );
  7337. },
  7338. focus: function(){
  7339. // summary:
  7340. // Focus the edit widget.
  7341. // tags:
  7342. // protected
  7343. this.editWidget.focus();
  7344. setTimeout(lang.hitch(this, function(){
  7345. if(this.editWidget.focusNode && this.editWidget.focusNode.tagName == "INPUT"){
  7346. _TextBoxMixin.selectInputText(this.editWidget.focusNode);
  7347. }
  7348. }), 0);
  7349. }
  7350. });
  7351. var InlineEditBox = declare("dijit.InlineEditBox", _Widget, {
  7352. // summary:
  7353. // An element with in-line edit capabilities
  7354. //
  7355. // description:
  7356. // Behavior for an existing node (`<p>`, `<div>`, `<span>`, etc.) so that
  7357. // when you click it, an editor shows up in place of the original
  7358. // text. Optionally, Save and Cancel button are displayed below the edit widget.
  7359. // When Save is clicked, the text is pulled from the edit
  7360. // widget and redisplayed and the edit widget is again hidden.
  7361. // By default a plain Textarea widget is used as the editor (or for
  7362. // inline values a TextBox), but you can specify an editor such as
  7363. // dijit.Editor (for editing HTML) or a Slider (for adjusting a number).
  7364. // An edit widget must support the following API to be used:
  7365. // - displayedValue or value as initialization parameter,
  7366. // and available through set('displayedValue') / set('value')
  7367. // - void focus()
  7368. // - DOM-node focusNode = node containing editable text
  7369. // editing: [readonly] Boolean
  7370. // Is the node currently in edit mode?
  7371. editing: false,
  7372. // autoSave: Boolean
  7373. // Changing the value automatically saves it; don't have to push save button
  7374. // (and save button isn't even displayed)
  7375. autoSave: true,
  7376. // buttonSave: String
  7377. // Save button label
  7378. buttonSave: "",
  7379. // buttonCancel: String
  7380. // Cancel button label
  7381. buttonCancel: "",
  7382. // renderAsHtml: Boolean
  7383. // Set this to true if the specified Editor's value should be interpreted as HTML
  7384. // rather than plain text (ex: `dijit.Editor`)
  7385. renderAsHtml: false,
  7386. // editor: String|Function
  7387. // Class name (or reference to the Class) for Editor widget
  7388. editor: TextBox,
  7389. // editorWrapper: String|Function
  7390. // Class name (or reference to the Class) for widget that wraps the editor widget, displaying save/cancel
  7391. // buttons.
  7392. editorWrapper: InlineEditor,
  7393. // editorParams: Object
  7394. // Set of parameters for editor, like {required: true}
  7395. editorParams: {},
  7396. // disabled: Boolean
  7397. // If true, clicking the InlineEditBox to edit it will have no effect.
  7398. disabled: false,
  7399. onChange: function(/*===== value =====*/){
  7400. // summary:
  7401. // Set this handler to be notified of changes to value.
  7402. // tags:
  7403. // callback
  7404. },
  7405. onCancel: function(){
  7406. // summary:
  7407. // Set this handler to be notified when editing is cancelled.
  7408. // tags:
  7409. // callback
  7410. },
  7411. // width: String
  7412. // Width of editor. By default it's width=100% (ie, block mode).
  7413. width: "100%",
  7414. // value: String
  7415. // The display value of the widget in read-only mode
  7416. value: "",
  7417. // noValueIndicator: [const] String
  7418. // The text that gets displayed when there is no value (so that the user has a place to click to edit)
  7419. noValueIndicator: has("ie") <= 6 ? // font-family needed on IE6 but it messes up IE8
  7420. "<span style='font-family: wingdings; text-decoration: underline;'>&#160;&#160;&#160;&#160;&#x270d;&#160;&#160;&#160;&#160;</span>" :
  7421. "<span style='text-decoration: underline;'>&#160;&#160;&#160;&#160;&#x270d;&#160;&#160;&#160;&#160;</span>", // // &#160; == &nbsp;
  7422. constructor: function(){
  7423. // summary:
  7424. // Sets up private arrays etc.
  7425. // tags:
  7426. // private
  7427. this.editorParams = {};
  7428. },
  7429. postMixInProperties: function(){
  7430. this.inherited(arguments);
  7431. // save pointer to original source node, since Widget nulls-out srcNodeRef
  7432. this.displayNode = this.srcNodeRef;
  7433. // connect handlers to the display node
  7434. var events = {
  7435. ondijitclick: "_onClick",
  7436. onmouseover: "_onMouseOver",
  7437. onmouseout: "_onMouseOut",
  7438. onfocus: "_onMouseOver",
  7439. onblur: "_onMouseOut"
  7440. };
  7441. for(var name in events){
  7442. this.connect(this.displayNode, name, events[name]);
  7443. }
  7444. this.displayNode.setAttribute("role", "button");
  7445. if(!this.displayNode.getAttribute("tabIndex")){
  7446. this.displayNode.setAttribute("tabIndex", 0);
  7447. }
  7448. if(!this.value && !("value" in this.params)){ // "" is a good value if specified directly so check params){
  7449. this.value = lang.trim(this.renderAsHtml ? this.displayNode.innerHTML :
  7450. (this.displayNode.innerText||this.displayNode.textContent||""));
  7451. }
  7452. if(!this.value){
  7453. this.displayNode.innerHTML = this.noValueIndicator;
  7454. }
  7455. domClass.add(this.displayNode, 'dijitInlineEditBoxDisplayMode');
  7456. },
  7457. setDisabled: function(/*Boolean*/ disabled){
  7458. // summary:
  7459. // Deprecated. Use set('disabled', ...) instead.
  7460. // tags:
  7461. // deprecated
  7462. kernel.deprecated("dijit.InlineEditBox.setDisabled() is deprecated. Use set('disabled', bool) instead.", "", "2.0");
  7463. this.set('disabled', disabled);
  7464. },
  7465. _setDisabledAttr: function(/*Boolean*/ disabled){
  7466. // summary:
  7467. // Hook to make set("disabled", ...) work.
  7468. // Set disabled state of widget.
  7469. this.domNode.setAttribute("aria-disabled", disabled);
  7470. if(disabled){
  7471. this.displayNode.removeAttribute("tabIndex");
  7472. }else{
  7473. this.displayNode.setAttribute("tabIndex", 0);
  7474. }
  7475. domClass.toggle(this.displayNode, "dijitInlineEditBoxDisplayModeDisabled", disabled);
  7476. this._set("disabled", disabled);
  7477. },
  7478. _onMouseOver: function(){
  7479. // summary:
  7480. // Handler for onmouseover and onfocus event.
  7481. // tags:
  7482. // private
  7483. if(!this.disabled){
  7484. domClass.add(this.displayNode, "dijitInlineEditBoxDisplayModeHover");
  7485. }
  7486. },
  7487. _onMouseOut: function(){
  7488. // summary:
  7489. // Handler for onmouseout and onblur event.
  7490. // tags:
  7491. // private
  7492. domClass.remove(this.displayNode, "dijitInlineEditBoxDisplayModeHover");
  7493. },
  7494. _onClick: function(/*Event*/ e){
  7495. // summary:
  7496. // Handler for onclick event.
  7497. // tags:
  7498. // private
  7499. if(this.disabled){ return; }
  7500. if(e){ event.stop(e); }
  7501. this._onMouseOut();
  7502. // Since FF gets upset if you move a node while in an event handler for that node...
  7503. setTimeout(lang.hitch(this, "edit"), 0);
  7504. },
  7505. edit: function(){
  7506. // summary:
  7507. // Display the editor widget in place of the original (read only) markup.
  7508. // tags:
  7509. // private
  7510. if(this.disabled || this.editing){ return; }
  7511. this._set('editing', true);
  7512. // save some display node values that can be restored later
  7513. this._savedPosition = domStyle.get(this.displayNode, "position") || "static";
  7514. this._savedOpacity = domStyle.get(this.displayNode, "opacity") || "1";
  7515. this._savedTabIndex = domAttr.get(this.displayNode, "tabIndex") || "0";
  7516. if(this.wrapperWidget){
  7517. var ew = this.wrapperWidget.editWidget;
  7518. ew.set("displayedValue" in ew ? "displayedValue" : "value", this.value);
  7519. }else{
  7520. // Placeholder for edit widget
  7521. // Put place holder (and eventually editWidget) before the display node so that it's positioned correctly
  7522. // when Calendar dropdown appears, which happens automatically on focus.
  7523. var placeholder = domConstruct.create("span", null, this.domNode, "before");
  7524. // Create the editor wrapper (the thing that holds the editor widget and the save/cancel buttons)
  7525. var ewc = typeof this.editorWrapper == "string" ? lang.getObject(this.editorWrapper) : this.editorWrapper;
  7526. this.wrapperWidget = new ewc({
  7527. value: this.value,
  7528. buttonSave: this.buttonSave,
  7529. buttonCancel: this.buttonCancel,
  7530. dir: this.dir,
  7531. lang: this.lang,
  7532. tabIndex: this._savedTabIndex,
  7533. editor: this.editor,
  7534. inlineEditBox: this,
  7535. sourceStyle: domStyle.getComputedStyle(this.displayNode),
  7536. save: lang.hitch(this, "save"),
  7537. cancel: lang.hitch(this, "cancel"),
  7538. textDir: this.textDir
  7539. }, placeholder);
  7540. if(!this._started){
  7541. this.startup();
  7542. }
  7543. }
  7544. var ww = this.wrapperWidget;
  7545. // to avoid screen jitter, we first create the editor with position:absolute, visibility:hidden,
  7546. // and then when it's finished rendering, we switch from display mode to editor
  7547. // position:absolute releases screen space allocated to the display node
  7548. // opacity:0 is the same as visibility:hidden but is still focusable
  7549. // visibility:hidden removes focus outline
  7550. domStyle.set(this.displayNode, { position: "absolute", opacity: "0" }); // makes display node invisible, display style used for focus-ability
  7551. domStyle.set(ww.domNode, { position: this._savedPosition, visibility: "visible", opacity: "1" });
  7552. domAttr.set(this.displayNode, "tabIndex", "-1"); // needed by WebKit for TAB from editor to skip displayNode
  7553. // After edit widget has finished initializing (in particular need to wait for dijit.Editor),
  7554. // or immediately if there is no onLoadDeferred Deferred,
  7555. // replace the display widget with edit widget, leaving them both displayed for a brief time so that
  7556. // focus can be shifted without incident.
  7557. Deferred.when(ww.editWidget.onLoadDeferred, function(){
  7558. // Note: not sure if we still need a setTimeout() now that there's a Deferred.when()
  7559. setTimeout(function(){
  7560. ww.focus(); // both nodes are showing, so we can switch focus safely
  7561. ww._resetValue = ww.getValue();
  7562. }, 0);
  7563. });
  7564. },
  7565. _onBlur: function(){
  7566. // summary:
  7567. // Called when focus moves outside the InlineEditBox.
  7568. // Performs garbage collection.
  7569. // tags:
  7570. // private
  7571. this.inherited(arguments);
  7572. if(!this.editing){
  7573. /* causes IE focus problems, see TooltipDialog_a11y.html...
  7574. setTimeout(lang.hitch(this, function(){
  7575. if(this.wrapperWidget){
  7576. this.wrapperWidget.destroy();
  7577. delete this.wrapperWidget;
  7578. }
  7579. }), 0);
  7580. */
  7581. }
  7582. },
  7583. destroy: function(){
  7584. if(this.wrapperWidget && !this.wrapperWidget._destroyed){
  7585. this.wrapperWidget.destroy();
  7586. delete this.wrapperWidget;
  7587. }
  7588. this.inherited(arguments);
  7589. },
  7590. _showText: function(/*Boolean*/ focus){
  7591. // summary:
  7592. // Revert to display mode, and optionally focus on display node
  7593. // tags:
  7594. // private
  7595. var ww = this.wrapperWidget;
  7596. domStyle.set(ww.domNode, { position: "absolute", visibility: "hidden", opacity: "0" }); // hide the editor from mouse/keyboard events
  7597. domStyle.set(this.displayNode, { position: this._savedPosition, opacity: this._savedOpacity }); // make the original text visible
  7598. domAttr.set(this.displayNode, "tabIndex", this._savedTabIndex);
  7599. if(focus){
  7600. fm.focus(this.displayNode);
  7601. }
  7602. },
  7603. save: function(/*Boolean*/ focus){
  7604. // summary:
  7605. // Save the contents of the editor and revert to display mode.
  7606. // focus: Boolean
  7607. // Focus on the display mode text
  7608. // tags:
  7609. // private
  7610. if(this.disabled || !this.editing){ return; }
  7611. this._set('editing', false);
  7612. var ww = this.wrapperWidget;
  7613. var value = ww.getValue();
  7614. this.set('value', value); // display changed, formatted value
  7615. this._showText(focus); // set focus as needed
  7616. },
  7617. setValue: function(/*String*/ val){
  7618. // summary:
  7619. // Deprecated. Use set('value', ...) instead.
  7620. // tags:
  7621. // deprecated
  7622. kernel.deprecated("dijit.InlineEditBox.setValue() is deprecated. Use set('value', ...) instead.", "", "2.0");
  7623. return this.set("value", val);
  7624. },
  7625. _setValueAttr: function(/*String*/ val){
  7626. // summary:
  7627. // Hook to make set("value", ...) work.
  7628. // Inserts specified HTML value into this node, or an "input needed" character if node is blank.
  7629. val = lang.trim(val);
  7630. var renderVal = this.renderAsHtml ? val : val.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;").replace(/\n/g, "<br>");
  7631. this.displayNode.innerHTML = renderVal || this.noValueIndicator;
  7632. this._set("value", val);
  7633. if(this._started){
  7634. // tell the world that we have changed
  7635. setTimeout(lang.hitch(this, "onChange", val), 0); // setTimeout prevents browser freeze for long-running event handlers
  7636. }
  7637. // contextual (auto) text direction depends on the text value
  7638. if(this.textDir == "auto"){
  7639. this.applyTextDir(this.displayNode, this.displayNode.innerText);
  7640. }
  7641. },
  7642. getValue: function(){
  7643. // summary:
  7644. // Deprecated. Use get('value') instead.
  7645. // tags:
  7646. // deprecated
  7647. kernel.deprecated("dijit.InlineEditBox.getValue() is deprecated. Use get('value') instead.", "", "2.0");
  7648. return this.get("value");
  7649. },
  7650. cancel: function(/*Boolean*/ focus){
  7651. // summary:
  7652. // Revert to display mode, discarding any changes made in the editor
  7653. // tags:
  7654. // private
  7655. if(this.disabled || !this.editing){ return; }
  7656. this._set('editing', false);
  7657. // tell the world that we have no changes
  7658. setTimeout(lang.hitch(this, "onCancel"), 0); // setTimeout prevents browser freeze for long-running event handlers
  7659. this._showText(focus);
  7660. },
  7661. _setTextDirAttr: function(/*String*/ textDir){
  7662. // summary:
  7663. // Setter for textDir.
  7664. // description:
  7665. // Users shouldn't call this function; they should be calling
  7666. // set('textDir', value)
  7667. // tags:
  7668. // private
  7669. if(!this._created || this.textDir != textDir){
  7670. this._set("textDir", textDir);
  7671. this.applyTextDir(this.displayNode, this.displayNode.innerText);
  7672. this.displayNode.align = this.dir == "rtl" ? "right" : "left"; //fix the text alignment
  7673. }
  7674. }
  7675. });
  7676. InlineEditBox._InlineEditor = InlineEditor; // for monkey patching
  7677. return InlineEditBox;
  7678. });
  7679. },
  7680. 'dojo/dnd/autoscroll':function(){
  7681. define(["../main", "../window"], function(dojo) {
  7682. // module:
  7683. // dojo/dnd/autoscroll
  7684. // summary:
  7685. // TODOC
  7686. dojo.getObject("dnd", true, dojo);
  7687. dojo.dnd.getViewport = dojo.window.getBox;
  7688. dojo.dnd.V_TRIGGER_AUTOSCROLL = 32;
  7689. dojo.dnd.H_TRIGGER_AUTOSCROLL = 32;
  7690. dojo.dnd.V_AUTOSCROLL_VALUE = 16;
  7691. dojo.dnd.H_AUTOSCROLL_VALUE = 16;
  7692. dojo.dnd.autoScroll = function(e){
  7693. // summary:
  7694. // a handler for onmousemove event, which scrolls the window, if
  7695. // necesary
  7696. // e: Event
  7697. // onmousemove event
  7698. // FIXME: needs more docs!
  7699. var v = dojo.window.getBox(), dx = 0, dy = 0;
  7700. if(e.clientX < dojo.dnd.H_TRIGGER_AUTOSCROLL){
  7701. dx = -dojo.dnd.H_AUTOSCROLL_VALUE;
  7702. }else if(e.clientX > v.w - dojo.dnd.H_TRIGGER_AUTOSCROLL){
  7703. dx = dojo.dnd.H_AUTOSCROLL_VALUE;
  7704. }
  7705. if(e.clientY < dojo.dnd.V_TRIGGER_AUTOSCROLL){
  7706. dy = -dojo.dnd.V_AUTOSCROLL_VALUE;
  7707. }else if(e.clientY > v.h - dojo.dnd.V_TRIGGER_AUTOSCROLL){
  7708. dy = dojo.dnd.V_AUTOSCROLL_VALUE;
  7709. }
  7710. window.scrollBy(dx, dy);
  7711. };
  7712. dojo.dnd._validNodes = {"div": 1, "p": 1, "td": 1};
  7713. dojo.dnd._validOverflow = {"auto": 1, "scroll": 1};
  7714. dojo.dnd.autoScrollNodes = function(e){
  7715. // summary:
  7716. // a handler for onmousemove event, which scrolls the first avaialble
  7717. // Dom element, it falls back to dojo.dnd.autoScroll()
  7718. // e: Event
  7719. // onmousemove event
  7720. // FIXME: needs more docs!
  7721. var b, t, w, h, rx, ry, dx = 0, dy = 0, oldLeft, oldTop;
  7722. for(var n = e.target; n;){
  7723. if(n.nodeType == 1 && (n.tagName.toLowerCase() in dojo.dnd._validNodes)){
  7724. var s = dojo.getComputedStyle(n),
  7725. overflow = (s.overflow.toLowerCase() in dojo.dnd._validOverflow),
  7726. overflowX = (s.overflowX.toLowerCase() in dojo.dnd._validOverflow),
  7727. overflowY = (s.overflowY.toLowerCase() in dojo.dnd._validOverflow);
  7728. if(overflow || overflowX || overflowY){
  7729. b = dojo._getContentBox(n, s);
  7730. t = dojo.position(n, true);
  7731. }
  7732. // overflow-x
  7733. if(overflow || overflowX){
  7734. w = Math.min(dojo.dnd.H_TRIGGER_AUTOSCROLL, b.w / 2);
  7735. rx = e.pageX - t.x;
  7736. if(dojo.isWebKit || dojo.isOpera){
  7737. // FIXME: this code should not be here, it should be taken into account
  7738. // either by the event fixing code, or the dojo.position()
  7739. // FIXME: this code doesn't work on Opera 9.5 Beta
  7740. rx += dojo.body().scrollLeft;
  7741. }
  7742. dx = 0;
  7743. if(rx > 0 && rx < b.w){
  7744. if(rx < w){
  7745. dx = -w;
  7746. }else if(rx > b.w - w){
  7747. dx = w;
  7748. }
  7749. oldLeft = n.scrollLeft;
  7750. n.scrollLeft = n.scrollLeft + dx;
  7751. }
  7752. }
  7753. // overflow-y
  7754. if(overflow || overflowY){
  7755. //console.log(b.l, b.t, t.x, t.y, n.scrollLeft, n.scrollTop);
  7756. h = Math.min(dojo.dnd.V_TRIGGER_AUTOSCROLL, b.h / 2);
  7757. ry = e.pageY - t.y;
  7758. if(dojo.isWebKit || dojo.isOpera){
  7759. // FIXME: this code should not be here, it should be taken into account
  7760. // either by the event fixing code, or the dojo.position()
  7761. // FIXME: this code doesn't work on Opera 9.5 Beta
  7762. ry += dojo.body().scrollTop;
  7763. }
  7764. dy = 0;
  7765. if(ry > 0 && ry < b.h){
  7766. if(ry < h){
  7767. dy = -h;
  7768. }else if(ry > b.h - h){
  7769. dy = h;
  7770. }
  7771. oldTop = n.scrollTop;
  7772. n.scrollTop = n.scrollTop + dy;
  7773. }
  7774. }
  7775. if(dx || dy){ return; }
  7776. }
  7777. try{
  7778. n = n.parentNode;
  7779. }catch(x){
  7780. n = null;
  7781. }
  7782. }
  7783. dojo.dnd.autoScroll(e);
  7784. };
  7785. return dojo.dnd;
  7786. });
  7787. },
  7788. 'dijit/form/_RadioButtonMixin':function(){
  7789. define([
  7790. "dojo/_base/array", // array.forEach
  7791. "dojo/_base/declare", // declare
  7792. "dojo/dom-attr", // domAttr.set
  7793. "dojo/_base/event", // event.stop
  7794. "dojo/_base/lang", // lang.hitch
  7795. "dojo/query", // query
  7796. "dojo/_base/window", // win.doc
  7797. "../registry" // registry.getEnclosingWidget
  7798. ], function(array, declare, domAttr, event, lang, query, win, registry){
  7799. // module:
  7800. // dijit/form/_RadioButtonMixin
  7801. // summary:
  7802. // Mixin to provide widget functionality for an HTML radio button
  7803. return declare("dijit.form._RadioButtonMixin", null, {
  7804. // summary:
  7805. // Mixin to provide widget functionality for an HTML radio button
  7806. // type: [private] String
  7807. // type attribute on <input> node.
  7808. // Users should not change this value.
  7809. type: "radio",
  7810. _getRelatedWidgets: function(){
  7811. // Private function needed to help iterate over all radio buttons in a group.
  7812. var ary = [];
  7813. query("input[type=radio]", this.focusNode.form || win.doc).forEach( // can't use name= since query doesn't support [] in the name
  7814. lang.hitch(this, function(inputNode){
  7815. if(inputNode.name == this.name && inputNode.form == this.focusNode.form){
  7816. var widget = registry.getEnclosingWidget(inputNode);
  7817. if(widget){
  7818. ary.push(widget);
  7819. }
  7820. }
  7821. })
  7822. );
  7823. return ary;
  7824. },
  7825. _setCheckedAttr: function(/*Boolean*/ value){
  7826. // If I am being checked then have to deselect currently checked radio button
  7827. this.inherited(arguments);
  7828. if(!this._created){ return; }
  7829. if(value){
  7830. array.forEach(this._getRelatedWidgets(), lang.hitch(this, function(widget){
  7831. if(widget != this && widget.checked){
  7832. widget.set('checked', false);
  7833. }
  7834. }));
  7835. }
  7836. },
  7837. _onClick: function(/*Event*/ e){
  7838. if(this.checked || this.disabled){ // nothing to do
  7839. event.stop(e);
  7840. return false;
  7841. }
  7842. if(this.readOnly){ // ignored by some browsers so we have to resync the DOM elements with widget values
  7843. event.stop(e);
  7844. array.forEach(this._getRelatedWidgets(), lang.hitch(this, function(widget){
  7845. domAttr.set(this.focusNode || this.domNode, 'checked', widget.checked);
  7846. }));
  7847. return false;
  7848. }
  7849. return this.inherited(arguments);
  7850. }
  7851. });
  7852. });
  7853. },
  7854. 'url:dijit/templates/TreeNode.html':"<div class=\"dijitTreeNode\" role=\"presentation\"\n\t><div data-dojo-attach-point=\"rowNode\" class=\"dijitTreeRow\" role=\"presentation\" data-dojo-attach-event=\"onmouseenter:_onMouseEnter, onmouseleave:_onMouseLeave, onclick:_onClick, ondblclick:_onDblClick\"\n\t\t><img src=\"${_blankGif}\" alt=\"\" data-dojo-attach-point=\"expandoNode\" class=\"dijitTreeExpando\" role=\"presentation\"\n\t\t/><span data-dojo-attach-point=\"expandoNodeText\" class=\"dijitExpandoText\" role=\"presentation\"\n\t\t></span\n\t\t><span data-dojo-attach-point=\"contentNode\"\n\t\t\tclass=\"dijitTreeContent\" role=\"presentation\">\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" data-dojo-attach-point=\"iconNode\" class=\"dijitIcon dijitTreeIcon\" role=\"presentation\"\n\t\t\t/><span data-dojo-attach-point=\"labelNode\" class=\"dijitTreeLabel\" role=\"treeitem\" tabindex=\"-1\" aria-selected=\"false\" data-dojo-attach-event=\"onfocus:_onLabelFocus\"></span>\n\t\t</span\n\t></div>\n\t<div data-dojo-attach-point=\"containerNode\" class=\"dijitTreeContainer\" role=\"presentation\" style=\"display: none;\"></div>\n</div>\n",
  7855. 'dojo/dnd/TimedMoveable':function(){
  7856. define(["../main", "./Moveable"], function(dojo) {
  7857. // module:
  7858. // dojo/dnd/TimedMoveable
  7859. // summary:
  7860. // TODOC
  7861. /*=====
  7862. dojo.declare("dojo.dnd.__TimedMoveableArgs", [dojo.dnd.__MoveableArgs], {
  7863. // timeout: Number
  7864. // delay move by this number of ms,
  7865. // accumulating position changes during the timeout
  7866. timeout: 0
  7867. });
  7868. =====*/
  7869. // precalculate long expressions
  7870. var oldOnMove = dojo.dnd.Moveable.prototype.onMove;
  7871. dojo.declare("dojo.dnd.TimedMoveable", dojo.dnd.Moveable, {
  7872. // summary:
  7873. // A specialized version of Moveable to support an FPS throttling.
  7874. // This class puts an upper restriction on FPS, which may reduce
  7875. // the CPU load. The additional parameter "timeout" regulates
  7876. // the delay before actually moving the moveable object.
  7877. // object attributes (for markup)
  7878. timeout: 40, // in ms, 40ms corresponds to 25 fps
  7879. constructor: function(node, params){
  7880. // summary:
  7881. // an object that makes a node moveable with a timer
  7882. // node: Node||String
  7883. // a node (or node's id) to be moved
  7884. // params: dojo.dnd.__TimedMoveableArgs
  7885. // object with additional parameters.
  7886. // sanitize parameters
  7887. if(!params){ params = {}; }
  7888. if(params.timeout && typeof params.timeout == "number" && params.timeout >= 0){
  7889. this.timeout = params.timeout;
  7890. }
  7891. },
  7892. onMoveStop: function(/* dojo.dnd.Mover */ mover){
  7893. if(mover._timer){
  7894. // stop timer
  7895. clearTimeout(mover._timer);
  7896. // reflect the last received position
  7897. oldOnMove.call(this, mover, mover._leftTop)
  7898. }
  7899. dojo.dnd.Moveable.prototype.onMoveStop.apply(this, arguments);
  7900. },
  7901. onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
  7902. mover._leftTop = leftTop;
  7903. if(!mover._timer){
  7904. var _t = this; // to avoid using dojo.hitch()
  7905. mover._timer = setTimeout(function(){
  7906. // we don't have any pending requests
  7907. mover._timer = null;
  7908. // reflect the last received position
  7909. oldOnMove.call(_t, mover, mover._leftTop);
  7910. }, this.timeout);
  7911. }
  7912. }
  7913. });
  7914. return dojo.dnd.TimedMoveable;
  7915. });
  7916. },
  7917. 'dijit/layout/LinkPane':function(){
  7918. define([
  7919. "./ContentPane",
  7920. "../_TemplatedMixin",
  7921. "dojo/_base/declare" // declare
  7922. ], function(ContentPane, _TemplatedMixin, declare){
  7923. /*=====
  7924. var _TemplatedMixin = dijit._TemplatedMixin;
  7925. var ContentPane = dijit.layout.ContentPane;
  7926. =====*/
  7927. // module:
  7928. // dijit/layout/LinkPane
  7929. // summary:
  7930. // A ContentPane with an href where (when declared in markup)
  7931. // the title is specified as innerHTML rather than as a title attribute.
  7932. return declare("dijit.layout.LinkPane", [ContentPane, _TemplatedMixin], {
  7933. // summary:
  7934. // A ContentPane with an href where (when declared in markup)
  7935. // the title is specified as innerHTML rather than as a title attribute.
  7936. // description:
  7937. // LinkPane is just a ContentPane that is declared in markup similarly
  7938. // to an anchor. The anchor's body (the words between `<a>` and `</a>`)
  7939. // become the title of the widget (used for TabContainer, AccordionContainer, etc.)
  7940. // example:
  7941. // | <a href="foo.html">my title</a>
  7942. // I'm using a template because the user may specify the input as
  7943. // <a href="foo.html">title</a>, in which case we need to get rid of the
  7944. // <a> because we don't want a link.
  7945. templateString: '<div class="dijitLinkPane" data-dojo-attach-point="containerNode"></div>',
  7946. postMixInProperties: function(){
  7947. // If user has specified node contents, they become the title
  7948. // (the link must be plain text)
  7949. if(this.srcNodeRef){
  7950. this.title += this.srcNodeRef.innerHTML;
  7951. }
  7952. this.inherited(arguments);
  7953. },
  7954. _fillContent: function(){
  7955. // Overrides _Templated._fillContent().
  7956. // _Templated._fillContent() relocates srcNodeRef innerHTML to templated container node,
  7957. // but in our case the srcNodeRef innerHTML is the title, so shouldn't be
  7958. // copied
  7959. }
  7960. });
  7961. });
  7962. },
  7963. 'dijit/form/_ListMouseMixin':function(){
  7964. define([
  7965. "dojo/_base/declare", // declare
  7966. "dojo/_base/event", // event.stop
  7967. "dojo/touch",
  7968. "./_ListBase"
  7969. ], function(declare, event, touch, _ListBase){
  7970. /*=====
  7971. var _ListBase = dijit.form._ListBase;
  7972. =====*/
  7973. // module:
  7974. // dijit/form/_ListMouseMixin
  7975. // summary:
  7976. // a mixin to handle mouse or touch events for a focus-less menu
  7977. return declare( "dijit.form._ListMouseMixin", _ListBase, {
  7978. // summary:
  7979. // a Mixin to handle mouse or touch events for a focus-less menu
  7980. // Abstract methods that must be defined externally:
  7981. // onClick: item was chosen (mousedown somewhere on the menu and mouseup somewhere on the menu)
  7982. // tags:
  7983. // private
  7984. postCreate: function(){
  7985. this.inherited(arguments);
  7986. this.connect(this.domNode, "onclick", function(evt){ this._onClick(evt, this._getTarget(evt)); });
  7987. this.connect(this.domNode, "onmousedown", "_onMouseDown");
  7988. this.connect(this.domNode, "onmouseup", "_onMouseUp");
  7989. this.connect(this.domNode, "onmouseover", "_onMouseOver");
  7990. this.connect(this.domNode, "onmouseout", "_onMouseOut");
  7991. },
  7992. _onClick: function(/*Event*/ evt, /*DomNode*/ target){
  7993. this._setSelectedAttr(target, false);
  7994. if(this._deferredClick){
  7995. this._deferredClick.remove();
  7996. }
  7997. this._deferredClick = this.defer(function(){
  7998. this._deferredClick = null;
  7999. this.onClick(target);
  8000. });
  8001. },
  8002. _onMouseDown: function(/*Event*/ evt){
  8003. if(this._hoveredNode){
  8004. this.onUnhover(this._hoveredNode);
  8005. this._hoveredNode = null;
  8006. }
  8007. this._isDragging = true;
  8008. this._setSelectedAttr(this._getTarget(evt), false);
  8009. },
  8010. _onMouseUp: function(/*Event*/ evt){
  8011. this._isDragging = false;
  8012. var selectedNode = this._getSelectedAttr();
  8013. var target = this._getTarget(evt);
  8014. var hoveredNode = this._hoveredNode;
  8015. if(selectedNode && target == selectedNode){
  8016. this.defer(function(){ this._onClick(evt, selectedNode); });
  8017. }else if(hoveredNode){ // drag to select
  8018. this.defer(function(){ this._onClick(evt, hoveredNode); });
  8019. }
  8020. },
  8021. _onMouseOut: function(/*Event*/ /*===== evt ====*/){
  8022. if(this._hoveredNode){
  8023. this.onUnhover(this._hoveredNode);
  8024. if(this._getSelectedAttr() == this._hoveredNode){
  8025. this.onSelect(this._hoveredNode);
  8026. }
  8027. this._hoveredNode = null;
  8028. }
  8029. if(this._isDragging){
  8030. this._cancelDrag = (new Date()).getTime() + 1000; // cancel in 1 second if no _onMouseOver fires
  8031. }
  8032. },
  8033. _onMouseOver: function(/*Event*/ evt){
  8034. if(this._cancelDrag){
  8035. var time = (new Date()).getTime();
  8036. if(time > this._cancelDrag){
  8037. this._isDragging = false;
  8038. }
  8039. this._cancelDrag = null;
  8040. }
  8041. var node = this._getTarget(evt);
  8042. if(!node){ return; }
  8043. if(this._hoveredNode != node){
  8044. if(this._hoveredNode){
  8045. this._onMouseOut({ target: this._hoveredNode });
  8046. }
  8047. if(node && node.parentNode == this.containerNode){
  8048. if(this._isDragging){
  8049. this._setSelectedAttr(node, false);
  8050. }else{
  8051. this._hoveredNode = node;
  8052. this.onHover(node);
  8053. }
  8054. }
  8055. }
  8056. }
  8057. });
  8058. });
  8059. },
  8060. 'url:dijit/templates/Tree.html':"<div class=\"dijitTree dijitTreeContainer\" role=\"tree\">\n\t<div class=\"dijitInline dijitTreeIndent\" style=\"position: absolute; top: -9999px\" data-dojo-attach-point=\"indentDetector\"></div>\n</div>\n",
  8061. 'dojo/cldr/monetary':function(){
  8062. define(["../main"], function(dojo) {
  8063. // module:
  8064. // dojo/cldr/monetary
  8065. // summary:
  8066. // TODOC
  8067. dojo.getObject("cldr.monetary", true, dojo);
  8068. dojo.cldr.monetary.getData = function(/*String*/code){
  8069. // summary: A mapping of currency code to currency-specific formatting information. Returns a unique object with properties: places, round.
  8070. // code: an [ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code
  8071. // from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/currencyData/fractions
  8072. var placesData = {
  8073. ADP:0,AFN:0,ALL:0,AMD:0,BHD:3,BIF:0,BYR:0,CLF:0,CLP:0,
  8074. COP:0,CRC:0,DJF:0,ESP:0,GNF:0,GYD:0,HUF:0,IDR:0,IQD:0,
  8075. IRR:3,ISK:0,ITL:0,JOD:3,JPY:0,KMF:0,KPW:0,KRW:0,KWD:3,
  8076. LAK:0,LBP:0,LUF:0,LYD:3,MGA:0,MGF:0,MMK:0,MNT:0,MRO:0,
  8077. MUR:0,OMR:3,PKR:0,PYG:0,RSD:0,RWF:0,SLL:0,SOS:0,STD:0,
  8078. SYP:0,TMM:0,TND:3,TRL:0,TZS:0,UGX:0,UZS:0,VND:0,VUV:0,
  8079. XAF:0,XOF:0,XPF:0,YER:0,ZMK:0,ZWD:0
  8080. };
  8081. var roundingData = {CHF:5};
  8082. var places = placesData[code], round = roundingData[code];
  8083. if(typeof places == "undefined"){ places = 2; }
  8084. if(typeof round == "undefined"){ round = 0; }
  8085. return {places: places, round: round}; // Object
  8086. };
  8087. return dojo.cldr.monetary;
  8088. });
  8089. },
  8090. 'dojo/cookie':function(){
  8091. define(["./_base/kernel", "./regexp"], function(dojo, regexp) {
  8092. // module:
  8093. // dojo/cookie
  8094. // summary:
  8095. // TODOC
  8096. /*=====
  8097. dojo.__cookieProps = function(){
  8098. // expires: Date|String|Number?
  8099. // If a number, the number of days from today at which the cookie
  8100. // will expire. If a date, the date past which the cookie will expire.
  8101. // If expires is in the past, the cookie will be deleted.
  8102. // If expires is omitted or is 0, the cookie will expire when the browser closes.
  8103. // path: String?
  8104. // The path to use for the cookie.
  8105. // domain: String?
  8106. // The domain to use for the cookie.
  8107. // secure: Boolean?
  8108. // Whether to only send the cookie on secure connections
  8109. this.expires = expires;
  8110. this.path = path;
  8111. this.domain = domain;
  8112. this.secure = secure;
  8113. }
  8114. =====*/
  8115. dojo.cookie = function(/*String*/name, /*String?*/value, /*dojo.__cookieProps?*/props){
  8116. // summary:
  8117. // Get or set a cookie.
  8118. // description:
  8119. // If one argument is passed, returns the value of the cookie
  8120. // For two or more arguments, acts as a setter.
  8121. // name:
  8122. // Name of the cookie
  8123. // value:
  8124. // Value for the cookie
  8125. // props:
  8126. // Properties for the cookie
  8127. // example:
  8128. // set a cookie with the JSON-serialized contents of an object which
  8129. // will expire 5 days from now:
  8130. // | dojo.cookie("configObj", dojo.toJson(config), { expires: 5 });
  8131. //
  8132. // example:
  8133. // de-serialize a cookie back into a JavaScript object:
  8134. // | var config = dojo.fromJson(dojo.cookie("configObj"));
  8135. //
  8136. // example:
  8137. // delete a cookie:
  8138. // | dojo.cookie("configObj", null, {expires: -1});
  8139. var c = document.cookie, ret;
  8140. if(arguments.length == 1){
  8141. var matches = c.match(new RegExp("(?:^|; )" + regexp.escapeString(name) + "=([^;]*)"));
  8142. ret = matches ? decodeURIComponent(matches[1]) : undefined;
  8143. }else{
  8144. props = props || {};
  8145. // FIXME: expires=0 seems to disappear right away, not on close? (FF3) Change docs?
  8146. var exp = props.expires;
  8147. if(typeof exp == "number"){
  8148. var d = new Date();
  8149. d.setTime(d.getTime() + exp*24*60*60*1000);
  8150. exp = props.expires = d;
  8151. }
  8152. if(exp && exp.toUTCString){ props.expires = exp.toUTCString(); }
  8153. value = encodeURIComponent(value);
  8154. var updatedCookie = name + "=" + value, propName;
  8155. for(propName in props){
  8156. updatedCookie += "; " + propName;
  8157. var propValue = props[propName];
  8158. if(propValue !== true){ updatedCookie += "=" + propValue; }
  8159. }
  8160. document.cookie = updatedCookie;
  8161. }
  8162. return ret; // String|undefined
  8163. };
  8164. dojo.cookie.isSupported = function(){
  8165. // summary:
  8166. // Use to determine if the current browser supports cookies or not.
  8167. //
  8168. // Returns true if user allows cookies.
  8169. // Returns false if user doesn't allow cookies.
  8170. if(!("cookieEnabled" in navigator)){
  8171. this("__djCookieTest__", "CookiesAllowed");
  8172. navigator.cookieEnabled = this("__djCookieTest__") == "CookiesAllowed";
  8173. if(navigator.cookieEnabled){
  8174. this("__djCookieTest__", "", {expires: -1});
  8175. }
  8176. }
  8177. return navigator.cookieEnabled;
  8178. };
  8179. return dojo.cookie;
  8180. });
  8181. },
  8182. 'url:dijit/form/templates/DropDownBox.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\"\n\tid=\"widget_${id}\"\n\trole=\"combobox\"\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\n\t\tdata-dojo-attach-point=\"_buttonNode, _popupStateNode\" role=\"presentation\"\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t\t\t${_buttonInputDisabled}\n\t/></div\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\n\t\t\tdata-dojo-attach-point=\"textbox,focusNode\" role=\"textbox\" aria-haspopup=\"true\"\n\t/></div\n></div>\n",
  8183. 'dijit/ProgressBar':function(){
  8184. define([
  8185. "require", // require.toUrl
  8186. "dojo/_base/declare", // declare
  8187. "dojo/dom-class", // domClass.toggle
  8188. "dojo/_base/lang", // lang.mixin
  8189. "dojo/number", // number.format
  8190. "./_Widget",
  8191. "./_TemplatedMixin",
  8192. "dojo/text!./templates/ProgressBar.html"
  8193. ], function(require, declare, domClass, lang, number, _Widget, _TemplatedMixin, template){
  8194. /*=====
  8195. var _Widget = dijit._Widget;
  8196. var _TemplatedMixin = dijit._TemplatedMixin;
  8197. =====*/
  8198. // module:
  8199. // dijit/ProgressBar
  8200. // summary:
  8201. // A progress indication widget, showing the amount completed
  8202. // (often the percentage completed) of a task.
  8203. return declare("dijit.ProgressBar", [_Widget, _TemplatedMixin], {
  8204. // summary:
  8205. // A progress indication widget, showing the amount completed
  8206. // (often the percentage completed) of a task.
  8207. //
  8208. // example:
  8209. // | <div data-dojo-type="ProgressBar"
  8210. // | places="0"
  8211. // | value="..." maximum="...">
  8212. // | </div>
  8213. // progress: [const] String (Percentage or Number)
  8214. // Number or percentage indicating amount of task completed.
  8215. // Deprecated. Use "value" instead.
  8216. progress: "0",
  8217. // value: String (Percentage or Number)
  8218. // Number or percentage indicating amount of task completed.
  8219. // With "%": percentage value, 0% <= progress <= 100%, or
  8220. // without "%": absolute value, 0 <= progress <= maximum.
  8221. // Infinity means that the progress bar is indeterminate.
  8222. value: "",
  8223. // maximum: [const] Float
  8224. // Max sample number
  8225. maximum: 100,
  8226. // places: [const] Number
  8227. // Number of places to show in values; 0 by default
  8228. places: 0,
  8229. // indeterminate: [const] Boolean
  8230. // If false: show progress value (number or percentage).
  8231. // If true: show that a process is underway but that the amount completed is unknown.
  8232. // Deprecated. Use "value" instead.
  8233. indeterminate: false,
  8234. // label: String?
  8235. // Label on progress bar. Defaults to percentage for determinate progress bar and
  8236. // blank for indeterminate progress bar.
  8237. label:"",
  8238. // name: String
  8239. // this is the field name (for a form) if set. This needs to be set if you want to use
  8240. // this widget in a dijit.form.Form widget (such as dijit.Dialog)
  8241. name: '',
  8242. templateString: template,
  8243. // _indeterminateHighContrastImagePath: [private] URL
  8244. // URL to image to use for indeterminate progress bar when display is in high contrast mode
  8245. _indeterminateHighContrastImagePath:
  8246. require.toUrl("./themes/a11y/indeterminate_progress.gif"),
  8247. postMixInProperties: function(){
  8248. this.inherited(arguments);
  8249. if(!("value" in this.params)){
  8250. this.value = this.indeterminate ? Infinity : this.progress;
  8251. }
  8252. },
  8253. buildRendering: function(){
  8254. this.inherited(arguments);
  8255. this.indeterminateHighContrastImage.setAttribute("src",
  8256. this._indeterminateHighContrastImagePath.toString());
  8257. this.update();
  8258. },
  8259. update: function(/*Object?*/attributes){
  8260. // summary:
  8261. // Internal method to change attributes of ProgressBar, similar to set(hash). Users should call
  8262. // set("value", ...) rather than calling this method directly.
  8263. // attributes:
  8264. // May provide progress and/or maximum properties on this parameter;
  8265. // see attribute specs for details.
  8266. // example:
  8267. // | myProgressBar.update({'indeterminate': true});
  8268. // | myProgressBar.update({'progress': 80});
  8269. // | myProgressBar.update({'indeterminate': true, label:"Loading ..." })
  8270. // tags:
  8271. // private
  8272. // TODO: deprecate this method and use set() instead
  8273. lang.mixin(this, attributes || {});
  8274. var tip = this.internalProgress, ap = this.domNode;
  8275. var percent = 1;
  8276. if(this.indeterminate){
  8277. ap.removeAttribute("aria-valuenow");
  8278. }else{
  8279. if(String(this.progress).indexOf("%") != -1){
  8280. percent = Math.min(parseFloat(this.progress)/100, 1);
  8281. this.progress = percent * this.maximum;
  8282. }else{
  8283. this.progress = Math.min(this.progress, this.maximum);
  8284. percent = this.maximum ? this.progress / this.maximum : 0;
  8285. }
  8286. ap.setAttribute("aria-valuenow", this.progress);
  8287. }
  8288. // Even indeterminate ProgressBars should have these attributes
  8289. ap.setAttribute("aria-describedby", this.labelNode.id);
  8290. ap.setAttribute("aria-valuemin", 0);
  8291. ap.setAttribute("aria-valuemax", this.maximum);
  8292. this.labelNode.innerHTML = this.report(percent);
  8293. domClass.toggle(this.domNode, "dijitProgressBarIndeterminate", this.indeterminate);
  8294. tip.style.width = (percent * 100) + "%";
  8295. this.onChange();
  8296. },
  8297. _setValueAttr: function(v){
  8298. this._set("value", v);
  8299. if(v == Infinity){
  8300. this.update({indeterminate:true});
  8301. }else{
  8302. this.update({indeterminate:false, progress:v});
  8303. }
  8304. },
  8305. _setLabelAttr: function(label){
  8306. this._set("label", label);
  8307. this.update();
  8308. },
  8309. _setIndeterminateAttr: function(indeterminate){
  8310. // Deprecated, use set("value", ...) instead
  8311. this.indeterminate = indeterminate;
  8312. this.update();
  8313. },
  8314. report: function(/*float*/percent){
  8315. // summary:
  8316. // Generates message to show inside progress bar (normally indicating amount of task completed).
  8317. // May be overridden.
  8318. // tags:
  8319. // extension
  8320. return this.label ? this.label :
  8321. (this.indeterminate ? "&#160;" : number.format(percent, { type: "percent", places: this.places, locale: this.lang }));
  8322. },
  8323. onChange: function(){
  8324. // summary:
  8325. // Callback fired when progress updates.
  8326. // tags:
  8327. // extension
  8328. }
  8329. });
  8330. });
  8331. },
  8332. 'dijit/form/NumberTextBox':function(){
  8333. define([
  8334. "dojo/_base/declare", // declare
  8335. "dojo/_base/lang", // lang.hitch lang.mixin
  8336. "dojo/number", // number._realNumberRegexp number.format number.parse number.regexp
  8337. "./RangeBoundTextBox"
  8338. ], function(declare, lang, number, RangeBoundTextBox){
  8339. /*=====
  8340. var RangeBoundTextBox = dijit.form.RangeBoundTextBox;
  8341. =====*/
  8342. // module:
  8343. // dijit/form/NumberTextBox
  8344. // summary:
  8345. // A TextBox for entering numbers, with formatting and range checking
  8346. /*=====
  8347. declare(
  8348. "dijit.form.NumberTextBox.__Constraints",
  8349. [dijit.form.RangeBoundTextBox.__Constraints, number.__FormatOptions, number.__ParseOptions], {
  8350. // summary:
  8351. // Specifies both the rules on valid/invalid values (minimum, maximum,
  8352. // number of required decimal places), and also formatting options for
  8353. // displaying the value when the field is not focused.
  8354. // example:
  8355. // Minimum/maximum:
  8356. // To specify a field between 0 and 120:
  8357. // | {min:0,max:120}
  8358. // To specify a field that must be an integer:
  8359. // | {fractional:false}
  8360. // To specify a field where 0 to 3 decimal places are allowed on input:
  8361. // | {places:'0,3'}
  8362. });
  8363. =====*/
  8364. var NumberTextBoxMixin = declare("dijit.form.NumberTextBoxMixin", null, {
  8365. // summary:
  8366. // A mixin for all number textboxes
  8367. // tags:
  8368. // protected
  8369. // Override ValidationTextBox.regExpGen().... we use a reg-ex generating function rather
  8370. // than a straight regexp to deal with locale (plus formatting options too?)
  8371. regExpGen: number.regexp,
  8372. /*=====
  8373. // constraints: dijit.form.NumberTextBox.__Constraints
  8374. // Despite the name, this parameter specifies both constraints on the input
  8375. // (including minimum/maximum allowed values) as well as
  8376. // formatting options like places (the number of digits to display after
  8377. // the decimal point). See `dijit.form.NumberTextBox.__Constraints` for details.
  8378. constraints: {},
  8379. ======*/
  8380. // value: Number
  8381. // The value of this NumberTextBox as a Javascript Number (i.e., not a String).
  8382. // If the displayed value is blank, the value is NaN, and if the user types in
  8383. // an gibberish value (like "hello world"), the value is undefined
  8384. // (i.e. get('value') returns undefined).
  8385. //
  8386. // Symmetrically, set('value', NaN) will clear the displayed value,
  8387. // whereas set('value', undefined) will have no effect.
  8388. value: NaN,
  8389. // editOptions: [protected] Object
  8390. // Properties to mix into constraints when the value is being edited.
  8391. // This is here because we edit the number in the format "12345", which is
  8392. // different than the display value (ex: "12,345")
  8393. editOptions: { pattern: '#.######' },
  8394. /*=====
  8395. _formatter: function(value, options){
  8396. // summary:
  8397. // _formatter() is called by format(). It's the base routine for formatting a number,
  8398. // as a string, for example converting 12345 into "12,345".
  8399. // value: Number
  8400. // The number to be converted into a string.
  8401. // options: dojo.number.__FormatOptions?
  8402. // Formatting options
  8403. // tags:
  8404. // protected extension
  8405. return "12345"; // String
  8406. },
  8407. =====*/
  8408. _formatter: number.format,
  8409. postMixInProperties: function(){
  8410. this.inherited(arguments);
  8411. this._set("type", "text"); // in case type="number" was specified which messes up parse/format
  8412. },
  8413. _setConstraintsAttr: function(/*Object*/ constraints){
  8414. var places = typeof constraints.places == "number"? constraints.places : 0;
  8415. if(places){ places++; } // decimal rounding errors take away another digit of precision
  8416. if(typeof constraints.max != "number"){
  8417. constraints.max = 9 * Math.pow(10, 15-places);
  8418. }
  8419. if(typeof constraints.min != "number"){
  8420. constraints.min = -9 * Math.pow(10, 15-places);
  8421. }
  8422. this.inherited(arguments, [ constraints ]);
  8423. if(this.focusNode && this.focusNode.value && !isNaN(this.value)){
  8424. this.set('value', this.value);
  8425. }
  8426. },
  8427. _onFocus: function(){
  8428. if(this.disabled){ return; }
  8429. var val = this.get('value');
  8430. if(typeof val == "number" && !isNaN(val)){
  8431. var formattedValue = this.format(val, this.constraints);
  8432. if(formattedValue !== undefined){
  8433. this.textbox.value = formattedValue;
  8434. }
  8435. }
  8436. this.inherited(arguments);
  8437. },
  8438. format: function(/*Number*/ value, /*dojo.number.__FormatOptions*/ constraints){
  8439. // summary:
  8440. // Formats the value as a Number, according to constraints.
  8441. // tags:
  8442. // protected
  8443. var formattedValue = String(value);
  8444. if(typeof value != "number"){ return formattedValue; }
  8445. if(isNaN(value)){ return ""; }
  8446. // check for exponential notation that dojo.number.format chokes on
  8447. if(!("rangeCheck" in this && this.rangeCheck(value, constraints)) && constraints.exponent !== false && /\de[-+]?\d/i.test(formattedValue)){
  8448. return formattedValue;
  8449. }
  8450. if(this.editOptions && this.focused){
  8451. constraints = lang.mixin({}, constraints, this.editOptions);
  8452. }
  8453. return this._formatter(value, constraints);
  8454. },
  8455. /*=====
  8456. _parser: function(value, constraints){
  8457. // summary:
  8458. // Parses the string value as a Number, according to constraints.
  8459. // value: String
  8460. // String representing a number
  8461. // constraints: dojo.number.__ParseOptions
  8462. // Formatting options
  8463. // tags:
  8464. // protected
  8465. return 123.45; // Number
  8466. },
  8467. =====*/
  8468. _parser: number.parse,
  8469. parse: function(/*String*/ value, /*number.__FormatOptions*/ constraints){
  8470. // summary:
  8471. // Replaceable function to convert a formatted string to a number value
  8472. // tags:
  8473. // protected extension
  8474. var v = this._parser(value, lang.mixin({}, constraints, (this.editOptions && this.focused) ? this.editOptions : {}));
  8475. if(this.editOptions && this.focused && isNaN(v)){
  8476. v = this._parser(value, constraints); // parse w/o editOptions: not technically needed but is nice for the user
  8477. }
  8478. return v;
  8479. },
  8480. _getDisplayedValueAttr: function(){
  8481. var v = this.inherited(arguments);
  8482. return isNaN(v) ? this.textbox.value : v;
  8483. },
  8484. filter: function(/*Number*/ value){
  8485. // summary:
  8486. // This is called with both the display value (string), and the actual value (a number).
  8487. // When called with the actual value it does corrections so that '' etc. are represented as NaN.
  8488. // Otherwise it dispatches to the superclass's filter() method.
  8489. //
  8490. // See `dijit.form.TextBox.filter` for more details.
  8491. return (value === null || value === '' || value === undefined) ? NaN : this.inherited(arguments); // set('value', null||''||undefined) should fire onChange(NaN)
  8492. },
  8493. serialize: function(/*Number*/ value, /*Object?*/ options){
  8494. // summary:
  8495. // Convert value (a Number) into a canonical string (ie, how the number literal is written in javascript/java/C/etc.)
  8496. // tags:
  8497. // protected
  8498. return (typeof value != "number" || isNaN(value)) ? '' : this.inherited(arguments);
  8499. },
  8500. _setBlurValue: function(){
  8501. var val = lang.hitch(lang.mixin({}, this, { focused: true }), "get")('value'); // parse with editOptions
  8502. this._setValueAttr(val, true);
  8503. },
  8504. _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
  8505. // summary:
  8506. // Hook so set('value', ...) works.
  8507. if(value !== undefined && formattedValue === undefined){
  8508. formattedValue = String(value);
  8509. if(typeof value == "number"){
  8510. if(isNaN(value)){ formattedValue = '' }
  8511. // check for exponential notation that number.format chokes on
  8512. else if(("rangeCheck" in this && this.rangeCheck(value, this.constraints)) || this.constraints.exponent === false || !/\de[-+]?\d/i.test(formattedValue)){
  8513. formattedValue = undefined; // lets format compute a real string value
  8514. }
  8515. }else if(!value){ // 0 processed in if branch above, ''|null|undefined flows through here
  8516. formattedValue = '';
  8517. value = NaN;
  8518. }else{ // non-numeric values
  8519. value = undefined;
  8520. }
  8521. }
  8522. this.inherited(arguments, [value, priorityChange, formattedValue]);
  8523. },
  8524. _getValueAttr: function(){
  8525. // summary:
  8526. // Hook so get('value') works.
  8527. // Returns Number, NaN for '', or undefined for unparseable text
  8528. var v = this.inherited(arguments); // returns Number for all values accepted by parse() or NaN for all other displayed values
  8529. // If the displayed value of the textbox is gibberish (ex: "hello world"), this.inherited() above
  8530. // returns NaN; this if() branch converts the return value to undefined.
  8531. // Returning undefined prevents user text from being overwritten when doing _setValueAttr(_getValueAttr()).
  8532. // A blank displayed value is still returned as NaN.
  8533. if(isNaN(v) && this.textbox.value !== ''){
  8534. if(this.constraints.exponent !== false && /\de[-+]?\d/i.test(this.textbox.value) && (new RegExp("^"+number._realNumberRegexp(lang.mixin({}, this.constraints))+"$").test(this.textbox.value))){ // check for exponential notation that parse() rejected (erroneously?)
  8535. var n = Number(this.textbox.value);
  8536. return isNaN(n) ? undefined : n; // return exponential Number or undefined for random text (may not be possible to do with the above RegExp check)
  8537. }else{
  8538. return undefined; // gibberish
  8539. }
  8540. }else{
  8541. return v; // Number or NaN for ''
  8542. }
  8543. },
  8544. isValid: function(/*Boolean*/ isFocused){
  8545. // Overrides dijit.form.RangeBoundTextBox.isValid to check that the editing-mode value is valid since
  8546. // it may not be formatted according to the regExp validation rules
  8547. if(!this.focused || this._isEmpty(this.textbox.value)){
  8548. return this.inherited(arguments);
  8549. }else{
  8550. var v = this.get('value');
  8551. if(!isNaN(v) && this.rangeCheck(v, this.constraints)){
  8552. if(this.constraints.exponent !== false && /\de[-+]?\d/i.test(this.textbox.value)){ // exponential, parse doesn't like it
  8553. return true; // valid exponential number in range
  8554. }else{
  8555. return this.inherited(arguments);
  8556. }
  8557. }else{
  8558. return false;
  8559. }
  8560. }
  8561. }
  8562. });
  8563. /*=====
  8564. NumberTextBoxMixin = dijit.form.NumberTextBoxMixin;
  8565. =====*/
  8566. var NumberTextBox = declare("dijit.form.NumberTextBox", [RangeBoundTextBox,NumberTextBoxMixin], {
  8567. // summary:
  8568. // A TextBox for entering numbers, with formatting and range checking
  8569. // description:
  8570. // NumberTextBox is a textbox for entering and displaying numbers, supporting
  8571. // the following main features:
  8572. //
  8573. // 1. Enforce minimum/maximum allowed values (as well as enforcing that the user types
  8574. // a number rather than a random string)
  8575. // 2. NLS support (altering roles of comma and dot as "thousands-separator" and "decimal-point"
  8576. // depending on locale).
  8577. // 3. Separate modes for editing the value and displaying it, specifically that
  8578. // the thousands separator character (typically comma) disappears when editing
  8579. // but reappears after the field is blurred.
  8580. // 4. Formatting and constraints regarding the number of places (digits after the decimal point)
  8581. // allowed on input, and number of places displayed when blurred (see `constraints` parameter).
  8582. baseClass: "dijitTextBox dijitNumberTextBox"
  8583. });
  8584. NumberTextBox.Mixin = NumberTextBoxMixin; // for monkey patching
  8585. return NumberTextBox;
  8586. });
  8587. },
  8588. 'dijit/form/TimeTextBox':function(){
  8589. define("dijit/form/TimeTextBox", [
  8590. "dojo/_base/declare", // declare
  8591. "dojo/keys", // keys.DOWN_ARROW keys.ENTER keys.ESCAPE keys.TAB keys.UP_ARROW
  8592. "dojo/_base/lang", // lang.hitch
  8593. "../_TimePicker",
  8594. "./_DateTimeTextBox"
  8595. ], function(declare, keys, lang, _TimePicker, _DateTimeTextBox){
  8596. /*=====
  8597. var _TimePicker = dijit._TimePicker;
  8598. var _DateTimeTextBox = dijit.form._DateTimeTextBox;
  8599. =====*/
  8600. // module:
  8601. // dijit/form/TimeTextBox
  8602. // summary:
  8603. // A validating, serializable, range-bound time text box with a drop down time picker
  8604. /*=====
  8605. declare(
  8606. "dijit.form.TimeTextBox.__Constraints",
  8607. [dijit.form._DateTimeTextBox.__Constraints, dijit._TimePicker.__Constraints]
  8608. );
  8609. =====*/
  8610. return declare("dijit.form.TimeTextBox", _DateTimeTextBox, {
  8611. // summary:
  8612. // A validating, serializable, range-bound time text box with a drop down time picker
  8613. baseClass: "dijitTextBox dijitComboBox dijitTimeTextBox",
  8614. popupClass: _TimePicker,
  8615. _selector: "time",
  8616. /*=====
  8617. // constraints: dijit.form.TimeTextBox.__Constraints
  8618. constraints:{},
  8619. =====*/
  8620. // value: Date
  8621. // The value of this widget as a JavaScript Date object. Note that the date portion implies time zone and daylight savings rules.
  8622. //
  8623. // Example:
  8624. // | new dijit.form.TimeTextBox({value: stamp.fromISOString("T12:59:59", new Date())})
  8625. //
  8626. // When passed to the parser in markup, must be specified according to locale-independent
  8627. // `stamp.fromISOString` format.
  8628. //
  8629. // Example:
  8630. // | <input data-dojo-type='dijit.form.TimeTextBox' value='T12:34:00'>
  8631. value: new Date(""), // value.toString()="NaN"
  8632. //FIXME: in markup, you have no control over daylight savings
  8633. _onKey: function(evt){
  8634. if(this.disabled || this.readOnly){ return; }
  8635. this.inherited(arguments);
  8636. // If the user has backspaced or typed some numbers, then filter the result list
  8637. // by what they typed. Maybe there's a better way to detect this, like _handleOnChange()?
  8638. switch(evt.keyCode){
  8639. case keys.ENTER:
  8640. case keys.TAB:
  8641. case keys.ESCAPE:
  8642. case keys.DOWN_ARROW:
  8643. case keys.UP_ARROW:
  8644. // these keys have special meaning
  8645. break;
  8646. default:
  8647. // setTimeout() because the keystroke hasn't yet appeared in the <input>,
  8648. // so the get('displayedValue') call below won't give the result we want.
  8649. setTimeout(lang.hitch(this, function(){
  8650. // set this.filterString to the filter to apply to the drop down list;
  8651. // it will be used in openDropDown()
  8652. var val = this.get('displayedValue');
  8653. this.filterString = (val && !this.parse(val, this.constraints)) ? val.toLowerCase() : "";
  8654. // close the drop down and reopen it, in order to filter the items shown in the list
  8655. // and also since the drop down may need to be repositioned if the number of list items has changed
  8656. // and it's being displayed above the <input>
  8657. if(this._opened){
  8658. this.closeDropDown();
  8659. }
  8660. this.openDropDown();
  8661. }), 0);
  8662. }
  8663. }
  8664. });
  8665. });
  8666. },
  8667. 'dijit/ColorPalette':function(){
  8668. define([
  8669. "require", // require.toUrl
  8670. "dojo/text!./templates/ColorPalette.html",
  8671. "./_Widget",
  8672. "./_TemplatedMixin",
  8673. "./_PaletteMixin",
  8674. "dojo/i18n", // i18n.getLocalization
  8675. "dojo/_base/Color", // dojo.Color dojo.Color.named
  8676. "dojo/_base/declare", // declare
  8677. "dojo/dom-class", // domClass.contains
  8678. "dojo/dom-construct", // domConstruct.place
  8679. "dojo/_base/window", // win.body
  8680. "dojo/string", // string.substitute
  8681. "dojo/i18n!dojo/nls/colors", // translations
  8682. "dojo/colors" // extend dojo.Color w/names of other colors
  8683. ], function(require, template, _Widget, _TemplatedMixin, _PaletteMixin, i18n, Color,
  8684. declare, domClass, domConstruct, win, string){
  8685. /*=====
  8686. var _Widget = dijit._Widget;
  8687. var _TemplatedMixin = dijit._TemplatedMixin;
  8688. var _PaletteMixin = dijit._PaletteMixin;
  8689. =====*/
  8690. // module:
  8691. // dijit/ColorPalette
  8692. // summary:
  8693. // A keyboard accessible color-picking widget
  8694. var ColorPalette = declare("dijit.ColorPalette", [_Widget, _TemplatedMixin, _PaletteMixin], {
  8695. // summary:
  8696. // A keyboard accessible color-picking widget
  8697. // description:
  8698. // Grid showing various colors, so the user can pick a certain color.
  8699. // Can be used standalone, or as a popup.
  8700. //
  8701. // example:
  8702. // | <div data-dojo-type="dijit.ColorPalette"></div>
  8703. //
  8704. // example:
  8705. // | var picker = new dijit.ColorPalette({ },srcNode);
  8706. // | picker.startup();
  8707. // palette: [const] String
  8708. // Size of grid, either "7x10" or "3x4".
  8709. palette: "7x10",
  8710. // _palettes: [protected] Map
  8711. // This represents the value of the colors.
  8712. // The first level is a hashmap of the different palettes available.
  8713. // The next two dimensions represent the columns and rows of colors.
  8714. _palettes: {
  8715. "7x10": [["white", "seashell", "cornsilk", "lemonchiffon","lightyellow", "palegreen", "paleturquoise", "lightcyan", "lavender", "plum"],
  8716. ["lightgray", "pink", "bisque", "moccasin", "khaki", "lightgreen", "lightseagreen", "lightskyblue", "cornflowerblue", "violet"],
  8717. ["silver", "lightcoral", "sandybrown", "orange", "palegoldenrod", "chartreuse", "mediumturquoise", "skyblue", "mediumslateblue","orchid"],
  8718. ["gray", "red", "orangered", "darkorange", "yellow", "limegreen", "darkseagreen", "royalblue", "slateblue", "mediumorchid"],
  8719. ["dimgray", "crimson", "chocolate", "coral", "gold", "forestgreen", "seagreen", "blue", "blueviolet", "darkorchid"],
  8720. ["darkslategray","firebrick","saddlebrown", "sienna", "olive", "green", "darkcyan", "mediumblue","darkslateblue", "darkmagenta" ],
  8721. ["black", "darkred", "maroon", "brown", "darkolivegreen", "darkgreen", "midnightblue", "navy", "indigo", "purple"]],
  8722. "3x4": [["white", "lime", "green", "blue"],
  8723. ["silver", "yellow", "fuchsia", "navy"],
  8724. ["gray", "red", "purple", "black"]]
  8725. },
  8726. // templateString: String
  8727. // The template of this widget.
  8728. templateString: template,
  8729. baseClass: "dijitColorPalette",
  8730. _dyeFactory: function(value, row, col){
  8731. // Overrides _PaletteMixin._dyeFactory().
  8732. return new this._dyeClass(value, row, col);
  8733. },
  8734. buildRendering: function(){
  8735. // Instantiate the template, which makes a skeleton into which we'll insert a bunch of
  8736. // <img> nodes
  8737. this.inherited(arguments);
  8738. // Creates customized constructor for dye class (color of a single cell) for
  8739. // specified palette and high-contrast vs. normal mode. Used in _getDye().
  8740. this._dyeClass = declare(ColorPalette._Color, {
  8741. hc: domClass.contains(win.body(), "dijit_a11y"),
  8742. palette: this.palette
  8743. });
  8744. // Creates <img> nodes in each cell of the template.
  8745. this._preparePalette(
  8746. this._palettes[this.palette],
  8747. i18n.getLocalization("dojo", "colors", this.lang));
  8748. }
  8749. });
  8750. ColorPalette._Color = declare("dijit._Color", Color, {
  8751. // summary:
  8752. // Object associated with each cell in a ColorPalette palette.
  8753. // Implements dijit.Dye.
  8754. // Template for each cell in normal (non-high-contrast mode). Each cell contains a wrapper
  8755. // node for showing the border (called dijitPaletteImg for back-compat), and dijitColorPaletteSwatch
  8756. // for showing the color.
  8757. template:
  8758. "<span class='dijitInline dijitPaletteImg'>" +
  8759. "<img src='${blankGif}' alt='${alt}' class='dijitColorPaletteSwatch' style='background-color: ${color}'/>" +
  8760. "</span>",
  8761. // Template for each cell in high contrast mode. Each cell contains an image with the whole palette,
  8762. // but scrolled and clipped to show the correct color only
  8763. hcTemplate:
  8764. "<span class='dijitInline dijitPaletteImg' style='position: relative; overflow: hidden; height: 12px; width: 14px;'>" +
  8765. "<img src='${image}' alt='${alt}' style='position: absolute; left: ${left}px; top: ${top}px; ${size}'/>" +
  8766. "</span>",
  8767. // _imagePaths: [protected] Map
  8768. // This is stores the path to the palette images used for high-contrast mode display
  8769. _imagePaths: {
  8770. "7x10": require.toUrl("./themes/a11y/colors7x10.png"),
  8771. "3x4": require.toUrl("./themes/a11y/colors3x4.png")
  8772. },
  8773. constructor: function(/*String*/alias, /*Number*/ row, /*Number*/ col){
  8774. this._alias = alias;
  8775. this._row = row;
  8776. this._col = col;
  8777. this.setColor(Color.named[alias]);
  8778. },
  8779. getValue: function(){
  8780. // summary:
  8781. // Note that although dijit._Color is initialized with a value like "white" getValue() always
  8782. // returns a hex value
  8783. return this.toHex();
  8784. },
  8785. fillCell: function(/*DOMNode*/ cell, /*String*/ blankGif){
  8786. var html = string.substitute(this.hc ? this.hcTemplate : this.template, {
  8787. // substitution variables for normal mode
  8788. color: this.toHex(),
  8789. blankGif: blankGif,
  8790. alt: this._alias,
  8791. // variables used for high contrast mode
  8792. image: this._imagePaths[this.palette].toString(),
  8793. left: this._col * -20 - 5,
  8794. top: this._row * -20 - 5,
  8795. size: this.palette == "7x10" ? "height: 145px; width: 206px" : "height: 64px; width: 86px"
  8796. });
  8797. domConstruct.place(html, cell);
  8798. }
  8799. });
  8800. return ColorPalette;
  8801. });
  8802. },
  8803. 'url:dijit/form/templates/Button.html':"<span class=\"dijit dijitReset dijitInline\" role=\"presentation\"\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\n\t\tdata-dojo-attach-event=\"ondijitclick:_onClick\" role=\"presentation\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdata-dojo-attach-point=\"titleNode,focusNode\"\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" data-dojo-attach-point=\"iconNode\"></span\n\t\t\t><span class=\"dijitReset dijitToggleButtonIconChar\">&#x25CF;</span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t\tdata-dojo-attach-point=\"containerNode\"\n\t\t\t></span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\n\t\ttabIndex=\"-1\" role=\"presentation\" data-dojo-attach-point=\"valueNode\"\n/></span>\n",
  8804. 'dijit/form/CurrencyTextBox':function(){
  8805. define([
  8806. "dojo/currency", // currency._mixInDefaults currency.format currency.parse currency.regexp
  8807. "dojo/_base/declare", // declare
  8808. "dojo/_base/lang", // lang.hitch
  8809. "./NumberTextBox"
  8810. ], function(currency, declare, lang, NumberTextBox){
  8811. /*=====
  8812. var NumberTextBox = dijit.form.NumberTextBox;
  8813. =====*/
  8814. // module:
  8815. // dijit/form/CurrencyTextBox
  8816. // summary:
  8817. // A validating currency textbox
  8818. /*=====
  8819. declare(
  8820. "dijit.form.CurrencyTextBox.__Constraints",
  8821. [dijit.form.NumberTextBox.__Constraints, currency.__FormatOptions, currency.__ParseOptions], {
  8822. // summary:
  8823. // Specifies both the rules on valid/invalid values (minimum, maximum,
  8824. // number of required decimal places), and also formatting options for
  8825. // displaying the value when the field is not focused (currency symbol,
  8826. // etc.)
  8827. // description:
  8828. // Follows the pattern of `dijit.form.NumberTextBox.constraints`.
  8829. // In general developers won't need to set this parameter
  8830. // example:
  8831. // To ensure that the user types in the cents (for example, 1.00 instead of just 1):
  8832. // | {fractional:true}
  8833. });
  8834. =====*/
  8835. return declare("dijit.form.CurrencyTextBox", NumberTextBox, {
  8836. // summary:
  8837. // A validating currency textbox
  8838. // description:
  8839. // CurrencyTextBox is similar to `dijit.form.NumberTextBox` but has a few
  8840. // extra features related to currency:
  8841. //
  8842. // 1. After specifying the currency type (american dollars, euros, etc.) it automatically
  8843. // sets parse/format options such as how many decimal places to show.
  8844. // 2. The currency mark (dollar sign, euro mark, etc.) is displayed when the field is blurred
  8845. // but erased during editing, so that the user can just enter a plain number.
  8846. // currency: [const] String
  8847. // the [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code, a three letter sequence like "USD"
  8848. currency: "",
  8849. /*=====
  8850. // constraints: dijit.form.CurrencyTextBox.__Constraints
  8851. // Despite the name, this parameter specifies both constraints on the input
  8852. // (including minimum/maximum allowed values) as well as
  8853. // formatting options. See `dijit.form.CurrencyTextBox.__Constraints` for details.
  8854. constraints: {},
  8855. ======*/
  8856. baseClass: "dijitTextBox dijitCurrencyTextBox",
  8857. // Override regExpGen ValidationTextBox.regExpGen().... we use a reg-ex generating function rather
  8858. // than a straight regexp to deal with locale (plus formatting options too?)
  8859. regExpGen: function(constraints){
  8860. // if focused, accept either currency data or NumberTextBox format
  8861. return '(' + (this.focused ? this.inherited(arguments, [ lang.mixin({}, constraints, this.editOptions) ]) + '|' : '')
  8862. + currency.regexp(constraints) + ')';
  8863. },
  8864. // Override NumberTextBox._formatter to deal with currencies, ex: converts "123.45" to "$123.45"
  8865. _formatter: currency.format,
  8866. _parser: currency.parse,
  8867. parse: function(/*String*/ value, /*Object*/ constraints){
  8868. // summary:
  8869. // Parses string value as a Currency, according to the constraints object
  8870. // tags:
  8871. // protected extension
  8872. var v = this.inherited(arguments);
  8873. if(isNaN(v) && /\d+/.test(value)){ // currency parse failed, but it could be because they are using NumberTextBox format so try its parse
  8874. v = lang.hitch(lang.mixin({}, this, { _parser: NumberTextBox.prototype._parser }), "inherited")(arguments);
  8875. }
  8876. return v;
  8877. },
  8878. _setConstraintsAttr: function(/*Object*/ constraints){
  8879. if(!constraints.currency && this.currency){
  8880. constraints.currency = this.currency;
  8881. }
  8882. this.inherited(arguments, [ currency._mixInDefaults(lang.mixin(constraints, { exponent: false })) ]); // get places
  8883. }
  8884. });
  8885. });
  8886. },
  8887. 'url:dijit/templates/MenuItem.html':"<tr class=\"dijitReset dijitMenuItem\" data-dojo-attach-point=\"focusNode\" role=\"menuitem\" tabIndex=\"-1\"\n\t\tdata-dojo-attach-event=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitMenuItemIcon\" data-dojo-attach-point=\"iconNode\"/>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" data-dojo-attach-point=\"containerNode\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" data-dojo-attach-point=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">\n\t\t<div data-dojo-attach-point=\"arrowWrapper\" style=\"visibility: hidden\">\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuExpand\"/>\n\t\t\t<span class=\"dijitMenuExpandA11y\">+</span>\n\t\t</div>\n\t</td>\n</tr>\n",
  8888. 'url:dijit/form/templates/CheckBox.html':"<div class=\"dijit dijitReset dijitInline\" role=\"presentation\"\n\t><input\n\t \t${!nameAttrSetting} type=\"${type}\" ${checkedAttrSetting}\n\t\tclass=\"dijitReset dijitCheckBoxInput\"\n\t\tdata-dojo-attach-point=\"focusNode\"\n\t \tdata-dojo-attach-event=\"onclick:_onClick\"\n/></div>\n",
  8889. 'url:dijit/form/templates/VerticalSlider.html':"<table class=\"dijit dijitReset dijitSlider dijitSliderV\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" rules=\"none\" data-dojo-attach-event=\"onkeypress:_onKeyPress,onkeyup:_onKeyUp\"\n\trole=\"presentation\"\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV\"\n\t\t\t><div class=\"dijitSliderIncrementIconV\" style=\"display:none\" data-dojo-attach-point=\"decrementButton\"><span class=\"dijitSliderButtonInner\">+</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderTopBumper\" data-dojo-attach-event=\"press:_onClkIncBumper\"></div></center\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td data-dojo-attach-point=\"leftDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationL dijitSliderDecorationV\"></td\n\t\t><td class=\"dijitReset dijitSliderDecorationC\" style=\"height:100%;\"\n\t\t\t><input data-dojo-attach-point=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\n\t\t\t/><center class=\"dijitReset dijitSliderBarContainerV\" role=\"presentation\" data-dojo-attach-point=\"sliderBarContainer\"\n\t\t\t\t><div role=\"presentation\" data-dojo-attach-point=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarV dijitSliderRemainingBar dijitSliderRemainingBarV\" data-dojo-attach-event=\"press:_onBarClick\"><!--#5629--></div\n\t\t\t\t><div role=\"presentation\" data-dojo-attach-point=\"progressBar\" class=\"dijitSliderBar dijitSliderBarV dijitSliderProgressBar dijitSliderProgressBarV\" data-dojo-attach-event=\"press:_onBarClick\"\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableV\" style=\"vertical-align:top;\"\n\t\t\t\t\t\t><div data-dojo-attach-point=\"sliderHandle,focusNode\" class=\"dijitSliderImageHandle dijitSliderImageHandleV\" data-dojo-attach-event=\"press:_onHandleClick\" role=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"></div\n\t\t\t\t\t></div\n\t\t\t\t></div\n\t\t\t></center\n\t\t></td\n\t\t><td data-dojo-attach-point=\"containerNode,rightDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationR dijitSliderDecorationV\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderBottomBumper\" data-dojo-attach-event=\"press:_onClkDecBumper\"></div></center\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV\"\n\t\t\t><div class=\"dijitSliderDecrementIconV\" style=\"display:none\" data-dojo-attach-point=\"incrementButton\"><span class=\"dijitSliderButtonInner\">-</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n></table>\n",
  8890. 'dijit/layout/LayoutContainer':function(){
  8891. define([
  8892. "dojo/_base/kernel", // kernel.deprecated
  8893. "dojo/_base/lang",
  8894. "dojo/_base/declare", // declare
  8895. "../_WidgetBase",
  8896. "./_LayoutWidget",
  8897. "./utils" // layoutUtils.layoutChildren
  8898. ], function(kernel, lang, declare, _WidgetBase, _LayoutWidget, layoutUtils){
  8899. /*=====
  8900. var _WidgetBase = dijit._WidgetBase;
  8901. var _LayoutWidget = dijit.layout._LayoutWidget;
  8902. =====*/
  8903. // module:
  8904. // dijit/layout/LayoutContainer
  8905. // summary:
  8906. // Deprecated. Use `dijit.layout.BorderContainer` instead.
  8907. // This argument can be specified for the children of a LayoutContainer.
  8908. // Since any widget can be specified as a LayoutContainer child, mix it
  8909. // into the base widget class. (This is a hack, but it's effective.)
  8910. lang.extend(_WidgetBase, {
  8911. // layoutAlign: String
  8912. // "none", "left", "right", "bottom", "top", and "client".
  8913. // See the LayoutContainer description for details on this parameter.
  8914. layoutAlign: 'none'
  8915. });
  8916. return declare("dijit.layout.LayoutContainer", _LayoutWidget, {
  8917. // summary:
  8918. // Deprecated. Use `dijit.layout.BorderContainer` instead.
  8919. //
  8920. // description:
  8921. // Provides Delphi-style panel layout semantics.
  8922. //
  8923. // A LayoutContainer is a box with a specified size (like style="width: 500px; height: 500px;"),
  8924. // that contains children widgets marked with "layoutAlign" of "left", "right", "bottom", "top", and "client".
  8925. // It takes it's children marked as left/top/bottom/right, and lays them out along the edges of the box,
  8926. // and then it takes the child marked "client" and puts it into the remaining space in the middle.
  8927. //
  8928. // Left/right positioning is similar to CSS's "float: left" and "float: right",
  8929. // and top/bottom positioning would be similar to "float: top" and "float: bottom", if there were such
  8930. // CSS.
  8931. //
  8932. // Note that there can only be one client element, but there can be multiple left, right, top,
  8933. // or bottom elements.
  8934. //
  8935. // example:
  8936. // | <style>
  8937. // | html, body{ height: 100%; width: 100%; }
  8938. // | </style>
  8939. // | <div data-dojo-type="dijit.layout.LayoutContainer" style="width: 100%; height: 100%">
  8940. // | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="layoutAlign: 'top'">header text</div>
  8941. // | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="layoutAlign: 'left'" style="width: 200px;">table of contents</div>
  8942. // | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="layoutAlign: 'client'">client area</div>
  8943. // | </div>
  8944. //
  8945. // Lays out each child in the natural order the children occur in.
  8946. // Basically each child is laid out into the "remaining space", where "remaining space" is initially
  8947. // the content area of this widget, but is reduced to a smaller rectangle each time a child is added.
  8948. // tags:
  8949. // deprecated
  8950. baseClass: "dijitLayoutContainer",
  8951. constructor: function(){
  8952. kernel.deprecated("dijit.layout.LayoutContainer is deprecated", "use BorderContainer instead", 2.0);
  8953. },
  8954. layout: function(){
  8955. layoutUtils.layoutChildren(this.domNode, this._contentBox, this.getChildren());
  8956. },
  8957. addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
  8958. this.inherited(arguments);
  8959. if(this._started){
  8960. layoutUtils.layoutChildren(this.domNode, this._contentBox, this.getChildren());
  8961. }
  8962. },
  8963. removeChild: function(/*dijit._Widget*/ widget){
  8964. this.inherited(arguments);
  8965. if(this._started){
  8966. layoutUtils.layoutChildren(this.domNode, this._contentBox, this.getChildren());
  8967. }
  8968. }
  8969. });
  8970. });
  8971. },
  8972. 'dijit/Tooltip':function(){
  8973. define([
  8974. "dojo/_base/array", // array.forEach array.indexOf array.map
  8975. "dojo/_base/declare", // declare
  8976. "dojo/_base/fx", // fx.fadeIn fx.fadeOut
  8977. "dojo/dom", // dom.byId
  8978. "dojo/dom-class", // domClass.add
  8979. "dojo/dom-geometry", // domGeometry.position
  8980. "dojo/dom-style", // domStyle.set, domStyle.get
  8981. "dojo/_base/lang", // lang.hitch lang.isArrayLike
  8982. "dojo/_base/sniff", // has("ie")
  8983. "dojo/_base/window", // win.body
  8984. "./_base/manager", // manager.defaultDuration
  8985. "./place",
  8986. "./_Widget",
  8987. "./_TemplatedMixin",
  8988. "./BackgroundIframe",
  8989. "dojo/text!./templates/Tooltip.html",
  8990. "." // sets dijit.showTooltip etc. for back-compat
  8991. ], function(array, declare, fx, dom, domClass, domGeometry, domStyle, lang, has, win,
  8992. manager, place, _Widget, _TemplatedMixin, BackgroundIframe, template, dijit){
  8993. /*=====
  8994. var _Widget = dijit._Widget;
  8995. var BackgroundIframe = dijit.BackgroundIframe;
  8996. var _TemplatedMixin = dijit._TemplatedMixin;
  8997. =====*/
  8998. // module:
  8999. // dijit/Tooltip
  9000. // summary:
  9001. // Defines dijit.Tooltip widget (to display a tooltip), showTooltip()/hideTooltip(), and _MasterTooltip
  9002. var MasterTooltip = declare("dijit._MasterTooltip", [_Widget, _TemplatedMixin], {
  9003. // summary:
  9004. // Internal widget that holds the actual tooltip markup,
  9005. // which occurs once per page.
  9006. // Called by Tooltip widgets which are just containers to hold
  9007. // the markup
  9008. // tags:
  9009. // protected
  9010. // duration: Integer
  9011. // Milliseconds to fade in/fade out
  9012. duration: manager.defaultDuration,
  9013. templateString: template,
  9014. postCreate: function(){
  9015. win.body().appendChild(this.domNode);
  9016. this.bgIframe = new BackgroundIframe(this.domNode);
  9017. // Setup fade-in and fade-out functions.
  9018. this.fadeIn = fx.fadeIn({ node: this.domNode, duration: this.duration, onEnd: lang.hitch(this, "_onShow") });
  9019. this.fadeOut = fx.fadeOut({ node: this.domNode, duration: this.duration, onEnd: lang.hitch(this, "_onHide") });
  9020. },
  9021. show: function(innerHTML, aroundNode, position, rtl, textDir){
  9022. // summary:
  9023. // Display tooltip w/specified contents to right of specified node
  9024. // (To left if there's no space on the right, or if rtl == true)
  9025. // innerHTML: String
  9026. // Contents of the tooltip
  9027. // aroundNode: DomNode || dijit.__Rectangle
  9028. // Specifies that tooltip should be next to this node / area
  9029. // position: String[]?
  9030. // List of positions to try to position tooltip (ex: ["right", "above"])
  9031. // rtl: Boolean?
  9032. // Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true
  9033. // means "rtl"; specifies GUI direction, not text direction.
  9034. // textDir: String?
  9035. // Corresponds to `WidgetBase.textdir` attribute; specifies direction of text.
  9036. if(this.aroundNode && this.aroundNode === aroundNode && this.containerNode.innerHTML == innerHTML){
  9037. return;
  9038. }
  9039. // reset width; it may have been set by orient() on a previous tooltip show()
  9040. this.domNode.width = "auto";
  9041. if(this.fadeOut.status() == "playing"){
  9042. // previous tooltip is being hidden; wait until the hide completes then show new one
  9043. this._onDeck=arguments;
  9044. return;
  9045. }
  9046. this.containerNode.innerHTML=innerHTML;
  9047. if(textDir){
  9048. this.set("textDir", textDir);
  9049. }
  9050. this.containerNode.align = rtl? "right" : "left"; //fix the text alignment
  9051. var pos = place.around(this.domNode, aroundNode,
  9052. position && position.length ? position : Tooltip.defaultPosition, !rtl, lang.hitch(this, "orient"));
  9053. // Position the tooltip connector for middle alignment.
  9054. // This could not have been done in orient() since the tooltip wasn't positioned at that time.
  9055. var aroundNodeCoords = pos.aroundNodePos;
  9056. if(pos.corner.charAt(0) == 'M' && pos.aroundCorner.charAt(0) == 'M'){
  9057. this.connectorNode.style.top = aroundNodeCoords.y + ((aroundNodeCoords.h - this.connectorNode.offsetHeight) >> 1) - pos.y + "px";
  9058. this.connectorNode.style.left = "";
  9059. }else if(pos.corner.charAt(1) == 'M' && pos.aroundCorner.charAt(1) == 'M'){
  9060. this.connectorNode.style.left = aroundNodeCoords.x + ((aroundNodeCoords.w - this.connectorNode.offsetWidth) >> 1) - pos.x + "px";
  9061. }
  9062. // show it
  9063. domStyle.set(this.domNode, "opacity", 0);
  9064. this.fadeIn.play();
  9065. this.isShowingNow = true;
  9066. this.aroundNode = aroundNode;
  9067. },
  9068. orient: function(/*DomNode*/ node, /*String*/ aroundCorner, /*String*/ tooltipCorner, /*Object*/ spaceAvailable, /*Object*/ aroundNodeCoords){
  9069. // summary:
  9070. // Private function to set CSS for tooltip node based on which position it's in.
  9071. // This is called by the dijit popup code. It will also reduce the tooltip's
  9072. // width to whatever width is available
  9073. // tags:
  9074. // protected
  9075. this.connectorNode.style.top = ""; //reset to default
  9076. // Adjust for space taking by tooltip connector.
  9077. // Take care not to modify the original spaceAvailable arg as that confuses the caller (dijit.place).
  9078. var heightAvailable = spaceAvailable.h,
  9079. widthAvailable = spaceAvailable.w;
  9080. if(aroundCorner.charAt(1) != tooltipCorner.charAt(1)){
  9081. // left/right tooltip
  9082. widthAvailable -= this.connectorNode.offsetWidth;
  9083. }else{
  9084. // above/below tooltip
  9085. heightAvailable -= this.connectorNode.offsetHeight;
  9086. }
  9087. node.className = "dijitTooltip " +
  9088. {
  9089. "MR-ML": "dijitTooltipRight",
  9090. "ML-MR": "dijitTooltipLeft",
  9091. "TM-BM": "dijitTooltipAbove",
  9092. "BM-TM": "dijitTooltipBelow",
  9093. "BL-TL": "dijitTooltipBelow dijitTooltipABLeft",
  9094. "TL-BL": "dijitTooltipAbove dijitTooltipABLeft",
  9095. "BR-TR": "dijitTooltipBelow dijitTooltipABRight",
  9096. "TR-BR": "dijitTooltipAbove dijitTooltipABRight",
  9097. "BR-BL": "dijitTooltipRight",
  9098. "BL-BR": "dijitTooltipLeft"
  9099. }[aroundCorner + "-" + tooltipCorner];
  9100. // reduce tooltip's width to the amount of width available, so that it doesn't overflow screen
  9101. this.domNode.style.width = "auto";
  9102. var size = domGeometry.getContentBox(this.domNode);
  9103. var width = Math.min((Math.max(widthAvailable,1)), size.w);
  9104. var widthWasReduced = width < size.w;
  9105. this.domNode.style.width = width+"px";
  9106. // Reposition the tooltip connector.
  9107. if(tooltipCorner.charAt(0) == 'B' && aroundCorner.charAt(0) == 'B'){
  9108. var bb = domGeometry.position(node);
  9109. var tooltipConnectorHeight = this.connectorNode.offsetHeight;
  9110. if(bb.h > heightAvailable){
  9111. // The tooltip starts at the top of the page and will extend past the aroundNode
  9112. var aroundNodePlacement = heightAvailable - ((aroundNodeCoords.h + tooltipConnectorHeight) >> 1);
  9113. this.connectorNode.style.top = aroundNodePlacement + "px";
  9114. this.connectorNode.style.bottom = "";
  9115. }else{
  9116. // Align center of connector with center of aroundNode, except don't let bottom
  9117. // of connector extend below bottom of tooltip content, or top of connector
  9118. // extend past top of tooltip content
  9119. this.connectorNode.style.bottom = Math.min(
  9120. Math.max(aroundNodeCoords.h/2 - tooltipConnectorHeight/2, 0),
  9121. bb.h - tooltipConnectorHeight) + "px";
  9122. this.connectorNode.style.top = "";
  9123. }
  9124. }else{
  9125. // reset the tooltip back to the defaults
  9126. this.connectorNode.style.top = "";
  9127. this.connectorNode.style.bottom = "";
  9128. }
  9129. return Math.max(0, size.w - widthAvailable);
  9130. },
  9131. _onShow: function(){
  9132. // summary:
  9133. // Called at end of fade-in operation
  9134. // tags:
  9135. // protected
  9136. if(has("ie")){
  9137. // the arrow won't show up on a node w/an opacity filter
  9138. this.domNode.style.filter="";
  9139. }
  9140. },
  9141. hide: function(aroundNode){
  9142. // summary:
  9143. // Hide the tooltip
  9144. if(this._onDeck && this._onDeck[1] == aroundNode){
  9145. // this hide request is for a show() that hasn't even started yet;
  9146. // just cancel the pending show()
  9147. this._onDeck=null;
  9148. }else if(this.aroundNode === aroundNode){
  9149. // this hide request is for the currently displayed tooltip
  9150. this.fadeIn.stop();
  9151. this.isShowingNow = false;
  9152. this.aroundNode = null;
  9153. this.fadeOut.play();
  9154. }else{
  9155. // just ignore the call, it's for a tooltip that has already been erased
  9156. }
  9157. },
  9158. _onHide: function(){
  9159. // summary:
  9160. // Called at end of fade-out operation
  9161. // tags:
  9162. // protected
  9163. this.domNode.style.cssText=""; // to position offscreen again
  9164. this.containerNode.innerHTML="";
  9165. if(this._onDeck){
  9166. // a show request has been queued up; do it now
  9167. this.show.apply(this, this._onDeck);
  9168. this._onDeck=null;
  9169. }
  9170. },
  9171. _setAutoTextDir: function(/*Object*/node){
  9172. // summary:
  9173. // Resolve "auto" text direction for children nodes
  9174. // tags:
  9175. // private
  9176. this.applyTextDir(node, has("ie") ? node.outerText : node.textContent);
  9177. array.forEach(node.children, function(child){this._setAutoTextDir(child); }, this);
  9178. },
  9179. _setTextDirAttr: function(/*String*/ textDir){
  9180. // summary:
  9181. // Setter for textDir.
  9182. // description:
  9183. // Users shouldn't call this function; they should be calling
  9184. // set('textDir', value)
  9185. // tags:
  9186. // private
  9187. this._set("textDir", textDir);
  9188. if (textDir == "auto"){
  9189. this._setAutoTextDir(this.containerNode);
  9190. }else{
  9191. this.containerNode.dir = this.textDir;
  9192. }
  9193. }
  9194. });
  9195. dijit.showTooltip = function(innerHTML, aroundNode, position, rtl, textDir){
  9196. // summary:
  9197. // Static method to display tooltip w/specified contents in specified position.
  9198. // See description of dijit.Tooltip.defaultPosition for details on position parameter.
  9199. // If position is not specified then dijit.Tooltip.defaultPosition is used.
  9200. // innerHTML: String
  9201. // Contents of the tooltip
  9202. // aroundNode: dijit.__Rectangle
  9203. // Specifies that tooltip should be next to this node / area
  9204. // position: String[]?
  9205. // List of positions to try to position tooltip (ex: ["right", "above"])
  9206. // rtl: Boolean?
  9207. // Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true
  9208. // means "rtl"; specifies GUI direction, not text direction.
  9209. // textDir: String?
  9210. // Corresponds to `WidgetBase.textdir` attribute; specifies direction of text.
  9211. // after/before don't work, but they used to, so for back-compat convert them to after-centered, before-centered
  9212. if(position){
  9213. position = array.map(position, function(val){
  9214. return {after: "after-centered", before: "before-centered"}[val] || val;
  9215. });
  9216. }
  9217. if(!Tooltip._masterTT){ dijit._masterTT = Tooltip._masterTT = new MasterTooltip(); }
  9218. return Tooltip._masterTT.show(innerHTML, aroundNode, position, rtl, textDir);
  9219. };
  9220. dijit.hideTooltip = function(aroundNode){
  9221. // summary:
  9222. // Static method to hide the tooltip displayed via showTooltip()
  9223. return Tooltip._masterTT && Tooltip._masterTT.hide(aroundNode);
  9224. };
  9225. var Tooltip = declare("dijit.Tooltip", _Widget, {
  9226. // summary:
  9227. // Pops up a tooltip (a help message) when you hover over a node.
  9228. // label: String
  9229. // Text to display in the tooltip.
  9230. // Specified as innerHTML when creating the widget from markup.
  9231. label: "",
  9232. // showDelay: Integer
  9233. // Number of milliseconds to wait after hovering over/focusing on the object, before
  9234. // the tooltip is displayed.
  9235. showDelay: 400,
  9236. // connectId: String|String[]
  9237. // Id of domNode(s) to attach the tooltip to.
  9238. // When user hovers over specified dom node, the tooltip will appear.
  9239. connectId: [],
  9240. // position: String[]
  9241. // See description of `dijit.Tooltip.defaultPosition` for details on position parameter.
  9242. position: [],
  9243. _setConnectIdAttr: function(/*String|String[]*/ newId){
  9244. // summary:
  9245. // Connect to specified node(s)
  9246. // Remove connections to old nodes (if there are any)
  9247. array.forEach(this._connections || [], function(nested){
  9248. array.forEach(nested, lang.hitch(this, "disconnect"));
  9249. }, this);
  9250. // Make array of id's to connect to, excluding entries for nodes that don't exist yet, see startup()
  9251. this._connectIds = array.filter(lang.isArrayLike(newId) ? newId : (newId ? [newId] : []),
  9252. function(id){ return dom.byId(id); });
  9253. // Make connections
  9254. this._connections = array.map(this._connectIds, function(id){
  9255. var node = dom.byId(id);
  9256. return [
  9257. this.connect(node, "onmouseenter", "_onHover"),
  9258. this.connect(node, "onmouseleave", "_onUnHover"),
  9259. this.connect(node, "onfocus", "_onHover"),
  9260. this.connect(node, "onblur", "_onUnHover")
  9261. ];
  9262. }, this);
  9263. this._set("connectId", newId);
  9264. },
  9265. addTarget: function(/*DOMNODE || String*/ node){
  9266. // summary:
  9267. // Attach tooltip to specified node if it's not already connected
  9268. // TODO: remove in 2.0 and just use set("connectId", ...) interface
  9269. var id = node.id || node;
  9270. if(array.indexOf(this._connectIds, id) == -1){
  9271. this.set("connectId", this._connectIds.concat(id));
  9272. }
  9273. },
  9274. removeTarget: function(/*DomNode || String*/ node){
  9275. // summary:
  9276. // Detach tooltip from specified node
  9277. // TODO: remove in 2.0 and just use set("connectId", ...) interface
  9278. var id = node.id || node, // map from DOMNode back to plain id string
  9279. idx = array.indexOf(this._connectIds, id);
  9280. if(idx >= 0){
  9281. // remove id (modifies original this._connectIds but that's OK in this case)
  9282. this._connectIds.splice(idx, 1);
  9283. this.set("connectId", this._connectIds);
  9284. }
  9285. },
  9286. buildRendering: function(){
  9287. this.inherited(arguments);
  9288. domClass.add(this.domNode,"dijitTooltipData");
  9289. },
  9290. startup: function(){
  9291. this.inherited(arguments);
  9292. // If this tooltip was created in a template, or for some other reason the specified connectId[s]
  9293. // didn't exist during the widget's initialization, then connect now.
  9294. var ids = this.connectId;
  9295. array.forEach(lang.isArrayLike(ids) ? ids : [ids], this.addTarget, this);
  9296. },
  9297. _onHover: function(/*Event*/ e){
  9298. // summary:
  9299. // Despite the name of this method, it actually handles both hover and focus
  9300. // events on the target node, setting a timer to show the tooltip.
  9301. // tags:
  9302. // private
  9303. if(!this._showTimer){
  9304. var target = e.target;
  9305. this._showTimer = setTimeout(lang.hitch(this, function(){this.open(target)}), this.showDelay);
  9306. }
  9307. },
  9308. _onUnHover: function(/*Event*/ /*===== e =====*/){
  9309. // summary:
  9310. // Despite the name of this method, it actually handles both mouseleave and blur
  9311. // events on the target node, hiding the tooltip.
  9312. // tags:
  9313. // private
  9314. // keep a tooltip open if the associated element still has focus (even though the
  9315. // mouse moved away)
  9316. if(this._focus){ return; }
  9317. if(this._showTimer){
  9318. clearTimeout(this._showTimer);
  9319. delete this._showTimer;
  9320. }
  9321. this.close();
  9322. },
  9323. open: function(/*DomNode*/ target){
  9324. // summary:
  9325. // Display the tooltip; usually not called directly.
  9326. // tags:
  9327. // private
  9328. if(this._showTimer){
  9329. clearTimeout(this._showTimer);
  9330. delete this._showTimer;
  9331. }
  9332. Tooltip.show(this.label || this.domNode.innerHTML, target, this.position, !this.isLeftToRight(), this.textDir);
  9333. this._connectNode = target;
  9334. this.onShow(target, this.position);
  9335. },
  9336. close: function(){
  9337. // summary:
  9338. // Hide the tooltip or cancel timer for show of tooltip
  9339. // tags:
  9340. // private
  9341. if(this._connectNode){
  9342. // if tooltip is currently shown
  9343. Tooltip.hide(this._connectNode);
  9344. delete this._connectNode;
  9345. this.onHide();
  9346. }
  9347. if(this._showTimer){
  9348. // if tooltip is scheduled to be shown (after a brief delay)
  9349. clearTimeout(this._showTimer);
  9350. delete this._showTimer;
  9351. }
  9352. },
  9353. onShow: function(/*===== target, position =====*/){
  9354. // summary:
  9355. // Called when the tooltip is shown
  9356. // tags:
  9357. // callback
  9358. },
  9359. onHide: function(){
  9360. // summary:
  9361. // Called when the tooltip is hidden
  9362. // tags:
  9363. // callback
  9364. },
  9365. uninitialize: function(){
  9366. this.close();
  9367. this.inherited(arguments);
  9368. }
  9369. });
  9370. Tooltip._MasterTooltip = MasterTooltip; // for monkey patching
  9371. Tooltip.show = dijit.showTooltip; // export function through module return value
  9372. Tooltip.hide = dijit.hideTooltip; // export function through module return value
  9373. // dijit.Tooltip.defaultPosition: String[]
  9374. // This variable controls the position of tooltips, if the position is not specified to
  9375. // the Tooltip widget or *TextBox widget itself. It's an array of strings with the values
  9376. // possible for `dijit/place::around()`. The recommended values are:
  9377. //
  9378. // * before-centered: centers tooltip to the left of the anchor node/widget, or to the right
  9379. // in the case of RTL scripts like Hebrew and Arabic
  9380. // * after-centered: centers tooltip to the right of the anchor node/widget, or to the left
  9381. // in the case of RTL scripts like Hebrew and Arabic
  9382. // * above-centered: tooltip is centered above anchor node
  9383. // * below-centered: tooltip is centered above anchor node
  9384. //
  9385. // The list is positions is tried, in order, until a position is found where the tooltip fits
  9386. // within the viewport.
  9387. //
  9388. // Be careful setting this parameter. A value of "above-centered" may work fine until the user scrolls
  9389. // the screen so that there's no room above the target node. Nodes with drop downs, like
  9390. // DropDownButton or FilteringSelect, are especially problematic, in that you need to be sure
  9391. // that the drop down and tooltip don't overlap, even when the viewport is scrolled so that there
  9392. // is only room below (or above) the target node, but not both.
  9393. Tooltip.defaultPosition = ["after-centered", "before-centered"];
  9394. return Tooltip;
  9395. });
  9396. },
  9397. 'url:dijit/templates/MenuSeparator.html':"<tr class=\"dijitMenuSeparator\">\n\t<td class=\"dijitMenuSeparatorIconCell\">\n\t\t<div class=\"dijitMenuSeparatorTop\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n\t<td colspan=\"3\" class=\"dijitMenuSeparatorLabelCell\">\n\t\t<div class=\"dijitMenuSeparatorTop dijitMenuSeparatorLabel\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n</tr>",
  9398. 'dijit/form/VerticalSlider':function(){
  9399. define([
  9400. "dojo/_base/declare", // declare
  9401. "./HorizontalSlider",
  9402. "dojo/text!./templates/VerticalSlider.html"
  9403. ], function(declare, HorizontalSlider, template){
  9404. /*=====
  9405. var HorizontalSlider = dijit.form.HorizontalSlider;
  9406. =====*/
  9407. // module:
  9408. // dijit/form/VerticalSlider
  9409. // summary:
  9410. // A form widget that allows one to select a value with a vertically draggable handle
  9411. return declare("dijit.form.VerticalSlider", HorizontalSlider, {
  9412. // summary:
  9413. // A form widget that allows one to select a value with a vertically draggable handle
  9414. templateString: template,
  9415. _mousePixelCoord: "pageY",
  9416. _pixelCount: "h",
  9417. _startingPixelCoord: "y",
  9418. _handleOffsetCoord: "top",
  9419. _progressPixelSize: "height",
  9420. // _descending: Boolean
  9421. // Specifies if the slider values go from high-on-top (true), or low-on-top (false)
  9422. // TODO: expose this in 1.2 - the css progress/remaining bar classes need to be reversed
  9423. _descending: true,
  9424. _isReversed: function(){
  9425. // summary:
  9426. // Overrides HorizontalSlider._isReversed.
  9427. // Indicates if values are high on top (with low numbers on the bottom).
  9428. return this._descending;
  9429. }
  9430. });
  9431. });
  9432. },
  9433. 'dijit/form/DropDownButton':function(){
  9434. define([
  9435. "dojo/_base/declare", // declare
  9436. "dojo/_base/lang", // hitch
  9437. "dojo/query", // query
  9438. "../registry", // registry.byNode
  9439. "../popup", // dijit.popup2.hide
  9440. "./Button",
  9441. "../_Container",
  9442. "../_HasDropDown",
  9443. "dojo/text!./templates/DropDownButton.html"
  9444. ], function(declare, lang, query, registry, popup, Button, _Container, _HasDropDown, template){
  9445. /*=====
  9446. Button = dijit.form.Button;
  9447. _Container = dijit._Container;
  9448. _HasDropDown = dijit._HasDropDown;
  9449. =====*/
  9450. // module:
  9451. // dijit/form/DropDownButton
  9452. // summary:
  9453. // A button with a drop down
  9454. return declare("dijit.form.DropDownButton", [Button, _Container, _HasDropDown], {
  9455. // summary:
  9456. // A button with a drop down
  9457. //
  9458. // example:
  9459. // | <button data-dojo-type="dijit.form.DropDownButton">
  9460. // | Hello world
  9461. // | <div data-dojo-type="dijit.Menu">...</div>
  9462. // | </button>
  9463. //
  9464. // example:
  9465. // | var button1 = new dijit.form.DropDownButton({ label: "hi", dropDown: new dijit.Menu(...) });
  9466. // | win.body().appendChild(button1);
  9467. //
  9468. baseClass : "dijitDropDownButton",
  9469. templateString: template,
  9470. _fillContent: function(){
  9471. // Overrides Button._fillContent().
  9472. //
  9473. // My inner HTML contains both the button contents and a drop down widget, like
  9474. // <DropDownButton> <span>push me</span> <Menu> ... </Menu> </DropDownButton>
  9475. // The first node is assumed to be the button content. The widget is the popup.
  9476. if(this.srcNodeRef){ // programatically created buttons might not define srcNodeRef
  9477. //FIXME: figure out how to filter out the widget and use all remaining nodes as button
  9478. // content, not just nodes[0]
  9479. var nodes = query("*", this.srcNodeRef);
  9480. this.inherited(arguments, [nodes[0]]);
  9481. // save pointer to srcNode so we can grab the drop down widget after it's instantiated
  9482. this.dropDownContainer = this.srcNodeRef;
  9483. }
  9484. },
  9485. startup: function(){
  9486. if(this._started){ return; }
  9487. // the child widget from srcNodeRef is the dropdown widget. Insert it in the page DOM,
  9488. // make it invisible, and store a reference to pass to the popup code.
  9489. if(!this.dropDown && this.dropDownContainer){
  9490. var dropDownNode = query("[widgetId]", this.dropDownContainer)[0];
  9491. this.dropDown = registry.byNode(dropDownNode);
  9492. delete this.dropDownContainer;
  9493. }
  9494. if(this.dropDown){
  9495. popup.hide(this.dropDown);
  9496. }
  9497. this.inherited(arguments);
  9498. },
  9499. isLoaded: function(){
  9500. // Returns whether or not we are loaded - if our dropdown has an href,
  9501. // then we want to check that.
  9502. var dropDown = this.dropDown;
  9503. return (!!dropDown && (!dropDown.href || dropDown.isLoaded));
  9504. },
  9505. loadDropDown: function(/*Function*/ callback){
  9506. // Default implementation assumes that drop down already exists,
  9507. // but hasn't loaded it's data (ex: ContentPane w/href).
  9508. // App must override if the drop down is lazy-created.
  9509. var dropDown = this.dropDown;
  9510. var handler = dropDown.on("load", lang.hitch(this, function(){
  9511. handler.remove();
  9512. callback();
  9513. }));
  9514. dropDown.refresh(); // tell it to load
  9515. },
  9516. isFocusable: function(){
  9517. // Overridden so that focus is handled by the _HasDropDown mixin, not by
  9518. // the _FormWidget mixin.
  9519. return this.inherited(arguments) && !this._mouseDown;
  9520. }
  9521. });
  9522. });
  9523. },
  9524. 'url:dijit/templates/ProgressBar.html':"<div class=\"dijitProgressBar dijitProgressBarEmpty\" role=\"progressbar\"\n\t><div data-dojo-attach-point=\"internalProgress\" class=\"dijitProgressBarFull\"\n\t\t><div class=\"dijitProgressBarTile\" role=\"presentation\"></div\n\t\t><span style=\"visibility:hidden\">&#160;</span\n\t></div\n\t><div data-dojo-attach-point=\"labelNode\" class=\"dijitProgressBarLabel\" id=\"${id}_label\"></div\n\t><img data-dojo-attach-point=\"indeterminateHighContrastImage\" class=\"dijitProgressBarIndeterminateHighContrastImage\" alt=\"\"\n/></div>\n",
  9525. 'dojo/date':function(){
  9526. define(["./_base/kernel", "./_base/lang"], function(dojo, lang) {
  9527. // module:
  9528. // dojo/date
  9529. // summary:
  9530. // TODOC
  9531. lang.getObject("date", true, dojo);
  9532. /*=====
  9533. dojo.date = {
  9534. // summary: Date manipulation utilities
  9535. }
  9536. =====*/
  9537. dojo.date.getDaysInMonth = function(/*Date*/dateObject){
  9538. // summary:
  9539. // Returns the number of days in the month used by dateObject
  9540. var month = dateObject.getMonth();
  9541. var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  9542. if(month == 1 && dojo.date.isLeapYear(dateObject)){ return 29; } // Number
  9543. return days[month]; // Number
  9544. };
  9545. dojo.date.isLeapYear = function(/*Date*/dateObject){
  9546. // summary:
  9547. // Determines if the year of the dateObject is a leap year
  9548. // description:
  9549. // Leap years are years with an additional day YYYY-02-29, where the
  9550. // year number is a multiple of four with the following exception: If
  9551. // a year is a multiple of 100, then it is only a leap year if it is
  9552. // also a multiple of 400. For example, 1900 was not a leap year, but
  9553. // 2000 is one.
  9554. var year = dateObject.getFullYear();
  9555. return !(year%400) || (!(year%4) && !!(year%100)); // Boolean
  9556. };
  9557. // FIXME: This is not localized
  9558. dojo.date.getTimezoneName = function(/*Date*/dateObject){
  9559. // summary:
  9560. // Get the user's time zone as provided by the browser
  9561. // dateObject:
  9562. // Needed because the timezone may vary with time (daylight savings)
  9563. // description:
  9564. // Try to get time zone info from toString or toLocaleString method of
  9565. // the Date object -- UTC offset is not a time zone. See
  9566. // http://www.twinsun.com/tz/tz-link.htm Note: results may be
  9567. // inconsistent across browsers.
  9568. var str = dateObject.toString(); // Start looking in toString
  9569. var tz = ''; // The result -- return empty string if nothing found
  9570. var match;
  9571. // First look for something in parentheses -- fast lookup, no regex
  9572. var pos = str.indexOf('(');
  9573. if(pos > -1){
  9574. tz = str.substring(++pos, str.indexOf(')'));
  9575. }else{
  9576. // If at first you don't succeed ...
  9577. // If IE knows about the TZ, it appears before the year
  9578. // Capital letters or slash before a 4-digit year
  9579. // at the end of string
  9580. var pat = /([A-Z\/]+) \d{4}$/;
  9581. if((match = str.match(pat))){
  9582. tz = match[1];
  9583. }else{
  9584. // Some browsers (e.g. Safari) glue the TZ on the end
  9585. // of toLocaleString instead of putting it in toString
  9586. str = dateObject.toLocaleString();
  9587. // Capital letters or slash -- end of string,
  9588. // after space
  9589. pat = / ([A-Z\/]+)$/;
  9590. if((match = str.match(pat))){
  9591. tz = match[1];
  9592. }
  9593. }
  9594. }
  9595. // Make sure it doesn't somehow end up return AM or PM
  9596. return (tz == 'AM' || tz == 'PM') ? '' : tz; // String
  9597. };
  9598. // Utility methods to do arithmetic calculations with Dates
  9599. dojo.date.compare = function(/*Date*/date1, /*Date?*/date2, /*String?*/portion){
  9600. // summary:
  9601. // Compare two date objects by date, time, or both.
  9602. // description:
  9603. // Returns 0 if equal, positive if a > b, else negative.
  9604. // date1:
  9605. // Date object
  9606. // date2:
  9607. // Date object. If not specified, the current Date is used.
  9608. // portion:
  9609. // A string indicating the "date" or "time" portion of a Date object.
  9610. // Compares both "date" and "time" by default. One of the following:
  9611. // "date", "time", "datetime"
  9612. // Extra step required in copy for IE - see #3112
  9613. date1 = new Date(+date1);
  9614. date2 = new Date(+(date2 || new Date()));
  9615. if(portion == "date"){
  9616. // Ignore times and compare dates.
  9617. date1.setHours(0, 0, 0, 0);
  9618. date2.setHours(0, 0, 0, 0);
  9619. }else if(portion == "time"){
  9620. // Ignore dates and compare times.
  9621. date1.setFullYear(0, 0, 0);
  9622. date2.setFullYear(0, 0, 0);
  9623. }
  9624. if(date1 > date2){ return 1; } // int
  9625. if(date1 < date2){ return -1; } // int
  9626. return 0; // int
  9627. };
  9628. dojo.date.add = function(/*Date*/date, /*String*/interval, /*int*/amount){
  9629. // summary:
  9630. // Add to a Date in intervals of different size, from milliseconds to years
  9631. // date: Date
  9632. // Date object to start with
  9633. // interval:
  9634. // A string representing the interval. One of the following:
  9635. // "year", "month", "day", "hour", "minute", "second",
  9636. // "millisecond", "quarter", "week", "weekday"
  9637. // amount:
  9638. // How much to add to the date.
  9639. var sum = new Date(+date); // convert to Number before copying to accomodate IE (#3112)
  9640. var fixOvershoot = false;
  9641. var property = "Date";
  9642. switch(interval){
  9643. case "day":
  9644. break;
  9645. case "weekday":
  9646. //i18n FIXME: assumes Saturday/Sunday weekend, but this is not always true. see dojo.cldr.supplemental
  9647. // Divide the increment time span into weekspans plus leftover days
  9648. // e.g., 8 days is one 5-day weekspan / and two leftover days
  9649. // Can't have zero leftover days, so numbers divisible by 5 get
  9650. // a days value of 5, and the remaining days make up the number of weeks
  9651. var days, weeks;
  9652. var mod = amount % 5;
  9653. if(!mod){
  9654. days = (amount > 0) ? 5 : -5;
  9655. weeks = (amount > 0) ? ((amount-5)/5) : ((amount+5)/5);
  9656. }else{
  9657. days = mod;
  9658. weeks = parseInt(amount/5);
  9659. }
  9660. // Get weekday value for orig date param
  9661. var strt = date.getDay();
  9662. // Orig date is Sat / positive incrementer
  9663. // Jump over Sun
  9664. var adj = 0;
  9665. if(strt == 6 && amount > 0){
  9666. adj = 1;
  9667. }else if(strt == 0 && amount < 0){
  9668. // Orig date is Sun / negative incrementer
  9669. // Jump back over Sat
  9670. adj = -1;
  9671. }
  9672. // Get weekday val for the new date
  9673. var trgt = strt + days;
  9674. // New date is on Sat or Sun
  9675. if(trgt == 0 || trgt == 6){
  9676. adj = (amount > 0) ? 2 : -2;
  9677. }
  9678. // Increment by number of weeks plus leftover days plus
  9679. // weekend adjustments
  9680. amount = (7 * weeks) + days + adj;
  9681. break;
  9682. case "year":
  9683. property = "FullYear";
  9684. // Keep increment/decrement from 2/29 out of March
  9685. fixOvershoot = true;
  9686. break;
  9687. case "week":
  9688. amount *= 7;
  9689. break;
  9690. case "quarter":
  9691. // Naive quarter is just three months
  9692. amount *= 3;
  9693. // fallthrough...
  9694. case "month":
  9695. // Reset to last day of month if you overshoot
  9696. fixOvershoot = true;
  9697. property = "Month";
  9698. break;
  9699. // case "hour":
  9700. // case "minute":
  9701. // case "second":
  9702. // case "millisecond":
  9703. default:
  9704. property = "UTC"+interval.charAt(0).toUpperCase() + interval.substring(1) + "s";
  9705. }
  9706. if(property){
  9707. sum["set"+property](sum["get"+property]()+amount);
  9708. }
  9709. if(fixOvershoot && (sum.getDate() < date.getDate())){
  9710. sum.setDate(0);
  9711. }
  9712. return sum; // Date
  9713. };
  9714. dojo.date.difference = function(/*Date*/date1, /*Date?*/date2, /*String?*/interval){
  9715. // summary:
  9716. // Get the difference in a specific unit of time (e.g., number of
  9717. // months, weeks, days, etc.) between two dates, rounded to the
  9718. // nearest integer.
  9719. // date1:
  9720. // Date object
  9721. // date2:
  9722. // Date object. If not specified, the current Date is used.
  9723. // interval:
  9724. // A string representing the interval. One of the following:
  9725. // "year", "month", "day", "hour", "minute", "second",
  9726. // "millisecond", "quarter", "week", "weekday"
  9727. // Defaults to "day".
  9728. date2 = date2 || new Date();
  9729. interval = interval || "day";
  9730. var yearDiff = date2.getFullYear() - date1.getFullYear();
  9731. var delta = 1; // Integer return value
  9732. switch(interval){
  9733. case "quarter":
  9734. var m1 = date1.getMonth();
  9735. var m2 = date2.getMonth();
  9736. // Figure out which quarter the months are in
  9737. var q1 = Math.floor(m1/3) + 1;
  9738. var q2 = Math.floor(m2/3) + 1;
  9739. // Add quarters for any year difference between the dates
  9740. q2 += (yearDiff * 4);
  9741. delta = q2 - q1;
  9742. break;
  9743. case "weekday":
  9744. var days = Math.round(dojo.date.difference(date1, date2, "day"));
  9745. var weeks = parseInt(dojo.date.difference(date1, date2, "week"));
  9746. var mod = days % 7;
  9747. // Even number of weeks
  9748. if(mod == 0){
  9749. days = weeks*5;
  9750. }else{
  9751. // Weeks plus spare change (< 7 days)
  9752. var adj = 0;
  9753. var aDay = date1.getDay();
  9754. var bDay = date2.getDay();
  9755. weeks = parseInt(days/7);
  9756. mod = days % 7;
  9757. // Mark the date advanced by the number of
  9758. // round weeks (may be zero)
  9759. var dtMark = new Date(date1);
  9760. dtMark.setDate(dtMark.getDate()+(weeks*7));
  9761. var dayMark = dtMark.getDay();
  9762. // Spare change days -- 6 or less
  9763. if(days > 0){
  9764. switch(true){
  9765. // Range starts on Sat
  9766. case aDay == 6:
  9767. adj = -1;
  9768. break;
  9769. // Range starts on Sun
  9770. case aDay == 0:
  9771. adj = 0;
  9772. break;
  9773. // Range ends on Sat
  9774. case bDay == 6:
  9775. adj = -1;
  9776. break;
  9777. // Range ends on Sun
  9778. case bDay == 0:
  9779. adj = -2;
  9780. break;
  9781. // Range contains weekend
  9782. case (dayMark + mod) > 5:
  9783. adj = -2;
  9784. }
  9785. }else if(days < 0){
  9786. switch(true){
  9787. // Range starts on Sat
  9788. case aDay == 6:
  9789. adj = 0;
  9790. break;
  9791. // Range starts on Sun
  9792. case aDay == 0:
  9793. adj = 1;
  9794. break;
  9795. // Range ends on Sat
  9796. case bDay == 6:
  9797. adj = 2;
  9798. break;
  9799. // Range ends on Sun
  9800. case bDay == 0:
  9801. adj = 1;
  9802. break;
  9803. // Range contains weekend
  9804. case (dayMark + mod) < 0:
  9805. adj = 2;
  9806. }
  9807. }
  9808. days += adj;
  9809. days -= (weeks*2);
  9810. }
  9811. delta = days;
  9812. break;
  9813. case "year":
  9814. delta = yearDiff;
  9815. break;
  9816. case "month":
  9817. delta = (date2.getMonth() - date1.getMonth()) + (yearDiff * 12);
  9818. break;
  9819. case "week":
  9820. // Truncate instead of rounding
  9821. // Don't use Math.floor -- value may be negative
  9822. delta = parseInt(dojo.date.difference(date1, date2, "day")/7);
  9823. break;
  9824. case "day":
  9825. delta /= 24;
  9826. // fallthrough
  9827. case "hour":
  9828. delta /= 60;
  9829. // fallthrough
  9830. case "minute":
  9831. delta /= 60;
  9832. // fallthrough
  9833. case "second":
  9834. delta /= 1000;
  9835. // fallthrough
  9836. case "millisecond":
  9837. delta *= date2.getTime() - date1.getTime();
  9838. }
  9839. // Round for fractional values and DST leaps
  9840. return Math.round(delta); // Number (integer)
  9841. };
  9842. return dojo.date;
  9843. });
  9844. },
  9845. 'dijit/layout/_ContentPaneResizeMixin':function(){
  9846. define([
  9847. "dojo/_base/array", // array.filter array.forEach
  9848. "dojo/_base/declare", // declare
  9849. "dojo/dom-attr", // domAttr.has
  9850. "dojo/dom-class", // domClass.contains domClass.toggle
  9851. "dojo/dom-geometry",// domGeometry.contentBox domGeometry.marginBox
  9852. "dojo/_base/lang", // lang.mixin
  9853. "dojo/query", // query
  9854. "dojo/_base/sniff", // has("ie")
  9855. "dojo/_base/window", // win.global
  9856. "../registry", // registry.byId
  9857. "./utils", // marginBox2contextBox
  9858. "../_Contained"
  9859. ], function(array, declare, domAttr, domClass, domGeometry, lang, query, has, win,
  9860. registry, layoutUtils, _Contained){
  9861. /*=====
  9862. var _Contained = dijit._Contained;
  9863. =====*/
  9864. // module:
  9865. // dijit/layout/_ContentPaneResizeMixin
  9866. // summary:
  9867. // Resize() functionality of ContentPane. If there's a single layout widget
  9868. // child then it will call resize() with the same dimensions as the ContentPane.
  9869. // Otherwise just calls resize on each child.
  9870. return declare("dijit.layout._ContentPaneResizeMixin", null, {
  9871. // summary:
  9872. // Resize() functionality of ContentPane. If there's a single layout widget
  9873. // child then it will call resize() with the same dimensions as the ContentPane.
  9874. // Otherwise just calls resize on each child.
  9875. //
  9876. // Also implements basic startup() functionality, where starting the parent
  9877. // will start the children
  9878. // doLayout: Boolean
  9879. // - false - don't adjust size of children
  9880. // - true - if there is a single visible child widget, set it's size to
  9881. // however big the ContentPane is
  9882. doLayout: true,
  9883. // isLayoutContainer: [protected] Boolean
  9884. // Indicates that this widget will call resize() on it's child widgets
  9885. // when they become visible.
  9886. isLayoutContainer: true,
  9887. startup: function(){
  9888. // summary:
  9889. // See `dijit.layout._LayoutWidget.startup` for description.
  9890. // Although ContentPane doesn't extend _LayoutWidget, it does implement
  9891. // the same API.
  9892. if(this._started){ return; }
  9893. var parent = this.getParent();
  9894. this._childOfLayoutWidget = parent && parent.isLayoutContainer;
  9895. // I need to call resize() on my child/children (when I become visible), unless
  9896. // I'm the child of a layout widget in which case my parent will call resize() on me and I'll do it then.
  9897. this._needLayout = !this._childOfLayoutWidget;
  9898. this.inherited(arguments);
  9899. if(this._isShown()){
  9900. this._onShow();
  9901. }
  9902. if(!this._childOfLayoutWidget){
  9903. // If my parent isn't a layout container, since my style *may be* width=height=100%
  9904. // or something similar (either set directly or via a CSS class),
  9905. // monitor when my size changes so that I can re-layout.
  9906. // For browsers where I can't directly monitor when my size changes,
  9907. // monitor when the viewport changes size, which *may* indicate a size change for me.
  9908. this.connect(has("ie") ? this.domNode : win.global, 'onresize', function(){
  9909. // Using function(){} closure to ensure no arguments to resize.
  9910. this._needLayout = !this._childOfLayoutWidget;
  9911. this.resize();
  9912. });
  9913. }
  9914. },
  9915. _checkIfSingleChild: function(){
  9916. // summary:
  9917. // Test if we have exactly one visible widget as a child,
  9918. // and if so assume that we are a container for that widget,
  9919. // and should propagate startup() and resize() calls to it.
  9920. // Skips over things like data stores since they aren't visible.
  9921. var childNodes = query("> *", this.containerNode).filter(function(node){
  9922. return node.tagName !== "SCRIPT"; // or a regexp for hidden elements like script|area|map|etc..
  9923. }),
  9924. childWidgetNodes = childNodes.filter(function(node){
  9925. return domAttr.has(node, "data-dojo-type") || domAttr.has(node, "dojoType") || domAttr.has(node, "widgetId");
  9926. }),
  9927. candidateWidgets = array.filter(childWidgetNodes.map(registry.byNode), function(widget){
  9928. return widget && widget.domNode && widget.resize;
  9929. });
  9930. if(
  9931. // all child nodes are widgets
  9932. childNodes.length == childWidgetNodes.length &&
  9933. // all but one are invisible (like dojo.data)
  9934. candidateWidgets.length == 1
  9935. ){
  9936. this._singleChild = candidateWidgets[0];
  9937. }else{
  9938. delete this._singleChild;
  9939. }
  9940. // So we can set overflow: hidden to avoid a safari bug w/scrollbars showing up (#9449)
  9941. domClass.toggle(this.containerNode, this.baseClass + "SingleChild", !!this._singleChild);
  9942. },
  9943. resize: function(changeSize, resultSize){
  9944. // summary:
  9945. // See `dijit.layout._LayoutWidget.resize` for description.
  9946. // Although ContentPane doesn't extend _LayoutWidget, it does implement
  9947. // the same API.
  9948. // For the TabContainer --> BorderContainer --> ContentPane case, _onShow() is
  9949. // never called, so resize() is our trigger to do the initial href download (see [20099]).
  9950. // However, don't load href for closed TitlePanes.
  9951. if(!this._wasShown && this.open !== false){
  9952. this._onShow();
  9953. }
  9954. this._resizeCalled = true;
  9955. this._scheduleLayout(changeSize, resultSize);
  9956. },
  9957. _scheduleLayout: function(changeSize, resultSize){
  9958. // summary:
  9959. // Resize myself, and call resize() on each of my child layout widgets, either now
  9960. // (if I'm currently visible) or when I become visible
  9961. if(this._isShown()){
  9962. this._layout(changeSize, resultSize);
  9963. }else{
  9964. this._needLayout = true;
  9965. this._changeSize = changeSize;
  9966. this._resultSize = resultSize;
  9967. }
  9968. },
  9969. _layout: function(changeSize, resultSize){
  9970. // summary:
  9971. // Resize myself according to optional changeSize/resultSize parameters, like a layout widget.
  9972. // Also, since I am a Container widget, each of my children expects me to
  9973. // call resize() or layout() on them.
  9974. //
  9975. // Should be called on initialization and also whenever we get new content
  9976. // (from an href, or from set('content', ...))... but deferred until
  9977. // the ContentPane is visible
  9978. // Set margin box size, unless it wasn't specified, in which case use current size.
  9979. if(changeSize){
  9980. domGeometry.setMarginBox(this.domNode, changeSize);
  9981. }
  9982. // Compute content box size of containerNode in case we [later] need to size our single child.
  9983. var cn = this.containerNode;
  9984. if(cn === this.domNode){
  9985. // If changeSize or resultSize was passed to this method and this.containerNode ==
  9986. // this.domNode then we can compute the content-box size without querying the node,
  9987. // which is more reliable (similar to LayoutWidget.resize) (see for example #9449).
  9988. var mb = resultSize || {};
  9989. lang.mixin(mb, changeSize || {}); // changeSize overrides resultSize
  9990. if(!("h" in mb) || !("w" in mb)){
  9991. mb = lang.mixin(domGeometry.getMarginBox(cn), mb); // just use domGeometry.setMarginBox() to fill in missing values
  9992. }
  9993. this._contentBox = layoutUtils.marginBox2contentBox(cn, mb);
  9994. }else{
  9995. this._contentBox = domGeometry.getContentBox(cn);
  9996. }
  9997. this._layoutChildren();
  9998. delete this._needLayout;
  9999. },
  10000. _layoutChildren: function(){
  10001. // Call _checkIfSingleChild() again in case app has manually mucked w/the content
  10002. // of the ContentPane (rather than changing it through the set("content", ...) API.
  10003. if(this.doLayout){
  10004. this._checkIfSingleChild();
  10005. }
  10006. if(this._singleChild && this._singleChild.resize){
  10007. var cb = this._contentBox || domGeometry.getContentBox(this.containerNode);
  10008. // note: if widget has padding this._contentBox will have l and t set,
  10009. // but don't pass them to resize() or it will doubly-offset the child
  10010. this._singleChild.resize({w: cb.w, h: cb.h});
  10011. }else{
  10012. // All my child widgets are independently sized (rather than matching my size),
  10013. // but I still need to call resize() on each child to make it layout.
  10014. array.forEach(this.getChildren(), function(widget){
  10015. if(widget.resize){
  10016. widget.resize();
  10017. }
  10018. });
  10019. }
  10020. },
  10021. _isShown: function(){
  10022. // summary:
  10023. // Returns true if the content is currently shown.
  10024. // description:
  10025. // If I am a child of a layout widget then it actually returns true if I've ever been visible,
  10026. // not whether I'm currently visible, since that's much faster than tracing up the DOM/widget
  10027. // tree every call, and at least solves the performance problem on page load by deferring loading
  10028. // hidden ContentPanes until they are first shown
  10029. if(this._childOfLayoutWidget){
  10030. // If we are TitlePane, etc - we return that only *IF* we've been resized
  10031. if(this._resizeCalled && "open" in this){
  10032. return this.open;
  10033. }
  10034. return this._resizeCalled;
  10035. }else if("open" in this){
  10036. return this.open; // for TitlePane, etc.
  10037. }else{
  10038. var node = this.domNode, parent = this.domNode.parentNode;
  10039. return (node.style.display != 'none') && (node.style.visibility != 'hidden') && !domClass.contains(node, "dijitHidden") &&
  10040. parent && parent.style && (parent.style.display != 'none');
  10041. }
  10042. },
  10043. _onShow: function(){
  10044. // summary:
  10045. // Called when the ContentPane is made visible
  10046. // description:
  10047. // For a plain ContentPane, this is called on initialization, from startup().
  10048. // If the ContentPane is a hidden pane of a TabContainer etc., then it's
  10049. // called whenever the pane is made visible.
  10050. //
  10051. // Does layout/resize of child widget(s)
  10052. // Need to keep track of whether ContentPane has been shown (which is different than
  10053. // whether or not it's currently visible).
  10054. this._wasShown = true;
  10055. if(this._needLayout){
  10056. // If a layout has been scheduled for when we become visible, do it now
  10057. this._layout(this._changeSize, this._resultSize);
  10058. }
  10059. this.inherited(arguments);
  10060. }
  10061. });
  10062. });
  10063. },
  10064. 'dijit/form/RangeBoundTextBox':function(){
  10065. define([
  10066. "dojo/_base/declare", // declare
  10067. "dojo/i18n", // i18n.getLocalization
  10068. "./MappedTextBox"
  10069. ], function(declare, i18n, MappedTextBox){
  10070. /*=====
  10071. var MappedTextBox = dijit.form.MappedTextBox;
  10072. =====*/
  10073. // module:
  10074. // dijit/form/RangeBoundTextBox
  10075. // summary:
  10076. // Base class for textbox form widgets which defines a range of valid values.
  10077. /*=====
  10078. dijit.form.RangeBoundTextBox.__Constraints = function(){
  10079. // min: Number
  10080. // Minimum signed value. Default is -Infinity
  10081. // max: Number
  10082. // Maximum signed value. Default is +Infinity
  10083. this.min = min;
  10084. this.max = max;
  10085. }
  10086. =====*/
  10087. return declare("dijit.form.RangeBoundTextBox", MappedTextBox, {
  10088. // summary:
  10089. // Base class for textbox form widgets which defines a range of valid values.
  10090. // rangeMessage: String
  10091. // The message to display if value is out-of-range
  10092. rangeMessage: "",
  10093. /*=====
  10094. // constraints: dijit.form.RangeBoundTextBox.__Constraints
  10095. constraints: {},
  10096. ======*/
  10097. rangeCheck: function(/*Number*/ primitive, /*dijit.form.RangeBoundTextBox.__Constraints*/ constraints){
  10098. // summary:
  10099. // Overridable function used to validate the range of the numeric input value.
  10100. // tags:
  10101. // protected
  10102. return ("min" in constraints? (this.compare(primitive,constraints.min) >= 0) : true) &&
  10103. ("max" in constraints? (this.compare(primitive,constraints.max) <= 0) : true); // Boolean
  10104. },
  10105. isInRange: function(/*Boolean*/ /*===== isFocused =====*/){
  10106. // summary:
  10107. // Tests if the value is in the min/max range specified in constraints
  10108. // tags:
  10109. // protected
  10110. return this.rangeCheck(this.get('value'), this.constraints);
  10111. },
  10112. _isDefinitelyOutOfRange: function(){
  10113. // summary:
  10114. // Returns true if the value is out of range and will remain
  10115. // out of range even if the user types more characters
  10116. var val = this.get('value');
  10117. var isTooLittle = false;
  10118. var isTooMuch = false;
  10119. if("min" in this.constraints){
  10120. var min = this.constraints.min;
  10121. min = this.compare(val, ((typeof min == "number") && min >= 0 && val !=0) ? 0 : min);
  10122. isTooLittle = (typeof min == "number") && min < 0;
  10123. }
  10124. if("max" in this.constraints){
  10125. var max = this.constraints.max;
  10126. max = this.compare(val, ((typeof max != "number") || max > 0) ? max : 0);
  10127. isTooMuch = (typeof max == "number") && max > 0;
  10128. }
  10129. return isTooLittle || isTooMuch;
  10130. },
  10131. _isValidSubset: function(){
  10132. // summary:
  10133. // Overrides `dijit.form.ValidationTextBox._isValidSubset`.
  10134. // Returns true if the input is syntactically valid, and either within
  10135. // range or could be made in range by more typing.
  10136. return this.inherited(arguments) && !this._isDefinitelyOutOfRange();
  10137. },
  10138. isValid: function(/*Boolean*/ isFocused){
  10139. // Overrides dijit.form.ValidationTextBox.isValid to check that the value is also in range.
  10140. return this.inherited(arguments) &&
  10141. ((this._isEmpty(this.textbox.value) && !this.required) || this.isInRange(isFocused)); // Boolean
  10142. },
  10143. getErrorMessage: function(/*Boolean*/ isFocused){
  10144. // Overrides dijit.form.ValidationTextBox.getErrorMessage to print "out of range" message if appropriate
  10145. var v = this.get('value');
  10146. if(v !== null && v !== '' && v !== undefined && (typeof v != "number" || !isNaN(v)) && !this.isInRange(isFocused)){ // don't check isInRange w/o a real value
  10147. return this.rangeMessage; // String
  10148. }
  10149. return this.inherited(arguments);
  10150. },
  10151. postMixInProperties: function(){
  10152. this.inherited(arguments);
  10153. if(!this.rangeMessage){
  10154. this.messages = i18n.getLocalization("dijit.form", "validate", this.lang);
  10155. this.rangeMessage = this.messages.rangeMessage;
  10156. }
  10157. },
  10158. _setConstraintsAttr: function(/*Object*/ constraints){
  10159. this.inherited(arguments);
  10160. if(this.focusNode){ // not set when called from postMixInProperties
  10161. if(this.constraints.min !== undefined){
  10162. this.focusNode.setAttribute("aria-valuemin", this.constraints.min);
  10163. }else{
  10164. this.focusNode.removeAttribute("aria-valuemin");
  10165. }
  10166. if(this.constraints.max !== undefined){
  10167. this.focusNode.setAttribute("aria-valuemax", this.constraints.max);
  10168. }else{
  10169. this.focusNode.removeAttribute("aria-valuemax");
  10170. }
  10171. }
  10172. },
  10173. _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange){
  10174. // summary:
  10175. // Hook so set('value', ...) works.
  10176. this.focusNode.setAttribute("aria-valuenow", value);
  10177. this.inherited(arguments);
  10178. },
  10179. applyTextDir: function(/*===== element, text =====*/){
  10180. // summary:
  10181. // The function overridden in the _BidiSupport module,
  10182. // originally used for setting element.dir according to this.textDir.
  10183. // In this case does nothing.
  10184. // element: Object
  10185. // text: String
  10186. // tags:
  10187. // protected.
  10188. }
  10189. });
  10190. });
  10191. },
  10192. 'dijit/_editor/RichText':function(){
  10193. define("dijit/_editor/RichText", [
  10194. "dojo/_base/array", // array.forEach array.indexOf array.some
  10195. "dojo/_base/config", // config
  10196. "dojo/_base/declare", // declare
  10197. "dojo/_base/Deferred", // Deferred
  10198. "dojo/dom", // dom.byId
  10199. "dojo/dom-attr", // domAttr.set or get
  10200. "dojo/dom-class", // domClass.add domClass.remove
  10201. "dojo/dom-construct", // domConstruct.create domConstruct.destroy domConstruct.place
  10202. "dojo/dom-geometry", // domGeometry.position
  10203. "dojo/dom-style", // domStyle.getComputedStyle domStyle.set
  10204. "dojo/_base/event", // event.stop
  10205. "dojo/_base/kernel", // kernel.deprecated
  10206. "dojo/keys", // keys.BACKSPACE keys.TAB
  10207. "dojo/_base/lang", // lang.clone lang.hitch lang.isArray lang.isFunction lang.isString lang.trim
  10208. "dojo/on", // on()
  10209. "dojo/query", // query
  10210. "dojo/ready", // ready
  10211. "dojo/_base/sniff", // has("ie") has("mozilla") has("opera") has("safari") has("webkit")
  10212. "dojo/topic", // topic.publish() (publish)
  10213. "dojo/_base/unload", // unload
  10214. "dojo/_base/url", // url
  10215. "dojo/_base/window", // win.body win.doc.body.focus win.doc.createElement win.global.location win.withGlobal
  10216. "../_Widget",
  10217. "../_CssStateMixin",
  10218. "./selection",
  10219. "./range",
  10220. "./html",
  10221. "../focus",
  10222. ".." // dijit._scopeName
  10223. ], function(array, config, declare, Deferred, dom, domAttr, domClass, domConstruct, domGeometry, domStyle,
  10224. event, kernel, keys, lang, on, query, ready, has, topic, unload, _Url, win,
  10225. _Widget, _CssStateMixin, selectionapi, rangeapi, htmlapi, focus, dijit){
  10226. /*=====
  10227. var _Widget = dijit._Widget;
  10228. var _CssStateMixin = dijit._CssStateMixin;
  10229. =====*/
  10230. // module:
  10231. // dijit/_editor/RichText
  10232. // summary:
  10233. // dijit._editor.RichText is the core of dijit.Editor, which provides basic
  10234. // WYSIWYG editing features.
  10235. // if you want to allow for rich text saving with back/forward actions, you must add a text area to your page with
  10236. // the id==dijit._scopeName + "._editor.RichText.value" (typically "dijit._editor.RichText.value). For example,
  10237. // something like this will work:
  10238. //
  10239. // <textarea id="dijit._editor.RichText.value" style="display:none;position:absolute;top:-100px;left:-100px;height:3px;width:3px;overflow:hidden;"></textarea>
  10240. //
  10241. var RichText = declare("dijit._editor.RichText", [_Widget, _CssStateMixin], {
  10242. // summary:
  10243. // dijit._editor.RichText is the core of dijit.Editor, which provides basic
  10244. // WYSIWYG editing features.
  10245. //
  10246. // description:
  10247. // dijit._editor.RichText is the core of dijit.Editor, which provides basic
  10248. // WYSIWYG editing features. It also encapsulates the differences
  10249. // of different js engines for various browsers. Do not use this widget
  10250. // with an HTML &lt;TEXTAREA&gt; tag, since the browser unescapes XML escape characters,
  10251. // like &lt;. This can have unexpected behavior and lead to security issues
  10252. // such as scripting attacks.
  10253. //
  10254. // tags:
  10255. // private
  10256. constructor: function(params){
  10257. // contentPreFilters: Function(String)[]
  10258. // Pre content filter function register array.
  10259. // these filters will be executed before the actual
  10260. // editing area gets the html content.
  10261. this.contentPreFilters = [];
  10262. // contentPostFilters: Function(String)[]
  10263. // post content filter function register array.
  10264. // These will be used on the resulting html
  10265. // from contentDomPostFilters. The resulting
  10266. // content is the final html (returned by getValue()).
  10267. this.contentPostFilters = [];
  10268. // contentDomPreFilters: Function(DomNode)[]
  10269. // Pre content dom filter function register array.
  10270. // These filters are applied after the result from
  10271. // contentPreFilters are set to the editing area.
  10272. this.contentDomPreFilters = [];
  10273. // contentDomPostFilters: Function(DomNode)[]
  10274. // Post content dom filter function register array.
  10275. // These filters are executed on the editing area dom.
  10276. // The result from these will be passed to contentPostFilters.
  10277. this.contentDomPostFilters = [];
  10278. // editingAreaStyleSheets: dojo._URL[]
  10279. // array to store all the stylesheets applied to the editing area
  10280. this.editingAreaStyleSheets = [];
  10281. // Make a copy of this.events before we start writing into it, otherwise we
  10282. // will modify the prototype which leads to bad things on pages w/multiple editors
  10283. this.events = [].concat(this.events);
  10284. this._keyHandlers = {};
  10285. if(params && lang.isString(params.value)){
  10286. this.value = params.value;
  10287. }
  10288. this.onLoadDeferred = new Deferred();
  10289. },
  10290. baseClass: "dijitEditor",
  10291. // inheritWidth: Boolean
  10292. // whether to inherit the parent's width or simply use 100%
  10293. inheritWidth: false,
  10294. // focusOnLoad: [deprecated] Boolean
  10295. // Focus into this widget when the page is loaded
  10296. focusOnLoad: false,
  10297. // name: String?
  10298. // Specifies the name of a (hidden) <textarea> node on the page that's used to save
  10299. // the editor content on page leave. Used to restore editor contents after navigating
  10300. // to a new page and then hitting the back button.
  10301. name: "",
  10302. // styleSheets: [const] String
  10303. // semicolon (";") separated list of css files for the editing area
  10304. styleSheets: "",
  10305. // height: String
  10306. // Set height to fix the editor at a specific height, with scrolling.
  10307. // By default, this is 300px. If you want to have the editor always
  10308. // resizes to accommodate the content, use AlwaysShowToolbar plugin
  10309. // and set height="". If this editor is used within a layout widget,
  10310. // set height="100%".
  10311. height: "300px",
  10312. // minHeight: String
  10313. // The minimum height that the editor should have.
  10314. minHeight: "1em",
  10315. // isClosed: [private] Boolean
  10316. isClosed: true,
  10317. // isLoaded: [private] Boolean
  10318. isLoaded: false,
  10319. // _SEPARATOR: [private] String
  10320. // Used to concat contents from multiple editors into a single string,
  10321. // so they can be saved into a single <textarea> node. See "name" attribute.
  10322. _SEPARATOR: "@@**%%__RICHTEXTBOUNDRY__%%**@@",
  10323. // _NAME_CONTENT_SEP: [private] String
  10324. // USed to separate name from content. Just a colon isn't safe.
  10325. _NAME_CONTENT_SEP: "@@**%%:%%**@@",
  10326. // onLoadDeferred: [readonly] dojo.Deferred
  10327. // Deferred which is fired when the editor finishes loading.
  10328. // Call myEditor.onLoadDeferred.then(callback) it to be informed
  10329. // when the rich-text area initialization is finalized.
  10330. onLoadDeferred: null,
  10331. // isTabIndent: Boolean
  10332. // Make tab key and shift-tab indent and outdent rather than navigating.
  10333. // Caution: sing this makes web pages inaccessible to users unable to use a mouse.
  10334. isTabIndent: false,
  10335. // disableSpellCheck: [const] Boolean
  10336. // When true, disables the browser's native spell checking, if supported.
  10337. // Works only in Firefox.
  10338. disableSpellCheck: false,
  10339. postCreate: function(){
  10340. if("textarea" === this.domNode.tagName.toLowerCase()){
  10341. console.warn("RichText should not be used with the TEXTAREA tag. See dijit._editor.RichText docs.");
  10342. }
  10343. // Push in the builtin filters now, making them the first executed, but not over-riding anything
  10344. // users passed in. See: #6062
  10345. this.contentPreFilters = [lang.hitch(this, "_preFixUrlAttributes")].concat(this.contentPreFilters);
  10346. if(has("mozilla")){
  10347. this.contentPreFilters = [this._normalizeFontStyle].concat(this.contentPreFilters);
  10348. this.contentPostFilters = [this._removeMozBogus].concat(this.contentPostFilters);
  10349. }
  10350. if(has("webkit")){
  10351. // Try to clean up WebKit bogus artifacts. The inserted classes
  10352. // made by WebKit sometimes messes things up.
  10353. this.contentPreFilters = [this._removeWebkitBogus].concat(this.contentPreFilters);
  10354. this.contentPostFilters = [this._removeWebkitBogus].concat(this.contentPostFilters);
  10355. }
  10356. if(has("ie") || has("trident")){
  10357. // IE generates <strong> and <em> but we want to normalize to <b> and <i>
  10358. // Still happens in IE11!
  10359. this.contentPostFilters = [this._normalizeFontStyle].concat(this.contentPostFilters);
  10360. this.contentDomPostFilters = [lang.hitch(this, this._stripBreakerNodes)].concat(this.contentDomPostFilters);
  10361. }
  10362. this.inherited(arguments);
  10363. topic.publish(dijit._scopeName + "._editor.RichText::init", this);
  10364. this.open();
  10365. this.setupDefaultShortcuts();
  10366. },
  10367. setupDefaultShortcuts: function(){
  10368. // summary:
  10369. // Add some default key handlers
  10370. // description:
  10371. // Overwrite this to setup your own handlers. The default
  10372. // implementation does not use Editor commands, but directly
  10373. // executes the builtin commands within the underlying browser
  10374. // support.
  10375. // tags:
  10376. // protected
  10377. var exec = lang.hitch(this, function(cmd, arg){
  10378. return function(){
  10379. return !this.execCommand(cmd,arg);
  10380. };
  10381. });
  10382. var ctrlKeyHandlers = {
  10383. b: exec("bold"),
  10384. i: exec("italic"),
  10385. u: exec("underline"),
  10386. a: exec("selectall"),
  10387. s: function(){ this.save(true); },
  10388. m: function(){ this.isTabIndent = !this.isTabIndent; },
  10389. "1": exec("formatblock", "h1"),
  10390. "2": exec("formatblock", "h2"),
  10391. "3": exec("formatblock", "h3"),
  10392. "4": exec("formatblock", "h4"),
  10393. "\\": exec("insertunorderedlist")
  10394. };
  10395. if(!has("ie")){
  10396. ctrlKeyHandlers.Z = exec("redo"); //FIXME: undo?
  10397. }
  10398. var key;
  10399. for(key in ctrlKeyHandlers){
  10400. this.addKeyHandler(key, true, false, ctrlKeyHandlers[key]);
  10401. }
  10402. },
  10403. // events: [private] String[]
  10404. // events which should be connected to the underlying editing area
  10405. events: ["onKeyPress", "onKeyDown", "onKeyUp"], // onClick handled specially
  10406. // captureEvents: [deprecated] String[]
  10407. // Events which should be connected to the underlying editing
  10408. // area, events in this array will be addListener with
  10409. // capture=true.
  10410. // TODO: looking at the code I don't see any distinction between events and captureEvents,
  10411. // so get rid of this for 2.0 if not sooner
  10412. captureEvents: [],
  10413. _editorCommandsLocalized: false,
  10414. _localizeEditorCommands: function(){
  10415. // summary:
  10416. // When IE is running in a non-English locale, the API actually changes,
  10417. // so that we have to say (for example) danraku instead of p (for paragraph).
  10418. // Handle that here.
  10419. // tags:
  10420. // private
  10421. if(RichText._editorCommandsLocalized){
  10422. // Use the already generate cache of mappings.
  10423. this._local2NativeFormatNames = RichText._local2NativeFormatNames;
  10424. this._native2LocalFormatNames = RichText._native2LocalFormatNames;
  10425. return;
  10426. }
  10427. RichText._editorCommandsLocalized = true;
  10428. RichText._local2NativeFormatNames = {};
  10429. RichText._native2LocalFormatNames = {};
  10430. this._local2NativeFormatNames = RichText._local2NativeFormatNames;
  10431. this._native2LocalFormatNames = RichText._native2LocalFormatNames;
  10432. //in IE, names for blockformat is locale dependent, so we cache the values here
  10433. //put p after div, so if IE returns Normal, we show it as paragraph
  10434. //We can distinguish p and div if IE returns Normal, however, in order to detect that,
  10435. //we have to call this.document.selection.createRange().parentElement() or such, which
  10436. //could slow things down. Leave it as it is for now
  10437. var formats = ['div', 'p', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'ul', 'address'];
  10438. var localhtml = "", format, i=0;
  10439. while((format=formats[i++])){
  10440. //append a <br> after each element to separate the elements more reliably
  10441. if(format.charAt(1) !== 'l'){
  10442. localhtml += "<"+format+"><span>content</span></"+format+"><br/>";
  10443. }else{
  10444. localhtml += "<"+format+"><li>content</li></"+format+"><br/>";
  10445. }
  10446. }
  10447. // queryCommandValue returns empty if we hide editNode, so move it out of screen temporary
  10448. // Also, IE9 does weird stuff unless we do it inside the editor iframe.
  10449. var style = { position: "absolute", top: "0px", zIndex: 10, opacity: 0.01 };
  10450. var div = domConstruct.create('div', {style: style, innerHTML: localhtml});
  10451. win.body().appendChild(div);
  10452. // IE9 has a timing issue with doing this right after setting
  10453. // the inner HTML, so put a delay in.
  10454. var inject = lang.hitch(this, function(){
  10455. var node = div.firstChild;
  10456. while(node){
  10457. try{
  10458. selectionapi.selectElement(node.firstChild);
  10459. var nativename = node.tagName.toLowerCase();
  10460. this._local2NativeFormatNames[nativename] = document.queryCommandValue("formatblock");
  10461. this._native2LocalFormatNames[this._local2NativeFormatNames[nativename]] = nativename;
  10462. node = node.nextSibling.nextSibling;
  10463. //console.log("Mapped: ", nativename, " to: ", this._local2NativeFormatNames[nativename]);
  10464. }catch(e){ /*Sqelch the occasional IE9 error */ }
  10465. }
  10466. div.parentNode.removeChild(div);
  10467. div.innerHTML = "";
  10468. });
  10469. setTimeout(inject, 0);
  10470. },
  10471. open: function(/*DomNode?*/ element){
  10472. // summary:
  10473. // Transforms the node referenced in this.domNode into a rich text editing
  10474. // node.
  10475. // description:
  10476. // Sets up the editing area asynchronously. This will result in
  10477. // the creation and replacement with an iframe.
  10478. // tags:
  10479. // private
  10480. if(!this.onLoadDeferred || this.onLoadDeferred.fired >= 0){
  10481. this.onLoadDeferred = new Deferred();
  10482. }
  10483. if(!this.isClosed){ this.close(); }
  10484. topic.publish(dijit._scopeName + "._editor.RichText::open", this);
  10485. if(arguments.length === 1 && element.nodeName){ // else unchanged
  10486. this.domNode = element;
  10487. }
  10488. var dn = this.domNode;
  10489. // "html" will hold the innerHTML of the srcNodeRef and will be used to
  10490. // initialize the editor.
  10491. var html;
  10492. if(lang.isString(this.value)){
  10493. // Allow setting the editor content programmatically instead of
  10494. // relying on the initial content being contained within the target
  10495. // domNode.
  10496. html = this.value;
  10497. delete this.value;
  10498. dn.innerHTML = "";
  10499. }else if(dn.nodeName && dn.nodeName.toLowerCase() == "textarea"){
  10500. // if we were created from a textarea, then we need to create a
  10501. // new editing harness node.
  10502. var ta = (this.textarea = dn);
  10503. this.name = ta.name;
  10504. html = ta.value;
  10505. dn = this.domNode = win.doc.createElement("div");
  10506. dn.setAttribute('widgetId', this.id);
  10507. ta.removeAttribute('widgetId');
  10508. dn.cssText = ta.cssText;
  10509. dn.className += " " + ta.className;
  10510. domConstruct.place(dn, ta, "before");
  10511. var tmpFunc = lang.hitch(this, function(){
  10512. //some browsers refuse to submit display=none textarea, so
  10513. //move the textarea off screen instead
  10514. domStyle.set(ta, {
  10515. display: "block",
  10516. position: "absolute",
  10517. top: "-1000px"
  10518. });
  10519. if(has("ie")){ //nasty IE bug: abnormal formatting if overflow is not hidden
  10520. var s = ta.style;
  10521. this.__overflow = s.overflow;
  10522. s.overflow = "hidden";
  10523. }
  10524. });
  10525. if(has("ie")){
  10526. setTimeout(tmpFunc, 10);
  10527. }else{
  10528. tmpFunc();
  10529. }
  10530. if(ta.form){
  10531. var resetValue = ta.value;
  10532. this.reset = function(){
  10533. var current = this.getValue();
  10534. if(current !== resetValue){
  10535. this.replaceValue(resetValue);
  10536. }
  10537. };
  10538. on(ta.form, "submit", lang.hitch(this, function(){
  10539. // Copy value to the <textarea> so it gets submitted along with form.
  10540. // FIXME: should we be calling close() here instead?
  10541. domAttr.set(ta, 'disabled', this.disabled); // don't submit the value if disabled
  10542. ta.value = this.getValue();
  10543. }));
  10544. }
  10545. }else{
  10546. html = htmlapi.getChildrenHtml(dn);
  10547. dn.innerHTML = "";
  10548. }
  10549. this.value = html;
  10550. // If we're a list item we have to put in a blank line to force the
  10551. // bullet to nicely align at the top of text
  10552. if(dn.nodeName && dn.nodeName === "LI"){
  10553. dn.innerHTML = " <br>";
  10554. }
  10555. // Construct the editor div structure.
  10556. this.header = dn.ownerDocument.createElement("div");
  10557. dn.appendChild(this.header);
  10558. this.editingArea = dn.ownerDocument.createElement("div");
  10559. dn.appendChild(this.editingArea);
  10560. this.footer = dn.ownerDocument.createElement("div");
  10561. dn.appendChild(this.footer);
  10562. if(!this.name){
  10563. this.name = this.id + "_AUTOGEN";
  10564. }
  10565. // User has pressed back/forward button so we lost the text in the editor, but it's saved
  10566. // in a hidden <textarea> (which contains the data for all the editors on this page),
  10567. // so get editor value from there
  10568. if(this.name !== "" && (!config["useXDomain"] || config["allowXdRichTextSave"])){
  10569. var saveTextarea = dom.byId(dijit._scopeName + "._editor.RichText.value");
  10570. if(saveTextarea && saveTextarea.value !== ""){
  10571. var datas = saveTextarea.value.split(this._SEPARATOR), i=0, dat;
  10572. while((dat=datas[i++])){
  10573. var data = dat.split(this._NAME_CONTENT_SEP);
  10574. if(data[0] === this.name){
  10575. html = data[1];
  10576. datas = datas.splice(i, 1);
  10577. saveTextarea.value = datas.join(this._SEPARATOR);
  10578. break;
  10579. }
  10580. }
  10581. }
  10582. if(!RichText._globalSaveHandler){
  10583. RichText._globalSaveHandler = {};
  10584. unload.addOnUnload(function(){
  10585. var id;
  10586. for(id in RichText._globalSaveHandler){
  10587. var f = RichText._globalSaveHandler[id];
  10588. if(lang.isFunction(f)){
  10589. f();
  10590. }
  10591. }
  10592. });
  10593. }
  10594. RichText._globalSaveHandler[this.id] = lang.hitch(this, "_saveContent");
  10595. }
  10596. this.isClosed = false;
  10597. var ifr = (this.editorObject = this.iframe = win.doc.createElement('iframe'));
  10598. ifr.id = this.id+"_iframe";
  10599. ifr.style.border = "none";
  10600. ifr.style.width = "100%";
  10601. if(this._layoutMode){
  10602. // iframe should be 100% height, thus getting it's height from surrounding
  10603. // <div> (which has the correct height set by Editor)
  10604. ifr.style.height = "100%";
  10605. }else{
  10606. if(has("ie") >= 7){
  10607. if(this.height){
  10608. ifr.style.height = this.height;
  10609. }
  10610. if(this.minHeight){
  10611. ifr.style.minHeight = this.minHeight;
  10612. }
  10613. }else{
  10614. ifr.style.height = this.height ? this.height : this.minHeight;
  10615. }
  10616. }
  10617. ifr.frameBorder = 0;
  10618. ifr._loadFunc = lang.hitch( this, function(w){
  10619. this.window = w;
  10620. this.document = w.document;
  10621. if(has("ie")){
  10622. this._localizeEditorCommands();
  10623. }
  10624. // Do final setup and set initial contents of editor
  10625. this.onLoad(html);
  10626. });
  10627. // Attach iframe to document, and set the initial (blank) content.
  10628. var src = this._getIframeDocTxt().replace(/\\/g, "\\\\").replace(/'/g, "\\'"),
  10629. s;
  10630. // IE10 and earlier will throw an "Access is denied" error when attempting to access the parent frame if
  10631. // document.domain has been set, unless the child frame also has the same document.domain set. The child frame
  10632. // can only set document.domain while the document is being constructed using open/write/close; attempting to
  10633. // set it later results in a different "This method can't be used in this context" error. See #17529
  10634. if (has("ie") < 11) {
  10635. s = 'javascript:document.open();try{parent.window;}catch(e){document.domain="' + document.domain + '";}' +
  10636. 'document.write(\'' + src + '\');document.close()';
  10637. }
  10638. else {
  10639. s = "javascript: '" + src + "'";
  10640. }
  10641. if(has("ie") == 9){
  10642. // On IE9, attach to document before setting the content, to avoid problem w/iframe running in
  10643. // wrong security context, see #16633.
  10644. this.editingArea.appendChild(ifr);
  10645. ifr.src = s;
  10646. }else{
  10647. // For other browsers, set src first, especially for IE6/7 where attaching first gives a warning on
  10648. // https:// about "this page contains secure and insecure items, do you want to view both?"
  10649. ifr.setAttribute('src', s);
  10650. this.editingArea.appendChild(ifr);
  10651. }
  10652. if(has("safari") <= 4){
  10653. src = ifr.getAttribute("src");
  10654. if(!src || src.indexOf("javascript") === -1){
  10655. // Safari 4 and earlier sometimes act oddly
  10656. // So we have to set it again.
  10657. setTimeout(function(){ifr.setAttribute('src', s);},0);
  10658. }
  10659. }
  10660. // TODO: this is a guess at the default line-height, kinda works
  10661. if(dn.nodeName === "LI"){
  10662. dn.lastChild.style.marginTop = "-1.2em";
  10663. }
  10664. domClass.add(this.domNode, this.baseClass);
  10665. },
  10666. //static cache variables shared among all instance of this class
  10667. _local2NativeFormatNames: {},
  10668. _native2LocalFormatNames: {},
  10669. _getIframeDocTxt: function(){
  10670. // summary:
  10671. // Generates the boilerplate text of the document inside the iframe (ie, <html><head>...</head><body/></html>).
  10672. // Editor content (if not blank) should be added afterwards.
  10673. // tags:
  10674. // private
  10675. var _cs = domStyle.getComputedStyle(this.domNode);
  10676. // The contents inside of <body>. The real contents are set later via a call to setValue().
  10677. // In auto-expand mode, need a wrapper div for AlwaysShowToolbar plugin to correctly
  10678. // expand/contract the editor as the content changes.
  10679. var html = "<div id='dijitEditorBody'></div>";
  10680. var font = [ _cs.fontWeight, _cs.fontSize, _cs.fontFamily ].join(" ");
  10681. // line height is tricky - applying a units value will mess things up.
  10682. // if we can't get a non-units value, bail out.
  10683. var lineHeight = _cs.lineHeight;
  10684. if(lineHeight.indexOf("px") >= 0){
  10685. lineHeight = parseFloat(lineHeight)/parseFloat(_cs.fontSize);
  10686. // console.debug(lineHeight);
  10687. }else if(lineHeight.indexOf("em")>=0){
  10688. lineHeight = parseFloat(lineHeight);
  10689. }else{
  10690. // If we can't get a non-units value, just default
  10691. // it to the CSS spec default of 'normal'. Seems to
  10692. // work better, esp on IE, than '1.0'
  10693. lineHeight = "normal";
  10694. }
  10695. var userStyle = "";
  10696. var self = this;
  10697. this.style.replace(/(^|;)\s*(line-|font-?)[^;]+/ig, function(match){
  10698. match = match.replace(/^;/ig,"") + ';';
  10699. var s = match.split(":")[0];
  10700. if(s){
  10701. s = lang.trim(s);
  10702. s = s.toLowerCase();
  10703. var i;
  10704. var sC = "";
  10705. for(i = 0; i < s.length; i++){
  10706. var c = s.charAt(i);
  10707. switch(c){
  10708. case "-":
  10709. i++;
  10710. c = s.charAt(i).toUpperCase();
  10711. default:
  10712. sC += c;
  10713. }
  10714. }
  10715. domStyle.set(self.domNode, sC, "");
  10716. }
  10717. userStyle += match + ';';
  10718. });
  10719. // need to find any associated label element and update iframe document title
  10720. var label=query('label[for="'+this.id+'"]');
  10721. return [
  10722. this.isLeftToRight() ? "<html>\n<head>\n" : "<html dir='rtl'>\n<head>\n",
  10723. (has("mozilla") && label.length ? "<title>" + label[0].innerHTML + "</title>\n" : ""),
  10724. "<meta http-equiv='Content-Type' content='text/html'>\n",
  10725. "<style>\n",
  10726. "\tbody,html {\n",
  10727. "\t\tbackground:transparent;\n",
  10728. "\t\tpadding: 1px 0 0 0;\n",
  10729. "\t\tmargin: -1px 0 0 0;\n", // remove extraneous vertical scrollbar on safari and firefox
  10730. "\t}\n",
  10731. "\tbody,html,#dijitEditorBody { outline: none; }",
  10732. // Set <body> to expand to full size of editor, so clicking anywhere will work.
  10733. // Except in auto-expand mode, in which case the editor expands to the size of <body>.
  10734. // Also determine how scrollers should be applied. In autoexpand mode (height = "") no scrollers on y at all.
  10735. // But in fixed height mode we want both x/y scrollers.
  10736. // Scrollers go on <body> since it's been set to height: 100%.
  10737. "html { height: 100%; width: 100%; overflow: hidden; }\n", // scroll bar is on #dijitEditorBody, shouldn't be on <html>
  10738. this.height ? "\tbody,#dijitEditorBody { height: 100%; width: 100%; overflow: auto; }\n" :
  10739. "\tbody,#dijitEditorBody { min-height: " + this.minHeight + "; width: 100%; overflow-x: auto; overflow-y: hidden; }\n",
  10740. // TODO: left positioning will cause contents to disappear out of view
  10741. // if it gets too wide for the visible area
  10742. "\tbody{\n",
  10743. "\t\ttop:0px;\n",
  10744. "\t\tleft:0px;\n",
  10745. "\t\tright:0px;\n",
  10746. "\t\tfont:", font, ";\n",
  10747. ((this.height||has("opera")) ? "" : "\t\tposition: fixed;\n"),
  10748. "\t\tline-height:", lineHeight,";\n",
  10749. "\t}\n",
  10750. "\tp{ margin: 1em 0; }\n",
  10751. "\tli > ul:-moz-first-node, li > ol:-moz-first-node{ padding-top: 1.2em; }\n",
  10752. // Can't set min-height in IE>=9, it puts layout on li, which puts move/resize handles.
  10753. (has("ie") || has("trident") ? "" : "\tli{ min-height:1.2em; }\n"),
  10754. "</style>\n",
  10755. this._applyEditingAreaStyleSheets(),"\n",
  10756. "</head>\n<body ",
  10757. "</head>\n<body role='main' ",
  10758. // Onload handler fills in real editor content.
  10759. // On IE9, sometimes onload is called twice, and the first time frameElement is null (test_FullScreen.html)
  10760. "onload='frameElement && frameElement._loadFunc(window,document)' ",
  10761. "style='"+userStyle+"'>", html, "</body>\n</html>"
  10762. ].join(""); // String
  10763. },
  10764. _applyEditingAreaStyleSheets: function(){
  10765. // summary:
  10766. // apply the specified css files in styleSheets
  10767. // tags:
  10768. // private
  10769. var files = [];
  10770. if(this.styleSheets){
  10771. files = this.styleSheets.split(';');
  10772. this.styleSheets = '';
  10773. }
  10774. //empty this.editingAreaStyleSheets here, as it will be filled in addStyleSheet
  10775. files = files.concat(this.editingAreaStyleSheets);
  10776. this.editingAreaStyleSheets = [];
  10777. var text='', i=0, url;
  10778. while((url=files[i++])){
  10779. var abstring = (new _Url(win.global.location, url)).toString();
  10780. this.editingAreaStyleSheets.push(abstring);
  10781. text += '<link rel="stylesheet" type="text/css" href="'+abstring+'"/>';
  10782. }
  10783. return text;
  10784. },
  10785. addStyleSheet: function(/*dojo._Url*/ uri){
  10786. // summary:
  10787. // add an external stylesheet for the editing area
  10788. // uri:
  10789. // A dojo.uri.Uri pointing to the url of the external css file
  10790. var url=uri.toString();
  10791. //if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe
  10792. if(url.charAt(0) === '.' || (url.charAt(0) !== '/' && !uri.host)){
  10793. url = (new _Url(win.global.location, url)).toString();
  10794. }
  10795. if(array.indexOf(this.editingAreaStyleSheets, url) > -1){
  10796. // console.debug("dijit._editor.RichText.addStyleSheet: Style sheet "+url+" is already applied");
  10797. return;
  10798. }
  10799. this.editingAreaStyleSheets.push(url);
  10800. this.onLoadDeferred.addCallback(lang.hitch(this, function(){
  10801. if(this.document.createStyleSheet){ //IE
  10802. this.document.createStyleSheet(url);
  10803. }else{ //other browser
  10804. var head = this.document.getElementsByTagName("head")[0];
  10805. var stylesheet = this.document.createElement("link");
  10806. stylesheet.rel="stylesheet";
  10807. stylesheet.type="text/css";
  10808. stylesheet.href=url;
  10809. head.appendChild(stylesheet);
  10810. }
  10811. }));
  10812. },
  10813. removeStyleSheet: function(/*dojo._Url*/ uri){
  10814. // summary:
  10815. // remove an external stylesheet for the editing area
  10816. var url=uri.toString();
  10817. //if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe
  10818. if(url.charAt(0) === '.' || (url.charAt(0) !== '/' && !uri.host)){
  10819. url = (new _Url(win.global.location, url)).toString();
  10820. }
  10821. var index = array.indexOf(this.editingAreaStyleSheets, url);
  10822. if(index === -1){
  10823. // console.debug("dijit._editor.RichText.removeStyleSheet: Style sheet "+url+" has not been applied");
  10824. return;
  10825. }
  10826. delete this.editingAreaStyleSheets[index];
  10827. win.withGlobal(this.window,'query', dojo, ['link:[href="'+url+'"]']).orphan();
  10828. },
  10829. // disabled: Boolean
  10830. // The editor is disabled; the text cannot be changed.
  10831. disabled: false,
  10832. _mozSettingProps: {'styleWithCSS':false},
  10833. _setDisabledAttr: function(/*Boolean*/ value){
  10834. value = !!value;
  10835. this._set("disabled", value);
  10836. if(!this.isLoaded){
  10837. return;
  10838. } // this method requires init to be complete
  10839. var preventIEfocus = has("ie") && (this.isLoaded || !this.focusOnLoad);
  10840. if(preventIEfocus){
  10841. this.editNode.unselectable = "on";
  10842. }
  10843. this.editNode.contentEditable = !value;
  10844. this.editNode.tabIndex = value ? "-1" : this.tabIndex;
  10845. if(preventIEfocus){
  10846. this.defer(function(){
  10847. if(this.editNode){ // guard in case widget destroyed before timeout
  10848. this.editNode.unselectable = "off";
  10849. }
  10850. });
  10851. }
  10852. if(has("mozilla") && !value && this._mozSettingProps){
  10853. var ps = this._mozSettingProps;
  10854. var n;
  10855. for(n in ps){
  10856. if(ps.hasOwnProperty(n)){
  10857. try{
  10858. this.document.execCommand(n, false, ps[n]);
  10859. }catch(e2){
  10860. }
  10861. }
  10862. }
  10863. }
  10864. this._disabledOK = true;
  10865. },
  10866. /* Event handlers
  10867. *****************/
  10868. onLoad: function(/*String*/ html){
  10869. // summary:
  10870. // Handler after the iframe finishes loading.
  10871. // html: String
  10872. // Editor contents should be set to this value
  10873. // tags:
  10874. // protected
  10875. // TODO: rename this to _onLoad, make empty public onLoad() method, deprecate/make protected onLoadDeferred handler?
  10876. if(!this.window.__registeredWindow){
  10877. this.window.__registeredWindow = true;
  10878. this._iframeRegHandle = focus.registerIframe(this.iframe);
  10879. }
  10880. // there's a wrapper div around the content, see _getIframeDocTxt().
  10881. this.editNode = this.document.body.firstChild;
  10882. var _this = this;
  10883. // Helper code so IE and FF skip over focusing on the <iframe> and just focus on the inner <div>.
  10884. // See #4996 IE wants to focus the BODY tag.
  10885. this.beforeIframeNode = domConstruct.place("<div tabIndex=-1></div>", this.iframe, "before");
  10886. this.afterIframeNode = domConstruct.place("<div tabIndex=-1></div>", this.iframe, "after");
  10887. this.iframe.onfocus = this.document.onfocus = function(){
  10888. _this.editNode.focus();
  10889. };
  10890. this.focusNode = this.editNode; // for InlineEditBox
  10891. var events = this.events.concat(this.captureEvents);
  10892. var ap = this.iframe ? this.document : this.editNode;
  10893. array.forEach(events, function(item){
  10894. this.connect(ap, item.toLowerCase(), item);
  10895. }, this);
  10896. this.connect(ap, "onmouseup", "onClick"); // mouseup in the margin does not generate an onclick event
  10897. if(has("ie")){ // IE contentEditable
  10898. this.connect(this.document, "onmousedown", "_onIEMouseDown"); // #4996 fix focus
  10899. // give the node Layout on IE
  10900. // TODO: this may no longer be needed, since we've reverted IE to using an iframe,
  10901. // not contentEditable. Removing it would also probably remove the need for creating
  10902. // the extra <div> in _getIframeDocTxt()
  10903. this.editNode.style.zoom = 1.0;
  10904. }else{
  10905. this.connect(this.document, "onmousedown", function(){
  10906. // Clear the moveToStart focus, as mouse
  10907. // down will set cursor point. Required to properly
  10908. // work with selection/position driven plugins and clicks in
  10909. // the window. refs: #10678
  10910. delete this._cursorToStart;
  10911. });
  10912. }
  10913. if(has("webkit")){
  10914. //WebKit sometimes doesn't fire right on selections, so the toolbar
  10915. //doesn't update right. Therefore, help it out a bit with an additional
  10916. //listener. A mouse up will typically indicate a display change, so fire this
  10917. //and get the toolbar to adapt. Reference: #9532
  10918. this._webkitListener = this.connect(this.document, "onmouseup", "onDisplayChanged");
  10919. this.connect(this.document, "onmousedown", function(e){
  10920. var t = e.target;
  10921. if(t && (t === this.document.body || t === this.document)){
  10922. // Since WebKit uses the inner DIV, we need to check and set position.
  10923. // See: #12024 as to why the change was made.
  10924. setTimeout(lang.hitch(this, "placeCursorAtEnd"), 0);
  10925. }
  10926. });
  10927. }
  10928. if(has("ie")){
  10929. // Try to make sure 'hidden' elements aren't visible in edit mode (like browsers other than IE
  10930. // do). See #9103
  10931. try{
  10932. this.document.execCommand('RespectVisibilityInDesign', true, null);
  10933. }catch(e){/* squelch */}
  10934. }
  10935. this.isLoaded = true;
  10936. this.set('disabled', this.disabled); // initialize content to editable (or not)
  10937. // Note that setValue() call will only work after isLoaded is set to true (above)
  10938. // Set up a function to allow delaying the setValue until a callback is fired
  10939. // This ensures extensions like dijit.Editor have a way to hold the value set
  10940. // until plugins load (and do things like register filters).
  10941. var setContent = lang.hitch(this, function(){
  10942. this.setValue(html);
  10943. if(this.onLoadDeferred){
  10944. this.onLoadDeferred.callback(true);
  10945. }
  10946. this.onDisplayChanged();
  10947. if(this.focusOnLoad){
  10948. // after the document loads, then set focus after updateInterval expires so that
  10949. // onNormalizedDisplayChanged has run to avoid input caret issues
  10950. ready(lang.hitch(this, function(){ setTimeout(lang.hitch(this, "focus"), this.updateInterval); }));
  10951. }
  10952. // Save off the initial content now
  10953. this.value = this.getValue(true);
  10954. });
  10955. if(this.setValueDeferred){
  10956. this.setValueDeferred.addCallback(setContent);
  10957. }else{
  10958. setContent();
  10959. }
  10960. },
  10961. onKeyDown: function(/* Event */ e){
  10962. // summary:
  10963. // Handler for onkeydown event
  10964. // tags:
  10965. // protected
  10966. // we need this event at the moment to get the events from control keys
  10967. // such as the backspace. It might be possible to add this to Dojo, so that
  10968. // keyPress events can be emulated by the keyDown and keyUp detection.
  10969. if(e.keyCode === keys.TAB && this.isTabIndent){
  10970. event.stop(e); //prevent tab from moving focus out of editor
  10971. // FIXME: this is a poor-man's indent/outdent. It would be
  10972. // better if it added 4 "&nbsp;" chars in an undoable way.
  10973. // Unfortunately pasteHTML does not prove to be undoable
  10974. if(this.queryCommandEnabled((e.shiftKey ? "outdent" : "indent"))){
  10975. this.execCommand((e.shiftKey ? "outdent" : "indent"));
  10976. }
  10977. }
  10978. // Make tab and shift-tab skip over the <iframe>, going from the nested <div> to the toolbar
  10979. // or next element after the editor. Needed on IE<9 and firefox.
  10980. if(e.keyCode == keys.TAB && !this.isTabIndent){
  10981. if(e.shiftKey && !e.ctrlKey && !e.altKey){
  10982. // focus the <iframe> so the browser will shift-tab away from it instead
  10983. this.beforeIframeNode.focus();
  10984. }else if(!e.shiftKey && !e.ctrlKey && !e.altKey){
  10985. // focus node after the <iframe> so the browser will tab away from it instead
  10986. this.afterIframeNode.focus();
  10987. }
  10988. }
  10989. if(has("ie") < 9 && e.keyCode === keys.BACKSPACE && this.document.selection.type === "Control"){
  10990. // IE has a bug where if a non-text object is selected in the editor,
  10991. // hitting backspace would act as if the browser's back button was
  10992. // clicked instead of deleting the object. see #1069
  10993. e.stopPropagation();
  10994. e.preventDefault();
  10995. this.execCommand("delete");
  10996. }
  10997. if(has("ff")){
  10998. if(e.keyCode === keys.PAGE_UP || e.keyCode === keys.PAGE_DOWN ){
  10999. if(this.editNode.clientHeight >= this.editNode.scrollHeight){
  11000. // Stop the event to prevent firefox from trapping the cursor when there is no scroll bar.
  11001. e.preventDefault();
  11002. }
  11003. }
  11004. }
  11005. return true;
  11006. },
  11007. onKeyUp: function(/*===== e =====*/){
  11008. // summary:
  11009. // Handler for onkeyup event
  11010. // tags:
  11011. // callback
  11012. },
  11013. setDisabled: function(/*Boolean*/ disabled){
  11014. // summary:
  11015. // Deprecated, use set('disabled', ...) instead.
  11016. // tags:
  11017. // deprecated
  11018. kernel.deprecated('dijit.Editor::setDisabled is deprecated','use dijit.Editor::attr("disabled",boolean) instead', 2.0);
  11019. this.set('disabled',disabled);
  11020. },
  11021. _setValueAttr: function(/*String*/ value){
  11022. // summary:
  11023. // Registers that attr("value", foo) should call setValue(foo)
  11024. this.setValue(value);
  11025. },
  11026. _setDisableSpellCheckAttr: function(/*Boolean*/ disabled){
  11027. if(this.document){
  11028. domAttr.set(this.document.body, "spellcheck", !disabled);
  11029. }else{
  11030. // try again after the editor is finished loading
  11031. this.onLoadDeferred.addCallback(lang.hitch(this, function(){
  11032. domAttr.set(this.document.body, "spellcheck", !disabled);
  11033. }));
  11034. }
  11035. this._set("disableSpellCheck", disabled);
  11036. },
  11037. onKeyPress: function(e){
  11038. // summary:
  11039. // Handle the various key events
  11040. // tags:
  11041. // protected
  11042. if(e.keyCode === keys.SHIFT ||
  11043. e.keyCode === keys.ALT ||
  11044. e.keyCode === keys.META ||
  11045. e.keyCode === keys.CTRL ||
  11046. (e.keyCode == keys.TAB && !this.isTabIndent && !e.ctrlKey && !e.altKey)){
  11047. return true;
  11048. }
  11049. var c = (e.keyChar && e.keyChar.toLowerCase()) || e.keyCode,
  11050. handlers = this._keyHandlers[c],
  11051. args = arguments;
  11052. if(handlers && !e.altKey){
  11053. array.some(handlers, function(h){
  11054. // treat meta- same as ctrl-, for benefit of mac users
  11055. if(!(h.shift ^ e.shiftKey) && !(h.ctrl ^ (e.ctrlKey||e.metaKey))){
  11056. if(!h.handler.apply(this, args)){
  11057. e.preventDefault();
  11058. }
  11059. return true;
  11060. }
  11061. }, this);
  11062. }
  11063. // function call after the character has been inserted
  11064. if(!this._onKeyHitch){
  11065. this._onKeyHitch = lang.hitch(this, "onKeyPressed");
  11066. }
  11067. setTimeout(this._onKeyHitch, 1);
  11068. return true;
  11069. },
  11070. addKeyHandler: function(/*String*/ key, /*Boolean*/ ctrl, /*Boolean*/ shift, /*Function*/ handler){
  11071. // summary:
  11072. // Add a handler for a keyboard shortcut
  11073. // description:
  11074. // The key argument should be in lowercase if it is a letter character
  11075. // tags:
  11076. // protected
  11077. if(!lang.isArray(this._keyHandlers[key])){
  11078. this._keyHandlers[key] = [];
  11079. }
  11080. //TODO: would be nice to make this a hash instead of an array for quick lookups
  11081. this._keyHandlers[key].push({
  11082. shift: shift || false,
  11083. ctrl: ctrl || false,
  11084. handler: handler
  11085. });
  11086. },
  11087. onKeyPressed: function(){
  11088. // summary:
  11089. // Handler for after the user has pressed a key, and the display has been updated.
  11090. // (Runs on a timer so that it runs after the display is updated)
  11091. // tags:
  11092. // private
  11093. this.onDisplayChanged(/*e*/); // can't pass in e
  11094. },
  11095. onClick: function(/*Event*/ e){
  11096. // summary:
  11097. // Handler for when the user clicks.
  11098. // tags:
  11099. // private
  11100. // console.info('onClick',this._tryDesignModeOn);
  11101. this.onDisplayChanged(e);
  11102. },
  11103. _onIEMouseDown: function(){
  11104. // summary:
  11105. // IE only to prevent 2 clicks to focus
  11106. // tags:
  11107. // protected
  11108. if(!this.focused && !this.disabled){
  11109. this.focus();
  11110. }
  11111. },
  11112. _onBlur: function(e){
  11113. // summary:
  11114. // Called from focus manager when focus has moved away from this editor
  11115. // tags:
  11116. // protected
  11117. // console.info('_onBlur')
  11118. this.inherited(arguments);
  11119. var newValue = this.getValue(true);
  11120. if(newValue !== this.value){
  11121. this.onChange(newValue);
  11122. }
  11123. this._set("value", newValue);
  11124. },
  11125. _onFocus: function(/*Event*/ e){
  11126. // summary:
  11127. // Called from focus manager when focus has moved into this editor
  11128. // tags:
  11129. // protected
  11130. // console.info('_onFocus')
  11131. if(!this.disabled){
  11132. if(!this._disabledOK){
  11133. this.set('disabled', false);
  11134. }
  11135. this.inherited(arguments);
  11136. }
  11137. },
  11138. // TODO: remove in 2.0
  11139. blur: function(){
  11140. // summary:
  11141. // Remove focus from this instance.
  11142. // tags:
  11143. // deprecated
  11144. if(!has("ie") && this.window.document.documentElement && this.window.document.documentElement.focus){
  11145. this.window.document.documentElement.focus();
  11146. }else if(win.doc.body.focus){
  11147. win.doc.body.focus();
  11148. }
  11149. },
  11150. focus: function(){
  11151. // summary:
  11152. // Move focus to this editor
  11153. if(!this.isLoaded){
  11154. this.focusOnLoad = true;
  11155. return;
  11156. }
  11157. if(this._cursorToStart){
  11158. delete this._cursorToStart;
  11159. if(this.editNode.childNodes){
  11160. this.placeCursorAtStart(); // this calls focus() so return
  11161. return;
  11162. }
  11163. }
  11164. if(has("ie") < 9){
  11165. //this.editNode.focus(); -> causes IE to scroll always (strict and quirks mode) to the top the Iframe
  11166. // if we fire the event manually and let the browser handle the focusing, the latest
  11167. // cursor position is focused like in FF
  11168. this.iframe.fireEvent('onfocus', document.createEventObject()); // createEventObject/fireEvent only in IE < 11
  11169. }else{
  11170. // Firefox and chrome
  11171. this.editNode.focus();
  11172. }
  11173. },
  11174. // _lastUpdate: 0,
  11175. updateInterval: 200,
  11176. _updateTimer: null,
  11177. onDisplayChanged: function(/*Event*/ /*===== e =====*/){
  11178. // summary:
  11179. // This event will be fired every time the display context
  11180. // changes and the result needs to be reflected in the UI.
  11181. // description:
  11182. // If you don't want to have update too often,
  11183. // onNormalizedDisplayChanged should be used instead
  11184. // tags:
  11185. // private
  11186. // var _t=new Date();
  11187. if(this._updateTimer){
  11188. clearTimeout(this._updateTimer);
  11189. }
  11190. if(!this._updateHandler){
  11191. this._updateHandler = lang.hitch(this,"onNormalizedDisplayChanged");
  11192. }
  11193. this._updateTimer = setTimeout(this._updateHandler, this.updateInterval);
  11194. // Technically this should trigger a call to watch("value", ...) registered handlers,
  11195. // but getValue() is too slow to call on every keystroke so we don't.
  11196. },
  11197. onNormalizedDisplayChanged: function(){
  11198. // summary:
  11199. // This event is fired every updateInterval ms or more
  11200. // description:
  11201. // If something needs to happen immediately after a
  11202. // user change, please use onDisplayChanged instead.
  11203. // tags:
  11204. // private
  11205. delete this._updateTimer;
  11206. },
  11207. onChange: function(/*===== newContent =====*/){
  11208. // summary:
  11209. // This is fired if and only if the editor loses focus and
  11210. // the content is changed.
  11211. },
  11212. _normalizeCommand: function(/*String*/ cmd, /*Anything?*/argument){
  11213. // summary:
  11214. // Used as the advice function to map our
  11215. // normalized set of commands to those supported by the target
  11216. // browser.
  11217. // tags:
  11218. // private
  11219. var command = cmd.toLowerCase();
  11220. if(command === "formatblock"){
  11221. if(has("safari") && argument === undefined){ command = "heading"; }
  11222. }else if(command === "hilitecolor" && !has("mozilla")){
  11223. command = "backcolor";
  11224. }
  11225. return command;
  11226. },
  11227. _qcaCache: {},
  11228. queryCommandAvailable: function(/*String*/ command){
  11229. // summary:
  11230. // Tests whether a command is supported by the host. Clients
  11231. // SHOULD check whether a command is supported before attempting
  11232. // to use it, behaviour for unsupported commands is undefined.
  11233. // command:
  11234. // The command to test for
  11235. // tags:
  11236. // private
  11237. // memoizing version. See _queryCommandAvailable for computing version
  11238. var ca = this._qcaCache[command];
  11239. if(ca !== undefined){ return ca; }
  11240. return (this._qcaCache[command] = this._queryCommandAvailable(command));
  11241. },
  11242. _queryCommandAvailable: function(/*String*/ command){
  11243. // summary:
  11244. // See queryCommandAvailable().
  11245. // tags:
  11246. // private
  11247. var ie = 1;
  11248. var mozilla = 1 << 1;
  11249. var webkit = 1 << 2;
  11250. var opera = 1 << 3;
  11251. function isSupportedBy(browsers){
  11252. return {
  11253. ie: Boolean(browsers & ie),
  11254. mozilla: Boolean(browsers & mozilla),
  11255. webkit: Boolean(browsers & webkit),
  11256. opera: Boolean(browsers & opera)
  11257. };
  11258. }
  11259. var supportedBy = null;
  11260. switch(command.toLowerCase()){
  11261. case "bold": case "italic": case "underline":
  11262. case "subscript": case "superscript":
  11263. case "fontname": case "fontsize":
  11264. case "forecolor": case "hilitecolor":
  11265. case "justifycenter": case "justifyfull": case "justifyleft":
  11266. case "justifyright": case "delete": case "selectall": case "toggledir":
  11267. supportedBy = isSupportedBy(mozilla | ie | webkit | opera);
  11268. break;
  11269. case "createlink": case "unlink": case "removeformat":
  11270. case "inserthorizontalrule": case "insertimage":
  11271. case "insertorderedlist": case "insertunorderedlist":
  11272. case "indent": case "outdent": case "formatblock":
  11273. case "inserthtml": case "undo": case "redo": case "strikethrough": case "tabindent":
  11274. supportedBy = isSupportedBy(mozilla | ie | opera | webkit);
  11275. break;
  11276. case "blockdirltr": case "blockdirrtl":
  11277. case "dirltr": case "dirrtl":
  11278. case "inlinedirltr": case "inlinedirrtl":
  11279. supportedBy = isSupportedBy(ie);
  11280. break;
  11281. case "cut": case "copy": case "paste":
  11282. supportedBy = isSupportedBy( ie | mozilla | webkit);
  11283. break;
  11284. case "inserttable":
  11285. supportedBy = isSupportedBy(mozilla | ie);
  11286. break;
  11287. case "insertcell": case "insertcol": case "insertrow":
  11288. case "deletecells": case "deletecols": case "deleterows":
  11289. case "mergecells": case "splitcell":
  11290. supportedBy = isSupportedBy(ie | mozilla);
  11291. break;
  11292. default: return false;
  11293. }
  11294. return ((has("ie") || has("trident")) && supportedBy.ie) ||
  11295. (has("mozilla") && supportedBy.mozilla) ||
  11296. (has("webkit") && supportedBy.webkit) ||
  11297. (has("opera") && supportedBy.opera); // Boolean return true if the command is supported, false otherwise
  11298. },
  11299. execCommand: function(/*String*/ command, argument){
  11300. // summary:
  11301. // Executes a command in the Rich Text area
  11302. // command:
  11303. // The command to execute
  11304. // argument:
  11305. // An optional argument to the command
  11306. // tags:
  11307. // protected
  11308. var returnValue;
  11309. //focus() is required for IE to work
  11310. //In addition, focus() makes sure after the execution of
  11311. //the command, the editor receives the focus as expected
  11312. if(this.focused){
  11313. // put focus back in the iframe, unless focus has somehow been shifted out of the editor completely
  11314. this.focus();
  11315. }
  11316. command = this._normalizeCommand(command, argument);
  11317. if(argument !== undefined){
  11318. if(command === "heading"){
  11319. throw new Error("unimplemented");
  11320. }else if(command === "formatblock" && (has("ie") || has("trident"))){
  11321. argument = '<'+argument+'>';
  11322. }
  11323. }
  11324. //Check to see if we have any over-rides for commands, they will be functions on this
  11325. //widget of the form _commandImpl. If we don't, fall through to the basic native
  11326. //exec command of the browser.
  11327. var implFunc = "_" + command + "Impl";
  11328. if(this[implFunc]){
  11329. returnValue = this[implFunc](argument);
  11330. }else{
  11331. argument = arguments.length > 1 ? argument : null;
  11332. if(argument || command !== "createlink"){
  11333. returnValue = this.document.execCommand(command, false, argument);
  11334. }
  11335. }
  11336. this.onDisplayChanged();
  11337. return returnValue;
  11338. },
  11339. queryCommandEnabled: function(/*String*/ command){
  11340. // summary:
  11341. // Check whether a command is enabled or not.
  11342. // command:
  11343. // The command to execute
  11344. // tags:
  11345. // protected
  11346. if(this.disabled || !this._disabledOK){ return false; }
  11347. command = this._normalizeCommand(command);
  11348. //Check to see if we have any over-rides for commands, they will be functions on this
  11349. //widget of the form _commandEnabledImpl. If we don't, fall through to the basic native
  11350. //command of the browser.
  11351. var implFunc = "_" + command + "EnabledImpl";
  11352. if(this[implFunc]){
  11353. return this[implFunc](command);
  11354. }else{
  11355. return this._browserQueryCommandEnabled(command);
  11356. }
  11357. },
  11358. queryCommandState: function(command){
  11359. // summary:
  11360. // Check the state of a given command and returns true or false.
  11361. // tags:
  11362. // protected
  11363. if(this.disabled || !this._disabledOK){ return false; }
  11364. command = this._normalizeCommand(command);
  11365. try{
  11366. return this.document.queryCommandState(command);
  11367. }catch(e){
  11368. //Squelch, occurs if editor is hidden on FF 3 (and maybe others.)
  11369. return false;
  11370. }
  11371. },
  11372. queryCommandValue: function(command){
  11373. // summary:
  11374. // Check the value of a given command. This matters most for
  11375. // custom selections and complex values like font value setting.
  11376. // tags:
  11377. // protected
  11378. if(this.disabled || !this._disabledOK){ return false; }
  11379. var r;
  11380. command = this._normalizeCommand(command);
  11381. if((has("ie") || has("trident")) && command === "formatblock"){
  11382. r = this._native2LocalFormatNames[this.document.queryCommandValue(command)];
  11383. }else if(has("mozilla") && command === "hilitecolor"){
  11384. var oldValue;
  11385. try{
  11386. oldValue = this.document.queryCommandValue("styleWithCSS");
  11387. }catch(e){
  11388. oldValue = false;
  11389. }
  11390. this.document.execCommand("styleWithCSS", false, true);
  11391. r = this.document.queryCommandValue(command);
  11392. this.document.execCommand("styleWithCSS", false, oldValue);
  11393. }else{
  11394. r = this.document.queryCommandValue(command);
  11395. }
  11396. return r;
  11397. },
  11398. // Misc.
  11399. _sCall: function(name, args){
  11400. // summary:
  11401. // Run the named method of dijit._editor.selection over the
  11402. // current editor instance's window, with the passed args.
  11403. // tags:
  11404. // private
  11405. return win.withGlobal(this.window, name, selectionapi, args);
  11406. },
  11407. // FIXME: this is a TON of code duplication. Why?
  11408. placeCursorAtStart: function(){
  11409. // summary:
  11410. // Place the cursor at the start of the editing area.
  11411. // tags:
  11412. // private
  11413. this.focus();
  11414. //see comments in placeCursorAtEnd
  11415. var isvalid=false;
  11416. if(has("mozilla")){
  11417. // TODO: Is this branch even necessary?
  11418. var first=this.editNode.firstChild;
  11419. while(first){
  11420. if(first.nodeType === 3){
  11421. if(first.nodeValue.replace(/^\s+|\s+$/g, "").length>0){
  11422. isvalid=true;
  11423. this._sCall("selectElement", [ first ]);
  11424. break;
  11425. }
  11426. }else if(first.nodeType === 1){
  11427. isvalid=true;
  11428. var tg = first.tagName ? first.tagName.toLowerCase() : "";
  11429. // Collapse before childless tags.
  11430. if(/br|input|img|base|meta|area|basefont|hr|link/.test(tg)){
  11431. this._sCall("selectElement", [ first ]);
  11432. }else{
  11433. // Collapse inside tags with children.
  11434. this._sCall("selectElementChildren", [ first ]);
  11435. }
  11436. break;
  11437. }
  11438. first = first.nextSibling;
  11439. }
  11440. }else{
  11441. isvalid=true;
  11442. this._sCall("selectElementChildren", [ this.editNode ]);
  11443. }
  11444. if(isvalid){
  11445. this._sCall("collapse", [ true ]);
  11446. }
  11447. },
  11448. placeCursorAtEnd: function(){
  11449. // summary:
  11450. // Place the cursor at the end of the editing area.
  11451. // tags:
  11452. // private
  11453. this.focus();
  11454. //In mozilla, if last child is not a text node, we have to use
  11455. // selectElementChildren on this.editNode.lastChild otherwise the
  11456. // cursor would be placed at the end of the closing tag of
  11457. //this.editNode.lastChild
  11458. var isvalid=false;
  11459. if(has("mozilla")){
  11460. var last=this.editNode.lastChild;
  11461. while(last){
  11462. if(last.nodeType === 3){
  11463. if(last.nodeValue.replace(/^\s+|\s+$/g, "").length>0){
  11464. isvalid=true;
  11465. this._sCall("selectElement", [ last ]);
  11466. break;
  11467. }
  11468. }else if(last.nodeType === 1){
  11469. isvalid=true;
  11470. if(last.lastChild){
  11471. this._sCall("selectElement", [ last.lastChild ]);
  11472. }else{
  11473. this._sCall("selectElement", [ last ]);
  11474. }
  11475. break;
  11476. }
  11477. last = last.previousSibling;
  11478. }
  11479. }else{
  11480. isvalid=true;
  11481. this._sCall("selectElementChildren", [ this.editNode ]);
  11482. }
  11483. if(isvalid){
  11484. this._sCall("collapse", [ false ]);
  11485. }
  11486. },
  11487. getValue: function(/*Boolean?*/ nonDestructive){
  11488. // summary:
  11489. // Return the current content of the editing area (post filters
  11490. // are applied). Users should call get('value') instead.
  11491. // nonDestructive:
  11492. // defaults to false. Should the post-filtering be run over a copy
  11493. // of the live DOM? Most users should pass "true" here unless they
  11494. // *really* know that none of the installed filters are going to
  11495. // mess up the editing session.
  11496. // tags:
  11497. // private
  11498. if(this.textarea){
  11499. if(this.isClosed || !this.isLoaded){
  11500. return this.textarea.value;
  11501. }
  11502. }
  11503. return this._postFilterContent(null, nonDestructive);
  11504. },
  11505. _getValueAttr: function(){
  11506. // summary:
  11507. // Hook to make attr("value") work
  11508. return this.getValue(true);
  11509. },
  11510. setValue: function(/*String*/ html){
  11511. // summary:
  11512. // This function sets the content. No undo history is preserved.
  11513. // Users should use set('value', ...) instead.
  11514. // tags:
  11515. // deprecated
  11516. // TODO: remove this and getValue() for 2.0, and move code to _setValueAttr()
  11517. if(!this.isLoaded){
  11518. // try again after the editor is finished loading
  11519. this.onLoadDeferred.addCallback(lang.hitch(this, function(){
  11520. this.setValue(html);
  11521. }));
  11522. return;
  11523. }
  11524. this._cursorToStart = true;
  11525. if(this.textarea && (this.isClosed || !this.isLoaded)){
  11526. this.textarea.value=html;
  11527. }else{
  11528. html = this._preFilterContent(html);
  11529. var node = this.isClosed ? this.domNode : this.editNode;
  11530. // Use &nbsp; to avoid webkit problems where editor is disabled until the user clicks it
  11531. if(!html && has("webkit")){
  11532. html = "&#160;"; // &nbsp;
  11533. }
  11534. node.innerHTML = html;
  11535. this._preDomFilterContent(node);
  11536. }
  11537. this.onDisplayChanged();
  11538. this._set("value", this.getValue(true));
  11539. },
  11540. replaceValue: function(/*String*/ html){
  11541. // summary:
  11542. // This function set the content while trying to maintain the undo stack
  11543. // (now only works fine with Moz, this is identical to setValue in all
  11544. // other browsers)
  11545. // tags:
  11546. // protected
  11547. if(this.isClosed){
  11548. this.setValue(html);
  11549. }else if(this.window && this.window.getSelection && !has("mozilla")){ // Safari
  11550. // look ma! it's a totally f'd browser!
  11551. this.setValue(html);
  11552. }else if(this.window && this.window.getSelection){ // Moz
  11553. html = this._preFilterContent(html);
  11554. this.execCommand("selectall");
  11555. this.execCommand("inserthtml", html);
  11556. this._preDomFilterContent(this.editNode);
  11557. }else if(this.document && this.document.selection){//IE
  11558. //In IE, when the first element is not a text node, say
  11559. //an <a> tag, when replacing the content of the editing
  11560. //area, the <a> tag will be around all the content
  11561. //so for now, use setValue for IE too
  11562. this.setValue(html);
  11563. }
  11564. this._set("value", this.getValue(true));
  11565. },
  11566. _preFilterContent: function(/*String*/ html){
  11567. // summary:
  11568. // Filter the input before setting the content of the editing
  11569. // area. DOM pre-filtering may happen after this
  11570. // string-based filtering takes place but as of 1.2, this is not
  11571. // guaranteed for operations such as the inserthtml command.
  11572. // tags:
  11573. // private
  11574. var ec = html;
  11575. array.forEach(this.contentPreFilters, function(ef){ if(ef){ ec = ef(ec); } });
  11576. return ec;
  11577. },
  11578. _preDomFilterContent: function(/*DomNode*/ dom){
  11579. // summary:
  11580. // filter the input's live DOM. All filter operations should be
  11581. // considered to be "live" and operating on the DOM that the user
  11582. // will be interacting with in their editing session.
  11583. // tags:
  11584. // private
  11585. dom = dom || this.editNode;
  11586. array.forEach(this.contentDomPreFilters, function(ef){
  11587. if(ef && lang.isFunction(ef)){
  11588. ef(dom);
  11589. }
  11590. }, this);
  11591. },
  11592. _postFilterContent: function(
  11593. /*DomNode|DomNode[]|String?*/ dom,
  11594. /*Boolean?*/ nonDestructive){
  11595. // summary:
  11596. // filter the output after getting the content of the editing area
  11597. //
  11598. // description:
  11599. // post-filtering allows plug-ins and users to specify any number
  11600. // of transforms over the editor's content, enabling many common
  11601. // use-cases such as transforming absolute to relative URLs (and
  11602. // vice-versa), ensuring conformance with a particular DTD, etc.
  11603. // The filters are registered in the contentDomPostFilters and
  11604. // contentPostFilters arrays. Each item in the
  11605. // contentDomPostFilters array is a function which takes a DOM
  11606. // Node or array of nodes as its only argument and returns the
  11607. // same. It is then passed down the chain for further filtering.
  11608. // The contentPostFilters array behaves the same way, except each
  11609. // member operates on strings. Together, the DOM and string-based
  11610. // filtering allow the full range of post-processing that should
  11611. // be necessaray to enable even the most agressive of post-editing
  11612. // conversions to take place.
  11613. //
  11614. // If nonDestructive is set to "true", the nodes are cloned before
  11615. // filtering proceeds to avoid potentially destructive transforms
  11616. // to the content which may still needed to be edited further.
  11617. // Once DOM filtering has taken place, the serialized version of
  11618. // the DOM which is passed is run through each of the
  11619. // contentPostFilters functions.
  11620. //
  11621. // dom:
  11622. // a node, set of nodes, which to filter using each of the current
  11623. // members of the contentDomPostFilters and contentPostFilters arrays.
  11624. //
  11625. // nonDestructive:
  11626. // defaults to "false". If true, ensures that filtering happens on
  11627. // a clone of the passed-in content and not the actual node
  11628. // itself.
  11629. //
  11630. // tags:
  11631. // private
  11632. var ec;
  11633. if(!lang.isString(dom)){
  11634. dom = dom || this.editNode;
  11635. if(this.contentDomPostFilters.length){
  11636. if(nonDestructive){
  11637. dom = lang.clone(dom);
  11638. }
  11639. array.forEach(this.contentDomPostFilters, function(ef){
  11640. dom = ef(dom);
  11641. });
  11642. }
  11643. ec = htmlapi.getChildrenHtml(dom);
  11644. }else{
  11645. ec = dom;
  11646. }
  11647. if(!lang.trim(ec.replace(/^\xA0\xA0*/, '').replace(/\xA0\xA0*$/, '')).length){
  11648. ec = "";
  11649. }
  11650. // if(has("ie")){
  11651. // //removing appended <P>&nbsp;</P> for IE
  11652. // ec = ec.replace(/(?:<p>&nbsp;</p>[\n\r]*)+$/i,"");
  11653. // }
  11654. array.forEach(this.contentPostFilters, function(ef){
  11655. ec = ef(ec);
  11656. });
  11657. return ec;
  11658. },
  11659. _saveContent: function(){
  11660. // summary:
  11661. // Saves the content in an onunload event if the editor has not been closed
  11662. // tags:
  11663. // private
  11664. var saveTextarea = dom.byId(dijit._scopeName + "._editor.RichText.value");
  11665. if(saveTextarea){
  11666. if(saveTextarea.value){
  11667. saveTextarea.value += this._SEPARATOR;
  11668. }
  11669. saveTextarea.value += this.name + this._NAME_CONTENT_SEP + this.getValue(true);
  11670. }
  11671. },
  11672. escapeXml: function(/*String*/ str, /*Boolean*/ noSingleQuotes){
  11673. // summary:
  11674. // Adds escape sequences for special characters in XML.
  11675. // Optionally skips escapes for single quotes
  11676. // tags:
  11677. // private
  11678. str = str.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;");
  11679. if(!noSingleQuotes){
  11680. str = str.replace(/'/gm, "&#39;");
  11681. }
  11682. return str; // string
  11683. },
  11684. getNodeHtml: function(/* DomNode */ node){
  11685. // summary:
  11686. // Deprecated. Use dijit/_editor/html::_getNodeHtml() instead.
  11687. // tags:
  11688. // deprecated
  11689. kernel.deprecated('dijit.Editor::getNodeHtml is deprecated','use dijit/_editor/html::getNodeHtml instead', 2);
  11690. return htmlapi.getNodeHtml(node); // String
  11691. },
  11692. getNodeChildrenHtml: function(/* DomNode */ dom){
  11693. // summary:
  11694. // Deprecated. Use dijit/_editor/html::getChildrenHtml() instead.
  11695. // tags:
  11696. // deprecated
  11697. kernel.deprecated('dijit.Editor::getNodeChildrenHtml is deprecated','use dijit/_editor/html::getChildrenHtml instead', 2);
  11698. return htmlapi.getChildrenHtml(dom);
  11699. },
  11700. close: function(/*Boolean?*/ save){
  11701. // summary:
  11702. // Kills the editor and optionally writes back the modified contents to the
  11703. // element from which it originated.
  11704. // save:
  11705. // Whether or not to save the changes. If false, the changes are discarded.
  11706. // tags:
  11707. // private
  11708. if(this.isClosed){ return; }
  11709. if(!arguments.length){ save = true; }
  11710. if(save){
  11711. this._set("value", this.getValue(true));
  11712. }
  11713. // line height is squashed for iframes
  11714. // FIXME: why was this here? if(this.iframe){ this.domNode.style.lineHeight = null; }
  11715. if(this.interval){ clearInterval(this.interval); }
  11716. if(this._webkitListener){
  11717. //Cleaup of WebKit fix: #9532
  11718. this.disconnect(this._webkitListener);
  11719. delete this._webkitListener;
  11720. }
  11721. // Guard against memory leaks on IE (see #9268)
  11722. if(has("ie")){
  11723. this.iframe.onfocus = null;
  11724. }
  11725. this.iframe._loadFunc = null;
  11726. if(this._iframeRegHandle){
  11727. this._iframeRegHandle.remove();
  11728. delete this._iframeRegHandle;
  11729. }
  11730. if(this.textarea){
  11731. var s = this.textarea.style;
  11732. s.position = "";
  11733. s.left = s.top = "";
  11734. if(has("ie")){
  11735. s.overflow = this.__overflow;
  11736. this.__overflow = null;
  11737. }
  11738. this.textarea.value = this.value;
  11739. domConstruct.destroy(this.domNode);
  11740. this.domNode = this.textarea;
  11741. }else{
  11742. // Note that this destroys the iframe
  11743. this.domNode.innerHTML = this.value;
  11744. }
  11745. delete this.iframe;
  11746. domClass.remove(this.domNode, this.baseClass);
  11747. this.isClosed = true;
  11748. this.isLoaded = false;
  11749. delete this.editNode;
  11750. delete this.focusNode;
  11751. if(this.window && this.window._frameElement){
  11752. this.window._frameElement = null;
  11753. }
  11754. this.window = null;
  11755. this.document = null;
  11756. this.editingArea = null;
  11757. this.editorObject = null;
  11758. },
  11759. destroy: function(){
  11760. if(!this.isClosed){ this.close(false); }
  11761. if(this._updateTimer){
  11762. clearTimeout(this._updateTimer);
  11763. }
  11764. this.inherited(arguments);
  11765. if(RichText._globalSaveHandler){
  11766. delete RichText._globalSaveHandler[this.id];
  11767. }
  11768. },
  11769. _removeMozBogus: function(/* String */ html){
  11770. // summary:
  11771. // Post filter to remove unwanted HTML attributes generated by mozilla
  11772. // tags:
  11773. // private
  11774. return html.replace(/\stype="_moz"/gi, '').replace(/\s_moz_dirty=""/gi, '').replace(/_moz_resizing="(true|false)"/gi,''); // String
  11775. },
  11776. _removeWebkitBogus: function(/* String */ html){
  11777. // summary:
  11778. // Post filter to remove unwanted HTML attributes generated by webkit
  11779. // tags:
  11780. // private
  11781. html = html.replace(/\sclass="webkit-block-placeholder"/gi, '');
  11782. html = html.replace(/\sclass="apple-style-span"/gi, '');
  11783. // For some reason copy/paste sometime adds extra meta tags for charset on
  11784. // webkit (chrome) on mac.They need to be removed. See: #12007"
  11785. html = html.replace(/<meta charset=\"utf-8\" \/>/gi, '');
  11786. return html; // String
  11787. },
  11788. _normalizeFontStyle: function(/* String */ html){
  11789. // summary:
  11790. // Convert 'strong' and 'em' to 'b' and 'i'.
  11791. // description:
  11792. // Moz can not handle strong/em tags correctly, so to help
  11793. // mozilla and also to normalize output, convert them to 'b' and 'i'.
  11794. //
  11795. // Note the IE generates 'strong' and 'em' rather than 'b' and 'i'
  11796. // tags:
  11797. // private
  11798. return html.replace(/<(\/)?strong([ \>])/gi, '<$1b$2')
  11799. .replace(/<(\/)?em([ \>])/gi, '<$1i$2' ); // String
  11800. },
  11801. _preFixUrlAttributes: function(/* String */ html){
  11802. // summary:
  11803. // Pre-filter to do fixing to href attributes on <a> and <img> tags
  11804. // tags:
  11805. // private
  11806. return html.replace(/(?:(<a(?=\s).*?\shref=)("|')(.*?)\2)|(?:(<a\s.*?href=)([^"'][^ >]+))/gi,
  11807. '$1$4$2$3$5$2 _djrealurl=$2$3$5$2')
  11808. .replace(/(?:(<img(?=\s).*?\ssrc=)("|')(.*?)\2)|(?:(<img\s.*?src=)([^"'][^ >]+))/gi,
  11809. '$1$4$2$3$5$2 _djrealurl=$2$3$5$2'); // String
  11810. },
  11811. /*****************************************************************************
  11812. The following functions implement HTML manipulation commands for various
  11813. browser/contentEditable implementations. The goal of them is to enforce
  11814. standard behaviors of them.
  11815. ******************************************************************************/
  11816. /*** queryCommandEnabled implementations ***/
  11817. _browserQueryCommandEnabled: function(command){
  11818. // summary:
  11819. // Implementation to call to the native queryCommandEnabled of the browser.
  11820. // command:
  11821. // The command to check.
  11822. // tags:
  11823. // protected
  11824. if(!command) { return false; }
  11825. var elem = has("ie") < 9 ? this.document.selection.createRange() : this.document;
  11826. try{
  11827. return elem.queryCommandEnabled(command);
  11828. }catch(e){
  11829. return false;
  11830. }
  11831. },
  11832. _createlinkEnabledImpl: function(/*===== argument =====*/){
  11833. // summary:
  11834. // This function implements the test for if the create link
  11835. // command should be enabled or not.
  11836. // argument:
  11837. // arguments to the exec command, if any.
  11838. // tags:
  11839. // protected
  11840. var enabled = true;
  11841. if(has("opera")){
  11842. var sel = this.window.getSelection();
  11843. if(sel.isCollapsed){
  11844. enabled = true;
  11845. }else{
  11846. enabled = this.document.queryCommandEnabled("createlink");
  11847. }
  11848. }else{
  11849. enabled = this._browserQueryCommandEnabled("createlink");
  11850. }
  11851. return enabled;
  11852. },
  11853. _unlinkEnabledImpl: function(/*===== argument =====*/){
  11854. // summary:
  11855. // This function implements the test for if the unlink
  11856. // command should be enabled or not.
  11857. // argument:
  11858. // arguments to the exec command, if any.
  11859. // tags:
  11860. // protected
  11861. var enabled = true;
  11862. if(has("mozilla") || has("webkit")){
  11863. enabled = this._sCall("hasAncestorElement", ["a"]);
  11864. }else{
  11865. enabled = this._browserQueryCommandEnabled("unlink");
  11866. }
  11867. return enabled;
  11868. },
  11869. _inserttableEnabledImpl: function(/*===== argument =====*/){
  11870. // summary:
  11871. // This function implements the test for if the inserttable
  11872. // command should be enabled or not.
  11873. // argument:
  11874. // arguments to the exec command, if any.
  11875. // tags:
  11876. // protected
  11877. var enabled = true;
  11878. if(has("mozilla") || has("webkit")){
  11879. enabled = true;
  11880. }else{
  11881. enabled = this._browserQueryCommandEnabled("inserttable");
  11882. }
  11883. return enabled;
  11884. },
  11885. _cutEnabledImpl: function(/*===== argument =====*/){
  11886. // summary:
  11887. // This function implements the test for if the cut
  11888. // command should be enabled or not.
  11889. // argument:
  11890. // arguments to the exec command, if any.
  11891. // tags:
  11892. // protected
  11893. var enabled = true;
  11894. if(has("webkit")){
  11895. // WebKit deems clipboard activity as a security threat and natively would return false
  11896. var sel = this.window.getSelection();
  11897. if(sel){ sel = sel.toString(); }
  11898. enabled = !!sel;
  11899. }else{
  11900. enabled = this._browserQueryCommandEnabled("cut");
  11901. }
  11902. return enabled;
  11903. },
  11904. _copyEnabledImpl: function(/*===== argument =====*/){
  11905. // summary:
  11906. // This function implements the test for if the copy
  11907. // command should be enabled or not.
  11908. // argument:
  11909. // arguments to the exec command, if any.
  11910. // tags:
  11911. // protected
  11912. var enabled = true;
  11913. if(has("webkit")){
  11914. // WebKit deems clipboard activity as a security threat and natively would return false
  11915. var sel = this.window.getSelection();
  11916. if(sel){ sel = sel.toString(); }
  11917. enabled = !!sel;
  11918. }else{
  11919. enabled = this._browserQueryCommandEnabled("copy");
  11920. }
  11921. return enabled;
  11922. },
  11923. _pasteEnabledImpl: function(/*===== argument =====*/){
  11924. // summary:c
  11925. // This function implements the test for if the paste
  11926. // command should be enabled or not.
  11927. // argument:
  11928. // arguments to the exec command, if any.
  11929. // tags:
  11930. // protected
  11931. var enabled = true;
  11932. if(has("webkit")){
  11933. return true;
  11934. }else{
  11935. enabled = this._browserQueryCommandEnabled("paste");
  11936. }
  11937. return enabled;
  11938. },
  11939. /*** execCommand implementations ***/
  11940. _inserthorizontalruleImpl: function(argument){
  11941. // summary:
  11942. // This function implements the insertion of HTML 'HR' tags.
  11943. // into a point on the page. IE doesn't to it right, so
  11944. // we have to use an alternate form
  11945. // argument:
  11946. // arguments to the exec command, if any.
  11947. // tags:
  11948. // protected
  11949. if(has("ie")){
  11950. return this._inserthtmlImpl("<hr>");
  11951. }
  11952. return this.document.execCommand("inserthorizontalrule", false, argument);
  11953. },
  11954. _unlinkImpl: function(argument){
  11955. // summary:
  11956. // This function implements the unlink of an 'a' tag.
  11957. // argument:
  11958. // arguments to the exec command, if any.
  11959. // tags:
  11960. // protected
  11961. if((this.queryCommandEnabled("unlink")) && (has("mozilla") || has("webkit"))){
  11962. var a = this._sCall("getAncestorElement", [ "a" ]);
  11963. this._sCall("selectElement", [ a ]);
  11964. return this.document.execCommand("unlink", false, null);
  11965. }
  11966. return this.document.execCommand("unlink", false, argument);
  11967. },
  11968. _hilitecolorImpl: function(argument){
  11969. // summary:
  11970. // This function implements the hilitecolor command
  11971. // argument:
  11972. // arguments to the exec command, if any.
  11973. // tags:
  11974. // protected
  11975. var returnValue;
  11976. var isApplied = this._handleTextColorOrProperties("hilitecolor", argument);
  11977. if(!isApplied){
  11978. if(has("mozilla")){
  11979. // mozilla doesn't support hilitecolor properly when useCSS is
  11980. // set to false (bugzilla #279330)
  11981. this.document.execCommand("styleWithCSS", false, true);
  11982. console.log("Executing color command.");
  11983. returnValue = this.document.execCommand("hilitecolor", false, argument);
  11984. this.document.execCommand("styleWithCSS", false, false);
  11985. }else{
  11986. returnValue = this.document.execCommand("hilitecolor", false, argument);
  11987. }
  11988. }
  11989. return returnValue;
  11990. },
  11991. _backcolorImpl: function(argument){
  11992. // summary:
  11993. // This function implements the backcolor command
  11994. // argument:
  11995. // arguments to the exec command, if any.
  11996. // tags:
  11997. // protected
  11998. if(has("ie")){
  11999. // Tested under IE 6 XP2, no problem here, comment out
  12000. // IE weirdly collapses ranges when we exec these commands, so prevent it
  12001. // var tr = this.document.selection.createRange();
  12002. argument = argument ? argument : null;
  12003. }
  12004. var isApplied = this._handleTextColorOrProperties("backcolor", argument);
  12005. if(!isApplied){
  12006. isApplied = this.document.execCommand("backcolor", false, argument);
  12007. }
  12008. return isApplied;
  12009. },
  12010. _forecolorImpl: function(argument){
  12011. // summary:
  12012. // This function implements the forecolor command
  12013. // argument:
  12014. // arguments to the exec command, if any.
  12015. // tags:
  12016. // protected
  12017. if(has("ie")){
  12018. // Tested under IE 6 XP2, no problem here, comment out
  12019. // IE weirdly collapses ranges when we exec these commands, so prevent it
  12020. // var tr = this.document.selection.createRange();
  12021. argument = argument? argument : null;
  12022. }
  12023. var isApplied = false;
  12024. isApplied = this._handleTextColorOrProperties("forecolor", argument);
  12025. if(!isApplied){
  12026. isApplied = this.document.execCommand("forecolor", false, argument);
  12027. }
  12028. return isApplied;
  12029. },
  12030. _inserthtmlImpl: function(argument){
  12031. // summary:
  12032. // This function implements the insertion of HTML content into
  12033. // a point on the page.
  12034. // argument:
  12035. // The content to insert, if any.
  12036. // tags:
  12037. // protected
  12038. argument = this._preFilterContent(argument);
  12039. var rv = true;
  12040. if(has("ie") < 9){
  12041. var insertRange = this.document.selection.createRange();
  12042. if(this.document.selection.type.toUpperCase() === 'CONTROL'){
  12043. var n = insertRange.item(0);
  12044. while(insertRange.length){
  12045. insertRange.remove(insertRange.item(0));
  12046. }
  12047. n.outerHTML = argument;
  12048. }else{
  12049. insertRange.pasteHTML(argument);
  12050. }
  12051. insertRange.select();
  12052. }else if(has("trident") < 8){
  12053. var insertRange;
  12054. var selection = rangeapi.getSelection(this.window);
  12055. if(selection && selection.rangeCount && selection.getRangeAt){
  12056. insertRange = selection.getRangeAt(0);
  12057. insertRange.deleteContents();
  12058. var div = domConstruct.create('div');
  12059. div.innerHTML = argument;
  12060. var node, lastNode;
  12061. var n = this.document.createDocumentFragment();
  12062. while((node = div.firstChild)){
  12063. lastNode = n.appendChild(node);
  12064. }
  12065. insertRange.insertNode(n);
  12066. if(lastNode) {
  12067. insertRange = insertRange.cloneRange();
  12068. insertRange.setStartAfter(lastNode);
  12069. insertRange.collapse(false);
  12070. selection.removeAllRanges();
  12071. selection.addRange(insertRange);
  12072. }
  12073. }
  12074. }else if(has("mozilla") && !argument.length){
  12075. //mozilla can not inserthtml an empty html to delete current selection
  12076. //so we delete the selection instead in this case
  12077. this._sCall("remove"); // FIXME
  12078. }else{
  12079. rv = this.document.execCommand("inserthtml", false, argument);
  12080. }
  12081. return rv;
  12082. },
  12083. _boldImpl: function(argument){
  12084. // summary:
  12085. // This function implements an over-ride of the bold command.
  12086. // argument:
  12087. // Not used, operates by selection.
  12088. // tags:
  12089. // protected
  12090. var applied = false;
  12091. if(has("ie") || has("trident")){
  12092. this._adaptIESelection();
  12093. applied = this._adaptIEFormatAreaAndExec("bold");
  12094. }
  12095. if(!applied){
  12096. applied = this.document.execCommand("bold", false, argument);
  12097. }
  12098. return applied;
  12099. },
  12100. _italicImpl: function(argument){
  12101. // summary:
  12102. // This function implements an over-ride of the italic command.
  12103. // argument:
  12104. // Not used, operates by selection.
  12105. // tags:
  12106. // protected
  12107. var applied = false;
  12108. if(has("ie") || has("trident")){
  12109. this._adaptIESelection();
  12110. applied = this._adaptIEFormatAreaAndExec("italic");
  12111. }
  12112. if(!applied){
  12113. applied = this.document.execCommand("italic", false, argument);
  12114. }
  12115. return applied;
  12116. },
  12117. _underlineImpl: function(argument){
  12118. // summary:
  12119. // This function implements an over-ride of the underline command.
  12120. // argument:
  12121. // Not used, operates by selection.
  12122. // tags:
  12123. // protected
  12124. var applied = false;
  12125. if(has("ie") || has("trident")){
  12126. this._adaptIESelection();
  12127. applied = this._adaptIEFormatAreaAndExec("underline");
  12128. }
  12129. if(!applied){
  12130. applied = this.document.execCommand("underline", false, argument);
  12131. }
  12132. return applied;
  12133. },
  12134. _strikethroughImpl: function(argument){
  12135. // summary:
  12136. // This function implements an over-ride of the strikethrough command.
  12137. // argument:
  12138. // Not used, operates by selection.
  12139. // tags:
  12140. // protected
  12141. var applied = false;
  12142. if(has("ie") || has("trident")){
  12143. this._adaptIESelection();
  12144. applied = this._adaptIEFormatAreaAndExec("strikethrough");
  12145. }
  12146. if(!applied){
  12147. applied = this.document.execCommand("strikethrough", false, argument);
  12148. }
  12149. return applied;
  12150. },
  12151. _superscriptImpl: function(argument){
  12152. // summary:
  12153. // This function implements an over-ride of the superscript command.
  12154. // argument:
  12155. // Not used, operates by selection.
  12156. // tags:
  12157. // protected
  12158. var applied = false;
  12159. if(has("ie") || has("trident")){
  12160. this._adaptIESelection();
  12161. applied = this._adaptIEFormatAreaAndExec("superscript");
  12162. }
  12163. if(!applied){
  12164. applied = this.document.execCommand("superscript", false, argument);
  12165. }
  12166. return applied;
  12167. },
  12168. _subscriptImpl: function(argument){
  12169. // summary:
  12170. // This function implements an over-ride of the superscript command.
  12171. // argument:
  12172. // Not used, operates by selection.
  12173. // tags:
  12174. // protected
  12175. var applied = false;
  12176. if(has("ie") || has("trident")){
  12177. this._adaptIESelection();
  12178. applied = this._adaptIEFormatAreaAndExec("subscript");
  12179. }
  12180. if(!applied){
  12181. applied = this.document.execCommand("subscript", false, argument);
  12182. }
  12183. return applied;
  12184. },
  12185. _fontnameImpl: function(argument){
  12186. // summary:
  12187. // This function implements the fontname command
  12188. // argument:
  12189. // arguments to the exec command, if any.
  12190. // tags:
  12191. // protected
  12192. var isApplied;
  12193. if(has("ie") || has("trident")){
  12194. isApplied = this._handleTextColorOrProperties("fontname", argument);
  12195. }
  12196. if(!isApplied){
  12197. isApplied = this.document.execCommand("fontname", false, argument);
  12198. }
  12199. return isApplied;
  12200. },
  12201. _fontsizeImpl: function(argument){
  12202. // summary:
  12203. // This function implements the fontsize command
  12204. // argument:
  12205. // arguments to the exec command, if any.
  12206. // tags:
  12207. // protected
  12208. var isApplied;
  12209. if(has("ie") || has("trident")){
  12210. isApplied = this._handleTextColorOrProperties("fontsize", argument);
  12211. }
  12212. if(!isApplied){
  12213. isApplied = this.document.execCommand("fontsize", false, argument);
  12214. }
  12215. return isApplied;
  12216. },
  12217. _insertorderedlistImpl: function(argument){
  12218. // summary:
  12219. // This function implements the insertorderedlist command
  12220. // argument:
  12221. // arguments to the exec command, if any.
  12222. // tags:
  12223. // protected
  12224. var applied = false;
  12225. if(has("ie") || has("trident")){
  12226. applied = this._adaptIEList("insertorderedlist", argument);
  12227. }
  12228. if(!applied){
  12229. applied = this.document.execCommand("insertorderedlist", false, argument);
  12230. }
  12231. return applied;
  12232. },
  12233. _insertunorderedlistImpl: function(argument){
  12234. // summary:
  12235. // This function implements the insertunorderedlist command
  12236. // argument:
  12237. // arguments to the exec command, if any.
  12238. // tags:
  12239. // protected
  12240. var applied = false;
  12241. if(has("ie") || has("trident")){
  12242. applied = this._adaptIEList("insertunorderedlist", argument);
  12243. }
  12244. if(!applied){
  12245. applied = this.document.execCommand("insertunorderedlist", false, argument);
  12246. }
  12247. return applied;
  12248. },
  12249. getHeaderHeight: function(){
  12250. // summary:
  12251. // A function for obtaining the height of the header node
  12252. return this._getNodeChildrenHeight(this.header); // Number
  12253. },
  12254. getFooterHeight: function(){
  12255. // summary:
  12256. // A function for obtaining the height of the footer node
  12257. return this._getNodeChildrenHeight(this.footer); // Number
  12258. },
  12259. _getNodeChildrenHeight: function(node){
  12260. // summary:
  12261. // An internal function for computing the cumulative height of all child nodes of 'node'
  12262. // node:
  12263. // The node to process the children of;
  12264. var h = 0;
  12265. if(node && node.childNodes){
  12266. // IE didn't compute it right when position was obtained on the node directly is some cases,
  12267. // so we have to walk over all the children manually.
  12268. var i;
  12269. for(i = 0; i < node.childNodes.length; i++){
  12270. var size = domGeometry.position(node.childNodes[i]);
  12271. h += size.h;
  12272. }
  12273. }
  12274. return h; // Number
  12275. },
  12276. _isNodeEmpty: function(node, startOffset){
  12277. // summary:
  12278. // Function to test if a node is devoid of real content.
  12279. // node:
  12280. // The node to check.
  12281. // tags:
  12282. // private.
  12283. if(node.nodeType === 1/*element*/){
  12284. if(node.childNodes.length > 0){
  12285. return this._isNodeEmpty(node.childNodes[0], startOffset);
  12286. }
  12287. return true;
  12288. }else if(node.nodeType === 3/*text*/){
  12289. return (node.nodeValue.substring(startOffset) === "");
  12290. }
  12291. return false;
  12292. },
  12293. _removeStartingRangeFromRange: function(node, range){
  12294. // summary:
  12295. // Function to adjust selection range by removing the current
  12296. // start node.
  12297. // node:
  12298. // The node to remove from the starting range.
  12299. // range:
  12300. // The range to adapt.
  12301. // tags:
  12302. // private
  12303. if(node.nextSibling){
  12304. range.setStart(node.nextSibling,0);
  12305. }else{
  12306. var parent = node.parentNode;
  12307. while(parent && parent.nextSibling == null){
  12308. //move up the tree until we find a parent that has another node, that node will be the next node
  12309. parent = parent.parentNode;
  12310. }
  12311. if(parent){
  12312. range.setStart(parent.nextSibling,0);
  12313. }
  12314. }
  12315. return range;
  12316. },
  12317. _adaptIESelection: function(){
  12318. // summary:
  12319. // Function to adapt the IE range by removing leading 'newlines'
  12320. // Needed to fix issue with bold/italics/underline not working if
  12321. // range included leading 'newlines'.
  12322. // In IE, if a user starts a selection at the very end of a line,
  12323. // then the native browser commands will fail to execute correctly.
  12324. // To work around the issue, we can remove all empty nodes from
  12325. // the start of the range selection.
  12326. var selection = rangeapi.getSelection(this.window);
  12327. if(selection && selection.rangeCount && !selection.isCollapsed){
  12328. var range = selection.getRangeAt(0);
  12329. var firstNode = range.startContainer;
  12330. var startOffset = range.startOffset;
  12331. while(firstNode.nodeType === 3/*text*/ && startOffset >= firstNode.length && firstNode.nextSibling){
  12332. //traverse the text nodes until we get to the one that is actually highlighted
  12333. startOffset = startOffset - firstNode.length;
  12334. firstNode = firstNode.nextSibling;
  12335. }
  12336. //Remove the starting ranges until the range does not start with an empty node.
  12337. var lastNode=null;
  12338. while(this._isNodeEmpty(firstNode, startOffset) && firstNode !== lastNode){
  12339. lastNode =firstNode; //this will break the loop in case we can't find the next sibling
  12340. range = this._removeStartingRangeFromRange(firstNode, range); //move the start container to the next node in the range
  12341. firstNode = range.startContainer;
  12342. startOffset = 0; //start at the beginning of the new starting range
  12343. }
  12344. selection.removeAllRanges();// this will work as long as users cannot select multiple ranges. I have not been able to do that in the editor.
  12345. selection.addRange(range);
  12346. }
  12347. },
  12348. _adaptIEFormatAreaAndExec: function(command){
  12349. // summary:
  12350. // Function to handle IE's quirkiness regarding how it handles
  12351. // format commands on a word. This involves a lit of node splitting
  12352. // and format cloning.
  12353. // command:
  12354. // The format command, needed to check if the desired
  12355. // command is true or not.
  12356. var selection = rangeapi.getSelection(this.window);
  12357. var doc = this.document;
  12358. var rs, ret, range, txt, startNode, endNode, breaker, sNode;
  12359. if(command && selection && selection.isCollapsed){
  12360. var isApplied = this.queryCommandValue(command);
  12361. if(isApplied){
  12362. // We have to split backwards until we hit the format
  12363. var nNames = this._tagNamesForCommand(command);
  12364. range = selection.getRangeAt(0);
  12365. var fs = range.startContainer;
  12366. if(fs.nodeType === 3){
  12367. var offset = range.endOffset;
  12368. if(fs.length < offset){
  12369. //We are not looking from the right node, try to locate the correct one
  12370. ret = this._adjustNodeAndOffset(rs, offset);
  12371. fs = ret.node;
  12372. offset = ret.offset;
  12373. }
  12374. }
  12375. var topNode;
  12376. while(fs && fs !== this.editNode){
  12377. // We have to walk back and see if this is still a format or not.
  12378. // Hm, how do I do this?
  12379. var tName = fs.tagName? fs.tagName.toLowerCase() : "";
  12380. if(array.indexOf(nNames, tName) > -1){
  12381. topNode = fs;
  12382. break;
  12383. }
  12384. fs = fs.parentNode;
  12385. }
  12386. // Okay, we have a stopping place, time to split things apart.
  12387. if(topNode){
  12388. // Okay, we know how far we have to split backwards, so we have to split now.
  12389. rs = range.startContainer;
  12390. var newblock = doc.createElement(topNode.tagName);
  12391. domConstruct.place(newblock, topNode, "after");
  12392. if(rs && rs.nodeType === 3){
  12393. // Text node, we have to split it.
  12394. var nodeToMove, tNode;
  12395. var endOffset = range.endOffset;
  12396. if(rs.length < endOffset){
  12397. //We are not splitting the right node, try to locate the correct one
  12398. ret = this._adjustNodeAndOffset(rs, endOffset);
  12399. rs = ret.node;
  12400. endOffset = ret.offset;
  12401. }
  12402. txt = rs.nodeValue;
  12403. startNode = doc.createTextNode(txt.substring(0, endOffset));
  12404. var endText = txt.substring(endOffset, txt.length);
  12405. if(endText){
  12406. endNode = doc.createTextNode(endText);
  12407. }
  12408. // Place the split, then remove original nodes.
  12409. domConstruct.place(startNode, rs, "before");
  12410. if(endNode){
  12411. breaker = doc.createElement("span");
  12412. breaker.className = "ieFormatBreakerSpan";
  12413. domConstruct.place(breaker, rs, "after");
  12414. domConstruct.place(endNode, breaker, "after");
  12415. endNode = breaker;
  12416. }
  12417. domConstruct.destroy(rs);
  12418. // Okay, we split the text. Now we need to see if we're
  12419. // parented to the block element we're splitting and if
  12420. // not, we have to split all the way up. Ugh.
  12421. var parentC = startNode.parentNode;
  12422. var tagList = [];
  12423. var tagData;
  12424. while(parentC !== topNode){
  12425. var tg = parentC.tagName;
  12426. tagData = {tagName: tg};
  12427. tagList.push(tagData);
  12428. var newTg = doc.createElement(tg);
  12429. // Clone over any 'style' data.
  12430. if(parentC.style){
  12431. if(newTg.style){
  12432. if(parentC.style.cssText){
  12433. newTg.style.cssText = parentC.style.cssText;
  12434. tagData.cssText = parentC.style.cssText;
  12435. }
  12436. }
  12437. }
  12438. // If font also need to clone over any font data.
  12439. if(parentC.tagName === "FONT"){
  12440. if(parentC.color){
  12441. newTg.color = parentC.color;
  12442. tagData.color = parentC.color;
  12443. }
  12444. if(parentC.face){
  12445. newTg.face = parentC.face;
  12446. tagData.face = parentC.face;
  12447. }
  12448. if(parentC.size){ // this check was necessary on IE
  12449. newTg.size = parentC.size;
  12450. tagData.size = parentC.size;
  12451. }
  12452. }
  12453. if(parentC.className){
  12454. newTg.className = parentC.className;
  12455. tagData.className = parentC.className;
  12456. }
  12457. // Now move end node and every sibling
  12458. // after it over into the new tag.
  12459. if(endNode){
  12460. nodeToMove = endNode;
  12461. while(nodeToMove){
  12462. tNode = nodeToMove.nextSibling;
  12463. newTg.appendChild(nodeToMove);
  12464. nodeToMove = tNode;
  12465. }
  12466. }
  12467. if(newTg.tagName == parentC.tagName){
  12468. breaker = doc.createElement("span");
  12469. breaker.className = "ieFormatBreakerSpan";
  12470. domConstruct.place(breaker, parentC, "after");
  12471. domConstruct.place(newTg, breaker, "after");
  12472. }else{
  12473. domConstruct.place(newTg, parentC, "after");
  12474. }
  12475. startNode = parentC;
  12476. endNode = newTg;
  12477. parentC = parentC.parentNode;
  12478. }
  12479. // Lastly, move the split out all the split tags
  12480. // to the new block as they should now be split properly.
  12481. if(endNode){
  12482. nodeToMove = endNode;
  12483. if(nodeToMove.nodeType === 1 || (nodeToMove.nodeType === 3 && nodeToMove.nodeValue)){
  12484. // Non-blank text and non-text nodes need to clear out that blank space
  12485. // before moving the contents.
  12486. newblock.innerHTML = "";
  12487. }
  12488. while(nodeToMove){
  12489. tNode = nodeToMove.nextSibling;
  12490. newblock.appendChild(nodeToMove);
  12491. nodeToMove = tNode;
  12492. }
  12493. }
  12494. // We had intermediate tags, we have to now recreate them inbetween the split
  12495. // and restore what styles, classnames, etc, we can.
  12496. if(tagList.length){
  12497. tagData = tagList.pop();
  12498. var newContTag = doc.createElement(tagData.tagName);
  12499. if(tagData.cssText && newContTag.style){
  12500. newContTag.style.cssText = tagData.cssText;
  12501. }
  12502. if(tagData.className){
  12503. newContTag.className = tagData.className;
  12504. }
  12505. if(tagData.tagName === "FONT"){
  12506. if(tagData.color){
  12507. newContTag.color = tagData.color;
  12508. }
  12509. if(tagData.face){
  12510. newContTag.face = tagData.face;
  12511. }
  12512. if(tagData.size){
  12513. newContTag.size = tagData.size;
  12514. }
  12515. }
  12516. domConstruct.place(newContTag, newblock, "before");
  12517. while(tagList.length){
  12518. tagData = tagList.pop();
  12519. var newTgNode = doc.createElement(tagData.tagName);
  12520. if(tagData.cssText && newTgNode.style){
  12521. newTgNode.style.cssText = tagData.cssText;
  12522. }
  12523. if(tagData.className){
  12524. newTgNode.className = tagData.className;
  12525. }
  12526. if(tagData.tagName === "FONT"){
  12527. if(tagData.color){
  12528. newTgNode.color = tagData.color;
  12529. }
  12530. if(tagData.face){
  12531. newTgNode.face = tagData.face;
  12532. }
  12533. if(tagData.size){
  12534. newTgNode.size = tagData.size;
  12535. }
  12536. }
  12537. newContTag.appendChild(newTgNode);
  12538. newContTag = newTgNode;
  12539. }
  12540. // Okay, everything is theoretically split apart and removed from the content
  12541. // so insert the dummy text to select, select it, then
  12542. // clear to position cursor.
  12543. sNode = doc.createTextNode(".");
  12544. breaker.appendChild(sNode);
  12545. newContTag.appendChild(sNode);
  12546. win.withGlobal(this.window, lang.hitch(this, function(){
  12547. var newrange = rangeapi.create();
  12548. newrange.setStart(sNode, 0);
  12549. newrange.setEnd(sNode, sNode.length);
  12550. selection.removeAllRanges();
  12551. selection.addRange(newrange);
  12552. selectionapi.collapse(false);
  12553. sNode.parentNode.innerHTML = "";
  12554. }));
  12555. }else{
  12556. // No extra tags, so we have to insert a breaker point and rely
  12557. // on filters to remove it later.
  12558. breaker = doc.createElement("span");
  12559. breaker.className="ieFormatBreakerSpan";
  12560. sNode = doc.createTextNode(".");
  12561. breaker.appendChild(sNode);
  12562. domConstruct.place(breaker, newblock, "before");
  12563. win.withGlobal(this.window, lang.hitch(this, function(){
  12564. var newrange = rangeapi.create();
  12565. newrange.setStart(sNode, 0);
  12566. newrange.setEnd(sNode, sNode.length);
  12567. selection.removeAllRanges();
  12568. selection.addRange(newrange);
  12569. selectionapi.collapse(false);
  12570. sNode.parentNode.innerHTML = "";
  12571. }));
  12572. }
  12573. if(!newblock.firstChild){
  12574. // Empty, we don't need it. Split was at end or similar
  12575. // So, remove it.
  12576. domConstruct.destroy(newblock);
  12577. }
  12578. return true;
  12579. }
  12580. }
  12581. return false;
  12582. }else{
  12583. range = selection.getRangeAt(0);
  12584. rs = range.startContainer;
  12585. if(rs && rs.nodeType === 3){
  12586. // Text node, we have to split it.
  12587. win.withGlobal(this.window, lang.hitch(this, function(){
  12588. var offset = range.startOffset;
  12589. if(rs.length < offset){
  12590. //We are not splitting the right node, try to locate the correct one
  12591. ret = this._adjustNodeAndOffset(rs, offset);
  12592. rs = ret.node;
  12593. offset = ret.offset;
  12594. }
  12595. txt = rs.nodeValue;
  12596. startNode = doc.createTextNode(txt.substring(0, offset));
  12597. var endText = txt.substring(offset);
  12598. if(endText !== ""){
  12599. endNode = doc.createTextNode(txt.substring(offset));
  12600. }
  12601. // Create a space, we'll select and bold it, so
  12602. // the whole word doesn't get bolded
  12603. breaker = doc.createElement("span");
  12604. sNode = doc.createTextNode(".");
  12605. breaker.appendChild(sNode);
  12606. if(startNode.length){
  12607. domConstruct.place(startNode, rs, "after");
  12608. }else{
  12609. startNode = rs;
  12610. }
  12611. domConstruct.place(breaker, startNode, "after");
  12612. if(endNode){
  12613. domConstruct.place(endNode, breaker, "after");
  12614. }
  12615. domConstruct.destroy(rs);
  12616. var newrange = rangeapi.create();
  12617. newrange.setStart(sNode, 0);
  12618. newrange.setEnd(sNode, sNode.length);
  12619. selection.removeAllRanges();
  12620. selection.addRange(newrange);
  12621. doc.execCommand(command);
  12622. domConstruct.place(breaker.firstChild, breaker, "before");
  12623. domConstruct.destroy(breaker);
  12624. newrange.setStart(sNode, 0);
  12625. newrange.setEnd(sNode, sNode.length);
  12626. selection.removeAllRanges();
  12627. selection.addRange(newrange);
  12628. selectionapi.collapse(false);
  12629. sNode.parentNode.innerHTML = "";
  12630. }));
  12631. return true;
  12632. }
  12633. }
  12634. }else{
  12635. return false;
  12636. }
  12637. },
  12638. _adaptIEList: function(command /*===== , argument =====*/){
  12639. // summary:
  12640. // This function handles normalizing the IE list behavior as
  12641. // much as possible.
  12642. // command:
  12643. // The list command to execute.
  12644. // argument:
  12645. // Any additional argument.
  12646. // tags:
  12647. // private
  12648. var selection = rangeapi.getSelection(this.window);
  12649. if(selection.isCollapsed){
  12650. // In the case of no selection, lets commonize the behavior and
  12651. // make sure that it indents if needed.
  12652. if(selection.rangeCount && !this.queryCommandValue(command)){
  12653. var range = selection.getRangeAt(0);
  12654. var sc = range.startContainer;
  12655. if(sc && sc.nodeType == 3){
  12656. // text node. Lets see if there is a node before it that isn't
  12657. // some sort of breaker.
  12658. if(!range.startOffset){
  12659. // We're at the beginning of a text area. It may have been br split
  12660. // Who knows? In any event, we must create the list manually
  12661. // or IE may shove too much into the list element. It seems to
  12662. // grab content before the text node too if it's br split.
  12663. // Why can't IE work like everyone else?
  12664. win.withGlobal(this.window, lang.hitch(this, function(){
  12665. // Create a space, we'll select and bold it, so
  12666. // the whole word doesn't get bolded
  12667. var lType = "ul";
  12668. if(command === "insertorderedlist"){
  12669. lType = "ol";
  12670. }
  12671. var list = domConstruct.create(lType);
  12672. var li = domConstruct.create("li", null, list);
  12673. domConstruct.place(list, sc, "before");
  12674. // Move in the text node as part of the li.
  12675. li.appendChild(sc);
  12676. // We need a br after it or the enter key handler
  12677. // sometimes throws errors.
  12678. domConstruct.create("br", null, list, "after");
  12679. // Okay, now lets move our cursor to the beginning.
  12680. var newrange = rangeapi.create();
  12681. newrange.setStart(sc, 0);
  12682. newrange.setEnd(sc, sc.length);
  12683. selection.removeAllRanges();
  12684. selection.addRange(newrange);
  12685. selectionapi.collapse(true);
  12686. }));
  12687. return true;
  12688. }
  12689. }
  12690. }
  12691. }
  12692. return false;
  12693. },
  12694. _handleTextColorOrProperties: function(command, argument){
  12695. // summary:
  12696. // This function handles appplying text color as best it is
  12697. // able to do so when the selection is collapsed, making the
  12698. // behavior cross-browser consistent. It also handles the name
  12699. // and size for IE.
  12700. // command:
  12701. // The command.
  12702. // argument:
  12703. // Any additional arguments.
  12704. // tags:
  12705. // private
  12706. var selection = rangeapi.getSelection(this.window);
  12707. var doc = this.document;
  12708. var rs, ret, range, txt, startNode, endNode, breaker, sNode;
  12709. argument = argument || null;
  12710. if(command && selection && selection.isCollapsed){
  12711. if(selection.rangeCount){
  12712. range = selection.getRangeAt(0);
  12713. rs = range.startContainer;
  12714. if(rs && rs.nodeType === 3){
  12715. // Text node, we have to split it.
  12716. win.withGlobal(this.window, lang.hitch(this, function(){
  12717. var offset = range.startOffset;
  12718. if(rs.length < offset){
  12719. //We are not splitting the right node, try to locate the correct one
  12720. ret = this._adjustNodeAndOffset(rs, offset);
  12721. rs = ret.node;
  12722. offset = ret.offset;
  12723. }
  12724. txt = rs.nodeValue;
  12725. startNode = doc.createTextNode(txt.substring(0, offset));
  12726. var endText = txt.substring(offset);
  12727. if(endText !== ""){
  12728. endNode = doc.createTextNode(txt.substring(offset));
  12729. }
  12730. // Create a space, we'll select and bold it, so
  12731. // the whole word doesn't get bolded
  12732. breaker = domConstruct.create("span");
  12733. sNode = doc.createTextNode(".");
  12734. breaker.appendChild(sNode);
  12735. // Create a junk node to avoid it trying to stlye the breaker.
  12736. // This will get destroyed later.
  12737. var extraSpan = domConstruct.create("span");
  12738. breaker.appendChild(extraSpan);
  12739. if(startNode.length){
  12740. domConstruct.place(startNode, rs, "after");
  12741. }else{
  12742. startNode = rs;
  12743. }
  12744. domConstruct.place(breaker, startNode, "after");
  12745. if(endNode){
  12746. domConstruct.place(endNode, breaker, "after");
  12747. }
  12748. domConstruct.destroy(rs);
  12749. var newrange = rangeapi.create();
  12750. newrange.setStart(sNode, 0);
  12751. newrange.setEnd(sNode, sNode.length);
  12752. selection.removeAllRanges();
  12753. selection.addRange(newrange);
  12754. if(has("webkit")){
  12755. // WebKit is frustrating with positioning the cursor.
  12756. // It stinks to have a selected space, but there really
  12757. // isn't much choice here.
  12758. var style = "color";
  12759. if(command === "hilitecolor" || command === "backcolor"){
  12760. style = "backgroundColor";
  12761. }
  12762. domStyle.set(breaker, style, argument);
  12763. selectionapi.remove();
  12764. domConstruct.destroy(extraSpan);
  12765. breaker.innerHTML = "&#160;"; // &nbsp;
  12766. selectionapi.selectElement(breaker);
  12767. this.focus();
  12768. }else{
  12769. this.execCommand(command, argument);
  12770. domConstruct.place(breaker.firstChild, breaker, "before");
  12771. domConstruct.destroy(breaker);
  12772. newrange.setStart(sNode, 0);
  12773. newrange.setEnd(sNode, sNode.length);
  12774. selection.removeAllRanges();
  12775. selection.addRange(newrange);
  12776. selectionapi.collapse(false);
  12777. sNode.parentNode.removeChild(sNode);
  12778. }
  12779. }));
  12780. return true;
  12781. }
  12782. }
  12783. }
  12784. return false;
  12785. },
  12786. _adjustNodeAndOffset: function(/*DomNode*/node, /*Int*/offset){
  12787. // summary:
  12788. // In the case there are multiple text nodes in a row the offset may not be within the node.
  12789. // If the offset is larger than the node length, it will attempt to find
  12790. // the next text sibling until it locates the text node in which the offset refers to
  12791. // node:
  12792. // The node to check.
  12793. // offset:
  12794. // The position to find within the text node
  12795. // tags:
  12796. // private.
  12797. while(node.length < offset && node.nextSibling && node.nextSibling.nodeType === 3){
  12798. //Adjust the offset and node in the case of multiple text nodes in a row
  12799. offset = offset - node.length;
  12800. node = node.nextSibling;
  12801. }
  12802. return {"node": node, "offset": offset};
  12803. },
  12804. _tagNamesForCommand: function(command){
  12805. // summary:
  12806. // Function to return the tab names that are associated
  12807. // with a particular style.
  12808. // command: String
  12809. // The command to return tags for.
  12810. // tags:
  12811. // private
  12812. if(command === "bold"){
  12813. return ["b", "strong"];
  12814. }else if(command === "italic"){
  12815. return ["i","em"];
  12816. }else if(command === "strikethrough"){
  12817. return ["s", "strike"];
  12818. }else if(command === "superscript"){
  12819. return ["sup"];
  12820. }else if(command === "subscript"){
  12821. return ["sub"];
  12822. }else if(command === "underline"){
  12823. return ["u"];
  12824. }
  12825. return [];
  12826. },
  12827. _stripBreakerNodes: function(node){
  12828. // summary:
  12829. // Function for stripping out the breaker spans inserted by the formatting command.
  12830. // Registered as a filter for IE, handles the breaker spans needed to fix up
  12831. // How bold/italic/etc, work when selection is collapsed (single cursor).
  12832. win.withGlobal(this.window, lang.hitch(this, function(){
  12833. var breakers = query(".ieFormatBreakerSpan", node);
  12834. var i;
  12835. for(i = 0; i < breakers.length; i++){
  12836. var b = breakers[i];
  12837. while(b.firstChild){
  12838. domConstruct.place(b.firstChild, b, "before");
  12839. }
  12840. domConstruct.destroy(b);
  12841. }
  12842. }));
  12843. return node;
  12844. }
  12845. });
  12846. return RichText;
  12847. });
  12848. },
  12849. 'dojo/dnd/Moveable':function(){
  12850. define(["../main", "../Evented", "../touch", "./Mover"], function(dojo, Evented, touch) {
  12851. // module:
  12852. // dojo/dnd/Moveable
  12853. // summary:
  12854. // TODOC
  12855. /*=====
  12856. dojo.declare("dojo.dnd.__MoveableArgs", [], {
  12857. // handle: Node||String
  12858. // A node (or node's id), which is used as a mouse handle.
  12859. // If omitted, the node itself is used as a handle.
  12860. handle: null,
  12861. // delay: Number
  12862. // delay move by this number of pixels
  12863. delay: 0,
  12864. // skip: Boolean
  12865. // skip move of form elements
  12866. skip: false,
  12867. // mover: Object
  12868. // a constructor of custom Mover
  12869. mover: dojo.dnd.Mover
  12870. });
  12871. =====*/
  12872. dojo.declare("dojo.dnd.Moveable", [Evented], {
  12873. // object attributes (for markup)
  12874. handle: "",
  12875. delay: 0,
  12876. skip: false,
  12877. constructor: function(node, params){
  12878. // summary:
  12879. // an object, which makes a node moveable
  12880. // node: Node
  12881. // a node (or node's id) to be moved
  12882. // params: dojo.dnd.__MoveableArgs?
  12883. // optional parameters
  12884. this.node = dojo.byId(node);
  12885. if(!params){ params = {}; }
  12886. this.handle = params.handle ? dojo.byId(params.handle) : null;
  12887. if(!this.handle){ this.handle = this.node; }
  12888. this.delay = params.delay > 0 ? params.delay : 0;
  12889. this.skip = params.skip;
  12890. this.mover = params.mover ? params.mover : dojo.dnd.Mover;
  12891. this.events = [
  12892. dojo.connect(this.handle, touch.press, this, "onMouseDown"),
  12893. // cancel text selection and text dragging
  12894. dojo.connect(this.handle, "ondragstart", this, "onSelectStart"),
  12895. dojo.connect(this.handle, "onselectstart", this, "onSelectStart")
  12896. ];
  12897. },
  12898. // markup methods
  12899. markupFactory: function(params, node, ctor){
  12900. return new ctor(node, params);
  12901. },
  12902. // methods
  12903. destroy: function(){
  12904. // summary:
  12905. // stops watching for possible move, deletes all references, so the object can be garbage-collected
  12906. dojo.forEach(this.events, dojo.disconnect);
  12907. this.events = this.node = this.handle = null;
  12908. },
  12909. // mouse event processors
  12910. onMouseDown: function(e){
  12911. // summary:
  12912. // event processor for onmousedown/ontouchstart, creates a Mover for the node
  12913. // e: Event
  12914. // mouse/touch event
  12915. if(this.skip && dojo.dnd.isFormElement(e)){ return; }
  12916. if(this.delay){
  12917. this.events.push(
  12918. dojo.connect(this.handle, touch.move, this, "onMouseMove"),
  12919. dojo.connect(this.handle, touch.release, this, "onMouseUp")
  12920. );
  12921. this._lastX = e.pageX;
  12922. this._lastY = e.pageY;
  12923. }else{
  12924. this.onDragDetected(e);
  12925. }
  12926. dojo.stopEvent(e);
  12927. },
  12928. onMouseMove: function(e){
  12929. // summary:
  12930. // event processor for onmousemove/ontouchmove, used only for delayed drags
  12931. // e: Event
  12932. // mouse/touch event
  12933. if(Math.abs(e.pageX - this._lastX) > this.delay || Math.abs(e.pageY - this._lastY) > this.delay){
  12934. this.onMouseUp(e);
  12935. this.onDragDetected(e);
  12936. }
  12937. dojo.stopEvent(e);
  12938. },
  12939. onMouseUp: function(e){
  12940. // summary:
  12941. // event processor for onmouseup, used only for delayed drags
  12942. // e: Event
  12943. // mouse event
  12944. for(var i = 0; i < 2; ++i){
  12945. dojo.disconnect(this.events.pop());
  12946. }
  12947. dojo.stopEvent(e);
  12948. },
  12949. onSelectStart: function(e){
  12950. // summary:
  12951. // event processor for onselectevent and ondragevent
  12952. // e: Event
  12953. // mouse event
  12954. if(!this.skip || !dojo.dnd.isFormElement(e)){
  12955. dojo.stopEvent(e);
  12956. }
  12957. },
  12958. // local events
  12959. onDragDetected: function(/* Event */ e){
  12960. // summary:
  12961. // called when the drag is detected;
  12962. // responsible for creation of the mover
  12963. new this.mover(this.node, e, this);
  12964. },
  12965. onMoveStart: function(/* dojo.dnd.Mover */ mover){
  12966. // summary:
  12967. // called before every move operation
  12968. dojo.publish("/dnd/move/start", [mover]);
  12969. dojo.addClass(dojo.body(), "dojoMove");
  12970. dojo.addClass(this.node, "dojoMoveItem");
  12971. },
  12972. onMoveStop: function(/* dojo.dnd.Mover */ mover){
  12973. // summary:
  12974. // called after every move operation
  12975. dojo.publish("/dnd/move/stop", [mover]);
  12976. dojo.removeClass(dojo.body(), "dojoMove");
  12977. dojo.removeClass(this.node, "dojoMoveItem");
  12978. },
  12979. onFirstMove: function(/* dojo.dnd.Mover */ mover, /* Event */ e){
  12980. // summary:
  12981. // called during the very first move notification;
  12982. // can be used to initialize coordinates, can be overwritten.
  12983. // default implementation does nothing
  12984. },
  12985. onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop, /* Event */ e){
  12986. // summary:
  12987. // called during every move notification;
  12988. // should actually move the node; can be overwritten.
  12989. this.onMoving(mover, leftTop);
  12990. var s = mover.node.style;
  12991. s.left = leftTop.l + "px";
  12992. s.top = leftTop.t + "px";
  12993. this.onMoved(mover, leftTop);
  12994. },
  12995. onMoving: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
  12996. // summary:
  12997. // called before every incremental move; can be overwritten.
  12998. // default implementation does nothing
  12999. },
  13000. onMoved: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
  13001. // summary:
  13002. // called after every incremental move; can be overwritten.
  13003. // default implementation does nothing
  13004. }
  13005. });
  13006. return dojo.dnd.Moveable;
  13007. });
  13008. },
  13009. 'dijit/TooltipDialog':function(){
  13010. define([
  13011. "dojo/_base/declare", // declare
  13012. "dojo/dom-class", // domClass.replace
  13013. "dojo/_base/event", // event.stop
  13014. "dojo/keys", // keys
  13015. "dojo/_base/lang", // lang.hitch
  13016. "./focus",
  13017. "./layout/ContentPane",
  13018. "./_DialogMixin",
  13019. "./form/_FormMixin",
  13020. "./_TemplatedMixin",
  13021. "dojo/text!./templates/TooltipDialog.html",
  13022. "." // exports methods to dijit global
  13023. ], function(declare, domClass, event, keys, lang,
  13024. focus, ContentPane, _DialogMixin, _FormMixin, _TemplatedMixin, template, dijit){
  13025. /*=====
  13026. var ContentPane = dijit.layout.ContentPane;
  13027. var _DialogMixin = dijit._DialogMixin;
  13028. var _FormMixin = dijit.form._FormMixin;
  13029. var _TemplatedMixin = dijit._TemplatedMixin;
  13030. =====*/
  13031. // module:
  13032. // dijit/TooltipDialog
  13033. // summary:
  13034. // Pops up a dialog that appears like a Tooltip
  13035. return declare("dijit.TooltipDialog",
  13036. [ContentPane, _TemplatedMixin, _FormMixin, _DialogMixin], {
  13037. // summary:
  13038. // Pops up a dialog that appears like a Tooltip
  13039. // title: String
  13040. // Description of tooltip dialog (required for a11y)
  13041. title: "",
  13042. // doLayout: [protected] Boolean
  13043. // Don't change this parameter from the default value.
  13044. // This ContentPane parameter doesn't make sense for TooltipDialog, since TooltipDialog
  13045. // is never a child of a layout container, nor can you specify the size of
  13046. // TooltipDialog in order to control the size of an inner widget.
  13047. doLayout: false,
  13048. // autofocus: Boolean
  13049. // A Toggle to modify the default focus behavior of a Dialog, which
  13050. // is to focus on the first dialog element after opening the dialog.
  13051. // False will disable autofocusing. Default: true
  13052. autofocus: true,
  13053. // baseClass: [protected] String
  13054. // The root className to use for the various states of this widget
  13055. baseClass: "dijitTooltipDialog",
  13056. // _firstFocusItem: [private] [readonly] DomNode
  13057. // The pointer to the first focusable node in the dialog.
  13058. // Set by `dijit._DialogMixin._getFocusItems`.
  13059. _firstFocusItem: null,
  13060. // _lastFocusItem: [private] [readonly] DomNode
  13061. // The pointer to which node has focus prior to our dialog.
  13062. // Set by `dijit._DialogMixin._getFocusItems`.
  13063. _lastFocusItem: null,
  13064. templateString: template,
  13065. _setTitleAttr: function(/*String*/ title){
  13066. this.containerNode.title = title;
  13067. this._set("title", title)
  13068. },
  13069. postCreate: function(){
  13070. this.inherited(arguments);
  13071. this.connect(this.containerNode, "onkeypress", "_onKey");
  13072. },
  13073. orient: function(/*DomNode*/ node, /*String*/ aroundCorner, /*String*/ corner){
  13074. // summary:
  13075. // Configure widget to be displayed in given position relative to the button.
  13076. // This is called from the dijit.popup code, and should not be called
  13077. // directly.
  13078. // tags:
  13079. // protected
  13080. var newC = "dijitTooltipAB" + (corner.charAt(1) == 'L' ? "Left" : "Right")
  13081. + " dijitTooltip"
  13082. + (corner.charAt(0) == 'T' ? "Below" : "Above");
  13083. domClass.replace(this.domNode, newC, this._currentOrientClass || "");
  13084. this._currentOrientClass = newC;
  13085. },
  13086. focus: function(){
  13087. // summary:
  13088. // Focus on first field
  13089. this._getFocusItems(this.containerNode);
  13090. focus.focus(this._firstFocusItem);
  13091. },
  13092. onOpen: function(/*Object*/ pos){
  13093. // summary:
  13094. // Called when dialog is displayed.
  13095. // This is called from the dijit.popup code, and should not be called directly.
  13096. // tags:
  13097. // protected
  13098. this.orient(this.domNode,pos.aroundCorner, pos.corner);
  13099. this._onShow(); // lazy load trigger
  13100. },
  13101. onClose: function(){
  13102. // summary:
  13103. // Called when dialog is hidden.
  13104. // This is called from the dijit.popup code, and should not be called directly.
  13105. // tags:
  13106. // protected
  13107. this.onHide();
  13108. },
  13109. _onKey: function(/*Event*/ evt){
  13110. // summary:
  13111. // Handler for keyboard events
  13112. // description:
  13113. // Keep keyboard focus in dialog; close dialog on escape key
  13114. // tags:
  13115. // private
  13116. var node = evt.target;
  13117. if(evt.charOrCode === keys.TAB){
  13118. this._getFocusItems(this.containerNode);
  13119. }
  13120. var singleFocusItem = (this._firstFocusItem == this._lastFocusItem);
  13121. if(evt.charOrCode == keys.ESCAPE){
  13122. // Use setTimeout to avoid crash on IE, see #10396.
  13123. setTimeout(lang.hitch(this, "onCancel"), 0);
  13124. event.stop(evt);
  13125. }else if(node == this._firstFocusItem && evt.shiftKey && evt.charOrCode === keys.TAB){
  13126. if(!singleFocusItem){
  13127. focus.focus(this._lastFocusItem); // send focus to last item in dialog
  13128. }
  13129. event.stop(evt);
  13130. }else if(node == this._lastFocusItem && evt.charOrCode === keys.TAB && !evt.shiftKey){
  13131. if(!singleFocusItem){
  13132. focus.focus(this._firstFocusItem); // send focus to first item in dialog
  13133. }
  13134. event.stop(evt);
  13135. }else if(evt.charOrCode === keys.TAB){
  13136. // we want the browser's default tab handling to move focus
  13137. // but we don't want the tab to propagate upwards
  13138. evt.stopPropagation();
  13139. }
  13140. }
  13141. });
  13142. });
  13143. },
  13144. 'dojo/store/util/SimpleQueryEngine':function(){
  13145. define(["../../_base/array"], function(arrayUtil) {
  13146. // module:
  13147. // dojo/store/util/SimpleQueryEngine
  13148. // summary:
  13149. // The module defines a simple filtering query engine for object stores.
  13150. return function(query, options){
  13151. // summary:
  13152. // Simple query engine that matches using filter functions, named filter
  13153. // functions or objects by name-value on a query object hash
  13154. //
  13155. // description:
  13156. // The SimpleQueryEngine provides a way of getting a QueryResults through
  13157. // the use of a simple object hash as a filter. The hash will be used to
  13158. // match properties on data objects with the corresponding value given. In
  13159. // other words, only exact matches will be returned.
  13160. //
  13161. // This function can be used as a template for more complex query engines;
  13162. // for example, an engine can be created that accepts an object hash that
  13163. // contains filtering functions, or a string that gets evaluated, etc.
  13164. //
  13165. // When creating a new dojo.store, simply set the store's queryEngine
  13166. // field as a reference to this function.
  13167. //
  13168. // query: Object
  13169. // An object hash with fields that may match fields of items in the store.
  13170. // Values in the hash will be compared by normal == operator, but regular expressions
  13171. // or any object that provides a test() method are also supported and can be
  13172. // used to match strings by more complex expressions
  13173. // (and then the regex's or object's test() method will be used to match values).
  13174. //
  13175. // options: dojo.store.util.SimpleQueryEngine.__queryOptions?
  13176. // An object that contains optional information such as sort, start, and count.
  13177. //
  13178. // returns: Function
  13179. // A function that caches the passed query under the field "matches". See any
  13180. // of the "query" methods on dojo.stores.
  13181. //
  13182. // example:
  13183. // Define a store with a reference to this engine, and set up a query method.
  13184. //
  13185. // | var myStore = function(options){
  13186. // | // ...more properties here
  13187. // | this.queryEngine = dojo.store.util.SimpleQueryEngine;
  13188. // | // define our query method
  13189. // | this.query = function(query, options){
  13190. // | return dojo.store.util.QueryResults(this.queryEngine(query, options)(this.data));
  13191. // | };
  13192. // | };
  13193. // create our matching query function
  13194. switch(typeof query){
  13195. default:
  13196. throw new Error("Can not query with a " + typeof query);
  13197. case "object": case "undefined":
  13198. var queryObject = query;
  13199. query = function(object){
  13200. for(var key in queryObject){
  13201. var required = queryObject[key];
  13202. if(required && required.test){
  13203. if(!required.test(object[key])){
  13204. return false;
  13205. }
  13206. }else if(required != object[key]){
  13207. return false;
  13208. }
  13209. }
  13210. return true;
  13211. };
  13212. break;
  13213. case "string":
  13214. // named query
  13215. if(!this[query]){
  13216. throw new Error("No filter function " + query + " was found in store");
  13217. }
  13218. query = this[query];
  13219. // fall through
  13220. case "function":
  13221. // fall through
  13222. }
  13223. function execute(array){
  13224. // execute the whole query, first we filter
  13225. var results = arrayUtil.filter(array, query);
  13226. // next we sort
  13227. if(options && options.sort){
  13228. results.sort(function(a, b){
  13229. for(var sort, i=0; sort = options.sort[i]; i++){
  13230. var aValue = a[sort.attribute];
  13231. var bValue = b[sort.attribute];
  13232. // valueOf enables proper comparison of dates
  13233. aValue = aValue != null ? aValue.valueOf() : aValue;
  13234. bValue = bValue != null ? bValue.valueOf() : bValue;
  13235. if (aValue != bValue) {
  13236. return !!sort.descending == aValue > bValue ? -1 : 1;
  13237. }
  13238. }
  13239. return 0;
  13240. });
  13241. }
  13242. // now we paginate
  13243. if(options && (options.start || options.count)){
  13244. var total = results.length;
  13245. results = results.slice(options.start || 0, (options.start || 0) + (options.count || Infinity));
  13246. results.total = total;
  13247. }
  13248. return results;
  13249. }
  13250. execute.matches = query;
  13251. return execute;
  13252. };
  13253. });
  13254. },
  13255. 'dijit/form/_ExpandingTextAreaMixin':function(){
  13256. define([
  13257. "dojo/_base/declare", // declare
  13258. "dojo/dom-construct", // domConstruct.create
  13259. "dojo/_base/lang", // lang.hitch
  13260. "dojo/_base/window" // win.body
  13261. ], function(declare, domConstruct, lang, win){
  13262. // module:
  13263. // dijit/form/_ExpandingTextAreaMixin
  13264. // summary:
  13265. // Mixin for textarea widgets to add auto-expanding capability
  13266. // feature detection
  13267. var needsHelpShrinking;
  13268. return declare("dijit.form._ExpandingTextAreaMixin", null, {
  13269. // summary:
  13270. // Mixin for textarea widgets to add auto-expanding capability
  13271. _setValueAttr: function(){
  13272. this.inherited(arguments);
  13273. this.resize();
  13274. },
  13275. postCreate: function(){
  13276. this.inherited(arguments);
  13277. var textarea = this.textbox;
  13278. if(needsHelpShrinking == undefined){
  13279. var te = domConstruct.create('textarea', {rows:"5", cols:"20", value: ' ', style: {zoom:1, fontSize:"12px", height:"96px", overflow:'hidden', visibility:'hidden', position:'absolute', border:"5px solid white", margin:"0", padding:"0", boxSizing: 'border-box', MsBoxSizing: 'border-box', WebkitBoxSizing: 'border-box', MozBoxSizing: 'border-box' }}, win.body(), "last");
  13280. needsHelpShrinking = te.scrollHeight >= te.clientHeight;
  13281. win.body().removeChild(te);
  13282. }
  13283. this.connect(textarea, "onresize", "_resizeLater");
  13284. this.connect(textarea, "onfocus", "_resizeLater");
  13285. textarea.style.overflowY = "hidden";
  13286. },
  13287. startup: function(){
  13288. this.inherited(arguments);
  13289. this._resizeLater();
  13290. },
  13291. _onInput: function(e){
  13292. this.inherited(arguments);
  13293. this.resize();
  13294. },
  13295. _estimateHeight: function(){
  13296. // summary:
  13297. // Approximate the height when the textarea is invisible with the number of lines in the text.
  13298. // Fails when someone calls setValue with a long wrapping line, but the layout fixes itself when the user clicks inside so . . .
  13299. // In IE, the resize event is supposed to fire when the textarea becomes visible again and that will correct the size automatically.
  13300. //
  13301. var textarea = this.textbox;
  13302. // #rows = #newlines+1
  13303. textarea.rows = (textarea.value.match(/\n/g) || []).length + 1;
  13304. },
  13305. _resizeLater: function(){
  13306. this.defer("resize");
  13307. },
  13308. resize: function(){
  13309. // summary:
  13310. // Resizes the textarea vertically (should be called after a style/value change)
  13311. var textarea = this.textbox;
  13312. function textareaScrollHeight(){
  13313. var empty = false;
  13314. if(textarea.value === ''){
  13315. textarea.value = ' ';
  13316. empty = true;
  13317. }
  13318. var sh = textarea.scrollHeight;
  13319. if(empty){ textarea.value = ''; }
  13320. return sh;
  13321. }
  13322. if(textarea.style.overflowY == "hidden"){ textarea.scrollTop = 0; }
  13323. if(this.busyResizing){ return; }
  13324. this.busyResizing = true;
  13325. if(textareaScrollHeight() || textarea.offsetHeight){
  13326. var newH = textareaScrollHeight() + Math.max(textarea.offsetHeight - textarea.clientHeight, 0);
  13327. var newHpx = newH + "px";
  13328. if(newHpx != textarea.style.height){
  13329. textarea.style.height = newHpx;
  13330. textarea.rows = 1; // rows can act like a minHeight if not cleared
  13331. }
  13332. if(needsHelpShrinking){
  13333. var origScrollHeight = textareaScrollHeight(),
  13334. newScrollHeight = origScrollHeight,
  13335. origMinHeight = textarea.style.minHeight,
  13336. decrement = 4, // not too fast, not too slow
  13337. thisScrollHeight,
  13338. origScrollTop = textarea.scrollTop;
  13339. textarea.style.minHeight = newHpx; // maintain current height
  13340. textarea.style.height = "auto"; // allow scrollHeight to change
  13341. while(newH > 0){
  13342. textarea.style.minHeight = Math.max(newH - decrement, 4) + "px";
  13343. thisScrollHeight = textareaScrollHeight();
  13344. var change = newScrollHeight - thisScrollHeight;
  13345. newH -= change;
  13346. if(change < decrement){
  13347. break; // scrollHeight didn't shrink
  13348. }
  13349. newScrollHeight = thisScrollHeight;
  13350. decrement <<= 1;
  13351. }
  13352. textarea.style.height = newH + "px";
  13353. textarea.style.minHeight = origMinHeight;
  13354. textarea.scrollTop = origScrollTop;
  13355. }
  13356. textarea.style.overflowY = textareaScrollHeight() > textarea.clientHeight ? "auto" : "hidden";
  13357. if(textarea.style.overflowY == "hidden"){ textarea.scrollTop = 0; }
  13358. }else{
  13359. // hidden content of unknown size
  13360. this._estimateHeight();
  13361. }
  13362. this.busyResizing = false;
  13363. }
  13364. });
  13365. });
  13366. },
  13367. 'dijit/MenuItem':function(){
  13368. define([
  13369. "dojo/_base/declare", // declare
  13370. "dojo/dom", // dom.setSelectable
  13371. "dojo/dom-attr", // domAttr.set
  13372. "dojo/dom-class", // domClass.toggle
  13373. "dojo/_base/event", // event.stop
  13374. "dojo/_base/kernel", // kernel.deprecated
  13375. "dojo/_base/sniff", // has("ie")
  13376. "./_Widget",
  13377. "./_TemplatedMixin",
  13378. "./_Contained",
  13379. "./_CssStateMixin",
  13380. "dojo/text!./templates/MenuItem.html"
  13381. ], function(declare, dom, domAttr, domClass, event, kernel, has,
  13382. _Widget, _TemplatedMixin, _Contained, _CssStateMixin, template){
  13383. /*=====
  13384. var _Widget = dijit._Widget;
  13385. var _TemplatedMixin = dijit._TemplatedMixin;
  13386. var _Contained = dijit._Contained;
  13387. var _CssStateMixin = dijit._CssStateMixin;
  13388. =====*/
  13389. // module:
  13390. // dijit/MenuItem
  13391. // summary:
  13392. // A line item in a Menu Widget
  13393. return declare("dijit.MenuItem",
  13394. [_Widget, _TemplatedMixin, _Contained, _CssStateMixin],
  13395. {
  13396. // summary:
  13397. // A line item in a Menu Widget
  13398. // Make 3 columns
  13399. // icon, label, and expand arrow (BiDi-dependent) indicating sub-menu
  13400. templateString: template,
  13401. baseClass: "dijitMenuItem",
  13402. // label: String
  13403. // Menu text
  13404. label: '',
  13405. _setLabelAttr: { node: "containerNode", type: "innerHTML" },
  13406. // iconClass: String
  13407. // Class to apply to DOMNode to make it display an icon.
  13408. iconClass: "dijitNoIcon",
  13409. _setIconClassAttr: { node: "iconNode", type: "class" },
  13410. // accelKey: String
  13411. // Text for the accelerator (shortcut) key combination.
  13412. // Note that although Menu can display accelerator keys there
  13413. // is no infrastructure to actually catch and execute these
  13414. // accelerators.
  13415. accelKey: "",
  13416. // disabled: Boolean
  13417. // If true, the menu item is disabled.
  13418. // If false, the menu item is enabled.
  13419. disabled: false,
  13420. _fillContent: function(/*DomNode*/ source){
  13421. // If button label is specified as srcNodeRef.innerHTML rather than
  13422. // this.params.label, handle it here.
  13423. if(source && !("label" in this.params)){
  13424. this.set('label', source.innerHTML);
  13425. }
  13426. },
  13427. buildRendering: function(){
  13428. this.inherited(arguments);
  13429. var label = this.id+"_text";
  13430. domAttr.set(this.containerNode, "id", label);
  13431. if(this.accelKeyNode){
  13432. domAttr.set(this.accelKeyNode, "id", this.id + "_accel");
  13433. label += " " + this.id + "_accel";
  13434. }
  13435. this.domNode.setAttribute("aria-labelledby", label);
  13436. dom.setSelectable(this.domNode, false);
  13437. },
  13438. _onHover: function(){
  13439. // summary:
  13440. // Handler when mouse is moved onto menu item
  13441. // tags:
  13442. // protected
  13443. this.getParent().onItemHover(this);
  13444. },
  13445. _onUnhover: function(){
  13446. // summary:
  13447. // Handler when mouse is moved off of menu item,
  13448. // possibly to a child menu, or maybe to a sibling
  13449. // menuitem or somewhere else entirely.
  13450. // tags:
  13451. // protected
  13452. // if we are unhovering the currently selected item
  13453. // then unselect it
  13454. this.getParent().onItemUnhover(this);
  13455. // When menu is hidden (collapsed) due to clicking a MenuItem and having it execute,
  13456. // FF and IE don't generate an onmouseout event for the MenuItem.
  13457. // So, help out _CssStateMixin in this case.
  13458. this._set("hovering", false);
  13459. },
  13460. _onClick: function(evt){
  13461. // summary:
  13462. // Internal handler for click events on MenuItem.
  13463. // tags:
  13464. // private
  13465. this.getParent().onItemClick(this, evt);
  13466. event.stop(evt);
  13467. },
  13468. onClick: function(/*Event*/){
  13469. // summary:
  13470. // User defined function to handle clicks
  13471. // tags:
  13472. // callback
  13473. },
  13474. focus: function(){
  13475. // summary:
  13476. // Focus on this MenuItem
  13477. try{
  13478. if(has("ie") == 8){
  13479. // needed for IE8 which won't scroll TR tags into view on focus yet calling scrollIntoView creates flicker (#10275)
  13480. this.containerNode.focus();
  13481. }
  13482. this.focusNode.focus();
  13483. }catch(e){
  13484. // this throws on IE (at least) in some scenarios
  13485. }
  13486. },
  13487. _onFocus: function(){
  13488. // summary:
  13489. // This is called by the focus manager when focus
  13490. // goes to this MenuItem or a child menu.
  13491. // tags:
  13492. // protected
  13493. this._setSelected(true);
  13494. this.getParent()._onItemFocus(this);
  13495. this.inherited(arguments);
  13496. },
  13497. _setSelected: function(selected){
  13498. // summary:
  13499. // Indicate that this node is the currently selected one
  13500. // tags:
  13501. // private
  13502. /***
  13503. * TODO: remove this method and calls to it, when _onBlur() is working for MenuItem.
  13504. * Currently _onBlur() gets called when focus is moved from the MenuItem to a child menu.
  13505. * That's not supposed to happen, but the problem is:
  13506. * In order to allow dijit.popup's getTopPopup() to work,a sub menu's popupParent
  13507. * points to the parent Menu, bypassing the parent MenuItem... thus the
  13508. * MenuItem is not in the chain of active widgets and gets a premature call to
  13509. * _onBlur()
  13510. */
  13511. domClass.toggle(this.domNode, "dijitMenuItemSelected", selected);
  13512. },
  13513. setLabel: function(/*String*/ content){
  13514. // summary:
  13515. // Deprecated. Use set('label', ...) instead.
  13516. // tags:
  13517. // deprecated
  13518. kernel.deprecated("dijit.MenuItem.setLabel() is deprecated. Use set('label', ...) instead.", "", "2.0");
  13519. this.set("label", content);
  13520. },
  13521. setDisabled: function(/*Boolean*/ disabled){
  13522. // summary:
  13523. // Deprecated. Use set('disabled', bool) instead.
  13524. // tags:
  13525. // deprecated
  13526. kernel.deprecated("dijit.Menu.setDisabled() is deprecated. Use set('disabled', bool) instead.", "", "2.0");
  13527. this.set('disabled', disabled);
  13528. },
  13529. _setDisabledAttr: function(/*Boolean*/ value){
  13530. // summary:
  13531. // Hook for attr('disabled', ...) to work.
  13532. // Enable or disable this menu item.
  13533. this.focusNode.setAttribute('aria-disabled', value ? 'true' : 'false');
  13534. this._set("disabled", value);
  13535. },
  13536. _setAccelKeyAttr: function(/*String*/ value){
  13537. // summary:
  13538. // Hook for attr('accelKey', ...) to work.
  13539. // Set accelKey on this menu item.
  13540. this.accelKeyNode.style.display=value?"":"none";
  13541. this.accelKeyNode.innerHTML=value;
  13542. //have to use colSpan to make it work in IE
  13543. domAttr.set(this.containerNode,'colSpan',value?"1":"2");
  13544. this._set("accelKey", value);
  13545. }
  13546. });
  13547. });
  13548. },
  13549. 'dijit/MenuBarItem':function(){
  13550. define([
  13551. "dojo/_base/declare", // declare
  13552. "./MenuItem",
  13553. "dojo/text!./templates/MenuBarItem.html"
  13554. ], function(declare, MenuItem, template){
  13555. /*=====
  13556. var MenuItem = dijit.MenuItem;
  13557. =====*/
  13558. // module:
  13559. // dijit/MenuBarItem
  13560. // summary:
  13561. // Item in a MenuBar that's clickable, and doesn't spawn a submenu when pressed (or hovered)
  13562. var _MenuBarItemMixin = declare("dijit._MenuBarItemMixin", null, {
  13563. templateString: template,
  13564. // Map widget attributes to DOMNode attributes.
  13565. _setIconClassAttr: null // cancel MenuItem setter because we don't have a place for an icon
  13566. });
  13567. var MenuBarItem = declare("dijit.MenuBarItem", [MenuItem, _MenuBarItemMixin], {
  13568. // summary:
  13569. // Item in a MenuBar that's clickable, and doesn't spawn a submenu when pressed (or hovered)
  13570. });
  13571. MenuBarItem._MenuBarItemMixin = _MenuBarItemMixin; // dojox.mobile is accessing this
  13572. return MenuBarItem;
  13573. });
  13574. },
  13575. 'dijit/layout/TabController':function(){
  13576. define([
  13577. "dojo/_base/declare", // declare
  13578. "dojo/dom", // dom.setSelectable
  13579. "dojo/dom-attr", // domAttr.attr
  13580. "dojo/dom-class", // domClass.toggle
  13581. "dojo/i18n", // i18n.getLocalization
  13582. "dojo/_base/lang", // lang.hitch lang.trim
  13583. "./StackController",
  13584. "../Menu",
  13585. "../MenuItem",
  13586. "dojo/text!./templates/_TabButton.html",
  13587. "dojo/i18n!../nls/common"
  13588. ], function(declare, dom, domAttr, domClass, i18n, lang, StackController, Menu, MenuItem, template){
  13589. /*=====
  13590. var StackController = dijit.layout.StackController;
  13591. var Menu = dijit.Menu;
  13592. var MenuItem = dijit.MenuItem;
  13593. =====*/
  13594. // module:
  13595. // dijit/layout/TabController
  13596. // summary:
  13597. // Set of tabs (the things with titles and a close button, that you click to show a tab panel).
  13598. // Used internally by `dijit.layout.TabContainer`.
  13599. var TabButton = declare("dijit.layout._TabButton", StackController.StackButton, {
  13600. // summary:
  13601. // A tab (the thing you click to select a pane).
  13602. // description:
  13603. // Contains the title of the pane, and optionally a close-button to destroy the pane.
  13604. // This is an internal widget and should not be instantiated directly.
  13605. // tags:
  13606. // private
  13607. // baseClass: String
  13608. // The CSS class applied to the domNode.
  13609. baseClass: "dijitTab",
  13610. // Apply dijitTabCloseButtonHover when close button is hovered
  13611. cssStateNodes: {
  13612. closeNode: "dijitTabCloseButton"
  13613. },
  13614. templateString: template,
  13615. // Override _FormWidget.scrollOnFocus.
  13616. // Don't scroll the whole tab container into view when the button is focused.
  13617. scrollOnFocus: false,
  13618. buildRendering: function(){
  13619. this.inherited(arguments);
  13620. dom.setSelectable(this.containerNode, false);
  13621. },
  13622. startup: function(){
  13623. this.inherited(arguments);
  13624. var n = this.domNode;
  13625. // Required to give IE6 a kick, as it initially hides the
  13626. // tabs until they are focused on.
  13627. setTimeout(function(){
  13628. n.className = n.className;
  13629. }, 1);
  13630. },
  13631. _setCloseButtonAttr: function(/*Boolean*/ disp){
  13632. // summary:
  13633. // Hide/show close button
  13634. this._set("closeButton", disp);
  13635. domClass.toggle(this.innerDiv, "dijitClosable", disp);
  13636. this.closeNode.style.display = disp ? "" : "none";
  13637. if(disp){
  13638. var _nlsResources = i18n.getLocalization("dijit", "common");
  13639. if(this.closeNode){
  13640. domAttr.set(this.closeNode,"title", _nlsResources.itemClose);
  13641. }
  13642. // add context menu onto title button
  13643. this._closeMenu = new Menu({
  13644. id: this.id+"_Menu",
  13645. dir: this.dir,
  13646. lang: this.lang,
  13647. textDir: this.textDir,
  13648. targetNodeIds: [this.domNode]
  13649. });
  13650. this._closeMenu.addChild(new MenuItem({
  13651. label: _nlsResources.itemClose,
  13652. dir: this.dir,
  13653. lang: this.lang,
  13654. textDir: this.textDir,
  13655. onClick: lang.hitch(this, "onClickCloseButton")
  13656. }));
  13657. }else{
  13658. if(this._closeMenu){
  13659. this._closeMenu.destroyRecursive();
  13660. delete this._closeMenu;
  13661. }
  13662. }
  13663. },
  13664. _setLabelAttr: function(/*String*/ content){
  13665. // summary:
  13666. // Hook for set('label', ...) to work.
  13667. // description:
  13668. // takes an HTML string.
  13669. // Inherited ToggleButton implementation will Set the label (text) of the button;
  13670. // Need to set the alt attribute of icon on tab buttons if no label displayed
  13671. this.inherited(arguments);
  13672. if(!this.showLabel && !this.params.title){
  13673. this.iconNode.alt = lang.trim(this.containerNode.innerText || this.containerNode.textContent || '');
  13674. }
  13675. },
  13676. destroy: function(){
  13677. if(this._closeMenu){
  13678. this._closeMenu.destroyRecursive();
  13679. delete this._closeMenu;
  13680. }
  13681. this.inherited(arguments);
  13682. }
  13683. });
  13684. var TabController = declare("dijit.layout.TabController", StackController, {
  13685. // summary:
  13686. // Set of tabs (the things with titles and a close button, that you click to show a tab panel).
  13687. // Used internally by `dijit.layout.TabContainer`.
  13688. // description:
  13689. // Lets the user select the currently shown pane in a TabContainer or StackContainer.
  13690. // TabController also monitors the TabContainer, and whenever a pane is
  13691. // added or deleted updates itself accordingly.
  13692. // tags:
  13693. // private
  13694. baseClass: "dijitTabController",
  13695. templateString: "<div role='tablist' data-dojo-attach-event='onkeypress:onkeypress'></div>",
  13696. // tabPosition: String
  13697. // Defines where tabs go relative to the content.
  13698. // "top", "bottom", "left-h", "right-h"
  13699. tabPosition: "top",
  13700. // buttonWidget: Constructor
  13701. // The tab widget to create to correspond to each page
  13702. buttonWidget: TabButton,
  13703. _rectifyRtlTabList: function(){
  13704. // summary:
  13705. // For left/right TabContainer when page is RTL mode, rectify the width of all tabs to be equal, otherwise the tab widths are different in IE
  13706. if(0 >= this.tabPosition.indexOf('-h')){ return; }
  13707. if(!this.pane2button){ return; }
  13708. var maxWidth = 0;
  13709. for(var pane in this.pane2button){
  13710. var ow = this.pane2button[pane].innerDiv.scrollWidth;
  13711. maxWidth = Math.max(maxWidth, ow);
  13712. }
  13713. //unify the length of all the tabs
  13714. for(pane in this.pane2button){
  13715. this.pane2button[pane].innerDiv.style.width = maxWidth + 'px';
  13716. }
  13717. }
  13718. });
  13719. TabController.TabButton = TabButton; // for monkey patching
  13720. return TabController;
  13721. });
  13722. },
  13723. 'dojo/cldr/supplemental':function(){
  13724. define(["../_base/kernel", "../_base/lang", "../i18n"], function(dojo, lang) {
  13725. // module:
  13726. // dojo/cldr/supplemental
  13727. // summary:
  13728. // TODOC
  13729. lang.getObject("cldr.supplemental", true, dojo);
  13730. dojo.cldr.supplemental.getFirstDayOfWeek = function(/*String?*/locale){
  13731. // summary: Returns a zero-based index for first day of the week
  13732. // description:
  13733. // Returns a zero-based index for first day of the week, as used by the local (Gregorian) calendar.
  13734. // e.g. Sunday (returns 0), or Monday (returns 1)
  13735. // from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/firstDay
  13736. var firstDay = {/*default is 1=Monday*/
  13737. mv:5,
  13738. ae:6,af:6,bh:6,dj:6,dz:6,eg:6,er:6,et:6,iq:6,ir:6,jo:6,ke:6,kw:6,
  13739. ly:6,ma:6,om:6,qa:6,sa:6,sd:6,so:6,sy:6,tn:6,ye:6,
  13740. ar:0,as:0,az:0,bw:0,ca:0,cn:0,fo:0,ge:0,gl:0,gu:0,hk:0,
  13741. il:0,'in':0,jm:0,jp:0,kg:0,kr:0,la:0,mh:0,mn:0,mo:0,mp:0,
  13742. mt:0,nz:0,ph:0,pk:0,sg:0,th:0,tt:0,tw:0,um:0,us:0,uz:0,
  13743. vi:0,zw:0
  13744. // variant. do not use? gb:0,
  13745. };
  13746. var country = dojo.cldr.supplemental._region(locale);
  13747. var dow = firstDay[country];
  13748. return (dow === undefined) ? 1 : dow; /*Number*/
  13749. };
  13750. dojo.cldr.supplemental._region = function(/*String?*/locale){
  13751. locale = dojo.i18n.normalizeLocale(locale);
  13752. var tags = locale.split('-');
  13753. var region = tags[1];
  13754. if(!region){
  13755. // IE often gives language only (#2269)
  13756. // Arbitrary mappings of language-only locales to a country:
  13757. region = {de:"de", en:"us", es:"es", fi:"fi", fr:"fr", he:"il", hu:"hu", it:"it",
  13758. ja:"jp", ko:"kr", nl:"nl", pt:"br", sv:"se", zh:"cn"}[tags[0]];
  13759. }else if(region.length == 4){
  13760. // The ISO 3166 country code is usually in the second position, unless a
  13761. // 4-letter script is given. See http://www.ietf.org/rfc/rfc4646.txt
  13762. region = tags[2];
  13763. }
  13764. return region;
  13765. };
  13766. dojo.cldr.supplemental.getWeekend = function(/*String?*/locale){
  13767. // summary: Returns a hash containing the start and end days of the weekend
  13768. // description:
  13769. // Returns a hash containing the start and end days of the weekend according to local custom using locale,
  13770. // or by default in the user's locale.
  13771. // e.g. {start:6, end:0}
  13772. // from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/weekend{Start,End}
  13773. var weekendStart = {/*default is 6=Saturday*/
  13774. 'in':0,
  13775. af:4,dz:4,ir:4,om:4,sa:4,ye:4,
  13776. ae:5,bh:5,eg:5,il:5,iq:5,jo:5,kw:5,ly:5,ma:5,qa:5,sd:5,sy:5,tn:5
  13777. };
  13778. var weekendEnd = {/*default is 0=Sunday*/
  13779. af:5,dz:5,ir:5,om:5,sa:5,ye:5,
  13780. ae:6,bh:5,eg:6,il:6,iq:6,jo:6,kw:6,ly:6,ma:6,qa:6,sd:6,sy:6,tn:6
  13781. };
  13782. var country = dojo.cldr.supplemental._region(locale);
  13783. var start = weekendStart[country];
  13784. var end = weekendEnd[country];
  13785. if(start === undefined){start=6;}
  13786. if(end === undefined){end=0;}
  13787. return {start:start, end:end}; /*Object {start,end}*/
  13788. };
  13789. return dojo.cldr.supplemental;
  13790. });
  13791. },
  13792. 'dijit/MenuBar':function(){
  13793. require({cache:{
  13794. 'url:dijit/templates/MenuBar.html':"<div class=\"dijitMenuBar dijitMenuPassive\" data-dojo-attach-point=\"containerNode\" role=\"menubar\" tabIndex=\"${tabIndex}\" data-dojo-attach-event=\"onkeypress: _onKeyPress\"></div>\n"}});
  13795. define("dijit/MenuBar", [
  13796. "dojo/_base/declare", // declare
  13797. "dojo/_base/event", // event.stop
  13798. "dojo/keys", // keys.DOWN_ARROW
  13799. "./_MenuBase",
  13800. "dojo/text!./templates/MenuBar.html"
  13801. ], function(declare, event, keys, _MenuBase, template){
  13802. /*=====
  13803. var _MenuBase = dijit._MenuBase;
  13804. =====*/
  13805. // module:
  13806. // dijit/MenuBar
  13807. // summary:
  13808. // A menu bar, listing menu choices horizontally, like the "File" menu in most desktop applications
  13809. return declare("dijit.MenuBar", _MenuBase, {
  13810. // summary:
  13811. // A menu bar, listing menu choices horizontally, like the "File" menu in most desktop applications
  13812. templateString: template,
  13813. baseClass: "dijitMenuBar",
  13814. // _isMenuBar: [protected] Boolean
  13815. // This is a MenuBar widget, not a (vertical) Menu widget.
  13816. _isMenuBar: true,
  13817. postCreate: function(){
  13818. var l = this.isLeftToRight();
  13819. this.connectKeyNavHandlers(
  13820. l ? [keys.LEFT_ARROW] : [keys.RIGHT_ARROW],
  13821. l ? [keys.RIGHT_ARROW] : [keys.LEFT_ARROW]
  13822. );
  13823. // parameter to dijit.popup.open() about where to put popup (relative to this.domNode)
  13824. this._orient = ["below"];
  13825. },
  13826. focusChild: function(item){
  13827. // overload focusChild so that whenever the focus is moved to a new item,
  13828. // check the previous focused whether it has its popup open, if so, after
  13829. // focusing the new item, open its submenu immediately
  13830. var prev_item = this.focusedChild,
  13831. showpopup = prev_item && prev_item.popup && prev_item.popup.isShowingNow;
  13832. this.inherited(arguments);
  13833. if(showpopup && item.popup && !item.disabled){
  13834. this._openPopup(); // TODO: on down arrow, _openPopup() is called here and in onItemClick()
  13835. }
  13836. },
  13837. _onKeyPress: function(/*Event*/ evt){
  13838. // summary:
  13839. // Handle keyboard based menu navigation.
  13840. // tags:
  13841. // protected
  13842. if(evt.ctrlKey || evt.altKey){ return; }
  13843. switch(evt.charOrCode){
  13844. case keys.DOWN_ARROW:
  13845. this._moveToPopup(evt);
  13846. event.stop(evt);
  13847. }
  13848. },
  13849. onItemClick: function(/*dijit._Widget*/ item, /*Event*/ evt){
  13850. // summary:
  13851. // Handle clicks on an item. Cancels a dropdown if already open.
  13852. // tags:
  13853. // private
  13854. if(item.popup && item.popup.isShowingNow){
  13855. item.popup.onCancel();
  13856. }else{
  13857. this.inherited(arguments);
  13858. }
  13859. }
  13860. });
  13861. });
  13862. },
  13863. 'dijit/ToolbarSeparator':function(){
  13864. define("dijit/ToolbarSeparator", [
  13865. "dojo/_base/declare", // declare
  13866. "dojo/dom", // dom.setSelectable
  13867. "./_Widget",
  13868. "./_TemplatedMixin"
  13869. ], function(declare, dom, _Widget, _TemplatedMixin){
  13870. /*=====
  13871. var _Widget = dijit._Widget;
  13872. var _TemplatedMixin = dijit._TemplatedMixin;
  13873. =====*/
  13874. // module:
  13875. // dijit/ToolbarSeparator
  13876. // summary:
  13877. // A spacer between two `dijit.Toolbar` items
  13878. return declare("dijit.ToolbarSeparator", [_Widget, _TemplatedMixin], {
  13879. // summary:
  13880. // A spacer between two `dijit.Toolbar` items
  13881. templateString: '<div class="dijitToolbarSeparator dijitInline" role="presentation"></div>',
  13882. buildRendering: function(){
  13883. this.inherited(arguments);
  13884. dom.setSelectable(this.domNode, false);
  13885. },
  13886. isFocusable: function(){
  13887. // summary:
  13888. // This widget isn't focusable, so pass along that fact.
  13889. // tags:
  13890. // protected
  13891. return false;
  13892. }
  13893. });
  13894. });
  13895. },
  13896. 'dijit/layout/StackController':function(){
  13897. define([
  13898. "dojo/_base/array", // array.forEach array.indexOf array.map
  13899. "dojo/_base/declare", // declare
  13900. "dojo/_base/event", // event.stop
  13901. "dojo/keys", // keys
  13902. "dojo/_base/lang", // lang.getObject
  13903. "dojo/_base/sniff", // has("ie")
  13904. "../focus", // focus.focus()
  13905. "../registry", // registry.byId
  13906. "../_Widget",
  13907. "../_TemplatedMixin",
  13908. "../_Container",
  13909. "../form/ToggleButton",
  13910. "dojo/i18n!../nls/common"
  13911. ], function(array, declare, event, keys, lang, has,
  13912. focus, registry, _Widget, _TemplatedMixin, _Container, ToggleButton){
  13913. /*=====
  13914. var _Widget = dijit._Widget;
  13915. var _TemplatedMixin = dijit._TemplatedMixin;
  13916. var _Container = dijit._Container;
  13917. var ToggleButton = dijit.form.ToggleButton;
  13918. =====*/
  13919. // module:
  13920. // dijit/layout/StackController
  13921. // summary:
  13922. // Set of buttons to select a page in a `dijit.layout.StackContainer`
  13923. var StackButton = declare("dijit.layout._StackButton", ToggleButton, {
  13924. // summary:
  13925. // Internal widget used by StackContainer.
  13926. // description:
  13927. // The button-like or tab-like object you click to select or delete a page
  13928. // tags:
  13929. // private
  13930. // Override _FormWidget.tabIndex.
  13931. // StackContainer buttons are not in the tab order by default.
  13932. // Probably we should be calling this.startupKeyNavChildren() instead.
  13933. tabIndex: "-1",
  13934. // closeButton: Boolean
  13935. // When true, display close button for this tab
  13936. closeButton: false,
  13937. _setCheckedAttr: function(/*Boolean*/ value, /*Boolean?*/ priorityChange){
  13938. this.inherited(arguments);
  13939. this.focusNode.removeAttribute("aria-pressed");
  13940. },
  13941. buildRendering: function(/*Event*/ evt){
  13942. this.inherited(arguments);
  13943. (this.focusNode || this.domNode).setAttribute("role", "tab");
  13944. },
  13945. onClick: function(/*Event*/ /*===== evt =====*/){
  13946. // summary:
  13947. // This is for TabContainer where the tabs are <span> rather than button,
  13948. // so need to set focus explicitly (on some browsers)
  13949. // Note that you shouldn't override this method, but you can connect to it.
  13950. focus.focus(this.focusNode);
  13951. // ... now let StackController catch the event and tell me what to do
  13952. },
  13953. onClickCloseButton: function(/*Event*/ evt){
  13954. // summary:
  13955. // StackContainer connects to this function; if your widget contains a close button
  13956. // then clicking it should call this function.
  13957. // Note that you shouldn't override this method, but you can connect to it.
  13958. evt.stopPropagation();
  13959. }
  13960. });
  13961. var StackController = declare("dijit.layout.StackController", [_Widget, _TemplatedMixin, _Container], {
  13962. // summary:
  13963. // Set of buttons to select a page in a `dijit.layout.StackContainer`
  13964. // description:
  13965. // Monitors the specified StackContainer, and whenever a page is
  13966. // added, deleted, or selected, updates itself accordingly.
  13967. baseClass: "dijitStackController",
  13968. templateString: "<span role='tablist' data-dojo-attach-event='onkeypress'></span>",
  13969. // containerId: [const] String
  13970. // The id of the page container that I point to
  13971. containerId: "",
  13972. // buttonWidget: [const] Constructor
  13973. // The button widget to create to correspond to each page
  13974. buttonWidget: StackButton,
  13975. constructor: function(){
  13976. this.pane2button = {}; // mapping from pane id to buttons
  13977. this.pane2connects = {}; // mapping from pane id to this.connect() handles
  13978. this.pane2watches = {}; // mapping from pane id to watch() handles
  13979. },
  13980. postCreate: function(){
  13981. this.inherited(arguments);
  13982. // Listen to notifications from StackContainer
  13983. this.subscribe(this.containerId+"-startup", "onStartup");
  13984. this.subscribe(this.containerId+"-addChild", "onAddChild");
  13985. this.subscribe(this.containerId+"-removeChild", "onRemoveChild");
  13986. this.subscribe(this.containerId+"-selectChild", "onSelectChild");
  13987. this.subscribe(this.containerId+"-containerKeyPress", "onContainerKeyPress");
  13988. },
  13989. onStartup: function(/*Object*/ info){
  13990. // summary:
  13991. // Called after StackContainer has finished initializing
  13992. // tags:
  13993. // private
  13994. array.forEach(info.children, this.onAddChild, this);
  13995. if(info.selected){
  13996. // Show button corresponding to selected pane (unless selected
  13997. // is null because there are no panes)
  13998. this.onSelectChild(info.selected);
  13999. }
  14000. },
  14001. destroy: function(){
  14002. for(var pane in this.pane2button){
  14003. this.onRemoveChild(registry.byId(pane));
  14004. }
  14005. this.inherited(arguments);
  14006. },
  14007. onAddChild: function(/*dijit._Widget*/ page, /*Integer?*/ insertIndex){
  14008. // summary:
  14009. // Called whenever a page is added to the container.
  14010. // Create button corresponding to the page.
  14011. // tags:
  14012. // private
  14013. // create an instance of the button widget
  14014. // (remove typeof buttonWidget == string support in 2.0)
  14015. var cls = lang.isString(this.buttonWidget) ? lang.getObject(this.buttonWidget) : this.buttonWidget;
  14016. var button = new cls({
  14017. id: this.id + "_" + page.id,
  14018. label: page.title,
  14019. dir: page.dir,
  14020. lang: page.lang,
  14021. textDir: page.textDir,
  14022. showLabel: page.showTitle,
  14023. iconClass: page.iconClass,
  14024. closeButton: page.closable,
  14025. title: page.tooltip
  14026. });
  14027. button.focusNode.setAttribute("aria-selected", "false");
  14028. // map from page attribute to corresponding tab button attribute
  14029. var pageAttrList = ["title", "showTitle", "iconClass", "closable", "tooltip"],
  14030. buttonAttrList = ["label", "showLabel", "iconClass", "closeButton", "title"];
  14031. // watch() so events like page title changes are reflected in tab button
  14032. this.pane2watches[page.id] = array.map(pageAttrList, function(pageAttr, idx){
  14033. return page.watch(pageAttr, function(name, oldVal, newVal){
  14034. button.set(buttonAttrList[idx], newVal);
  14035. });
  14036. });
  14037. // connections so that clicking a tab button selects the corresponding page
  14038. this.pane2connects[page.id] = [
  14039. this.connect(button, 'onClick', lang.hitch(this,"onButtonClick", page)),
  14040. this.connect(button, 'onClickCloseButton', lang.hitch(this,"onCloseButtonClick", page))
  14041. ];
  14042. this.addChild(button, insertIndex);
  14043. this.pane2button[page.id] = button;
  14044. page.controlButton = button; // this value might be overwritten if two tabs point to same container
  14045. if(!this._currentChild){ // put the first child into the tab order
  14046. button.focusNode.setAttribute("tabIndex", "0");
  14047. button.focusNode.setAttribute("aria-selected", "true");
  14048. this._currentChild = page;
  14049. }
  14050. // make sure all tabs have the same length
  14051. if(!this.isLeftToRight() && has("ie") && this._rectifyRtlTabList){
  14052. this._rectifyRtlTabList();
  14053. }
  14054. },
  14055. onRemoveChild: function(/*dijit._Widget*/ page){
  14056. // summary:
  14057. // Called whenever a page is removed from the container.
  14058. // Remove the button corresponding to the page.
  14059. // tags:
  14060. // private
  14061. if(this._currentChild === page){ this._currentChild = null; }
  14062. // disconnect/unwatch connections/watches related to page being removed
  14063. array.forEach(this.pane2connects[page.id], lang.hitch(this, "disconnect"));
  14064. delete this.pane2connects[page.id];
  14065. array.forEach(this.pane2watches[page.id], function(w){ w.unwatch(); });
  14066. delete this.pane2watches[page.id];
  14067. var button = this.pane2button[page.id];
  14068. if(button){
  14069. this.removeChild(button);
  14070. delete this.pane2button[page.id];
  14071. button.destroy();
  14072. }
  14073. delete page.controlButton;
  14074. },
  14075. onSelectChild: function(/*dijit._Widget*/ page){
  14076. // summary:
  14077. // Called when a page has been selected in the StackContainer, either by me or by another StackController
  14078. // tags:
  14079. // private
  14080. if(!page){ return; }
  14081. if(this._currentChild){
  14082. var oldButton=this.pane2button[this._currentChild.id];
  14083. oldButton.set('checked', false);
  14084. oldButton.focusNode.setAttribute("aria-selected", "false");
  14085. oldButton.focusNode.setAttribute("tabIndex", "-1");
  14086. }
  14087. var newButton=this.pane2button[page.id];
  14088. newButton.set('checked', true);
  14089. newButton.focusNode.setAttribute("aria-selected", "true");
  14090. this._currentChild = page;
  14091. newButton.focusNode.setAttribute("tabIndex", "0");
  14092. var container = registry.byId(this.containerId);
  14093. container.containerNode.setAttribute("aria-labelledby", newButton.id);
  14094. },
  14095. onButtonClick: function(/*dijit._Widget*/ page){
  14096. // summary:
  14097. // Called whenever one of my child buttons is pressed in an attempt to select a page
  14098. // tags:
  14099. // private
  14100. if(this._currentChild.id === page.id) {
  14101. //In case the user clicked the checked button, keep it in the checked state because it remains to be the selected stack page.
  14102. var button=this.pane2button[page.id];
  14103. button.set('checked', true);
  14104. }
  14105. var container = registry.byId(this.containerId);
  14106. container.selectChild(page);
  14107. },
  14108. onCloseButtonClick: function(/*dijit._Widget*/ page){
  14109. // summary:
  14110. // Called whenever one of my child buttons [X] is pressed in an attempt to close a page
  14111. // tags:
  14112. // private
  14113. var container = registry.byId(this.containerId);
  14114. container.closeChild(page);
  14115. if(this._currentChild){
  14116. var b = this.pane2button[this._currentChild.id];
  14117. if(b){
  14118. focus.focus(b.focusNode || b.domNode);
  14119. }
  14120. }
  14121. },
  14122. // TODO: this is a bit redundant with forward, back api in StackContainer
  14123. adjacent: function(/*Boolean*/ forward){
  14124. // summary:
  14125. // Helper for onkeypress to find next/previous button
  14126. // tags:
  14127. // private
  14128. if(!this.isLeftToRight() && (!this.tabPosition || /top|bottom/.test(this.tabPosition))){ forward = !forward; }
  14129. // find currently focused button in children array
  14130. var children = this.getChildren();
  14131. var current = array.indexOf(children, this.pane2button[this._currentChild.id]);
  14132. // pick next button to focus on
  14133. var offset = forward ? 1 : children.length - 1;
  14134. return children[ (current + offset) % children.length ]; // dijit._Widget
  14135. },
  14136. onkeypress: function(/*Event*/ e){
  14137. // summary:
  14138. // Handle keystrokes on the page list, for advancing to next/previous button
  14139. // and closing the current page if the page is closable.
  14140. // tags:
  14141. // private
  14142. if(this.disabled || e.altKey ){ return; }
  14143. var forward = null;
  14144. if(e.ctrlKey || !e._djpage){
  14145. switch(e.charOrCode){
  14146. case keys.LEFT_ARROW:
  14147. case keys.UP_ARROW:
  14148. if(!e._djpage){ forward = false; }
  14149. break;
  14150. case keys.PAGE_UP:
  14151. if(e.ctrlKey){ forward = false; }
  14152. break;
  14153. case keys.RIGHT_ARROW:
  14154. case keys.DOWN_ARROW:
  14155. if(!e._djpage){ forward = true; }
  14156. break;
  14157. case keys.PAGE_DOWN:
  14158. if(e.ctrlKey){ forward = true; }
  14159. break;
  14160. case keys.HOME:
  14161. case keys.END:
  14162. var children = this.getChildren();
  14163. if(children && children.length){
  14164. children[e.charOrCode == keys.HOME ? 0 : children.length-1].onClick();
  14165. }
  14166. event.stop(e);
  14167. break;
  14168. case keys.DELETE:
  14169. if(this._currentChild.closable){
  14170. this.onCloseButtonClick(this._currentChild);
  14171. }
  14172. event.stop(e);
  14173. break;
  14174. default:
  14175. if(e.ctrlKey){
  14176. if(e.charOrCode === keys.TAB){
  14177. this.adjacent(!e.shiftKey).onClick();
  14178. event.stop(e);
  14179. }else if(e.charOrCode == "w"){
  14180. if(this._currentChild.closable){
  14181. this.onCloseButtonClick(this._currentChild);
  14182. }
  14183. event.stop(e); // avoid browser tab closing.
  14184. }
  14185. }
  14186. }
  14187. // handle next/previous page navigation (left/right arrow, etc.)
  14188. if(forward !== null){
  14189. this.adjacent(forward).onClick();
  14190. event.stop(e);
  14191. }
  14192. }
  14193. },
  14194. onContainerKeyPress: function(/*Object*/ info){
  14195. // summary:
  14196. // Called when there was a keypress on the container
  14197. // tags:
  14198. // private
  14199. info.e._djpage = info.page;
  14200. this.onkeypress(info.e);
  14201. }
  14202. });
  14203. StackController.StackButton = StackButton; // for monkey patching
  14204. return StackController;
  14205. });
  14206. },
  14207. 'url:dijit/templates/TooltipDialog.html':"<div role=\"presentation\" tabIndex=\"-1\">\n\t<div class=\"dijitTooltipContainer\" role=\"presentation\">\n\t\t<div class =\"dijitTooltipContents dijitTooltipFocusNode\" data-dojo-attach-point=\"containerNode\" role=\"dialog\"></div>\n\t</div>\n\t<div class=\"dijitTooltipConnector\" role=\"presentation\"></div>\n</div>\n",
  14208. 'dojo/dnd/Mover':function(){
  14209. define(["../main", "../Evented", "../touch", "./common", "./autoscroll"], function(dojo, Evented, touch) {
  14210. // module:
  14211. // dojo/dnd/Mover
  14212. // summary:
  14213. // TODOC
  14214. dojo.declare("dojo.dnd.Mover", [Evented], {
  14215. constructor: function(node, e, host){
  14216. // summary:
  14217. // an object which makes a node follow the mouse, or touch-drag on touch devices.
  14218. // Used as a default mover, and as a base class for custom movers.
  14219. // node: Node
  14220. // a node (or node's id) to be moved
  14221. // e: Event
  14222. // a mouse event, which started the move;
  14223. // only pageX and pageY properties are used
  14224. // host: Object?
  14225. // object which implements the functionality of the move,
  14226. // and defines proper events (onMoveStart and onMoveStop)
  14227. this.node = dojo.byId(node);
  14228. this.marginBox = {l: e.pageX, t: e.pageY};
  14229. this.mouseButton = e.button;
  14230. var h = (this.host = host), d = node.ownerDocument;
  14231. this.events = [
  14232. // At the start of a drag, onFirstMove is called, and then the following two
  14233. // connects are disconnected
  14234. dojo.connect(d, touch.move, this, "onFirstMove"),
  14235. // These are called continually during the drag
  14236. dojo.connect(d, touch.move, this, "onMouseMove"),
  14237. // And these are called at the end of the drag
  14238. dojo.connect(d, touch.release, this, "onMouseUp"),
  14239. // cancel text selection and text dragging
  14240. dojo.connect(d, "ondragstart", dojo.stopEvent),
  14241. dojo.connect(d.body, "onselectstart", dojo.stopEvent)
  14242. ];
  14243. // notify that the move has started
  14244. if(h && h.onMoveStart){
  14245. h.onMoveStart(this);
  14246. }
  14247. },
  14248. // mouse event processors
  14249. onMouseMove: function(e){
  14250. // summary:
  14251. // event processor for onmousemove/ontouchmove
  14252. // e: Event
  14253. // mouse/touch event
  14254. dojo.dnd.autoScroll(e);
  14255. var m = this.marginBox;
  14256. this.host.onMove(this, {l: m.l + e.pageX, t: m.t + e.pageY}, e);
  14257. dojo.stopEvent(e);
  14258. },
  14259. onMouseUp: function(e){
  14260. if(dojo.isWebKit && dojo.isMac && this.mouseButton == 2 ?
  14261. e.button == 0 : this.mouseButton == e.button){ // TODO Should condition be met for touch devices, too?
  14262. this.destroy();
  14263. }
  14264. dojo.stopEvent(e);
  14265. },
  14266. // utilities
  14267. onFirstMove: function(e){
  14268. // summary:
  14269. // makes the node absolute; it is meant to be called only once.
  14270. // relative and absolutely positioned nodes are assumed to use pixel units
  14271. var s = this.node.style, l, t, h = this.host;
  14272. switch(s.position){
  14273. case "relative":
  14274. case "absolute":
  14275. // assume that left and top values are in pixels already
  14276. l = Math.round(parseFloat(s.left)) || 0;
  14277. t = Math.round(parseFloat(s.top)) || 0;
  14278. break;
  14279. default:
  14280. s.position = "absolute"; // enforcing the absolute mode
  14281. var m = dojo.marginBox(this.node);
  14282. // event.pageX/pageY (which we used to generate the initial
  14283. // margin box) includes padding and margin set on the body.
  14284. // However, setting the node's position to absolute and then
  14285. // doing dojo.marginBox on it *doesn't* take that additional
  14286. // space into account - so we need to subtract the combined
  14287. // padding and margin. We use getComputedStyle and
  14288. // _getMarginBox/_getContentBox to avoid the extra lookup of
  14289. // the computed style.
  14290. var b = dojo.doc.body;
  14291. var bs = dojo.getComputedStyle(b);
  14292. var bm = dojo._getMarginBox(b, bs);
  14293. var bc = dojo._getContentBox(b, bs);
  14294. l = m.l - (bc.l - bm.l);
  14295. t = m.t - (bc.t - bm.t);
  14296. break;
  14297. }
  14298. this.marginBox.l = l - this.marginBox.l;
  14299. this.marginBox.t = t - this.marginBox.t;
  14300. if(h && h.onFirstMove){
  14301. h.onFirstMove(this, e);
  14302. }
  14303. // Disconnect onmousemove and ontouchmove events that call this function
  14304. dojo.disconnect(this.events.shift());
  14305. },
  14306. destroy: function(){
  14307. // summary:
  14308. // stops the move, deletes all references, so the object can be garbage-collected
  14309. dojo.forEach(this.events, dojo.disconnect);
  14310. // undo global settings
  14311. var h = this.host;
  14312. if(h && h.onMoveStop){
  14313. h.onMoveStop(this);
  14314. }
  14315. // destroy objects
  14316. this.events = this.node = this.host = null;
  14317. }
  14318. });
  14319. return dojo.dnd.Mover;
  14320. });
  14321. },
  14322. 'dijit/form/HorizontalRule':function(){
  14323. define([
  14324. "dojo/_base/declare", // declare
  14325. "../_Widget",
  14326. "../_TemplatedMixin"
  14327. ], function(declare, _Widget, _TemplatedMixin){
  14328. /*=====
  14329. var _Widget = dijit._Widget;
  14330. var _TemplatedMixin = dijit._TemplatedMixin;
  14331. =====*/
  14332. // module:
  14333. // dijit/form/HorizontalRule
  14334. // summary:
  14335. // Hash marks for `dijit.form.HorizontalSlider`
  14336. return declare("dijit.form.HorizontalRule", [_Widget, _TemplatedMixin], {
  14337. // summary:
  14338. // Hash marks for `dijit.form.HorizontalSlider`
  14339. templateString: '<div class="dijitRuleContainer dijitRuleContainerH"></div>',
  14340. // count: Integer
  14341. // Number of hash marks to generate
  14342. count: 3,
  14343. // container: String
  14344. // For HorizontalSlider, this is either "topDecoration" or "bottomDecoration",
  14345. // and indicates whether this rule goes above or below the slider.
  14346. container: "containerNode",
  14347. // ruleStyle: String
  14348. // CSS style to apply to individual hash marks
  14349. ruleStyle: "",
  14350. _positionPrefix: '<div class="dijitRuleMark dijitRuleMarkH" style="left:',
  14351. _positionSuffix: '%;',
  14352. _suffix: '"></div>',
  14353. _genHTML: function(pos){
  14354. return this._positionPrefix + pos + this._positionSuffix + this.ruleStyle + this._suffix;
  14355. },
  14356. // _isHorizontal: [protected extension] Boolean
  14357. // VerticalRule will override this...
  14358. _isHorizontal: true,
  14359. buildRendering: function(){
  14360. this.inherited(arguments);
  14361. var innerHTML;
  14362. if(this.count == 1){
  14363. innerHTML = this._genHTML(50, 0);
  14364. }else{
  14365. var i;
  14366. var interval = 100 / (this.count-1);
  14367. if(!this._isHorizontal || this.isLeftToRight()){
  14368. innerHTML = this._genHTML(0, 0);
  14369. for(i=1; i < this.count-1; i++){
  14370. innerHTML += this._genHTML(interval*i, i);
  14371. }
  14372. innerHTML += this._genHTML(100, this.count-1);
  14373. }else{
  14374. innerHTML = this._genHTML(100, 0);
  14375. for(i=1; i < this.count-1; i++){
  14376. innerHTML += this._genHTML(100-interval*i, i);
  14377. }
  14378. innerHTML += this._genHTML(0, this.count-1);
  14379. }
  14380. }
  14381. this.domNode.innerHTML = innerHTML;
  14382. }
  14383. });
  14384. });
  14385. },
  14386. 'dijit/layout/TabContainer':function(){
  14387. define([
  14388. "dojo/_base/lang", // lang.getObject
  14389. "dojo/_base/declare", // declare
  14390. "./_TabContainerBase",
  14391. "./TabController",
  14392. "./ScrollingTabController"
  14393. ], function(lang, declare, _TabContainerBase, TabController, ScrollingTabController){
  14394. /*=====
  14395. var _TabContainerBase = dijit.layout._TabContainerBase;
  14396. var TabController = dijit.layout.TabController;
  14397. var ScrollingTabController = dijit.layout.ScrollingTabController;
  14398. =====*/
  14399. // module:
  14400. // dijit/layout/TabContainer
  14401. // summary:
  14402. // A Container with tabs to select each child (only one of which is displayed at a time).
  14403. return declare("dijit.layout.TabContainer", _TabContainerBase, {
  14404. // summary:
  14405. // A Container with tabs to select each child (only one of which is displayed at a time).
  14406. // description:
  14407. // A TabContainer is a container that has multiple panes, but shows only
  14408. // one pane at a time. There are a set of tabs corresponding to each pane,
  14409. // where each tab has the name (aka title) of the pane, and optionally a close button.
  14410. // useMenu: [const] Boolean
  14411. // True if a menu should be used to select tabs when they are too
  14412. // wide to fit the TabContainer, false otherwise.
  14413. useMenu: true,
  14414. // useSlider: [const] Boolean
  14415. // True if a slider should be used to select tabs when they are too
  14416. // wide to fit the TabContainer, false otherwise.
  14417. useSlider: true,
  14418. // controllerWidget: String
  14419. // An optional parameter to override the widget used to display the tab labels
  14420. controllerWidget: "",
  14421. _makeController: function(/*DomNode*/ srcNode){
  14422. // summary:
  14423. // Instantiate tablist controller widget and return reference to it.
  14424. // Callback from _TabContainerBase.postCreate().
  14425. // tags:
  14426. // protected extension
  14427. var cls = this.baseClass + "-tabs" + (this.doLayout ? "" : " dijitTabNoLayout"),
  14428. TabController = lang.getObject(this.controllerWidget);
  14429. return new TabController({
  14430. id: this.id + "_tablist",
  14431. dir: this.dir,
  14432. lang: this.lang,
  14433. textDir: this.textDir,
  14434. tabPosition: this.tabPosition,
  14435. doLayout: this.doLayout,
  14436. containerId: this.id,
  14437. "class": cls,
  14438. nested: this.nested,
  14439. useMenu: this.useMenu,
  14440. useSlider: this.useSlider,
  14441. tabStripClass: this.tabStrip ? this.baseClass + (this.tabStrip ? "":"No") + "Strip": null
  14442. }, srcNode);
  14443. },
  14444. postMixInProperties: function(){
  14445. this.inherited(arguments);
  14446. // Scrolling controller only works for horizontal non-nested tabs
  14447. if(!this.controllerWidget){
  14448. this.controllerWidget = (this.tabPosition == "top" || this.tabPosition == "bottom") && !this.nested ?
  14449. "dijit.layout.ScrollingTabController" : "dijit.layout.TabController";
  14450. }
  14451. }
  14452. });
  14453. });
  14454. },
  14455. 'url:dijit/templates/Menu.html':"<table class=\"dijit dijitMenu dijitMenuPassive dijitReset dijitMenuTable\" role=\"menu\" tabIndex=\"${tabIndex}\" data-dojo-attach-event=\"onkeypress:_onKeyPress\" cellspacing=\"0\">\n\t<tbody class=\"dijitReset\" data-dojo-attach-point=\"containerNode\"></tbody>\n</table>\n",
  14456. 'dijit/form/_Spinner':function(){
  14457. define([
  14458. "dojo/_base/declare", // declare
  14459. "dojo/_base/event", // event.stop
  14460. "dojo/keys", // keys keys.DOWN_ARROW keys.PAGE_DOWN keys.PAGE_UP keys.UP_ARROW
  14461. "dojo/_base/lang", // lang.hitch
  14462. "dojo/_base/sniff", // has("mozilla")
  14463. "dijit/typematic",
  14464. "./RangeBoundTextBox",
  14465. "dojo/text!./templates/Spinner.html",
  14466. "./_TextBoxMixin" // selectInputText
  14467. ], function(declare, event, keys, lang, has, typematic, RangeBoundTextBox, template, _TextBoxMixin){
  14468. /*=====
  14469. var RangeBoundTextBox = dijit.form.RangeBoundTextBox;
  14470. =====*/
  14471. // module:
  14472. // dijit/form/_Spinner
  14473. // summary:
  14474. // Mixin for validation widgets with a spinner.
  14475. return declare("dijit.form._Spinner", RangeBoundTextBox, {
  14476. // summary:
  14477. // Mixin for validation widgets with a spinner.
  14478. // description:
  14479. // This class basically (conceptually) extends `dijit.form.ValidationTextBox`.
  14480. // It modifies the template to have up/down arrows, and provides related handling code.
  14481. // defaultTimeout: Number
  14482. // Number of milliseconds before a held arrow key or up/down button becomes typematic
  14483. defaultTimeout: 500,
  14484. // minimumTimeout: Number
  14485. // minimum number of milliseconds that typematic event fires when held key or button is held
  14486. minimumTimeout: 10,
  14487. // timeoutChangeRate: Number
  14488. // Fraction of time used to change the typematic timer between events.
  14489. // 1.0 means that each typematic event fires at defaultTimeout intervals.
  14490. // < 1.0 means that each typematic event fires at an increasing faster rate.
  14491. timeoutChangeRate: 0.90,
  14492. // smallDelta: Number
  14493. // Adjust the value by this much when spinning using the arrow keys/buttons
  14494. smallDelta: 1,
  14495. // largeDelta: Number
  14496. // Adjust the value by this much when spinning using the PgUp/Dn keys
  14497. largeDelta: 10,
  14498. templateString: template,
  14499. baseClass: "dijitTextBox dijitSpinner",
  14500. // Set classes like dijitUpArrowButtonHover or dijitDownArrowButtonActive depending on
  14501. // mouse action over specified node
  14502. cssStateNodes: {
  14503. "upArrowNode": "dijitUpArrowButton",
  14504. "downArrowNode": "dijitDownArrowButton"
  14505. },
  14506. adjust: function(val /*=====, delta =====*/){
  14507. // summary:
  14508. // Overridable function used to adjust a primitive value(Number/Date/...) by the delta amount specified.
  14509. // The val is adjusted in a way that makes sense to the object type.
  14510. // val: Object
  14511. // delta: Number
  14512. // tags:
  14513. // protected extension
  14514. return val;
  14515. },
  14516. _arrowPressed: function(/*Node*/ nodePressed, /*Number*/ direction, /*Number*/ increment){
  14517. // summary:
  14518. // Handler for arrow button or arrow key being pressed
  14519. if(this.disabled || this.readOnly){ return; }
  14520. this._setValueAttr(this.adjust(this.get('value'), direction*increment), false);
  14521. _TextBoxMixin.selectInputText(this.textbox, this.textbox.value.length);
  14522. },
  14523. _arrowReleased: function(/*Node*/ /*===== node =====*/){
  14524. // summary:
  14525. // Handler for arrow button or arrow key being released
  14526. this._wheelTimer = null;
  14527. },
  14528. _typematicCallback: function(/*Number*/ count, /*DOMNode*/ node, /*Event*/ evt){
  14529. var inc=this.smallDelta;
  14530. if(node == this.textbox){
  14531. var key = evt.charOrCode;
  14532. inc = (key == keys.PAGE_UP || key == keys.PAGE_DOWN) ? this.largeDelta : this.smallDelta;
  14533. node = (key == keys.UP_ARROW || key == keys.PAGE_UP) ? this.upArrowNode : this.downArrowNode;
  14534. }
  14535. if(count == -1){ this._arrowReleased(node); }
  14536. else{ this._arrowPressed(node, (node == this.upArrowNode) ? 1 : -1, inc); }
  14537. },
  14538. _wheelTimer: null,
  14539. _mouseWheeled: function(/*Event*/ evt){
  14540. // summary:
  14541. // Mouse wheel listener where supported
  14542. event.stop(evt);
  14543. // FIXME: Safari bubbles
  14544. // be nice to DOH and scroll as much as the event says to
  14545. var wheelDelta = evt.wheelDelta / 120;
  14546. if(Math.floor(wheelDelta) != wheelDelta){
  14547. // If not an int multiple of 120, then its touchpad scrolling.
  14548. // This can change very fast so just assume 1 wheel click to make it more manageable.
  14549. wheelDelta = evt.wheelDelta > 0 ? 1 : -1;
  14550. }
  14551. var scrollAmount = evt.detail ? (evt.detail * -1) : wheelDelta;
  14552. if(scrollAmount !== 0){
  14553. var node = this[(scrollAmount > 0 ? "upArrowNode" : "downArrowNode" )];
  14554. this._arrowPressed(node, scrollAmount, this.smallDelta);
  14555. if(!this._wheelTimer){
  14556. clearTimeout(this._wheelTimer);
  14557. }
  14558. this._wheelTimer = setTimeout(lang.hitch(this,"_arrowReleased",node), 50);
  14559. }
  14560. },
  14561. postCreate: function(){
  14562. this.inherited(arguments);
  14563. // extra listeners
  14564. this.connect(this.domNode, !has("mozilla") ? "onmousewheel" : 'DOMMouseScroll', "_mouseWheeled");
  14565. this._connects.push(typematic.addListener(this.upArrowNode, this.textbox, {charOrCode:keys.UP_ARROW,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
  14566. this._connects.push(typematic.addListener(this.downArrowNode, this.textbox, {charOrCode:keys.DOWN_ARROW,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
  14567. this._connects.push(typematic.addListener(this.upArrowNode, this.textbox, {charOrCode:keys.PAGE_UP,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
  14568. this._connects.push(typematic.addListener(this.downArrowNode, this.textbox, {charOrCode:keys.PAGE_DOWN,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
  14569. }
  14570. });
  14571. });
  14572. },
  14573. 'dijit/form/Button':function(){
  14574. define([
  14575. "require",
  14576. "dojo/_base/declare", // declare
  14577. "dojo/dom-class", // domClass.toggle
  14578. "dojo/_base/kernel", // kernel.deprecated
  14579. "dojo/_base/lang", // lang.trim
  14580. "dojo/ready",
  14581. "./_FormWidget",
  14582. "./_ButtonMixin",
  14583. "dojo/text!./templates/Button.html"
  14584. ], function(require, declare, domClass, kernel, lang, ready, _FormWidget, _ButtonMixin, template){
  14585. /*=====
  14586. var _FormWidget = dijit.form._FormWidget;
  14587. var _ButtonMixin = dijit.form._ButtonMixin;
  14588. =====*/
  14589. // module:
  14590. // dijit/form/Button
  14591. // summary:
  14592. // Button widget
  14593. // Back compat w/1.6, remove for 2.0
  14594. if(!kernel.isAsync){
  14595. ready(0, function(){
  14596. var requires = ["dijit/form/DropDownButton", "dijit/form/ComboButton", "dijit/form/ToggleButton"];
  14597. require(requires); // use indirection so modules not rolled into a build
  14598. });
  14599. }
  14600. return declare("dijit.form.Button", [_FormWidget, _ButtonMixin], {
  14601. // summary:
  14602. // Basically the same thing as a normal HTML button, but with special styling.
  14603. // description:
  14604. // Buttons can display a label, an icon, or both.
  14605. // A label should always be specified (through innerHTML) or the label
  14606. // attribute. It can be hidden via showLabel=false.
  14607. // example:
  14608. // | <button data-dojo-type="dijit.form.Button" onClick="...">Hello world</button>
  14609. //
  14610. // example:
  14611. // | var button1 = new dijit.form.Button({label: "hello world", onClick: foo});
  14612. // | dojo.body().appendChild(button1.domNode);
  14613. // showLabel: Boolean
  14614. // Set this to true to hide the label text and display only the icon.
  14615. // (If showLabel=false then iconClass must be specified.)
  14616. // Especially useful for toolbars.
  14617. // If showLabel=true, the label will become the title (a.k.a. tooltip/hint) of the icon.
  14618. //
  14619. // The exception case is for computers in high-contrast mode, where the label
  14620. // will still be displayed, since the icon doesn't appear.
  14621. showLabel: true,
  14622. // iconClass: String
  14623. // Class to apply to DOMNode in button to make it display an icon
  14624. iconClass: "dijitNoIcon",
  14625. _setIconClassAttr: { node: "iconNode", type: "class" },
  14626. baseClass: "dijitButton",
  14627. templateString: template,
  14628. // Map widget attributes to DOMNode attributes.
  14629. _setValueAttr: "valueNode",
  14630. _onClick: function(/*Event*/ e){
  14631. // summary:
  14632. // Internal function to handle click actions
  14633. var ok = this.inherited(arguments);
  14634. if(ok){
  14635. if(this.valueNode){
  14636. this.valueNode.click();
  14637. e.preventDefault(); // cancel BUTTON click and continue with hidden INPUT click
  14638. // leave ok = true so that subclasses can do what they need to do
  14639. }
  14640. }
  14641. return ok;
  14642. },
  14643. _fillContent: function(/*DomNode*/ source){
  14644. // Overrides _Templated._fillContent().
  14645. // If button label is specified as srcNodeRef.innerHTML rather than
  14646. // this.params.label, handle it here.
  14647. // TODO: remove the method in 2.0, parser will do it all for me
  14648. if(source && (!this.params || !("label" in this.params))){
  14649. var sourceLabel = lang.trim(source.innerHTML);
  14650. if(sourceLabel){
  14651. this.label = sourceLabel; // _applyAttributes will be called after buildRendering completes to update the DOM
  14652. }
  14653. }
  14654. },
  14655. _setShowLabelAttr: function(val){
  14656. if(this.containerNode){
  14657. domClass.toggle(this.containerNode, "dijitDisplayNone", !val);
  14658. }
  14659. this._set("showLabel", val);
  14660. },
  14661. setLabel: function(/*String*/ content){
  14662. // summary:
  14663. // Deprecated. Use set('label', ...) instead.
  14664. kernel.deprecated("dijit.form.Button.setLabel() is deprecated. Use set('label', ...) instead.", "", "2.0");
  14665. this.set("label", content);
  14666. },
  14667. _setLabelAttr: function(/*String*/ content){
  14668. // summary:
  14669. // Hook for set('label', ...) to work.
  14670. // description:
  14671. // Set the label (text) of the button; takes an HTML string.
  14672. // If the label is hidden (showLabel=false) then and no title has
  14673. // been specified, then label is also set as title attribute of icon.
  14674. this.inherited(arguments);
  14675. if(!this.showLabel && !("title" in this.params)){
  14676. this.titleNode.title = lang.trim(this.containerNode.innerText || this.containerNode.textContent || '');
  14677. }
  14678. }
  14679. });
  14680. });
  14681. },
  14682. 'url:dijit/layout/templates/TabContainer.html':"<div class=\"dijitTabContainer\">\n\t<div class=\"dijitTabListWrapper\" data-dojo-attach-point=\"tablistNode\"></div>\n\t<div data-dojo-attach-point=\"tablistSpacer\" class=\"dijitTabSpacer ${baseClass}-spacer\"></div>\n\t<div class=\"dijitTabPaneWrapper ${baseClass}-container\" data-dojo-attach-point=\"containerNode\"></div>\n</div>\n",
  14683. 'dojo/dnd/move':function(){
  14684. define(["../main", "./Mover", "./Moveable"], function(dojo) {
  14685. // module:
  14686. // dojo/dnd/move
  14687. // summary:
  14688. // TODOC
  14689. /*=====
  14690. dojo.declare("dojo.dnd.move.__constrainedMoveableArgs", [dojo.dnd.__MoveableArgs], {
  14691. // constraints: Function
  14692. // Calculates a constraint box.
  14693. // It is called in a context of the moveable object.
  14694. constraints: function(){},
  14695. // within: Boolean
  14696. // restrict move within boundaries.
  14697. within: false
  14698. });
  14699. =====*/
  14700. dojo.declare("dojo.dnd.move.constrainedMoveable", dojo.dnd.Moveable, {
  14701. // object attributes (for markup)
  14702. constraints: function(){},
  14703. within: false,
  14704. constructor: function(node, params){
  14705. // summary:
  14706. // an object that makes a node moveable
  14707. // node: Node
  14708. // a node (or node's id) to be moved
  14709. // params: dojo.dnd.move.__constrainedMoveableArgs?
  14710. // an optional object with additional parameters;
  14711. // the rest is passed to the base class
  14712. if(!params){ params = {}; }
  14713. this.constraints = params.constraints;
  14714. this.within = params.within;
  14715. },
  14716. onFirstMove: function(/* dojo.dnd.Mover */ mover){
  14717. // summary:
  14718. // called during the very first move notification;
  14719. // can be used to initialize coordinates, can be overwritten.
  14720. var c = this.constraintBox = this.constraints.call(this, mover);
  14721. c.r = c.l + c.w;
  14722. c.b = c.t + c.h;
  14723. if(this.within){
  14724. var mb = dojo._getMarginSize(mover.node);
  14725. c.r -= mb.w;
  14726. c.b -= mb.h;
  14727. }
  14728. },
  14729. onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
  14730. // summary:
  14731. // called during every move notification;
  14732. // should actually move the node; can be overwritten.
  14733. var c = this.constraintBox, s = mover.node.style;
  14734. this.onMoving(mover, leftTop);
  14735. leftTop.l = leftTop.l < c.l ? c.l : c.r < leftTop.l ? c.r : leftTop.l;
  14736. leftTop.t = leftTop.t < c.t ? c.t : c.b < leftTop.t ? c.b : leftTop.t;
  14737. s.left = leftTop.l + "px";
  14738. s.top = leftTop.t + "px";
  14739. this.onMoved(mover, leftTop);
  14740. }
  14741. });
  14742. /*=====
  14743. dojo.declare("dojo.dnd.move.__boxConstrainedMoveableArgs", [dojo.dnd.move.__constrainedMoveableArgs], {
  14744. // box: Object
  14745. // a constraint box
  14746. box: {}
  14747. });
  14748. =====*/
  14749. dojo.declare("dojo.dnd.move.boxConstrainedMoveable", dojo.dnd.move.constrainedMoveable, {
  14750. // box:
  14751. // object attributes (for markup)
  14752. box: {},
  14753. constructor: function(node, params){
  14754. // summary:
  14755. // an object, which makes a node moveable
  14756. // node: Node
  14757. // a node (or node's id) to be moved
  14758. // params: dojo.dnd.move.__boxConstrainedMoveableArgs?
  14759. // an optional object with parameters
  14760. var box = params && params.box;
  14761. this.constraints = function(){ return box; };
  14762. }
  14763. });
  14764. /*=====
  14765. dojo.declare("dojo.dnd.move.__parentConstrainedMoveableArgs", [dojo.dnd.move.__constrainedMoveableArgs], {
  14766. // area: String
  14767. // A parent's area to restrict the move.
  14768. // Can be "margin", "border", "padding", or "content".
  14769. area: ""
  14770. });
  14771. =====*/
  14772. dojo.declare("dojo.dnd.move.parentConstrainedMoveable", dojo.dnd.move.constrainedMoveable, {
  14773. // area:
  14774. // object attributes (for markup)
  14775. area: "content",
  14776. constructor: function(node, params){
  14777. // summary:
  14778. // an object, which makes a node moveable
  14779. // node: Node
  14780. // a node (or node's id) to be moved
  14781. // params: dojo.dnd.move.__parentConstrainedMoveableArgs?
  14782. // an optional object with parameters
  14783. var area = params && params.area;
  14784. this.constraints = function(){
  14785. var n = this.node.parentNode,
  14786. s = dojo.getComputedStyle(n),
  14787. mb = dojo._getMarginBox(n, s);
  14788. if(area == "margin"){
  14789. return mb; // Object
  14790. }
  14791. var t = dojo._getMarginExtents(n, s);
  14792. mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
  14793. if(area == "border"){
  14794. return mb; // Object
  14795. }
  14796. t = dojo._getBorderExtents(n, s);
  14797. mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
  14798. if(area == "padding"){
  14799. return mb; // Object
  14800. }
  14801. t = dojo._getPadExtents(n, s);
  14802. mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
  14803. return mb; // Object
  14804. };
  14805. }
  14806. });
  14807. // patching functions one level up for compatibility
  14808. dojo.dnd.constrainedMover = dojo.dnd.move.constrainedMover;
  14809. dojo.dnd.boxConstrainedMover = dojo.dnd.move.boxConstrainedMover;
  14810. dojo.dnd.parentConstrainedMover = dojo.dnd.move.parentConstrainedMover;
  14811. return dojo.dnd.move;
  14812. });
  14813. },
  14814. 'dijit/form/Form':function(){
  14815. define([
  14816. "dojo/_base/declare", // declare
  14817. "dojo/dom-attr", // domAttr.set
  14818. "dojo/_base/event", // event.stop
  14819. "dojo/_base/kernel", // kernel.deprecated
  14820. "dojo/_base/sniff", // has("ie")
  14821. "../_Widget",
  14822. "../_TemplatedMixin",
  14823. "./_FormMixin",
  14824. "../layout/_ContentPaneResizeMixin"
  14825. ], function(declare, domAttr, event, kernel, has, _Widget, _TemplatedMixin, _FormMixin, _ContentPaneResizeMixin){
  14826. /*=====
  14827. var _Widget = dijit._Widget;
  14828. var _TemplatedMixin = dijit._TemplatedMixin;
  14829. var _FormMixin = dijit.form._FormMixin;
  14830. var _ContentPaneResizeMixin = dijit.layout._ContentPaneResizeMixin;
  14831. =====*/
  14832. // module:
  14833. // dijit/form/Form
  14834. // summary:
  14835. // Widget corresponding to HTML form tag, for validation and serialization
  14836. return declare("dijit.form.Form", [_Widget, _TemplatedMixin, _FormMixin, _ContentPaneResizeMixin], {
  14837. // summary:
  14838. // Widget corresponding to HTML form tag, for validation and serialization
  14839. //
  14840. // example:
  14841. // | <form data-dojo-type="dijit.form.Form" id="myForm">
  14842. // | Name: <input type="text" name="name" />
  14843. // | </form>
  14844. // | myObj = {name: "John Doe"};
  14845. // | dijit.byId('myForm').set('value', myObj);
  14846. // |
  14847. // | myObj=dijit.byId('myForm').get('value');
  14848. // HTML <FORM> attributes
  14849. // name: String?
  14850. // Name of form for scripting.
  14851. name: "",
  14852. // action: String?
  14853. // Server-side form handler.
  14854. action: "",
  14855. // method: String?
  14856. // HTTP method used to submit the form, either "GET" or "POST".
  14857. method: "",
  14858. // encType: String?
  14859. // Encoding type for the form, ex: application/x-www-form-urlencoded.
  14860. encType: "",
  14861. // accept-charset: String?
  14862. // List of supported charsets.
  14863. "accept-charset": "",
  14864. // accept: String?
  14865. // List of MIME types for file upload.
  14866. accept: "",
  14867. // target: String?
  14868. // Target frame for the document to be opened in.
  14869. target: "",
  14870. templateString: "<form data-dojo-attach-point='containerNode' data-dojo-attach-event='onreset:_onReset,onsubmit:_onSubmit' ${!nameAttrSetting}></form>",
  14871. postMixInProperties: function(){
  14872. // Setup name=foo string to be referenced from the template (but only if a name has been specified)
  14873. // Unfortunately we can't use _setNameAttr to set the name due to IE limitations, see #8660
  14874. this.nameAttrSetting = this.name ? ("name='" + this.name + "'") : "";
  14875. this.inherited(arguments);
  14876. },
  14877. execute: function(/*Object*/ /*===== formContents =====*/){
  14878. // summary:
  14879. // Deprecated: use submit()
  14880. // tags:
  14881. // deprecated
  14882. },
  14883. onExecute: function(){
  14884. // summary:
  14885. // Deprecated: use onSubmit()
  14886. // tags:
  14887. // deprecated
  14888. },
  14889. _setEncTypeAttr: function(/*String*/ value){
  14890. this.encType = value;
  14891. domAttr.set(this.domNode, "encType", value);
  14892. if(has("ie")){ this.domNode.encoding = value; }
  14893. },
  14894. reset: function(/*Event?*/ e){
  14895. // summary:
  14896. // restores all widget values back to their init values,
  14897. // calls onReset() which can cancel the reset by returning false
  14898. // create fake event so we can know if preventDefault() is called
  14899. var faux = {
  14900. returnValue: true, // the IE way
  14901. preventDefault: function(){ // not IE
  14902. this.returnValue = false;
  14903. },
  14904. stopPropagation: function(){},
  14905. currentTarget: e ? e.target : this.domNode,
  14906. target: e ? e.target : this.domNode
  14907. };
  14908. // if return value is not exactly false, and haven't called preventDefault(), then reset
  14909. if(!(this.onReset(faux) === false) && faux.returnValue){
  14910. this.inherited(arguments, []);
  14911. }
  14912. },
  14913. onReset: function(/*Event?*/ /*===== e =====*/){
  14914. // summary:
  14915. // Callback when user resets the form. This method is intended
  14916. // to be over-ridden. When the `reset` method is called
  14917. // programmatically, the return value from `onReset` is used
  14918. // to compute whether or not resetting should proceed
  14919. // tags:
  14920. // callback
  14921. return true; // Boolean
  14922. },
  14923. _onReset: function(e){
  14924. this.reset(e);
  14925. event.stop(e);
  14926. return false;
  14927. },
  14928. _onSubmit: function(e){
  14929. var fp = this.constructor.prototype;
  14930. // TODO: remove this if statement beginning with 2.0
  14931. if(this.execute != fp.execute || this.onExecute != fp.onExecute){
  14932. kernel.deprecated("dijit.form.Form:execute()/onExecute() are deprecated. Use onSubmit() instead.", "", "2.0");
  14933. this.onExecute();
  14934. this.execute(this.getValues());
  14935. }
  14936. if(this.onSubmit(e) === false){ // only exactly false stops submit
  14937. event.stop(e);
  14938. }
  14939. },
  14940. onSubmit: function(/*Event?*/ /*===== e =====*/){
  14941. // summary:
  14942. // Callback when user submits the form.
  14943. // description:
  14944. // This method is intended to be over-ridden, but by default it checks and
  14945. // returns the validity of form elements. When the `submit`
  14946. // method is called programmatically, the return value from
  14947. // `onSubmit` is used to compute whether or not submission
  14948. // should proceed
  14949. // tags:
  14950. // extension
  14951. return this.isValid(); // Boolean
  14952. },
  14953. submit: function(){
  14954. // summary:
  14955. // programmatically submit form if and only if the `onSubmit` returns true
  14956. if(!(this.onSubmit() === false)){
  14957. this.containerNode.submit();
  14958. }
  14959. }
  14960. });
  14961. });
  14962. },
  14963. 'dijit/layout/_TabContainerBase':function(){
  14964. define([
  14965. "dojo/text!./templates/TabContainer.html",
  14966. "./StackContainer",
  14967. "./utils", // marginBox2contextBox, layoutChildren
  14968. "../_TemplatedMixin",
  14969. "dojo/_base/declare", // declare
  14970. "dojo/dom-class", // domClass.add
  14971. "dojo/dom-geometry", // domGeometry.contentBox
  14972. "dojo/dom-style" // domStyle.style
  14973. ], function(template, StackContainer, layoutUtils, _TemplatedMixin, declare, domClass, domGeometry, domStyle){
  14974. /*=====
  14975. var StackContainer = dijit.layout.StackContainer;
  14976. var _TemplatedMixin = dijit._TemplatedMixin;
  14977. =====*/
  14978. // module:
  14979. // dijit/layout/_TabContainerBase
  14980. // summary:
  14981. // Abstract base class for TabContainer. Must define _makeController() to instantiate
  14982. // and return the widget that displays the tab labels
  14983. return declare("dijit.layout._TabContainerBase", [StackContainer, _TemplatedMixin], {
  14984. // summary:
  14985. // Abstract base class for TabContainer. Must define _makeController() to instantiate
  14986. // and return the widget that displays the tab labels
  14987. // description:
  14988. // A TabContainer is a container that has multiple panes, but shows only
  14989. // one pane at a time. There are a set of tabs corresponding to each pane,
  14990. // where each tab has the name (aka title) of the pane, and optionally a close button.
  14991. // tabPosition: String
  14992. // Defines where tabs go relative to tab content.
  14993. // "top", "bottom", "left-h", "right-h"
  14994. tabPosition: "top",
  14995. baseClass: "dijitTabContainer",
  14996. // tabStrip: [const] Boolean
  14997. // Defines whether the tablist gets an extra class for layouting, putting a border/shading
  14998. // around the set of tabs. Not supported by claro theme.
  14999. tabStrip: false,
  15000. // nested: [const] Boolean
  15001. // If true, use styling for a TabContainer nested inside another TabContainer.
  15002. // For tundra etc., makes tabs look like links, and hides the outer
  15003. // border since the outer TabContainer already has a border.
  15004. nested: false,
  15005. templateString: template,
  15006. postMixInProperties: function(){
  15007. // set class name according to tab position, ex: dijitTabContainerTop
  15008. this.baseClass += this.tabPosition.charAt(0).toUpperCase() + this.tabPosition.substr(1).replace(/-.*/, "");
  15009. this.srcNodeRef && domStyle.set(this.srcNodeRef, "visibility", "hidden");
  15010. this.inherited(arguments);
  15011. },
  15012. buildRendering: function(){
  15013. this.inherited(arguments);
  15014. // Create the tab list that will have a tab (a.k.a. tab button) for each tab panel
  15015. this.tablist = this._makeController(this.tablistNode);
  15016. if(!this.doLayout){ domClass.add(this.domNode, "dijitTabContainerNoLayout"); }
  15017. if(this.nested){
  15018. /* workaround IE's lack of support for "a > b" selectors by
  15019. * tagging each node in the template.
  15020. */
  15021. domClass.add(this.domNode, "dijitTabContainerNested");
  15022. domClass.add(this.tablist.containerNode, "dijitTabContainerTabListNested");
  15023. domClass.add(this.tablistSpacer, "dijitTabContainerSpacerNested");
  15024. domClass.add(this.containerNode, "dijitTabPaneWrapperNested");
  15025. }else{
  15026. domClass.add(this.domNode, "tabStrip-" + (this.tabStrip ? "enabled" : "disabled"));
  15027. }
  15028. },
  15029. _setupChild: function(/*dijit._Widget*/ tab){
  15030. // Overrides StackContainer._setupChild().
  15031. domClass.add(tab.domNode, "dijitTabPane");
  15032. this.inherited(arguments);
  15033. },
  15034. startup: function(){
  15035. if(this._started){ return; }
  15036. // wire up the tablist and its tabs
  15037. this.tablist.startup();
  15038. this.inherited(arguments);
  15039. },
  15040. layout: function(){
  15041. // Overrides StackContainer.layout().
  15042. // Configure the content pane to take up all the space except for where the tabs are
  15043. if(!this._contentBox || typeof(this._contentBox.l) == "undefined"){return;}
  15044. var sc = this.selectedChildWidget;
  15045. if(this.doLayout){
  15046. // position and size the titles and the container node
  15047. var titleAlign = this.tabPosition.replace(/-h/, "");
  15048. this.tablist.layoutAlign = titleAlign;
  15049. var children = [this.tablist, {
  15050. domNode: this.tablistSpacer,
  15051. layoutAlign: titleAlign
  15052. }, {
  15053. domNode: this.containerNode,
  15054. layoutAlign: "client"
  15055. }];
  15056. layoutUtils.layoutChildren(this.domNode, this._contentBox, children);
  15057. // Compute size to make each of my children.
  15058. // children[2] is the margin-box size of this.containerNode, set by layoutChildren() call above
  15059. this._containerContentBox = layoutUtils.marginBox2contentBox(this.containerNode, children[2]);
  15060. if(sc && sc.resize){
  15061. sc.resize(this._containerContentBox);
  15062. }
  15063. }else{
  15064. // just layout the tab controller, so it can position left/right buttons etc.
  15065. if(this.tablist.resize){
  15066. //make the tabs zero width so that they don't interfere with width calc, then reset
  15067. var s = this.tablist.domNode.style;
  15068. s.width="0";
  15069. var width = domGeometry.getContentBox(this.domNode).w;
  15070. s.width="";
  15071. this.tablist.resize({w: width});
  15072. }
  15073. // and call resize() on the selected pane just to tell it that it's been made visible
  15074. if(sc && sc.resize){
  15075. sc.resize();
  15076. }
  15077. }
  15078. },
  15079. destroy: function(){
  15080. if(this.tablist){
  15081. this.tablist.destroy();
  15082. }
  15083. this.inherited(arguments);
  15084. }
  15085. });
  15086. });
  15087. },
  15088. 'dojo/store/Memory':function(){
  15089. define(["../_base/declare", "./util/QueryResults", "./util/SimpleQueryEngine"], function(declare, QueryResults, SimpleQueryEngine) {
  15090. // module:
  15091. // dojo/store/Memory
  15092. // summary:
  15093. // The module defines an in-memory object store.
  15094. return declare("dojo.store.Memory", null, {
  15095. // summary:
  15096. // This is a basic in-memory object store. It implements dojo.store.api.Store.
  15097. constructor: function(/*dojo.store.Memory*/ options){
  15098. // summary:
  15099. // Creates a memory object store.
  15100. // options:
  15101. // This provides any configuration information that will be mixed into the store.
  15102. // This should generally include the data property to provide the starting set of data.
  15103. for(var i in options){
  15104. this[i] = options[i];
  15105. }
  15106. this.setData(this.data || []);
  15107. },
  15108. // data: Array
  15109. // The array of all the objects in the memory store
  15110. data:null,
  15111. // idProperty: String
  15112. // Indicates the property to use as the identity property. The values of this
  15113. // property should be unique.
  15114. idProperty: "id",
  15115. // index: Object
  15116. // An index of data indices into the data array by id
  15117. index:null,
  15118. // queryEngine: Function
  15119. // Defines the query engine to use for querying the data store
  15120. queryEngine: SimpleQueryEngine,
  15121. get: function(id){
  15122. // summary:
  15123. // Retrieves an object by its identity
  15124. // id: Number
  15125. // The identity to use to lookup the object
  15126. // returns: Object
  15127. // The object in the store that matches the given id.
  15128. return this.data[this.index[id]];
  15129. },
  15130. getIdentity: function(object){
  15131. // summary:
  15132. // Returns an object's identity
  15133. // object: Object
  15134. // The object to get the identity from
  15135. // returns: Number
  15136. return object[this.idProperty];
  15137. },
  15138. put: function(object, options){
  15139. // summary:
  15140. // Stores an object
  15141. // object: Object
  15142. // The object to store.
  15143. // options: dojo.store.api.Store.PutDirectives??
  15144. // Additional metadata for storing the data. Includes an "id"
  15145. // property if a specific id is to be used.
  15146. // returns: Number
  15147. var data = this.data,
  15148. index = this.index,
  15149. idProperty = this.idProperty;
  15150. var id = (options && "id" in options) ? options.id : idProperty in object ? object[idProperty] : Math.random();
  15151. if(id in index){
  15152. // object exists
  15153. if(options && options.overwrite === false){
  15154. throw new Error("Object already exists");
  15155. }
  15156. // replace the entry in data
  15157. data[index[id]] = object;
  15158. }else{
  15159. // add the new object
  15160. index[id] = data.push(object) - 1;
  15161. }
  15162. return id;
  15163. },
  15164. add: function(object, options){
  15165. // summary:
  15166. // Creates an object, throws an error if the object already exists
  15167. // object: Object
  15168. // The object to store.
  15169. // options: dojo.store.api.Store.PutDirectives??
  15170. // Additional metadata for storing the data. Includes an "id"
  15171. // property if a specific id is to be used.
  15172. // returns: Number
  15173. (options = options || {}).overwrite = false;
  15174. // call put with overwrite being false
  15175. return this.put(object, options);
  15176. },
  15177. remove: function(id){
  15178. // summary:
  15179. // Deletes an object by its identity
  15180. // id: Number
  15181. // The identity to use to delete the object
  15182. // returns: Boolean
  15183. // Returns true if an object was removed, falsy (undefined) if no object matched the id
  15184. var index = this.index;
  15185. var data = this.data;
  15186. if(id in index){
  15187. data.splice(index[id], 1);
  15188. // now we have to reindex
  15189. this.setData(data);
  15190. return true;
  15191. }
  15192. },
  15193. query: function(query, options){
  15194. // summary:
  15195. // Queries the store for objects.
  15196. // query: Object
  15197. // The query to use for retrieving objects from the store.
  15198. // options: dojo.store.api.Store.QueryOptions?
  15199. // The optional arguments to apply to the resultset.
  15200. // returns: dojo.store.api.Store.QueryResults
  15201. // The results of the query, extended with iterative methods.
  15202. //
  15203. // example:
  15204. // Given the following store:
  15205. //
  15206. // | var store = new dojo.store.Memory({
  15207. // | data: [
  15208. // | {id: 1, name: "one", prime: false },
  15209. // | {id: 2, name: "two", even: true, prime: true},
  15210. // | {id: 3, name: "three", prime: true},
  15211. // | {id: 4, name: "four", even: true, prime: false},
  15212. // | {id: 5, name: "five", prime: true}
  15213. // | ]
  15214. // | });
  15215. //
  15216. // ...find all items where "prime" is true:
  15217. //
  15218. // | var results = store.query({ prime: true });
  15219. //
  15220. // ...or find all items where "even" is true:
  15221. //
  15222. // | var results = store.query({ even: true });
  15223. return QueryResults(this.queryEngine(query, options)(this.data));
  15224. },
  15225. setData: function(data){
  15226. // summary:
  15227. // Sets the given data as the source for this store, and indexes it
  15228. // data: Object[]
  15229. // An array of objects to use as the source of data.
  15230. if(data.items){
  15231. // just for convenience with the data format IFRS expects
  15232. this.idProperty = data.identifier || this.idProperty;
  15233. data = this.data = data.items;
  15234. }else{
  15235. this.data = data;
  15236. }
  15237. this.index = {};
  15238. for(var i = 0, l = data.length; i < l; i++){
  15239. this.index[data[i][this.idProperty]] = i;
  15240. }
  15241. }
  15242. });
  15243. });
  15244. },
  15245. 'url:dijit/templates/Tooltip.html':"<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\"\n\t><div class=\"dijitTooltipContainer dijitTooltipContents\" data-dojo-attach-point=\"containerNode\" role='alert'></div\n\t><div class=\"dijitTooltipConnector\" data-dojo-attach-point=\"connectorNode\"></div\n></div>\n",
  15246. 'dijit/Editor':function(){
  15247. define([
  15248. "dojo/_base/array", // array.forEach
  15249. "dojo/_base/declare", // declare
  15250. "dojo/_base/Deferred", // Deferred
  15251. "dojo/i18n", // i18n.getLocalization
  15252. "dojo/dom-attr", // domAttr.set
  15253. "dojo/dom-class", // domClass.add
  15254. "dojo/dom-geometry",
  15255. "dojo/dom-style", // domStyle.set, get
  15256. "dojo/_base/event", // event.stop
  15257. "dojo/keys", // keys.F1 keys.F15 keys.TAB
  15258. "dojo/_base/lang", // lang.getObject lang.hitch
  15259. "dojo/_base/sniff", // has("ie") has("mac") has("webkit")
  15260. "dojo/string", // string.substitute
  15261. "dojo/topic", // topic.publish()
  15262. "dojo/_base/window", // win.withGlobal
  15263. "./_base/focus", // dijit.getBookmark()
  15264. "./_Container",
  15265. "./Toolbar",
  15266. "./ToolbarSeparator",
  15267. "./layout/_LayoutWidget",
  15268. "./form/ToggleButton",
  15269. "./_editor/_Plugin",
  15270. "./_editor/plugins/EnterKeyHandling",
  15271. "./_editor/html",
  15272. "./_editor/range",
  15273. "./_editor/RichText",
  15274. ".", // dijit._scopeName
  15275. "dojo/i18n!./_editor/nls/commands"
  15276. ], function(array, declare, Deferred, i18n, domAttr, domClass, domGeometry, domStyle,
  15277. event, keys, lang, has, string, topic, win,
  15278. focusBase, _Container, Toolbar, ToolbarSeparator, _LayoutWidget, ToggleButton,
  15279. _Plugin, EnterKeyHandling, html, rangeapi, RichText, dijit){
  15280. // module:
  15281. // dijit/Editor
  15282. // summary:
  15283. // A rich text Editing widget
  15284. var Editor = declare("dijit.Editor", RichText, {
  15285. // summary:
  15286. // A rich text Editing widget
  15287. //
  15288. // description:
  15289. // This widget provides basic WYSIWYG editing features, based on the browser's
  15290. // underlying rich text editing capability, accompanied by a toolbar (`dijit.Toolbar`).
  15291. // A plugin model is available to extend the editor's capabilities as well as the
  15292. // the options available in the toolbar. Content generation may vary across
  15293. // browsers, and clipboard operations may have different results, to name
  15294. // a few limitations. Note: this widget should not be used with the HTML
  15295. // &lt;TEXTAREA&gt; tag -- see dijit._editor.RichText for details.
  15296. // plugins: [const] Object[]
  15297. // A list of plugin names (as strings) or instances (as objects)
  15298. // for this widget.
  15299. //
  15300. // When declared in markup, it might look like:
  15301. // | plugins="['bold',{name:'dijit._editor.plugins.FontChoice', command:'fontName', generic:true}]"
  15302. plugins: null,
  15303. // extraPlugins: [const] Object[]
  15304. // A list of extra plugin names which will be appended to plugins array
  15305. extraPlugins: null,
  15306. constructor: function(){
  15307. // summary:
  15308. // Runs on widget initialization to setup arrays etc.
  15309. // tags:
  15310. // private
  15311. if(!lang.isArray(this.plugins)){
  15312. this.plugins=["undo","redo","|","cut","copy","paste","|","bold","italic","underline","strikethrough","|",
  15313. "insertOrderedList","insertUnorderedList","indent","outdent","|","justifyLeft","justifyRight","justifyCenter","justifyFull",
  15314. EnterKeyHandling /*, "createLink"*/];
  15315. }
  15316. this._plugins=[];
  15317. this._editInterval = this.editActionInterval * 1000;
  15318. //IE will always lose focus when other element gets focus, while for FF and safari,
  15319. //when no iframe is used, focus will be lost whenever another element gets focus.
  15320. //For IE, we can connect to onBeforeDeactivate, which will be called right before
  15321. //the focus is lost, so we can obtain the selected range. For other browsers,
  15322. //no equivalent of onBeforeDeactivate, so we need to do two things to make sure
  15323. //selection is properly saved before focus is lost: 1) when user clicks another
  15324. //element in the page, in which case we listen to mousedown on the entire page and
  15325. //see whether user clicks out of a focus editor, if so, save selection (focus will
  15326. //only lost after onmousedown event is fired, so we can obtain correct caret pos.)
  15327. //2) when user tabs away from the editor, which is handled in onKeyDown below.
  15328. if(has("ie") || has("trident")){
  15329. this.events.push("onBeforeDeactivate");
  15330. this.events.push("onBeforeActivate");
  15331. }
  15332. },
  15333. postMixInProperties: function(){
  15334. // summary:
  15335. // Extension to make sure a deferred is in place before certain functions
  15336. // execute, like making sure all the plugins are properly inserted.
  15337. // Set up a deferred so that the value isn't applied to the editor
  15338. // until all the plugins load, needed to avoid timing condition
  15339. // reported in #10537.
  15340. this.setValueDeferred = new Deferred();
  15341. this.inherited(arguments);
  15342. },
  15343. postCreate: function(){
  15344. //for custom undo/redo, if enabled.
  15345. this._steps=this._steps.slice(0);
  15346. this._undoedSteps=this._undoedSteps.slice(0);
  15347. if(lang.isArray(this.extraPlugins)){
  15348. this.plugins=this.plugins.concat(this.extraPlugins);
  15349. }
  15350. this.inherited(arguments);
  15351. this.commands = i18n.getLocalization("dijit._editor", "commands", this.lang);
  15352. if(!this.toolbar){
  15353. // if we haven't been assigned a toolbar, create one
  15354. this.toolbar = new Toolbar({
  15355. dir: this.dir,
  15356. lang: this.lang
  15357. });
  15358. this.header.appendChild(this.toolbar.domNode);
  15359. }
  15360. array.forEach(this.plugins, this.addPlugin, this);
  15361. // Okay, denote the value can now be set.
  15362. this.setValueDeferred.callback(true);
  15363. domClass.add(this.iframe.parentNode, "dijitEditorIFrameContainer");
  15364. domClass.add(this.iframe, "dijitEditorIFrame");
  15365. domAttr.set(this.iframe, "allowTransparency", true);
  15366. if(has("webkit")){
  15367. // Disable selecting the entire editor by inadvertent double-clicks.
  15368. // on buttons, title bar, etc. Otherwise clicking too fast on
  15369. // a button such as undo/redo selects the entire editor.
  15370. domStyle.set(this.domNode, "KhtmlUserSelect", "none");
  15371. }
  15372. this.toolbar.startup();
  15373. this.onNormalizedDisplayChanged(); //update toolbar button status
  15374. },
  15375. destroy: function(){
  15376. array.forEach(this._plugins, function(p){
  15377. if(p && p.destroy){
  15378. p.destroy();
  15379. }
  15380. });
  15381. this._plugins=[];
  15382. this.toolbar.destroyRecursive();
  15383. delete this.toolbar;
  15384. this.inherited(arguments);
  15385. },
  15386. addPlugin: function(/*String||Object||Function*/plugin, /*Integer?*/index){
  15387. // summary:
  15388. // takes a plugin name as a string or a plugin instance and
  15389. // adds it to the toolbar and associates it with this editor
  15390. // instance. The resulting plugin is added to the Editor's
  15391. // plugins array. If index is passed, it's placed in the plugins
  15392. // array at that index. No big magic, but a nice helper for
  15393. // passing in plugin names via markup.
  15394. //
  15395. // plugin: String, args object, plugin instance, or plugin constructor
  15396. //
  15397. // args:
  15398. // This object will be passed to the plugin constructor
  15399. //
  15400. // index: Integer
  15401. // Used when creating an instance from
  15402. // something already in this.plugins. Ensures that the new
  15403. // instance is assigned to this.plugins at that index.
  15404. var args=lang.isString(plugin)?{name:plugin}:lang.isFunction(plugin)?{ctor:plugin}:plugin;
  15405. if(!args.setEditor){
  15406. var o={"args":args,"plugin":null,"editor":this};
  15407. if(args.name){
  15408. // search registry for a plugin factory matching args.name, if it's not there then
  15409. // fallback to 1.0 API:
  15410. // ask all loaded plugin modules to fill in o.plugin if they can (ie, if they implement args.name)
  15411. // remove fallback for 2.0.
  15412. if(_Plugin.registry[args.name]){
  15413. o.plugin = _Plugin.registry[args.name](args);
  15414. }else{
  15415. topic.publish(dijit._scopeName + ".Editor.getPlugin", o); // publish
  15416. }
  15417. }
  15418. if(!o.plugin){
  15419. var pc = args.ctor || lang.getObject(args.name);
  15420. if(pc){
  15421. o.plugin=new pc(args);
  15422. }
  15423. }
  15424. if(!o.plugin){
  15425. console.warn('Cannot find plugin',plugin);
  15426. return;
  15427. }
  15428. plugin=o.plugin;
  15429. }
  15430. if(arguments.length > 1){
  15431. this._plugins[index] = plugin;
  15432. }else{
  15433. this._plugins.push(plugin);
  15434. }
  15435. plugin.setEditor(this);
  15436. if(lang.isFunction(plugin.setToolbar)){
  15437. plugin.setToolbar(this.toolbar);
  15438. }
  15439. },
  15440. //the following 2 functions are required to make the editor play nice under a layout widget, see #4070
  15441. resize: function(size){
  15442. // summary:
  15443. // Resize the editor to the specified size, see `dijit.layout._LayoutWidget.resize`
  15444. if(size){
  15445. // we've been given a height/width for the entire editor (toolbar + contents), calls layout()
  15446. // to split the allocated size between the toolbar and the contents
  15447. _LayoutWidget.prototype.resize.apply(this, arguments);
  15448. }
  15449. /*
  15450. else{
  15451. // do nothing, the editor is already laid out correctly. The user has probably specified
  15452. // the height parameter, which was used to set a size on the iframe
  15453. }
  15454. */
  15455. },
  15456. layout: function(){
  15457. // summary:
  15458. // Called from `dijit.layout._LayoutWidget.resize`. This shouldn't be called directly
  15459. // tags:
  15460. // protected
  15461. // Converts the iframe (or rather the <div> surrounding it) to take all the available space
  15462. // except what's needed for the header (toolbars) and footer (breadcrumbs, etc).
  15463. // A class was added to the iframe container and some themes style it, so we have to
  15464. // calc off the added margins and padding too. See tracker: #10662
  15465. var areaHeight = (this._contentBox.h -
  15466. (this.getHeaderHeight() + this.getFooterHeight() +
  15467. domGeometry.getPadBorderExtents(this.iframe.parentNode).h +
  15468. domGeometry.getMarginExtents(this.iframe.parentNode).h));
  15469. this.editingArea.style.height = areaHeight + "px";
  15470. if(this.iframe){
  15471. this.iframe.style.height="100%";
  15472. }
  15473. this._layoutMode = true;
  15474. },
  15475. _onIEMouseDown: function(/*Event*/ e){
  15476. // summary:
  15477. // IE only to prevent 2 clicks to focus
  15478. // tags:
  15479. // private
  15480. var outsideClientArea;
  15481. // IE 8's componentFromPoint is broken, which is a shame since it
  15482. // was smaller code, but oh well. We have to do this brute force
  15483. // to detect if the click was scroller or not.
  15484. var b = this.document.body;
  15485. var clientWidth = b.clientWidth;
  15486. var clientHeight = b.clientHeight;
  15487. var clientLeft = b.clientLeft;
  15488. var offsetWidth = b.offsetWidth;
  15489. var offsetHeight = b.offsetHeight;
  15490. var offsetLeft = b.offsetLeft;
  15491. //Check for vertical scroller click.
  15492. if(/^rtl$/i.test(b.dir || "")){
  15493. if(clientWidth < offsetWidth && e.x > clientWidth && e.x < offsetWidth){
  15494. // Check the click was between width and offset width, if so, scroller
  15495. outsideClientArea = true;
  15496. }
  15497. }else{
  15498. // RTL mode, we have to go by the left offsets.
  15499. if(e.x < clientLeft && e.x > offsetLeft){
  15500. // Check the click was between width and offset width, if so, scroller
  15501. outsideClientArea = true;
  15502. }
  15503. }
  15504. if(!outsideClientArea){
  15505. // Okay, might be horiz scroller, check that.
  15506. if(clientHeight < offsetHeight && e.y > clientHeight && e.y < offsetHeight){
  15507. // Horizontal scroller.
  15508. outsideClientArea = true;
  15509. }
  15510. }
  15511. if(!outsideClientArea){
  15512. delete this._cursorToStart; // Remove the force to cursor to start position.
  15513. delete this._savedSelection; // new mouse position overrides old selection
  15514. if(e.target.tagName == "BODY"){
  15515. setTimeout(lang.hitch(this, "placeCursorAtEnd"), 0);
  15516. }
  15517. this.inherited(arguments);
  15518. }
  15519. },
  15520. onBeforeActivate: function(){
  15521. this._restoreSelection();
  15522. },
  15523. onBeforeDeactivate: function(e){
  15524. // summary:
  15525. // Called on IE right before focus is lost. Saves the selected range.
  15526. // tags:
  15527. // private
  15528. if(this.customUndo){
  15529. this.endEditing(true);
  15530. }
  15531. //in IE, the selection will be lost when other elements get focus,
  15532. //let's save focus before the editor is deactivated
  15533. if(e.target.tagName != "BODY"){
  15534. this._saveSelection();
  15535. }
  15536. //console.log('onBeforeDeactivate',this);
  15537. },
  15538. /* beginning of custom undo/redo support */
  15539. // customUndo: Boolean
  15540. // Whether we shall use custom undo/redo support instead of the native
  15541. // browser support. By default, we now use custom undo. It works better
  15542. // than native browser support and provides a consistent behavior across
  15543. // browsers with a minimal performance hit. We already had the hit on
  15544. // the slowest browser, IE, anyway.
  15545. customUndo: true,
  15546. // editActionInterval: Integer
  15547. // When using customUndo, not every keystroke will be saved as a step.
  15548. // Instead typing (including delete) will be grouped together: after
  15549. // a user stops typing for editActionInterval seconds, a step will be
  15550. // saved; if a user resume typing within editActionInterval seconds,
  15551. // the timeout will be restarted. By default, editActionInterval is 3
  15552. // seconds.
  15553. editActionInterval: 3,
  15554. beginEditing: function(cmd){
  15555. // summary:
  15556. // Called to note that the user has started typing alphanumeric characters, if it's not already noted.
  15557. // Deals with saving undo; see editActionInterval parameter.
  15558. // tags:
  15559. // private
  15560. if(!this._inEditing){
  15561. this._inEditing=true;
  15562. this._beginEditing(cmd);
  15563. }
  15564. if(this.editActionInterval>0){
  15565. if(this._editTimer){
  15566. clearTimeout(this._editTimer);
  15567. }
  15568. this._editTimer = setTimeout(lang.hitch(this, this.endEditing), this._editInterval);
  15569. }
  15570. },
  15571. // TODO: declaring these in the prototype is meaningless, just create in the constructor/postCreate
  15572. _steps:[],
  15573. _undoedSteps:[],
  15574. execCommand: function(cmd){
  15575. // summary:
  15576. // Main handler for executing any commands to the editor, like paste, bold, etc.
  15577. // Called by plugins, but not meant to be called by end users.
  15578. // tags:
  15579. // protected
  15580. if(this.customUndo && (cmd == 'undo' || cmd == 'redo')){
  15581. return this[cmd]();
  15582. }else{
  15583. if(this.customUndo){
  15584. this.endEditing();
  15585. this._beginEditing();
  15586. }
  15587. var r = this.inherited(arguments);
  15588. if(this.customUndo){
  15589. this._endEditing();
  15590. }
  15591. return r;
  15592. }
  15593. },
  15594. _pasteImpl: function(){
  15595. // summary:
  15596. // Over-ride of paste command control to make execCommand cleaner
  15597. // tags:
  15598. // Protected
  15599. return this._clipboardCommand("paste");
  15600. },
  15601. _cutImpl: function(){
  15602. // summary:
  15603. // Over-ride of cut command control to make execCommand cleaner
  15604. // tags:
  15605. // Protected
  15606. return this._clipboardCommand("cut");
  15607. },
  15608. _copyImpl: function(){
  15609. // summary:
  15610. // Over-ride of copy command control to make execCommand cleaner
  15611. // tags:
  15612. // Protected
  15613. return this._clipboardCommand("copy");
  15614. },
  15615. _clipboardCommand: function(cmd){
  15616. // summary:
  15617. // Function to handle processing clipboard commands (or at least try to).
  15618. // tags:
  15619. // Private
  15620. var r;
  15621. try{
  15622. // Try to exec the superclass exec-command and see if it works.
  15623. r = this.document.execCommand(cmd, false, null);
  15624. if(has("webkit") && !r){ //see #4598: webkit does not guarantee clipboard support from js
  15625. throw { code: 1011 }; // throw an object like Mozilla's error
  15626. }
  15627. }catch(e){
  15628. //TODO: when else might we get an exception? Do we need the Mozilla test below?
  15629. if(e.code == 1011 /* Mozilla: service denied */){
  15630. // Warn user of platform limitation. Cannot programmatically access clipboard. See ticket #4136
  15631. var sub = string.substitute,
  15632. accel = {cut:'X', copy:'C', paste:'V'};
  15633. alert(sub(this.commands.systemShortcut,
  15634. [this.commands[cmd], sub(this.commands[has("mac") ? 'appleKey' : 'ctrlKey'], [accel[cmd]])]));
  15635. }
  15636. r = false;
  15637. }
  15638. return r;
  15639. },
  15640. queryCommandEnabled: function(cmd){
  15641. // summary:
  15642. // Returns true if specified editor command is enabled.
  15643. // Used by the plugins to know when to highlight/not highlight buttons.
  15644. // tags:
  15645. // protected
  15646. if(this.customUndo && (cmd == 'undo' || cmd == 'redo')){
  15647. return cmd == 'undo' ? (this._steps.length > 1) : (this._undoedSteps.length > 0);
  15648. }else{
  15649. return this.inherited(arguments);
  15650. }
  15651. },
  15652. _moveToBookmark: function(b){
  15653. // summary:
  15654. // Selects the text specified in bookmark b
  15655. // tags:
  15656. // private
  15657. var bookmark = b.mark;
  15658. var mark = b.mark;
  15659. var col = b.isCollapsed;
  15660. var r, sNode, eNode, sel;
  15661. if(mark){
  15662. if(has("ie") < 9){
  15663. if(lang.isArray(mark)){
  15664. //IE CONTROL, have to use the native bookmark.
  15665. bookmark = [];
  15666. array.forEach(mark,function(n){
  15667. bookmark.push(rangeapi.getNode(n,this.editNode));
  15668. },this);
  15669. win.withGlobal(this.window,'moveToBookmark',dijit,[{mark: bookmark, isCollapsed: col}]);
  15670. }else{
  15671. if(mark.startContainer && mark.endContainer){
  15672. // Use the pseudo WC3 range API. This works better for positions
  15673. // than the IE native bookmark code.
  15674. sel = rangeapi.getSelection(this.window);
  15675. if(sel && sel.removeAllRanges){
  15676. sel.removeAllRanges();
  15677. r = rangeapi.create(this.window);
  15678. sNode = rangeapi.getNode(mark.startContainer,this.editNode);
  15679. eNode = rangeapi.getNode(mark.endContainer,this.editNode);
  15680. if(sNode && eNode){
  15681. // Okay, we believe we found the position, so add it into the selection
  15682. // There are cases where it may not be found, particularly in undo/redo, when
  15683. // IE changes the underlying DOM on us (wraps text in a <p> tag or similar.
  15684. // So, in those cases, don't bother restoring selection.
  15685. r.setStart(sNode,mark.startOffset);
  15686. r.setEnd(eNode,mark.endOffset);
  15687. sel.addRange(r);
  15688. }
  15689. }
  15690. }
  15691. }
  15692. }else{//w3c range
  15693. sel = rangeapi.getSelection(this.window);
  15694. if(sel && sel.removeAllRanges){
  15695. sel.removeAllRanges();
  15696. r = rangeapi.create(this.window);
  15697. sNode = rangeapi.getNode(mark.startContainer,this.editNode);
  15698. eNode = rangeapi.getNode(mark.endContainer,this.editNode);
  15699. if(sNode && eNode){
  15700. // Okay, we believe we found the position, so add it into the selection
  15701. // There are cases where it may not be found, particularly in undo/redo, when
  15702. // formatting as been done and so on, so don't restore selection then.
  15703. r.setStart(sNode,mark.startOffset);
  15704. r.setEnd(eNode,mark.endOffset);
  15705. sel.addRange(r);
  15706. }
  15707. }
  15708. }
  15709. }
  15710. },
  15711. _changeToStep: function(from, to){
  15712. // summary:
  15713. // Reverts editor to "to" setting, from the undo stack.
  15714. // tags:
  15715. // private
  15716. this.setValue(to.text);
  15717. var b=to.bookmark;
  15718. if(!b){ return; }
  15719. this._moveToBookmark(b);
  15720. },
  15721. undo: function(){
  15722. // summary:
  15723. // Handler for editor undo (ex: ctrl-z) operation
  15724. // tags:
  15725. // private
  15726. //console.log('undo');
  15727. var ret = false;
  15728. if(!this._undoRedoActive){
  15729. this._undoRedoActive = true;
  15730. this.endEditing(true);
  15731. var s=this._steps.pop();
  15732. if(s && this._steps.length>0){
  15733. this.focus();
  15734. this._changeToStep(s,this._steps[this._steps.length-1]);
  15735. this._undoedSteps.push(s);
  15736. this.onDisplayChanged();
  15737. delete this._undoRedoActive;
  15738. ret = true;
  15739. }
  15740. delete this._undoRedoActive;
  15741. }
  15742. return ret;
  15743. },
  15744. redo: function(){
  15745. // summary:
  15746. // Handler for editor redo (ex: ctrl-y) operation
  15747. // tags:
  15748. // private
  15749. //console.log('redo');
  15750. var ret = false;
  15751. if(!this._undoRedoActive){
  15752. this._undoRedoActive = true;
  15753. this.endEditing(true);
  15754. var s=this._undoedSteps.pop();
  15755. if(s && this._steps.length>0){
  15756. this.focus();
  15757. this._changeToStep(this._steps[this._steps.length-1],s);
  15758. this._steps.push(s);
  15759. this.onDisplayChanged();
  15760. ret = true;
  15761. }
  15762. delete this._undoRedoActive;
  15763. }
  15764. return ret;
  15765. },
  15766. endEditing: function(ignore_caret){
  15767. // summary:
  15768. // Called to note that the user has stopped typing alphanumeric characters, if it's not already noted.
  15769. // Deals with saving undo; see editActionInterval parameter.
  15770. // tags:
  15771. // private
  15772. if(this._editTimer){
  15773. clearTimeout(this._editTimer);
  15774. }
  15775. if(this._inEditing){
  15776. this._endEditing(ignore_caret);
  15777. this._inEditing=false;
  15778. }
  15779. },
  15780. _getBookmark: function(){
  15781. // summary:
  15782. // Get the currently selected text
  15783. // tags:
  15784. // protected
  15785. var b=win.withGlobal(this.window,focusBase.getBookmark);
  15786. var tmp=[];
  15787. if(b && b.mark){
  15788. var mark = b.mark;
  15789. if(has("ie") < 9){
  15790. // Try to use the pseudo range API on IE for better accuracy.
  15791. var sel = rangeapi.getSelection(this.window);
  15792. if(!lang.isArray(mark)){
  15793. if(sel){
  15794. var range;
  15795. if(sel.rangeCount){
  15796. range = sel.getRangeAt(0);
  15797. }
  15798. if(range){
  15799. b.mark = range.cloneRange();
  15800. }else{
  15801. b.mark = win.withGlobal(this.window,focusBase.getBookmark);
  15802. }
  15803. }
  15804. }else{
  15805. // Control ranges (img, table, etc), handle differently.
  15806. array.forEach(b.mark,function(n){
  15807. tmp.push(rangeapi.getIndex(n,this.editNode).o);
  15808. },this);
  15809. b.mark = tmp;
  15810. }
  15811. }
  15812. try{
  15813. if(b.mark && b.mark.startContainer){
  15814. tmp=rangeapi.getIndex(b.mark.startContainer,this.editNode).o;
  15815. b.mark={startContainer:tmp,
  15816. startOffset:b.mark.startOffset,
  15817. endContainer:b.mark.endContainer===b.mark.startContainer?tmp:rangeapi.getIndex(b.mark.endContainer,this.editNode).o,
  15818. endOffset:b.mark.endOffset};
  15819. }
  15820. }catch(e){
  15821. b.mark = null;
  15822. }
  15823. }
  15824. return b;
  15825. },
  15826. _beginEditing: function(){
  15827. // summary:
  15828. // Called when the user starts typing alphanumeric characters.
  15829. // Deals with saving undo; see editActionInterval parameter.
  15830. // tags:
  15831. // private
  15832. if(this._steps.length === 0){
  15833. // You want to use the editor content without post filtering
  15834. // to make sure selection restores right for the 'initial' state.
  15835. // and undo is called. So not using this.value, as it was 'processed'
  15836. // and the line-up for selections may have been altered.
  15837. this._steps.push({'text':html.getChildrenHtml(this.editNode),'bookmark':this._getBookmark()});
  15838. }
  15839. },
  15840. _endEditing: function(){
  15841. // summary:
  15842. // Called when the user stops typing alphanumeric characters.
  15843. // Deals with saving undo; see editActionInterval parameter.
  15844. // tags:
  15845. // private
  15846. // Avoid filtering to make sure selections restore.
  15847. var v = html.getChildrenHtml(this.editNode);
  15848. this._undoedSteps=[];//clear undoed steps
  15849. this._steps.push({text: v, bookmark: this._getBookmark()});
  15850. },
  15851. onKeyDown: function(e){
  15852. // summary:
  15853. // Handler for onkeydown event.
  15854. // tags:
  15855. // private
  15856. //We need to save selection if the user TAB away from this editor
  15857. //no need to call _saveSelection for IE, as that will be taken care of in onBeforeDeactivate
  15858. if(!has("ie") && !this.iframe && e.keyCode == keys.TAB && !this.tabIndent){
  15859. this._saveSelection();
  15860. }
  15861. if(!this.customUndo){
  15862. this.inherited(arguments);
  15863. return;
  15864. }
  15865. var k = e.keyCode;
  15866. if(e.ctrlKey && !e.altKey){//undo and redo only if the special right Alt + z/y are not pressed #5892
  15867. if(k == 90 || k == 122){ //z
  15868. event.stop(e);
  15869. this.undo();
  15870. return;
  15871. }else if(k == 89 || k == 121){ //y
  15872. event.stop(e);
  15873. this.redo();
  15874. return;
  15875. }
  15876. }
  15877. this.inherited(arguments);
  15878. switch(k){
  15879. case keys.ENTER:
  15880. case keys.BACKSPACE:
  15881. case keys.DELETE:
  15882. this.beginEditing();
  15883. break;
  15884. case 88: //x
  15885. case 86: //v
  15886. if(e.ctrlKey && !e.altKey && !e.metaKey){
  15887. this.endEditing();//end current typing step if any
  15888. if(e.keyCode == 88){
  15889. this.beginEditing('cut');
  15890. //use timeout to trigger after the cut is complete
  15891. setTimeout(lang.hitch(this, this.endEditing), 1);
  15892. }else{
  15893. this.beginEditing('paste');
  15894. //use timeout to trigger after the paste is complete
  15895. setTimeout(lang.hitch(this, this.endEditing), 1);
  15896. }
  15897. break;
  15898. }
  15899. //pass through
  15900. default:
  15901. if(!e.ctrlKey && !e.altKey && !e.metaKey && (e.keyCode<keys.F1 || e.keyCode>keys.F15)){
  15902. this.beginEditing();
  15903. break;
  15904. }
  15905. //pass through
  15906. case keys.ALT:
  15907. this.endEditing();
  15908. break;
  15909. case keys.UP_ARROW:
  15910. case keys.DOWN_ARROW:
  15911. case keys.LEFT_ARROW:
  15912. case keys.RIGHT_ARROW:
  15913. case keys.HOME:
  15914. case keys.END:
  15915. case keys.PAGE_UP:
  15916. case keys.PAGE_DOWN:
  15917. this.endEditing(true);
  15918. break;
  15919. //maybe ctrl+backspace/delete, so don't endEditing when ctrl is pressed
  15920. case keys.CTRL:
  15921. case keys.SHIFT:
  15922. case keys.TAB:
  15923. break;
  15924. }
  15925. },
  15926. _onBlur: function(){
  15927. // summary:
  15928. // Called from focus manager when focus has moved away from this editor
  15929. // tags:
  15930. // protected
  15931. //this._saveSelection();
  15932. this.inherited(arguments);
  15933. this.endEditing(true);
  15934. },
  15935. _saveSelection: function(){
  15936. // summary:
  15937. // Save the currently selected text in _savedSelection attribute
  15938. // tags:
  15939. // private
  15940. try{
  15941. this._savedSelection=this._getBookmark();
  15942. }catch(e){ /* Squelch any errors that occur if selection save occurs due to being hidden simultaneously. */}
  15943. },
  15944. _restoreSelection: function(){
  15945. // summary:
  15946. // Re-select the text specified in _savedSelection attribute;
  15947. // see _saveSelection().
  15948. // tags:
  15949. // private
  15950. if(this._savedSelection){
  15951. // Clear off cursor to start, we're deliberately going to a selection.
  15952. delete this._cursorToStart;
  15953. // only restore the selection if the current range is collapsed
  15954. // if not collapsed, then it means the editor does not lose
  15955. // selection and there is no need to restore it
  15956. if(win.withGlobal(this.window,'isCollapsed',dijit)){
  15957. this._moveToBookmark(this._savedSelection);
  15958. }
  15959. delete this._savedSelection;
  15960. }
  15961. },
  15962. onClick: function(){
  15963. // summary:
  15964. // Handler for when editor is clicked
  15965. // tags:
  15966. // protected
  15967. this.endEditing(true);
  15968. this.inherited(arguments);
  15969. },
  15970. replaceValue: function(/*String*/ html){
  15971. // summary:
  15972. // over-ride of replaceValue to support custom undo and stack maintenance.
  15973. // tags:
  15974. // protected
  15975. if(!this.customUndo){
  15976. this.inherited(arguments);
  15977. }else{
  15978. if(this.isClosed){
  15979. this.setValue(html);
  15980. }else{
  15981. this.beginEditing();
  15982. if(!html){
  15983. html = "&#160;"; // &nbsp;
  15984. }
  15985. this.setValue(html);
  15986. this.endEditing();
  15987. }
  15988. }
  15989. },
  15990. _setDisabledAttr: function(/*Boolean*/ value){
  15991. var disableFunc = lang.hitch(this, function(){
  15992. if((!this.disabled && value) || (!this._buttonEnabledPlugins && value)){
  15993. // Disable editor: disable all enabled buttons and remember that list
  15994. array.forEach(this._plugins, function(p){
  15995. p.set("disabled", true);
  15996. });
  15997. }else if(this.disabled && !value){
  15998. // Restore plugins to being active.
  15999. array.forEach(this._plugins, function(p){
  16000. p.set("disabled", false);
  16001. });
  16002. }
  16003. });
  16004. this.setValueDeferred.addCallback(disableFunc);
  16005. this.inherited(arguments);
  16006. },
  16007. _setStateClass: function(){
  16008. try{
  16009. this.inherited(arguments);
  16010. // Let theme set the editor's text color based on editor enabled/disabled state.
  16011. // We need to jump through hoops because the main document (where the theme CSS is)
  16012. // is separate from the iframe's document.
  16013. if(this.document && this.document.body){
  16014. domStyle.set(this.document.body, "color", domStyle.get(this.iframe, "color"));
  16015. }
  16016. }catch(e){ /* Squelch any errors caused by focus change if hidden during a state change */}
  16017. }
  16018. });
  16019. // Register the "default plugins", ie, the built-in editor commands
  16020. function simplePluginFactory(args){
  16021. return new _Plugin({ command: args.name });
  16022. }
  16023. function togglePluginFactory(args){
  16024. return new _Plugin({ buttonClass: ToggleButton, command: args.name });
  16025. }
  16026. lang.mixin(_Plugin.registry, {
  16027. "undo": simplePluginFactory,
  16028. "redo": simplePluginFactory,
  16029. "cut": simplePluginFactory,
  16030. "copy": simplePluginFactory,
  16031. "paste": simplePluginFactory,
  16032. "insertOrderedList": simplePluginFactory,
  16033. "insertUnorderedList": simplePluginFactory,
  16034. "indent": simplePluginFactory,
  16035. "outdent": simplePluginFactory,
  16036. "justifyCenter": simplePluginFactory,
  16037. "justifyFull": simplePluginFactory,
  16038. "justifyLeft": simplePluginFactory,
  16039. "justifyRight": simplePluginFactory,
  16040. "delete": simplePluginFactory,
  16041. "selectAll": simplePluginFactory,
  16042. "removeFormat": simplePluginFactory,
  16043. "unlink": simplePluginFactory,
  16044. "insertHorizontalRule": simplePluginFactory,
  16045. "bold": togglePluginFactory,
  16046. "italic": togglePluginFactory,
  16047. "underline": togglePluginFactory,
  16048. "strikethrough": togglePluginFactory,
  16049. "subscript": togglePluginFactory,
  16050. "superscript": togglePluginFactory,
  16051. "|": function(){
  16052. return new _Plugin({ button: new ToolbarSeparator(), setEditor: function(editor){this.editor = editor;}});
  16053. }
  16054. });
  16055. return Editor;
  16056. });
  16057. },
  16058. 'dijit/Toolbar':function(){
  16059. define([
  16060. "require",
  16061. "dojo/_base/declare", // declare
  16062. "dojo/_base/kernel",
  16063. "dojo/keys", // keys.LEFT_ARROW keys.RIGHT_ARROW
  16064. "dojo/ready",
  16065. "./_Widget",
  16066. "./_KeyNavContainer",
  16067. "./_TemplatedMixin"
  16068. ], function(require, declare, kernel, keys, ready, _Widget, _KeyNavContainer, _TemplatedMixin){
  16069. /*=====
  16070. var _Widget = dijit._Widget;
  16071. var _KeyNavContainer = dijit._KeyNavContainer;
  16072. var _TemplatedMixin = dijit._TemplatedMixin;
  16073. =====*/
  16074. // module:
  16075. // dijit/Toolbar
  16076. // summary:
  16077. // A Toolbar widget, used to hold things like `dijit.Editor` buttons
  16078. // Back compat w/1.6, remove for 2.0
  16079. if(!kernel.isAsync){
  16080. ready(0, function(){
  16081. var requires = ["dijit/ToolbarSeparator"];
  16082. require(requires); // use indirection so modules not rolled into a build
  16083. });
  16084. }
  16085. return declare("dijit.Toolbar", [_Widget, _TemplatedMixin, _KeyNavContainer], {
  16086. // summary:
  16087. // A Toolbar widget, used to hold things like `dijit.Editor` buttons
  16088. templateString:
  16089. '<div class="dijit" role="toolbar" tabIndex="${tabIndex}" data-dojo-attach-point="containerNode">' +
  16090. '</div>',
  16091. baseClass: "dijitToolbar",
  16092. postCreate: function(){
  16093. this.inherited(arguments);
  16094. this.connectKeyNavHandlers(
  16095. this.isLeftToRight() ? [keys.LEFT_ARROW] : [keys.RIGHT_ARROW],
  16096. this.isLeftToRight() ? [keys.RIGHT_ARROW] : [keys.LEFT_ARROW]
  16097. );
  16098. }
  16099. });
  16100. });
  16101. },
  16102. 'dijit/layout/StackContainer':function(){
  16103. define([
  16104. "dojo/_base/array", // array.forEach array.indexOf array.some
  16105. "dojo/cookie", // cookie
  16106. "dojo/_base/declare", // declare
  16107. "dojo/dom-class", // domClass.add domClass.replace
  16108. "dojo/_base/kernel", // kernel.isAsync
  16109. "dojo/_base/lang", // lang.extend
  16110. "dojo/ready",
  16111. "dojo/topic", // publish
  16112. "../registry", // registry.byId
  16113. "../_WidgetBase",
  16114. "./_LayoutWidget",
  16115. "dojo/i18n!../nls/common"
  16116. ], function(array, cookie, declare, domClass, kernel, lang, ready, topic,
  16117. registry, _WidgetBase, _LayoutWidget){
  16118. /*=====
  16119. var _WidgetBase = dijit._WidgetBase;
  16120. var _LayoutWidget = dijit.layout._LayoutWidget;
  16121. var StackController = dijit.layout.StackController;
  16122. =====*/
  16123. // module:
  16124. // dijit/layout/StackContainer
  16125. // summary:
  16126. // A container that has multiple children, but shows only one child at a time.
  16127. // Back compat w/1.6, remove for 2.0
  16128. if(!kernel.isAsync){
  16129. ready(0, function(){
  16130. var requires = ["dijit/layout/StackController"];
  16131. require(requires); // use indirection so modules not rolled into a build
  16132. });
  16133. }
  16134. // These arguments can be specified for the children of a StackContainer.
  16135. // Since any widget can be specified as a StackContainer child, mix them
  16136. // into the base widget class. (This is a hack, but it's effective.)
  16137. lang.extend(_WidgetBase, {
  16138. // selected: Boolean
  16139. // Parameter for children of `dijit.layout.StackContainer` or subclasses.
  16140. // Specifies that this widget should be the initially displayed pane.
  16141. // Note: to change the selected child use `dijit.layout.StackContainer.selectChild`
  16142. selected: false,
  16143. // closable: Boolean
  16144. // Parameter for children of `dijit.layout.StackContainer` or subclasses.
  16145. // True if user can close (destroy) this child, such as (for example) clicking the X on the tab.
  16146. closable: false,
  16147. // iconClass: String
  16148. // Parameter for children of `dijit.layout.StackContainer` or subclasses.
  16149. // CSS Class specifying icon to use in label associated with this pane.
  16150. iconClass: "dijitNoIcon",
  16151. // showTitle: Boolean
  16152. // Parameter for children of `dijit.layout.StackContainer` or subclasses.
  16153. // When true, display title of this widget as tab label etc., rather than just using
  16154. // icon specified in iconClass
  16155. showTitle: true
  16156. });
  16157. return declare("dijit.layout.StackContainer", _LayoutWidget, {
  16158. // summary:
  16159. // A container that has multiple children, but shows only
  16160. // one child at a time
  16161. //
  16162. // description:
  16163. // A container for widgets (ContentPanes, for example) That displays
  16164. // only one Widget at a time.
  16165. //
  16166. // Publishes topics [widgetId]-addChild, [widgetId]-removeChild, and [widgetId]-selectChild
  16167. //
  16168. // Can be base class for container, Wizard, Show, etc.
  16169. // doLayout: Boolean
  16170. // If true, change the size of my currently displayed child to match my size
  16171. doLayout: true,
  16172. // persist: Boolean
  16173. // Remembers the selected child across sessions
  16174. persist: false,
  16175. baseClass: "dijitStackContainer",
  16176. /*=====
  16177. // selectedChildWidget: [readonly] dijit._Widget
  16178. // References the currently selected child widget, if any.
  16179. // Adjust selected child with selectChild() method.
  16180. selectedChildWidget: null,
  16181. =====*/
  16182. buildRendering: function(){
  16183. this.inherited(arguments);
  16184. domClass.add(this.domNode, "dijitLayoutContainer");
  16185. this.containerNode.setAttribute("role", "tabpanel");
  16186. },
  16187. postCreate: function(){
  16188. this.inherited(arguments);
  16189. this.connect(this.domNode, "onkeypress", this._onKeyPress);
  16190. },
  16191. startup: function(){
  16192. if(this._started){ return; }
  16193. var children = this.getChildren();
  16194. // Setup each page panel to be initially hidden
  16195. array.forEach(children, this._setupChild, this);
  16196. // Figure out which child to initially display, defaulting to first one
  16197. if(this.persist){
  16198. this.selectedChildWidget = registry.byId(cookie(this.id + "_selectedChild"));
  16199. }else{
  16200. array.some(children, function(child){
  16201. if(child.selected){
  16202. this.selectedChildWidget = child;
  16203. }
  16204. return child.selected;
  16205. }, this);
  16206. }
  16207. var selected = this.selectedChildWidget;
  16208. if(!selected && children[0]){
  16209. selected = this.selectedChildWidget = children[0];
  16210. selected.selected = true;
  16211. }
  16212. // Publish information about myself so any StackControllers can initialize.
  16213. // This needs to happen before this.inherited(arguments) so that for
  16214. // TabContainer, this._contentBox doesn't include the space for the tab labels.
  16215. topic.publish(this.id+"-startup", {children: children, selected: selected});
  16216. // Startup each child widget, and do initial layout like setting this._contentBox,
  16217. // then calls this.resize() which does the initial sizing on the selected child.
  16218. this.inherited(arguments);
  16219. },
  16220. resize: function(){
  16221. // Resize is called when we are first made visible (it's called from startup()
  16222. // if we are initially visible). If this is the first time we've been made
  16223. // visible then show our first child.
  16224. if(!this._hasBeenShown){
  16225. this._hasBeenShown = true;
  16226. var selected = this.selectedChildWidget;
  16227. if(selected){
  16228. this._showChild(selected);
  16229. }
  16230. }
  16231. this.inherited(arguments);
  16232. },
  16233. _setupChild: function(/*dijit._Widget*/ child){
  16234. // Overrides _LayoutWidget._setupChild()
  16235. this.inherited(arguments);
  16236. domClass.replace(child.domNode, "dijitHidden", "dijitVisible");
  16237. // remove the title attribute so it doesn't show up when i hover
  16238. // over a node
  16239. child.domNode.title = "";
  16240. },
  16241. addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
  16242. // Overrides _Container.addChild() to do layout and publish events
  16243. this.inherited(arguments);
  16244. if(this._started){
  16245. topic.publish(this.id+"-addChild", child, insertIndex); // publish
  16246. // in case the tab titles have overflowed from one line to two lines
  16247. // (or, if this if first child, from zero lines to one line)
  16248. // TODO: w/ScrollingTabController this is no longer necessary, although
  16249. // ScrollTabController.resize() does need to get called to show/hide
  16250. // the navigation buttons as appropriate, but that's handled in ScrollingTabController.onAddChild().
  16251. // If this is updated to not layout [except for initial child added / last child removed], update
  16252. // "childless startup" test in StackContainer.html to check for no resize event after second addChild()
  16253. this.layout();
  16254. // if this is the first child, then select it
  16255. if(!this.selectedChildWidget){
  16256. this.selectChild(child);
  16257. }
  16258. }
  16259. },
  16260. removeChild: function(/*dijit._Widget*/ page){
  16261. // Overrides _Container.removeChild() to do layout and publish events
  16262. this.inherited(arguments);
  16263. if(this._started){
  16264. // this will notify any tablists to remove a button; do this first because it may affect sizing
  16265. topic.publish(this.id + "-removeChild", page); // publish
  16266. }
  16267. // If all our children are being destroyed than don't run the code below (to select another page),
  16268. // because we are deleting every page one by one
  16269. if(this._descendantsBeingDestroyed){ return; }
  16270. // Select new page to display, also updating TabController to show the respective tab.
  16271. // Do this before layout call because it can affect the height of the TabController.
  16272. if(this.selectedChildWidget === page){
  16273. this.selectedChildWidget = undefined;
  16274. if(this._started){
  16275. var children = this.getChildren();
  16276. if(children.length){
  16277. this.selectChild(children[0]);
  16278. }
  16279. }
  16280. }
  16281. if(this._started){
  16282. // In case the tab titles now take up one line instead of two lines
  16283. // (note though that ScrollingTabController never overflows to multiple lines),
  16284. // or the height has changed slightly because of addition/removal of tab which close icon
  16285. this.layout();
  16286. }
  16287. },
  16288. selectChild: function(/*dijit._Widget|String*/ page, /*Boolean*/ animate){
  16289. // summary:
  16290. // Show the given widget (which must be one of my children)
  16291. // page:
  16292. // Reference to child widget or id of child widget
  16293. page = registry.byId(page);
  16294. if(this.selectedChildWidget != page){
  16295. // Deselect old page and select new one
  16296. var d = this._transition(page, this.selectedChildWidget, animate);
  16297. this._set("selectedChildWidget", page);
  16298. topic.publish(this.id+"-selectChild", page); // publish
  16299. if(this.persist){
  16300. cookie(this.id + "_selectedChild", this.selectedChildWidget.id);
  16301. }
  16302. }
  16303. return d; // If child has an href, promise that fires when the child's href finishes loading
  16304. },
  16305. _transition: function(newWidget, oldWidget /*===== , animate =====*/){
  16306. // summary:
  16307. // Hide the old widget and display the new widget.
  16308. // Subclasses should override this.
  16309. // newWidget: dijit._Widget
  16310. // The newly selected widget.
  16311. // oldWidget: dijit._Widget
  16312. // The previously selected widget.
  16313. // animate: Boolean
  16314. // Used by AccordionContainer to turn on/off slide effect.
  16315. // tags:
  16316. // protected extension
  16317. if(oldWidget){
  16318. this._hideChild(oldWidget);
  16319. }
  16320. var d = this._showChild(newWidget);
  16321. // Size the new widget, in case this is the first time it's being shown,
  16322. // or I have been resized since the last time it was shown.
  16323. // Note that page must be visible for resizing to work.
  16324. if(newWidget.resize){
  16325. if(this.doLayout){
  16326. newWidget.resize(this._containerContentBox || this._contentBox);
  16327. }else{
  16328. // the child should pick it's own size but we still need to call resize()
  16329. // (with no arguments) to let the widget lay itself out
  16330. newWidget.resize();
  16331. }
  16332. }
  16333. return d; // If child has an href, promise that fires when the child's href finishes loading
  16334. },
  16335. _adjacent: function(/*Boolean*/ forward){
  16336. // summary:
  16337. // Gets the next/previous child widget in this container from the current selection.
  16338. var children = this.getChildren();
  16339. var index = array.indexOf(children, this.selectedChildWidget);
  16340. index += forward ? 1 : children.length - 1;
  16341. return children[ index % children.length ]; // dijit._Widget
  16342. },
  16343. forward: function(){
  16344. // summary:
  16345. // Advance to next page.
  16346. return this.selectChild(this._adjacent(true), true);
  16347. },
  16348. back: function(){
  16349. // summary:
  16350. // Go back to previous page.
  16351. return this.selectChild(this._adjacent(false), true);
  16352. },
  16353. _onKeyPress: function(e){
  16354. topic.publish(this.id+"-containerKeyPress", { e: e, page: this}); // publish
  16355. },
  16356. layout: function(){
  16357. // Implement _LayoutWidget.layout() virtual method.
  16358. var child = this.selectedChildWidget;
  16359. if(child && child.resize){
  16360. if(this.doLayout){
  16361. child.resize(this._containerContentBox || this._contentBox);
  16362. }else{
  16363. child.resize();
  16364. }
  16365. }
  16366. },
  16367. _showChild: function(/*dijit._Widget*/ page){
  16368. // summary:
  16369. // Show the specified child by changing it's CSS, and call _onShow()/onShow() so
  16370. // it can do any updates it needs regarding loading href's etc.
  16371. // returns:
  16372. // Promise that fires when page has finished showing, or true if there's no href
  16373. var children = this.getChildren();
  16374. page.isFirstChild = (page == children[0]);
  16375. page.isLastChild = (page == children[children.length-1]);
  16376. page._set("selected", true);
  16377. domClass.replace(page.domNode, "dijitVisible", "dijitHidden");
  16378. return (page._onShow && page._onShow()) || true;
  16379. },
  16380. _hideChild: function(/*dijit._Widget*/ page){
  16381. // summary:
  16382. // Hide the specified child by changing it's CSS, and call _onHide() so
  16383. // it's notified.
  16384. page._set("selected", false);
  16385. domClass.replace(page.domNode, "dijitHidden", "dijitVisible");
  16386. page.onHide && page.onHide();
  16387. },
  16388. closeChild: function(/*dijit._Widget*/ page){
  16389. // summary:
  16390. // Callback when user clicks the [X] to remove a page.
  16391. // If onClose() returns true then remove and destroy the child.
  16392. // tags:
  16393. // private
  16394. var remove = page.onClose(this, page);
  16395. if(remove){
  16396. this.removeChild(page);
  16397. // makes sure we can clean up executeScripts in ContentPane onUnLoad
  16398. page.destroyRecursive();
  16399. }
  16400. },
  16401. destroyDescendants: function(/*Boolean*/ preserveDom){
  16402. this._descendantsBeingDestroyed = true;
  16403. this.selectedChildWidget = undefined;
  16404. array.forEach(this.getChildren(), function(child){
  16405. if(!preserveDom){
  16406. this.removeChild(child);
  16407. }
  16408. child.destroyRecursive(preserveDom);
  16409. }, this);
  16410. this._descendantsBeingDestroyed = false;
  16411. }
  16412. });
  16413. });
  16414. },
  16415. 'dojo/regexp':function(){
  16416. define(["./_base/kernel", "./_base/lang"], function(dojo, lang) {
  16417. // module:
  16418. // dojo/regexp
  16419. // summary:
  16420. // TODOC
  16421. lang.getObject("regexp", true, dojo);
  16422. /*=====
  16423. dojo.regexp = {
  16424. // summary: Regular expressions and Builder resources
  16425. };
  16426. =====*/
  16427. dojo.regexp.escapeString = function(/*String*/str, /*String?*/except){
  16428. // summary:
  16429. // Adds escape sequences for special characters in regular expressions
  16430. // except:
  16431. // a String with special characters to be left unescaped
  16432. return str.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, function(ch){
  16433. if(except && except.indexOf(ch) != -1){
  16434. return ch;
  16435. }
  16436. return "\\" + ch;
  16437. }); // String
  16438. };
  16439. dojo.regexp.buildGroupRE = function(/*Object|Array*/arr, /*Function*/re, /*Boolean?*/nonCapture){
  16440. // summary:
  16441. // Builds a regular expression that groups subexpressions
  16442. // description:
  16443. // A utility function used by some of the RE generators. The
  16444. // subexpressions are constructed by the function, re, in the second
  16445. // parameter. re builds one subexpression for each elem in the array
  16446. // a, in the first parameter. Returns a string for a regular
  16447. // expression that groups all the subexpressions.
  16448. // arr:
  16449. // A single value or an array of values.
  16450. // re:
  16451. // A function. Takes one parameter and converts it to a regular
  16452. // expression.
  16453. // nonCapture:
  16454. // If true, uses non-capturing match, otherwise matches are retained
  16455. // by regular expression. Defaults to false
  16456. // case 1: a is a single value.
  16457. if(!(arr instanceof Array)){
  16458. return re(arr); // String
  16459. }
  16460. // case 2: a is an array
  16461. var b = [];
  16462. for(var i = 0; i < arr.length; i++){
  16463. // convert each elem to a RE
  16464. b.push(re(arr[i]));
  16465. }
  16466. // join the REs as alternatives in a RE group.
  16467. return dojo.regexp.group(b.join("|"), nonCapture); // String
  16468. };
  16469. dojo.regexp.group = function(/*String*/expression, /*Boolean?*/nonCapture){
  16470. // summary:
  16471. // adds group match to expression
  16472. // nonCapture:
  16473. // If true, uses non-capturing match, otherwise matches are retained
  16474. // by regular expression.
  16475. return "(" + (nonCapture ? "?:":"") + expression + ")"; // String
  16476. };
  16477. return dojo.regexp;
  16478. });
  16479. },
  16480. 'dijit/form/ComboBox':function(){
  16481. define([
  16482. "dojo/_base/declare", // declare
  16483. "./ValidationTextBox",
  16484. "./ComboBoxMixin"
  16485. ], function(declare, ValidationTextBox, ComboBoxMixin){
  16486. /*=====
  16487. var ValidationTextBox = dijit.form.ValidationTextBox;
  16488. var ComboBoxMixin = dijit.form.ComboBoxMixin;
  16489. =====*/
  16490. // module:
  16491. // dijit/form/ComboBox
  16492. // summary:
  16493. // Auto-completing text box
  16494. return declare("dijit.form.ComboBox", [ValidationTextBox, ComboBoxMixin], {
  16495. // summary:
  16496. // Auto-completing text box
  16497. //
  16498. // description:
  16499. // The drop down box's values are populated from an class called
  16500. // a data provider, which returns a list of values based on the characters
  16501. // that the user has typed into the input box.
  16502. // If OPTION tags are used as the data provider via markup,
  16503. // then the OPTION tag's child text node is used as the widget value
  16504. // when selected. The OPTION tag's value attribute is ignored.
  16505. // To set the default value when using OPTION tags, specify the selected
  16506. // attribute on 1 of the child OPTION tags.
  16507. //
  16508. // Some of the options to the ComboBox are actually arguments to the data
  16509. // provider.
  16510. });
  16511. });
  16512. },
  16513. 'dijit/form/_FormMixin':function(){
  16514. define([
  16515. "dojo/_base/array", // array.every array.filter array.forEach array.indexOf array.map
  16516. "dojo/_base/declare", // declare
  16517. "dojo/_base/kernel", // kernel.deprecated
  16518. "dojo/_base/lang", // lang.hitch lang.isArray
  16519. "dojo/window" // winUtils.scrollIntoView
  16520. ], function(array, declare, kernel, lang, winUtils){
  16521. // module:
  16522. // dijit/form/_FormMixin
  16523. // summary:
  16524. // Mixin for containers of form widgets (i.e. widgets that represent a single value
  16525. // and can be children of a <form> node or dijit.form.Form widget)
  16526. return declare("dijit.form._FormMixin", null, {
  16527. // summary:
  16528. // Mixin for containers of form widgets (i.e. widgets that represent a single value
  16529. // and can be children of a <form> node or dijit.form.Form widget)
  16530. // description:
  16531. // Can extract all the form widgets
  16532. // values and combine them into a single javascript object, or alternately
  16533. // take such an object and set the values for all the contained
  16534. // form widgets
  16535. /*=====
  16536. // value: Object
  16537. // Name/value hash for each child widget with a name and value.
  16538. // Child widgets without names are not part of the hash.
  16539. //
  16540. // If there are multiple child widgets w/the same name, value is an array,
  16541. // unless they are radio buttons in which case value is a scalar (since only
  16542. // one radio button can be checked at a time).
  16543. //
  16544. // If a child widget's name is a dot separated list (like a.b.c.d), it's a nested structure.
  16545. //
  16546. // Example:
  16547. // | { name: "John Smith", interests: ["sports", "movies"] }
  16548. =====*/
  16549. // state: [readonly] String
  16550. // Will be "Error" if one or more of the child widgets has an invalid value,
  16551. // "Incomplete" if not all of the required child widgets are filled in. Otherwise, "",
  16552. // which indicates that the form is ready to be submitted.
  16553. state: "",
  16554. // TODO:
  16555. // * Repeater
  16556. // * better handling for arrays. Often form elements have names with [] like
  16557. // * people[3].sex (for a list of people [{name: Bill, sex: M}, ...])
  16558. //
  16559. //
  16560. _getDescendantFormWidgets: function(/*dijit._WidgetBase[]?*/ children){
  16561. // summary:
  16562. // Returns all form widget descendants, searching through non-form child widgets like BorderContainer
  16563. var res = [];
  16564. array.forEach(children || this.getChildren(), function(child){
  16565. if("value" in child){
  16566. res.push(child);
  16567. }else{
  16568. res = res.concat(this._getDescendantFormWidgets(child.getChildren()));
  16569. }
  16570. }, this);
  16571. return res;
  16572. },
  16573. reset: function(){
  16574. array.forEach(this._getDescendantFormWidgets(), function(widget){
  16575. if(widget.reset){
  16576. widget.reset();
  16577. }
  16578. });
  16579. },
  16580. validate: function(){
  16581. // summary:
  16582. // returns if the form is valid - same as isValid - but
  16583. // provides a few additional (ui-specific) features.
  16584. // 1 - it will highlight any sub-widgets that are not
  16585. // valid
  16586. // 2 - it will call focus() on the first invalid
  16587. // sub-widget
  16588. var didFocus = false;
  16589. return array.every(array.map(this._getDescendantFormWidgets(), function(widget){
  16590. // Need to set this so that "required" widgets get their
  16591. // state set.
  16592. widget._hasBeenBlurred = true;
  16593. var valid = widget.disabled || !widget.validate || widget.validate();
  16594. if(!valid && !didFocus){
  16595. // Set focus of the first non-valid widget
  16596. winUtils.scrollIntoView(widget.containerNode || widget.domNode);
  16597. widget.focus();
  16598. didFocus = true;
  16599. }
  16600. return valid;
  16601. }), function(item){ return item; });
  16602. },
  16603. setValues: function(val){
  16604. kernel.deprecated(this.declaredClass+"::setValues() is deprecated. Use set('value', val) instead.", "", "2.0");
  16605. return this.set('value', val);
  16606. },
  16607. _setValueAttr: function(/*Object*/ obj){
  16608. // summary:
  16609. // Fill in form values from according to an Object (in the format returned by get('value'))
  16610. // generate map from name --> [list of widgets with that name]
  16611. var map = { };
  16612. array.forEach(this._getDescendantFormWidgets(), function(widget){
  16613. if(!widget.name){ return; }
  16614. var entry = map[widget.name] || (map[widget.name] = [] );
  16615. entry.push(widget);
  16616. });
  16617. for(var name in map){
  16618. if(!map.hasOwnProperty(name)){
  16619. continue;
  16620. }
  16621. var widgets = map[name], // array of widgets w/this name
  16622. values = lang.getObject(name, false, obj); // list of values for those widgets
  16623. if(values === undefined){
  16624. continue;
  16625. }
  16626. if(!lang.isArray(values)){
  16627. values = [ values ];
  16628. }
  16629. if(typeof widgets[0].checked == 'boolean'){
  16630. // for checkbox/radio, values is a list of which widgets should be checked
  16631. array.forEach(widgets, function(w){
  16632. w.set('value', array.indexOf(values, w.value) != -1);
  16633. });
  16634. }else if(widgets[0].multiple){
  16635. // it takes an array (e.g. multi-select)
  16636. widgets[0].set('value', values);
  16637. }else{
  16638. // otherwise, values is a list of values to be assigned sequentially to each widget
  16639. array.forEach(widgets, function(w, i){
  16640. w.set('value', values[i]);
  16641. });
  16642. }
  16643. }
  16644. /***
  16645. * TODO: code for plain input boxes (this shouldn't run for inputs that are part of widgets)
  16646. array.forEach(this.containerNode.elements, function(element){
  16647. if(element.name == ''){return}; // like "continue"
  16648. var namePath = element.name.split(".");
  16649. var myObj=obj;
  16650. var name=namePath[namePath.length-1];
  16651. for(var j=1,len2=namePath.length;j<len2;++j){
  16652. var p=namePath[j - 1];
  16653. // repeater support block
  16654. var nameA=p.split("[");
  16655. if(nameA.length > 1){
  16656. if(typeof(myObj[nameA[0]]) == "undefined"){
  16657. myObj[nameA[0]]=[ ];
  16658. } // if
  16659. nameIndex=parseInt(nameA[1]);
  16660. if(typeof(myObj[nameA[0]][nameIndex]) == "undefined"){
  16661. myObj[nameA[0]][nameIndex] = { };
  16662. }
  16663. myObj=myObj[nameA[0]][nameIndex];
  16664. continue;
  16665. } // repeater support ends
  16666. if(typeof(myObj[p]) == "undefined"){
  16667. myObj=undefined;
  16668. break;
  16669. };
  16670. myObj=myObj[p];
  16671. }
  16672. if(typeof(myObj) == "undefined"){
  16673. return; // like "continue"
  16674. }
  16675. if(typeof(myObj[name]) == "undefined" && this.ignoreNullValues){
  16676. return; // like "continue"
  16677. }
  16678. // TODO: widget values (just call set('value', ...) on the widget)
  16679. // TODO: maybe should call dojo.getNodeProp() instead
  16680. switch(element.type){
  16681. case "checkbox":
  16682. element.checked = (name in myObj) &&
  16683. array.some(myObj[name], function(val){ return val == element.value; });
  16684. break;
  16685. case "radio":
  16686. element.checked = (name in myObj) && myObj[name] == element.value;
  16687. break;
  16688. case "select-multiple":
  16689. element.selectedIndex=-1;
  16690. array.forEach(element.options, function(option){
  16691. option.selected = array.some(myObj[name], function(val){ return option.value == val; });
  16692. });
  16693. break;
  16694. case "select-one":
  16695. element.selectedIndex="0";
  16696. array.forEach(element.options, function(option){
  16697. option.selected = option.value == myObj[name];
  16698. });
  16699. break;
  16700. case "hidden":
  16701. case "text":
  16702. case "textarea":
  16703. case "password":
  16704. element.value = myObj[name] || "";
  16705. break;
  16706. }
  16707. });
  16708. */
  16709. // Note: no need to call this._set("value", ...) as the child updates will trigger onChange events
  16710. // which I am monitoring.
  16711. },
  16712. getValues: function(){
  16713. kernel.deprecated(this.declaredClass+"::getValues() is deprecated. Use get('value') instead.", "", "2.0");
  16714. return this.get('value');
  16715. },
  16716. _getValueAttr: function(){
  16717. // summary:
  16718. // Returns Object representing form values. See description of `value` for details.
  16719. // description:
  16720. // The value is updated into this.value every time a child has an onChange event,
  16721. // so in the common case this function could just return this.value. However,
  16722. // that wouldn't work when:
  16723. //
  16724. // 1. User presses return key to submit a form. That doesn't fire an onchange event,
  16725. // and even if it did it would come too late due to the setTimeout(..., 0) in _handleOnChange()
  16726. //
  16727. // 2. app for some reason calls this.get("value") while the user is typing into a
  16728. // form field. Not sure if that case needs to be supported or not.
  16729. // get widget values
  16730. var obj = { };
  16731. array.forEach(this._getDescendantFormWidgets(), function(widget){
  16732. var name = widget.name;
  16733. if(!name || widget.disabled){ return; }
  16734. // Single value widget (checkbox, radio, or plain <input> type widget)
  16735. var value = widget.get('value');
  16736. // Store widget's value(s) as a scalar, except for checkboxes which are automatically arrays
  16737. if(typeof widget.checked == 'boolean'){
  16738. if(/Radio/.test(widget.declaredClass)){
  16739. // radio button
  16740. if(value !== false){
  16741. lang.setObject(name, value, obj);
  16742. }else{
  16743. // give radio widgets a default of null
  16744. value = lang.getObject(name, false, obj);
  16745. if(value === undefined){
  16746. lang.setObject(name, null, obj);
  16747. }
  16748. }
  16749. }else{
  16750. // checkbox/toggle button
  16751. var ary=lang.getObject(name, false, obj);
  16752. if(!ary){
  16753. ary=[];
  16754. lang.setObject(name, ary, obj);
  16755. }
  16756. if(value !== false){
  16757. ary.push(value);
  16758. }
  16759. }
  16760. }else{
  16761. var prev=lang.getObject(name, false, obj);
  16762. if(typeof prev != "undefined"){
  16763. if(lang.isArray(prev)){
  16764. prev.push(value);
  16765. }else{
  16766. lang.setObject(name, [prev, value], obj);
  16767. }
  16768. }else{
  16769. // unique name
  16770. lang.setObject(name, value, obj);
  16771. }
  16772. }
  16773. });
  16774. /***
  16775. * code for plain input boxes (see also domForm.formToObject, can we use that instead of this code?
  16776. * but it doesn't understand [] notation, presumably)
  16777. var obj = { };
  16778. array.forEach(this.containerNode.elements, function(elm){
  16779. if(!elm.name) {
  16780. return; // like "continue"
  16781. }
  16782. var namePath = elm.name.split(".");
  16783. var myObj=obj;
  16784. var name=namePath[namePath.length-1];
  16785. for(var j=1,len2=namePath.length;j<len2;++j){
  16786. var nameIndex = null;
  16787. var p=namePath[j - 1];
  16788. var nameA=p.split("[");
  16789. if(nameA.length > 1){
  16790. if(typeof(myObj[nameA[0]]) == "undefined"){
  16791. myObj[nameA[0]]=[ ];
  16792. } // if
  16793. nameIndex=parseInt(nameA[1]);
  16794. if(typeof(myObj[nameA[0]][nameIndex]) == "undefined"){
  16795. myObj[nameA[0]][nameIndex] = { };
  16796. }
  16797. }else if(typeof(myObj[nameA[0]]) == "undefined"){
  16798. myObj[nameA[0]] = { }
  16799. } // if
  16800. if(nameA.length == 1){
  16801. myObj=myObj[nameA[0]];
  16802. }else{
  16803. myObj=myObj[nameA[0]][nameIndex];
  16804. } // if
  16805. } // for
  16806. if((elm.type != "select-multiple" && elm.type != "checkbox" && elm.type != "radio") || (elm.type == "radio" && elm.checked)){
  16807. if(name == name.split("[")[0]){
  16808. myObj[name]=elm.value;
  16809. }else{
  16810. // can not set value when there is no name
  16811. }
  16812. }else if(elm.type == "checkbox" && elm.checked){
  16813. if(typeof(myObj[name]) == 'undefined'){
  16814. myObj[name]=[ ];
  16815. }
  16816. myObj[name].push(elm.value);
  16817. }else if(elm.type == "select-multiple"){
  16818. if(typeof(myObj[name]) == 'undefined'){
  16819. myObj[name]=[ ];
  16820. }
  16821. for(var jdx=0,len3=elm.options.length; jdx<len3; ++jdx){
  16822. if(elm.options[jdx].selected){
  16823. myObj[name].push(elm.options[jdx].value);
  16824. }
  16825. }
  16826. } // if
  16827. name=undefined;
  16828. }); // forEach
  16829. ***/
  16830. return obj;
  16831. },
  16832. isValid: function(){
  16833. // summary:
  16834. // Returns true if all of the widgets are valid.
  16835. // Deprecated, will be removed in 2.0. Use get("state") instead.
  16836. return this.state == "";
  16837. },
  16838. onValidStateChange: function(/*Boolean*/ /*===== isValid =====*/){
  16839. // summary:
  16840. // Stub function to connect to if you want to do something
  16841. // (like disable/enable a submit button) when the valid
  16842. // state changes on the form as a whole.
  16843. //
  16844. // Deprecated. Will be removed in 2.0. Use watch("state", ...) instead.
  16845. },
  16846. _getState: function(){
  16847. // summary:
  16848. // Compute what this.state should be based on state of children
  16849. var states = array.map(this._descendants, function(w){
  16850. return w.get("state") || "";
  16851. });
  16852. return array.indexOf(states, "Error") >= 0 ? "Error" :
  16853. array.indexOf(states, "Incomplete") >= 0 ? "Incomplete" : "";
  16854. },
  16855. disconnectChildren: function(){
  16856. // summary:
  16857. // Remove connections to monitor changes to children's value, error state, and disabled state,
  16858. // in order to update Form.value and Form.state.
  16859. array.forEach(this._childConnections || [], lang.hitch(this, "disconnect"));
  16860. array.forEach(this._childWatches || [], function(w){ w.unwatch(); });
  16861. },
  16862. connectChildren: function(/*Boolean*/ inStartup){
  16863. // summary:
  16864. // Setup connections to monitor changes to children's value, error state, and disabled state,
  16865. // in order to update Form.value and Form.state.
  16866. //
  16867. // You can call this function directly, ex. in the event that you
  16868. // programmatically add a widget to the form *after* the form has been
  16869. // initialized.
  16870. var _this = this;
  16871. // Remove old connections, if any
  16872. this.disconnectChildren();
  16873. this._descendants = this._getDescendantFormWidgets();
  16874. // (Re)set this.value and this.state. Send watch() notifications but not on startup.
  16875. var set = inStartup ? function(name, val){ _this[name] = val; } : lang.hitch(this, "_set");
  16876. set("value", this.get("value"));
  16877. set("state", this._getState());
  16878. // Monitor changes to error state and disabled state in order to update
  16879. // Form.state
  16880. var conns = (this._childConnections = []),
  16881. watches = (this._childWatches = []);
  16882. array.forEach(array.filter(this._descendants,
  16883. function(item){ return item.validate; }
  16884. ),
  16885. function(widget){
  16886. // We are interested in whenever the widget changes validity state - or
  16887. // whenever the disabled attribute on that widget is changed.
  16888. array.forEach(["state", "disabled"], function(attr){
  16889. watches.push(widget.watch(attr, function(){
  16890. _this.set("state", _this._getState());
  16891. }));
  16892. });
  16893. });
  16894. // And monitor calls to child.onChange so we can update this.value
  16895. var onChange = function(){
  16896. // summary:
  16897. // Called when child's value or disabled state changes
  16898. // Use setTimeout() to collapse value changes in multiple children into a single
  16899. // update to my value. Multiple updates will occur on:
  16900. // 1. Form.set()
  16901. // 2. Form.reset()
  16902. // 3. user selecting a radio button (which will de-select another radio button,
  16903. // causing two onChange events)
  16904. if(_this._onChangeDelayTimer){
  16905. clearTimeout(_this._onChangeDelayTimer);
  16906. }
  16907. _this._onChangeDelayTimer = setTimeout(function(){
  16908. delete _this._onChangeDelayTimer;
  16909. _this._set("value", _this.get("value"));
  16910. }, 10);
  16911. };
  16912. array.forEach(
  16913. array.filter(this._descendants, function(item){ return item.onChange; } ),
  16914. function(widget){
  16915. // When a child widget's value changes,
  16916. // the efficient thing to do is to just update that one attribute in this.value,
  16917. // but that gets a little complicated when a checkbox is checked/unchecked
  16918. // since this.value["checkboxName"] contains an array of all the checkboxes w/the same name.
  16919. // Doing simple thing for now.
  16920. conns.push(_this.connect(widget, "onChange", onChange));
  16921. // Disabling/enabling a child widget should remove it's value from this.value.
  16922. // Again, this code could be more efficient, doing simple thing for now.
  16923. watches.push(widget.watch("disabled", onChange));
  16924. }
  16925. );
  16926. },
  16927. startup: function(){
  16928. this.inherited(arguments);
  16929. // Initialize value and valid/invalid state tracking. Needs to be done in startup()
  16930. // so that children are initialized.
  16931. this.connectChildren(true);
  16932. // Make state change call onValidStateChange(), will be removed in 2.0
  16933. this.watch("state", function(attr, oldVal, newVal){ this.onValidStateChange(newVal == ""); });
  16934. },
  16935. destroy: function(){
  16936. this.disconnectChildren();
  16937. this.inherited(arguments);
  16938. }
  16939. });
  16940. });
  16941. },
  16942. 'dijit/_editor/plugins/LinkDialog':function(){
  16943. define([
  16944. "require",
  16945. "dojo/_base/declare", // declare
  16946. "dojo/dom-attr", // domAttr.get
  16947. "dojo/keys", // keys.ENTER
  16948. "dojo/_base/lang", // lang.delegate lang.hitch lang.trim
  16949. "dojo/_base/sniff", // has("ie")
  16950. "dojo/_base/query", // query
  16951. "dojo/string", // string.substitute
  16952. "dojo/_base/window", // win.withGlobal
  16953. "../../_Widget",
  16954. "../_Plugin",
  16955. "../../form/DropDownButton",
  16956. "../range",
  16957. "../selection"
  16958. ], function(require, declare, domAttr, keys, lang, has, query, string, win,
  16959. _Widget, _Plugin, DropDownButton, rangeapi, selectionapi){
  16960. /*=====
  16961. var _Plugin = dijit._editor._Plugin;
  16962. =====*/
  16963. // module:
  16964. // dijit/_editor/plugins/LinkDialog
  16965. // summary:
  16966. // Editor plugins: LinkDialog (for inserting links) and ImgLinkDialog (for inserting images)
  16967. var LinkDialog = declare("dijit._editor.plugins.LinkDialog", _Plugin, {
  16968. // summary:
  16969. // This plugin provides the basis for an 'anchor' (link) dialog and an extension of it
  16970. // provides the image link dialog.
  16971. //
  16972. // description:
  16973. // The command provided by this plugin is:
  16974. // * createLink
  16975. // Override _Plugin.buttonClass. This plugin is controlled by a DropDownButton
  16976. // (which triggers a TooltipDialog).
  16977. buttonClass: DropDownButton,
  16978. // Override _Plugin.useDefaultCommand... processing is handled by this plugin, not by dijit.Editor.
  16979. useDefaultCommand: false,
  16980. // urlRegExp: [protected] String
  16981. // Used for validating input as correct URL. While file:// urls are not terribly
  16982. // useful, they are technically valid.
  16983. urlRegExp: "((https?|ftps?|file)\\://|\./|/|)(/[a-zA-Z]{1,1}:/|)(((?:(?:[\\da-zA-Z](?:[-\\da-zA-Z]{0,61}[\\da-zA-Z])?)\\.)*(?:[a-zA-Z](?:[-\\da-zA-Z]{0,80}[\\da-zA-Z])?)\\.?)|(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])|(0[xX]0*[\\da-fA-F]?[\\da-fA-F]\\.){3}0[xX]0*[\\da-fA-F]?[\\da-fA-F]|(0+[0-3][0-7][0-7]\\.){3}0+[0-3][0-7][0-7]|(0|[1-9]\\d{0,8}|[1-3]\\d{9}|4[01]\\d{8}|42[0-8]\\d{7}|429[0-3]\\d{6}|4294[0-8]\\d{5}|42949[0-5]\\d{4}|429496[0-6]\\d{3}|4294967[01]\\d{2}|42949672[0-8]\\d|429496729[0-5])|0[xX]0*[\\da-fA-F]{1,8}|([\\da-fA-F]{1,4}\\:){7}[\\da-fA-F]{1,4}|([\\da-fA-F]{1,4}\\:){6}((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])))(\\:\\d+)?(/(?:[^?#\\s/]+/)*(?:[^?#\\s/]{0,}(?:\\?[^?#\\s/]*)?(?:#.*)?)?)?",
  16984. // emailRegExp: [protected] String
  16985. // Used for validating input as correct email address. Taken from dojox.validate
  16986. emailRegExp: "<?(mailto\\:)([!#-'*+\\-\\/-9=?A-Z^-~]+[.])*[!#-'*+\\-\\/-9=?A-Z^-~]+" /*username*/ + "@" +
  16987. "((?:(?:[\\da-zA-Z](?:[-\\da-zA-Z]{0,61}[\\da-zA-Z])?)\\.)+(?:[a-zA-Z](?:[-\\da-zA-Z]{0,6}[\\da-zA-Z])?)\\.?)|localhost|^[^-][a-zA-Z0-9_-]*>?", // host.
  16988. // htmlTemplate: [protected] String
  16989. // String used for templating the HTML to insert at the desired point.
  16990. htmlTemplate: "<a href=\"${urlInput}\" _djrealurl=\"${urlInput}\"" +
  16991. " target=\"${targetSelect}\"" +
  16992. ">${textInput}</a>",
  16993. // tag: [protected] String
  16994. // Tag used for the link type.
  16995. tag: "a",
  16996. // _hostRxp [private] RegExp
  16997. // Regular expression used to validate url fragments (ip address, hostname, etc)
  16998. _hostRxp: /^((([^\[:]+):)?([^@]+)@)?(\[([^\]]+)\]|([^\[:]*))(:([0-9]+))?$/,
  16999. // _userAtRxp [private] RegExp
  17000. // Regular expression used to validate e-mail address fragment.
  17001. _userAtRxp: /^([!#-'*+\-\/-9=?A-Z^-~]+[.])*[!#-'*+\-\/-9=?A-Z^-~]+@/i,
  17002. // linkDialogTemplate: [protected] String
  17003. // Template for contents of TooltipDialog to pick URL
  17004. linkDialogTemplate: [
  17005. "<table><tr><td>",
  17006. "<label for='${id}_urlInput'>${url}</label>",
  17007. "</td><td>",
  17008. "<input data-dojo-type='dijit.form.ValidationTextBox' required='true' " +
  17009. "id='${id}_urlInput' name='urlInput' data-dojo-props='intermediateChanges:true'/>",
  17010. "</td></tr><tr><td>",
  17011. "<label for='${id}_textInput'>${text}</label>",
  17012. "</td><td>",
  17013. "<input data-dojo-type='dijit.form.ValidationTextBox' required='true' id='${id}_textInput' " +
  17014. "name='textInput' data-dojo-props='intermediateChanges:true'/>",
  17015. "</td></tr><tr><td>",
  17016. "<label for='${id}_targetSelect'>${target}</label>",
  17017. "</td><td>",
  17018. "<select id='${id}_targetSelect' name='targetSelect' data-dojo-type='dijit.form.Select'>",
  17019. "<option selected='selected' value='_self'>${currentWindow}</option>",
  17020. "<option value='_blank'>${newWindow}</option>",
  17021. "<option value='_top'>${topWindow}</option>",
  17022. "<option value='_parent'>${parentWindow}</option>",
  17023. "</select>",
  17024. "</td></tr><tr><td colspan='2'>",
  17025. "<button data-dojo-type='dijit.form.Button' type='submit' id='${id}_setButton'>${set}</button>",
  17026. "<button data-dojo-type='dijit.form.Button' type='button' id='${id}_cancelButton'>${buttonCancel}</button>",
  17027. "</td></tr></table>"
  17028. ].join(""),
  17029. _initButton: function(){
  17030. this.inherited(arguments);
  17031. // Setup to lazy create TooltipDialog first time the button is clicked
  17032. this.button.loadDropDown = lang.hitch(this, "_loadDropDown");
  17033. this._connectTagEvents();
  17034. },
  17035. _loadDropDown: function(callback){
  17036. // Called the first time the button is pressed. Initialize TooltipDialog.
  17037. require([
  17038. "dojo/i18n", // i18n.getLocalization
  17039. "../../TooltipDialog",
  17040. "../../registry", // registry.byId, registry.getUniqueId
  17041. "../../form/Button", // used by template
  17042. "../../form/Select", // used by template
  17043. "../../form/ValidationTextBox", // used by template
  17044. "dojo/i18n!../../nls/common",
  17045. "dojo/i18n!../nls/LinkDialog"
  17046. ], lang.hitch(this, function(i18n, TooltipDialog, registry){
  17047. var _this = this;
  17048. this.tag = this.command == 'insertImage' ? 'img' : 'a';
  17049. var messages = lang.delegate(i18n.getLocalization("dijit", "common", this.lang),
  17050. i18n.getLocalization("dijit._editor", "LinkDialog", this.lang));
  17051. var dropDown = (this.dropDown = this.button.dropDown = new TooltipDialog({
  17052. title: messages[this.command + "Title"],
  17053. execute: lang.hitch(this, "setValue"),
  17054. onOpen: function(){
  17055. _this._onOpenDialog();
  17056. TooltipDialog.prototype.onOpen.apply(this, arguments);
  17057. },
  17058. onCancel: function(){
  17059. setTimeout(lang.hitch(_this, "_onCloseDialog"),0);
  17060. }
  17061. }));
  17062. messages.urlRegExp = this.urlRegExp;
  17063. messages.id = registry.getUniqueId(this.editor.id);
  17064. this._uniqueId = messages.id;
  17065. this._setContent(dropDown.title +
  17066. "<div style='border-bottom: 1px black solid;padding-bottom:2pt;margin-bottom:4pt'></div>" +
  17067. string.substitute(this.linkDialogTemplate, messages));
  17068. dropDown.startup();
  17069. this._urlInput = registry.byId(this._uniqueId + "_urlInput");
  17070. this._textInput = registry.byId(this._uniqueId + "_textInput");
  17071. this._setButton = registry.byId(this._uniqueId + "_setButton");
  17072. this.connect(registry.byId(this._uniqueId + "_cancelButton"), "onClick", function(){
  17073. this.dropDown.onCancel();
  17074. });
  17075. if(this._urlInput){
  17076. this.connect(this._urlInput, "onChange", "_checkAndFixInput");
  17077. }
  17078. if(this._textInput){
  17079. this.connect(this._textInput, "onChange", "_checkAndFixInput");
  17080. }
  17081. // Build up the dual check for http/https/file:, and mailto formats.
  17082. this._urlRegExp = new RegExp("^" + this.urlRegExp + "$", "i");
  17083. this._emailRegExp = new RegExp("^" + this.emailRegExp + "$", "i");
  17084. this._urlInput.isValid = lang.hitch(this, function(){
  17085. // Function over-ride of isValid to test if the input matches a url or a mailto style link.
  17086. var value = this._urlInput.get("value");
  17087. return this._urlRegExp.test(value) || this._emailRegExp.test(value);
  17088. });
  17089. // Listen for enter and execute if valid.
  17090. this.connect(dropDown.domNode, "onkeypress", function(e){
  17091. if(e && e.charOrCode == keys.ENTER &&
  17092. !e.shiftKey && !e.metaKey && !e.ctrlKey && !e.altKey){
  17093. if(!this._setButton.get("disabled")){
  17094. dropDown.onExecute();
  17095. dropDown.execute(dropDown.get('value'));
  17096. }
  17097. }
  17098. });
  17099. callback();
  17100. }));
  17101. },
  17102. _checkAndFixInput: function(){
  17103. // summary:
  17104. // A function to listen for onChange events and test the input contents
  17105. // for valid information, such as valid urls with http/https/ftp and if
  17106. // not present, try and guess if the input url is relative or not, and if
  17107. // not, append http:// to it. Also validates other fields as determined by
  17108. // the internal _isValid function.
  17109. var self = this;
  17110. var url = this._urlInput.get("value");
  17111. var fixupUrl = function(url){
  17112. var appendHttp = false;
  17113. var appendMailto = false;
  17114. if(url && url.length > 1){
  17115. url = lang.trim(url);
  17116. if(url.indexOf("mailto:") !== 0){
  17117. if(url.indexOf("/") > 0){
  17118. if(url.indexOf("://") === -1){
  17119. // Check that it doesn't start with / or ./, which would
  17120. // imply 'target server relativeness'
  17121. if(url.charAt(0) !== '/' && url.indexOf("./") !== 0){
  17122. if(self._hostRxp.test(url)){
  17123. appendHttp = true;
  17124. }
  17125. }
  17126. }
  17127. }else if(self._userAtRxp.test(url)){
  17128. // If it looks like a foo@, append a mailto.
  17129. appendMailto = true;
  17130. }
  17131. }
  17132. }
  17133. if(appendHttp){
  17134. self._urlInput.set("value", "http://" + url);
  17135. }
  17136. if(appendMailto){
  17137. self._urlInput.set("value", "mailto:" + url);
  17138. }
  17139. self._setButton.set("disabled", !self._isValid());
  17140. };
  17141. if(this._delayedCheck){
  17142. clearTimeout(this._delayedCheck);
  17143. this._delayedCheck = null;
  17144. }
  17145. this._delayedCheck = setTimeout(function(){
  17146. fixupUrl(url);
  17147. }, 250);
  17148. },
  17149. _connectTagEvents: function(){
  17150. // summary:
  17151. // Over-ridable function that connects tag specific events.
  17152. this.editor.onLoadDeferred.addCallback(lang.hitch(this, function(){
  17153. this.connect(this.editor.editNode, "ondblclick", this._onDblClick);
  17154. }));
  17155. },
  17156. _isValid: function(){
  17157. // summary:
  17158. // Internal function to allow validating of the inputs
  17159. // for a link to determine if set should be disabled or not
  17160. // tags:
  17161. // protected
  17162. return this._urlInput.isValid() && this._textInput.isValid();
  17163. },
  17164. _setContent: function(staticPanel){
  17165. // summary:
  17166. // Helper for _initButton above. Not sure why it's a separate method.
  17167. this.dropDown.set({
  17168. parserScope: "dojo", // make parser search for dojoType/data-dojo-type even if page is multi-version
  17169. content: staticPanel
  17170. });
  17171. },
  17172. _checkValues: function(args){
  17173. // summary:
  17174. // Function to check the values in args and 'fix' them up as needed.
  17175. // args: Object
  17176. // Content being set.
  17177. // tags:
  17178. // protected
  17179. if(args && args.urlInput){
  17180. args.urlInput = args.urlInput.replace(/"/g, "&quot;");
  17181. }
  17182. return args;
  17183. },
  17184. setValue: function(args){
  17185. // summary:
  17186. // Callback from the dialog when user presses "set" button.
  17187. // tags:
  17188. // private
  17189. //TODO: prevent closing popup if the text is empty
  17190. this._onCloseDialog();
  17191. if(has("ie") < 9){ //see #4151
  17192. var sel = rangeapi.getSelection(this.editor.window);
  17193. var range = sel.getRangeAt(0);
  17194. var a = range.endContainer;
  17195. if(a.nodeType === 3){
  17196. // Text node, may be the link contents, so check parent.
  17197. // This plugin doesn't really support nested HTML elements
  17198. // in the link, it assumes all link content is text.
  17199. a = a.parentNode;
  17200. }
  17201. if(a && (a.nodeName && a.nodeName.toLowerCase() !== this.tag)){
  17202. // Still nothing, one last thing to try on IE, as it might be 'img'
  17203. // and thus considered a control.
  17204. a = win.withGlobal(this.editor.window,
  17205. "getSelectedElement", selectionapi, [this.tag]);
  17206. }
  17207. if(a && (a.nodeName && a.nodeName.toLowerCase() === this.tag)){
  17208. // Okay, we do have a match. IE, for some reason, sometimes pastes before
  17209. // instead of removing the targeted paste-over element, so we unlink the
  17210. // old one first. If we do not the <a> tag remains, but it has no content,
  17211. // so isn't readily visible (but is wrong for the action).
  17212. if(this.editor.queryCommandEnabled("unlink")){
  17213. // Select all the link children, then unlink. The following insert will
  17214. // then replace the selected text.
  17215. win.withGlobal(this.editor.window,
  17216. "selectElementChildren", selectionapi, [a]);
  17217. this.editor.execCommand("unlink");
  17218. }
  17219. }
  17220. }
  17221. // make sure values are properly escaped, etc.
  17222. args = this._checkValues(args);
  17223. this.editor.execCommand('inserthtml',
  17224. string.substitute(this.htmlTemplate, args));
  17225. // IE sometimes leaves a blank link, so we need to fix it up.
  17226. // Go ahead and do this for everyone just to avoid blank links
  17227. // in the page.
  17228. query("a", this.editor.document).forEach(function(a){
  17229. if(!a.innerHTML && !domAttr.has(a, "name")){
  17230. // Remove empty anchors that do not have "name" set.
  17231. // Empty ones with a name set could be a hidden hash
  17232. // anchor.
  17233. a.parentNode.removeChild(a);
  17234. }
  17235. }, this);
  17236. },
  17237. _onCloseDialog: function(){
  17238. // summary:
  17239. // Handler for close event on the dialog
  17240. if(this.editor.focused){
  17241. // put focus back in the edit area, unless the dialog closed because the user clicked somewhere else
  17242. this.editor.focus();
  17243. }
  17244. },
  17245. _getCurrentValues: function(a){
  17246. // summary:
  17247. // Over-ride for getting the values to set in the dropdown.
  17248. // a:
  17249. // The anchor/link to process for data for the dropdown.
  17250. // tags:
  17251. // protected
  17252. var url, text, target;
  17253. if(a && a.tagName.toLowerCase() === this.tag){
  17254. url = a.getAttribute('_djrealurl') || a.getAttribute('href');
  17255. target = a.getAttribute('target') || "_self";
  17256. text = a.textContent || a.innerText;
  17257. win.withGlobal(this.editor.window, "selectElement", selectionapi, [a, true]);
  17258. }else{
  17259. text = win.withGlobal(this.editor.window, selectionapi.getSelectedText);
  17260. }
  17261. return {urlInput: url || '', textInput: text || '', targetSelect: target || ''}; //Object;
  17262. },
  17263. _onOpenDialog: function(){
  17264. // summary:
  17265. // Handler for when the dialog is opened.
  17266. // If the caret is currently in a URL then populate the URL's info into the dialog.
  17267. var a;
  17268. if(has("ie") < 9){
  17269. // IE is difficult to select the element in, using the range unified
  17270. // API seems to work reasonably well.
  17271. var sel = rangeapi.getSelection(this.editor.window);
  17272. var range = sel.getRangeAt(0);
  17273. a = range.endContainer;
  17274. if(a.nodeType === 3){
  17275. // Text node, may be the link contents, so check parent.
  17276. // This plugin doesn't really support nested HTML elements
  17277. // in the link, it assumes all link content is text.
  17278. a = a.parentNode;
  17279. }
  17280. if(a && (a.nodeName && a.nodeName.toLowerCase() !== this.tag)){
  17281. // Still nothing, one last thing to try on IE, as it might be 'img'
  17282. // and thus considered a control.
  17283. a = win.withGlobal(this.editor.window,
  17284. "getSelectedElement", selectionapi, [this.tag]);
  17285. }
  17286. }else{
  17287. a = win.withGlobal(this.editor.window,
  17288. "getAncestorElement", selectionapi, [this.tag]);
  17289. }
  17290. this.dropDown.reset();
  17291. this._setButton.set("disabled", true);
  17292. this.dropDown.set("value", this._getCurrentValues(a));
  17293. },
  17294. _onDblClick: function(e){
  17295. // summary:
  17296. // Function to define a behavior on double clicks on the element
  17297. // type this dialog edits to select it and pop up the editor
  17298. // dialog.
  17299. // e: Object
  17300. // The double-click event.
  17301. // tags:
  17302. // protected.
  17303. if(e && e.target){
  17304. var t = e.target;
  17305. var tg = t.tagName? t.tagName.toLowerCase() : "";
  17306. if(tg === this.tag && domAttr.get(t,"href")){
  17307. var editor = this.editor;
  17308. win.withGlobal(editor.window,
  17309. "selectElement",
  17310. selectionapi, [t]);
  17311. editor.onDisplayChanged();
  17312. // Call onNormalizedDisplayChange() now, rather than on timer.
  17313. // On IE, when focus goes to the first <input> in the TooltipDialog, the editor loses it's selection.
  17314. // Later if onNormalizedDisplayChange() gets called via the timer it will disable the LinkDialog button
  17315. // (actually, all the toolbar buttons), at which point clicking the <input> will close the dialog,
  17316. // since (for unknown reasons) focus.js ignores disabled controls.
  17317. if(editor._updateTimer){
  17318. clearTimeout(editor._updateTimer);
  17319. delete editor._updateTimer;
  17320. }
  17321. editor.onNormalizedDisplayChanged();
  17322. var button = this.button;
  17323. setTimeout(function(){
  17324. // Focus shift outside the event handler.
  17325. // IE doesn't like focus changes in event handles.
  17326. button.set("disabled", false);
  17327. button.loadAndOpenDropDown().then(function(){
  17328. if(button.dropDown.focus){
  17329. button.dropDown.focus();
  17330. }
  17331. });
  17332. }, 10);
  17333. }
  17334. }
  17335. }
  17336. });
  17337. var ImgLinkDialog = declare("dijit._editor.plugins.ImgLinkDialog", [LinkDialog], {
  17338. // summary:
  17339. // This plugin extends LinkDialog and adds in a plugin for handling image links.
  17340. // provides the image link dialog.
  17341. //
  17342. // description:
  17343. // The command provided by this plugin is:
  17344. // * insertImage
  17345. // linkDialogTemplate: [protected] String
  17346. // Over-ride for template since img dialog doesn't need target that anchor tags may.
  17347. linkDialogTemplate: [
  17348. "<table><tr><td>",
  17349. "<label for='${id}_urlInput'>${url}</label>",
  17350. "</td><td>",
  17351. "<input dojoType='dijit.form.ValidationTextBox' regExp='${urlRegExp}' " +
  17352. "required='true' id='${id}_urlInput' name='urlInput' data-dojo-props='intermediateChanges:true'/>",
  17353. "</td></tr><tr><td>",
  17354. "<label for='${id}_textInput'>${text}</label>",
  17355. "</td><td>",
  17356. "<input data-dojo-type='dijit.form.ValidationTextBox' required='false' id='${id}_textInput' " +
  17357. "name='textInput' data-dojo-props='intermediateChanges:true'/>",
  17358. "</td></tr><tr><td>",
  17359. "</td><td>",
  17360. "</td></tr><tr><td colspan='2'>",
  17361. "<button data-dojo-type='dijit.form.Button' type='submit' id='${id}_setButton'>${set}</button>",
  17362. "<button data-dojo-type='dijit.form.Button' type='button' id='${id}_cancelButton'>${buttonCancel}</button>",
  17363. "</td></tr></table>"
  17364. ].join(""),
  17365. // htmlTemplate: [protected] String
  17366. // String used for templating the <img> HTML to insert at the desired point.
  17367. htmlTemplate: "<img src=\"${urlInput}\" _djrealurl=\"${urlInput}\" alt=\"${textInput}\" />",
  17368. // tag: [protected] String
  17369. // Tag used for the link type (img).
  17370. tag: "img",
  17371. _getCurrentValues: function(img){
  17372. // summary:
  17373. // Over-ride for getting the values to set in the dropdown.
  17374. // a:
  17375. // The anchor/link to process for data for the dropdown.
  17376. // tags:
  17377. // protected
  17378. var url, text;
  17379. if(img && img.tagName.toLowerCase() === this.tag){
  17380. url = img.getAttribute('_djrealurl') || img.getAttribute('src');
  17381. text = img.getAttribute('alt');
  17382. win.withGlobal(this.editor.window,
  17383. "selectElement", selectionapi, [img, true]);
  17384. }else{
  17385. text = win.withGlobal(this.editor.window, selectionapi.getSelectedText);
  17386. }
  17387. return {urlInput: url || '', textInput: text || ''}; //Object;
  17388. },
  17389. _isValid: function(){
  17390. // summary:
  17391. // Over-ride for images. You can have alt text of blank, it is valid.
  17392. // tags:
  17393. // protected
  17394. return this._urlInput.isValid();
  17395. },
  17396. _connectTagEvents: function(){
  17397. // summary:
  17398. // Over-ridable function that connects tag specific events.
  17399. this.inherited(arguments);
  17400. this.editor.onLoadDeferred.addCallback(lang.hitch(this, function(){
  17401. // Use onmousedown instead of onclick. Seems that IE eats the first onclick
  17402. // to wrap it in a selector box, then the second one acts as onclick. See #10420
  17403. this.connect(this.editor.editNode, "onmousedown", this._selectTag);
  17404. }));
  17405. },
  17406. _selectTag: function(e){
  17407. // summary:
  17408. // A simple event handler that lets me select an image if it is clicked on.
  17409. // makes it easier to select images in a standard way across browsers. Otherwise
  17410. // selecting an image for edit becomes difficult.
  17411. // e: Event
  17412. // The mousedown event.
  17413. // tags:
  17414. // private
  17415. if(e && e.target){
  17416. var t = e.target;
  17417. var tg = t.tagName? t.tagName.toLowerCase() : "";
  17418. if(tg === this.tag){
  17419. win.withGlobal(this.editor.window,
  17420. "selectElement",
  17421. selectionapi, [t]);
  17422. }
  17423. }
  17424. },
  17425. _checkValues: function(args){
  17426. // summary:
  17427. // Function to check the values in args and 'fix' them up as needed
  17428. // (special characters in the url or alt text)
  17429. // args: Object
  17430. // Content being set.
  17431. // tags:
  17432. // protected
  17433. if(args && args.urlInput){
  17434. args.urlInput = args.urlInput.replace(/"/g, "&quot;");
  17435. }
  17436. if(args && args.textInput){
  17437. args.textInput = args.textInput.replace(/"/g, "&quot;");
  17438. }
  17439. return args;
  17440. },
  17441. _onDblClick: function(e){
  17442. // summary:
  17443. // Function to define a behavior on double clicks on the element
  17444. // type this dialog edits to select it and pop up the editor
  17445. // dialog.
  17446. // e: Object
  17447. // The double-click event.
  17448. // tags:
  17449. // protected.
  17450. if(e && e.target){
  17451. var t = e.target;
  17452. var tg = t.tagName ? t.tagName.toLowerCase() : "";
  17453. if(tg === this.tag && domAttr.get(t,"src")){
  17454. var editor = this.editor;
  17455. win.withGlobal(editor.window,
  17456. "selectElement",
  17457. selectionapi, [t]);
  17458. editor.onDisplayChanged();
  17459. // Call onNormalizedDisplayChange() now, rather than on timer.
  17460. // On IE, when focus goes to the first <input> in the TooltipDialog, the editor loses it's selection.
  17461. // Later if onNormalizedDisplayChange() gets called via the timer it will disable the LinkDialog button
  17462. // (actually, all the toolbar buttons), at which point clicking the <input> will close the dialog,
  17463. // since (for unknown reasons) focus.js ignores disabled controls.
  17464. if(editor._updateTimer){
  17465. clearTimeout(editor._updateTimer);
  17466. delete editor._updateTimer;
  17467. }
  17468. editor.onNormalizedDisplayChanged();
  17469. var button = this.button;
  17470. setTimeout(function(){
  17471. // Focus shift outside the event handler.
  17472. // IE doesn't like focus changes in event handles.
  17473. button.set("disabled", false);
  17474. button.loadAndOpenDropDown().then(function(){
  17475. if(button.dropDown.focus){
  17476. button.dropDown.focus();
  17477. }
  17478. });
  17479. }, 10);
  17480. }
  17481. }
  17482. }
  17483. });
  17484. // Register these plugins
  17485. _Plugin.registry["createLink"] = function(){
  17486. return new LinkDialog({command: "createLink"});
  17487. };
  17488. _Plugin.registry["insertImage"] = function(){
  17489. return new ImgLinkDialog({command: "insertImage"});
  17490. };
  17491. // Export both LinkDialog and ImgLinkDialog
  17492. LinkDialog.ImgLinkDialog = ImgLinkDialog;
  17493. return LinkDialog;
  17494. });
  17495. },
  17496. 'dijit/DropDownMenu':function(){
  17497. define([
  17498. "dojo/_base/declare", // declare
  17499. "dojo/_base/event", // event.stop
  17500. "dojo/keys", // keys
  17501. "dojo/text!./templates/Menu.html",
  17502. "./_OnDijitClickMixin",
  17503. "./_MenuBase"
  17504. ], function(declare, event, keys, template, _OnDijitClickMixin, _MenuBase){
  17505. /*=====
  17506. var _MenuBase = dijit._MenuBase;
  17507. var _OnDijitClickMixin = dijit._OnDijitClickMixin;
  17508. =====*/
  17509. // module:
  17510. // dijit/DropDownMenu
  17511. // summary:
  17512. // dijit.DropDownMenu widget
  17513. return declare("dijit.DropDownMenu", [_MenuBase, _OnDijitClickMixin], {
  17514. // summary:
  17515. // A menu, without features for context menu (Meaning, drop down menu)
  17516. templateString: template,
  17517. baseClass: "dijitMenu",
  17518. postCreate: function(){
  17519. var l = this.isLeftToRight();
  17520. this._openSubMenuKey = l ? keys.RIGHT_ARROW : keys.LEFT_ARROW;
  17521. this._closeSubMenuKey = l ? keys.LEFT_ARROW : keys.RIGHT_ARROW;
  17522. this.connectKeyNavHandlers([keys.UP_ARROW], [keys.DOWN_ARROW]);
  17523. },
  17524. _onKeyPress: function(/*Event*/ evt){
  17525. // summary:
  17526. // Handle keyboard based menu navigation.
  17527. // tags:
  17528. // protected
  17529. if(evt.ctrlKey || evt.altKey){ return; }
  17530. switch(evt.charOrCode){
  17531. case this._openSubMenuKey:
  17532. this._moveToPopup(evt);
  17533. event.stop(evt);
  17534. break;
  17535. case this._closeSubMenuKey:
  17536. if(this.parentMenu){
  17537. if(this.parentMenu._isMenuBar){
  17538. this.parentMenu.focusPrev();
  17539. }else{
  17540. this.onCancel(false);
  17541. }
  17542. }else{
  17543. event.stop(evt);
  17544. }
  17545. break;
  17546. }
  17547. }
  17548. });
  17549. });
  17550. },
  17551. 'dijit/Menu':function(){
  17552. define("dijit/Menu", [
  17553. "require",
  17554. "dojo/_base/array", // array.forEach
  17555. "dojo/_base/declare", // declare
  17556. "dojo/_base/event", // event.stop
  17557. "dojo/dom", // dom.byId dom.isDescendant
  17558. "dojo/dom-attr", // domAttr.get domAttr.set domAttr.has domAttr.remove
  17559. "dojo/dom-geometry", // domStyle.getComputedStyle domGeometry.position
  17560. "dojo/dom-style", // domStyle.getComputedStyle
  17561. "dojo/_base/kernel",
  17562. "dojo/keys", // keys.F10
  17563. "dojo/_base/lang", // lang.hitch
  17564. "dojo/on",
  17565. "dojo/_base/sniff", // has("ie"), has("quirks")
  17566. "dojo/_base/window", // win.body win.doc.documentElement win.doc.frames win.withGlobal
  17567. "dojo/window", // winUtils.get
  17568. "./popup",
  17569. "./DropDownMenu",
  17570. "dojo/ready"
  17571. ], function(require, array, declare, event, dom, domAttr, domGeometry, domStyle, kernel, keys, lang, on,
  17572. has, win, winUtils, pm, DropDownMenu, ready){
  17573. /*=====
  17574. var DropDownMenu = dijit.DropDownMenu;
  17575. =====*/
  17576. // module:
  17577. // dijit/Menu
  17578. // summary:
  17579. // Includes dijit.Menu widget and base class dijit._MenuBase
  17580. // Back compat w/1.6, remove for 2.0
  17581. if(!kernel.isAsync){
  17582. ready(0, function(){
  17583. var requires = ["dijit/MenuItem", "dijit/PopupMenuItem", "dijit/CheckedMenuItem", "dijit/MenuSeparator"];
  17584. require(requires); // use indirection so modules not rolled into a build
  17585. });
  17586. }
  17587. return declare("dijit.Menu", DropDownMenu, {
  17588. // summary:
  17589. // A context menu you can assign to multiple elements
  17590. constructor: function(){
  17591. this._bindings = [];
  17592. },
  17593. // targetNodeIds: [const] String[]
  17594. // Array of dom node ids of nodes to attach to.
  17595. // Fill this with nodeIds upon widget creation and it becomes context menu for those nodes.
  17596. targetNodeIds: [],
  17597. // contextMenuForWindow: [const] Boolean
  17598. // If true, right clicking anywhere on the window will cause this context menu to open.
  17599. // If false, must specify targetNodeIds.
  17600. contextMenuForWindow: false,
  17601. // leftClickToOpen: [const] Boolean
  17602. // If true, menu will open on left click instead of right click, similar to a file menu.
  17603. leftClickToOpen: false,
  17604. // refocus: Boolean
  17605. // When this menu closes, re-focus the element which had focus before it was opened.
  17606. refocus: true,
  17607. postCreate: function(){
  17608. if(this.contextMenuForWindow){
  17609. this.bindDomNode(win.body());
  17610. }else{
  17611. // TODO: should have _setTargetNodeIds() method to handle initialization and a possible
  17612. // later set('targetNodeIds', ...) call. There's also a problem that targetNodeIds[]
  17613. // gets stale after calls to bindDomNode()/unBindDomNode() as it still is just the original list (see #9610)
  17614. array.forEach(this.targetNodeIds, this.bindDomNode, this);
  17615. }
  17616. this.inherited(arguments);
  17617. },
  17618. // thanks burstlib!
  17619. _iframeContentWindow: function(/* HTMLIFrameElement */iframe_el){
  17620. // summary:
  17621. // Returns the window reference of the passed iframe
  17622. // tags:
  17623. // private
  17624. return winUtils.get(this._iframeContentDocument(iframe_el)) ||
  17625. // Moz. TODO: is this available when defaultView isn't?
  17626. this._iframeContentDocument(iframe_el)['__parent__'] ||
  17627. (iframe_el.name && win.doc.frames[iframe_el.name]) || null; // Window
  17628. },
  17629. _iframeContentDocument: function(/* HTMLIFrameElement */iframe_el){
  17630. // summary:
  17631. // Returns a reference to the document object inside iframe_el
  17632. // tags:
  17633. // protected
  17634. return iframe_el.contentDocument // W3
  17635. || (iframe_el.contentWindow && iframe_el.contentWindow.document) // IE
  17636. || (iframe_el.name && win.doc.frames[iframe_el.name] && win.doc.frames[iframe_el.name].document)
  17637. || null; // HTMLDocument
  17638. },
  17639. bindDomNode: function(/*String|DomNode*/ node){
  17640. // summary:
  17641. // Attach menu to given node
  17642. node = dom.byId(node);
  17643. var cn; // Connect node
  17644. // Support context menus on iframes. Rather than binding to the iframe itself we need
  17645. // to bind to the <body> node inside the iframe.
  17646. if(node.tagName.toLowerCase() == "iframe"){
  17647. var iframe = node,
  17648. window = this._iframeContentWindow(iframe);
  17649. cn = win.withGlobal(window, win.body);
  17650. }else{
  17651. // To capture these events at the top level, attach to <html>, not <body>.
  17652. // Otherwise right-click context menu just doesn't work.
  17653. cn = (node == win.body() ? win.doc.documentElement : node);
  17654. }
  17655. // "binding" is the object to track our connection to the node (ie, the parameter to bindDomNode())
  17656. var binding = {
  17657. node: node,
  17658. iframe: iframe
  17659. };
  17660. // Save info about binding in _bindings[], and make node itself record index(+1) into
  17661. // _bindings[] array. Prefix w/_dijitMenu to avoid setting an attribute that may
  17662. // start with a number, which fails on FF/safari.
  17663. domAttr.set(node, "_dijitMenu" + this.id, this._bindings.push(binding));
  17664. // Setup the connections to monitor click etc., unless we are connecting to an iframe which hasn't finished
  17665. // loading yet, in which case we need to wait for the onload event first, and then connect
  17666. // On linux Shift-F10 produces the oncontextmenu event, but on Windows it doesn't, so
  17667. // we need to monitor keyboard events in addition to the oncontextmenu event.
  17668. var doConnects = lang.hitch(this, function(cn){
  17669. return [
  17670. // TODO: when leftClickToOpen is true then shouldn't space/enter key trigger the menu,
  17671. // rather than shift-F10?
  17672. on(cn, this.leftClickToOpen ? "click" : "contextmenu", lang.hitch(this, function(evt){
  17673. // Schedule context menu to be opened unless it's already been scheduled from onkeydown handler
  17674. event.stop(evt);
  17675. this._scheduleOpen(evt.target, iframe, {x: evt.pageX, y: evt.pageY});
  17676. })),
  17677. on(cn, "keydown", lang.hitch(this, function(evt){
  17678. if(evt.shiftKey && evt.keyCode == keys.F10){
  17679. event.stop(evt);
  17680. this._scheduleOpen(evt.target, iframe); // no coords - open near target node
  17681. }
  17682. }))
  17683. ];
  17684. });
  17685. binding.connects = cn ? doConnects(cn) : [];
  17686. if(iframe){
  17687. // Setup handler to [re]bind to the iframe when the contents are initially loaded,
  17688. // and every time the contents change.
  17689. // Need to do this b/c we are actually binding to the iframe's <body> node.
  17690. // Note: can't use connect.connect(), see #9609.
  17691. binding.onloadHandler = lang.hitch(this, function(){
  17692. // want to remove old connections, but IE throws exceptions when trying to
  17693. // access the <body> node because it's already gone, or at least in a state of limbo
  17694. var window = this._iframeContentWindow(iframe);
  17695. cn = win.withGlobal(window, win.body);
  17696. binding.connects = doConnects(cn);
  17697. });
  17698. if(iframe.addEventListener){
  17699. iframe.addEventListener("load", binding.onloadHandler, false);
  17700. }else{
  17701. iframe.attachEvent("onload", binding.onloadHandler);
  17702. }
  17703. }
  17704. },
  17705. unBindDomNode: function(/*String|DomNode*/ nodeName){
  17706. // summary:
  17707. // Detach menu from given node
  17708. var node;
  17709. try{
  17710. node = dom.byId(nodeName);
  17711. }catch(e){
  17712. // On IE the dom.byId() call will get an exception if the attach point was
  17713. // the <body> node of an <iframe> that has since been reloaded (and thus the
  17714. // <body> node is in a limbo state of destruction.
  17715. return;
  17716. }
  17717. // node["_dijitMenu" + this.id] contains index(+1) into my _bindings[] array
  17718. var attrName = "_dijitMenu" + this.id;
  17719. if(node && domAttr.has(node, attrName)){
  17720. var bid = domAttr.get(node, attrName)-1, b = this._bindings[bid], h;
  17721. while(h = b.connects.pop()){
  17722. h.remove();
  17723. }
  17724. // Remove listener for iframe onload events
  17725. var iframe = b.iframe;
  17726. if(iframe){
  17727. if(iframe.removeEventListener){
  17728. iframe.removeEventListener("load", b.onloadHandler, false);
  17729. }else{
  17730. iframe.detachEvent("onload", b.onloadHandler);
  17731. }
  17732. }
  17733. domAttr.remove(node, attrName);
  17734. delete this._bindings[bid];
  17735. }
  17736. },
  17737. _scheduleOpen: function(/*DomNode?*/ target, /*DomNode?*/ iframe, /*Object?*/ coords){
  17738. // summary:
  17739. // Set timer to display myself. Using a timer rather than displaying immediately solves
  17740. // two problems:
  17741. //
  17742. // 1. IE: without the delay, focus work in "open" causes the system
  17743. // context menu to appear in spite of stopEvent.
  17744. //
  17745. // 2. Avoid double-shows on linux, where shift-F10 generates an oncontextmenu event
  17746. // even after a event.stop(e). (Shift-F10 on windows doesn't generate the
  17747. // oncontextmenu event.)
  17748. if(!this._openTimer){
  17749. this._openTimer = setTimeout(lang.hitch(this, function(){
  17750. delete this._openTimer;
  17751. this._openMyself({
  17752. target: target,
  17753. iframe: iframe,
  17754. coords: coords
  17755. });
  17756. }), 1);
  17757. }
  17758. },
  17759. _openMyself: function(args){
  17760. // summary:
  17761. // Internal function for opening myself when the user does a right-click or something similar.
  17762. // args:
  17763. // This is an Object containing:
  17764. // * target:
  17765. // The node that is being clicked
  17766. // * iframe:
  17767. // If an <iframe> is being clicked, iframe points to that iframe
  17768. // * coords:
  17769. // Put menu at specified x/y position in viewport, or if iframe is
  17770. // specified, then relative to iframe.
  17771. //
  17772. // _openMyself() formerly took the event object, and since various code references
  17773. // evt.target (after connecting to _openMyself()), using an Object for parameters
  17774. // (so that old code still works).
  17775. var target = args.target,
  17776. iframe = args.iframe,
  17777. coords = args.coords;
  17778. // Get coordinates to open menu, either at specified (mouse) position or (if triggered via keyboard)
  17779. // then near the node the menu is assigned to.
  17780. if(coords){
  17781. if(iframe){
  17782. // Specified coordinates are on <body> node of an <iframe>, convert to match main document
  17783. var ifc = domGeometry.position(iframe, true),
  17784. window = this._iframeContentWindow(iframe),
  17785. scroll = win.withGlobal(window, "_docScroll", dojo);
  17786. var cs = domStyle.getComputedStyle(iframe),
  17787. tp = domStyle.toPixelValue,
  17788. left = (has("ie") && has("quirks") ? 0 : tp(iframe, cs.paddingLeft)) + (has("ie") && has("quirks") ? tp(iframe, cs.borderLeftWidth) : 0),
  17789. top = (has("ie") && has("quirks") ? 0 : tp(iframe, cs.paddingTop)) + (has("ie") && has("quirks") ? tp(iframe, cs.borderTopWidth) : 0);
  17790. coords.x += ifc.x + left - scroll.x;
  17791. coords.y += ifc.y + top - scroll.y;
  17792. }
  17793. }else{
  17794. coords = domGeometry.position(target, true);
  17795. coords.x += 10;
  17796. coords.y += 10;
  17797. }
  17798. var self=this;
  17799. var prevFocusNode = this._focusManager.get("prevNode");
  17800. var curFocusNode = this._focusManager.get("curNode");
  17801. var savedFocusNode = !curFocusNode || (dom.isDescendant(curFocusNode, this.domNode)) ? prevFocusNode : curFocusNode;
  17802. function closeAndRestoreFocus(){
  17803. // user has clicked on a menu or popup
  17804. if(self.refocus && savedFocusNode){
  17805. savedFocusNode.focus();
  17806. }
  17807. pm.close(self);
  17808. }
  17809. pm.open({
  17810. popup: this,
  17811. x: coords.x,
  17812. y: coords.y,
  17813. onExecute: closeAndRestoreFocus,
  17814. onCancel: closeAndRestoreFocus,
  17815. orient: this.isLeftToRight() ? 'L' : 'R'
  17816. });
  17817. this.focus();
  17818. this._onBlur = function(){
  17819. this.inherited('_onBlur', arguments);
  17820. // Usually the parent closes the child widget but if this is a context
  17821. // menu then there is no parent
  17822. pm.close(this);
  17823. // don't try to restore focus; user has clicked another part of the screen
  17824. // and set focus there
  17825. };
  17826. },
  17827. uninitialize: function(){
  17828. array.forEach(this._bindings, function(b){ if(b){ this.unBindDomNode(b.node); } }, this);
  17829. this.inherited(arguments);
  17830. }
  17831. });
  17832. });
  17833. },
  17834. 'dijit/form/_CheckBoxMixin':function(){
  17835. define([
  17836. "dojo/_base/declare", // declare
  17837. "dojo/dom-attr", // domAttr.set
  17838. "dojo/_base/event" // event.stop
  17839. ], function(declare, domAttr, event){
  17840. // module:
  17841. // dijit/form/_CheckBoxMixin
  17842. // summary:
  17843. // Mixin to provide widget functionality corresponding to an HTML checkbox
  17844. return declare("dijit.form._CheckBoxMixin", null, {
  17845. // summary:
  17846. // Mixin to provide widget functionality corresponding to an HTML checkbox
  17847. //
  17848. // description:
  17849. // User interacts with real html inputs.
  17850. // On onclick (which occurs by mouse click, space-bar, or
  17851. // using the arrow keys to switch the selected radio button),
  17852. // we update the state of the checkbox/radio.
  17853. //
  17854. // type: [private] String
  17855. // type attribute on <input> node.
  17856. // Overrides `dijit.form.Button.type`. Users should not change this value.
  17857. type: "checkbox",
  17858. // value: String
  17859. // As an initialization parameter, equivalent to value field on normal checkbox
  17860. // (if checked, the value is passed as the value when form is submitted).
  17861. value: "on",
  17862. // readOnly: Boolean
  17863. // Should this widget respond to user input?
  17864. // In markup, this is specified as "readOnly".
  17865. // Similar to disabled except readOnly form values are submitted.
  17866. readOnly: false,
  17867. // aria-pressed for toggle buttons, and aria-checked for checkboxes
  17868. _aria_attr: "aria-checked",
  17869. _setReadOnlyAttr: function(/*Boolean*/ value){
  17870. this._set("readOnly", value);
  17871. domAttr.set(this.focusNode, 'readOnly', value);
  17872. },
  17873. // Override dijit.form.Button._setLabelAttr() since we don't even have a containerNode.
  17874. // Normally users won't try to set label, except when CheckBox or RadioButton is the child of a dojox.layout.TabContainer
  17875. _setLabelAttr: undefined,
  17876. postMixInProperties: function(){
  17877. if(this.value == ""){
  17878. this.value = "on";
  17879. }
  17880. this.inherited(arguments);
  17881. },
  17882. reset: function(){
  17883. this.inherited(arguments);
  17884. // Handle unlikely event that the <input type=checkbox> value attribute has changed
  17885. this._set("value", this.params.value || "on");
  17886. domAttr.set(this.focusNode, 'value', this.value);
  17887. },
  17888. _onClick: function(/*Event*/ e){
  17889. // summary:
  17890. // Internal function to handle click actions - need to check
  17891. // readOnly, since button no longer does that check.
  17892. if(this.readOnly){
  17893. event.stop(e);
  17894. return false;
  17895. }
  17896. return this.inherited(arguments);
  17897. }
  17898. });
  17899. });
  17900. },
  17901. 'dijit/layout/ContentPane':function(){
  17902. define([
  17903. "dojo/_base/kernel", // kernel.deprecated
  17904. "dojo/_base/lang", // lang.mixin lang.delegate lang.hitch lang.isFunction lang.isObject
  17905. "../_Widget",
  17906. "./_ContentPaneResizeMixin",
  17907. "dojo/string", // string.substitute
  17908. "dojo/html", // html._ContentSetter html._emptyNode
  17909. "dojo/i18n!../nls/loading",
  17910. "dojo/_base/array", // array.forEach
  17911. "dojo/_base/declare", // declare
  17912. "dojo/_base/Deferred", // Deferred
  17913. "dojo/dom", // dom.byId
  17914. "dojo/dom-attr", // domAttr.attr
  17915. "dojo/_base/window", // win.body win.doc.createDocumentFragment
  17916. "dojo/_base/xhr", // xhr.get
  17917. "dojo/i18n" // i18n.getLocalization
  17918. ], function(kernel, lang, _Widget, _ContentPaneResizeMixin, string, html, nlsLoading,
  17919. array, declare, Deferred, dom, domAttr, win, xhr, i18n){
  17920. /*=====
  17921. var _Widget = dijit._Widget;
  17922. var _ContentPaneResizeMixin = dijit.layout._ContentPaneResizeMixin;
  17923. =====*/
  17924. // module:
  17925. // dijit/layout/ContentPane
  17926. // summary:
  17927. // A widget containing an HTML fragment, specified inline
  17928. // or by uri. Fragment may include widgets.
  17929. return declare("dijit.layout.ContentPane", [_Widget, _ContentPaneResizeMixin], {
  17930. // summary:
  17931. // A widget containing an HTML fragment, specified inline
  17932. // or by uri. Fragment may include widgets.
  17933. //
  17934. // description:
  17935. // This widget embeds a document fragment in the page, specified
  17936. // either by uri, javascript generated markup or DOM reference.
  17937. // Any widgets within this content are instantiated and managed,
  17938. // but laid out according to the HTML structure. Unlike IFRAME,
  17939. // ContentPane embeds a document fragment as would be found
  17940. // inside the BODY tag of a full HTML document. It should not
  17941. // contain the HTML, HEAD, or BODY tags.
  17942. // For more advanced functionality with scripts and
  17943. // stylesheets, see dojox.layout.ContentPane. This widget may be
  17944. // used stand alone or as a base class for other widgets.
  17945. // ContentPane is useful as a child of other layout containers
  17946. // such as BorderContainer or TabContainer, but note that those
  17947. // widgets can contain any widget as a child.
  17948. //
  17949. // example:
  17950. // Some quick samples:
  17951. // To change the innerHTML: cp.set('content', '<b>new content</b>')
  17952. //
  17953. // Or you can send it a NodeList: cp.set('content', dojo.query('div [class=selected]', userSelection))
  17954. //
  17955. // To do an ajax update: cp.set('href', url)
  17956. // href: String
  17957. // The href of the content that displays now.
  17958. // Set this at construction if you want to load data externally when the
  17959. // pane is shown. (Set preload=true to load it immediately.)
  17960. // Changing href after creation doesn't have any effect; Use set('href', ...);
  17961. href: "",
  17962. // content: String || DomNode || NodeList || dijit._Widget
  17963. // The innerHTML of the ContentPane.
  17964. // Note that the initialization parameter / argument to set("content", ...)
  17965. // can be a String, DomNode, Nodelist, or _Widget.
  17966. content: "",
  17967. // extractContent: Boolean
  17968. // Extract visible content from inside of <body> .... </body>.
  17969. // I.e., strip <html> and <head> (and it's contents) from the href
  17970. extractContent: false,
  17971. // parseOnLoad: Boolean
  17972. // Parse content and create the widgets, if any.
  17973. parseOnLoad: true,
  17974. // parserScope: String
  17975. // Flag passed to parser. Root for attribute names to search for. If scopeName is dojo,
  17976. // will search for data-dojo-type (or dojoType). For backwards compatibility
  17977. // reasons defaults to dojo._scopeName (which is "dojo" except when
  17978. // multi-version support is used, when it will be something like dojo16, dojo20, etc.)
  17979. parserScope: kernel._scopeName,
  17980. // preventCache: Boolean
  17981. // Prevent caching of data from href's by appending a timestamp to the href.
  17982. preventCache: false,
  17983. // preload: Boolean
  17984. // Force load of data on initialization even if pane is hidden.
  17985. preload: false,
  17986. // refreshOnShow: Boolean
  17987. // Refresh (re-download) content when pane goes from hidden to shown
  17988. refreshOnShow: false,
  17989. // loadingMessage: String
  17990. // Message that shows while downloading
  17991. loadingMessage: "<span class='dijitContentPaneLoading'><span class='dijitInline dijitIconLoading'></span>${loadingState}</span>",
  17992. // errorMessage: String
  17993. // Message that shows if an error occurs
  17994. errorMessage: "<span class='dijitContentPaneError'><span class='dijitInline dijitIconError'></span>${errorState}</span>",
  17995. // isLoaded: [readonly] Boolean
  17996. // True if the ContentPane has data in it, either specified
  17997. // during initialization (via href or inline content), or set
  17998. // via set('content', ...) / set('href', ...)
  17999. //
  18000. // False if it doesn't have any content, or if ContentPane is
  18001. // still in the process of downloading href.
  18002. isLoaded: false,
  18003. baseClass: "dijitContentPane",
  18004. /*======
  18005. // ioMethod: dojo.xhrGet|dojo.xhrPost
  18006. // Function that should grab the content specified via href.
  18007. ioMethod: dojo.xhrGet,
  18008. ======*/
  18009. // ioArgs: Object
  18010. // Parameters to pass to xhrGet() request, for example:
  18011. // | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="href: './bar', ioArgs: {timeout: 500}">
  18012. ioArgs: {},
  18013. // onLoadDeferred: [readonly] dojo.Deferred
  18014. // This is the `dojo.Deferred` returned by set('href', ...) and refresh().
  18015. // Calling onLoadDeferred.addCallback() or addErrback() registers your
  18016. // callback to be called only once, when the prior set('href', ...) call or
  18017. // the initial href parameter to the constructor finishes loading.
  18018. //
  18019. // This is different than an onLoad() handler which gets called any time any href
  18020. // or content is loaded.
  18021. onLoadDeferred: null,
  18022. // Cancel _WidgetBase's _setTitleAttr because we don't want the title attribute (used to specify
  18023. // tab labels) to be copied to ContentPane.domNode... otherwise a tooltip shows up over the
  18024. // entire pane.
  18025. _setTitleAttr: null,
  18026. // Flag to parser that I'll parse my contents, so it shouldn't.
  18027. stopParser: true,
  18028. // template: [private] Boolean
  18029. // Flag from the parser that this ContentPane is inside a template
  18030. // so the contents are pre-parsed.
  18031. // (TODO: this declaration can be commented out in 2.0)
  18032. template: false,
  18033. create: function(params, srcNodeRef){
  18034. // Convert a srcNodeRef argument into a content parameter, so that the original contents are
  18035. // processed in the same way as contents set via set("content", ...), calling the parser etc.
  18036. // Avoid modifying original params object since that breaks NodeList instantiation, see #11906.
  18037. if((!params || !params.template) && srcNodeRef && !("href" in params) && !("content" in params)){
  18038. var df = win.doc.createDocumentFragment();
  18039. srcNodeRef = dom.byId(srcNodeRef);
  18040. while(srcNodeRef.firstChild){
  18041. df.appendChild(srcNodeRef.firstChild);
  18042. }
  18043. params = lang.delegate(params, {content: df});
  18044. }
  18045. this.inherited(arguments, [params, srcNodeRef]);
  18046. },
  18047. postMixInProperties: function(){
  18048. this.inherited(arguments);
  18049. var messages = i18n.getLocalization("dijit", "loading", this.lang);
  18050. this.loadingMessage = string.substitute(this.loadingMessage, messages);
  18051. this.errorMessage = string.substitute(this.errorMessage, messages);
  18052. },
  18053. buildRendering: function(){
  18054. this.inherited(arguments);
  18055. // Since we have no template we need to set this.containerNode ourselves, to make getChildren() work.
  18056. // For subclasses of ContentPane that do have a template, does nothing.
  18057. if(!this.containerNode){
  18058. this.containerNode = this.domNode;
  18059. }
  18060. // remove the title attribute so it doesn't show up when hovering
  18061. // over a node (TODO: remove in 2.0, no longer needed after #11490)
  18062. this.domNode.removeAttribute("title");
  18063. if(!domAttr.get(this.domNode,"role")){
  18064. this.domNode.setAttribute("role", "group");
  18065. }
  18066. },
  18067. startup: function(){
  18068. // summary:
  18069. // Call startup() on all children including non _Widget ones like dojo.dnd.Source objects
  18070. // This starts all the widgets
  18071. this.inherited(arguments);
  18072. // And this catches stuff like dojo.dnd.Source
  18073. if(this._contentSetter){
  18074. array.forEach(this._contentSetter.parseResults, function(obj){
  18075. if(!obj._started && !obj._destroyed && lang.isFunction(obj.startup)){
  18076. obj.startup();
  18077. obj._started = true;
  18078. }
  18079. }, this);
  18080. }
  18081. },
  18082. setHref: function(/*String|Uri*/ href){
  18083. // summary:
  18084. // Deprecated. Use set('href', ...) instead.
  18085. kernel.deprecated("dijit.layout.ContentPane.setHref() is deprecated. Use set('href', ...) instead.", "", "2.0");
  18086. return this.set("href", href);
  18087. },
  18088. _setHrefAttr: function(/*String|Uri*/ href){
  18089. // summary:
  18090. // Hook so set("href", ...) works.
  18091. // description:
  18092. // Reset the (external defined) content of this pane and replace with new url
  18093. // Note: It delays the download until widget is shown if preload is false.
  18094. // href:
  18095. // url to the page you want to get, must be within the same domain as your mainpage
  18096. // Cancel any in-flight requests (a set('href', ...) will cancel any in-flight set('href', ...))
  18097. this.cancel();
  18098. this.onLoadDeferred = new Deferred(lang.hitch(this, "cancel"));
  18099. this.onLoadDeferred.addCallback(lang.hitch(this, "onLoad"));
  18100. this._set("href", href);
  18101. // _setHrefAttr() is called during creation and by the user, after creation.
  18102. // Assuming preload == false, only in the second case do we actually load the URL;
  18103. // otherwise it's done in startup(), and only if this widget is shown.
  18104. if(this.preload || (this._created && this._isShown())){
  18105. this._load();
  18106. }else{
  18107. // Set flag to indicate that href needs to be loaded the next time the
  18108. // ContentPane is made visible
  18109. this._hrefChanged = true;
  18110. }
  18111. return this.onLoadDeferred; // Deferred
  18112. },
  18113. setContent: function(/*String|DomNode|Nodelist*/data){
  18114. // summary:
  18115. // Deprecated. Use set('content', ...) instead.
  18116. kernel.deprecated("dijit.layout.ContentPane.setContent() is deprecated. Use set('content', ...) instead.", "", "2.0");
  18117. this.set("content", data);
  18118. },
  18119. _setContentAttr: function(/*String|DomNode|Nodelist*/data){
  18120. // summary:
  18121. // Hook to make set("content", ...) work.
  18122. // Replaces old content with data content, include style classes from old content
  18123. // data:
  18124. // the new Content may be String, DomNode or NodeList
  18125. //
  18126. // if data is a NodeList (or an array of nodes) nodes are copied
  18127. // so you can import nodes from another document implicitly
  18128. // clear href so we can't run refresh and clear content
  18129. // refresh should only work if we downloaded the content
  18130. this._set("href", "");
  18131. // Cancel any in-flight requests (a set('content', ...) will cancel any in-flight set('href', ...))
  18132. this.cancel();
  18133. // Even though user is just setting content directly, still need to define an onLoadDeferred
  18134. // because the _onLoadHandler() handler is still getting called from setContent()
  18135. this.onLoadDeferred = new Deferred(lang.hitch(this, "cancel"));
  18136. if(this._created){
  18137. // For back-compat reasons, call onLoad() for set('content', ...)
  18138. // calls but not for content specified in srcNodeRef (ie: <div data-dojo-type=ContentPane>...</div>)
  18139. // or as initialization parameter (ie: new ContentPane({content: ...})
  18140. this.onLoadDeferred.addCallback(lang.hitch(this, "onLoad"));
  18141. }
  18142. this._setContent(data || "");
  18143. this._isDownloaded = false; // mark that content is from a set('content') not a set('href')
  18144. return this.onLoadDeferred; // Deferred
  18145. },
  18146. _getContentAttr: function(){
  18147. // summary:
  18148. // Hook to make get("content") work
  18149. return this.containerNode.innerHTML;
  18150. },
  18151. cancel: function(){
  18152. // summary:
  18153. // Cancels an in-flight download of content
  18154. if(this._xhrDfd && (this._xhrDfd.fired == -1)){
  18155. this._xhrDfd.cancel();
  18156. }
  18157. delete this._xhrDfd; // garbage collect
  18158. this.onLoadDeferred = null;
  18159. },
  18160. uninitialize: function(){
  18161. if(this._beingDestroyed){
  18162. this.cancel();
  18163. }
  18164. this.inherited(arguments);
  18165. },
  18166. destroyRecursive: function(/*Boolean*/ preserveDom){
  18167. // summary:
  18168. // Destroy the ContentPane and its contents
  18169. // if we have multiple controllers destroying us, bail after the first
  18170. if(this._beingDestroyed){
  18171. return;
  18172. }
  18173. this.inherited(arguments);
  18174. },
  18175. _onShow: function(){
  18176. // summary:
  18177. // Called when the ContentPane is made visible
  18178. // description:
  18179. // For a plain ContentPane, this is called on initialization, from startup().
  18180. // If the ContentPane is a hidden pane of a TabContainer etc., then it's
  18181. // called whenever the pane is made visible.
  18182. //
  18183. // Does necessary processing, including href download and layout/resize of
  18184. // child widget(s)
  18185. this.inherited(arguments);
  18186. if(this.href){
  18187. if(!this._xhrDfd && // if there's an href that isn't already being loaded
  18188. (!this.isLoaded || this._hrefChanged || this.refreshOnShow)
  18189. ){
  18190. return this.refresh(); // If child has an href, promise that fires when the load is complete
  18191. }
  18192. }
  18193. },
  18194. refresh: function(){
  18195. // summary:
  18196. // [Re]download contents of href and display
  18197. // description:
  18198. // 1. cancels any currently in-flight requests
  18199. // 2. posts "loading..." message
  18200. // 3. sends XHR to download new data
  18201. // Cancel possible prior in-flight request
  18202. this.cancel();
  18203. this.onLoadDeferred = new Deferred(lang.hitch(this, "cancel"));
  18204. this.onLoadDeferred.addCallback(lang.hitch(this, "onLoad"));
  18205. this._load();
  18206. return this.onLoadDeferred; // If child has an href, promise that fires when refresh is complete
  18207. },
  18208. _load: function(){
  18209. // summary:
  18210. // Load/reload the href specified in this.href
  18211. // display loading message
  18212. this._setContent(this.onDownloadStart(), true);
  18213. var self = this;
  18214. var getArgs = {
  18215. preventCache: (this.preventCache || this.refreshOnShow),
  18216. url: this.href,
  18217. handleAs: "text"
  18218. };
  18219. if(lang.isObject(this.ioArgs)){
  18220. lang.mixin(getArgs, this.ioArgs);
  18221. }
  18222. var hand = (this._xhrDfd = (this.ioMethod || xhr.get)(getArgs));
  18223. hand.addCallback(function(html){
  18224. try{
  18225. self._isDownloaded = true;
  18226. self._setContent(html, false);
  18227. self.onDownloadEnd();
  18228. }catch(err){
  18229. self._onError('Content', err); // onContentError
  18230. }
  18231. delete self._xhrDfd;
  18232. return html;
  18233. });
  18234. hand.addErrback(function(err){
  18235. if(!hand.canceled){
  18236. // show error message in the pane
  18237. self._onError('Download', err); // onDownloadError
  18238. }
  18239. delete self._xhrDfd;
  18240. return err;
  18241. });
  18242. // Remove flag saying that a load is needed
  18243. delete this._hrefChanged;
  18244. },
  18245. _onLoadHandler: function(data){
  18246. // summary:
  18247. // This is called whenever new content is being loaded
  18248. this._set("isLoaded", true);
  18249. try{
  18250. this.onLoadDeferred.callback(data);
  18251. }catch(e){
  18252. console.error('Error '+this.widgetId+' running custom onLoad code: ' + e.message);
  18253. }
  18254. },
  18255. _onUnloadHandler: function(){
  18256. // summary:
  18257. // This is called whenever the content is being unloaded
  18258. this._set("isLoaded", false);
  18259. try{
  18260. this.onUnload();
  18261. }catch(e){
  18262. console.error('Error '+this.widgetId+' running custom onUnload code: ' + e.message);
  18263. }
  18264. },
  18265. destroyDescendants: function(/*Boolean*/ preserveDom){
  18266. // summary:
  18267. // Destroy all the widgets inside the ContentPane and empty containerNode
  18268. // Make sure we call onUnload (but only when the ContentPane has real content)
  18269. if(this.isLoaded){
  18270. this._onUnloadHandler();
  18271. }
  18272. // Even if this.isLoaded == false there might still be a "Loading..." message
  18273. // to erase, so continue...
  18274. // For historical reasons we need to delete all widgets under this.containerNode,
  18275. // even ones that the user has created manually.
  18276. var setter = this._contentSetter;
  18277. array.forEach(this.getChildren(), function(widget){
  18278. if(widget.destroyRecursive){
  18279. widget.destroyRecursive(preserveDom);
  18280. }
  18281. });
  18282. if(setter){
  18283. // Most of the widgets in setter.parseResults have already been destroyed, but
  18284. // things like Menu that have been moved to <body> haven't yet
  18285. array.forEach(setter.parseResults, function(widget){
  18286. if(widget.destroyRecursive && widget.domNode && widget.domNode.parentNode == win.body()){
  18287. widget.destroyRecursive(preserveDom);
  18288. }
  18289. });
  18290. delete setter.parseResults;
  18291. }
  18292. // And then clear away all the DOM nodes
  18293. if(!preserveDom){
  18294. html._emptyNode(this.containerNode);
  18295. }
  18296. // Delete any state information we have about current contents
  18297. delete this._singleChild;
  18298. },
  18299. _setContent: function(/*String|DocumentFragment*/ cont, /*Boolean*/ isFakeContent){
  18300. // summary:
  18301. // Insert the content into the container node
  18302. // first get rid of child widgets
  18303. this.destroyDescendants();
  18304. // html.set will take care of the rest of the details
  18305. // we provide an override for the error handling to ensure the widget gets the errors
  18306. // configure the setter instance with only the relevant widget instance properties
  18307. // NOTE: unless we hook into attr, or provide property setters for each property,
  18308. // we need to re-configure the ContentSetter with each use
  18309. var setter = this._contentSetter;
  18310. if(! (setter && setter instanceof html._ContentSetter)){
  18311. setter = this._contentSetter = new html._ContentSetter({
  18312. node: this.containerNode,
  18313. _onError: lang.hitch(this, this._onError),
  18314. onContentError: lang.hitch(this, function(e){
  18315. // fires if a domfault occurs when we are appending this.errorMessage
  18316. // like for instance if domNode is a UL and we try append a DIV
  18317. var errMess = this.onContentError(e);
  18318. try{
  18319. this.containerNode.innerHTML = errMess;
  18320. }catch(e){
  18321. console.error('Fatal '+this.id+' could not change content due to '+e.message, e);
  18322. }
  18323. })/*,
  18324. _onError */
  18325. });
  18326. }
  18327. var setterParams = lang.mixin({
  18328. cleanContent: this.cleanContent,
  18329. extractContent: this.extractContent,
  18330. parseContent: !cont.domNode && this.parseOnLoad,
  18331. parserScope: this.parserScope,
  18332. startup: false,
  18333. dir: this.dir,
  18334. lang: this.lang,
  18335. textDir: this.textDir
  18336. }, this._contentSetterParams || {});
  18337. setter.set( (lang.isObject(cont) && cont.domNode) ? cont.domNode : cont, setterParams );
  18338. // setter params must be pulled afresh from the ContentPane each time
  18339. delete this._contentSetterParams;
  18340. if(this.doLayout){
  18341. this._checkIfSingleChild();
  18342. }
  18343. if(!isFakeContent){
  18344. if(this._started){
  18345. // Startup each top level child widget (and they will start their children, recursively)
  18346. delete this._started;
  18347. this.startup();
  18348. // Call resize() on each of my child layout widgets,
  18349. // or resize() on my single child layout widget...
  18350. // either now (if I'm currently visible) or when I become visible
  18351. this._scheduleLayout();
  18352. }
  18353. this._onLoadHandler(cont);
  18354. }
  18355. },
  18356. _onError: function(type, err, consoleText){
  18357. this.onLoadDeferred.errback(err);
  18358. // shows user the string that is returned by on[type]Error
  18359. // override on[type]Error and return your own string to customize
  18360. var errText = this['on' + type + 'Error'].call(this, err);
  18361. if(consoleText){
  18362. console.error(consoleText, err);
  18363. }else if(errText){// a empty string won't change current content
  18364. this._setContent(errText, true);
  18365. }
  18366. },
  18367. // EVENT's, should be overide-able
  18368. onLoad: function(/*===== data =====*/){
  18369. // summary:
  18370. // Event hook, is called after everything is loaded and widgetified
  18371. // tags:
  18372. // callback
  18373. },
  18374. onUnload: function(){
  18375. // summary:
  18376. // Event hook, is called before old content is cleared
  18377. // tags:
  18378. // callback
  18379. },
  18380. onDownloadStart: function(){
  18381. // summary:
  18382. // Called before download starts.
  18383. // description:
  18384. // The string returned by this function will be the html
  18385. // that tells the user we are loading something.
  18386. // Override with your own function if you want to change text.
  18387. // tags:
  18388. // extension
  18389. return this.loadingMessage;
  18390. },
  18391. onContentError: function(/*Error*/ /*===== error =====*/){
  18392. // summary:
  18393. // Called on DOM faults, require faults etc. in content.
  18394. //
  18395. // In order to display an error message in the pane, return
  18396. // the error message from this method, as an HTML string.
  18397. //
  18398. // By default (if this method is not overriden), it returns
  18399. // nothing, so the error message is just printed to the console.
  18400. // tags:
  18401. // extension
  18402. },
  18403. onDownloadError: function(/*Error*/ /*===== error =====*/){
  18404. // summary:
  18405. // Called when download error occurs.
  18406. //
  18407. // In order to display an error message in the pane, return
  18408. // the error message from this method, as an HTML string.
  18409. //
  18410. // Default behavior (if this method is not overriden) is to display
  18411. // the error message inside the pane.
  18412. // tags:
  18413. // extension
  18414. return this.errorMessage;
  18415. },
  18416. onDownloadEnd: function(){
  18417. // summary:
  18418. // Called when download is finished.
  18419. // tags:
  18420. // callback
  18421. }
  18422. });
  18423. });
  18424. },
  18425. 'url:dijit/form/templates/ValidationTextBox.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\"\n\tid=\"widget_${id}\" role=\"presentation\"\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" data-dojo-attach-point='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n",
  18426. 'url:dijit/form/templates/TextBox.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\" id=\"widget_${id}\" role=\"presentation\"\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" data-dojo-attach-point='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n",
  18427. 'dijit/_KeyNavContainer':function(){
  18428. define([
  18429. "dojo/_base/kernel", // kernel.deprecated
  18430. "./_Container",
  18431. "./_FocusMixin",
  18432. "dojo/_base/array", // array.forEach
  18433. "dojo/keys", // keys.END keys.HOME
  18434. "dojo/_base/declare", // declare
  18435. "dojo/_base/event", // event.stop
  18436. "dojo/dom-attr", // domAttr.set
  18437. "dojo/_base/lang" // lang.hitch
  18438. ], function(kernel, _Container, _FocusMixin, array, keys, declare, event, domAttr, lang){
  18439. /*=====
  18440. var _FocusMixin = dijit._FocusMixin;
  18441. var _Container = dijit._Container;
  18442. =====*/
  18443. // module:
  18444. // dijit/_KeyNavContainer
  18445. // summary:
  18446. // A _Container with keyboard navigation of its children.
  18447. return declare("dijit._KeyNavContainer", [_FocusMixin, _Container], {
  18448. // summary:
  18449. // A _Container with keyboard navigation of its children.
  18450. // description:
  18451. // To use this mixin, call connectKeyNavHandlers() in
  18452. // postCreate().
  18453. // It provides normalized keyboard and focusing code for Container
  18454. // widgets.
  18455. /*=====
  18456. // focusedChild: [protected] Widget
  18457. // The currently focused child widget, or null if there isn't one
  18458. focusedChild: null,
  18459. =====*/
  18460. // tabIndex: Integer
  18461. // Tab index of the container; same as HTML tabIndex attribute.
  18462. // Note then when user tabs into the container, focus is immediately
  18463. // moved to the first item in the container.
  18464. tabIndex: "0",
  18465. connectKeyNavHandlers: function(/*keys[]*/ prevKeyCodes, /*keys[]*/ nextKeyCodes){
  18466. // summary:
  18467. // Call in postCreate() to attach the keyboard handlers
  18468. // to the container.
  18469. // preKeyCodes: keys[]
  18470. // Key codes for navigating to the previous child.
  18471. // nextKeyCodes: keys[]
  18472. // Key codes for navigating to the next child.
  18473. // tags:
  18474. // protected
  18475. // TODO: call this automatically from my own postCreate()
  18476. var keyCodes = (this._keyNavCodes = {});
  18477. var prev = lang.hitch(this, "focusPrev");
  18478. var next = lang.hitch(this, "focusNext");
  18479. array.forEach(prevKeyCodes, function(code){ keyCodes[code] = prev; });
  18480. array.forEach(nextKeyCodes, function(code){ keyCodes[code] = next; });
  18481. keyCodes[keys.HOME] = lang.hitch(this, "focusFirstChild");
  18482. keyCodes[keys.END] = lang.hitch(this, "focusLastChild");
  18483. this.connect(this.domNode, "onkeypress", "_onContainerKeypress");
  18484. this.connect(this.domNode, "onfocus", "_onContainerFocus");
  18485. },
  18486. startupKeyNavChildren: function(){
  18487. kernel.deprecated("startupKeyNavChildren() call no longer needed", "", "2.0");
  18488. },
  18489. startup: function(){
  18490. this.inherited(arguments);
  18491. array.forEach(this.getChildren(), lang.hitch(this, "_startupChild"));
  18492. },
  18493. addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){
  18494. this.inherited(arguments);
  18495. this._startupChild(widget);
  18496. },
  18497. focus: function(){
  18498. // summary:
  18499. // Default focus() implementation: focus the first child.
  18500. this.focusFirstChild();
  18501. },
  18502. focusFirstChild: function(){
  18503. // summary:
  18504. // Focus the first focusable child in the container.
  18505. // tags:
  18506. // protected
  18507. this.focusChild(this._getFirstFocusableChild());
  18508. },
  18509. focusLastChild: function(){
  18510. // summary:
  18511. // Focus the last focusable child in the container.
  18512. // tags:
  18513. // protected
  18514. this.focusChild(this._getLastFocusableChild());
  18515. },
  18516. focusNext: function(){
  18517. // summary:
  18518. // Focus the next widget
  18519. // tags:
  18520. // protected
  18521. this.focusChild(this._getNextFocusableChild(this.focusedChild, 1));
  18522. },
  18523. focusPrev: function(){
  18524. // summary:
  18525. // Focus the last focusable node in the previous widget
  18526. // (ex: go to the ComboButton icon section rather than button section)
  18527. // tags:
  18528. // protected
  18529. this.focusChild(this._getNextFocusableChild(this.focusedChild, -1), true);
  18530. },
  18531. focusChild: function(/*dijit._Widget*/ widget, /*Boolean*/ last){
  18532. // summary:
  18533. // Focus specified child widget.
  18534. // widget:
  18535. // Reference to container's child widget
  18536. // last:
  18537. // If true and if widget has multiple focusable nodes, focus the
  18538. // last one instead of the first one
  18539. // tags:
  18540. // protected
  18541. if(!widget){ return; }
  18542. if(this.focusedChild && widget !== this.focusedChild){
  18543. this._onChildBlur(this.focusedChild); // used by _MenuBase
  18544. }
  18545. widget.set("tabIndex", this.tabIndex); // for IE focus outline to appear, must set tabIndex before focs
  18546. widget.focus(last ? "end" : "start");
  18547. this._set("focusedChild", widget);
  18548. },
  18549. _startupChild: function(/*dijit._Widget*/ widget){
  18550. // summary:
  18551. // Setup for each child widget
  18552. // description:
  18553. // Sets tabIndex=-1 on each child, so that the tab key will
  18554. // leave the container rather than visiting each child.
  18555. // tags:
  18556. // private
  18557. widget.set("tabIndex", "-1");
  18558. this.connect(widget, "_onFocus", function(){
  18559. // Set valid tabIndex so tabbing away from widget goes to right place, see #10272
  18560. widget.set("tabIndex", this.tabIndex);
  18561. });
  18562. this.connect(widget, "_onBlur", function(){
  18563. widget.set("tabIndex", "-1");
  18564. });
  18565. },
  18566. _onContainerFocus: function(evt){
  18567. // summary:
  18568. // Handler for when the container gets focus
  18569. // description:
  18570. // Initially the container itself has a tabIndex, but when it gets
  18571. // focus, switch focus to first child...
  18572. // tags:
  18573. // private
  18574. // Note that we can't use _onFocus() because switching focus from the
  18575. // _onFocus() handler confuses the focus.js code
  18576. // (because it causes _onFocusNode() to be called recursively)
  18577. // Also, _onFocus() would fire when focus went directly to a child widget due to mouse click.
  18578. // Ignore spurious focus events:
  18579. // 1. focus on a child widget bubbles on FF
  18580. // 2. on IE, clicking the scrollbar of a select dropdown moves focus from the focused child item to me
  18581. if(evt.target !== this.domNode || this.focusedChild){ return; }
  18582. this.focusFirstChild();
  18583. // and then set the container's tabIndex to -1,
  18584. // (don't remove as that breaks Safari 4)
  18585. // so that tab or shift-tab will go to the fields after/before
  18586. // the container, rather than the container itself
  18587. domAttr.set(this.domNode, "tabIndex", "-1");
  18588. },
  18589. _onBlur: function(evt){
  18590. // When focus is moved away the container, and its descendant (popup) widgets,
  18591. // then restore the container's tabIndex so that user can tab to it again.
  18592. // Note that using _onBlur() so that this doesn't happen when focus is shifted
  18593. // to one of my child widgets (typically a popup)
  18594. if(this.tabIndex){
  18595. domAttr.set(this.domNode, "tabIndex", this.tabIndex);
  18596. }
  18597. this.focusedChild = null;
  18598. this.inherited(arguments);
  18599. },
  18600. _onContainerKeypress: function(evt){
  18601. // summary:
  18602. // When a key is pressed, if it's an arrow key etc. then
  18603. // it's handled here.
  18604. // tags:
  18605. // private
  18606. if(evt.ctrlKey || evt.altKey){ return; }
  18607. var func = this._keyNavCodes[evt.charOrCode];
  18608. if(func){
  18609. func();
  18610. event.stop(evt);
  18611. }
  18612. },
  18613. _onChildBlur: function(/*dijit._Widget*/ /*===== widget =====*/){
  18614. // summary:
  18615. // Called when focus leaves a child widget to go
  18616. // to a sibling widget.
  18617. // Used by MenuBase.js (TODO: move code there)
  18618. // tags:
  18619. // protected
  18620. },
  18621. _getFirstFocusableChild: function(){
  18622. // summary:
  18623. // Returns first child that can be focused
  18624. return this._getNextFocusableChild(null, 1); // dijit._Widget
  18625. },
  18626. _getLastFocusableChild: function(){
  18627. // summary:
  18628. // Returns last child that can be focused
  18629. return this._getNextFocusableChild(null, -1); // dijit._Widget
  18630. },
  18631. _getNextFocusableChild: function(child, dir){
  18632. // summary:
  18633. // Returns the next or previous focusable child, compared
  18634. // to "child"
  18635. // child: Widget
  18636. // The current widget
  18637. // dir: Integer
  18638. // * 1 = after
  18639. // * -1 = before
  18640. if(child){
  18641. child = this._getSiblingOfChild(child, dir);
  18642. }
  18643. var children = this.getChildren();
  18644. for(var i=0; i < children.length; i++){
  18645. if(!child){
  18646. child = children[(dir>0) ? 0 : (children.length-1)];
  18647. }
  18648. if(child.isFocusable()){
  18649. return child; // dijit._Widget
  18650. }
  18651. child = this._getSiblingOfChild(child, dir);
  18652. }
  18653. // no focusable child found
  18654. return null; // dijit._Widget
  18655. }
  18656. });
  18657. });
  18658. },
  18659. 'dijit/layout/utils':function(){
  18660. define([
  18661. "dojo/_base/array", // array.filter array.forEach
  18662. "dojo/dom-class", // domClass.add domClass.remove
  18663. "dojo/dom-geometry", // domGeometry.marginBox
  18664. "dojo/dom-style", // domStyle.getComputedStyle
  18665. "dojo/_base/lang", // lang.mixin
  18666. ".." // for exporting symbols to dijit, remove in 2.0
  18667. ], function(array, domClass, domGeometry, domStyle, lang, dijit){
  18668. // module:
  18669. // dijit/layout/utils
  18670. // summary:
  18671. // marginBox2contentBox() and layoutChildren()
  18672. var layout = lang.getObject("layout", true, dijit);
  18673. /*===== layout = dijit.layout =====*/
  18674. layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
  18675. // summary:
  18676. // Given the margin-box size of a node, return its content box size.
  18677. // Functions like domGeometry.contentBox() but is more reliable since it doesn't have
  18678. // to wait for the browser to compute sizes.
  18679. var cs = domStyle.getComputedStyle(node);
  18680. var me = domGeometry.getMarginExtents(node, cs);
  18681. var pb = domGeometry.getPadBorderExtents(node, cs);
  18682. return {
  18683. l: domStyle.toPixelValue(node, cs.paddingLeft),
  18684. t: domStyle.toPixelValue(node, cs.paddingTop),
  18685. w: mb.w - (me.w + pb.w),
  18686. h: mb.h - (me.h + pb.h)
  18687. };
  18688. };
  18689. function capitalize(word){
  18690. return word.substring(0,1).toUpperCase() + word.substring(1);
  18691. }
  18692. function size(widget, dim){
  18693. // size the child
  18694. var newSize = widget.resize ? widget.resize(dim) : domGeometry.setMarginBox(widget.domNode, dim);
  18695. // record child's size
  18696. if(newSize){
  18697. // if the child returned it's new size then use that
  18698. lang.mixin(widget, newSize);
  18699. }else{
  18700. // otherwise, call getMarginBox(), but favor our own numbers when we have them.
  18701. // the browser lies sometimes
  18702. lang.mixin(widget, domGeometry.getMarginBox(widget.domNode));
  18703. lang.mixin(widget, dim);
  18704. }
  18705. }
  18706. layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Widget[]*/ children,
  18707. /*String?*/ changedRegionId, /*Number?*/ changedRegionSize){
  18708. // summary:
  18709. // Layout a bunch of child dom nodes within a parent dom node
  18710. // container:
  18711. // parent node
  18712. // dim:
  18713. // {l, t, w, h} object specifying dimensions of container into which to place children
  18714. // children:
  18715. // an array of Widgets or at least objects containing:
  18716. // * domNode: pointer to DOM node to position
  18717. // * region or layoutAlign: position to place DOM node
  18718. // * resize(): (optional) method to set size of node
  18719. // * id: (optional) Id of widgets, referenced from resize object, below.
  18720. // changedRegionId:
  18721. // If specified, the slider for the region with the specified id has been dragged, and thus
  18722. // the region's height or width should be adjusted according to changedRegionSize
  18723. // changedRegionSize:
  18724. // See changedRegionId.
  18725. // copy dim because we are going to modify it
  18726. dim = lang.mixin({}, dim);
  18727. domClass.add(container, "dijitLayoutContainer");
  18728. // Move "client" elements to the end of the array for layout. a11y dictates that the author
  18729. // needs to be able to put them in the document in tab-order, but this algorithm requires that
  18730. // client be last. TODO: move these lines to LayoutContainer? Unneeded other places I think.
  18731. children = array.filter(children, function(item){ return item.region != "center" && item.layoutAlign != "client"; })
  18732. .concat(array.filter(children, function(item){ return item.region == "center" || item.layoutAlign == "client"; }));
  18733. // set positions/sizes
  18734. array.forEach(children, function(child){
  18735. var elm = child.domNode,
  18736. pos = (child.region || child.layoutAlign);
  18737. if(!pos){
  18738. throw new Error("No region setting for " + child.id)
  18739. }
  18740. // set elem to upper left corner of unused space; may move it later
  18741. var elmStyle = elm.style;
  18742. elmStyle.left = dim.l+"px";
  18743. elmStyle.top = dim.t+"px";
  18744. elmStyle.position = "absolute";
  18745. domClass.add(elm, "dijitAlign" + capitalize(pos));
  18746. // Size adjustments to make to this child widget
  18747. var sizeSetting = {};
  18748. // Check for optional size adjustment due to splitter drag (height adjustment for top/bottom align
  18749. // panes and width adjustment for left/right align panes.
  18750. if(changedRegionId && changedRegionId == child.id){
  18751. sizeSetting[child.region == "top" || child.region == "bottom" ? "h" : "w"] = changedRegionSize;
  18752. }
  18753. // set size && adjust record of remaining space.
  18754. // note that setting the width of a <div> may affect its height.
  18755. if(pos == "top" || pos == "bottom"){
  18756. sizeSetting.w = dim.w;
  18757. size(child, sizeSetting);
  18758. dim.h -= child.h;
  18759. if(pos == "top"){
  18760. dim.t += child.h;
  18761. }else{
  18762. elmStyle.top = dim.t + dim.h + "px";
  18763. }
  18764. }else if(pos == "left" || pos == "right"){
  18765. sizeSetting.h = dim.h;
  18766. size(child, sizeSetting);
  18767. dim.w -= child.w;
  18768. if(pos == "left"){
  18769. dim.l += child.w;
  18770. }else{
  18771. elmStyle.left = dim.l + dim.w + "px";
  18772. }
  18773. }else if(pos == "client" || pos == "center"){
  18774. size(child, dim);
  18775. }
  18776. });
  18777. };
  18778. return {
  18779. marginBox2contentBox: layout.marginBox2contentBox,
  18780. layoutChildren: layout.layoutChildren
  18781. };
  18782. });
  18783. },
  18784. 'dijit/form/DataList':function(){
  18785. define([
  18786. "dojo/_base/declare", // declare
  18787. "dojo/dom", // dom.byId
  18788. "dojo/_base/lang", // lang.trim
  18789. "dojo/query", // query
  18790. "dojo/store/Memory", // dojo.store.Memory
  18791. "../registry" // registry.add registry.remove
  18792. ], function(declare, dom, lang, query, MemoryStore, registry){
  18793. // module:
  18794. // dijit/form/DataList
  18795. // summary:
  18796. // Inefficient but small data store specialized for inlined data via OPTION tags
  18797. function toItem(/*DOMNode*/ option){
  18798. // summary:
  18799. // Convert <option> node to hash
  18800. return {
  18801. id: option.value,
  18802. value: option.value,
  18803. name: lang.trim(option.innerText || option.textContent || '')
  18804. };
  18805. }
  18806. return declare("dijit.form.DataList", MemoryStore, {
  18807. // summary:
  18808. // Inefficient but small data store specialized for inlined data via OPTION tags
  18809. //
  18810. // description:
  18811. // Provides a store for inlined data like:
  18812. //
  18813. // | <datalist>
  18814. // | <option value="AL">Alabama</option>
  18815. // | ...
  18816. constructor: function(/*Object?*/ params, /*DomNode|String*/ srcNodeRef){
  18817. // store pointer to original DOM tree
  18818. this.domNode = dom.byId(srcNodeRef);
  18819. lang.mixin(this, params);
  18820. if(this.id){
  18821. registry.add(this); // add to registry so it can be easily found by id
  18822. }
  18823. this.domNode.style.display = "none";
  18824. this.inherited(arguments, [{
  18825. data: query("option", this.domNode).map(toItem)
  18826. }]);
  18827. },
  18828. destroy: function(){
  18829. registry.remove(this.id);
  18830. },
  18831. fetchSelectedItem: function(){
  18832. // summary:
  18833. // Get the option marked as selected, like `<option selected>`.
  18834. // Not part of dojo.data API.
  18835. var option = query("> option[selected]", this.domNode)[0] || query("> option", this.domNode)[0];
  18836. return option && toItem(option);
  18837. }
  18838. });
  18839. });
  18840. },
  18841. 'url:dijit/templates/Dialog.html':"<div class=\"dijitDialog\" role=\"dialog\" aria-labelledby=\"${id}_title\">\n\t<div data-dojo-attach-point=\"titleBar\" class=\"dijitDialogTitleBar\">\n\t<span data-dojo-attach-point=\"titleNode\" class=\"dijitDialogTitle\" id=\"${id}_title\"></span>\n\t<span data-dojo-attach-point=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" data-dojo-attach-event=\"ondijitclick: onCancel\" title=\"${buttonCancel}\" role=\"button\" tabIndex=\"0\">\n\t\t<span data-dojo-attach-point=\"closeText\" class=\"closeText\" title=\"${buttonCancel}\">x</span>\n\t</span>\n\t</div>\n\t\t<div data-dojo-attach-point=\"containerNode\" class=\"dijitDialogPaneContent\"></div>\n</div>\n",
  18842. 'dijit/_editor/_Plugin':function(){
  18843. define([
  18844. "dojo/_base/connect", // connect.connect
  18845. "dojo/_base/declare", // declare
  18846. "dojo/_base/lang", // lang.mixin, lang.hitch
  18847. "../form/Button"
  18848. ], function(connect, declare, lang, Button){
  18849. // module:
  18850. // dijit/_editor/_Plugin
  18851. // summary:
  18852. // Base class for a "plugin" to the editor, which is usually
  18853. // a single button on the Toolbar and some associated code
  18854. var _Plugin = declare("dijit._editor._Plugin", null, {
  18855. // summary:
  18856. // Base class for a "plugin" to the editor, which is usually
  18857. // a single button on the Toolbar and some associated code
  18858. constructor: function(/*Object?*/args){
  18859. this.params = args || {};
  18860. lang.mixin(this, this.params);
  18861. this._connects=[];
  18862. this._attrPairNames = {};
  18863. },
  18864. // editor: [const] dijit.Editor
  18865. // Points to the parent editor
  18866. editor: null,
  18867. // iconClassPrefix: [const] String
  18868. // The CSS class name for the button node is formed from `iconClassPrefix` and `command`
  18869. iconClassPrefix: "dijitEditorIcon",
  18870. // button: dijit._Widget?
  18871. // Pointer to `dijit.form.Button` or other widget (ex: `dijit.form.FilteringSelect`)
  18872. // that is added to the toolbar to control this plugin.
  18873. // If not specified, will be created on initialization according to `buttonClass`
  18874. button: null,
  18875. // command: String
  18876. // String like "insertUnorderedList", "outdent", "justifyCenter", etc. that represents an editor command.
  18877. // Passed to editor.execCommand() if `useDefaultCommand` is true.
  18878. command: "",
  18879. // useDefaultCommand: Boolean
  18880. // If true, this plugin executes by calling Editor.execCommand() with the argument specified in `command`.
  18881. useDefaultCommand: true,
  18882. // buttonClass: Widget Class
  18883. // Class of widget (ex: dijit.form.Button or dijit.form.FilteringSelect)
  18884. // that is added to the toolbar to control this plugin.
  18885. // This is used to instantiate the button, unless `button` itself is specified directly.
  18886. buttonClass: Button,
  18887. // disabled: Boolean
  18888. // Flag to indicate if this plugin has been disabled and should do nothing
  18889. // helps control button state, among other things. Set via the setter api.
  18890. disabled: false,
  18891. getLabel: function(/*String*/key){
  18892. // summary:
  18893. // Returns the label to use for the button
  18894. // tags:
  18895. // private
  18896. return this.editor.commands[key]; // String
  18897. },
  18898. _initButton: function(){
  18899. // summary:
  18900. // Initialize the button or other widget that will control this plugin.
  18901. // This code only works for plugins controlling built-in commands in the editor.
  18902. // tags:
  18903. // protected extension
  18904. if(this.command.length){
  18905. var label = this.getLabel(this.command),
  18906. editor = this.editor,
  18907. className = this.iconClassPrefix+" "+this.iconClassPrefix + this.command.charAt(0).toUpperCase() + this.command.substr(1);
  18908. if(!this.button){
  18909. var props = lang.mixin({
  18910. label: label,
  18911. dir: editor.dir,
  18912. lang: editor.lang,
  18913. showLabel: false,
  18914. iconClass: className,
  18915. dropDown: this.dropDown,
  18916. tabIndex: "-1"
  18917. }, this.params || {});
  18918. this.button = new this.buttonClass(props);
  18919. }
  18920. }
  18921. if(this.get("disabled") && this.button){
  18922. this.button.set("disabled", this.get("disabled"));
  18923. }
  18924. },
  18925. destroy: function(){
  18926. // summary:
  18927. // Destroy this plugin
  18928. var h;
  18929. while(h = this._connects.pop()){ h.remove(); }
  18930. if(this.dropDown){
  18931. this.dropDown.destroyRecursive();
  18932. }
  18933. },
  18934. connect: function(o, f, tf){
  18935. // summary:
  18936. // Make a connect.connect() that is automatically disconnected when this plugin is destroyed.
  18937. // Similar to `dijit._Widget.connect`.
  18938. // tags:
  18939. // protected
  18940. this._connects.push(connect.connect(o, f, this, tf));
  18941. },
  18942. updateState: function(){
  18943. // summary:
  18944. // Change state of the plugin to respond to events in the editor.
  18945. // description:
  18946. // This is called on meaningful events in the editor, such as change of selection
  18947. // or caret position (but not simple typing of alphanumeric keys). It gives the
  18948. // plugin a chance to update the CSS of its button.
  18949. //
  18950. // For example, the "bold" plugin will highlight/unhighlight the bold button depending on whether the
  18951. // characters next to the caret are bold or not.
  18952. //
  18953. // Only makes sense when `useDefaultCommand` is true, as it calls Editor.queryCommandEnabled(`command`).
  18954. var e = this.editor,
  18955. c = this.command,
  18956. checked, enabled;
  18957. if(!e || !e.isLoaded || !c.length){ return; }
  18958. var disabled = this.get("disabled");
  18959. if(this.button){
  18960. try{
  18961. enabled = !disabled && e.queryCommandEnabled(c);
  18962. if(this.enabled !== enabled){
  18963. this.enabled = enabled;
  18964. this.button.set('disabled', !enabled);
  18965. }
  18966. if(typeof this.button.checked == 'boolean'){
  18967. checked = e.queryCommandState(c);
  18968. if(this.checked !== checked){
  18969. this.checked = checked;
  18970. this.button.set('checked', e.queryCommandState(c));
  18971. }
  18972. }
  18973. }catch(e){
  18974. console.log(e); // FIXME: we shouldn't have debug statements in our code. Log as an error?
  18975. }
  18976. }
  18977. },
  18978. setEditor: function(/*dijit.Editor*/ editor){
  18979. // summary:
  18980. // Tell the plugin which Editor it is associated with.
  18981. // TODO: refactor code to just pass editor to constructor.
  18982. // FIXME: detach from previous editor!!
  18983. this.editor = editor;
  18984. // FIXME: prevent creating this if we don't need to (i.e., editor can't handle our command)
  18985. this._initButton();
  18986. // Processing for buttons that execute by calling editor.execCommand()
  18987. if(this.button && this.useDefaultCommand){
  18988. if(this.editor.queryCommandAvailable(this.command)){
  18989. this.connect(this.button, "onClick",
  18990. lang.hitch(this.editor, "execCommand", this.command, this.commandArg)
  18991. );
  18992. }else{
  18993. // hide button because editor doesn't support command (due to browser limitations)
  18994. this.button.domNode.style.display = "none";
  18995. }
  18996. }
  18997. this.connect(this.editor, "onNormalizedDisplayChanged", "updateState");
  18998. },
  18999. setToolbar: function(/*dijit.Toolbar*/ toolbar){
  19000. // summary:
  19001. // Tell the plugin to add it's controller widget (often a button)
  19002. // to the toolbar. Does nothing if there is no controller widget.
  19003. // TODO: refactor code to just pass toolbar to constructor.
  19004. if(this.button){
  19005. toolbar.addChild(this.button);
  19006. }
  19007. // console.debug("adding", this.button, "to:", toolbar);
  19008. },
  19009. set: function(/* attribute */ name, /* anything */ value){
  19010. // summary:
  19011. // Set a property on a plugin
  19012. // name:
  19013. // The property to set.
  19014. // value:
  19015. // The value to set in the property.
  19016. // description:
  19017. // Sets named properties on a plugin which may potentially be handled by a
  19018. // setter in the plugin.
  19019. // For example, if the plugin has a properties "foo"
  19020. // and "bar" and a method named "_setFooAttr", calling:
  19021. // | plugin.set("foo", "Howdy!");
  19022. // would be equivalent to writing:
  19023. // | plugin._setFooAttr("Howdy!");
  19024. // and:
  19025. // | plugin.set("bar", 3);
  19026. // would be equivalent to writing:
  19027. // | plugin.bar = 3;
  19028. //
  19029. // set() may also be called with a hash of name/value pairs, ex:
  19030. // | plugin.set({
  19031. // | foo: "Howdy",
  19032. // | bar: 3
  19033. // | })
  19034. // This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
  19035. if(typeof name === "object"){
  19036. for(var x in name){
  19037. this.set(x, name[x]);
  19038. }
  19039. return this;
  19040. }
  19041. var names = this._getAttrNames(name);
  19042. if(this[names.s]){
  19043. // use the explicit setter
  19044. var result = this[names.s].apply(this, Array.prototype.slice.call(arguments, 1));
  19045. }else{
  19046. this._set(name, value);
  19047. }
  19048. return result || this;
  19049. },
  19050. get: function(name){
  19051. // summary:
  19052. // Get a property from a plugin.
  19053. // name:
  19054. // The property to get.
  19055. // description:
  19056. // Get a named property from a plugin. The property may
  19057. // potentially be retrieved via a getter method. If no getter is defined, this
  19058. // just retrieves the object's property.
  19059. // For example, if the plugin has a properties "foo"
  19060. // and "bar" and a method named "_getFooAttr", calling:
  19061. // | plugin.get("foo");
  19062. // would be equivalent to writing:
  19063. // | plugin._getFooAttr();
  19064. // and:
  19065. // | plugin.get("bar");
  19066. // would be equivalent to writing:
  19067. // | plugin.bar;
  19068. var names = this._getAttrNames(name);
  19069. return this[names.g] ? this[names.g]() : this[name];
  19070. },
  19071. _setDisabledAttr: function(disabled){
  19072. // summary:
  19073. // Function to set the plugin state and call updateState to make sure the
  19074. // button is updated appropriately.
  19075. this.disabled = disabled;
  19076. this.updateState();
  19077. },
  19078. _getAttrNames: function(name){
  19079. // summary:
  19080. // Helper function for get() and set().
  19081. // Caches attribute name values so we don't do the string ops every time.
  19082. // tags:
  19083. // private
  19084. var apn = this._attrPairNames;
  19085. if(apn[name]){ return apn[name]; }
  19086. var uc = name.charAt(0).toUpperCase() + name.substr(1);
  19087. return (apn[name] = {
  19088. s: "_set"+uc+"Attr",
  19089. g: "_get"+uc+"Attr"
  19090. });
  19091. },
  19092. _set: function(/*String*/ name, /*anything*/ value){
  19093. // summary:
  19094. // Helper function to set new value for specified attribute
  19095. this[name] = value;
  19096. }
  19097. });
  19098. // Hash mapping plugin name to factory, used for registering plugins
  19099. _Plugin.registry = {};
  19100. return _Plugin;
  19101. });
  19102. },
  19103. 'dijit/form/CheckBox':function(){
  19104. define([
  19105. "require",
  19106. "dojo/_base/declare", // declare
  19107. "dojo/dom-attr", // domAttr.set
  19108. "dojo/_base/kernel",
  19109. "dojo/query", // query
  19110. "dojo/ready",
  19111. "./ToggleButton",
  19112. "./_CheckBoxMixin",
  19113. "dojo/text!./templates/CheckBox.html",
  19114. "dojo/NodeList-dom" // NodeList.addClass/removeClass
  19115. ], function(require, declare, domAttr, kernel, query, ready, ToggleButton, _CheckBoxMixin, template){
  19116. /*=====
  19117. var ToggleButton = dijit.form.ToggleButton;
  19118. var _CheckBoxMixin = dijit.form._CheckBoxMixin;
  19119. =====*/
  19120. // module:
  19121. // dijit/form/CheckBox
  19122. // summary:
  19123. // Checkbox widget
  19124. // Back compat w/1.6, remove for 2.0
  19125. if(!kernel.isAsync){
  19126. ready(0, function(){
  19127. var requires = ["dijit/form/RadioButton"];
  19128. require(requires); // use indirection so modules not rolled into a build
  19129. });
  19130. }
  19131. return declare("dijit.form.CheckBox", [ToggleButton, _CheckBoxMixin], {
  19132. // summary:
  19133. // Same as an HTML checkbox, but with fancy styling.
  19134. //
  19135. // description:
  19136. // User interacts with real html inputs.
  19137. // On onclick (which occurs by mouse click, space-bar, or
  19138. // using the arrow keys to switch the selected radio button),
  19139. // we update the state of the checkbox/radio.
  19140. //
  19141. // There are two modes:
  19142. // 1. High contrast mode
  19143. // 2. Normal mode
  19144. //
  19145. // In case 1, the regular html inputs are shown and used by the user.
  19146. // In case 2, the regular html inputs are invisible but still used by
  19147. // the user. They are turned quasi-invisible and overlay the background-image.
  19148. templateString: template,
  19149. baseClass: "dijitCheckBox",
  19150. _setValueAttr: function(/*String|Boolean*/ newValue, /*Boolean*/ priorityChange){
  19151. // summary:
  19152. // Handler for value= attribute to constructor, and also calls to
  19153. // set('value', val).
  19154. // description:
  19155. // During initialization, just saves as attribute to the <input type=checkbox>.
  19156. //
  19157. // After initialization,
  19158. // when passed a boolean, controls whether or not the CheckBox is checked.
  19159. // If passed a string, changes the value attribute of the CheckBox (the one
  19160. // specified as "value" when the CheckBox was constructed (ex: <input
  19161. // data-dojo-type="dijit.CheckBox" value="chicken">)
  19162. // widget.set('value', string) will check the checkbox and change the value to the
  19163. // specified string
  19164. // widget.set('value', boolean) will change the checked state.
  19165. if(typeof newValue == "string"){
  19166. this._set("value", newValue);
  19167. domAttr.set(this.focusNode, 'value', newValue);
  19168. newValue = true;
  19169. }
  19170. if(this._created){
  19171. this.set('checked', newValue, priorityChange);
  19172. }
  19173. },
  19174. _getValueAttr: function(){
  19175. // summary:
  19176. // Hook so get('value') works.
  19177. // description:
  19178. // If the CheckBox is checked, returns the value attribute.
  19179. // Otherwise returns false.
  19180. return (this.checked ? this.value : false);
  19181. },
  19182. // Override behavior from Button, since we don't have an iconNode
  19183. _setIconClassAttr: null,
  19184. postMixInProperties: function(){
  19185. this.inherited(arguments);
  19186. // Need to set initial checked state as part of template, so that form submit works.
  19187. // domAttr.set(node, "checked", bool) doesn't work on IE until node has been attached
  19188. // to <body>, see #8666
  19189. this.checkedAttrSetting = this.checked ? "checked" : "";
  19190. },
  19191. _fillContent: function(){
  19192. // Override Button::_fillContent() since it doesn't make sense for CheckBox,
  19193. // since CheckBox doesn't even have a container
  19194. },
  19195. _onFocus: function(){
  19196. if(this.id){
  19197. query("label[for='"+this.id+"']").addClass("dijitFocusedLabel");
  19198. }
  19199. this.inherited(arguments);
  19200. },
  19201. _onBlur: function(){
  19202. if(this.id){
  19203. query("label[for='"+this.id+"']").removeClass("dijitFocusedLabel");
  19204. }
  19205. this.inherited(arguments);
  19206. }
  19207. });
  19208. });
  19209. },
  19210. 'url:dijit/templates/MenuBar.html':"<div class=\"dijitMenuBar dijitMenuPassive\" data-dojo-attach-point=\"containerNode\" role=\"menubar\" tabIndex=\"${tabIndex}\" data-dojo-attach-event=\"onkeypress: _onKeyPress\"></div>\n",
  19211. 'dijit/tree/_dndSelector':function(){
  19212. define([
  19213. "dojo/_base/array", // array.filter array.forEach array.map
  19214. "dojo/_base/connect", // connect.isCopyKey
  19215. "dojo/_base/declare", // declare
  19216. "dojo/_base/lang", // lang.hitch
  19217. "dojo/mouse", // mouse.isLeft
  19218. "dojo/on",
  19219. "dojo/touch",
  19220. "dojo/_base/window", // win.global
  19221. "./_dndContainer"
  19222. ], function(array, connect, declare, lang, mouse, on, touch, win, _dndContainer){
  19223. // module:
  19224. // dijit/tree/_dndSelector
  19225. // summary:
  19226. // This is a base class for `dijit.tree.dndSource` , and isn't meant to be used directly.
  19227. // It's based on `dojo.dnd.Selector`.
  19228. return declare("dijit.tree._dndSelector", _dndContainer, {
  19229. // summary:
  19230. // This is a base class for `dijit.tree.dndSource` , and isn't meant to be used directly.
  19231. // It's based on `dojo.dnd.Selector`.
  19232. // tags:
  19233. // protected
  19234. /*=====
  19235. // selection: Hash<String, DomNode>
  19236. // (id, DomNode) map for every TreeNode that's currently selected.
  19237. // The DOMNode is the TreeNode.rowNode.
  19238. selection: {},
  19239. =====*/
  19240. constructor: function(){
  19241. // summary:
  19242. // Initialization
  19243. // tags:
  19244. // private
  19245. this.selection={};
  19246. this.anchor = null;
  19247. this.tree.domNode.setAttribute("aria-multiselect", !this.singular);
  19248. this.events.push(
  19249. on(this.tree.domNode, touch.press, lang.hitch(this,"onMouseDown")),
  19250. on(this.tree.domNode, touch.release, lang.hitch(this,"onMouseUp")),
  19251. on(this.tree.domNode, touch.move, lang.hitch(this,"onMouseMove"))
  19252. );
  19253. },
  19254. // singular: Boolean
  19255. // Allows selection of only one element, if true.
  19256. // Tree hasn't been tested in singular=true mode, unclear if it works.
  19257. singular: false,
  19258. // methods
  19259. getSelectedTreeNodes: function(){
  19260. // summary:
  19261. // Returns a list of selected node(s).
  19262. // Used by dndSource on the start of a drag.
  19263. // tags:
  19264. // protected
  19265. var nodes=[], sel = this.selection;
  19266. for(var i in sel){
  19267. nodes.push(sel[i]);
  19268. }
  19269. return nodes;
  19270. },
  19271. selectNone: function(){
  19272. // summary:
  19273. // Unselects all items
  19274. // tags:
  19275. // private
  19276. this.setSelection([]);
  19277. return this; // self
  19278. },
  19279. destroy: function(){
  19280. // summary:
  19281. // Prepares the object to be garbage-collected
  19282. this.inherited(arguments);
  19283. this.selection = this.anchor = null;
  19284. },
  19285. addTreeNode: function(/*dijit._TreeNode*/node, /*Boolean?*/isAnchor){
  19286. // summary:
  19287. // add node to current selection
  19288. // node: Node
  19289. // node to add
  19290. // isAnchor: Boolean
  19291. // Whether the node should become anchor.
  19292. this.setSelection(this.getSelectedTreeNodes().concat( [node] ));
  19293. if(isAnchor){ this.anchor = node; }
  19294. return node;
  19295. },
  19296. removeTreeNode: function(/*dijit._TreeNode*/node){
  19297. // summary:
  19298. // remove node from current selection
  19299. // node: Node
  19300. // node to remove
  19301. this.setSelection(this._setDifference(this.getSelectedTreeNodes(), [node]));
  19302. return node;
  19303. },
  19304. isTreeNodeSelected: function(/*dijit._TreeNode*/node){
  19305. // summary:
  19306. // return true if node is currently selected
  19307. // node: Node
  19308. // the node to check whether it's in the current selection
  19309. return node.id && !!this.selection[node.id];
  19310. },
  19311. setSelection: function(/*dijit._treeNode[]*/ newSelection){
  19312. // summary:
  19313. // set the list of selected nodes to be exactly newSelection. All changes to the
  19314. // selection should be passed through this function, which ensures that derived
  19315. // attributes are kept up to date. Anchor will be deleted if it has been removed
  19316. // from the selection, but no new anchor will be added by this function.
  19317. // newSelection: Node[]
  19318. // list of tree nodes to make selected
  19319. var oldSelection = this.getSelectedTreeNodes();
  19320. array.forEach(this._setDifference(oldSelection, newSelection), lang.hitch(this, function(node){
  19321. node.setSelected(false);
  19322. if(this.anchor == node){
  19323. delete this.anchor;
  19324. }
  19325. delete this.selection[node.id];
  19326. }));
  19327. array.forEach(this._setDifference(newSelection, oldSelection), lang.hitch(this, function(node){
  19328. node.setSelected(true);
  19329. this.selection[node.id] = node;
  19330. }));
  19331. this._updateSelectionProperties();
  19332. },
  19333. _setDifference: function(xs,ys){
  19334. // summary:
  19335. // Returns a copy of xs which lacks any objects
  19336. // occurring in ys. Checks for membership by
  19337. // modifying and then reading the object, so it will
  19338. // not properly handle sets of numbers or strings.
  19339. array.forEach(ys, function(y){ y.__exclude__ = true; });
  19340. var ret = array.filter(xs, function(x){ return !x.__exclude__; });
  19341. // clean up after ourselves.
  19342. array.forEach(ys, function(y){ delete y['__exclude__'] });
  19343. return ret;
  19344. },
  19345. _updateSelectionProperties: function(){
  19346. // summary:
  19347. // Update the following tree properties from the current selection:
  19348. // path[s], selectedItem[s], selectedNode[s]
  19349. var selected = this.getSelectedTreeNodes();
  19350. var paths = [], nodes = [];
  19351. array.forEach(selected, function(node){
  19352. nodes.push(node);
  19353. paths.push(node.getTreePath());
  19354. });
  19355. var items = array.map(nodes,function(node){ return node.item; });
  19356. this.tree._set("paths", paths);
  19357. this.tree._set("path", paths[0] || []);
  19358. this.tree._set("selectedNodes", nodes);
  19359. this.tree._set("selectedNode", nodes[0] || null);
  19360. this.tree._set("selectedItems", items);
  19361. this.tree._set("selectedItem", items[0] || null);
  19362. },
  19363. // mouse events
  19364. onMouseDown: function(e){
  19365. // summary:
  19366. // Event processor for onmousedown/ontouchstart
  19367. // e: Event
  19368. // onmousedown/ontouchstart event
  19369. // tags:
  19370. // protected
  19371. // ignore click on expando node
  19372. if(!this.current || this.tree.isExpandoNode(e.target, this.current)){ return; }
  19373. if(e.type == "mousedown" && mouse.isLeft(e)){
  19374. // Prevent text selection while dragging on desktop, see #16328. But don't call preventDefault()
  19375. // for mobile because it will break things completely, see #15838. Also, don't preventDefault() on
  19376. // MSPointerDown or pointerdown events, because that stops the mousedown event from being generated,
  19377. // see #17709.
  19378. // TODO: remove this completely in 2.0. It shouldn't be needed since dojo/dnd/Manager already
  19379. // calls preventDefault() for the "selectstart" event. It can also be achieved via CSS:
  19380. // http://stackoverflow.com/questions/826782/css-rule-to-disable-text-selection-highlighting
  19381. e.preventDefault();
  19382. }else if(e.type != "touchstart"){
  19383. // Ignore right click
  19384. return;
  19385. }
  19386. var treeNode = this.current,
  19387. copy = connect.isCopyKey(e), id = treeNode.id;
  19388. // if shift key is not pressed, and the node is already in the selection,
  19389. // delay deselection until onmouseup so in the case of DND, deselection
  19390. // will be canceled by onmousemove.
  19391. if(!this.singular && !e.shiftKey && this.selection[id]){
  19392. this._doDeselect = true;
  19393. return;
  19394. }else{
  19395. this._doDeselect = false;
  19396. }
  19397. this.userSelect(treeNode, copy, e.shiftKey);
  19398. },
  19399. onMouseUp: function(e){
  19400. // summary:
  19401. // Event processor for onmouseup/ontouchend
  19402. // e: Event
  19403. // onmouseup/ontouchend event
  19404. // tags:
  19405. // protected
  19406. // _doDeselect is the flag to indicate that the user wants to either ctrl+click on
  19407. // a already selected item (to deselect the item), or click on a not-yet selected item
  19408. // (which should remove all current selection, and add the clicked item). This can not
  19409. // be done in onMouseDown, because the user may start a drag after mousedown. By moving
  19410. // the deselection logic here, the user can drags an already selected item.
  19411. if(!this._doDeselect){ return; }
  19412. this._doDeselect = false;
  19413. this.userSelect(this.current, connect.isCopyKey(e), e.shiftKey);
  19414. },
  19415. onMouseMove: function(/*===== e =====*/){
  19416. // summary:
  19417. // event processor for onmousemove/ontouchmove
  19418. // e: Event
  19419. // onmousemove/ontouchmove event
  19420. this._doDeselect = false;
  19421. },
  19422. _compareNodes: function(n1, n2){
  19423. if(n1 === n2){
  19424. return 0;
  19425. }
  19426. if('sourceIndex' in document.documentElement){ //IE
  19427. //TODO: does not yet work if n1 and/or n2 is a text node
  19428. return n1.sourceIndex - n2.sourceIndex;
  19429. }else if('compareDocumentPosition' in document.documentElement){ //FF, Opera
  19430. return n1.compareDocumentPosition(n2) & 2 ? 1: -1;
  19431. }else if(document.createRange){ //Webkit
  19432. var r1 = doc.createRange();
  19433. r1.setStartBefore(n1);
  19434. var r2 = doc.createRange();
  19435. r2.setStartBefore(n2);
  19436. return r1.compareBoundaryPoints(r1.END_TO_END, r2);
  19437. }else{
  19438. throw Error("dijit.tree._compareNodes don't know how to compare two different nodes in this browser");
  19439. }
  19440. },
  19441. userSelect: function(node, multi, range){
  19442. // summary:
  19443. // Add or remove the given node from selection, responding
  19444. // to a user action such as a click or keypress.
  19445. // multi: Boolean
  19446. // Indicates whether this is meant to be a multi-select action (e.g. ctrl-click)
  19447. // range: Boolean
  19448. // Indicates whether this is meant to be a ranged action (e.g. shift-click)
  19449. // tags:
  19450. // protected
  19451. if(this.singular){
  19452. if(this.anchor == node && multi){
  19453. this.selectNone();
  19454. }else{
  19455. this.setSelection([node]);
  19456. this.anchor = node;
  19457. }
  19458. }else{
  19459. if(range && this.anchor){
  19460. var cr = this._compareNodes(this.anchor.rowNode, node.rowNode),
  19461. begin, end, anchor = this.anchor;
  19462. if(cr < 0){ //current is after anchor
  19463. begin = anchor;
  19464. end = node;
  19465. }else{ //current is before anchor
  19466. begin = node;
  19467. end = anchor;
  19468. }
  19469. var nodes = [];
  19470. //add everything betweeen begin and end inclusively
  19471. while(begin != end){
  19472. nodes.push(begin);
  19473. begin = this.tree._getNextNode(begin);
  19474. }
  19475. nodes.push(end);
  19476. this.setSelection(nodes);
  19477. }else{
  19478. if( this.selection[ node.id ] && multi ){
  19479. this.removeTreeNode( node );
  19480. }else if(multi){
  19481. this.addTreeNode(node, true);
  19482. }else{
  19483. this.setSelection([node]);
  19484. this.anchor = node;
  19485. }
  19486. }
  19487. }
  19488. },
  19489. getItem: function(/*String*/ key){
  19490. // summary:
  19491. // Returns the dojo.dnd.Item (representing a dragged node) by it's key (id).
  19492. // Called by dojo.dnd.Source.checkAcceptance().
  19493. // tags:
  19494. // protected
  19495. var widget = this.selection[key];
  19496. return {
  19497. data: widget,
  19498. type: ["treeNode"]
  19499. }; // dojo.dnd.Item
  19500. },
  19501. forInSelectedItems: function(/*Function*/ f, /*Object?*/ o){
  19502. // summary:
  19503. // Iterates over selected items;
  19504. // see `dojo.dnd.Container.forInItems()` for details
  19505. o = o || win.global;
  19506. for(var id in this.selection){
  19507. // console.log("selected item id: " + id);
  19508. f.call(o, this.getItem(id), id, this);
  19509. }
  19510. }
  19511. });
  19512. });
  19513. },
  19514. 'dojo/html':function(){
  19515. define(["./_base/kernel", "./_base/lang", "./_base/array", "./_base/declare", "./dom", "./dom-construct", "./parser"], function(dojo, lang, darray, declare, dom, domConstruct, parser) {
  19516. // module:
  19517. // dojo/html
  19518. // summary:
  19519. // TODOC
  19520. lang.getObject("html", true, dojo);
  19521. // the parser might be needed..
  19522. // idCounter is incremented with each instantiation to allow asignment of a unique id for tracking, logging purposes
  19523. var idCounter = 0;
  19524. dojo.html._secureForInnerHtml = function(/*String*/ cont){
  19525. // summary:
  19526. // removes !DOCTYPE and title elements from the html string.
  19527. //
  19528. // khtml is picky about dom faults, you can't attach a style or <title> node as child of body
  19529. // must go into head, so we need to cut out those tags
  19530. // cont:
  19531. // An html string for insertion into the dom
  19532. //
  19533. return cont.replace(/(?:\s*<!DOCTYPE\s[^>]+>|<title[^>]*>[\s\S]*?<\/title>)/ig, ""); // String
  19534. };
  19535. /*====
  19536. dojo.html._emptyNode = function(node){
  19537. // summary:
  19538. // removes all child nodes from the given node
  19539. // node: DOMNode
  19540. // the parent element
  19541. };
  19542. =====*/
  19543. dojo.html._emptyNode = domConstruct.empty;
  19544. dojo.html._setNodeContent = function(/* DomNode */ node, /* String|DomNode|NodeList */ cont){
  19545. // summary:
  19546. // inserts the given content into the given node
  19547. // node:
  19548. // the parent element
  19549. // content:
  19550. // the content to be set on the parent element.
  19551. // This can be an html string, a node reference or a NodeList, dojo.NodeList, Array or other enumerable list of nodes
  19552. // always empty
  19553. domConstruct.empty(node);
  19554. if(cont) {
  19555. if(typeof cont == "string") {
  19556. cont = domConstruct.toDom(cont, node.ownerDocument);
  19557. }
  19558. if(!cont.nodeType && lang.isArrayLike(cont)) {
  19559. // handle as enumerable, but it may shrink as we enumerate it
  19560. for(var startlen=cont.length, i=0; i<cont.length; i=startlen==cont.length ? i+1 : 0) {
  19561. domConstruct.place( cont[i], node, "last");
  19562. }
  19563. } else {
  19564. // pass nodes, documentFragments and unknowns through to dojo.place
  19565. domConstruct.place(cont, node, "last");
  19566. }
  19567. }
  19568. // return DomNode
  19569. return node;
  19570. };
  19571. // we wrap up the content-setting operation in a object
  19572. declare("dojo.html._ContentSetter", null,
  19573. {
  19574. // node: DomNode|String
  19575. // An node which will be the parent element that we set content into
  19576. node: "",
  19577. // content: String|DomNode|DomNode[]
  19578. // The content to be placed in the node. Can be an HTML string, a node reference, or a enumerable list of nodes
  19579. content: "",
  19580. // id: String?
  19581. // Usually only used internally, and auto-generated with each instance
  19582. id: "",
  19583. // cleanContent: Boolean
  19584. // Should the content be treated as a full html document,
  19585. // and the real content stripped of <html>, <body> wrapper before injection
  19586. cleanContent: false,
  19587. // extractContent: Boolean
  19588. // Should the content be treated as a full html document, and the real content stripped of <html>, <body> wrapper before injection
  19589. extractContent: false,
  19590. // parseContent: Boolean
  19591. // Should the node by passed to the parser after the new content is set
  19592. parseContent: false,
  19593. // parserScope: String
  19594. // Flag passed to parser. Root for attribute names to search for. If scopeName is dojo,
  19595. // will search for data-dojo-type (or dojoType). For backwards compatibility
  19596. // reasons defaults to dojo._scopeName (which is "dojo" except when
  19597. // multi-version support is used, when it will be something like dojo16, dojo20, etc.)
  19598. parserScope: dojo._scopeName,
  19599. // startup: Boolean
  19600. // Start the child widgets after parsing them. Only obeyed if parseContent is true.
  19601. startup: true,
  19602. // lifecyle methods
  19603. constructor: function(/* Object */params, /* String|DomNode */node){
  19604. // summary:
  19605. // Provides a configurable, extensible object to wrap the setting on content on a node
  19606. // call the set() method to actually set the content..
  19607. // the original params are mixed directly into the instance "this"
  19608. lang.mixin(this, params || {});
  19609. // give precedence to params.node vs. the node argument
  19610. // and ensure its a node, not an id string
  19611. node = this.node = dom.byId( this.node || node );
  19612. if(!this.id){
  19613. this.id = [
  19614. "Setter",
  19615. (node) ? node.id || node.tagName : "",
  19616. idCounter++
  19617. ].join("_");
  19618. }
  19619. },
  19620. set: function(/* String|DomNode|NodeList? */ cont, /* Object? */ params){
  19621. // summary:
  19622. // front-end to the set-content sequence
  19623. // cont:
  19624. // An html string, node or enumerable list of nodes for insertion into the dom
  19625. // If not provided, the object's content property will be used
  19626. if(undefined !== cont){
  19627. this.content = cont;
  19628. }
  19629. // in the re-use scenario, set needs to be able to mixin new configuration
  19630. if(params){
  19631. this._mixin(params);
  19632. }
  19633. this.onBegin();
  19634. this.setContent();
  19635. this.onEnd();
  19636. return this.node;
  19637. },
  19638. setContent: function(){
  19639. // summary:
  19640. // sets the content on the node
  19641. var node = this.node;
  19642. if(!node) {
  19643. // can't proceed
  19644. throw new Error(this.declaredClass + ": setContent given no node");
  19645. }
  19646. try{
  19647. node = dojo.html._setNodeContent(node, this.content);
  19648. }catch(e){
  19649. // check if a domfault occurs when we are appending this.errorMessage
  19650. // like for instance if domNode is a UL and we try append a DIV
  19651. // FIXME: need to allow the user to provide a content error message string
  19652. var errMess = this.onContentError(e);
  19653. try{
  19654. node.innerHTML = errMess;
  19655. }catch(e){
  19656. console.error('Fatal ' + this.declaredClass + '.setContent could not change content due to '+e.message, e);
  19657. }
  19658. }
  19659. // always put back the node for the next method
  19660. this.node = node; // DomNode
  19661. },
  19662. empty: function() {
  19663. // summary
  19664. // cleanly empty out existing content
  19665. // destroy any widgets from a previous run
  19666. // NOTE: if you dont want this you'll need to empty
  19667. // the parseResults array property yourself to avoid bad things happenning
  19668. if(this.parseResults && this.parseResults.length) {
  19669. darray.forEach(this.parseResults, function(w) {
  19670. if(w.destroy){
  19671. w.destroy();
  19672. }
  19673. });
  19674. delete this.parseResults;
  19675. }
  19676. // this is fast, but if you know its already empty or safe, you could
  19677. // override empty to skip this step
  19678. dojo.html._emptyNode(this.node);
  19679. },
  19680. onBegin: function(){
  19681. // summary
  19682. // Called after instantiation, but before set();
  19683. // It allows modification of any of the object properties
  19684. // - including the node and content provided - before the set operation actually takes place
  19685. // This default implementation checks for cleanContent and extractContent flags to
  19686. // optionally pre-process html string content
  19687. var cont = this.content;
  19688. if(lang.isString(cont)){
  19689. if(this.cleanContent){
  19690. cont = dojo.html._secureForInnerHtml(cont);
  19691. }
  19692. if(this.extractContent){
  19693. var match = cont.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
  19694. if(match){ cont = match[1]; }
  19695. }
  19696. }
  19697. // clean out the node and any cruft associated with it - like widgets
  19698. this.empty();
  19699. this.content = cont;
  19700. return this.node; /* DomNode */
  19701. },
  19702. onEnd: function(){
  19703. // summary
  19704. // Called after set(), when the new content has been pushed into the node
  19705. // It provides an opportunity for post-processing before handing back the node to the caller
  19706. // This default implementation checks a parseContent flag to optionally run the dojo parser over the new content
  19707. if(this.parseContent){
  19708. // populates this.parseResults if you need those..
  19709. this._parse();
  19710. }
  19711. return this.node; /* DomNode */
  19712. },
  19713. tearDown: function(){
  19714. // summary
  19715. // manually reset the Setter instance if its being re-used for example for another set()
  19716. // description
  19717. // tearDown() is not called automatically.
  19718. // In normal use, the Setter instance properties are simply allowed to fall out of scope
  19719. // but the tearDown method can be called to explicitly reset this instance.
  19720. delete this.parseResults;
  19721. delete this.node;
  19722. delete this.content;
  19723. },
  19724. onContentError: function(err){
  19725. return "Error occured setting content: " + err;
  19726. },
  19727. _mixin: function(params){
  19728. // mix properties/methods into the instance
  19729. // TODO: the intention with tearDown is to put the Setter's state
  19730. // back to that of the original constructor (vs. deleting/resetting everything regardless of ctor params)
  19731. // so we could do something here to move the original properties aside for later restoration
  19732. var empty = {}, key;
  19733. for(key in params){
  19734. if(key in empty){ continue; }
  19735. // TODO: here's our opportunity to mask the properties we dont consider configurable/overridable
  19736. // .. but history shows we'll almost always guess wrong
  19737. this[key] = params[key];
  19738. }
  19739. },
  19740. _parse: function(){
  19741. // summary:
  19742. // runs the dojo parser over the node contents, storing any results in this.parseResults
  19743. // Any errors resulting from parsing are passed to _onError for handling
  19744. var rootNode = this.node;
  19745. try{
  19746. // store the results (widgets, whatever) for potential retrieval
  19747. var inherited = {};
  19748. darray.forEach(["dir", "lang", "textDir"], function(name){
  19749. if(this[name]){
  19750. inherited[name] = this[name];
  19751. }
  19752. }, this);
  19753. this.parseResults = parser.parse({
  19754. rootNode: rootNode,
  19755. noStart: !this.startup,
  19756. inherited: inherited,
  19757. scope: this.parserScope
  19758. });
  19759. }catch(e){
  19760. this._onError('Content', e, "Error parsing in _ContentSetter#"+this.id);
  19761. }
  19762. },
  19763. _onError: function(type, err, consoleText){
  19764. // summary:
  19765. // shows user the string that is returned by on[type]Error
  19766. // overide/implement on[type]Error and return your own string to customize
  19767. var errText = this['on' + type + 'Error'].call(this, err);
  19768. if(consoleText){
  19769. console.error(consoleText, err);
  19770. }else if(errText){ // a empty string won't change current content
  19771. dojo.html._setNodeContent(this.node, errText, true);
  19772. }
  19773. }
  19774. }); // end dojo.declare()
  19775. dojo.html.set = function(/* DomNode */ node, /* String|DomNode|NodeList */ cont, /* Object? */ params){
  19776. // summary:
  19777. // inserts (replaces) the given content into the given node. dojo.place(cont, node, "only")
  19778. // may be a better choice for simple HTML insertion.
  19779. // description:
  19780. // Unless you need to use the params capabilities of this method, you should use
  19781. // dojo.place(cont, node, "only"). dojo.place() has more robust support for injecting
  19782. // an HTML string into the DOM, but it only handles inserting an HTML string as DOM
  19783. // elements, or inserting a DOM node. dojo.place does not handle NodeList insertions
  19784. // or the other capabilities as defined by the params object for this method.
  19785. // node:
  19786. // the parent element that will receive the content
  19787. // cont:
  19788. // the content to be set on the parent element.
  19789. // This can be an html string, a node reference or a NodeList, dojo.NodeList, Array or other enumerable list of nodes
  19790. // params:
  19791. // Optional flags/properties to configure the content-setting. See dojo.html._ContentSetter
  19792. // example:
  19793. // A safe string/node/nodelist content replacement/injection with hooks for extension
  19794. // Example Usage:
  19795. // dojo.html.set(node, "some string");
  19796. // dojo.html.set(node, contentNode, {options});
  19797. // dojo.html.set(node, myNode.childNodes, {options});
  19798. if(undefined == cont){
  19799. console.warn("dojo.html.set: no cont argument provided, using empty string");
  19800. cont = "";
  19801. }
  19802. if(!params){
  19803. // simple and fast
  19804. return dojo.html._setNodeContent(node, cont, true);
  19805. }else{
  19806. // more options but slower
  19807. // note the arguments are reversed in order, to match the convention for instantiation via the parser
  19808. var op = new dojo.html._ContentSetter(lang.mixin(
  19809. params,
  19810. { content: cont, node: node }
  19811. ));
  19812. return op.set();
  19813. }
  19814. };
  19815. return dojo.html;
  19816. });
  19817. },
  19818. 'dijit/_PaletteMixin':function(){
  19819. define([
  19820. "dojo/_base/declare", // declare
  19821. "dojo/dom-attr", // domAttr.set
  19822. "dojo/dom-class", // domClass.add domClass.remove
  19823. "dojo/dom-construct", // domConstruct.create domConstruct.place
  19824. "dojo/_base/event", // event.stop
  19825. "dojo/keys", // keys
  19826. "dojo/_base/lang", // lang.getObject
  19827. "./_CssStateMixin",
  19828. "./focus",
  19829. "./typematic"
  19830. ], function(declare, domAttr, domClass, domConstruct, event, keys, lang, _CssStateMixin, focus, typematic){
  19831. /*=====
  19832. var _CssStateMixin = dijit._CssStateMixin;
  19833. =====*/
  19834. // module:
  19835. // dijit/_PaletteMixin
  19836. // summary:
  19837. // A keyboard accessible palette, for picking a color/emoticon/etc.
  19838. return declare("dijit._PaletteMixin", [_CssStateMixin], {
  19839. // summary:
  19840. // A keyboard accessible palette, for picking a color/emoticon/etc.
  19841. // description:
  19842. // A mixin for a grid showing various entities, so the user can pick a certain entity.
  19843. // defaultTimeout: Number
  19844. // Number of milliseconds before a held key or button becomes typematic
  19845. defaultTimeout: 500,
  19846. // timeoutChangeRate: Number
  19847. // Fraction of time used to change the typematic timer between events
  19848. // 1.0 means that each typematic event fires at defaultTimeout intervals
  19849. // < 1.0 means that each typematic event fires at an increasing faster rate
  19850. timeoutChangeRate: 0.90,
  19851. // value: String
  19852. // Currently selected color/emoticon/etc.
  19853. value: "",
  19854. // _selectedCell: [private] Integer
  19855. // Index of the currently selected cell. Initially, none selected
  19856. _selectedCell: -1,
  19857. /*=====
  19858. // _currentFocus: [private] DomNode
  19859. // The currently focused cell (if the palette itself has focus), or otherwise
  19860. // the cell to be focused when the palette itself gets focus.
  19861. // Different from value, which represents the selected (i.e. clicked) cell.
  19862. _currentFocus: null,
  19863. =====*/
  19864. /*=====
  19865. // _xDim: [protected] Integer
  19866. // This is the number of cells horizontally across.
  19867. _xDim: null,
  19868. =====*/
  19869. /*=====
  19870. // _yDim: [protected] Integer
  19871. // This is the number of cells vertically down.
  19872. _yDim: null,
  19873. =====*/
  19874. // tabIndex: String
  19875. // Widget tab index.
  19876. tabIndex: "0",
  19877. // cellClass: [protected] String
  19878. // CSS class applied to each cell in the palette
  19879. cellClass: "dijitPaletteCell",
  19880. // dyeClass: [protected] String
  19881. // Name of javascript class for Object created for each cell of the palette.
  19882. // dyeClass should implements dijit.Dye interface
  19883. dyeClass: '',
  19884. // summary: String
  19885. // Localized summary for the palette table
  19886. summary: '',
  19887. _setSummaryAttr: "paletteTableNode",
  19888. _dyeFactory: function(value /*===== , row, col =====*/){
  19889. // summary:
  19890. // Return instance of dijit.Dye for specified cell of palette
  19891. // tags:
  19892. // extension
  19893. var dyeClassObj = lang.getObject(this.dyeClass);
  19894. return new dyeClassObj(value);
  19895. },
  19896. _preparePalette: function(choices, titles) {
  19897. // summary:
  19898. // Subclass must call _preparePalette() from postCreate(), passing in the tooltip
  19899. // for each cell
  19900. // choices: String[][]
  19901. // id's for each cell of the palette, used to create Dye JS object for each cell
  19902. // titles: String[]
  19903. // Localized tooltip for each cell
  19904. this._cells = [];
  19905. var url = this._blankGif;
  19906. this.connect(this.gridNode, "ondijitclick", "_onCellClick");
  19907. for(var row=0; row < choices.length; row++){
  19908. var rowNode = domConstruct.create("tr", {tabIndex: "-1"}, this.gridNode);
  19909. for(var col=0; col < choices[row].length; col++){
  19910. var value = choices[row][col];
  19911. if(value){
  19912. var cellObject = this._dyeFactory(value, row, col);
  19913. var cellNode = domConstruct.create("td", {
  19914. "class": this.cellClass,
  19915. tabIndex: "-1",
  19916. title: titles[value],
  19917. role: "gridcell"
  19918. });
  19919. // prepare cell inner structure
  19920. cellObject.fillCell(cellNode, url);
  19921. domConstruct.place(cellNode, rowNode);
  19922. cellNode.index = this._cells.length;
  19923. // save cell info into _cells
  19924. this._cells.push({node:cellNode, dye:cellObject});
  19925. }
  19926. }
  19927. }
  19928. this._xDim = choices[0].length;
  19929. this._yDim = choices.length;
  19930. // Now set all events
  19931. // The palette itself is navigated to with the tab key on the keyboard
  19932. // Keyboard navigation within the Palette is with the arrow keys
  19933. // Spacebar selects the cell.
  19934. // For the up key the index is changed by negative the x dimension.
  19935. var keyIncrementMap = {
  19936. UP_ARROW: -this._xDim,
  19937. // The down key the index is increase by the x dimension.
  19938. DOWN_ARROW: this._xDim,
  19939. // Right and left move the index by 1.
  19940. RIGHT_ARROW: this.isLeftToRight() ? 1 : -1,
  19941. LEFT_ARROW: this.isLeftToRight() ? -1 : 1
  19942. };
  19943. for(var key in keyIncrementMap){
  19944. this._connects.push(
  19945. typematic.addKeyListener(
  19946. this.domNode,
  19947. {charOrCode:keys[key], ctrlKey:false, altKey:false, shiftKey:false},
  19948. this,
  19949. function(){
  19950. var increment = keyIncrementMap[key];
  19951. return function(count){ this._navigateByKey(increment, count); };
  19952. }(),
  19953. this.timeoutChangeRate,
  19954. this.defaultTimeout
  19955. )
  19956. );
  19957. }
  19958. },
  19959. postCreate: function(){
  19960. this.inherited(arguments);
  19961. // Set initial navigable node.
  19962. this._setCurrent(this._cells[0].node);
  19963. },
  19964. focus: function(){
  19965. // summary:
  19966. // Focus this widget. Puts focus on the most recently focused cell.
  19967. // The cell already has tabIndex set, just need to set CSS and focus it
  19968. focus.focus(this._currentFocus);
  19969. },
  19970. _onCellClick: function(/*Event*/ evt){
  19971. // summary:
  19972. // Handler for click, enter key & space key. Selects the cell.
  19973. // evt:
  19974. // The event.
  19975. // tags:
  19976. // private
  19977. var target = evt.target;
  19978. // Find TD associated with click event. For ColorPalette user likely clicked IMG inside of TD
  19979. while(target.tagName != "TD"){
  19980. if(!target.parentNode || target == this.gridNode){ // probably can never happen, but just in case
  19981. return;
  19982. }
  19983. target = target.parentNode;
  19984. }
  19985. var value = this._getDye(target).getValue();
  19986. // First focus the clicked cell, and then send onChange() notification.
  19987. // onChange() (via _setValueAttr) must be after the focus call, because
  19988. // it may trigger a refocus to somewhere else (like the Editor content area), and that
  19989. // second focus should win.
  19990. this._setCurrent(target);
  19991. focus.focus(target);
  19992. this._setValueAttr(value, true);
  19993. event.stop(evt);
  19994. },
  19995. _setCurrent: function(/*DomNode*/ node){
  19996. // summary:
  19997. // Sets which node is the focused cell.
  19998. // description:
  19999. // At any point in time there's exactly one
  20000. // cell with tabIndex != -1. If focus is inside the palette then
  20001. // focus is on that cell.
  20002. //
  20003. // After calling this method, arrow key handlers and mouse click handlers
  20004. // should focus the cell in a setTimeout().
  20005. // tags:
  20006. // protected
  20007. if("_currentFocus" in this){
  20008. // Remove tabIndex on old cell
  20009. domAttr.set(this._currentFocus, "tabIndex", "-1");
  20010. }
  20011. // Set tabIndex of new cell
  20012. this._currentFocus = node;
  20013. if(node){
  20014. domAttr.set(node, "tabIndex", this.tabIndex);
  20015. }
  20016. },
  20017. _setValueAttr: function(value, priorityChange){
  20018. // summary:
  20019. // This selects a cell. It triggers the onChange event.
  20020. // value: String value of the cell to select
  20021. // tags:
  20022. // protected
  20023. // priorityChange:
  20024. // Optional parameter used to tell the select whether or not to fire
  20025. // onChange event.
  20026. // clear old selected cell
  20027. if(this._selectedCell >= 0){
  20028. domClass.remove(this._cells[this._selectedCell].node, this.cellClass + "Selected");
  20029. }
  20030. this._selectedCell = -1;
  20031. // search for cell matching specified value
  20032. if(value){
  20033. for(var i = 0; i < this._cells.length; i++){
  20034. if(value == this._cells[i].dye.getValue()){
  20035. this._selectedCell = i;
  20036. domClass.add(this._cells[i].node, this.cellClass + "Selected");
  20037. break;
  20038. }
  20039. }
  20040. }
  20041. // record new value, or null if no matching cell
  20042. this._set("value", this._selectedCell >= 0 ? value : null);
  20043. if(priorityChange || priorityChange === undefined){
  20044. this.onChange(value);
  20045. }
  20046. },
  20047. onChange: function(/*===== value =====*/){
  20048. // summary:
  20049. // Callback when a cell is selected.
  20050. // value: String
  20051. // Value corresponding to cell.
  20052. },
  20053. _navigateByKey: function(increment, typeCount){
  20054. // summary:
  20055. // This is the callback for typematic.
  20056. // It changes the focus and the highlighed cell.
  20057. // increment:
  20058. // How much the key is navigated.
  20059. // typeCount:
  20060. // How many times typematic has fired.
  20061. // tags:
  20062. // private
  20063. // typecount == -1 means the key is released.
  20064. if(typeCount == -1){ return; }
  20065. var newFocusIndex = this._currentFocus.index + increment;
  20066. if(newFocusIndex < this._cells.length && newFocusIndex > -1){
  20067. var focusNode = this._cells[newFocusIndex].node;
  20068. this._setCurrent(focusNode);
  20069. // Actually focus the node, for the benefit of screen readers.
  20070. // Use setTimeout because IE doesn't like changing focus inside of an event handler
  20071. setTimeout(lang.hitch(dijit, "focus", focusNode), 0);
  20072. }
  20073. },
  20074. _getDye: function(/*DomNode*/ cell){
  20075. // summary:
  20076. // Get JS object for given cell DOMNode
  20077. return this._cells[cell.index].dye;
  20078. }
  20079. });
  20080. /*=====
  20081. declare("dijit.Dye",
  20082. null,
  20083. {
  20084. // summary:
  20085. // Interface for the JS Object associated with a palette cell (i.e. DOMNode)
  20086. constructor: function(alias, row, col){
  20087. // summary:
  20088. // Initialize according to value or alias like "white"
  20089. // alias: String
  20090. },
  20091. getValue: function(){
  20092. // summary:
  20093. // Return "value" of cell; meaning of "value" varies by subclass.
  20094. // description:
  20095. // For example color hex value, emoticon ascii value etc, entity hex value.
  20096. },
  20097. fillCell: function(cell, blankGif){
  20098. // summary:
  20099. // Add cell DOMNode inner structure
  20100. // cell: DomNode
  20101. // The surrounding cell
  20102. // blankGif: String
  20103. // URL for blank cell image
  20104. }
  20105. }
  20106. );
  20107. =====*/
  20108. });
  20109. },
  20110. 'url:dijit/templates/TitlePane.html':"<div>\n\t<div data-dojo-attach-event=\"onclick:_onTitleClick, onkeydown:_onTitleKey\"\n\t\t\tclass=\"dijitTitlePaneTitle\" data-dojo-attach-point=\"titleBarNode\">\n\t\t<div class=\"dijitTitlePaneTitleFocus\" data-dojo-attach-point=\"focusNode\">\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" data-dojo-attach-point=\"arrowNode\" class=\"dijitArrowNode\" role=\"presentation\"\n\t\t\t/><span data-dojo-attach-point=\"arrowNodeInner\" class=\"dijitArrowNodeInner\"></span\n\t\t\t><span data-dojo-attach-point=\"titleNode\" class=\"dijitTitlePaneTextNode\"></span>\n\t\t</div>\n\t</div>\n\t<div class=\"dijitTitlePaneContentOuter\" data-dojo-attach-point=\"hideNode\" role=\"presentation\">\n\t\t<div class=\"dijitReset\" data-dojo-attach-point=\"wipeNode\" role=\"presentation\">\n\t\t\t<div class=\"dijitTitlePaneContentInner\" data-dojo-attach-point=\"containerNode\" role=\"region\" id=\"${id}_pane\">\n\t\t\t\t<!-- nested divs because wipeIn()/wipeOut() doesn't work right on node w/padding etc. Put padding on inner div. -->\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n",
  20111. 'dijit/form/ValidationTextBox':function(){
  20112. define([
  20113. "dojo/_base/declare", // declare
  20114. "dojo/i18n", // i18n.getLocalization
  20115. "./TextBox",
  20116. "../Tooltip",
  20117. "dojo/text!./templates/ValidationTextBox.html",
  20118. "dojo/i18n!./nls/validate"
  20119. ], function(declare, i18n, TextBox, Tooltip, template){
  20120. /*=====
  20121. var Tooltip = dijit.Tooltip;
  20122. var TextBox = dijit.form.TextBox;
  20123. =====*/
  20124. // module:
  20125. // dijit/form/ValidationTextBox
  20126. // summary:
  20127. // Base class for textbox widgets with the ability to validate content of various types and provide user feedback.
  20128. /*=====
  20129. dijit.form.ValidationTextBox.__Constraints = function(){
  20130. // locale: String
  20131. // locale used for validation, picks up value from this widget's lang attribute
  20132. // _flags_: anything
  20133. // various flags passed to regExpGen function
  20134. this.locale = "";
  20135. this._flags_ = "";
  20136. }
  20137. =====*/
  20138. return declare("dijit.form.ValidationTextBox", TextBox, {
  20139. // summary:
  20140. // Base class for textbox widgets with the ability to validate content of various types and provide user feedback.
  20141. // tags:
  20142. // protected
  20143. templateString: template,
  20144. baseClass: "dijitTextBox dijitValidationTextBox",
  20145. // required: Boolean
  20146. // User is required to enter data into this field.
  20147. required: false,
  20148. // promptMessage: String
  20149. // If defined, display this hint string immediately on focus to the textbox, if empty.
  20150. // Also displays if the textbox value is Incomplete (not yet valid but will be with additional input).
  20151. // Think of this like a tooltip that tells the user what to do, not an error message
  20152. // that tells the user what they've done wrong.
  20153. //
  20154. // Message disappears when user starts typing.
  20155. promptMessage: "",
  20156. // invalidMessage: String
  20157. // The message to display if value is invalid.
  20158. // The translated string value is read from the message file by default.
  20159. // Set to "" to use the promptMessage instead.
  20160. invalidMessage: "$_unset_$",
  20161. // missingMessage: String
  20162. // The message to display if value is empty and the field is required.
  20163. // The translated string value is read from the message file by default.
  20164. // Set to "" to use the invalidMessage instead.
  20165. missingMessage: "$_unset_$",
  20166. // message: String
  20167. // Currently error/prompt message.
  20168. // When using the default tooltip implementation, this will only be
  20169. // displayed when the field is focused.
  20170. message: "",
  20171. // constraints: dijit.form.ValidationTextBox.__Constraints
  20172. // user-defined object needed to pass parameters to the validator functions
  20173. constraints: {},
  20174. // regExp: [extension protected] String
  20175. // regular expression string used to validate the input
  20176. // Do not specify both regExp and regExpGen
  20177. regExp: ".*",
  20178. regExpGen: function(/*dijit.form.ValidationTextBox.__Constraints*/ /*===== constraints =====*/){
  20179. // summary:
  20180. // Overridable function used to generate regExp when dependent on constraints.
  20181. // Do not specify both regExp and regExpGen.
  20182. // tags:
  20183. // extension protected
  20184. return this.regExp; // String
  20185. },
  20186. // state: [readonly] String
  20187. // Shows current state (ie, validation result) of input (""=Normal, Incomplete, or Error)
  20188. state: "",
  20189. // tooltipPosition: String[]
  20190. // See description of `dijit.Tooltip.defaultPosition` for details on this parameter.
  20191. tooltipPosition: [],
  20192. _setValueAttr: function(){
  20193. // summary:
  20194. // Hook so set('value', ...) works.
  20195. this.inherited(arguments);
  20196. this.validate(this.focused);
  20197. },
  20198. validator: function(/*anything*/ value, /*dijit.form.ValidationTextBox.__Constraints*/ constraints){
  20199. // summary:
  20200. // Overridable function used to validate the text input against the regular expression.
  20201. // tags:
  20202. // protected
  20203. return (new RegExp("^(?:" + this.regExpGen(constraints) + ")"+(this.required?"":"?")+"$")).test(value) &&
  20204. (!this.required || !this._isEmpty(value)) &&
  20205. (this._isEmpty(value) || this.parse(value, constraints) !== undefined); // Boolean
  20206. },
  20207. _isValidSubset: function(){
  20208. // summary:
  20209. // Returns true if the value is either already valid or could be made valid by appending characters.
  20210. // This is used for validation while the user [may be] still typing.
  20211. return this.textbox.value.search(this._partialre) == 0;
  20212. },
  20213. isValid: function(/*Boolean*/ /*===== isFocused =====*/){
  20214. // summary:
  20215. // Tests if value is valid.
  20216. // Can override with your own routine in a subclass.
  20217. // tags:
  20218. // protected
  20219. return this.validator(this.textbox.value, this.constraints);
  20220. },
  20221. _isEmpty: function(value){
  20222. // summary:
  20223. // Checks for whitespace
  20224. return (this.trim ? /^\s*$/ : /^$/).test(value); // Boolean
  20225. },
  20226. getErrorMessage: function(/*Boolean*/ /*===== isFocused =====*/){
  20227. // summary:
  20228. // Return an error message to show if appropriate
  20229. // tags:
  20230. // protected
  20231. return (this.required && this._isEmpty(this.textbox.value)) ? this.missingMessage : this.invalidMessage; // String
  20232. },
  20233. getPromptMessage: function(/*Boolean*/ /*===== isFocused =====*/){
  20234. // summary:
  20235. // Return a hint message to show when widget is first focused
  20236. // tags:
  20237. // protected
  20238. return this.promptMessage; // String
  20239. },
  20240. _maskValidSubsetError: true,
  20241. validate: function(/*Boolean*/ isFocused){
  20242. // summary:
  20243. // Called by oninit, onblur, and onkeypress.
  20244. // description:
  20245. // Show missing or invalid messages if appropriate, and highlight textbox field.
  20246. // tags:
  20247. // protected
  20248. var message = "";
  20249. var isValid = this.disabled || this.isValid(isFocused);
  20250. if(isValid){ this._maskValidSubsetError = true; }
  20251. var isEmpty = this._isEmpty(this.textbox.value);
  20252. var isValidSubset = !isValid && isFocused && this._isValidSubset();
  20253. this._set("state", isValid ? "" : (((((!this._hasBeenBlurred || isFocused) && isEmpty) || isValidSubset) && this._maskValidSubsetError) ? "Incomplete" : "Error"));
  20254. this.focusNode.setAttribute("aria-invalid", isValid ? "false" : "true");
  20255. if(this.state == "Error"){
  20256. this._maskValidSubsetError = isFocused && isValidSubset; // we want the error to show up after a blur and refocus
  20257. message = this.getErrorMessage(isFocused);
  20258. }else if(this.state == "Incomplete"){
  20259. message = this.getPromptMessage(isFocused); // show the prompt whenever the value is not yet complete
  20260. this._maskValidSubsetError = !this._hasBeenBlurred || isFocused; // no Incomplete warnings while focused
  20261. }else if(isEmpty){
  20262. message = this.getPromptMessage(isFocused); // show the prompt whenever there's no error and no text
  20263. }
  20264. this.set("message", message);
  20265. return isValid;
  20266. },
  20267. displayMessage: function(/*String*/ message){
  20268. // summary:
  20269. // Overridable method to display validation errors/hints.
  20270. // By default uses a tooltip.
  20271. // tags:
  20272. // extension
  20273. if(message && this.focused){
  20274. Tooltip.show(message, this.domNode, this.tooltipPosition, !this.isLeftToRight());
  20275. }else{
  20276. Tooltip.hide(this.domNode);
  20277. }
  20278. },
  20279. _refreshState: function(){
  20280. // Overrides TextBox._refreshState()
  20281. this.validate(this.focused);
  20282. this.inherited(arguments);
  20283. },
  20284. //////////// INITIALIZATION METHODS ///////////////////////////////////////
  20285. constructor: function(){
  20286. this.constraints = {};
  20287. },
  20288. _setConstraintsAttr: function(/*Object*/ constraints){
  20289. if(!constraints.locale && this.lang){
  20290. constraints.locale = this.lang;
  20291. }
  20292. this._set("constraints", constraints);
  20293. this._computePartialRE();
  20294. },
  20295. _computePartialRE: function(){
  20296. var p = this.regExpGen(this.constraints);
  20297. this.regExp = p;
  20298. var partialre = "";
  20299. // parse the regexp and produce a new regexp that matches valid subsets
  20300. // if the regexp is .* then there's no use in matching subsets since everything is valid
  20301. if(p != ".*"){ this.regExp.replace(/\\.|\[\]|\[.*?[^\\]{1}\]|\{.*?\}|\(\?[=:!]|./g,
  20302. function(re){
  20303. switch(re.charAt(0)){
  20304. case '{':
  20305. case '+':
  20306. case '?':
  20307. case '*':
  20308. case '^':
  20309. case '$':
  20310. case '|':
  20311. case '(':
  20312. partialre += re;
  20313. break;
  20314. case ")":
  20315. partialre += "|$)";
  20316. break;
  20317. default:
  20318. partialre += "(?:"+re+"|$)";
  20319. break;
  20320. }
  20321. }
  20322. );}
  20323. try{ // this is needed for now since the above regexp parsing needs more test verification
  20324. "".search(partialre);
  20325. }catch(e){ // should never be here unless the original RE is bad or the parsing is bad
  20326. partialre = this.regExp;
  20327. console.warn('RegExp error in ' + this.declaredClass + ': ' + this.regExp);
  20328. } // should never be here unless the original RE is bad or the parsing is bad
  20329. this._partialre = "^(?:" + partialre + ")$";
  20330. },
  20331. postMixInProperties: function(){
  20332. this.inherited(arguments);
  20333. this.messages = i18n.getLocalization("dijit.form", "validate", this.lang);
  20334. if(this.invalidMessage == "$_unset_$"){ this.invalidMessage = this.messages.invalidMessage; }
  20335. if(!this.invalidMessage){ this.invalidMessage = this.promptMessage; }
  20336. if(this.missingMessage == "$_unset_$"){ this.missingMessage = this.messages.missingMessage; }
  20337. if(!this.missingMessage){ this.missingMessage = this.invalidMessage; }
  20338. this._setConstraintsAttr(this.constraints); // this needs to happen now (and later) due to codependency on _set*Attr calls attachPoints
  20339. },
  20340. _setDisabledAttr: function(/*Boolean*/ value){
  20341. this.inherited(arguments); // call FormValueWidget._setDisabledAttr()
  20342. this._refreshState();
  20343. },
  20344. _setRequiredAttr: function(/*Boolean*/ value){
  20345. this._set("required", value);
  20346. this.focusNode.setAttribute("aria-required", value);
  20347. this._refreshState();
  20348. },
  20349. _setMessageAttr: function(/*String*/ message){
  20350. this._set("message", message);
  20351. this.displayMessage(message);
  20352. },
  20353. reset:function(){
  20354. // Overrides dijit.form.TextBox.reset() by also
  20355. // hiding errors about partial matches
  20356. this._maskValidSubsetError = true;
  20357. this.inherited(arguments);
  20358. },
  20359. _onBlur: function(){
  20360. // the message still exists but for back-compat, and to erase the tooltip
  20361. // (if the message is being displayed as a tooltip), call displayMessage('')
  20362. this.displayMessage('');
  20363. this.inherited(arguments);
  20364. }
  20365. });
  20366. });
  20367. },
  20368. 'dijit/layout/BorderContainer':function(){
  20369. define([
  20370. "dojo/_base/array", // array.filter array.forEach array.map
  20371. "dojo/cookie", // cookie
  20372. "dojo/_base/declare", // declare
  20373. "dojo/dom-class", // domClass.add domClass.remove domClass.toggle
  20374. "dojo/dom-construct", // domConstruct.destroy domConstruct.place
  20375. "dojo/dom-geometry", // domGeometry.marginBox
  20376. "dojo/dom-style", // domStyle.style
  20377. "dojo/_base/event", // event.stop
  20378. "dojo/keys",
  20379. "dojo/_base/lang", // lang.getObject lang.hitch
  20380. "dojo/on",
  20381. "dojo/touch",
  20382. "dojo/_base/window", // win.body win.doc win.doc.createElement
  20383. "../_WidgetBase",
  20384. "../_Widget",
  20385. "../_TemplatedMixin",
  20386. "./_LayoutWidget",
  20387. "./utils" // layoutUtils.layoutChildren
  20388. ], function(array, cookie, declare, domClass, domConstruct, domGeometry, domStyle, event, keys, lang, on, touch, win,
  20389. _WidgetBase, _Widget, _TemplatedMixin, _LayoutWidget, layoutUtils){
  20390. /*=====
  20391. var _WidgetBase = dijit._WidgetBase;
  20392. var _Widget = dijit._Widget;
  20393. var _TemplatedMixin = dijit._TemplatedMixin;
  20394. var _LayoutWidget = dijit.layout._LayoutWidget;
  20395. =====*/
  20396. // module:
  20397. // dijit/layout/BorderContainer
  20398. // summary:
  20399. // Provides layout in up to 5 regions, a mandatory center with optional borders along its 4 sides.
  20400. var _Splitter = declare("dijit.layout._Splitter", [_Widget, _TemplatedMixin ],
  20401. {
  20402. // summary:
  20403. // A draggable spacer between two items in a `dijit.layout.BorderContainer`.
  20404. // description:
  20405. // This is instantiated by `dijit.layout.BorderContainer`. Users should not
  20406. // create it directly.
  20407. // tags:
  20408. // private
  20409. /*=====
  20410. // container: [const] dijit.layout.BorderContainer
  20411. // Pointer to the parent BorderContainer
  20412. container: null,
  20413. // child: [const] dijit.layout._LayoutWidget
  20414. // Pointer to the pane associated with this splitter
  20415. child: null,
  20416. // region: [const] String
  20417. // Region of pane associated with this splitter.
  20418. // "top", "bottom", "left", "right".
  20419. region: null,
  20420. =====*/
  20421. // live: [const] Boolean
  20422. // If true, the child's size changes and the child widget is redrawn as you drag the splitter;
  20423. // otherwise, the size doesn't change until you drop the splitter (by mouse-up)
  20424. live: true,
  20425. templateString: '<div class="dijitSplitter" data-dojo-attach-event="onkeypress:_onKeyPress,press:_startDrag,onmouseenter:_onMouse,onmouseleave:_onMouse" tabIndex="0" role="separator"><div class="dijitSplitterThumb"></div></div>',
  20426. constructor: function(){
  20427. this._handlers = [];
  20428. },
  20429. postMixInProperties: function(){
  20430. this.inherited(arguments);
  20431. this.horizontal = /top|bottom/.test(this.region);
  20432. this._factor = /top|left/.test(this.region) ? 1 : -1;
  20433. this._cookieName = this.container.id + "_" + this.region;
  20434. },
  20435. buildRendering: function(){
  20436. this.inherited(arguments);
  20437. domClass.add(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V"));
  20438. if(this.container.persist){
  20439. // restore old size
  20440. var persistSize = cookie(this._cookieName);
  20441. if(persistSize){
  20442. this.child.domNode.style[this.horizontal ? "height" : "width"] = persistSize;
  20443. }
  20444. }
  20445. },
  20446. _computeMaxSize: function(){
  20447. // summary:
  20448. // Return the maximum size that my corresponding pane can be set to
  20449. var dim = this.horizontal ? 'h' : 'w',
  20450. childSize = domGeometry.getMarginBox(this.child.domNode)[dim],
  20451. center = array.filter(this.container.getChildren(), function(child){ return child.region == "center";})[0],
  20452. spaceAvailable = domGeometry.getMarginBox(center.domNode)[dim]; // can expand until center is crushed to 0
  20453. return Math.min(this.child.maxSize, childSize + spaceAvailable);
  20454. },
  20455. _startDrag: function(e){
  20456. if(!this.cover){
  20457. this.cover = win.doc.createElement('div');
  20458. domClass.add(this.cover, "dijitSplitterCover");
  20459. domConstruct.place(this.cover, this.child.domNode, "after");
  20460. }
  20461. domClass.add(this.cover, "dijitSplitterCoverActive");
  20462. // Safeguard in case the stop event was missed. Shouldn't be necessary if we always get the mouse up.
  20463. if(this.fake){ domConstruct.destroy(this.fake); }
  20464. if(!(this._resize = this.live)){ //TODO: disable live for IE6?
  20465. // create fake splitter to display at old position while we drag
  20466. (this.fake = this.domNode.cloneNode(true)).removeAttribute("id");
  20467. domClass.add(this.domNode, "dijitSplitterShadow");
  20468. domConstruct.place(this.fake, this.domNode, "after");
  20469. }
  20470. domClass.add(this.domNode, "dijitSplitterActive dijitSplitter" + (this.horizontal ? "H" : "V") + "Active");
  20471. if(this.fake){
  20472. domClass.remove(this.fake, "dijitSplitterHover dijitSplitter" + (this.horizontal ? "H" : "V") + "Hover");
  20473. }
  20474. //Performance: load data info local vars for onmousevent function closure
  20475. var factor = this._factor,
  20476. isHorizontal = this.horizontal,
  20477. axis = isHorizontal ? "pageY" : "pageX",
  20478. pageStart = e[axis],
  20479. splitterStyle = this.domNode.style,
  20480. dim = isHorizontal ? 'h' : 'w',
  20481. childStart = domGeometry.getMarginBox(this.child.domNode)[dim],
  20482. max = this._computeMaxSize(),
  20483. min = this.child.minSize || 20,
  20484. region = this.region,
  20485. splitterAttr = region == "top" || region == "bottom" ? "top" : "left", // style attribute of splitter to adjust
  20486. splitterStart = parseInt(splitterStyle[splitterAttr], 10),
  20487. resize = this._resize,
  20488. layoutFunc = lang.hitch(this.container, "_layoutChildren", this.child.id),
  20489. de = win.doc;
  20490. this._handlers = this._handlers.concat([
  20491. on(de, touch.move, this._drag = function(e, forceResize){
  20492. var delta = e[axis] - pageStart,
  20493. childSize = factor * delta + childStart,
  20494. boundChildSize = Math.max(Math.min(childSize, max), min);
  20495. if(resize || forceResize){
  20496. layoutFunc(boundChildSize);
  20497. }
  20498. // TODO: setting style directly (usually) sets content box size, need to set margin box size
  20499. splitterStyle[splitterAttr] = delta + splitterStart + factor*(boundChildSize - childSize) + "px";
  20500. }),
  20501. on(de, "dragstart", event.stop),
  20502. on(win.body(), "selectstart", event.stop),
  20503. on(de, touch.release, lang.hitch(this, "_stopDrag"))
  20504. ]);
  20505. event.stop(e);
  20506. },
  20507. _onMouse: function(e){
  20508. // summary:
  20509. // Handler for onmouseenter / onmouseleave events
  20510. var o = (e.type == "mouseover" || e.type == "mouseenter");
  20511. domClass.toggle(this.domNode, "dijitSplitterHover", o);
  20512. domClass.toggle(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V") + "Hover", o);
  20513. },
  20514. _stopDrag: function(e){
  20515. try{
  20516. if(this.cover){
  20517. domClass.remove(this.cover, "dijitSplitterCoverActive");
  20518. }
  20519. if(this.fake){ domConstruct.destroy(this.fake); }
  20520. domClass.remove(this.domNode, "dijitSplitterActive dijitSplitter"
  20521. + (this.horizontal ? "H" : "V") + "Active dijitSplitterShadow");
  20522. this._drag(e); //TODO: redundant with onmousemove?
  20523. this._drag(e, true);
  20524. }finally{
  20525. this._cleanupHandlers();
  20526. delete this._drag;
  20527. }
  20528. if(this.container.persist){
  20529. cookie(this._cookieName, this.child.domNode.style[this.horizontal ? "height" : "width"], {expires:365});
  20530. }
  20531. },
  20532. _cleanupHandlers: function(){
  20533. var h;
  20534. while(h = this._handlers.pop()){ h.remove(); }
  20535. },
  20536. _onKeyPress: function(/*Event*/ e){
  20537. // should we apply typematic to this?
  20538. this._resize = true;
  20539. var horizontal = this.horizontal;
  20540. var tick = 1;
  20541. switch(e.charOrCode){
  20542. case horizontal ? keys.UP_ARROW : keys.LEFT_ARROW:
  20543. tick *= -1;
  20544. // break;
  20545. case horizontal ? keys.DOWN_ARROW : keys.RIGHT_ARROW:
  20546. break;
  20547. default:
  20548. // this.inherited(arguments);
  20549. return;
  20550. }
  20551. var childSize = domGeometry.getMarginSize(this.child.domNode)[ horizontal ? 'h' : 'w' ] + this._factor * tick;
  20552. this.container._layoutChildren(this.child.id, Math.max(Math.min(childSize, this._computeMaxSize()), this.child.minSize));
  20553. event.stop(e);
  20554. },
  20555. destroy: function(){
  20556. this._cleanupHandlers();
  20557. delete this.child;
  20558. delete this.container;
  20559. delete this.cover;
  20560. delete this.fake;
  20561. this.inherited(arguments);
  20562. }
  20563. });
  20564. var _Gutter = declare("dijit.layout._Gutter", [_Widget, _TemplatedMixin],
  20565. {
  20566. // summary:
  20567. // Just a spacer div to separate side pane from center pane.
  20568. // Basically a trick to lookup the gutter/splitter width from the theme.
  20569. // description:
  20570. // Instantiated by `dijit.layout.BorderContainer`. Users should not
  20571. // create directly.
  20572. // tags:
  20573. // private
  20574. templateString: '<div class="dijitGutter" role="presentation"></div>',
  20575. postMixInProperties: function(){
  20576. this.inherited(arguments);
  20577. this.horizontal = /top|bottom/.test(this.region);
  20578. },
  20579. buildRendering: function(){
  20580. this.inherited(arguments);
  20581. domClass.add(this.domNode, "dijitGutter" + (this.horizontal ? "H" : "V"));
  20582. }
  20583. });
  20584. var BorderContainer = declare("dijit.layout.BorderContainer", _LayoutWidget, {
  20585. // summary:
  20586. // Provides layout in up to 5 regions, a mandatory center with optional borders along its 4 sides.
  20587. //
  20588. // description:
  20589. // A BorderContainer is a box with a specified size, such as style="width: 500px; height: 500px;",
  20590. // that contains a child widget marked region="center" and optionally children widgets marked
  20591. // region equal to "top", "bottom", "leading", "trailing", "left" or "right".
  20592. // Children along the edges will be laid out according to width or height dimensions and may
  20593. // include optional splitters (splitter="true") to make them resizable by the user. The remaining
  20594. // space is designated for the center region.
  20595. //
  20596. // The outer size must be specified on the BorderContainer node. Width must be specified for the sides
  20597. // and height for the top and bottom, respectively. No dimensions should be specified on the center;
  20598. // it will fill the remaining space. Regions named "leading" and "trailing" may be used just like
  20599. // "left" and "right" except that they will be reversed in right-to-left environments.
  20600. //
  20601. // For complex layouts, multiple children can be specified for a single region. In this case, the
  20602. // layoutPriority flag on the children determines which child is closer to the edge (low layoutPriority)
  20603. // and which child is closer to the center (high layoutPriority). layoutPriority can also be used
  20604. // instead of the design attribute to control layout precedence of horizontal vs. vertical panes.
  20605. // example:
  20606. // | <div data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design: 'sidebar', gutters: false"
  20607. // | style="width: 400px; height: 300px;">
  20608. // | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region: 'top'">header text</div>
  20609. // | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region: 'right', splitter: true" style="width: 200px;">table of contents</div>
  20610. // | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region: 'center'">client area</div>
  20611. // | </div>
  20612. // design: String
  20613. // Which design is used for the layout:
  20614. // - "headline" (default) where the top and bottom extend
  20615. // the full width of the container
  20616. // - "sidebar" where the left and right sides extend from top to bottom.
  20617. design: "headline",
  20618. // gutters: [const] Boolean
  20619. // Give each pane a border and margin.
  20620. // Margin determined by domNode.paddingLeft.
  20621. // When false, only resizable panes have a gutter (i.e. draggable splitter) for resizing.
  20622. gutters: true,
  20623. // liveSplitters: [const] Boolean
  20624. // Specifies whether splitters resize as you drag (true) or only upon mouseup (false)
  20625. liveSplitters: true,
  20626. // persist: Boolean
  20627. // Save splitter positions in a cookie.
  20628. persist: false,
  20629. baseClass: "dijitBorderContainer",
  20630. // _splitterClass: Function||String
  20631. // Optional hook to override the default Splitter widget used by BorderContainer
  20632. _splitterClass: _Splitter,
  20633. postMixInProperties: function(){
  20634. // change class name to indicate that BorderContainer is being used purely for
  20635. // layout (like LayoutContainer) rather than for pretty formatting.
  20636. if(!this.gutters){
  20637. this.baseClass += "NoGutter";
  20638. }
  20639. this.inherited(arguments);
  20640. },
  20641. startup: function(){
  20642. if(this._started){ return; }
  20643. array.forEach(this.getChildren(), this._setupChild, this);
  20644. this.inherited(arguments);
  20645. },
  20646. _setupChild: function(/*dijit._Widget*/ child){
  20647. // Override _LayoutWidget._setupChild().
  20648. var region = child.region;
  20649. if(region){
  20650. this.inherited(arguments);
  20651. domClass.add(child.domNode, this.baseClass+"Pane");
  20652. var ltr = this.isLeftToRight();
  20653. if(region == "leading"){ region = ltr ? "left" : "right"; }
  20654. if(region == "trailing"){ region = ltr ? "right" : "left"; }
  20655. // Create draggable splitter for resizing pane,
  20656. // or alternately if splitter=false but BorderContainer.gutters=true then
  20657. // insert dummy div just for spacing
  20658. if(region != "center" && (child.splitter || this.gutters) && !child._splitterWidget){
  20659. var _Splitter = child.splitter ? this._splitterClass : _Gutter;
  20660. if(lang.isString(_Splitter)){
  20661. _Splitter = lang.getObject(_Splitter); // for back-compat, remove in 2.0
  20662. }
  20663. var splitter = new _Splitter({
  20664. id: child.id + "_splitter",
  20665. container: this,
  20666. child: child,
  20667. region: region,
  20668. live: this.liveSplitters
  20669. });
  20670. splitter.isSplitter = true;
  20671. child._splitterWidget = splitter;
  20672. domConstruct.place(splitter.domNode, child.domNode, "after");
  20673. // Splitters aren't added as Contained children, so we need to call startup explicitly
  20674. splitter.startup();
  20675. }
  20676. child.region = region; // TODO: technically wrong since it overwrites "trailing" with "left" etc.
  20677. }
  20678. },
  20679. layout: function(){
  20680. // Implement _LayoutWidget.layout() virtual method.
  20681. this._layoutChildren();
  20682. },
  20683. addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
  20684. // Override _LayoutWidget.addChild().
  20685. this.inherited(arguments);
  20686. if(this._started){
  20687. this.layout(); //OPT
  20688. }
  20689. },
  20690. removeChild: function(/*dijit._Widget*/ child){
  20691. // Override _LayoutWidget.removeChild().
  20692. var region = child.region;
  20693. var splitter = child._splitterWidget;
  20694. if(splitter){
  20695. splitter.destroy();
  20696. delete child._splitterWidget;
  20697. }
  20698. this.inherited(arguments);
  20699. if(this._started){
  20700. this._layoutChildren();
  20701. }
  20702. // Clean up whatever style changes we made to the child pane.
  20703. // Unclear how height and width should be handled.
  20704. domClass.remove(child.domNode, this.baseClass+"Pane");
  20705. domStyle.set(child.domNode, {
  20706. top: "auto",
  20707. bottom: "auto",
  20708. left: "auto",
  20709. right: "auto",
  20710. position: "static"
  20711. });
  20712. domStyle.set(child.domNode, region == "top" || region == "bottom" ? "width" : "height", "auto");
  20713. },
  20714. getChildren: function(){
  20715. // Override _LayoutWidget.getChildren() to only return real children, not the splitters.
  20716. return array.filter(this.inherited(arguments), function(widget){
  20717. return !widget.isSplitter;
  20718. });
  20719. },
  20720. // TODO: remove in 2.0
  20721. getSplitter: function(/*String*/region){
  20722. // summary:
  20723. // Returns the widget responsible for rendering the splitter associated with region
  20724. // tags:
  20725. // deprecated
  20726. return array.filter(this.getChildren(), function(child){
  20727. return child.region == region;
  20728. })[0]._splitterWidget;
  20729. },
  20730. resize: function(newSize, currentSize){
  20731. // Overrides _LayoutWidget.resize().
  20732. // resetting potential padding to 0px to provide support for 100% width/height + padding
  20733. // TODO: this hack doesn't respect the box model and is a temporary fix
  20734. if(!this.cs || !this.pe){
  20735. var node = this.domNode;
  20736. this.cs = domStyle.getComputedStyle(node);
  20737. this.pe = domGeometry.getPadExtents(node, this.cs);
  20738. this.pe.r = domStyle.toPixelValue(node, this.cs.paddingRight);
  20739. this.pe.b = domStyle.toPixelValue(node, this.cs.paddingBottom);
  20740. domStyle.set(node, "padding", "0px");
  20741. }
  20742. this.inherited(arguments);
  20743. },
  20744. _layoutChildren: function(/*String?*/ changedChildId, /*Number?*/ changedChildSize){
  20745. // summary:
  20746. // This is the main routine for setting size/position of each child.
  20747. // description:
  20748. // With no arguments, measures the height of top/bottom panes, the width
  20749. // of left/right panes, and then sizes all panes accordingly.
  20750. //
  20751. // With changedRegion specified (as "left", "top", "bottom", or "right"),
  20752. // it changes that region's width/height to changedRegionSize and
  20753. // then resizes other regions that were affected.
  20754. // changedChildId:
  20755. // Id of the child which should be resized because splitter was dragged.
  20756. // changedChildSize:
  20757. // The new width/height (in pixels) to make specified child
  20758. if(!this._borderBox || !this._borderBox.h){
  20759. // We are currently hidden, or we haven't been sized by our parent yet.
  20760. // Abort. Someone will resize us later.
  20761. return;
  20762. }
  20763. // Generate list of wrappers of my children in the order that I want layoutChildren()
  20764. // to process them (i.e. from the outside to the inside)
  20765. var wrappers = array.map(this.getChildren(), function(child, idx){
  20766. return {
  20767. pane: child,
  20768. weight: [
  20769. child.region == "center" ? Infinity : 0,
  20770. child.layoutPriority,
  20771. (this.design == "sidebar" ? 1 : -1) * (/top|bottom/.test(child.region) ? 1 : -1),
  20772. idx
  20773. ]
  20774. };
  20775. }, this);
  20776. wrappers.sort(function(a, b){
  20777. var aw = a.weight, bw = b.weight;
  20778. for(var i=0; i<aw.length; i++){
  20779. if(aw[i] != bw[i]){
  20780. return aw[i] - bw[i];
  20781. }
  20782. }
  20783. return 0;
  20784. });
  20785. // Make new list, combining the externally specified children with splitters and gutters
  20786. var childrenAndSplitters = [];
  20787. array.forEach(wrappers, function(wrapper){
  20788. var pane = wrapper.pane;
  20789. childrenAndSplitters.push(pane);
  20790. if(pane._splitterWidget){
  20791. childrenAndSplitters.push(pane._splitterWidget);
  20792. }
  20793. });
  20794. // Compute the box in which to lay out my children
  20795. var dim = {
  20796. l: this.pe.l,
  20797. t: this.pe.t,
  20798. w: this._borderBox.w - this.pe.w,
  20799. h: this._borderBox.h - this.pe.h
  20800. };
  20801. // Layout the children, possibly changing size due to a splitter drag
  20802. layoutUtils.layoutChildren(this.domNode, dim, childrenAndSplitters,
  20803. changedChildId, changedChildSize);
  20804. },
  20805. destroyRecursive: function(){
  20806. // Destroy splitters first, while getChildren() still works
  20807. array.forEach(this.getChildren(), function(child){
  20808. var splitter = child._splitterWidget;
  20809. if(splitter){
  20810. splitter.destroy();
  20811. }
  20812. delete child._splitterWidget;
  20813. });
  20814. // Then destroy the real children, and myself
  20815. this.inherited(arguments);
  20816. }
  20817. });
  20818. // This argument can be specified for the children of a BorderContainer.
  20819. // Since any widget can be specified as a LayoutContainer child, mix it
  20820. // into the base widget class. (This is a hack, but it's effective.)
  20821. lang.extend(_WidgetBase, {
  20822. // region: [const] String
  20823. // Parameter for children of `dijit.layout.BorderContainer`.
  20824. // Values: "top", "bottom", "leading", "trailing", "left", "right", "center".
  20825. // See the `dijit.layout.BorderContainer` description for details.
  20826. region: '',
  20827. // layoutPriority: [const] Number
  20828. // Parameter for children of `dijit.layout.BorderContainer`.
  20829. // Children with a higher layoutPriority will be placed closer to the BorderContainer center,
  20830. // between children with a lower layoutPriority.
  20831. layoutPriority: 0,
  20832. // splitter: [const] Boolean
  20833. // Parameter for child of `dijit.layout.BorderContainer` where region != "center".
  20834. // If true, enables user to resize the widget by putting a draggable splitter between
  20835. // this widget and the region=center widget.
  20836. splitter: false,
  20837. // minSize: [const] Number
  20838. // Parameter for children of `dijit.layout.BorderContainer`.
  20839. // Specifies a minimum size (in pixels) for this widget when resized by a splitter.
  20840. minSize: 0,
  20841. // maxSize: [const] Number
  20842. // Parameter for children of `dijit.layout.BorderContainer`.
  20843. // Specifies a maximum size (in pixels) for this widget when resized by a splitter.
  20844. maxSize: Infinity
  20845. });
  20846. // For monkey patching
  20847. BorderContainer._Splitter = _Splitter;
  20848. BorderContainer._Gutter = _Gutter;
  20849. return BorderContainer;
  20850. });
  20851. },
  20852. 'dojo/number':function(){
  20853. define(["./_base/kernel", "./_base/lang", "./i18n", "./i18n!./cldr/nls/number", "./string", "./regexp"],
  20854. function(dojo, lang, i18n, nlsNumber, dstring, dregexp) {
  20855. // module:
  20856. // dojo/number
  20857. // summary:
  20858. // TODOC
  20859. lang.getObject("number", true, dojo);
  20860. /*=====
  20861. dojo.number = {
  20862. // summary: localized formatting and parsing routines for Number
  20863. }
  20864. dojo.number.__FormatOptions = function(){
  20865. // pattern: String?
  20866. // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  20867. // with this string. Default value is based on locale. Overriding this property will defeat
  20868. // localization. Literal characters in patterns are not supported.
  20869. // type: String?
  20870. // choose a format type based on the locale from the following:
  20871. // decimal, scientific (not yet supported), percent, currency. decimal by default.
  20872. // places: Number?
  20873. // fixed number of decimal places to show. This overrides any
  20874. // information in the provided pattern.
  20875. // round: Number?
  20876. // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
  20877. // means do not round.
  20878. // locale: String?
  20879. // override the locale used to determine formatting rules
  20880. // fractional: Boolean?
  20881. // If false, show no decimal places, overriding places and pattern settings.
  20882. this.pattern = pattern;
  20883. this.type = type;
  20884. this.places = places;
  20885. this.round = round;
  20886. this.locale = locale;
  20887. this.fractional = fractional;
  20888. }
  20889. =====*/
  20890. dojo.number.format = function(/*Number*/value, /*dojo.number.__FormatOptions?*/options){
  20891. // summary:
  20892. // Format a Number as a String, using locale-specific settings
  20893. // description:
  20894. // Create a string from a Number using a known localized pattern.
  20895. // Formatting patterns appropriate to the locale are chosen from the
  20896. // [Common Locale Data Repository](http://unicode.org/cldr) as well as the appropriate symbols and
  20897. // delimiters.
  20898. // If value is Infinity, -Infinity, or is not a valid JavaScript number, return null.
  20899. // value:
  20900. // the number to be formatted
  20901. options = lang.mixin({}, options || {});
  20902. var locale = i18n.normalizeLocale(options.locale),
  20903. bundle = i18n.getLocalization("dojo.cldr", "number", locale);
  20904. options.customs = bundle;
  20905. var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"];
  20906. if(isNaN(value) || Math.abs(value) == Infinity){ return null; } // null
  20907. return dojo.number._applyPattern(value, pattern, options); // String
  20908. };
  20909. //dojo.number._numberPatternRE = /(?:[#0]*,?)*[#0](?:\.0*#*)?/; // not precise, but good enough
  20910. dojo.number._numberPatternRE = /[#0,]*[#0](?:\.0*#*)?/; // not precise, but good enough
  20911. dojo.number._applyPattern = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatOptions?*/options){
  20912. // summary:
  20913. // Apply pattern to format value as a string using options. Gives no
  20914. // consideration to local customs.
  20915. // value:
  20916. // the number to be formatted.
  20917. // pattern:
  20918. // a pattern string as described by
  20919. // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  20920. // options: dojo.number.__FormatOptions?
  20921. // _applyPattern is usually called via `dojo.number.format()` which
  20922. // populates an extra property in the options parameter, "customs".
  20923. // The customs object specifies group and decimal parameters if set.
  20924. //TODO: support escapes
  20925. options = options || {};
  20926. var group = options.customs.group,
  20927. decimal = options.customs.decimal,
  20928. patternList = pattern.split(';'),
  20929. positivePattern = patternList[0];
  20930. pattern = patternList[(value < 0) ? 1 : 0] || ("-" + positivePattern);
  20931. //TODO: only test against unescaped
  20932. if(pattern.indexOf('%') != -1){
  20933. value *= 100;
  20934. }else if(pattern.indexOf('\u2030') != -1){
  20935. value *= 1000; // per mille
  20936. }else if(pattern.indexOf('\u00a4') != -1){
  20937. group = options.customs.currencyGroup || group;//mixins instead?
  20938. decimal = options.customs.currencyDecimal || decimal;// Should these be mixins instead?
  20939. pattern = pattern.replace(/\u00a4{1,3}/, function(match){
  20940. var prop = ["symbol", "currency", "displayName"][match.length-1];
  20941. return options[prop] || options.currency || "";
  20942. });
  20943. }else if(pattern.indexOf('E') != -1){
  20944. throw new Error("exponential notation not supported");
  20945. }
  20946. //TODO: support @ sig figs?
  20947. var numberPatternRE = dojo.number._numberPatternRE;
  20948. var numberPattern = positivePattern.match(numberPatternRE);
  20949. if(!numberPattern){
  20950. throw new Error("unable to find a number expression in pattern: "+pattern);
  20951. }
  20952. if(options.fractional === false){ options.places = 0; }
  20953. return pattern.replace(numberPatternRE,
  20954. dojo.number._formatAbsolute(value, numberPattern[0], {decimal: decimal, group: group, places: options.places, round: options.round}));
  20955. };
  20956. dojo.number.round = function(/*Number*/value, /*Number?*/places, /*Number?*/increment){
  20957. // summary:
  20958. // Rounds to the nearest value with the given number of decimal places, away from zero
  20959. // description:
  20960. // Rounds to the nearest value with the given number of decimal places, away from zero if equal.
  20961. // Similar to Number.toFixed(), but compensates for browser quirks. Rounding can be done by
  20962. // fractional increments also, such as the nearest quarter.
  20963. // NOTE: Subject to floating point errors. See dojox.math.round for experimental workaround.
  20964. // value:
  20965. // The number to round
  20966. // places:
  20967. // The number of decimal places where rounding takes place. Defaults to 0 for whole rounding.
  20968. // Must be non-negative.
  20969. // increment:
  20970. // Rounds next place to nearest value of increment/10. 10 by default.
  20971. // example:
  20972. // >>> dojo.number.round(-0.5)
  20973. // -1
  20974. // >>> dojo.number.round(162.295, 2)
  20975. // 162.29 // note floating point error. Should be 162.3
  20976. // >>> dojo.number.round(10.71, 0, 2.5)
  20977. // 10.75
  20978. var factor = 10 / (increment || 10);
  20979. return (factor * +value).toFixed(places) / factor; // Number
  20980. };
  20981. if((0.9).toFixed() == 0){
  20982. // (isIE) toFixed() bug workaround: Rounding fails on IE when most significant digit
  20983. // is just after the rounding place and is >=5
  20984. var round = dojo.number.round;
  20985. dojo.number.round = function(v, p, m){
  20986. var d = Math.pow(10, -p || 0), a = Math.abs(v);
  20987. if(!v || a >= d){
  20988. d = 0;
  20989. }else{
  20990. a /= d;
  20991. if(a < 0.5 || a >= 0.95){
  20992. d = 0;
  20993. }
  20994. }
  20995. return round(v, p, m) + (v > 0 ? d : -d);
  20996. };
  20997. }
  20998. /*=====
  20999. dojo.number.__FormatAbsoluteOptions = function(){
  21000. // decimal: String?
  21001. // the decimal separator
  21002. // group: String?
  21003. // the group separator
  21004. // places: Number?|String?
  21005. // number of decimal places. the range "n,m" will format to m places.
  21006. // round: Number?
  21007. // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
  21008. // means don't round.
  21009. this.decimal = decimal;
  21010. this.group = group;
  21011. this.places = places;
  21012. this.round = round;
  21013. }
  21014. =====*/
  21015. dojo.number._formatAbsolute = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatAbsoluteOptions?*/options){
  21016. // summary:
  21017. // Apply numeric pattern to absolute value using options. Gives no
  21018. // consideration to local customs.
  21019. // value:
  21020. // the number to be formatted, ignores sign
  21021. // pattern:
  21022. // the number portion of a pattern (e.g. `#,##0.00`)
  21023. options = options || {};
  21024. if(options.places === true){options.places=0;}
  21025. if(options.places === Infinity){options.places=6;} // avoid a loop; pick a limit
  21026. var patternParts = pattern.split("."),
  21027. comma = typeof options.places == "string" && options.places.indexOf(","),
  21028. maxPlaces = options.places;
  21029. if(comma){
  21030. maxPlaces = options.places.substring(comma + 1);
  21031. }else if(!(maxPlaces >= 0)){
  21032. maxPlaces = (patternParts[1] || []).length;
  21033. }
  21034. if(!(options.round < 0)){
  21035. value = dojo.number.round(value, maxPlaces, options.round);
  21036. }
  21037. var valueParts = String(Math.abs(value)).split("."),
  21038. fractional = valueParts[1] || "";
  21039. if(patternParts[1] || options.places){
  21040. if(comma){
  21041. options.places = options.places.substring(0, comma);
  21042. }
  21043. // Pad fractional with trailing zeros
  21044. var pad = options.places !== undefined ? options.places : (patternParts[1] && patternParts[1].lastIndexOf("0") + 1);
  21045. if(pad > fractional.length){
  21046. valueParts[1] = dstring.pad(fractional, pad, '0', true);
  21047. }
  21048. // Truncate fractional
  21049. if(maxPlaces < fractional.length){
  21050. valueParts[1] = fractional.substr(0, maxPlaces);
  21051. }
  21052. }else{
  21053. if(valueParts[1]){ valueParts.pop(); }
  21054. }
  21055. // Pad whole with leading zeros
  21056. var patternDigits = patternParts[0].replace(',', '');
  21057. pad = patternDigits.indexOf("0");
  21058. if(pad != -1){
  21059. pad = patternDigits.length - pad;
  21060. if(pad > valueParts[0].length){
  21061. valueParts[0] = dstring.pad(valueParts[0], pad);
  21062. }
  21063. // Truncate whole
  21064. if(patternDigits.indexOf("#") == -1){
  21065. valueParts[0] = valueParts[0].substr(valueParts[0].length - pad);
  21066. }
  21067. }
  21068. // Add group separators
  21069. var index = patternParts[0].lastIndexOf(','),
  21070. groupSize, groupSize2;
  21071. if(index != -1){
  21072. groupSize = patternParts[0].length - index - 1;
  21073. var remainder = patternParts[0].substr(0, index);
  21074. index = remainder.lastIndexOf(',');
  21075. if(index != -1){
  21076. groupSize2 = remainder.length - index - 1;
  21077. }
  21078. }
  21079. var pieces = [];
  21080. for(var whole = valueParts[0]; whole;){
  21081. var off = whole.length - groupSize;
  21082. pieces.push((off > 0) ? whole.substr(off) : whole);
  21083. whole = (off > 0) ? whole.slice(0, off) : "";
  21084. if(groupSize2){
  21085. groupSize = groupSize2;
  21086. delete groupSize2;
  21087. }
  21088. }
  21089. valueParts[0] = pieces.reverse().join(options.group || ",");
  21090. return valueParts.join(options.decimal || ".");
  21091. };
  21092. /*=====
  21093. dojo.number.__RegexpOptions = function(){
  21094. // pattern: String?
  21095. // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  21096. // with this string. Default value is based on locale. Overriding this property will defeat
  21097. // localization.
  21098. // type: String?
  21099. // choose a format type based on the locale from the following:
  21100. // decimal, scientific (not yet supported), percent, currency. decimal by default.
  21101. // locale: String?
  21102. // override the locale used to determine formatting rules
  21103. // strict: Boolean?
  21104. // strict parsing, false by default. Strict parsing requires input as produced by the format() method.
  21105. // Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators
  21106. // places: Number|String?
  21107. // number of decimal places to accept: Infinity, a positive number, or
  21108. // a range "n,m". Defined by pattern or Infinity if pattern not provided.
  21109. this.pattern = pattern;
  21110. this.type = type;
  21111. this.locale = locale;
  21112. this.strict = strict;
  21113. this.places = places;
  21114. }
  21115. =====*/
  21116. dojo.number.regexp = function(/*dojo.number.__RegexpOptions?*/options){
  21117. // summary:
  21118. // Builds the regular needed to parse a number
  21119. // description:
  21120. // Returns regular expression with positive and negative match, group
  21121. // and decimal separators
  21122. return dojo.number._parseInfo(options).regexp; // String
  21123. };
  21124. dojo.number._parseInfo = function(/*Object?*/options){
  21125. options = options || {};
  21126. var locale = i18n.normalizeLocale(options.locale),
  21127. bundle = i18n.getLocalization("dojo.cldr", "number", locale),
  21128. pattern = options.pattern || bundle[(options.type || "decimal") + "Format"],
  21129. //TODO: memoize?
  21130. group = bundle.group,
  21131. decimal = bundle.decimal,
  21132. factor = 1;
  21133. if(pattern.indexOf('%') != -1){
  21134. factor /= 100;
  21135. }else if(pattern.indexOf('\u2030') != -1){
  21136. factor /= 1000; // per mille
  21137. }else{
  21138. var isCurrency = pattern.indexOf('\u00a4') != -1;
  21139. if(isCurrency){
  21140. group = bundle.currencyGroup || group;
  21141. decimal = bundle.currencyDecimal || decimal;
  21142. }
  21143. }
  21144. //TODO: handle quoted escapes
  21145. var patternList = pattern.split(';');
  21146. if(patternList.length == 1){
  21147. patternList.push("-" + patternList[0]);
  21148. }
  21149. var re = dregexp.buildGroupRE(patternList, function(pattern){
  21150. pattern = "(?:"+dregexp.escapeString(pattern, '.')+")";
  21151. return pattern.replace(dojo.number._numberPatternRE, function(format){
  21152. var flags = {
  21153. signed: false,
  21154. separator: options.strict ? group : [group,""],
  21155. fractional: options.fractional,
  21156. decimal: decimal,
  21157. exponent: false
  21158. },
  21159. parts = format.split('.'),
  21160. places = options.places;
  21161. // special condition for percent (factor != 1)
  21162. // allow decimal places even if not specified in pattern
  21163. if(parts.length == 1 && factor != 1){
  21164. parts[1] = "###";
  21165. }
  21166. if(parts.length == 1 || places === 0){
  21167. flags.fractional = false;
  21168. }else{
  21169. if(places === undefined){ places = options.pattern ? parts[1].lastIndexOf('0') + 1 : Infinity; }
  21170. if(places && options.fractional == undefined){flags.fractional = true;} // required fractional, unless otherwise specified
  21171. if(!options.places && (places < parts[1].length)){ places += "," + parts[1].length; }
  21172. flags.places = places;
  21173. }
  21174. var groups = parts[0].split(',');
  21175. if(groups.length > 1){
  21176. flags.groupSize = groups.pop().length;
  21177. if(groups.length > 1){
  21178. flags.groupSize2 = groups.pop().length;
  21179. }
  21180. }
  21181. return "("+dojo.number._realNumberRegexp(flags)+")";
  21182. });
  21183. }, true);
  21184. if(isCurrency){
  21185. // substitute the currency symbol for the placeholder in the pattern
  21186. re = re.replace(/([\s\xa0]*)(\u00a4{1,3})([\s\xa0]*)/g, function(match, before, target, after){
  21187. var prop = ["symbol", "currency", "displayName"][target.length-1],
  21188. symbol = dregexp.escapeString(options[prop] || options.currency || "");
  21189. before = before ? "[\\s\\xa0]" : "";
  21190. after = after ? "[\\s\\xa0]" : "";
  21191. if(!options.strict){
  21192. if(before){before += "*";}
  21193. if(after){after += "*";}
  21194. return "(?:"+before+symbol+after+")?";
  21195. }
  21196. return before+symbol+after;
  21197. });
  21198. }
  21199. //TODO: substitute localized sign/percent/permille/etc.?
  21200. // normalize whitespace and return
  21201. return {regexp: re.replace(/[\xa0 ]/g, "[\\s\\xa0]"), group: group, decimal: decimal, factor: factor}; // Object
  21202. };
  21203. /*=====
  21204. dojo.number.__ParseOptions = function(){
  21205. // pattern: String?
  21206. // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  21207. // with this string. Default value is based on locale. Overriding this property will defeat
  21208. // localization. Literal characters in patterns are not supported.
  21209. // type: String?
  21210. // choose a format type based on the locale from the following:
  21211. // decimal, scientific (not yet supported), percent, currency. decimal by default.
  21212. // locale: String?
  21213. // override the locale used to determine formatting rules
  21214. // strict: Boolean?
  21215. // strict parsing, false by default. Strict parsing requires input as produced by the format() method.
  21216. // Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators
  21217. // fractional: Boolean?|Array?
  21218. // Whether to include the fractional portion, where the number of decimal places are implied by pattern
  21219. // or explicit 'places' parameter. The value [true,false] makes the fractional portion optional.
  21220. this.pattern = pattern;
  21221. this.type = type;
  21222. this.locale = locale;
  21223. this.strict = strict;
  21224. this.fractional = fractional;
  21225. }
  21226. =====*/
  21227. dojo.number.parse = function(/*String*/expression, /*dojo.number.__ParseOptions?*/options){
  21228. // summary:
  21229. // Convert a properly formatted string to a primitive Number, using
  21230. // locale-specific settings.
  21231. // description:
  21232. // Create a Number from a string using a known localized pattern.
  21233. // Formatting patterns are chosen appropriate to the locale
  21234. // and follow the syntax described by
  21235. // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  21236. // Note that literal characters in patterns are not supported.
  21237. // expression:
  21238. // A string representation of a Number
  21239. var info = dojo.number._parseInfo(options),
  21240. results = (new RegExp("^"+info.regexp+"$")).exec(expression);
  21241. if(!results){
  21242. return NaN; //NaN
  21243. }
  21244. var absoluteMatch = results[1]; // match for the positive expression
  21245. if(!results[1]){
  21246. if(!results[2]){
  21247. return NaN; //NaN
  21248. }
  21249. // matched the negative pattern
  21250. absoluteMatch =results[2];
  21251. info.factor *= -1;
  21252. }
  21253. // Transform it to something Javascript can parse as a number. Normalize
  21254. // decimal point and strip out group separators or alternate forms of whitespace
  21255. absoluteMatch = absoluteMatch.
  21256. replace(new RegExp("["+info.group + "\\s\\xa0"+"]", "g"), "").
  21257. replace(info.decimal, ".");
  21258. // Adjust for negative sign, percent, etc. as necessary
  21259. return absoluteMatch * info.factor; //Number
  21260. };
  21261. /*=====
  21262. dojo.number.__RealNumberRegexpFlags = function(){
  21263. // places: Number?
  21264. // The integer number of decimal places or a range given as "n,m". If
  21265. // not given, the decimal part is optional and the number of places is
  21266. // unlimited.
  21267. // decimal: String?
  21268. // A string for the character used as the decimal point. Default
  21269. // is ".".
  21270. // fractional: Boolean?|Array?
  21271. // Whether decimal places are used. Can be true, false, or [true,
  21272. // false]. Default is [true, false] which means optional.
  21273. // exponent: Boolean?|Array?
  21274. // Express in exponential notation. Can be true, false, or [true,
  21275. // false]. Default is [true, false], (i.e. will match if the
  21276. // exponential part is present are not).
  21277. // eSigned: Boolean?|Array?
  21278. // The leading plus-or-minus sign on the exponent. Can be true,
  21279. // false, or [true, false]. Default is [true, false], (i.e. will
  21280. // match if it is signed or unsigned). flags in regexp.integer can be
  21281. // applied.
  21282. this.places = places;
  21283. this.decimal = decimal;
  21284. this.fractional = fractional;
  21285. this.exponent = exponent;
  21286. this.eSigned = eSigned;
  21287. }
  21288. =====*/
  21289. dojo.number._realNumberRegexp = function(/*dojo.number.__RealNumberRegexpFlags?*/flags){
  21290. // summary:
  21291. // Builds a regular expression to match a real number in exponential
  21292. // notation
  21293. // assign default values to missing parameters
  21294. flags = flags || {};
  21295. //TODO: use mixin instead?
  21296. if(!("places" in flags)){ flags.places = Infinity; }
  21297. if(typeof flags.decimal != "string"){ flags.decimal = "."; }
  21298. if(!("fractional" in flags) || /^0/.test(flags.places)){ flags.fractional = [true, false]; }
  21299. if(!("exponent" in flags)){ flags.exponent = [true, false]; }
  21300. if(!("eSigned" in flags)){ flags.eSigned = [true, false]; }
  21301. var integerRE = dojo.number._integerRegexp(flags),
  21302. decimalRE = dregexp.buildGroupRE(flags.fractional,
  21303. function(q){
  21304. var re = "";
  21305. if(q && (flags.places!==0)){
  21306. re = "\\" + flags.decimal;
  21307. if(flags.places == Infinity){
  21308. re = "(?:" + re + "\\d+)?";
  21309. }else{
  21310. re += "\\d{" + flags.places + "}";
  21311. }
  21312. }
  21313. return re;
  21314. },
  21315. true
  21316. );
  21317. var exponentRE = dregexp.buildGroupRE(flags.exponent,
  21318. function(q){
  21319. if(q){ return "([eE]" + dojo.number._integerRegexp({ signed: flags.eSigned}) + ")"; }
  21320. return "";
  21321. }
  21322. );
  21323. var realRE = integerRE + decimalRE;
  21324. // allow for decimals without integers, e.g. .25
  21325. if(decimalRE){realRE = "(?:(?:"+ realRE + ")|(?:" + decimalRE + "))";}
  21326. return realRE + exponentRE; // String
  21327. };
  21328. /*=====
  21329. dojo.number.__IntegerRegexpFlags = function(){
  21330. // signed: Boolean?
  21331. // The leading plus-or-minus sign. Can be true, false, or `[true,false]`.
  21332. // Default is `[true, false]`, (i.e. will match if it is signed
  21333. // or unsigned).
  21334. // separator: String?
  21335. // The character used as the thousands separator. Default is no
  21336. // separator. For more than one symbol use an array, e.g. `[",", ""]`,
  21337. // makes ',' optional.
  21338. // groupSize: Number?
  21339. // group size between separators
  21340. // groupSize2: Number?
  21341. // second grouping, where separators 2..n have a different interval than the first separator (for India)
  21342. this.signed = signed;
  21343. this.separator = separator;
  21344. this.groupSize = groupSize;
  21345. this.groupSize2 = groupSize2;
  21346. }
  21347. =====*/
  21348. dojo.number._integerRegexp = function(/*dojo.number.__IntegerRegexpFlags?*/flags){
  21349. // summary:
  21350. // Builds a regular expression that matches an integer
  21351. // assign default values to missing parameters
  21352. flags = flags || {};
  21353. if(!("signed" in flags)){ flags.signed = [true, false]; }
  21354. if(!("separator" in flags)){
  21355. flags.separator = "";
  21356. }else if(!("groupSize" in flags)){
  21357. flags.groupSize = 3;
  21358. }
  21359. var signRE = dregexp.buildGroupRE(flags.signed,
  21360. function(q){ return q ? "[-+]" : ""; },
  21361. true
  21362. );
  21363. var numberRE = dregexp.buildGroupRE(flags.separator,
  21364. function(sep){
  21365. if(!sep){
  21366. return "(?:\\d+)";
  21367. }
  21368. sep = dregexp.escapeString(sep);
  21369. if(sep == " "){ sep = "\\s"; }
  21370. else if(sep == "\xa0"){ sep = "\\s\\xa0"; }
  21371. var grp = flags.groupSize, grp2 = flags.groupSize2;
  21372. //TODO: should we continue to enforce that numbers with separators begin with 1-9? See #6933
  21373. if(grp2){
  21374. var grp2RE = "(?:0|[1-9]\\d{0," + (grp2-1) + "}(?:[" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})";
  21375. return ((grp-grp2) > 0) ? "(?:" + grp2RE + "|(?:0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE;
  21376. }
  21377. return "(?:0|[1-9]\\d{0," + (grp-1) + "}(?:[" + sep + "]\\d{" + grp + "})*)";
  21378. },
  21379. true
  21380. );
  21381. return signRE + numberRE; // String
  21382. };
  21383. return dojo.number;
  21384. });
  21385. },
  21386. 'dojo/data/util/filter':function(){
  21387. define(["../../_base/lang"], function(lang) {
  21388. // module:
  21389. // dojo/data/util/filter
  21390. // summary:
  21391. // TODOC
  21392. var filter = lang.getObject("dojo.data.util.filter", true);
  21393. filter.patternToRegExp = function(/*String*/pattern, /*boolean?*/ ignoreCase){
  21394. // summary:
  21395. // Helper function to convert a simple pattern to a regular expression for matching.
  21396. // description:
  21397. // Returns a regular expression object that conforms to the defined conversion rules.
  21398. // For example:
  21399. // ca* -> /^ca.*$/
  21400. // *ca* -> /^.*ca.*$/
  21401. // *c\*a* -> /^.*c\*a.*$/
  21402. // *c\*a?* -> /^.*c\*a..*$/
  21403. // and so on.
  21404. //
  21405. // pattern: string
  21406. // A simple matching pattern to convert that follows basic rules:
  21407. // * Means match anything, so ca* means match anything starting with ca
  21408. // ? Means match single character. So, b?b will match to bob and bab, and so on.
  21409. // \ is an escape character. So for example, \* means do not treat * as a match, but literal character *.
  21410. // To use a \ as a character in the string, it must be escaped. So in the pattern it should be
  21411. // represented by \\ to be treated as an ordinary \ character instead of an escape.
  21412. //
  21413. // ignoreCase:
  21414. // An optional flag to indicate if the pattern matching should be treated as case-sensitive or not when comparing
  21415. // By default, it is assumed case sensitive.
  21416. var rxp = "^";
  21417. var c = null;
  21418. for(var i = 0; i < pattern.length; i++){
  21419. c = pattern.charAt(i);
  21420. switch(c){
  21421. case '\\':
  21422. rxp += c;
  21423. i++;
  21424. rxp += pattern.charAt(i);
  21425. break;
  21426. case '*':
  21427. rxp += ".*"; break;
  21428. case '?':
  21429. rxp += "."; break;
  21430. case '$':
  21431. case '^':
  21432. case '/':
  21433. case '+':
  21434. case '.':
  21435. case '|':
  21436. case '(':
  21437. case ')':
  21438. case '{':
  21439. case '}':
  21440. case '[':
  21441. case ']':
  21442. rxp += "\\"; //fallthrough
  21443. default:
  21444. rxp += c;
  21445. }
  21446. }
  21447. rxp += "$";
  21448. if(ignoreCase){
  21449. return new RegExp(rxp,"mi"); //RegExp
  21450. }else{
  21451. return new RegExp(rxp,"m"); //RegExp
  21452. }
  21453. };
  21454. return filter;
  21455. });
  21456. },
  21457. 'dijit/_WidgetsInTemplateMixin':function(){
  21458. define([
  21459. "dojo/_base/array", // array.forEach
  21460. "dojo/_base/declare", // declare
  21461. "dojo/parser", // parser.parse
  21462. "dijit/registry" // registry.findWidgets
  21463. ], function(array, declare, parser, registry){
  21464. // module:
  21465. // dijit/_WidgetsInTemplateMixin
  21466. // summary:
  21467. // Mixin to supplement _TemplatedMixin when template contains widgets
  21468. return declare("dijit._WidgetsInTemplateMixin", null, {
  21469. // summary:
  21470. // Mixin to supplement _TemplatedMixin when template contains widgets
  21471. // _earlyTemplatedStartup: Boolean
  21472. // A fallback to preserve the 1.0 - 1.3 behavior of children in
  21473. // templates having their startup called before the parent widget
  21474. // fires postCreate. Defaults to 'false', causing child widgets to
  21475. // have their .startup() called immediately before a parent widget
  21476. // .startup(), but always after the parent .postCreate(). Set to
  21477. // 'true' to re-enable to previous, arguably broken, behavior.
  21478. _earlyTemplatedStartup: false,
  21479. // widgetsInTemplate: [protected] Boolean
  21480. // Should we parse the template to find widgets that might be
  21481. // declared in markup inside it? (Remove for 2.0 and assume true)
  21482. widgetsInTemplate: true,
  21483. _beforeFillContent: function(){
  21484. if(this.widgetsInTemplate){
  21485. // Before copying over content, instantiate widgets in template
  21486. var node = this.domNode;
  21487. var cw = (this._startupWidgets = parser.parse(node, {
  21488. noStart: !this._earlyTemplatedStartup,
  21489. template: true,
  21490. inherited: {dir: this.dir, lang: this.lang, textDir: this.textDir},
  21491. propsThis: this, // so data-dojo-props of widgets in the template can reference "this" to refer to me
  21492. scope: "dojo" // even in multi-version mode templates use dojoType/data-dojo-type
  21493. }));
  21494. this._supportingWidgets = registry.findWidgets(node);
  21495. this._attachTemplateNodes(cw, function(n,p){
  21496. return n[p];
  21497. });
  21498. }
  21499. },
  21500. startup: function(){
  21501. array.forEach(this._startupWidgets, function(w){
  21502. if(w && !w._started && w.startup){
  21503. w.startup();
  21504. }
  21505. });
  21506. this.inherited(arguments);
  21507. }
  21508. });
  21509. });
  21510. },
  21511. 'dijit/form/HorizontalRuleLabels':function(){
  21512. define([
  21513. "dojo/_base/declare", // declare
  21514. "dojo/number", // number.format
  21515. "dojo/query", // query
  21516. "./HorizontalRule"
  21517. ], function(declare, number, query, HorizontalRule){
  21518. /*=====
  21519. var HorizontalRule = dijit.form.HorizontalRule;
  21520. =====*/
  21521. // module:
  21522. // dijit/form/HorizontalRuleLabels
  21523. // summary:
  21524. // Labels for `dijit.form.HorizontalSlider`
  21525. return declare("dijit.form.HorizontalRuleLabels", HorizontalRule, {
  21526. // summary:
  21527. // Labels for `dijit.form.HorizontalSlider`
  21528. templateString: '<div class="dijitRuleContainer dijitRuleContainerH dijitRuleLabelsContainer dijitRuleLabelsContainerH"></div>',
  21529. // labelStyle: String
  21530. // CSS style to apply to individual text labels
  21531. labelStyle: "",
  21532. // labels: String[]?
  21533. // Array of text labels to render - evenly spaced from left-to-right or bottom-to-top.
  21534. // Alternately, minimum and maximum can be specified, to get numeric labels.
  21535. labels: [],
  21536. // numericMargin: Integer
  21537. // Number of generated numeric labels that should be rendered as '' on the ends when labels[] are not specified
  21538. numericMargin: 0,
  21539. // numericMinimum: Integer
  21540. // Leftmost label value for generated numeric labels when labels[] are not specified
  21541. minimum: 0,
  21542. // numericMaximum: Integer
  21543. // Rightmost label value for generated numeric labels when labels[] are not specified
  21544. maximum: 1,
  21545. // constraints: Object
  21546. // pattern, places, lang, et al (see dojo.number) for generated numeric labels when labels[] are not specified
  21547. constraints: {pattern:"#%"},
  21548. _positionPrefix: '<div class="dijitRuleLabelContainer dijitRuleLabelContainerH" style="left:',
  21549. _labelPrefix: '"><div class="dijitRuleLabel dijitRuleLabelH">',
  21550. _suffix: '</div></div>',
  21551. _calcPosition: function(pos){
  21552. // summary:
  21553. // Returns the value to be used in HTML for the label as part of the left: attribute
  21554. // tags:
  21555. // protected extension
  21556. return pos;
  21557. },
  21558. _genHTML: function(pos, ndx){
  21559. return this._positionPrefix + this._calcPosition(pos) + this._positionSuffix + this.labelStyle + this._labelPrefix + this.labels[ndx] + this._suffix;
  21560. },
  21561. getLabels: function(){
  21562. // summary:
  21563. // Overridable function to return array of labels to use for this slider.
  21564. // Can specify a getLabels() method instead of a labels[] array, or min/max attributes.
  21565. // tags:
  21566. // protected extension
  21567. // if the labels array was not specified directly, then see if <li> children were
  21568. var labels = this.labels;
  21569. if(!labels.length){
  21570. // for markup creation, labels are specified as child elements
  21571. labels = query("> li", this.srcNodeRef).map(function(node){
  21572. return String(node.innerHTML);
  21573. });
  21574. }
  21575. this.srcNodeRef.innerHTML = '';
  21576. // if the labels were not specified directly and not as <li> children, then calculate numeric labels
  21577. if(!labels.length && this.count > 1){
  21578. var start = this.minimum;
  21579. var inc = (this.maximum - start) / (this.count-1);
  21580. for(var i=0; i < this.count; i++){
  21581. labels.push((i < this.numericMargin || i >= (this.count-this.numericMargin)) ? '' : number.format(start, this.constraints));
  21582. start += inc;
  21583. }
  21584. }
  21585. return labels;
  21586. },
  21587. postMixInProperties: function(){
  21588. this.inherited(arguments);
  21589. this.labels = this.getLabels();
  21590. this.count = this.labels.length;
  21591. }
  21592. });
  21593. });
  21594. },
  21595. 'url:dijit/templates/MenuBarItem.html':"<div class=\"dijitReset dijitInline dijitMenuItem dijitMenuItemLabel\" data-dojo-attach-point=\"focusNode\" role=\"menuitem\" tabIndex=\"-1\"\n\t\tdata-dojo-attach-event=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<span data-dojo-attach-point=\"containerNode\"></span>\n</div>\n",
  21596. 'dijit/form/FilteringSelect':function(){
  21597. define([
  21598. "dojo/data/util/filter", // filter.patternToRegExp
  21599. "dojo/_base/declare", // declare
  21600. "dojo/_base/Deferred", // Deferred.when
  21601. "dojo/_base/lang", // lang.mixin
  21602. "./MappedTextBox",
  21603. "./ComboBoxMixin"
  21604. ], function(filter, declare, Deferred, lang, MappedTextBox, ComboBoxMixin){
  21605. /*=====
  21606. var MappedTextBox = dijit.form.MappedTextBox;
  21607. var ComboBoxMixin = dijit.form.ComboBoxMixin;
  21608. =====*/
  21609. // module:
  21610. // dijit/form/FilteringSelect
  21611. // summary:
  21612. // An enhanced version of the HTML SELECT tag, populated dynamically
  21613. return declare("dijit.form.FilteringSelect", [MappedTextBox, ComboBoxMixin], {
  21614. // summary:
  21615. // An enhanced version of the HTML SELECT tag, populated dynamically
  21616. //
  21617. // description:
  21618. // An enhanced version of the HTML SELECT tag, populated dynamically. It works
  21619. // very nicely with very large data sets because it can load and page data as needed.
  21620. // It also resembles ComboBox, but does not allow values outside of the provided ones.
  21621. // If OPTION tags are used as the data provider via markup, then the
  21622. // OPTION tag's child text node is used as the displayed value when selected
  21623. // while the OPTION tag's value attribute is used as the widget value on form submit.
  21624. // To set the default value when using OPTION tags, specify the selected
  21625. // attribute on 1 of the child OPTION tags.
  21626. //
  21627. // Similar features:
  21628. // - There is a drop down list of possible values.
  21629. // - You can only enter a value from the drop down list. (You can't
  21630. // enter an arbitrary value.)
  21631. // - The value submitted with the form is the hidden value (ex: CA),
  21632. // not the displayed value a.k.a. label (ex: California)
  21633. //
  21634. // Enhancements over plain HTML version:
  21635. // - If you type in some text then it will filter down the list of
  21636. // possible values in the drop down list.
  21637. // - List can be specified either as a static list or via a javascript
  21638. // function (that can get the list from a server)
  21639. // required: Boolean
  21640. // True (default) if user is required to enter a value into this field.
  21641. required: true,
  21642. _lastDisplayedValue: "",
  21643. _isValidSubset: function(){
  21644. return this._opened;
  21645. },
  21646. isValid: function(){
  21647. // Overrides ValidationTextBox.isValid()
  21648. return !!this.item || (!this.required && this.get('displayedValue') == ""); // #5974
  21649. },
  21650. _refreshState: function(){
  21651. if(!this.searchTimer){ // state will be refreshed after results are returned
  21652. this.inherited(arguments);
  21653. }
  21654. },
  21655. _callbackSetLabel: function(
  21656. /*Array*/ result,
  21657. /*Object*/ query,
  21658. /*Object*/ options,
  21659. /*Boolean?*/ priorityChange){
  21660. // summary:
  21661. // Callback from dojo.store after lookup of user entered value finishes
  21662. // setValue does a synchronous lookup,
  21663. // so it calls _callbackSetLabel directly,
  21664. // and so does not pass dataObject
  21665. // still need to test against _lastQuery in case it came too late
  21666. if((query && query[this.searchAttr] !== this._lastQuery) || (!query && result.length && this.store.getIdentity(result[0]) != this._lastQuery)){
  21667. return;
  21668. }
  21669. if(!result.length){
  21670. //#3268: don't modify display value on bad input
  21671. //#3285: change CSS to indicate error
  21672. this.set("value", '', priorityChange || (priorityChange === undefined && !this.focused), this.textbox.value, null);
  21673. }else{
  21674. this.set('item', result[0], priorityChange);
  21675. }
  21676. },
  21677. _openResultList: function(/*Object*/ results, /*Object*/ query, /*Object*/ options){
  21678. // Callback when a data store query completes.
  21679. // Overrides ComboBox._openResultList()
  21680. // #3285: tap into search callback to see if user's query resembles a match
  21681. if(query[this.searchAttr] !== this._lastQuery){
  21682. return;
  21683. }
  21684. this.inherited(arguments);
  21685. if(this.item === undefined){ // item == undefined for keyboard search
  21686. // If the search returned no items that means that the user typed
  21687. // in something invalid (and they can't make it valid by typing more characters),
  21688. // so flag the FilteringSelect as being in an invalid state
  21689. this.validate(true);
  21690. }
  21691. },
  21692. _getValueAttr: function(){
  21693. // summary:
  21694. // Hook for get('value') to work.
  21695. // don't get the textbox value but rather the previously set hidden value.
  21696. // Use this.valueNode.value which isn't always set for other MappedTextBox widgets until blur
  21697. return this.valueNode.value;
  21698. },
  21699. _getValueField: function(){
  21700. // Overrides ComboBox._getValueField()
  21701. return "value";
  21702. },
  21703. _setValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange, /*String?*/ displayedValue, /*item?*/ item){
  21704. // summary:
  21705. // Hook so set('value', value) works.
  21706. // description:
  21707. // Sets the value of the select.
  21708. // Also sets the label to the corresponding value by reverse lookup.
  21709. if(!this._onChangeActive){ priorityChange = null; }
  21710. if(item === undefined){
  21711. if(value === null || value === ''){
  21712. value = '';
  21713. if(!lang.isString(displayedValue)){
  21714. this._setDisplayedValueAttr(displayedValue||'', priorityChange);
  21715. return;
  21716. }
  21717. }
  21718. var self = this;
  21719. this._lastQuery = value;
  21720. Deferred.when(this.store.get(value), function(item){
  21721. self._callbackSetLabel(item? [item] : [], undefined, undefined, priorityChange);
  21722. });
  21723. }else{
  21724. this.valueNode.value = value;
  21725. this.inherited(arguments);
  21726. }
  21727. },
  21728. _setItemAttr: function(/*item*/ item, /*Boolean?*/ priorityChange, /*String?*/ displayedValue){
  21729. // summary:
  21730. // Set the displayed valued in the input box, and the hidden value
  21731. // that gets submitted, based on a dojo.data store item.
  21732. // description:
  21733. // Users shouldn't call this function; they should be calling
  21734. // set('item', value)
  21735. // tags:
  21736. // private
  21737. this.inherited(arguments);
  21738. this._lastDisplayedValue = this.textbox.value;
  21739. },
  21740. _getDisplayQueryString: function(/*String*/ text){
  21741. return text.replace(/([\\\*\?])/g, "\\$1");
  21742. },
  21743. _setDisplayedValueAttr: function(/*String*/ label, /*Boolean?*/ priorityChange){
  21744. // summary:
  21745. // Hook so set('displayedValue', label) works.
  21746. // description:
  21747. // Sets textbox to display label. Also performs reverse lookup
  21748. // to set the hidden value. label should corresponding to item.searchAttr.
  21749. if(label == null){ label = ''; }
  21750. // This is called at initialization along with every custom setter.
  21751. // Usually (or always?) the call can be ignored. If it needs to be
  21752. // processed then at least make sure that the XHR request doesn't trigger an onChange()
  21753. // event, even if it returns after creation has finished
  21754. if(!this._created){
  21755. if(!("displayedValue" in this.params)){
  21756. return;
  21757. }
  21758. priorityChange = false;
  21759. }
  21760. // Do a reverse lookup to map the specified displayedValue to the hidden value.
  21761. // Note that if there's a custom labelFunc() this code
  21762. if(this.store){
  21763. this.closeDropDown();
  21764. var query = lang.clone(this.query); // #6196: populate query with user-specifics
  21765. // Generate query
  21766. var qs = this._getDisplayQueryString(label), q;
  21767. if(this.store._oldAPI){
  21768. // remove this branch for 2.0
  21769. q = qs;
  21770. }else{
  21771. // Query on searchAttr is a regex for benefit of dojo.store.Memory,
  21772. // but with a toString() method to help dojo.store.JsonRest.
  21773. // Search string like "Co*" converted to regex like /^Co.*$/i.
  21774. q = filter.patternToRegExp(qs, this.ignoreCase);
  21775. q.toString = function(){ return qs; };
  21776. }
  21777. this._lastQuery = query[this.searchAttr] = q;
  21778. // If the label is not valid, the callback will never set it,
  21779. // so the last valid value will get the warning textbox. Set the
  21780. // textbox value now so that the impending warning will make
  21781. // sense to the user
  21782. this.textbox.value = label;
  21783. this._lastDisplayedValue = label;
  21784. this._set("displayedValue", label); // for watch("displayedValue") notification
  21785. var _this = this;
  21786. var options = {
  21787. queryOptions: {
  21788. ignoreCase: this.ignoreCase,
  21789. deep: true
  21790. }
  21791. };
  21792. lang.mixin(options, this.fetchProperties);
  21793. this._fetchHandle = this.store.query(query, options);
  21794. Deferred.when(this._fetchHandle, function(result){
  21795. _this._fetchHandle = null;
  21796. _this._callbackSetLabel(result || [], query, options, priorityChange);
  21797. }, function(err){
  21798. _this._fetchHandle = null;
  21799. if(!_this._cancelingQuery){ // don't treat canceled query as an error
  21800. console.error('dijit.form.FilteringSelect: ' + err.toString());
  21801. }
  21802. });
  21803. }
  21804. },
  21805. undo: function(){
  21806. this.set('displayedValue', this._lastDisplayedValue);
  21807. }
  21808. });
  21809. });
  21810. },
  21811. 'dojo/data/util/sorter':function(){
  21812. define(["../../_base/lang"], function(lang) {
  21813. // module:
  21814. // dojo/data/util/sorter
  21815. // summary:
  21816. // TODOC
  21817. var sorter = lang.getObject("dojo.data.util.sorter", true);
  21818. sorter.basicComparator = function( /*anything*/ a,
  21819. /*anything*/ b){
  21820. // summary:
  21821. // Basic comparision function that compares if an item is greater or less than another item
  21822. // description:
  21823. // returns 1 if a > b, -1 if a < b, 0 if equal.
  21824. // 'null' values (null, undefined) are treated as larger values so that they're pushed to the end of the list.
  21825. // And compared to each other, null is equivalent to undefined.
  21826. //null is a problematic compare, so if null, we set to undefined.
  21827. //Makes the check logic simple, compact, and consistent
  21828. //And (null == undefined) === true, so the check later against null
  21829. //works for undefined and is less bytes.
  21830. var r = -1;
  21831. if(a === null){
  21832. a = undefined;
  21833. }
  21834. if(b === null){
  21835. b = undefined;
  21836. }
  21837. if(a == b){
  21838. r = 0;
  21839. }else if(a > b || a == null){
  21840. r = 1;
  21841. }
  21842. return r; //int {-1,0,1}
  21843. };
  21844. sorter.createSortFunction = function( /* attributes array */sortSpec, /*dojo.data.core.Read*/ store){
  21845. // summary:
  21846. // Helper function to generate the sorting function based off the list of sort attributes.
  21847. // description:
  21848. // The sort function creation will look for a property on the store called 'comparatorMap'. If it exists
  21849. // it will look in the mapping for comparisons function for the attributes. If one is found, it will
  21850. // use it instead of the basic comparator, which is typically used for strings, ints, booleans, and dates.
  21851. // Returns the sorting function for this particular list of attributes and sorting directions.
  21852. //
  21853. // sortSpec: array
  21854. // A JS object that array that defines out what attribute names to sort on and whether it should be descenting or asending.
  21855. // The objects should be formatted as follows:
  21856. // {
  21857. // attribute: "attributeName-string" || attribute,
  21858. // descending: true|false; // Default is false.
  21859. // }
  21860. // store: object
  21861. // The datastore object to look up item values from.
  21862. //
  21863. var sortFunctions=[];
  21864. function createSortFunction(attr, dir, comp, s){
  21865. //Passing in comp and s (comparator and store), makes this
  21866. //function much faster.
  21867. return function(itemA, itemB){
  21868. var a = s.getValue(itemA, attr);
  21869. var b = s.getValue(itemB, attr);
  21870. return dir * comp(a,b); //int
  21871. };
  21872. }
  21873. var sortAttribute;
  21874. var map = store.comparatorMap;
  21875. var bc = sorter.basicComparator;
  21876. for(var i = 0; i < sortSpec.length; i++){
  21877. sortAttribute = sortSpec[i];
  21878. var attr = sortAttribute.attribute;
  21879. if(attr){
  21880. var dir = (sortAttribute.descending) ? -1 : 1;
  21881. var comp = bc;
  21882. if(map){
  21883. if(typeof attr !== "string" && ("toString" in attr)){
  21884. attr = attr.toString();
  21885. }
  21886. comp = map[attr] || bc;
  21887. }
  21888. sortFunctions.push(createSortFunction(attr,
  21889. dir, comp, store));
  21890. }
  21891. }
  21892. return function(rowA, rowB){
  21893. var i=0;
  21894. while(i < sortFunctions.length){
  21895. var ret = sortFunctions[i++](rowA, rowB);
  21896. if(ret !== 0){
  21897. return ret;//int
  21898. }
  21899. }
  21900. return 0; //int
  21901. }; // Function
  21902. };
  21903. return sorter;
  21904. });
  21905. },
  21906. 'dijit/form/_ButtonMixin':function(){
  21907. define([
  21908. "dojo/_base/declare", // declare
  21909. "dojo/dom", // dom.setSelectable
  21910. "dojo/_base/event", // event.stop
  21911. "../registry" // registry.byNode
  21912. ], function(declare, dom, event, registry){
  21913. // module:
  21914. // dijit/form/_ButtonMixin
  21915. // summary:
  21916. // A mixin to add a thin standard API wrapper to a normal HTML button
  21917. return declare("dijit.form._ButtonMixin", null, {
  21918. // summary:
  21919. // A mixin to add a thin standard API wrapper to a normal HTML button
  21920. // description:
  21921. // A label should always be specified (through innerHTML) or the label attribute.
  21922. // Attach points:
  21923. // focusNode (required): this node receives focus
  21924. // valueNode (optional): this node's value gets submitted with FORM elements
  21925. // containerNode (optional): this node gets the innerHTML assignment for label
  21926. // example:
  21927. // | <button data-dojo-type="dijit.form.Button" onClick="...">Hello world</button>
  21928. //
  21929. // example:
  21930. // | var button1 = new dijit.form.Button({label: "hello world", onClick: foo});
  21931. // | dojo.body().appendChild(button1.domNode);
  21932. // label: HTML String
  21933. // Content to display in button.
  21934. label: "",
  21935. // type: [const] String
  21936. // Type of button (submit, reset, button, checkbox, radio)
  21937. type: "button",
  21938. _onClick: function(/*Event*/ e){
  21939. // summary:
  21940. // Internal function to handle click actions
  21941. if(this.disabled){
  21942. event.stop(e);
  21943. return false;
  21944. }
  21945. var preventDefault = this.onClick(e) === false; // user click actions
  21946. if(!preventDefault && this.type == "submit" && !(this.valueNode||this.focusNode).form){ // see if a non-form widget needs to be signalled
  21947. for(var node=this.domNode; node.parentNode; node=node.parentNode){
  21948. var widget=registry.byNode(node);
  21949. if(widget && typeof widget._onSubmit == "function"){
  21950. widget._onSubmit(e);
  21951. preventDefault = true;
  21952. break;
  21953. }
  21954. }
  21955. }
  21956. if(preventDefault){
  21957. e.preventDefault();
  21958. }
  21959. return !preventDefault;
  21960. },
  21961. postCreate: function(){
  21962. this.inherited(arguments);
  21963. dom.setSelectable(this.focusNode, false);
  21964. },
  21965. onClick: function(/*Event*/ /*===== e =====*/){
  21966. // summary:
  21967. // Callback for when button is clicked.
  21968. // If type="submit", return true to perform submit, or false to cancel it.
  21969. // type:
  21970. // callback
  21971. return true; // Boolean
  21972. },
  21973. _setLabelAttr: function(/*String*/ content){
  21974. // summary:
  21975. // Hook for set('label', ...) to work.
  21976. // description:
  21977. // Set the label (text) of the button; takes an HTML string.
  21978. this._set("label", content);
  21979. (this.containerNode||this.focusNode).innerHTML = content;
  21980. }
  21981. });
  21982. });
  21983. },
  21984. 'dojo/colors':function(){
  21985. define(["./_base/kernel", "./_base/lang", "./_base/Color", "./_base/array"], function(dojo, lang, Color, ArrayUtil) {
  21986. // module:
  21987. // dojo/colors
  21988. // summary:
  21989. // TODOC
  21990. var ColorExt = lang.getObject("dojo.colors", true);
  21991. //TODO: this module appears to break naming conventions
  21992. /*=====
  21993. lang.mixin(dojo, {
  21994. colors: {
  21995. // summary: Color utilities, extending Base dojo.Color
  21996. }
  21997. });
  21998. =====*/
  21999. // this is a standard conversion prescribed by the CSS3 Color Module
  22000. var hue2rgb = function(m1, m2, h){
  22001. if(h < 0){ ++h; }
  22002. if(h > 1){ --h; }
  22003. var h6 = 6 * h;
  22004. if(h6 < 1){ return m1 + (m2 - m1) * h6; }
  22005. if(2 * h < 1){ return m2; }
  22006. if(3 * h < 2){ return m1 + (m2 - m1) * (2 / 3 - h) * 6; }
  22007. return m1;
  22008. };
  22009. // Override base Color.fromRgb with the impl in this module
  22010. dojo.colorFromRgb = Color.fromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){
  22011. // summary:
  22012. // get rgb(a) array from css-style color declarations
  22013. // description:
  22014. // this function can handle all 4 CSS3 Color Module formats: rgb,
  22015. // rgba, hsl, hsla, including rgb(a) with percentage values.
  22016. var m = color.toLowerCase().match(/^(rgba?|hsla?)\(([\s\.\-,%0-9]+)\)/);
  22017. if(m){
  22018. var c = m[2].split(/\s*,\s*/), l = c.length, t = m[1], a;
  22019. if((t == "rgb" && l == 3) || (t == "rgba" && l == 4)){
  22020. var r = c[0];
  22021. if(r.charAt(r.length - 1) == "%"){
  22022. // 3 rgb percentage values
  22023. a = ArrayUtil.map(c, function(x){
  22024. return parseFloat(x) * 2.56;
  22025. });
  22026. if(l == 4){ a[3] = c[3]; }
  22027. return Color.fromArray(a, obj); // dojo.Color
  22028. }
  22029. return Color.fromArray(c, obj); // dojo.Color
  22030. }
  22031. if((t == "hsl" && l == 3) || (t == "hsla" && l == 4)){
  22032. // normalize hsl values
  22033. var H = ((parseFloat(c[0]) % 360) + 360) % 360 / 360,
  22034. S = parseFloat(c[1]) / 100,
  22035. L = parseFloat(c[2]) / 100,
  22036. // calculate rgb according to the algorithm
  22037. // recommended by the CSS3 Color Module
  22038. m2 = L <= 0.5 ? L * (S + 1) : L + S - L * S,
  22039. m1 = 2 * L - m2;
  22040. a = [
  22041. hue2rgb(m1, m2, H + 1 / 3) * 256,
  22042. hue2rgb(m1, m2, H) * 256,
  22043. hue2rgb(m1, m2, H - 1 / 3) * 256,
  22044. 1
  22045. ];
  22046. if(l == 4){ a[3] = c[3]; }
  22047. return Color.fromArray(a, obj); // dojo.Color
  22048. }
  22049. }
  22050. return null; // dojo.Color
  22051. };
  22052. var confine = function(c, low, high){
  22053. // summary:
  22054. // sanitize a color component by making sure it is a number,
  22055. // and clamping it to valid values
  22056. c = Number(c);
  22057. return isNaN(c) ? high : c < low ? low : c > high ? high : c; // Number
  22058. };
  22059. Color.prototype.sanitize = function(){
  22060. // summary: makes sure that the object has correct attributes
  22061. var t = this;
  22062. t.r = Math.round(confine(t.r, 0, 255));
  22063. t.g = Math.round(confine(t.g, 0, 255));
  22064. t.b = Math.round(confine(t.b, 0, 255));
  22065. t.a = confine(t.a, 0, 1);
  22066. return this; // dojo.Color
  22067. };
  22068. ColorExt.makeGrey = Color.makeGrey = function(/*Number*/ g, /*Number?*/ a){
  22069. // summary: creates a greyscale color with an optional alpha
  22070. return Color.fromArray([g, g, g, a]); // dojo.Color
  22071. };
  22072. // mixin all CSS3 named colors not already in _base, along with SVG 1.0 variant spellings
  22073. lang.mixin(Color.named, {
  22074. "aliceblue": [240,248,255],
  22075. "antiquewhite": [250,235,215],
  22076. "aquamarine": [127,255,212],
  22077. "azure": [240,255,255],
  22078. "beige": [245,245,220],
  22079. "bisque": [255,228,196],
  22080. "blanchedalmond": [255,235,205],
  22081. "blueviolet": [138,43,226],
  22082. "brown": [165,42,42],
  22083. "burlywood": [222,184,135],
  22084. "cadetblue": [95,158,160],
  22085. "chartreuse": [127,255,0],
  22086. "chocolate": [210,105,30],
  22087. "coral": [255,127,80],
  22088. "cornflowerblue": [100,149,237],
  22089. "cornsilk": [255,248,220],
  22090. "crimson": [220,20,60],
  22091. "cyan": [0,255,255],
  22092. "darkblue": [0,0,139],
  22093. "darkcyan": [0,139,139],
  22094. "darkgoldenrod": [184,134,11],
  22095. "darkgray": [169,169,169],
  22096. "darkgreen": [0,100,0],
  22097. "darkgrey": [169,169,169],
  22098. "darkkhaki": [189,183,107],
  22099. "darkmagenta": [139,0,139],
  22100. "darkolivegreen": [85,107,47],
  22101. "darkorange": [255,140,0],
  22102. "darkorchid": [153,50,204],
  22103. "darkred": [139,0,0],
  22104. "darksalmon": [233,150,122],
  22105. "darkseagreen": [143,188,143],
  22106. "darkslateblue": [72,61,139],
  22107. "darkslategray": [47,79,79],
  22108. "darkslategrey": [47,79,79],
  22109. "darkturquoise": [0,206,209],
  22110. "darkviolet": [148,0,211],
  22111. "deeppink": [255,20,147],
  22112. "deepskyblue": [0,191,255],
  22113. "dimgray": [105,105,105],
  22114. "dimgrey": [105,105,105],
  22115. "dodgerblue": [30,144,255],
  22116. "firebrick": [178,34,34],
  22117. "floralwhite": [255,250,240],
  22118. "forestgreen": [34,139,34],
  22119. "gainsboro": [220,220,220],
  22120. "ghostwhite": [248,248,255],
  22121. "gold": [255,215,0],
  22122. "goldenrod": [218,165,32],
  22123. "greenyellow": [173,255,47],
  22124. "grey": [128,128,128],
  22125. "honeydew": [240,255,240],
  22126. "hotpink": [255,105,180],
  22127. "indianred": [205,92,92],
  22128. "indigo": [75,0,130],
  22129. "ivory": [255,255,240],
  22130. "khaki": [240,230,140],
  22131. "lavender": [230,230,250],
  22132. "lavenderblush": [255,240,245],
  22133. "lawngreen": [124,252,0],
  22134. "lemonchiffon": [255,250,205],
  22135. "lightblue": [173,216,230],
  22136. "lightcoral": [240,128,128],
  22137. "lightcyan": [224,255,255],
  22138. "lightgoldenrodyellow": [250,250,210],
  22139. "lightgray": [211,211,211],
  22140. "lightgreen": [144,238,144],
  22141. "lightgrey": [211,211,211],
  22142. "lightpink": [255,182,193],
  22143. "lightsalmon": [255,160,122],
  22144. "lightseagreen": [32,178,170],
  22145. "lightskyblue": [135,206,250],
  22146. "lightslategray": [119,136,153],
  22147. "lightslategrey": [119,136,153],
  22148. "lightsteelblue": [176,196,222],
  22149. "lightyellow": [255,255,224],
  22150. "limegreen": [50,205,50],
  22151. "linen": [250,240,230],
  22152. "magenta": [255,0,255],
  22153. "mediumaquamarine": [102,205,170],
  22154. "mediumblue": [0,0,205],
  22155. "mediumorchid": [186,85,211],
  22156. "mediumpurple": [147,112,219],
  22157. "mediumseagreen": [60,179,113],
  22158. "mediumslateblue": [123,104,238],
  22159. "mediumspringgreen": [0,250,154],
  22160. "mediumturquoise": [72,209,204],
  22161. "mediumvioletred": [199,21,133],
  22162. "midnightblue": [25,25,112],
  22163. "mintcream": [245,255,250],
  22164. "mistyrose": [255,228,225],
  22165. "moccasin": [255,228,181],
  22166. "navajowhite": [255,222,173],
  22167. "oldlace": [253,245,230],
  22168. "olivedrab": [107,142,35],
  22169. "orange": [255,165,0],
  22170. "orangered": [255,69,0],
  22171. "orchid": [218,112,214],
  22172. "palegoldenrod": [238,232,170],
  22173. "palegreen": [152,251,152],
  22174. "paleturquoise": [175,238,238],
  22175. "palevioletred": [219,112,147],
  22176. "papayawhip": [255,239,213],
  22177. "peachpuff": [255,218,185],
  22178. "peru": [205,133,63],
  22179. "pink": [255,192,203],
  22180. "plum": [221,160,221],
  22181. "powderblue": [176,224,230],
  22182. "rosybrown": [188,143,143],
  22183. "royalblue": [65,105,225],
  22184. "saddlebrown": [139,69,19],
  22185. "salmon": [250,128,114],
  22186. "sandybrown": [244,164,96],
  22187. "seagreen": [46,139,87],
  22188. "seashell": [255,245,238],
  22189. "sienna": [160,82,45],
  22190. "skyblue": [135,206,235],
  22191. "slateblue": [106,90,205],
  22192. "slategray": [112,128,144],
  22193. "slategrey": [112,128,144],
  22194. "snow": [255,250,250],
  22195. "springgreen": [0,255,127],
  22196. "steelblue": [70,130,180],
  22197. "tan": [210,180,140],
  22198. "thistle": [216,191,216],
  22199. "tomato": [255,99,71],
  22200. "turquoise": [64,224,208],
  22201. "violet": [238,130,238],
  22202. "wheat": [245,222,179],
  22203. "whitesmoke": [245,245,245],
  22204. "yellowgreen": [154,205,50]
  22205. });
  22206. return Color;
  22207. });
  22208. },
  22209. 'url:dijit/form/templates/Spinner.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\"\n\tid=\"widget_${id}\" role=\"presentation\"\n\t><div class=\"dijitReset dijitButtonNode dijitSpinnerButtonContainer\"\n\t\t><input class=\"dijitReset dijitInputField dijitSpinnerButtonInner\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t\t/><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitUpArrowButton\"\n\t\t\tdata-dojo-attach-point=\"upArrowNode\"\n\t\t\t><div class=\"dijitArrowButtonInner\"\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9650;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t\t\t\t\t${_buttonInputDisabled}\n\t\t\t/></div\n\t\t></div\n\t\t><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitDownArrowButton\"\n\t\t\tdata-dojo-attach-point=\"downArrowNode\"\n\t\t\t><div class=\"dijitArrowButtonInner\"\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9660;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t\t\t\t\t${_buttonInputDisabled}\n\t\t\t/></div\n\t\t></div\n\t></div\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class='dijitReset dijitInputInner' data-dojo-attach-point=\"textbox,focusNode\" type=\"${type}\" data-dojo-attach-event=\"onkeypress:_onKeyPress\"\n\t\t\trole=\"spinbutton\" autocomplete=\"off\" ${!nameAttrSetting}\n\t/></div\n></div>\n",
  22210. 'dijit/tree/_dndContainer':function(){
  22211. define([
  22212. "dojo/aspect", // aspect.after
  22213. "dojo/_base/declare", // declare
  22214. "dojo/dom-class", // domClass.add domClass.remove domClass.replace
  22215. "dojo/_base/event", // event.stop
  22216. "dojo/_base/lang", // lang.getObject lang.mixin lang.hitch
  22217. "dojo/mouse", // mouse.enter, mouse.leave
  22218. "dojo/on"
  22219. ], function(aspect, declare, domClass, event, lang, mouse, on){
  22220. // module:
  22221. // dijit/tree/_dndContainer
  22222. // summary:
  22223. // This is a base class for `dijit.tree._dndSelector`, and isn't meant to be used directly.
  22224. // It's modeled after `dojo.dnd.Container`.
  22225. return declare("dijit.tree._dndContainer", null, {
  22226. // summary:
  22227. // This is a base class for `dijit.tree._dndSelector`, and isn't meant to be used directly.
  22228. // It's modeled after `dojo.dnd.Container`.
  22229. // tags:
  22230. // protected
  22231. /*=====
  22232. // current: DomNode
  22233. // The currently hovered TreeNode.rowNode (which is the DOM node
  22234. // associated w/a given node in the tree, excluding it's descendants)
  22235. current: null,
  22236. =====*/
  22237. constructor: function(tree, params){
  22238. // summary:
  22239. // A constructor of the Container
  22240. // tree: Node
  22241. // Node or node's id to build the container on
  22242. // params: dijit.tree.__SourceArgs
  22243. // A dict of parameters, which gets mixed into the object
  22244. // tags:
  22245. // private
  22246. this.tree = tree;
  22247. this.node = tree.domNode; // TODO: rename; it's not a TreeNode but the whole Tree
  22248. lang.mixin(this, params);
  22249. // class-specific variables
  22250. this.current = null; // current TreeNode's DOM node
  22251. // states
  22252. this.containerState = "";
  22253. domClass.add(this.node, "dojoDndContainer");
  22254. // set up events
  22255. this.events = [
  22256. // container level events
  22257. on(this.node, mouse.enter, lang.hitch(this, "onOverEvent")),
  22258. on(this.node, mouse.leave, lang.hitch(this, "onOutEvent")),
  22259. // switching between TreeNodes
  22260. aspect.after(this.tree, "_onNodeMouseEnter", lang.hitch(this, "onMouseOver"), true),
  22261. aspect.after(this.tree, "_onNodeMouseLeave", lang.hitch(this, "onMouseOut"), true),
  22262. // cancel text selection and text dragging
  22263. on(this.node, "dragstart", lang.hitch(event, "stop")),
  22264. on(this.node, "selectstart", lang.hitch(event, "stop"))
  22265. ];
  22266. },
  22267. destroy: function(){
  22268. // summary:
  22269. // Prepares this object to be garbage-collected
  22270. var h;
  22271. while(h = this.events.pop()){ h.remove(); }
  22272. // this.clearItems();
  22273. this.node = this.parent = null;
  22274. },
  22275. // mouse events
  22276. onMouseOver: function(widget /*===== , evt =====*/){
  22277. // summary:
  22278. // Called when mouse is moved over a TreeNode
  22279. // widget: TreeNode
  22280. // evt: Event
  22281. // tags:
  22282. // protected
  22283. this.current = widget;
  22284. },
  22285. onMouseOut: function(/*===== widget, evt =====*/){
  22286. // summary:
  22287. // Called when mouse is moved away from a TreeNode
  22288. // widget: TreeNode
  22289. // evt: Event
  22290. // tags:
  22291. // protected
  22292. this.current = null;
  22293. },
  22294. _changeState: function(type, newState){
  22295. // summary:
  22296. // Changes a named state to new state value
  22297. // type: String
  22298. // A name of the state to change
  22299. // newState: String
  22300. // new state
  22301. var prefix = "dojoDnd" + type;
  22302. var state = type.toLowerCase() + "State";
  22303. //domClass.replace(this.node, prefix + newState, prefix + this[state]);
  22304. domClass.replace(this.node, prefix + newState, prefix + this[state]);
  22305. this[state] = newState;
  22306. },
  22307. _addItemClass: function(node, type){
  22308. // summary:
  22309. // Adds a class with prefix "dojoDndItem"
  22310. // node: Node
  22311. // A node
  22312. // type: String
  22313. // A variable suffix for a class name
  22314. domClass.add(node, "dojoDndItem" + type);
  22315. },
  22316. _removeItemClass: function(node, type){
  22317. // summary:
  22318. // Removes a class with prefix "dojoDndItem"
  22319. // node: Node
  22320. // A node
  22321. // type: String
  22322. // A variable suffix for a class name
  22323. domClass.remove(node, "dojoDndItem" + type);
  22324. },
  22325. onOverEvent: function(){
  22326. // summary:
  22327. // This function is called once, when mouse is over our container
  22328. // tags:
  22329. // protected
  22330. this._changeState("Container", "Over");
  22331. },
  22332. onOutEvent: function(){
  22333. // summary:
  22334. // This function is called once, when mouse is out of our container
  22335. // tags:
  22336. // protected
  22337. this._changeState("Container", "");
  22338. }
  22339. });
  22340. });
  22341. },
  22342. 'dojo/date/locale':function(){
  22343. define([
  22344. "../_base/kernel",
  22345. "../_base/lang",
  22346. "../_base/array",
  22347. "../date",
  22348. "../cldr/supplemental",
  22349. "../regexp",
  22350. "../string",
  22351. "../i18n!../cldr/nls/gregorian"
  22352. ], function(dojo, lang, array, date, cldr, regexp, string, gregorian) {
  22353. // module:
  22354. // dojo/date/locale
  22355. // summary:
  22356. // This modules defines dojo.date.locale, localization methods for Date.
  22357. lang.getObject("date.locale", true, dojo);
  22358. // Localization methods for Date. Honor local customs using locale-dependent dojo.cldr data.
  22359. // Load the bundles containing localization information for
  22360. // names and formats
  22361. //NOTE: Everything in this module assumes Gregorian calendars.
  22362. // Other calendars will be implemented in separate modules.
  22363. // Format a pattern without literals
  22364. function formatPattern(dateObject, bundle, options, pattern){
  22365. return pattern.replace(/([a-z])\1*/ig, function(match){
  22366. var s, pad,
  22367. c = match.charAt(0),
  22368. l = match.length,
  22369. widthList = ["abbr", "wide", "narrow"];
  22370. switch(c){
  22371. case 'G':
  22372. s = bundle[(l < 4) ? "eraAbbr" : "eraNames"][dateObject.getFullYear() < 0 ? 0 : 1];
  22373. break;
  22374. case 'y':
  22375. s = dateObject.getFullYear();
  22376. switch(l){
  22377. case 1:
  22378. break;
  22379. case 2:
  22380. if(!options.fullYear){
  22381. s = String(s); s = s.substr(s.length - 2);
  22382. break;
  22383. }
  22384. // fallthrough
  22385. default:
  22386. pad = true;
  22387. }
  22388. break;
  22389. case 'Q':
  22390. case 'q':
  22391. s = Math.ceil((dateObject.getMonth()+1)/3);
  22392. // switch(l){
  22393. // case 1: case 2:
  22394. pad = true;
  22395. // break;
  22396. // case 3: case 4: // unimplemented
  22397. // }
  22398. break;
  22399. case 'M':
  22400. var m = dateObject.getMonth();
  22401. if(l<3){
  22402. s = m+1; pad = true;
  22403. }else{
  22404. var propM = ["months", "format", widthList[l-3]].join("-");
  22405. s = bundle[propM][m];
  22406. }
  22407. break;
  22408. case 'w':
  22409. var firstDay = 0;
  22410. s = dojo.date.locale._getWeekOfYear(dateObject, firstDay); pad = true;
  22411. break;
  22412. case 'd':
  22413. s = dateObject.getDate(); pad = true;
  22414. break;
  22415. case 'D':
  22416. s = dojo.date.locale._getDayOfYear(dateObject); pad = true;
  22417. break;
  22418. case 'E':
  22419. var d = dateObject.getDay();
  22420. if(l<3){
  22421. s = d+1; pad = true;
  22422. }else{
  22423. var propD = ["days", "format", widthList[l-3]].join("-");
  22424. s = bundle[propD][d];
  22425. }
  22426. break;
  22427. case 'a':
  22428. var timePeriod = (dateObject.getHours() < 12) ? 'am' : 'pm';
  22429. s = options[timePeriod] || bundle['dayPeriods-format-wide-' + timePeriod];
  22430. break;
  22431. case 'h':
  22432. case 'H':
  22433. case 'K':
  22434. case 'k':
  22435. var h = dateObject.getHours();
  22436. // strange choices in the date format make it impossible to write this succinctly
  22437. switch (c){
  22438. case 'h': // 1-12
  22439. s = (h % 12) || 12;
  22440. break;
  22441. case 'H': // 0-23
  22442. s = h;
  22443. break;
  22444. case 'K': // 0-11
  22445. s = (h % 12);
  22446. break;
  22447. case 'k': // 1-24
  22448. s = h || 24;
  22449. break;
  22450. }
  22451. pad = true;
  22452. break;
  22453. case 'm':
  22454. s = dateObject.getMinutes(); pad = true;
  22455. break;
  22456. case 's':
  22457. s = dateObject.getSeconds(); pad = true;
  22458. break;
  22459. case 'S':
  22460. s = Math.round(dateObject.getMilliseconds() * Math.pow(10, l-3)); pad = true;
  22461. break;
  22462. case 'v': // FIXME: don't know what this is. seems to be same as z?
  22463. case 'z':
  22464. // We only have one timezone to offer; the one from the browser
  22465. s = dojo.date.locale._getZone(dateObject, true, options);
  22466. if(s){break;}
  22467. l=4;
  22468. // fallthrough... use GMT if tz not available
  22469. case 'Z':
  22470. var offset = dojo.date.locale._getZone(dateObject, false, options);
  22471. var tz = [
  22472. (offset<=0 ? "+" : "-"),
  22473. string.pad(Math.floor(Math.abs(offset)/60), 2),
  22474. string.pad(Math.abs(offset)% 60, 2)
  22475. ];
  22476. if(l==4){
  22477. tz.splice(0, 0, "GMT");
  22478. tz.splice(3, 0, ":");
  22479. }
  22480. s = tz.join("");
  22481. break;
  22482. // case 'Y': case 'u': case 'W': case 'F': case 'g': case 'A': case 'e':
  22483. // console.log(match+" modifier unimplemented");
  22484. default:
  22485. throw new Error("dojo.date.locale.format: invalid pattern char: "+pattern);
  22486. }
  22487. if(pad){ s = string.pad(s, l); }
  22488. return s;
  22489. });
  22490. }
  22491. /*=====
  22492. dojo.date.locale.__FormatOptions = function(){
  22493. // selector: String
  22494. // choice of 'time','date' (default: date and time)
  22495. // formatLength: String
  22496. // choice of long, short, medium or full (plus any custom additions). Defaults to 'short'
  22497. // datePattern:String
  22498. // override pattern with this string
  22499. // timePattern:String
  22500. // override pattern with this string
  22501. // am: String
  22502. // override strings for am in times
  22503. // pm: String
  22504. // override strings for pm in times
  22505. // locale: String
  22506. // override the locale used to determine formatting rules
  22507. // fullYear: Boolean
  22508. // (format only) use 4 digit years whenever 2 digit years are called for
  22509. // strict: Boolean
  22510. // (parse only) strict parsing, off by default
  22511. this.selector = selector;
  22512. this.formatLength = formatLength;
  22513. this.datePattern = datePattern;
  22514. this.timePattern = timePattern;
  22515. this.am = am;
  22516. this.pm = pm;
  22517. this.locale = locale;
  22518. this.fullYear = fullYear;
  22519. this.strict = strict;
  22520. }
  22521. =====*/
  22522. dojo.date.locale._getZone = function(/*Date*/dateObject, /*boolean*/getName, /*dojo.date.locale.__FormatOptions?*/options){
  22523. // summary:
  22524. // Returns the zone (or offset) for the given date and options. This
  22525. // is broken out into a separate function so that it can be overridden
  22526. // by timezone-aware code.
  22527. //
  22528. // dateObject:
  22529. // the date and/or time being formatted.
  22530. //
  22531. // getName:
  22532. // Whether to return the timezone string (if true), or the offset (if false)
  22533. //
  22534. // options:
  22535. // The options being used for formatting
  22536. if(getName){
  22537. return date.getTimezoneName(dateObject);
  22538. }else{
  22539. return dateObject.getTimezoneOffset();
  22540. }
  22541. };
  22542. dojo.date.locale.format = function(/*Date*/dateObject, /*dojo.date.locale.__FormatOptions?*/options){
  22543. // summary:
  22544. // Format a Date object as a String, using locale-specific settings.
  22545. //
  22546. // description:
  22547. // Create a string from a Date object using a known localized pattern.
  22548. // By default, this method formats both date and time from dateObject.
  22549. // Formatting patterns are chosen appropriate to the locale. Different
  22550. // formatting lengths may be chosen, with "full" used by default.
  22551. // Custom patterns may be used or registered with translations using
  22552. // the dojo.date.locale.addCustomFormats method.
  22553. // Formatting patterns are implemented using [the syntax described at
  22554. // unicode.org](http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns)
  22555. //
  22556. // dateObject:
  22557. // the date and/or time to be formatted. If a time only is formatted,
  22558. // the values in the year, month, and day fields are irrelevant. The
  22559. // opposite is true when formatting only dates.
  22560. options = options || {};
  22561. var locale = dojo.i18n.normalizeLocale(options.locale),
  22562. formatLength = options.formatLength || 'short',
  22563. bundle = dojo.date.locale._getGregorianBundle(locale),
  22564. str = [],
  22565. sauce = lang.hitch(this, formatPattern, dateObject, bundle, options);
  22566. if(options.selector == "year"){
  22567. return _processPattern(bundle["dateFormatItem-yyyy"] || "yyyy", sauce);
  22568. }
  22569. var pattern;
  22570. if(options.selector != "date"){
  22571. pattern = options.timePattern || bundle["timeFormat-"+formatLength];
  22572. if(pattern){str.push(_processPattern(pattern, sauce));}
  22573. }
  22574. if(options.selector != "time"){
  22575. pattern = options.datePattern || bundle["dateFormat-"+formatLength];
  22576. if(pattern){str.push(_processPattern(pattern, sauce));}
  22577. }
  22578. return str.length == 1 ? str[0] : bundle["dateTimeFormat-"+formatLength].replace(/\{(\d+)\}/g,
  22579. function(match, key){ return str[key]; }); // String
  22580. };
  22581. dojo.date.locale.regexp = function(/*dojo.date.locale.__FormatOptions?*/options){
  22582. // summary:
  22583. // Builds the regular needed to parse a localized date
  22584. return dojo.date.locale._parseInfo(options).regexp; // String
  22585. };
  22586. dojo.date.locale._parseInfo = function(/*dojo.date.locale.__FormatOptions?*/options){
  22587. options = options || {};
  22588. var locale = dojo.i18n.normalizeLocale(options.locale),
  22589. bundle = dojo.date.locale._getGregorianBundle(locale),
  22590. formatLength = options.formatLength || 'short',
  22591. datePattern = options.datePattern || bundle["dateFormat-" + formatLength],
  22592. timePattern = options.timePattern || bundle["timeFormat-" + formatLength],
  22593. pattern;
  22594. if(options.selector == 'date'){
  22595. pattern = datePattern;
  22596. }else if(options.selector == 'time'){
  22597. pattern = timePattern;
  22598. }else{
  22599. pattern = bundle["dateTimeFormat-"+formatLength].replace(/\{(\d+)\}/g,
  22600. function(match, key){ return [timePattern, datePattern][key]; });
  22601. }
  22602. var tokens = [],
  22603. re = _processPattern(pattern, lang.hitch(this, _buildDateTimeRE, tokens, bundle, options));
  22604. return {regexp: re, tokens: tokens, bundle: bundle};
  22605. };
  22606. dojo.date.locale.parse = function(/*String*/value, /*dojo.date.locale.__FormatOptions?*/options){
  22607. // summary:
  22608. // Convert a properly formatted string to a primitive Date object,
  22609. // using locale-specific settings.
  22610. //
  22611. // description:
  22612. // Create a Date object from a string using a known localized pattern.
  22613. // By default, this method parses looking for both date and time in the string.
  22614. // Formatting patterns are chosen appropriate to the locale. Different
  22615. // formatting lengths may be chosen, with "full" used by default.
  22616. // Custom patterns may be used or registered with translations using
  22617. // the dojo.date.locale.addCustomFormats method.
  22618. //
  22619. // Formatting patterns are implemented using [the syntax described at
  22620. // unicode.org](http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns)
  22621. // When two digit years are used, a century is chosen according to a sliding
  22622. // window of 80 years before and 20 years after present year, for both `yy` and `yyyy` patterns.
  22623. // year < 100CE requires strict mode.
  22624. //
  22625. // value:
  22626. // A string representation of a date
  22627. // remove non-printing bidi control chars from input and pattern
  22628. var controlChars = /[\u200E\u200F\u202A\u202E]/g,
  22629. info = dojo.date.locale._parseInfo(options),
  22630. tokens = info.tokens, bundle = info.bundle,
  22631. re = new RegExp("^" + info.regexp.replace(controlChars, "") + "$",
  22632. info.strict ? "" : "i"),
  22633. match = re.exec(value && value.replace(controlChars, ""));
  22634. if(!match){ return null; } // null
  22635. var widthList = ['abbr', 'wide', 'narrow'],
  22636. result = [1970,0,1,0,0,0,0], // will get converted to a Date at the end
  22637. amPm = "",
  22638. valid = dojo.every(match, function(v, i){
  22639. if(!i){return true;}
  22640. var token=tokens[i-1];
  22641. var l=token.length;
  22642. switch(token.charAt(0)){
  22643. case 'y':
  22644. if(l != 2 && options.strict){
  22645. //interpret year literally, so '5' would be 5 A.D.
  22646. result[0] = v;
  22647. }else{
  22648. if(v<100){
  22649. v = Number(v);
  22650. //choose century to apply, according to a sliding window
  22651. //of 80 years before and 20 years after present year
  22652. var year = '' + new Date().getFullYear(),
  22653. century = year.substring(0, 2) * 100,
  22654. cutoff = Math.min(Number(year.substring(2, 4)) + 20, 99);
  22655. result[0] = (v < cutoff) ? century + v : century - 100 + v;
  22656. }else{
  22657. //we expected 2 digits and got more...
  22658. if(options.strict){
  22659. return false;
  22660. }
  22661. //interpret literally, so '150' would be 150 A.D.
  22662. //also tolerate '1950', if 'yyyy' input passed to 'yy' format
  22663. result[0] = v;
  22664. }
  22665. }
  22666. break;
  22667. case 'M':
  22668. if(l>2){
  22669. var months = bundle['months-format-' + widthList[l-3]].concat();
  22670. if(!options.strict){
  22671. //Tolerate abbreviating period in month part
  22672. //Case-insensitive comparison
  22673. v = v.replace(".","").toLowerCase();
  22674. months = dojo.map(months, function(s){ return s.replace(".","").toLowerCase(); } );
  22675. }
  22676. v = dojo.indexOf(months, v);
  22677. if(v == -1){
  22678. // console.log("dojo.date.locale.parse: Could not parse month name: '" + v + "'.");
  22679. return false;
  22680. }
  22681. }else{
  22682. v--;
  22683. }
  22684. result[1] = v;
  22685. break;
  22686. case 'E':
  22687. case 'e':
  22688. var days = bundle['days-format-' + widthList[l-3]].concat();
  22689. if(!options.strict){
  22690. //Case-insensitive comparison
  22691. v = v.toLowerCase();
  22692. days = dojo.map(days, function(d){return d.toLowerCase();});
  22693. }
  22694. v = dojo.indexOf(days, v);
  22695. if(v == -1){
  22696. // console.log("dojo.date.locale.parse: Could not parse weekday name: '" + v + "'.");
  22697. return false;
  22698. }
  22699. //TODO: not sure what to actually do with this input,
  22700. //in terms of setting something on the Date obj...?
  22701. //without more context, can't affect the actual date
  22702. //TODO: just validate?
  22703. break;
  22704. case 'D':
  22705. result[1] = 0;
  22706. // fallthrough...
  22707. case 'd':
  22708. result[2] = v;
  22709. break;
  22710. case 'a': //am/pm
  22711. var am = options.am || bundle['dayPeriods-format-wide-am'],
  22712. pm = options.pm || bundle['dayPeriods-format-wide-pm'];
  22713. if(!options.strict){
  22714. var period = /\./g;
  22715. v = v.replace(period,'').toLowerCase();
  22716. am = am.replace(period,'').toLowerCase();
  22717. pm = pm.replace(period,'').toLowerCase();
  22718. }
  22719. if(options.strict && v != am && v != pm){
  22720. // console.log("dojo.date.locale.parse: Could not parse am/pm part.");
  22721. return false;
  22722. }
  22723. // we might not have seen the hours field yet, so store the state and apply hour change later
  22724. amPm = (v == pm) ? 'p' : (v == am) ? 'a' : '';
  22725. break;
  22726. case 'K': //hour (1-24)
  22727. if(v == 24){ v = 0; }
  22728. // fallthrough...
  22729. case 'h': //hour (1-12)
  22730. case 'H': //hour (0-23)
  22731. case 'k': //hour (0-11)
  22732. //TODO: strict bounds checking, padding
  22733. if(v > 23){
  22734. // console.log("dojo.date.locale.parse: Illegal hours value");
  22735. return false;
  22736. }
  22737. //in the 12-hour case, adjusting for am/pm requires the 'a' part
  22738. //which could come before or after the hour, so we will adjust later
  22739. result[3] = v;
  22740. break;
  22741. case 'm': //minutes
  22742. result[4] = v;
  22743. break;
  22744. case 's': //seconds
  22745. result[5] = v;
  22746. break;
  22747. case 'S': //milliseconds
  22748. result[6] = v;
  22749. // break;
  22750. // case 'w':
  22751. //TODO var firstDay = 0;
  22752. // default:
  22753. //TODO: throw?
  22754. // console.log("dojo.date.locale.parse: unsupported pattern char=" + token.charAt(0));
  22755. }
  22756. return true;
  22757. });
  22758. var hours = +result[3];
  22759. if(amPm === 'p' && hours < 12){
  22760. result[3] = hours + 12; //e.g., 3pm -> 15
  22761. }else if(amPm === 'a' && hours == 12){
  22762. result[3] = 0; //12am -> 0
  22763. }
  22764. //TODO: implement a getWeekday() method in order to test
  22765. //validity of input strings containing 'EEE' or 'EEEE'...
  22766. var dateObject = new Date(result[0], result[1], result[2], result[3], result[4], result[5], result[6]); // Date
  22767. if(options.strict){
  22768. dateObject.setFullYear(result[0]);
  22769. }
  22770. // Check for overflow. The Date() constructor normalizes things like April 32nd...
  22771. //TODO: why isn't this done for times as well?
  22772. var allTokens = tokens.join(""),
  22773. dateToken = allTokens.indexOf('d') != -1,
  22774. monthToken = allTokens.indexOf('M') != -1;
  22775. if(!valid ||
  22776. (monthToken && dateObject.getMonth() > result[1]) ||
  22777. (dateToken && dateObject.getDate() > result[2])){
  22778. return null;
  22779. }
  22780. // Check for underflow, due to DST shifts. See #9366
  22781. // This assumes a 1 hour dst shift correction at midnight
  22782. // We could compare the timezone offset after the shift and add the difference instead.
  22783. if((monthToken && dateObject.getMonth() < result[1]) ||
  22784. (dateToken && dateObject.getDate() < result[2])){
  22785. dateObject = date.add(dateObject, "hour", 1);
  22786. }
  22787. return dateObject; // Date
  22788. };
  22789. function _processPattern(pattern, applyPattern, applyLiteral, applyAll){
  22790. //summary: Process a pattern with literals in it
  22791. // Break up on single quotes, treat every other one as a literal, except '' which becomes '
  22792. var identity = function(x){return x;};
  22793. applyPattern = applyPattern || identity;
  22794. applyLiteral = applyLiteral || identity;
  22795. applyAll = applyAll || identity;
  22796. //split on single quotes (which escape literals in date format strings)
  22797. //but preserve escaped single quotes (e.g., o''clock)
  22798. var chunks = pattern.match(/(''|[^'])+/g),
  22799. literal = pattern.charAt(0) == "'";
  22800. dojo.forEach(chunks, function(chunk, i){
  22801. if(!chunk){
  22802. chunks[i]='';
  22803. }else{
  22804. chunks[i]=(literal ? applyLiteral : applyPattern)(chunk.replace(/''/g, "'"));
  22805. literal = !literal;
  22806. }
  22807. });
  22808. return applyAll(chunks.join(''));
  22809. }
  22810. function _buildDateTimeRE(tokens, bundle, options, pattern){
  22811. pattern = regexp.escapeString(pattern);
  22812. if(!options.strict){ pattern = pattern.replace(" a", " ?a"); } // kludge to tolerate no space before am/pm
  22813. return pattern.replace(/([a-z])\1*/ig, function(match){
  22814. // Build a simple regexp. Avoid captures, which would ruin the tokens list
  22815. var s,
  22816. c = match.charAt(0),
  22817. l = match.length,
  22818. p2 = '', p3 = '';
  22819. if(options.strict){
  22820. if(l > 1){ p2 = '0' + '{'+(l-1)+'}'; }
  22821. if(l > 2){ p3 = '0' + '{'+(l-2)+'}'; }
  22822. }else{
  22823. p2 = '0?'; p3 = '0{0,2}';
  22824. }
  22825. switch(c){
  22826. case 'y':
  22827. s = '\\d{2,4}';
  22828. break;
  22829. case 'M':
  22830. s = (l>2) ? '\\S+?' : '1[0-2]|'+p2+'[1-9]';
  22831. break;
  22832. case 'D':
  22833. s = '[12][0-9][0-9]|3[0-5][0-9]|36[0-6]|'+p2+'[1-9][0-9]|'+p3+'[1-9]';
  22834. break;
  22835. case 'd':
  22836. s = '3[01]|[12]\\d|'+p2+'[1-9]';
  22837. break;
  22838. case 'w':
  22839. s = '[1-4][0-9]|5[0-3]|'+p2+'[1-9]';
  22840. break;
  22841. case 'E':
  22842. s = '\\S+';
  22843. break;
  22844. case 'h': //hour (1-12)
  22845. s = '1[0-2]|'+p2+'[1-9]';
  22846. break;
  22847. case 'k': //hour (0-11)
  22848. s = '1[01]|'+p2+'\\d';
  22849. break;
  22850. case 'H': //hour (0-23)
  22851. s = '1\\d|2[0-3]|'+p2+'\\d';
  22852. break;
  22853. case 'K': //hour (1-24)
  22854. s = '1\\d|2[0-4]|'+p2+'[1-9]';
  22855. break;
  22856. case 'm':
  22857. case 's':
  22858. s = '[0-5]\\d';
  22859. break;
  22860. case 'S':
  22861. s = '\\d{'+l+'}';
  22862. break;
  22863. case 'a':
  22864. var am = options.am || bundle['dayPeriods-format-wide-am'],
  22865. pm = options.pm || bundle['dayPeriods-format-wide-pm'];
  22866. s = am + '|' + pm;
  22867. if(!options.strict){
  22868. if(am != am.toLowerCase()){ s += '|' + am.toLowerCase(); }
  22869. if(pm != pm.toLowerCase()){ s += '|' + pm.toLowerCase(); }
  22870. if(s.indexOf('.') != -1){ s += '|' + s.replace(/\./g, ""); }
  22871. }
  22872. s = s.replace(/\./g, "\\.");
  22873. break;
  22874. default:
  22875. // case 'v':
  22876. // case 'z':
  22877. // case 'Z':
  22878. s = ".*";
  22879. // console.log("parse of date format, pattern=" + pattern);
  22880. }
  22881. if(tokens){ tokens.push(match); }
  22882. return "(" + s + ")"; // add capture
  22883. }).replace(/[\xa0 ]/g, "[\\s\\xa0]"); // normalize whitespace. Need explicit handling of \xa0 for IE.
  22884. }
  22885. var _customFormats = [];
  22886. dojo.date.locale.addCustomFormats = function(/*String*/packageName, /*String*/bundleName){
  22887. // summary:
  22888. // Add a reference to a bundle containing localized custom formats to be
  22889. // used by date/time formatting and parsing routines.
  22890. //
  22891. // description:
  22892. // The user may add custom localized formats where the bundle has properties following the
  22893. // same naming convention used by dojo.cldr: `dateFormat-xxxx` / `timeFormat-xxxx`
  22894. // The pattern string should match the format used by the CLDR.
  22895. // See dojo.date.locale.format() for details.
  22896. // The resources must be loaded by dojo.requireLocalization() prior to use
  22897. _customFormats.push({pkg:packageName,name:bundleName});
  22898. };
  22899. dojo.date.locale._getGregorianBundle = function(/*String*/locale){
  22900. var gregorian = {};
  22901. dojo.forEach(_customFormats, function(desc){
  22902. var bundle = dojo.i18n.getLocalization(desc.pkg, desc.name, locale);
  22903. gregorian = lang.mixin(gregorian, bundle);
  22904. }, this);
  22905. return gregorian; /*Object*/
  22906. };
  22907. dojo.date.locale.addCustomFormats("dojo.cldr","gregorian");
  22908. dojo.date.locale.getNames = function(/*String*/item, /*String*/type, /*String?*/context, /*String?*/locale){
  22909. // summary:
  22910. // Used to get localized strings from dojo.cldr for day or month names.
  22911. //
  22912. // item:
  22913. // 'months' || 'days'
  22914. // type:
  22915. // 'wide' || 'abbr' || 'narrow' (e.g. "Monday", "Mon", or "M" respectively, in English)
  22916. // context:
  22917. // 'standAlone' || 'format' (default)
  22918. // locale:
  22919. // override locale used to find the names
  22920. var label,
  22921. lookup = dojo.date.locale._getGregorianBundle(locale),
  22922. props = [item, context, type];
  22923. if(context == 'standAlone'){
  22924. var key = props.join('-');
  22925. label = lookup[key];
  22926. // Fall back to 'format' flavor of name
  22927. if(label[0] == 1){ label = undefined; } // kludge, in the absence of real aliasing support in dojo.cldr
  22928. }
  22929. props[1] = 'format';
  22930. // return by copy so changes won't be made accidentally to the in-memory model
  22931. return (label || lookup[props.join('-')]).concat(); /*Array*/
  22932. };
  22933. dojo.date.locale.isWeekend = function(/*Date?*/dateObject, /*String?*/locale){
  22934. // summary:
  22935. // Determines if the date falls on a weekend, according to local custom.
  22936. var weekend = cldr.getWeekend(locale),
  22937. day = (dateObject || new Date()).getDay();
  22938. if(weekend.end < weekend.start){
  22939. weekend.end += 7;
  22940. if(day < weekend.start){ day += 7; }
  22941. }
  22942. return day >= weekend.start && day <= weekend.end; // Boolean
  22943. };
  22944. // These are used only by format and strftime. Do they need to be public? Which module should they go in?
  22945. dojo.date.locale._getDayOfYear = function(/*Date*/dateObject){
  22946. // summary: gets the day of the year as represented by dateObject
  22947. return date.difference(new Date(dateObject.getFullYear(), 0, 1, dateObject.getHours()), dateObject) + 1; // Number
  22948. };
  22949. dojo.date.locale._getWeekOfYear = function(/*Date*/dateObject, /*Number*/firstDayOfWeek){
  22950. if(arguments.length == 1){ firstDayOfWeek = 0; } // Sunday
  22951. var firstDayOfYear = new Date(dateObject.getFullYear(), 0, 1).getDay(),
  22952. adj = (firstDayOfYear - firstDayOfWeek + 7) % 7,
  22953. week = Math.floor((dojo.date.locale._getDayOfYear(dateObject) + adj - 1) / 7);
  22954. // if year starts on the specified day, start counting weeks at 1
  22955. if(firstDayOfYear == firstDayOfWeek){ week++; }
  22956. return week; // Number
  22957. };
  22958. return dojo.date.locale;
  22959. });
  22960. },
  22961. 'url:dijit/templates/InlineEditBox.html':"<span data-dojo-attach-point=\"editNode\" role=\"presentation\" style=\"position: absolute; visibility:hidden\" class=\"dijitReset dijitInline\"\n\tdata-dojo-attach-event=\"onkeypress: _onKeyPress\"\n\t><span data-dojo-attach-point=\"editorPlaceholder\"></span\n\t><span data-dojo-attach-point=\"buttonContainer\"\n\t\t><button data-dojo-type=\"dijit.form.Button\" data-dojo-props=\"label: '${buttonSave}', 'class': 'saveButton'\"\n\t\t\tdata-dojo-attach-point=\"saveButton\" data-dojo-attach-event=\"onClick:save\"></button\n\t\t><button data-dojo-type=\"dijit.form.Button\" data-dojo-props=\"label: '${buttonCancel}', 'class': 'cancelButton'\"\n\t\t\tdata-dojo-attach-point=\"cancelButton\" data-dojo-attach-event=\"onClick:cancel\"></button\n\t></span\n></span>\n",
  22962. 'dijit/form/VerticalRule':function(){
  22963. define([
  22964. "dojo/_base/declare", // declare
  22965. "./HorizontalRule"
  22966. ], function(declare, HorizontalRule){
  22967. /*=====
  22968. var HorizontalRule = dijit.form.HorizontalRule;
  22969. =====*/
  22970. // module:
  22971. // dijit/form/VerticalRule
  22972. // summary:
  22973. // Hash marks for the `dijit.form.VerticalSlider`
  22974. return declare("dijit.form.VerticalRule", HorizontalRule, {
  22975. // summary:
  22976. // Hash marks for the `dijit.form.VerticalSlider`
  22977. templateString: '<div class="dijitRuleContainer dijitRuleContainerV"></div>',
  22978. _positionPrefix: '<div class="dijitRuleMark dijitRuleMarkV" style="top:',
  22979. /*=====
  22980. // container: String
  22981. // This is either "leftDecoration" or "rightDecoration",
  22982. // to indicate whether this rule goes to the left or to the right of the slider.
  22983. // Note that on RTL system, "leftDecoration" would actually go to the right, and vice-versa.
  22984. container: "",
  22985. =====*/
  22986. // Overrides HorizontalRule._isHorizontal
  22987. _isHorizontal: false
  22988. });
  22989. });
  22990. },
  22991. 'dijit/form/_FormSelectWidget':function(){
  22992. define([
  22993. "dojo/_base/array", // array.filter array.forEach array.map array.some
  22994. "dojo/aspect", // aspect.after
  22995. "dojo/data/util/sorter", // util.sorter.createSortFunction
  22996. "dojo/_base/declare", // declare
  22997. "dojo/dom", // dom.setSelectable
  22998. "dojo/dom-class", // domClass.toggle
  22999. "dojo/_base/kernel", // _scopeName
  23000. "dojo/_base/lang", // lang.delegate lang.isArray lang.isObject lang.hitch
  23001. "dojo/query", // query
  23002. "./_FormValueWidget"
  23003. ], function(array, aspect, sorter, declare, dom, domClass, kernel, lang, query, _FormValueWidget){
  23004. /*=====
  23005. var _FormValueWidget = dijit.form._FormValueWidget;
  23006. =====*/
  23007. // module:
  23008. // dijit/form/_FormSelectWidget
  23009. // summary:
  23010. // Extends _FormValueWidget in order to provide "select-specific"
  23011. // values - i.e., those values that are unique to <select> elements.
  23012. /*=====
  23013. dijit.form.__SelectOption = function(){
  23014. // value: String
  23015. // The value of the option. Setting to empty (or missing) will
  23016. // place a separator at that location
  23017. // label: String
  23018. // The label for our option. It can contain html tags.
  23019. // selected: Boolean
  23020. // Whether or not we are a selected option
  23021. // disabled: Boolean
  23022. // Whether or not this specific option is disabled
  23023. this.value = value;
  23024. this.label = label;
  23025. this.selected = selected;
  23026. this.disabled = disabled;
  23027. }
  23028. =====*/
  23029. return declare("dijit.form._FormSelectWidget", _FormValueWidget, {
  23030. // summary:
  23031. // Extends _FormValueWidget in order to provide "select-specific"
  23032. // values - i.e., those values that are unique to <select> elements.
  23033. // This also provides the mechanism for reading the elements from
  23034. // a store, if desired.
  23035. // multiple: [const] Boolean
  23036. // Whether or not we are multi-valued
  23037. multiple: false,
  23038. // options: dijit.form.__SelectOption[]
  23039. // The set of options for our select item. Roughly corresponds to
  23040. // the html <option> tag.
  23041. options: null,
  23042. // store: dojo.data.api.Identity
  23043. // A store which, at the very least implements dojo.data.api.Identity
  23044. // to use for getting our list of options - rather than reading them
  23045. // from the <option> html tags.
  23046. store: null,
  23047. // query: object
  23048. // A query to use when fetching items from our store
  23049. query: null,
  23050. // queryOptions: object
  23051. // Query options to use when fetching from the store
  23052. queryOptions: null,
  23053. // onFetch: Function
  23054. // A callback to do with an onFetch - but before any items are actually
  23055. // iterated over (i.e. to filter even further what you want to add)
  23056. onFetch: null,
  23057. // sortByLabel: Boolean
  23058. // Flag to sort the options returned from a store by the label of
  23059. // the store.
  23060. sortByLabel: true,
  23061. // loadChildrenOnOpen: Boolean
  23062. // By default loadChildren is called when the items are fetched from the
  23063. // store. This property allows delaying loadChildren (and the creation
  23064. // of the options/menuitems) until the user clicks the button to open the
  23065. // dropdown.
  23066. loadChildrenOnOpen: false,
  23067. getOptions: function(/*anything*/ valueOrIdx){
  23068. // summary:
  23069. // Returns a given option (or options).
  23070. // valueOrIdx:
  23071. // If passed in as a string, that string is used to look up the option
  23072. // in the array of options - based on the value property.
  23073. // (See dijit.form.__SelectOption).
  23074. //
  23075. // If passed in a number, then the option with the given index (0-based)
  23076. // within this select will be returned.
  23077. //
  23078. // If passed in a dijit.form.__SelectOption, the same option will be
  23079. // returned if and only if it exists within this select.
  23080. //
  23081. // If passed an array, then an array will be returned with each element
  23082. // in the array being looked up.
  23083. //
  23084. // If not passed a value, then all options will be returned
  23085. //
  23086. // returns:
  23087. // The option corresponding with the given value or index. null
  23088. // is returned if any of the following are true:
  23089. // - A string value is passed in which doesn't exist
  23090. // - An index is passed in which is outside the bounds of the array of options
  23091. // - A dijit.form.__SelectOption is passed in which is not a part of the select
  23092. // NOTE: the compare for passing in a dijit.form.__SelectOption checks
  23093. // if the value property matches - NOT if the exact option exists
  23094. // NOTE: if passing in an array, null elements will be placed in the returned
  23095. // array when a value is not found.
  23096. var lookupValue = valueOrIdx, opts = this.options || [], l = opts.length;
  23097. if(lookupValue === undefined){
  23098. return opts; // dijit.form.__SelectOption[]
  23099. }
  23100. if(lang.isArray(lookupValue)){
  23101. return array.map(lookupValue, "return this.getOptions(item);", this); // dijit.form.__SelectOption[]
  23102. }
  23103. if(lang.isObject(valueOrIdx)){
  23104. // We were passed an option - so see if it's in our array (directly),
  23105. // and if it's not, try and find it by value.
  23106. if(!array.some(this.options, function(o, idx){
  23107. if(o === lookupValue ||
  23108. (o.value && o.value === lookupValue.value)){
  23109. lookupValue = idx;
  23110. return true;
  23111. }
  23112. return false;
  23113. })){
  23114. lookupValue = -1;
  23115. }
  23116. }
  23117. if(typeof lookupValue == "string"){
  23118. for(var i=0; i<l; i++){
  23119. if(opts[i].value === lookupValue){
  23120. lookupValue = i;
  23121. break;
  23122. }
  23123. }
  23124. }
  23125. if(typeof lookupValue == "number" && lookupValue >= 0 && lookupValue < l){
  23126. return this.options[lookupValue]; // dijit.form.__SelectOption
  23127. }
  23128. return null; // null
  23129. },
  23130. addOption: function(/*dijit.form.__SelectOption|dijit.form.__SelectOption[]*/ option){
  23131. // summary:
  23132. // Adds an option or options to the end of the select. If value
  23133. // of the option is empty or missing, a separator is created instead.
  23134. // Passing in an array of options will yield slightly better performance
  23135. // since the children are only loaded once.
  23136. if(!lang.isArray(option)){ option = [option]; }
  23137. array.forEach(option, function(i){
  23138. if(i && lang.isObject(i)){
  23139. this.options.push(i);
  23140. }
  23141. }, this);
  23142. this._loadChildren();
  23143. },
  23144. removeOption: function(/*String|dijit.form.__SelectOption|Number|Array*/ valueOrIdx){
  23145. // summary:
  23146. // Removes the given option or options. You can remove by string
  23147. // (in which case the value is removed), number (in which case the
  23148. // index in the options array is removed), or select option (in
  23149. // which case, the select option with a matching value is removed).
  23150. // You can also pass in an array of those values for a slightly
  23151. // better performance since the children are only loaded once.
  23152. if(!lang.isArray(valueOrIdx)){ valueOrIdx = [valueOrIdx]; }
  23153. var oldOpts = this.getOptions(valueOrIdx);
  23154. array.forEach(oldOpts, function(i){
  23155. // We can get null back in our array - if our option was not found. In
  23156. // that case, we don't want to blow up...
  23157. if(i){
  23158. this.options = array.filter(this.options, function(node){
  23159. return (node.value !== i.value || node.label !== i.label);
  23160. });
  23161. this._removeOptionItem(i);
  23162. }
  23163. }, this);
  23164. this._loadChildren();
  23165. },
  23166. updateOption: function(/*dijit.form.__SelectOption|dijit.form.__SelectOption[]*/ newOption){
  23167. // summary:
  23168. // Updates the values of the given option. The option to update
  23169. // is matched based on the value of the entered option. Passing
  23170. // in an array of new options will yield better performance since
  23171. // the children will only be loaded once.
  23172. if(!lang.isArray(newOption)){ newOption = [newOption]; }
  23173. array.forEach(newOption, function(i){
  23174. var oldOpt = this.getOptions(i), k;
  23175. if(oldOpt){
  23176. for(k in i){ oldOpt[k] = i[k]; }
  23177. }
  23178. }, this);
  23179. this._loadChildren();
  23180. },
  23181. setStore: function(/*dojo.data.api.Identity*/ store,
  23182. /*anything?*/ selectedValue,
  23183. /*Object?*/ fetchArgs){
  23184. // summary:
  23185. // Sets the store you would like to use with this select widget.
  23186. // The selected value is the value of the new store to set. This
  23187. // function returns the original store, in case you want to reuse
  23188. // it or something.
  23189. // store: dojo.data.api.Identity
  23190. // The store you would like to use - it MUST implement dojo.data.api.Identity,
  23191. // and MAY implement dojo.data.api.Notification.
  23192. // selectedValue: anything?
  23193. // The value that this widget should set itself to *after* the store
  23194. // has been loaded
  23195. // fetchArgs: Object?
  23196. // The arguments that will be passed to the store's fetch() function
  23197. var oStore = this.store;
  23198. fetchArgs = fetchArgs || {};
  23199. if(oStore !== store){
  23200. // Our store has changed, so update our notifications
  23201. var h;
  23202. while(h = this._notifyConnections.pop()){ h.remove(); }
  23203. if(store && store.getFeatures()["dojo.data.api.Notification"]){
  23204. this._notifyConnections = [
  23205. aspect.after(store, "onNew", lang.hitch(this, "_onNewItem"), true),
  23206. aspect.after(store, "onDelete", lang.hitch(this, "_onDeleteItem"), true),
  23207. aspect.after(store, "onSet", lang.hitch(this, "_onSetItem"), true)
  23208. ];
  23209. }
  23210. this._set("store", store);
  23211. }
  23212. // Turn off change notifications while we make all these changes
  23213. this._onChangeActive = false;
  23214. // Remove existing options (if there are any)
  23215. if(this.options && this.options.length){
  23216. this.removeOption(this.options);
  23217. }
  23218. // Add our new options
  23219. if(store){
  23220. this._loadingStore = true;
  23221. store.fetch(lang.delegate(fetchArgs, {
  23222. onComplete: function(items, opts){
  23223. if(this.sortByLabel && !fetchArgs.sort && items.length){
  23224. items.sort(sorter.createSortFunction([{
  23225. attribute: store.getLabelAttributes(items[0])[0]
  23226. }], store));
  23227. }
  23228. if(fetchArgs.onFetch){
  23229. items = fetchArgs.onFetch.call(this, items, opts);
  23230. }
  23231. // TODO: Add these guys as a batch, instead of separately
  23232. array.forEach(items, function(i){
  23233. this._addOptionForItem(i);
  23234. }, this);
  23235. // Set our value (which might be undefined), and then tweak
  23236. // it to send a change event with the real value
  23237. this._loadingStore = false;
  23238. this.set("value", "_pendingValue" in this ? this._pendingValue : selectedValue);
  23239. delete this._pendingValue;
  23240. if(!this.loadChildrenOnOpen){
  23241. this._loadChildren();
  23242. }else{
  23243. this._pseudoLoadChildren(items);
  23244. }
  23245. this._fetchedWith = opts;
  23246. this._lastValueReported = this.multiple ? [] : null;
  23247. this._onChangeActive = true;
  23248. this.onSetStore();
  23249. this._handleOnChange(this.value);
  23250. },
  23251. scope: this
  23252. }));
  23253. }else{
  23254. delete this._fetchedWith;
  23255. }
  23256. return oStore; // dojo.data.api.Identity
  23257. },
  23258. // TODO: implement set() and watch() for store and query, although not sure how to handle
  23259. // setting them individually rather than together (as in setStore() above)
  23260. _setValueAttr: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
  23261. // summary:
  23262. // set the value of the widget.
  23263. // If a string is passed, then we set our value from looking it up.
  23264. if(this._loadingStore){
  23265. // Our store is loading - so save our value, and we'll set it when
  23266. // we're done
  23267. this._pendingValue = newValue;
  23268. return;
  23269. }
  23270. var opts = this.getOptions() || [];
  23271. if(!lang.isArray(newValue)){
  23272. newValue = [newValue];
  23273. }
  23274. array.forEach(newValue, function(i, idx){
  23275. if(!lang.isObject(i)){
  23276. i = i + "";
  23277. }
  23278. if(typeof i === "string"){
  23279. newValue[idx] = array.filter(opts, function(node){
  23280. return node.value === i;
  23281. })[0] || {value: "", label: ""};
  23282. }
  23283. }, this);
  23284. // Make sure some sane default is set
  23285. newValue = array.filter(newValue, function(i){ return i && i.value; });
  23286. if(!this.multiple && (!newValue[0] || !newValue[0].value) && opts.length){
  23287. newValue[0] = opts[0];
  23288. }
  23289. array.forEach(opts, function(i){
  23290. i.selected = array.some(newValue, function(v){ return v.value === i.value; });
  23291. });
  23292. var val = array.map(newValue, function(i){ return i.value; }),
  23293. disp = array.map(newValue, function(i){ return i.label; });
  23294. this._set("value", this.multiple ? val : val[0]);
  23295. this._setDisplay(this.multiple ? disp : disp[0]);
  23296. this._updateSelection();
  23297. this._handleOnChange(this.value, priorityChange);
  23298. },
  23299. _getDisplayedValueAttr: function(){
  23300. // summary:
  23301. // returns the displayed value of the widget
  23302. var val = this.get("value");
  23303. if(!lang.isArray(val)){
  23304. val = [val];
  23305. }
  23306. var ret = array.map(this.getOptions(val), function(v){
  23307. if(v && "label" in v){
  23308. return v.label;
  23309. }else if(v){
  23310. return v.value;
  23311. }
  23312. return null;
  23313. }, this);
  23314. return this.multiple ? ret : ret[0];
  23315. },
  23316. _loadChildren: function(){
  23317. // summary:
  23318. // Loads the children represented by this widget's options.
  23319. // reset the menu to make it populatable on the next click
  23320. if(this._loadingStore){ return; }
  23321. array.forEach(this._getChildren(), function(child){
  23322. child.destroyRecursive();
  23323. });
  23324. // Add each menu item
  23325. array.forEach(this.options, this._addOptionItem, this);
  23326. // Update states
  23327. this._updateSelection();
  23328. },
  23329. _updateSelection: function(){
  23330. // summary:
  23331. // Sets the "selected" class on the item for styling purposes
  23332. this._set("value", this._getValueFromOpts());
  23333. var val = this.value;
  23334. if(!lang.isArray(val)){
  23335. val = [val];
  23336. }
  23337. if(val && val[0]){
  23338. array.forEach(this._getChildren(), function(child){
  23339. var isSelected = array.some(val, function(v){
  23340. return child.option && (v === child.option.value);
  23341. });
  23342. domClass.toggle(child.domNode, this.baseClass + "SelectedOption", isSelected);
  23343. child.domNode.setAttribute("aria-selected", isSelected);
  23344. }, this);
  23345. }
  23346. },
  23347. _getValueFromOpts: function(){
  23348. // summary:
  23349. // Returns the value of the widget by reading the options for
  23350. // the selected flag
  23351. var opts = this.getOptions() || [];
  23352. if(!this.multiple && opts.length){
  23353. // Mirror what a select does - choose the first one
  23354. var opt = array.filter(opts, function(i){
  23355. return i.selected;
  23356. })[0];
  23357. if(opt && opt.value){
  23358. return opt.value
  23359. }else{
  23360. opts[0].selected = true;
  23361. return opts[0].value;
  23362. }
  23363. }else if(this.multiple){
  23364. // Set value to be the sum of all selected
  23365. return array.map(array.filter(opts, function(i){
  23366. return i.selected;
  23367. }), function(i){
  23368. return i.value;
  23369. }) || [];
  23370. }
  23371. return "";
  23372. },
  23373. // Internal functions to call when we have store notifications come in
  23374. _onNewItem: function(/*item*/ item, /*Object?*/ parentInfo){
  23375. if(!parentInfo || !parentInfo.parent){
  23376. // Only add it if we are top-level
  23377. this._addOptionForItem(item);
  23378. }
  23379. },
  23380. _onDeleteItem: function(/*item*/ item){
  23381. var store = this.store;
  23382. this.removeOption(store.getIdentity(item));
  23383. },
  23384. _onSetItem: function(/*item*/ item){
  23385. this.updateOption(this._getOptionObjForItem(item));
  23386. },
  23387. _getOptionObjForItem: function(item){
  23388. // summary:
  23389. // Returns an option object based off the given item. The "value"
  23390. // of the option item will be the identity of the item, the "label"
  23391. // of the option will be the label of the item. If the item contains
  23392. // children, the children value of the item will be set
  23393. var store = this.store, label = store.getLabel(item),
  23394. value = (label ? store.getIdentity(item) : null);
  23395. return {value: value, label: label, item:item}; // dijit.form.__SelectOption
  23396. },
  23397. _addOptionForItem: function(/*item*/ item){
  23398. // summary:
  23399. // Creates (and adds) the option for the given item
  23400. var store = this.store;
  23401. if(!store.isItemLoaded(item)){
  23402. // We are not loaded - so let's load it and add later
  23403. store.loadItem({item: item, onItem: function(i){
  23404. this._addOptionForItem(i);
  23405. },
  23406. scope: this});
  23407. return;
  23408. }
  23409. var newOpt = this._getOptionObjForItem(item);
  23410. this.addOption(newOpt);
  23411. },
  23412. constructor: function(/*Object*/ keywordArgs){
  23413. // summary:
  23414. // Saves off our value, if we have an initial one set so we
  23415. // can use it if we have a store as well (see startup())
  23416. this._oValue = (keywordArgs || {}).value || null;
  23417. this._notifyConnections = [];
  23418. },
  23419. buildRendering: function(){
  23420. this.inherited(arguments);
  23421. dom.setSelectable(this.focusNode, false);
  23422. },
  23423. _fillContent: function(){
  23424. // summary:
  23425. // Loads our options and sets up our dropdown correctly. We
  23426. // don't want any content, so we don't call any inherit chain
  23427. // function.
  23428. var opts = this.options;
  23429. if(!opts){
  23430. opts = this.options = this.srcNodeRef ? query("> *",
  23431. this.srcNodeRef).map(function(node){
  23432. if(node.getAttribute("type") === "separator"){
  23433. return { value: "", label: "", selected: false, disabled: false };
  23434. }
  23435. return {
  23436. value: (node.getAttribute("data-" + kernel._scopeName + "-value") || node.getAttribute("value")),
  23437. label: String(node.innerHTML),
  23438. // FIXME: disabled and selected are not valid on complex markup children (which is why we're
  23439. // looking for data-dojo-value above. perhaps we should data-dojo-props="" this whole thing?)
  23440. // decide before 1.6
  23441. selected: node.getAttribute("selected") || false,
  23442. disabled: node.getAttribute("disabled") || false
  23443. };
  23444. }, this) : [];
  23445. }
  23446. if(!this.value){
  23447. this._set("value", this._getValueFromOpts());
  23448. }else if(this.multiple && typeof this.value == "string"){
  23449. this._set("value", this.value.split(","));
  23450. }
  23451. },
  23452. postCreate: function(){
  23453. // summary:
  23454. // sets up our event handling that we need for functioning
  23455. // as a select
  23456. this.inherited(arguments);
  23457. // Make our event connections for updating state
  23458. this.connect(this, "onChange", "_updateSelection");
  23459. this.connect(this, "startup", "_loadChildren");
  23460. this._setValueAttr(this.value, null);
  23461. },
  23462. startup: function(){
  23463. // summary:
  23464. // Connects in our store, if we have one defined
  23465. this.inherited(arguments);
  23466. var store = this.store, fetchArgs = {};
  23467. array.forEach(["query", "queryOptions", "onFetch"], function(i){
  23468. if(this[i]){
  23469. fetchArgs[i] = this[i];
  23470. }
  23471. delete this[i];
  23472. }, this);
  23473. if(store && store.getFeatures()["dojo.data.api.Identity"]){
  23474. // Temporarily set our store to null so that it will get set
  23475. // and connected appropriately
  23476. this.store = null;
  23477. this.setStore(store, this._oValue, fetchArgs);
  23478. }
  23479. },
  23480. destroy: function(){
  23481. // summary:
  23482. // Clean up our connections
  23483. var h;
  23484. while(h = this._notifyConnections.pop()){ h.remove(); }
  23485. this.inherited(arguments);
  23486. },
  23487. _addOptionItem: function(/*dijit.form.__SelectOption*/ /*===== option =====*/){
  23488. // summary:
  23489. // User-overridable function which, for the given option, adds an
  23490. // item to the select. If the option doesn't have a value, then a
  23491. // separator is added in that place. Make sure to store the option
  23492. // in the created option widget.
  23493. },
  23494. _removeOptionItem: function(/*dijit.form.__SelectOption*/ /*===== option =====*/){
  23495. // summary:
  23496. // User-overridable function which, for the given option, removes
  23497. // its item from the select.
  23498. },
  23499. _setDisplay: function(/*String or String[]*/ /*===== newDisplay =====*/){
  23500. // summary:
  23501. // Overridable function which will set the display for the
  23502. // widget. newDisplay is either a string (in the case of
  23503. // single selects) or array of strings (in the case of multi-selects)
  23504. },
  23505. _getChildren: function(){
  23506. // summary:
  23507. // Overridable function to return the children that this widget contains.
  23508. return [];
  23509. },
  23510. _getSelectedOptionsAttr: function(){
  23511. // summary:
  23512. // hooks into this.attr to provide a mechanism for getting the
  23513. // option items for the current value of the widget.
  23514. return this.getOptions(this.get("value"));
  23515. },
  23516. _pseudoLoadChildren: function(/*item[]*/ /*===== items =====*/){
  23517. // summary:
  23518. // a function that will "fake" loading children, if needed, and
  23519. // if we have set to not load children until the widget opens.
  23520. // items:
  23521. // An array of items that will be loaded, when needed
  23522. },
  23523. onSetStore: function(){
  23524. // summary:
  23525. // a function that can be connected to in order to receive a
  23526. // notification that the store has finished loading and all options
  23527. // from that store are available
  23528. }
  23529. });
  23530. });
  23531. },
  23532. 'dijit/form/Select':function(){
  23533. define([
  23534. "dojo/_base/array", // array.forEach
  23535. "dojo/_base/declare", // declare
  23536. "dojo/dom-attr", // domAttr.set
  23537. "dojo/dom-class", // domClass.add domClass.remove domClass.toggle
  23538. "dojo/dom-construct", // domConstruct.create
  23539. "dojo/dom-geometry", // domGeometry.setMarginBox
  23540. "dojo/_base/event", // event.stop
  23541. "dojo/i18n", // i18n.getLocalization
  23542. "dojo/_base/lang", // lang.hitch
  23543. "./_FormSelectWidget",
  23544. "../_HasDropDown",
  23545. "../Menu",
  23546. "../MenuItem",
  23547. "../MenuSeparator",
  23548. "../Tooltip",
  23549. "dojo/text!./templates/Select.html",
  23550. "dojo/i18n!./nls/validate"
  23551. ], function(array, declare, domAttr, domClass, domConstruct, domGeometry, event, i18n, lang,
  23552. _FormSelectWidget, _HasDropDown, Menu, MenuItem, MenuSeparator, Tooltip, template){
  23553. /*=====
  23554. var _FormSelectWidget = dijit.form._FormSelectWidget;
  23555. var _HasDropDown = dijit._HasDropDown;
  23556. var _FormSelectWidget = dijit._FormSelectWidget;
  23557. var Menu = dijit.Menu;
  23558. var MenuItem = dijit.MenuItem;
  23559. var MenuSeparator = dijit.MenuSeparator;
  23560. var Tooltip = dijit.Tooltip;
  23561. =====*/
  23562. // module:
  23563. // dijit/form/Select
  23564. // summary:
  23565. // This is a "styleable" select box - it is basically a DropDownButton which
  23566. // can take a <select> as its input.
  23567. var _SelectMenu = declare("dijit.form._SelectMenu", Menu, {
  23568. // summary:
  23569. // An internally-used menu for dropdown that allows us a vertical scrollbar
  23570. buildRendering: function(){
  23571. // summary:
  23572. // Stub in our own changes, so that our domNode is not a table
  23573. // otherwise, we won't respond correctly to heights/overflows
  23574. this.inherited(arguments);
  23575. var o = (this.menuTableNode = this.domNode);
  23576. var n = (this.domNode = domConstruct.create("div", {style: {overflowX: "hidden", overflowY: "scroll"}}));
  23577. if(o.parentNode){
  23578. o.parentNode.replaceChild(n, o);
  23579. }
  23580. domClass.remove(o, "dijitMenuTable");
  23581. n.className = o.className + " dijitSelectMenu";
  23582. o.className = "dijitReset dijitMenuTable";
  23583. o.setAttribute("role", "listbox");
  23584. n.setAttribute("role", "presentation");
  23585. n.appendChild(o);
  23586. },
  23587. postCreate: function(){
  23588. // summary:
  23589. // stop mousemove from selecting text on IE to be consistent with other browsers
  23590. this.inherited(arguments);
  23591. this.connect(this.domNode, "onmousemove", event.stop);
  23592. },
  23593. resize: function(/*Object*/ mb){
  23594. // summary:
  23595. // Overridden so that we are able to handle resizing our
  23596. // internal widget. Note that this is not a "full" resize
  23597. // implementation - it only works correctly if you pass it a
  23598. // marginBox.
  23599. //
  23600. // mb: Object
  23601. // The margin box to set this dropdown to.
  23602. if(mb){
  23603. domGeometry.setMarginBox(this.domNode, mb);
  23604. if("w" in mb){
  23605. // We've explicitly set the wrapper <div>'s width, so set <table> width to match.
  23606. // 100% is safer than a pixel value because there may be a scroll bar with
  23607. // browser/OS specific width.
  23608. this.menuTableNode.style.width = "100%";
  23609. }
  23610. }
  23611. }
  23612. });
  23613. var Select = declare("dijit.form.Select", [_FormSelectWidget, _HasDropDown], {
  23614. // summary:
  23615. // This is a "styleable" select box - it is basically a DropDownButton which
  23616. // can take a <select> as its input.
  23617. baseClass: "dijitSelect",
  23618. templateString: template,
  23619. // required: Boolean
  23620. // Can be true or false, default is false.
  23621. required: false,
  23622. // state: [readonly] String
  23623. // "Incomplete" if this select is required but unset (i.e. blank value), "" otherwise
  23624. state: "",
  23625. // message: String
  23626. // Currently displayed error/prompt message
  23627. message: "",
  23628. // tooltipPosition: String[]
  23629. // See description of dijit.Tooltip.defaultPosition for details on this parameter.
  23630. tooltipPosition: [],
  23631. // emptyLabel: string
  23632. // What to display in an "empty" dropdown
  23633. emptyLabel: "&#160;", // &nbsp;
  23634. // _isLoaded: Boolean
  23635. // Whether or not we have been loaded
  23636. _isLoaded: false,
  23637. // _childrenLoaded: Boolean
  23638. // Whether or not our children have been loaded
  23639. _childrenLoaded: false,
  23640. _fillContent: function(){
  23641. // summary:
  23642. // Set the value to be the first, or the selected index
  23643. this.inherited(arguments);
  23644. // set value from selected option
  23645. if(this.options.length && !this.value && this.srcNodeRef){
  23646. var si = this.srcNodeRef.selectedIndex || 0; // || 0 needed for when srcNodeRef is not a SELECT
  23647. this.value = this.options[si >= 0 ? si : 0].value;
  23648. }
  23649. // Create the dropDown widget
  23650. this.dropDown = new _SelectMenu({id: this.id + "_menu"});
  23651. domClass.add(this.dropDown.domNode, this.baseClass + "Menu");
  23652. },
  23653. _getMenuItemForOption: function(/*dijit.form.__SelectOption*/ option){
  23654. // summary:
  23655. // For the given option, return the menu item that should be
  23656. // used to display it. This can be overridden as needed
  23657. if(!option.value && !option.label){
  23658. // We are a separator (no label set for it)
  23659. return new MenuSeparator();
  23660. }else{
  23661. // Just a regular menu option
  23662. var click = lang.hitch(this, "_setValueAttr", option);
  23663. var item = new MenuItem({
  23664. option: option,
  23665. label: option.label || this.emptyLabel,
  23666. onClick: click,
  23667. disabled: option.disabled || false
  23668. });
  23669. item.focusNode.setAttribute("role", "listitem");
  23670. return item;
  23671. }
  23672. },
  23673. _addOptionItem: function(/*dijit.form.__SelectOption*/ option){
  23674. // summary:
  23675. // For the given option, add an option to our dropdown.
  23676. // If the option doesn't have a value, then a separator is added
  23677. // in that place.
  23678. if(this.dropDown){
  23679. this.dropDown.addChild(this._getMenuItemForOption(option));
  23680. }
  23681. },
  23682. _getChildren: function(){
  23683. if(!this.dropDown){
  23684. return [];
  23685. }
  23686. return this.dropDown.getChildren();
  23687. },
  23688. _loadChildren: function(/*Boolean*/ loadMenuItems){
  23689. // summary:
  23690. // Resets the menu and the length attribute of the button - and
  23691. // ensures that the label is appropriately set.
  23692. // loadMenuItems: Boolean
  23693. // actually loads the child menu items - we only do this when we are
  23694. // populating for showing the dropdown.
  23695. if(loadMenuItems === true){
  23696. // this.inherited destroys this.dropDown's child widgets (MenuItems).
  23697. // Avoid this.dropDown (Menu widget) having a pointer to a destroyed widget (which will cause
  23698. // issues later in _setSelected). (see #10296)
  23699. if(this.dropDown){
  23700. delete this.dropDown.focusedChild;
  23701. }
  23702. if(this.options.length){
  23703. this.inherited(arguments);
  23704. }else{
  23705. // Drop down menu is blank but add one blank entry just so something appears on the screen
  23706. // to let users know that they are no choices (mimicing native select behavior)
  23707. array.forEach(this._getChildren(), function(child){ child.destroyRecursive(); });
  23708. var item = new MenuItem({label: "&#160;"});
  23709. this.dropDown.addChild(item);
  23710. }
  23711. }else{
  23712. this._updateSelection();
  23713. }
  23714. this._isLoaded = false;
  23715. this._childrenLoaded = true;
  23716. if(!this._loadingStore){
  23717. // Don't call this if we are loading - since we will handle it later
  23718. this._setValueAttr(this.value);
  23719. }
  23720. },
  23721. _setValueAttr: function(value){
  23722. this.inherited(arguments);
  23723. domAttr.set(this.valueNode, "value", this.get("value"));
  23724. this.validate(this.focused); // to update this.state
  23725. },
  23726. _setDisabledAttr: function(/*Boolean*/ value){
  23727. this.inherited(arguments);
  23728. this.validate(this.focused); // to update this.state
  23729. },
  23730. _setRequiredAttr: function(/*Boolean*/ value){
  23731. this._set("required", value);
  23732. this.focusNode.setAttribute("aria-required", value);
  23733. this.validate(this.focused); // to update this.state
  23734. },
  23735. _setDisplay: function(/*String*/ newDisplay){
  23736. // summary:
  23737. // sets the display for the given value (or values)
  23738. var lbl = newDisplay || this.emptyLabel;
  23739. this.containerNode.innerHTML = '<span class="dijitReset dijitInline ' + this.baseClass + 'Label">' + lbl + '</span>';
  23740. this.focusNode.setAttribute("aria-valuetext", lbl);
  23741. },
  23742. validate: function(/*Boolean*/ isFocused){
  23743. // summary:
  23744. // Called by oninit, onblur, and onkeypress, and whenever required/disabled state changes
  23745. // description:
  23746. // Show missing or invalid messages if appropriate, and highlight textbox field.
  23747. // Used when a select is initially set to no value and the user is required to
  23748. // set the value.
  23749. var isValid = this.disabled || this.isValid(isFocused);
  23750. this._set("state", isValid ? "" : "Incomplete");
  23751. this.focusNode.setAttribute("aria-invalid", isValid ? "false" : "true");
  23752. var message = isValid ? "" : this._missingMsg;
  23753. if(message && this.focused && this._hasBeenBlurred){
  23754. Tooltip.show(message, this.domNode, this.tooltipPosition, !this.isLeftToRight());
  23755. }else{
  23756. Tooltip.hide(this.domNode);
  23757. }
  23758. this._set("message", message);
  23759. return isValid;
  23760. },
  23761. isValid: function(/*Boolean*/ /*===== isFocused =====*/){
  23762. // summary:
  23763. // Whether or not this is a valid value. The only way a Select
  23764. // can be invalid is when it's required but nothing is selected.
  23765. return (!this.required || this.value === 0 || !(/^\s*$/.test(this.value || ""))); // handle value is null or undefined
  23766. },
  23767. reset: function(){
  23768. // summary:
  23769. // Overridden so that the state will be cleared.
  23770. this.inherited(arguments);
  23771. Tooltip.hide(this.domNode);
  23772. this.validate(this.focused); // to update this.state
  23773. },
  23774. postMixInProperties: function(){
  23775. // summary:
  23776. // set the missing message
  23777. this.inherited(arguments);
  23778. this._missingMsg = i18n.getLocalization("dijit.form", "validate",
  23779. this.lang).missingMessage;
  23780. },
  23781. postCreate: function(){
  23782. // summary:
  23783. // stop mousemove from selecting text on IE to be consistent with other browsers
  23784. this.inherited(arguments);
  23785. this.connect(this.domNode, "onmousemove", event.stop);
  23786. },
  23787. _setStyleAttr: function(/*String||Object*/ value){
  23788. this.inherited(arguments);
  23789. domClass.toggle(this.domNode, this.baseClass + "FixedWidth", !!this.domNode.style.width);
  23790. },
  23791. isLoaded: function(){
  23792. return this._isLoaded;
  23793. },
  23794. loadDropDown: function(/*Function*/ loadCallback){
  23795. // summary:
  23796. // populates the menu
  23797. this._loadChildren(true);
  23798. this._isLoaded = true;
  23799. loadCallback();
  23800. },
  23801. closeDropDown: function(){
  23802. // overriding _HasDropDown.closeDropDown()
  23803. this.inherited(arguments);
  23804. if(this.dropDown && this.dropDown.menuTableNode){
  23805. // Erase possible width: 100% setting from _SelectMenu.resize().
  23806. // Leaving it would interfere with the next openDropDown() call, which
  23807. // queries the natural size of the drop down.
  23808. this.dropDown.menuTableNode.style.width = "";
  23809. }
  23810. },
  23811. uninitialize: function(preserveDom){
  23812. if(this.dropDown && !this.dropDown._destroyed){
  23813. this.dropDown.destroyRecursive(preserveDom);
  23814. delete this.dropDown;
  23815. }
  23816. this.inherited(arguments);
  23817. },
  23818. _onFocus: function(){
  23819. this.validate(true); // show tooltip if second focus of required tooltip, but no selection
  23820. this.inherited(arguments);
  23821. },
  23822. _onBlur: function(){
  23823. Tooltip.hide(this.domNode);
  23824. this.inherited(arguments);
  23825. }
  23826. });
  23827. Select._Menu = _SelectMenu; // for monkey patching
  23828. return Select;
  23829. });
  23830. },
  23831. 'dijit/_editor/range':function(){
  23832. define("dijit/_editor/range", [
  23833. "dojo/_base/array", // array.every
  23834. "dojo/_base/declare", // declare
  23835. "dojo/_base/lang", // lang.isArray
  23836. "dojo/_base/window", // win.global
  23837. ".." // for exporting symbols to dijit, TODO: remove in 2.0
  23838. ], function(array, declare, lang, win, dijit){
  23839. // module:
  23840. // dijit/_editor/range
  23841. // summary:
  23842. // W3C range API
  23843. dijit.range={};
  23844. dijit.range.getIndex = function(/*DomNode*/node, /*DomNode*/parent){
  23845. // dojo.profile.start("dijit.range.getIndex");
  23846. var ret = [], retR = [];
  23847. var onode = node;
  23848. var pnode, n;
  23849. while(node != parent){
  23850. var i = 0;
  23851. pnode = node.parentNode;
  23852. while((n = pnode.childNodes[i++])){
  23853. if(n === node){
  23854. --i;
  23855. break;
  23856. }
  23857. }
  23858. //if(i>=pnode.childNodes.length){
  23859. //dojo.debug("Error finding index of a node in dijit.range.getIndex");
  23860. //}
  23861. ret.unshift(i);
  23862. retR.unshift(i - pnode.childNodes.length);
  23863. node = pnode;
  23864. }
  23865. //normalized() can not be called so often to prevent
  23866. //invalidating selection/range, so we have to detect
  23867. //here that any text nodes in a row
  23868. if(ret.length > 0 && onode.nodeType == 3){
  23869. n = onode.previousSibling;
  23870. while(n && n.nodeType == 3){
  23871. ret[ret.length - 1]--;
  23872. n = n.previousSibling;
  23873. }
  23874. n = onode.nextSibling;
  23875. while(n && n.nodeType == 3){
  23876. retR[retR.length - 1]++;
  23877. n = n.nextSibling;
  23878. }
  23879. }
  23880. // dojo.profile.end("dijit.range.getIndex");
  23881. return {o: ret, r:retR};
  23882. };
  23883. dijit.range.getNode = function(/*Array*/index, /*DomNode*/parent){
  23884. if(!lang.isArray(index) || index.length == 0){
  23885. return parent;
  23886. }
  23887. var node = parent;
  23888. // if(!node)debugger
  23889. array.every(index, function(i){
  23890. if(i >= 0 && i < node.childNodes.length){
  23891. node = node.childNodes[i];
  23892. }else{
  23893. node = null;
  23894. //console.debug('Error: can not find node with index',index,'under parent node',parent );
  23895. return false; //terminate array.every
  23896. }
  23897. return true; //carry on the every loop
  23898. });
  23899. return node;
  23900. };
  23901. dijit.range.getCommonAncestor = function(n1, n2, root){
  23902. root = root || n1.ownerDocument.body;
  23903. var getAncestors = function(n){
  23904. var as = [];
  23905. while(n){
  23906. as.unshift(n);
  23907. if(n !== root){
  23908. n = n.parentNode;
  23909. }else{
  23910. break;
  23911. }
  23912. }
  23913. return as;
  23914. };
  23915. var n1as = getAncestors(n1);
  23916. var n2as = getAncestors(n2);
  23917. var m = Math.min(n1as.length, n2as.length);
  23918. var com = n1as[0]; //at least, one element should be in the array: the root (BODY by default)
  23919. for(var i = 1; i < m; i++){
  23920. if(n1as[i] === n2as[i]){
  23921. com = n1as[i]
  23922. }else{
  23923. break;
  23924. }
  23925. }
  23926. return com;
  23927. };
  23928. dijit.range.getAncestor = function(/*DomNode*/node, /*RegEx?*/regex, /*DomNode?*/root){
  23929. root = root || node.ownerDocument.body;
  23930. while(node && node !== root){
  23931. var name = node.nodeName.toUpperCase();
  23932. if(regex.test(name)){
  23933. return node;
  23934. }
  23935. node = node.parentNode;
  23936. }
  23937. return null;
  23938. };
  23939. dijit.range.BlockTagNames = /^(?:P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|DT|DE)$/;
  23940. dijit.range.getBlockAncestor = function(/*DomNode*/node, /*RegEx?*/regex, /*DomNode?*/root){
  23941. root = root || node.ownerDocument.body;
  23942. regex = regex || dijit.range.BlockTagNames;
  23943. var block = null, blockContainer;
  23944. while(node && node !== root){
  23945. var name = node.nodeName.toUpperCase();
  23946. if(!block && regex.test(name)){
  23947. block = node;
  23948. }
  23949. if(!blockContainer && (/^(?:BODY|TD|TH|CAPTION)$/).test(name)){
  23950. blockContainer = node;
  23951. }
  23952. node = node.parentNode;
  23953. }
  23954. return {blockNode:block, blockContainer:blockContainer || node.ownerDocument.body};
  23955. };
  23956. dijit.range.atBeginningOfContainer = function(/*DomNode*/container, /*DomNode*/node, /*Int*/offset){
  23957. var atBeginning = false;
  23958. var offsetAtBeginning = (offset == 0);
  23959. if(!offsetAtBeginning && node.nodeType == 3){ //if this is a text node, check whether the left part is all space
  23960. if(/^[\s\xA0]+$/.test(node.nodeValue.substr(0, offset))){
  23961. offsetAtBeginning = true;
  23962. }
  23963. }
  23964. if(offsetAtBeginning){
  23965. var cnode = node;
  23966. atBeginning = true;
  23967. while(cnode && cnode !== container){
  23968. if(cnode.previousSibling){
  23969. atBeginning = false;
  23970. break;
  23971. }
  23972. cnode = cnode.parentNode;
  23973. }
  23974. }
  23975. return atBeginning;
  23976. };
  23977. dijit.range.atEndOfContainer = function(/*DomNode*/container, /*DomNode*/node, /*Int*/offset){
  23978. var atEnd = false;
  23979. var offsetAtEnd = (offset == (node.length || node.childNodes.length));
  23980. if(!offsetAtEnd && node.nodeType == 3){ //if this is a text node, check whether the right part is all space
  23981. if(/^[\s\xA0]+$/.test(node.nodeValue.substr(offset))){
  23982. offsetAtEnd = true;
  23983. }
  23984. }
  23985. if(offsetAtEnd){
  23986. var cnode = node;
  23987. atEnd = true;
  23988. while(cnode && cnode !== container){
  23989. if(cnode.nextSibling){
  23990. atEnd = false;
  23991. break;
  23992. }
  23993. cnode = cnode.parentNode;
  23994. }
  23995. }
  23996. return atEnd;
  23997. };
  23998. dijit.range.adjacentNoneTextNode = function(startnode, next){
  23999. var node = startnode;
  24000. var len = (0 - startnode.length) || 0;
  24001. var prop = next ? 'nextSibling' : 'previousSibling';
  24002. while(node){
  24003. if(node.nodeType != 3){
  24004. break;
  24005. }
  24006. len += node.length;
  24007. node = node[prop];
  24008. }
  24009. return [node,len];
  24010. };
  24011. dijit.range._w3c = Boolean(window['getSelection']);
  24012. dijit.range.create = function(/*Window?*/window){
  24013. if(dijit.range._w3c){
  24014. return (window || win.global).document.createRange();
  24015. }else{//IE
  24016. return new dijit.range.W3CRange;
  24017. }
  24018. };
  24019. dijit.range.getSelection = function(/*Window*/win, /*Boolean?*/ignoreUpdate){
  24020. if(dijit.range._w3c){
  24021. return win.getSelection();
  24022. }else{//IE
  24023. var s = new dijit.range.ie.selection(win);
  24024. if(!ignoreUpdate){
  24025. s._getCurrentSelection();
  24026. }
  24027. return s;
  24028. }
  24029. };
  24030. if(!dijit.range._w3c){
  24031. dijit.range.ie = {
  24032. cachedSelection: {},
  24033. selection: function(win){
  24034. this._ranges = [];
  24035. this.addRange = function(r, /*boolean*/internal){
  24036. this._ranges.push(r);
  24037. if(!internal){
  24038. r._select();
  24039. }
  24040. this.rangeCount = this._ranges.length;
  24041. };
  24042. this.removeAllRanges = function(){
  24043. //don't detach, the range may be used later
  24044. // for(var i=0;i<this._ranges.length;i++){
  24045. // this._ranges[i].detach();
  24046. // }
  24047. this._ranges = [];
  24048. this.rangeCount = 0;
  24049. };
  24050. var _initCurrentRange = function(){
  24051. var r = win.document.selection.createRange();
  24052. var type = win.document.selection.type.toUpperCase();
  24053. if(type == "CONTROL"){
  24054. //TODO: multiple range selection(?)
  24055. return new dijit.range.W3CRange(dijit.range.ie.decomposeControlRange(r));
  24056. }else{
  24057. return new dijit.range.W3CRange(dijit.range.ie.decomposeTextRange(r));
  24058. }
  24059. };
  24060. this.getRangeAt = function(i){
  24061. return this._ranges[i];
  24062. };
  24063. this._getCurrentSelection = function(){
  24064. this.removeAllRanges();
  24065. var r = _initCurrentRange();
  24066. if(r){
  24067. this.addRange(r, true);
  24068. this.isCollapsed = r.collapsed;
  24069. }else{
  24070. this.isCollapsed = true;
  24071. }
  24072. };
  24073. },
  24074. decomposeControlRange: function(range){
  24075. var firstnode = range.item(0), lastnode = range.item(range.length - 1);
  24076. var startContainer = firstnode.parentNode, endContainer = lastnode.parentNode;
  24077. var startOffset = dijit.range.getIndex(firstnode, startContainer).o[0];
  24078. var endOffset = dijit.range.getIndex(lastnode, endContainer).o[0] + 1;
  24079. return [startContainer, startOffset,endContainer, endOffset];
  24080. },
  24081. getEndPoint: function(range, end){
  24082. var atmrange = range.duplicate();
  24083. atmrange.collapse(!end);
  24084. var cmpstr = 'EndTo' + (end ? 'End' : 'Start');
  24085. var parentNode = atmrange.parentElement();
  24086. var startnode, startOffset, lastNode;
  24087. if(parentNode.childNodes.length > 0){
  24088. array.every(parentNode.childNodes, function(node, i){
  24089. var calOffset;
  24090. if(node.nodeType != 3){
  24091. atmrange.moveToElementText(node);
  24092. if(atmrange.compareEndPoints(cmpstr, range) > 0){
  24093. //startnode = node.previousSibling;
  24094. if(lastNode && lastNode.nodeType == 3){
  24095. //where shall we put the start? in the text node or after?
  24096. startnode = lastNode;
  24097. calOffset = true;
  24098. }else{
  24099. startnode = parentNode;
  24100. startOffset = i;
  24101. return false;
  24102. }
  24103. }else{
  24104. if(i == parentNode.childNodes.length - 1){
  24105. startnode = parentNode;
  24106. startOffset = parentNode.childNodes.length;
  24107. return false;
  24108. }
  24109. }
  24110. }else{
  24111. if(i == parentNode.childNodes.length - 1){//at the end of this node
  24112. startnode = node;
  24113. calOffset = true;
  24114. }
  24115. }
  24116. // try{
  24117. if(calOffset && startnode){
  24118. var prevnode = dijit.range.adjacentNoneTextNode(startnode)[0];
  24119. if(prevnode){
  24120. startnode = prevnode.nextSibling;
  24121. }else{
  24122. startnode = parentNode.firstChild; //firstChild must be a text node
  24123. }
  24124. var prevnodeobj = dijit.range.adjacentNoneTextNode(startnode);
  24125. prevnode = prevnodeobj[0];
  24126. var lenoffset = prevnodeobj[1];
  24127. if(prevnode){
  24128. atmrange.moveToElementText(prevnode);
  24129. atmrange.collapse(false);
  24130. }else{
  24131. atmrange.moveToElementText(parentNode);
  24132. }
  24133. atmrange.setEndPoint(cmpstr, range);
  24134. startOffset = atmrange.text.length - lenoffset;
  24135. return false;
  24136. }
  24137. // }catch(e){ debugger }
  24138. lastNode = node;
  24139. return true;
  24140. });
  24141. }else{
  24142. startnode = parentNode;
  24143. startOffset = 0;
  24144. }
  24145. //if at the end of startnode and we are dealing with start container, then
  24146. //move the startnode to nextSibling if it is a text node
  24147. //TODO: do this for end container?
  24148. if(!end && startnode.nodeType == 1 && startOffset == startnode.childNodes.length){
  24149. var nextnode = startnode.nextSibling;
  24150. if(nextnode && nextnode.nodeType == 3){
  24151. startnode = nextnode;
  24152. startOffset = 0;
  24153. }
  24154. }
  24155. return [startnode, startOffset];
  24156. },
  24157. setEndPoint: function(range, container, offset){
  24158. //text node
  24159. var atmrange = range.duplicate(), node, len;
  24160. if(container.nodeType != 3){ //normal node
  24161. if(offset > 0){
  24162. node = container.childNodes[offset - 1];
  24163. if(node){
  24164. if(node.nodeType == 3){
  24165. container = node;
  24166. offset = node.length;
  24167. //pass through
  24168. }else{
  24169. if(node.nextSibling && node.nextSibling.nodeType == 3){
  24170. container = node.nextSibling;
  24171. offset = 0;
  24172. //pass through
  24173. }else{
  24174. atmrange.moveToElementText(node.nextSibling ? node : container);
  24175. var parent = node.parentNode;
  24176. var tempNode = parent.insertBefore(node.ownerDocument.createTextNode(' '), node.nextSibling);
  24177. atmrange.collapse(false);
  24178. parent.removeChild(tempNode);
  24179. }
  24180. }
  24181. }
  24182. }else{
  24183. atmrange.moveToElementText(container);
  24184. atmrange.collapse(true);
  24185. }
  24186. }
  24187. if(container.nodeType == 3){
  24188. var prevnodeobj = dijit.range.adjacentNoneTextNode(container);
  24189. var prevnode = prevnodeobj[0];
  24190. len = prevnodeobj[1];
  24191. if(prevnode){
  24192. atmrange.moveToElementText(prevnode);
  24193. atmrange.collapse(false);
  24194. //if contentEditable is not inherit, the above collapse won't make the end point
  24195. //in the correctly position: it always has a -1 offset, so compensate it
  24196. if(prevnode.contentEditable != 'inherit'){
  24197. len++;
  24198. }
  24199. }else{
  24200. atmrange.moveToElementText(container.parentNode);
  24201. atmrange.collapse(true);
  24202. }
  24203. offset += len;
  24204. if(offset > 0){
  24205. if(atmrange.move('character', offset) != offset){
  24206. console.error('Error when moving!');
  24207. }
  24208. }
  24209. }
  24210. return atmrange;
  24211. },
  24212. decomposeTextRange: function(range){
  24213. var tmpary = dijit.range.ie.getEndPoint(range);
  24214. var startContainer = tmpary[0], startOffset = tmpary[1];
  24215. var endContainer = tmpary[0], endOffset = tmpary[1];
  24216. if(range.htmlText.length){
  24217. if(range.htmlText == range.text){ //in the same text node
  24218. endOffset = startOffset + range.text.length;
  24219. }else{
  24220. tmpary = dijit.range.ie.getEndPoint(range, true);
  24221. endContainer = tmpary[0],endOffset = tmpary[1];
  24222. // if(startContainer.tagName == "BODY"){
  24223. // startContainer = startContainer.firstChild;
  24224. // }
  24225. }
  24226. }
  24227. return [startContainer, startOffset, endContainer, endOffset];
  24228. },
  24229. setRange: function(range, startContainer, startOffset, endContainer, endOffset, collapsed){
  24230. var start = dijit.range.ie.setEndPoint(range, startContainer, startOffset);
  24231. range.setEndPoint('StartToStart', start);
  24232. if(!collapsed){
  24233. var end = dijit.range.ie.setEndPoint(range, endContainer, endOffset);
  24234. }
  24235. range.setEndPoint('EndToEnd', end || start);
  24236. return range;
  24237. }
  24238. };
  24239. declare("dijit.range.W3CRange",null, {
  24240. constructor: function(){
  24241. if(arguments.length>0){
  24242. this.setStart(arguments[0][0],arguments[0][1]);
  24243. this.setEnd(arguments[0][2],arguments[0][3]);
  24244. }else{
  24245. this.commonAncestorContainer = null;
  24246. this.startContainer = null;
  24247. this.startOffset = 0;
  24248. this.endContainer = null;
  24249. this.endOffset = 0;
  24250. this.collapsed = true;
  24251. }
  24252. },
  24253. _updateInternal: function(){
  24254. if(this.startContainer !== this.endContainer){
  24255. this.commonAncestorContainer = dijit.range.getCommonAncestor(this.startContainer, this.endContainer);
  24256. }else{
  24257. this.commonAncestorContainer = this.startContainer;
  24258. }
  24259. this.collapsed = (this.startContainer === this.endContainer) && (this.startOffset == this.endOffset);
  24260. },
  24261. setStart: function(node, offset){
  24262. offset=parseInt(offset);
  24263. if(this.startContainer === node && this.startOffset == offset){
  24264. return;
  24265. }
  24266. delete this._cachedBookmark;
  24267. this.startContainer = node;
  24268. this.startOffset = offset;
  24269. if(!this.endContainer){
  24270. this.setEnd(node, offset);
  24271. }else{
  24272. this._updateInternal();
  24273. }
  24274. },
  24275. setEnd: function(node, offset){
  24276. offset=parseInt(offset);
  24277. if(this.endContainer === node && this.endOffset == offset){
  24278. return;
  24279. }
  24280. delete this._cachedBookmark;
  24281. this.endContainer = node;
  24282. this.endOffset = offset;
  24283. if(!this.startContainer){
  24284. this.setStart(node, offset);
  24285. }else{
  24286. this._updateInternal();
  24287. }
  24288. },
  24289. setStartAfter: function(node, offset){
  24290. this._setPoint('setStart', node, offset, 1);
  24291. },
  24292. setStartBefore: function(node, offset){
  24293. this._setPoint('setStart', node, offset, 0);
  24294. },
  24295. setEndAfter: function(node, offset){
  24296. this._setPoint('setEnd', node, offset, 1);
  24297. },
  24298. setEndBefore: function(node, offset){
  24299. this._setPoint('setEnd', node, offset, 0);
  24300. },
  24301. _setPoint: function(what, node, offset, ext){
  24302. var index = dijit.range.getIndex(node, node.parentNode).o;
  24303. this[what](node.parentNode, index.pop()+ext);
  24304. },
  24305. _getIERange: function(){
  24306. var r = (this._body || this.endContainer.ownerDocument.body).createTextRange();
  24307. dijit.range.ie.setRange(r, this.startContainer, this.startOffset, this.endContainer, this.endOffset, this.collapsed);
  24308. return r;
  24309. },
  24310. getBookmark: function(){
  24311. this._getIERange();
  24312. return this._cachedBookmark;
  24313. },
  24314. _select: function(){
  24315. var r = this._getIERange();
  24316. r.select();
  24317. },
  24318. deleteContents: function(){
  24319. var s = this.startContainer, r = this._getIERange();
  24320. if(s.nodeType === 3 && !this.startOffset){
  24321. //if the range starts at the beginning of a
  24322. //text node, move it to before the textnode
  24323. //to make sure the range is still valid
  24324. //after deleteContents() finishes
  24325. this.setStartBefore(s);
  24326. }
  24327. r.pasteHTML('');
  24328. this.endContainer = this.startContainer;
  24329. this.endOffset = this.startOffset;
  24330. this.collapsed = true;
  24331. },
  24332. cloneRange: function(){
  24333. var r = new dijit.range.W3CRange([this.startContainer,this.startOffset,
  24334. this.endContainer,this.endOffset]);
  24335. r._body = this._body;
  24336. return r;
  24337. },
  24338. detach: function(){
  24339. this._body = null;
  24340. this.commonAncestorContainer = null;
  24341. this.startContainer = null;
  24342. this.startOffset = 0;
  24343. this.endContainer = null;
  24344. this.endOffset = 0;
  24345. this.collapsed = true;
  24346. }
  24347. });
  24348. } //if(!dijit.range._w3c)
  24349. return dijit.range;
  24350. });
  24351. },
  24352. 'dojo/store/util/QueryResults':function(){
  24353. define(["../../_base/array", "../../_base/lang", "../../_base/Deferred"
  24354. ], function(array, lang, Deferred) {
  24355. // module:
  24356. // dojo/store/util/QueryResults
  24357. // summary:
  24358. // The module defines a query results wrapper
  24359. var util = lang.getObject("dojo.store.util", true);
  24360. util.QueryResults = function(results){
  24361. // summary:
  24362. // A function that wraps the results of a store query with additional
  24363. // methods.
  24364. //
  24365. // description:
  24366. // QueryResults is a basic wrapper that allows for array-like iteration
  24367. // over any kind of returned data from a query. While the simplest store
  24368. // will return a plain array of data, other stores may return deferreds or
  24369. // promises; this wrapper makes sure that *all* results can be treated
  24370. // the same.
  24371. //
  24372. // Additional methods include `forEach`, `filter` and `map`.
  24373. //
  24374. // returns: Object
  24375. // An array-like object that can be used for iterating over.
  24376. //
  24377. // example:
  24378. // Query a store and iterate over the results.
  24379. //
  24380. // | store.query({ prime: true }).forEach(function(item){
  24381. // | // do something
  24382. // | });
  24383. if(!results){
  24384. return results;
  24385. }
  24386. // if it is a promise it may be frozen
  24387. if(results.then){
  24388. results = lang.delegate(results);
  24389. }
  24390. function addIterativeMethod(method){
  24391. if(!results[method]){
  24392. results[method] = function(){
  24393. var args = arguments;
  24394. return Deferred.when(results, function(results){
  24395. Array.prototype.unshift.call(args, results);
  24396. return util.QueryResults(array[method].apply(array, args));
  24397. });
  24398. };
  24399. }
  24400. }
  24401. addIterativeMethod("forEach");
  24402. addIterativeMethod("filter");
  24403. addIterativeMethod("map");
  24404. if(!results.total){
  24405. results.total = Deferred.when(results, function(results){
  24406. return results.length;
  24407. });
  24408. }
  24409. return results;
  24410. };
  24411. return util.QueryResults;
  24412. });
  24413. },
  24414. 'dijit/form/_ListBase':function(){
  24415. define([
  24416. "dojo/_base/declare", // declare
  24417. "dojo/window" // winUtils.scrollIntoView
  24418. ], function(declare, winUtils){
  24419. // module:
  24420. // dijit/form/_ListBase
  24421. // summary:
  24422. // Focus-less menu to handle UI events consistently
  24423. return declare( "dijit.form._ListBase", null, {
  24424. // summary:
  24425. // Focus-less menu to handle UI events consistently
  24426. // Abstract methods that must be defined externally:
  24427. // onSelect: item is active (mousedown but not yet mouseup, or keyboard arrow selected but no Enter)
  24428. // onDeselect: cancels onSelect
  24429. // tags:
  24430. // private
  24431. // selected: DOMnode
  24432. // currently selected node
  24433. selected: null,
  24434. _getTarget: function(/*Event*/ evt){
  24435. var tgt = evt.target;
  24436. var container = this.containerNode;
  24437. if(tgt == container || tgt == this.domNode){ return null; }
  24438. while(tgt && tgt.parentNode != container){
  24439. // recurse to the top
  24440. tgt = tgt.parentNode;
  24441. }
  24442. return tgt;
  24443. },
  24444. selectFirstNode: function(){
  24445. // summary:
  24446. // Select the first displayed item in the list.
  24447. var first = this.containerNode.firstChild;
  24448. while(first && first.style.display == "none"){
  24449. first = first.nextSibling;
  24450. }
  24451. this._setSelectedAttr(first, true);
  24452. },
  24453. selectLastNode: function(){
  24454. // summary:
  24455. // Select the last displayed item in the list
  24456. var last = this.containerNode.lastChild;
  24457. while(last && last.style.display == "none"){
  24458. last = last.previousSibling;
  24459. }
  24460. this._setSelectedAttr(last, true);
  24461. },
  24462. selectNextNode: function(){
  24463. // summary:
  24464. // Select the item just below the current selection.
  24465. // If nothing selected, select first node.
  24466. var selectedNode = this._getSelectedAttr();
  24467. if(!selectedNode){
  24468. this.selectFirstNode();
  24469. }else{
  24470. var next = selectedNode.nextSibling;
  24471. while(next && next.style.display == "none"){
  24472. next = next.nextSibling;
  24473. }
  24474. if(!next){
  24475. this.selectFirstNode();
  24476. }else{
  24477. this._setSelectedAttr(next, true);
  24478. }
  24479. }
  24480. },
  24481. selectPreviousNode: function(){
  24482. // summary:
  24483. // Select the item just above the current selection.
  24484. // If nothing selected, select last node (if
  24485. // you select Previous and try to keep scrolling up the list).
  24486. var selectedNode = this._getSelectedAttr();
  24487. if(!selectedNode){
  24488. this.selectLastNode();
  24489. }else{
  24490. var prev = selectedNode.previousSibling;
  24491. while(prev && prev.style.display == "none"){
  24492. prev = prev.previousSibling;
  24493. }
  24494. if(!prev){
  24495. this.selectLastNode();
  24496. }else{
  24497. this._setSelectedAttr(prev, true);
  24498. }
  24499. }
  24500. },
  24501. _setSelectedAttr: function(/*DomNode*/ node, /*Boolean*/ scroll){
  24502. // summary:
  24503. // Does the actual select.
  24504. // node:
  24505. // The option to select
  24506. // scroll:
  24507. // If necessary, scroll node into view. Set to false for mouse/touch to
  24508. // avoid jumping problems on mobile/RTL, see https://bugs.dojotoolkit.org/ticket/17739.
  24509. if(this.selected != node){
  24510. var selectedNode = this._getSelectedAttr();
  24511. if(selectedNode){
  24512. this.onDeselect(selectedNode);
  24513. this.selected = null;
  24514. }
  24515. if(node && node.parentNode == this.containerNode){
  24516. this.selected = node;
  24517. if(scroll){
  24518. winUtils.scrollIntoView(node);
  24519. }
  24520. this.onSelect(node);
  24521. }
  24522. }else if(node){
  24523. this.onSelect(node);
  24524. }
  24525. },
  24526. _getSelectedAttr: function(){
  24527. // summary:
  24528. // Returns the selected node.
  24529. var v = this.selected;
  24530. return (v && v.parentNode == this.containerNode) ? v : (this.selected = null);
  24531. }
  24532. });
  24533. });
  24534. },
  24535. 'dojo/DeferredList':function(){
  24536. define(["./_base/kernel", "./_base/Deferred", "./_base/array"], function(dojo, Deferred, darray) {
  24537. // module:
  24538. // dojo/DeferredList
  24539. // summary:
  24540. // TODOC
  24541. dojo.DeferredList = function(/*Array*/ list, /*Boolean?*/ fireOnOneCallback, /*Boolean?*/ fireOnOneErrback, /*Boolean?*/ consumeErrors, /*Function?*/ canceller){
  24542. // summary:
  24543. // Provides event handling for a group of Deferred objects.
  24544. // description:
  24545. // DeferredList takes an array of existing deferreds and returns a new deferred of its own
  24546. // this new deferred will typically have its callback fired when all of the deferreds in
  24547. // the given list have fired their own deferreds. The parameters `fireOnOneCallback` and
  24548. // fireOnOneErrback, will fire before all the deferreds as appropriate
  24549. //
  24550. // list:
  24551. // The list of deferreds to be synchronizied with this DeferredList
  24552. // fireOnOneCallback:
  24553. // Will cause the DeferredLists callback to be fired as soon as any
  24554. // of the deferreds in its list have been fired instead of waiting until
  24555. // the entire list has finished
  24556. // fireonOneErrback:
  24557. // Will cause the errback to fire upon any of the deferreds errback
  24558. // canceller:
  24559. // A deferred canceller function, see dojo.Deferred
  24560. var resultList = [];
  24561. Deferred.call(this);
  24562. var self = this;
  24563. if(list.length === 0 && !fireOnOneCallback){
  24564. this.resolve([0, []]);
  24565. }
  24566. var finished = 0;
  24567. darray.forEach(list, function(item, i){
  24568. item.then(function(result){
  24569. if(fireOnOneCallback){
  24570. self.resolve([i, result]);
  24571. }else{
  24572. addResult(true, result);
  24573. }
  24574. },function(error){
  24575. if(fireOnOneErrback){
  24576. self.reject(error);
  24577. }else{
  24578. addResult(false, error);
  24579. }
  24580. if(consumeErrors){
  24581. return null;
  24582. }
  24583. throw error;
  24584. });
  24585. function addResult(succeeded, result){
  24586. resultList[i] = [succeeded, result];
  24587. finished++;
  24588. if(finished === list.length){
  24589. self.resolve(resultList);
  24590. }
  24591. }
  24592. });
  24593. };
  24594. dojo.DeferredList.prototype = new Deferred();
  24595. dojo.DeferredList.prototype.gatherResults = function(deferredList){
  24596. // summary:
  24597. // Gathers the results of the deferreds for packaging
  24598. // as the parameters to the Deferred Lists' callback
  24599. // deferredList: dojo.DeferredList
  24600. // The deferred list from which this function gathers results.
  24601. // returns: dojo.DeferredList
  24602. // The newly created deferred list which packs results as
  24603. // parameters to its callback.
  24604. var d = new dojo.DeferredList(deferredList, false, true, false);
  24605. d.addCallback(function(results){
  24606. var ret = [];
  24607. darray.forEach(results, function(result){
  24608. ret.push(result[1]);
  24609. });
  24610. return ret;
  24611. });
  24612. return d;
  24613. };
  24614. return dojo.DeferredList;
  24615. });
  24616. },
  24617. 'dojo/dnd/common':function(){
  24618. define(["../main"], function(dojo) {
  24619. // module:
  24620. // dojo/dnd/common
  24621. // summary:
  24622. // TODOC
  24623. dojo.getObject("dnd", true, dojo);
  24624. dojo.dnd.getCopyKeyState = dojo.isCopyKey;
  24625. dojo.dnd._uniqueId = 0;
  24626. dojo.dnd.getUniqueId = function(){
  24627. // summary:
  24628. // returns a unique string for use with any DOM element
  24629. var id;
  24630. do{
  24631. id = dojo._scopeName + "Unique" + (++dojo.dnd._uniqueId);
  24632. }while(dojo.byId(id));
  24633. return id;
  24634. };
  24635. dojo.dnd._empty = {};
  24636. dojo.dnd.isFormElement = function(/*Event*/ e){
  24637. // summary:
  24638. // returns true if user clicked on a form element
  24639. var t = e.target;
  24640. if(t.nodeType == 3 /*TEXT_NODE*/){
  24641. t = t.parentNode;
  24642. }
  24643. return " button textarea input select option ".indexOf(" " + t.tagName.toLowerCase() + " ") >= 0; // Boolean
  24644. };
  24645. return dojo.dnd;
  24646. });
  24647. },
  24648. 'dijit/CalendarLite':function(){
  24649. define([
  24650. "dojo/_base/array", // array.forEach array.map
  24651. "dojo/_base/declare", // declare
  24652. "dojo/cldr/supplemental", // cldrSupplemental.getFirstDayOfWeek
  24653. "dojo/date", // date
  24654. "dojo/date/locale",
  24655. "dojo/dom", // dom.setSelectable
  24656. "dojo/dom-class", // domClass.contains
  24657. "dojo/_base/event", // event.stop
  24658. "dojo/_base/lang", // lang.getObject, lang.hitch
  24659. "dojo/_base/sniff", // has("ie") has("webkit")
  24660. "dojo/string", // string.substitute
  24661. "dojo/_base/window", // win.doc.createTextNode
  24662. "./_WidgetBase",
  24663. "./_TemplatedMixin",
  24664. "dojo/text!./templates/Calendar.html"
  24665. ], function(array, declare, cldrSupplemental, date, local, dom, domClass, event, lang, has, string, win,
  24666. _WidgetBase, _TemplatedMixin, template){
  24667. /*=====
  24668. var _WidgetBase = dijit._WidgetBase;
  24669. var _TemplatedMixin = dijit._TemplatedMixin;
  24670. =====*/
  24671. // module:
  24672. // dijit/CalendarLite
  24673. // summary:
  24674. // Lightweight version of Calendar widget aimed towards mobile use
  24675. var CalendarLite = declare("dijit.CalendarLite", [_WidgetBase, _TemplatedMixin], {
  24676. // summary:
  24677. // Lightweight version of Calendar widget aimed towards mobile use
  24678. //
  24679. // description:
  24680. // A simple GUI for choosing a date in the context of a monthly calendar.
  24681. // This widget can't be used in a form because it doesn't serialize the date to an
  24682. // `<input>` field. For a form element, use dijit.form.DateTextBox instead.
  24683. //
  24684. // Note that the parser takes all dates attributes passed in the
  24685. // [RFC 3339 format](http://www.faqs.org/rfcs/rfc3339.html), e.g. `2005-06-30T08:05:00-07:00`
  24686. // so that they are serializable and locale-independent.
  24687. //
  24688. // Also note that this widget isn't keyboard accessible; use dijit.Calendar for that
  24689. // example:
  24690. // | var calendar = new dijit.CalendarLite({}, dojo.byId("calendarNode"));
  24691. //
  24692. // example:
  24693. // | <div data-dojo-type="dijit.CalendarLite"></div>
  24694. // Template for main calendar
  24695. templateString: template,
  24696. // Template for cell for a day of the week (ex: M)
  24697. dowTemplateString: '<th class="dijitReset dijitCalendarDayLabelTemplate" role="columnheader"><span class="dijitCalendarDayLabel">${d}</span></th>',
  24698. // Templates for a single date (ex: 13), and for a row for a week (ex: 20 21 22 23 24 25 26)
  24699. dateTemplateString: '<td class="dijitReset" role="gridcell" data-dojo-attach-point="dateCells"><span class="dijitCalendarDateLabel" data-dojo-attach-point="dateLabels"></span></td>',
  24700. weekTemplateString: '<tr class="dijitReset dijitCalendarWeekTemplate" role="row">${d}${d}${d}${d}${d}${d}${d}</tr>',
  24701. // value: Date
  24702. // The currently selected Date, initially set to invalid date to indicate no selection.
  24703. value: new Date(""),
  24704. // TODO: for 2.0 make this a string (ISO format) rather than a Date
  24705. // datePackage: String
  24706. // JavaScript object containing Calendar functions. Uses Gregorian Calendar routines
  24707. // from dojo.date by default.
  24708. datePackage: date,
  24709. // dayWidth: String
  24710. // How to represent the days of the week in the calendar header. See locale
  24711. dayWidth: "narrow",
  24712. // tabIndex: Integer
  24713. // Order fields are traversed when user hits the tab key
  24714. tabIndex: "0",
  24715. // currentFocus: Date
  24716. // Date object containing the currently focused date, or the date which would be focused
  24717. // if the calendar itself was focused. Also indicates which year and month to display,
  24718. // i.e. the current "page" the calendar is on.
  24719. currentFocus: new Date(),
  24720. baseClass:"dijitCalendar",
  24721. _isValidDate: function(/*Date*/ value){
  24722. // summary:
  24723. // Runs various tests on the value, checking that it's a valid date, rather
  24724. // than blank or NaN.
  24725. // tags:
  24726. // private
  24727. return value && !isNaN(value) && typeof value == "object" &&
  24728. value.toString() != this.constructor.prototype.value.toString();
  24729. },
  24730. _getValueAttr: function(){
  24731. // summary:
  24732. // Support get('value')
  24733. // this.value is set to 1AM, but return midnight, local time for back-compat
  24734. if(this.value && !isNaN(this.value)){
  24735. var value = new this.dateClassObj(this.value);
  24736. value.setHours(0, 0, 0, 0);
  24737. // If daylight savings pushes midnight to the previous date, fix the Date
  24738. // object to point at 1am so it will represent the correct day. See #9366
  24739. if(value.getDate() < this.value.getDate()){
  24740. value = this.dateFuncObj.add(value, "hour", 1);
  24741. }
  24742. return value;
  24743. }else{
  24744. return null;
  24745. }
  24746. },
  24747. _setValueAttr: function(/*Date|Number*/ value, /*Boolean*/ priorityChange){
  24748. // summary:
  24749. // Support set("value", ...)
  24750. // description:
  24751. // Set the current date and update the UI. If the date is disabled, the value will
  24752. // not change, but the display will change to the corresponding month.
  24753. // value:
  24754. // Either a Date or the number of seconds since 1970.
  24755. // tags:
  24756. // protected
  24757. if(value){
  24758. // convert from Number to Date, or make copy of Date object so that setHours() call below
  24759. // doesn't affect original value
  24760. value = new this.dateClassObj(value);
  24761. }
  24762. if(this._isValidDate(value)){
  24763. if(!this._isValidDate(this.value) || this.dateFuncObj.compare(value, this.value)){
  24764. value.setHours(1, 0, 0, 0); // round to nearest day (1am to avoid issues when DST shift occurs at midnight, see #8521, #9366)
  24765. if(!this.isDisabledDate(value, this.lang)){
  24766. this._set("value", value);
  24767. // Set focus cell to the new value. Arguably this should only happen when there isn't a current
  24768. // focus point. This will also repopulate the grid, showing the new selected value (and possibly
  24769. // new month/year).
  24770. this.set("currentFocus", value);
  24771. if(priorityChange || typeof priorityChange == "undefined"){
  24772. this.onChange(this.get('value'));
  24773. }
  24774. }
  24775. }
  24776. }else{
  24777. // clear value, and repopulate grid (to deselect the previously selected day) without changing currentFocus
  24778. this._set("value", null);
  24779. this.set("currentFocus", this.currentFocus);
  24780. }
  24781. },
  24782. _setText: function(node, text){
  24783. // summary:
  24784. // This just sets the content of node to the specified text.
  24785. // Can't do "node.innerHTML=text" because of an IE bug w/tables, see #3434.
  24786. // tags:
  24787. // private
  24788. while(node.firstChild){
  24789. node.removeChild(node.firstChild);
  24790. }
  24791. node.appendChild(win.doc.createTextNode(text));
  24792. },
  24793. _populateGrid: function(){
  24794. // summary:
  24795. // Fills in the calendar grid with each day (1-31)
  24796. // tags:
  24797. // private
  24798. var month = new this.dateClassObj(this.currentFocus);
  24799. month.setDate(1);
  24800. var firstDay = month.getDay(),
  24801. daysInMonth = this.dateFuncObj.getDaysInMonth(month),
  24802. daysInPreviousMonth = this.dateFuncObj.getDaysInMonth(this.dateFuncObj.add(month, "month", -1)),
  24803. today = new this.dateClassObj(),
  24804. dayOffset = cldrSupplemental.getFirstDayOfWeek(this.lang);
  24805. if(dayOffset > firstDay){ dayOffset -= 7; }
  24806. // Mapping from date (as specified by number returned from Date.valueOf()) to corresponding <td>
  24807. this._date2cell = {};
  24808. // Iterate through dates in the calendar and fill in date numbers and style info
  24809. array.forEach(this.dateCells, function(template, idx){
  24810. var i = idx + dayOffset;
  24811. var date = new this.dateClassObj(month),
  24812. number, clazz = "dijitCalendar", adj = 0;
  24813. if(i < firstDay){
  24814. number = daysInPreviousMonth - firstDay + i + 1;
  24815. adj = -1;
  24816. clazz += "Previous";
  24817. }else if(i >= (firstDay + daysInMonth)){
  24818. number = i - firstDay - daysInMonth + 1;
  24819. adj = 1;
  24820. clazz += "Next";
  24821. }else{
  24822. number = i - firstDay + 1;
  24823. clazz += "Current";
  24824. }
  24825. if(adj){
  24826. date = this.dateFuncObj.add(date, "month", adj);
  24827. }
  24828. date.setDate(number);
  24829. if(!this.dateFuncObj.compare(date, today, "date")){
  24830. clazz = "dijitCalendarCurrentDate " + clazz;
  24831. }
  24832. if(this._isSelectedDate(date, this.lang)){
  24833. clazz = "dijitCalendarSelectedDate " + clazz;
  24834. template.setAttribute("aria-selected", true);
  24835. }else{
  24836. template.setAttribute("aria-selected", false);
  24837. }
  24838. if(this.isDisabledDate(date, this.lang)){
  24839. clazz = "dijitCalendarDisabledDate " + clazz;
  24840. template.setAttribute("aria-disabled", true);
  24841. }else{
  24842. clazz = "dijitCalendarEnabledDate " + clazz;
  24843. template.removeAttribute("aria-disabled");
  24844. }
  24845. var clazz2 = this.getClassForDate(date, this.lang);
  24846. if(clazz2){
  24847. clazz = clazz2 + " " + clazz;
  24848. }
  24849. template.className = clazz + "Month dijitCalendarDateTemplate";
  24850. // Each cell has an associated integer value representing it's date
  24851. var dateVal = date.valueOf();
  24852. this._date2cell[dateVal] = template;
  24853. template.dijitDateValue = dateVal;
  24854. // Set Date string (ex: "13").
  24855. this._setText(this.dateLabels[idx], date.getDateLocalized ? date.getDateLocalized(this.lang) : date.getDate());
  24856. }, this);
  24857. // set name of this month
  24858. this.monthWidget.set("month", month);
  24859. // Fill in localized prev/current/next years
  24860. var y = month.getFullYear() - 1;
  24861. var d = new this.dateClassObj();
  24862. array.forEach(["previous", "current", "next"], function(name){
  24863. d.setFullYear(y++);
  24864. this._setText(this[name+"YearLabelNode"],
  24865. this.dateLocaleModule.format(d, {selector:'year', locale:this.lang}));
  24866. }, this);
  24867. },
  24868. goToToday: function(){
  24869. // summary:
  24870. // Sets calendar's value to today's date
  24871. this.set('value', new this.dateClassObj());
  24872. },
  24873. constructor: function(/*Object*/args){
  24874. this.datePackage = args.datePackage || this.datePackage;
  24875. this.dateFuncObj = typeof this.datePackage == "string" ?
  24876. lang.getObject(this.datePackage, false) :// "string" part for back-compat, remove for 2.0
  24877. this.datePackage;
  24878. this.dateClassObj = this.dateFuncObj.Date || Date;
  24879. this.dateLocaleModule = lang.getObject("locale", false, this.dateFuncObj);
  24880. },
  24881. _createMonthWidget: function(){
  24882. // summary:
  24883. // Creates the drop down button that displays the current month and lets user pick a new one
  24884. return CalendarLite._MonthWidget({
  24885. id: this.id + "_mw",
  24886. lang: this.lang,
  24887. dateLocaleModule: this.dateLocaleModule
  24888. }, this.monthNode);
  24889. },
  24890. buildRendering: function(){
  24891. // Markup for days of the week (referenced from template)
  24892. var d = this.dowTemplateString,
  24893. dayNames = this.dateLocaleModule.getNames('days', this.dayWidth, 'standAlone', this.lang),
  24894. dayOffset = cldrSupplemental.getFirstDayOfWeek(this.lang);
  24895. this.dayCellsHtml = string.substitute([d,d,d,d,d,d,d].join(""), {d: ""}, function(){
  24896. return dayNames[dayOffset++ % 7]
  24897. });
  24898. // Markup for dates of the month (referenced from template), but without numbers filled in
  24899. var r = string.substitute(this.weekTemplateString, {d: this.dateTemplateString});
  24900. this.dateRowsHtml = [r,r,r,r,r,r].join("");
  24901. // Instantiate from template.
  24902. // dateCells and dateLabels arrays filled when _Templated parses my template.
  24903. this.dateCells = [];
  24904. this.dateLabels = [];
  24905. this.inherited(arguments);
  24906. dom.setSelectable(this.domNode, false);
  24907. var dateObj = new this.dateClassObj(this.currentFocus);
  24908. this._supportingWidgets.push(this.monthWidget = this._createMonthWidget());
  24909. this.set('currentFocus', dateObj, false); // draw the grid to the month specified by currentFocus
  24910. // Set up connects for increment/decrement of months/years
  24911. var connect = lang.hitch(this, function(nodeProp, part, amount){
  24912. this.connect(this[nodeProp], "onclick", function(){
  24913. this._setCurrentFocusAttr(this.dateFuncObj.add(this.currentFocus, part, amount));
  24914. });
  24915. });
  24916. connect("incrementMonth", "month", 1);
  24917. connect("decrementMonth", "month", -1);
  24918. connect("nextYearLabelNode", "year", 1);
  24919. connect("previousYearLabelNode", "year", -1);
  24920. },
  24921. _setCurrentFocusAttr: function(/*Date*/ date, /*Boolean*/ forceFocus){
  24922. // summary:
  24923. // If the calendar currently has focus, then focuses specified date,
  24924. // changing the currently displayed month/year if necessary.
  24925. // If the calendar doesn't have focus, updates currently
  24926. // displayed month/year, and sets the cell that will get focus.
  24927. // forceFocus:
  24928. // If true, will focus() the cell even if calendar itself doesn't have focus
  24929. var oldFocus = this.currentFocus,
  24930. oldCell = oldFocus && this._date2cell ? this._date2cell[oldFocus.valueOf()] : null;
  24931. // round specified value to nearest day (1am to avoid issues when DST shift occurs at midnight, see #8521, #9366)
  24932. date = new this.dateClassObj(date);
  24933. date.setHours(1, 0, 0, 0);
  24934. this._set("currentFocus", date);
  24935. // TODO: only re-populate grid when month/year has changed
  24936. this._populateGrid();
  24937. // set tabIndex=0 on new cell, and focus it (but only if Calendar itself is focused)
  24938. var newCell = this._date2cell[date.valueOf()];
  24939. newCell.setAttribute("tabIndex", this.tabIndex);
  24940. if(this.focused || forceFocus){
  24941. newCell.focus();
  24942. }
  24943. // set tabIndex=-1 on old focusable cell
  24944. if(oldCell && oldCell != newCell){
  24945. if(has("webkit")){ // see #11064 about webkit bug
  24946. oldCell.setAttribute("tabIndex", "-1");
  24947. }else{
  24948. oldCell.removeAttribute("tabIndex");
  24949. }
  24950. }
  24951. },
  24952. focus: function(){
  24953. // summary:
  24954. // Focus the calendar by focusing one of the calendar cells
  24955. this._setCurrentFocusAttr(this.currentFocus, true);
  24956. },
  24957. _onDayClick: function(/*Event*/ evt){
  24958. // summary:
  24959. // Handler for day clicks, selects the date if appropriate
  24960. // tags:
  24961. // protected
  24962. event.stop(evt);
  24963. for(var node = evt.target; node && !node.dijitDateValue; node = node.parentNode);
  24964. if(node && !domClass.contains(node, "dijitCalendarDisabledDate")){
  24965. this.set('value', node.dijitDateValue);
  24966. }
  24967. },
  24968. onChange: function(/*Date*/ /*===== date =====*/){
  24969. // summary:
  24970. // Called only when the selected date has changed
  24971. },
  24972. _isSelectedDate: function(dateObject /*===== , locale =====*/){
  24973. // summary:
  24974. // Extension point so developers can subclass Calendar to
  24975. // support multiple (concurrently) selected dates
  24976. // dateObject: Date
  24977. // locale: String?
  24978. // tags:
  24979. // protected extension
  24980. return this._isValidDate(this.value) && !this.dateFuncObj.compare(dateObject, this.value, "date")
  24981. },
  24982. isDisabledDate: function(/*===== dateObject, locale =====*/){
  24983. // summary:
  24984. // May be overridden to disable certain dates in the calendar e.g. `isDisabledDate=dojo.date.locale.isWeekend`
  24985. // dateObject: Date
  24986. // locale: String?
  24987. // tags:
  24988. // extension
  24989. /*=====
  24990. return false; // Boolean
  24991. =====*/
  24992. },
  24993. getClassForDate: function(/*===== dateObject, locale =====*/){
  24994. // summary:
  24995. // May be overridden to return CSS classes to associate with the date entry for the given dateObject,
  24996. // for example to indicate a holiday in specified locale.
  24997. // dateObject: Date
  24998. // locale: String?
  24999. // tags:
  25000. // extension
  25001. /*=====
  25002. return ""; // String
  25003. =====*/
  25004. }
  25005. });
  25006. CalendarLite._MonthWidget = declare("dijit.CalendarLite._MonthWidget", _WidgetBase, {
  25007. // summary:
  25008. // Displays name of current month padded to the width of the month
  25009. // w/the longest name, so that changing months doesn't change width.
  25010. //
  25011. // Create as new dijit.Calendar._MonthWidget({
  25012. // lang: ...,
  25013. // dateLocaleModule: ...
  25014. // })
  25015. _setMonthAttr: function(month){
  25016. // summary:
  25017. // Set the current month to display as a label
  25018. var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, month),
  25019. spacer =
  25020. (has("ie") == 6 ? "" : "<div class='dijitSpacer'>" +
  25021. array.map(monthNames, function(s){ return "<div>" + s + "</div>"; }).join("") + "</div>");
  25022. // Set name of current month and also fill in spacer element with all the month names
  25023. // (invisible) so that the maximum width will affect layout. But not on IE6 because then
  25024. // the center <TH> overlaps the right <TH> (due to a browser bug).
  25025. this.domNode.innerHTML =
  25026. spacer +
  25027. "<div class='dijitCalendarMonthLabel dijitCalendarCurrentMonthLabel'>" +
  25028. monthNames[month.getMonth()] + "</div>";
  25029. }
  25030. });
  25031. return CalendarLite;
  25032. });
  25033. },
  25034. 'dijit/CheckedMenuItem':function(){
  25035. require({cache:{
  25036. 'url:dijit/templates/CheckedMenuItem.html':"<tr class=\"dijitReset dijitMenuItem\" data-dojo-attach-point=\"focusNode\" role=\"menuitemcheckbox\" tabIndex=\"-1\"\n\t\tdata-dojo-attach-event=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuItemIcon dijitCheckedMenuItemIcon\" data-dojo-attach-point=\"iconNode\"/>\n\t\t<span class=\"dijitCheckedMenuItemIconChar\">&#10003;</span>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" data-dojo-attach-point=\"containerNode,labelNode\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" data-dojo-attach-point=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">&#160;</td>\n</tr>\n"}});
  25037. define("dijit/CheckedMenuItem", [
  25038. "dojo/_base/declare", // declare
  25039. "dojo/dom-class", // domClass.toggle
  25040. "./MenuItem",
  25041. "dojo/text!./templates/CheckedMenuItem.html",
  25042. "./hccss"
  25043. ], function(declare, domClass, MenuItem, template){
  25044. /*=====
  25045. var MenuItem = dijit.MenuItem;
  25046. =====*/
  25047. // module:
  25048. // dijit/CheckedMenuItem
  25049. // summary:
  25050. // A checkbox-like menu item for toggling on and off
  25051. return declare("dijit.CheckedMenuItem", MenuItem, {
  25052. // summary:
  25053. // A checkbox-like menu item for toggling on and off
  25054. templateString: template,
  25055. // checked: Boolean
  25056. // Our checked state
  25057. checked: false,
  25058. _setCheckedAttr: function(/*Boolean*/ checked){
  25059. // summary:
  25060. // Hook so attr('checked', bool) works.
  25061. // Sets the class and state for the check box.
  25062. domClass.toggle(this.domNode, "dijitCheckedMenuItemChecked", checked);
  25063. this.domNode.setAttribute("aria-checked", checked);
  25064. this._set("checked", checked);
  25065. },
  25066. iconClass: "", // override dijitNoIcon
  25067. onChange: function(/*Boolean*/ /*===== checked =====*/){
  25068. // summary:
  25069. // User defined function to handle check/uncheck events
  25070. // tags:
  25071. // callback
  25072. },
  25073. _onClick: function(/*Event*/ e){
  25074. // summary:
  25075. // Clicking this item just toggles its state
  25076. // tags:
  25077. // private
  25078. if(!this.disabled){
  25079. this.set("checked", !this.checked);
  25080. this.onChange(this.checked);
  25081. }
  25082. this.inherited(arguments);
  25083. }
  25084. });
  25085. });
  25086. },
  25087. 'dijit/form/VerticalRuleLabels':function(){
  25088. define([
  25089. "dojo/_base/declare", // declare
  25090. "./HorizontalRuleLabels"
  25091. ], function(declare, HorizontalRuleLabels){
  25092. /*=====
  25093. var HorizontalRuleLabels = dijit.form.HorizontalRuleLabels;
  25094. =====*/
  25095. // module:
  25096. // dijit/form/VerticalRuleLabels
  25097. // summary:
  25098. // Labels for the `dijit.form.VerticalSlider`
  25099. return declare("dijit.form.VerticalRuleLabels", HorizontalRuleLabels, {
  25100. // summary:
  25101. // Labels for the `dijit.form.VerticalSlider`
  25102. templateString: '<div class="dijitRuleContainer dijitRuleContainerV dijitRuleLabelsContainer dijitRuleLabelsContainerV"></div>',
  25103. _positionPrefix: '<div class="dijitRuleLabelContainer dijitRuleLabelContainerV" style="top:',
  25104. _labelPrefix: '"><span class="dijitRuleLabel dijitRuleLabelV">',
  25105. _calcPosition: function(pos){
  25106. // Overrides HorizontalRuleLabel._calcPosition()
  25107. return 100-pos;
  25108. },
  25109. // needed to prevent labels from being reversed in RTL mode
  25110. _isHorizontal: false
  25111. });
  25112. });
  25113. },
  25114. 'dijit/Declaration':function(){
  25115. define([
  25116. "dojo/_base/array", // array.forEach array.map
  25117. "dojo/_base/connect", // connect.connect
  25118. "dojo/_base/declare", // declare
  25119. "dojo/_base/lang", // lang.getObject
  25120. "dojo/parser", // parser._functionFromScript
  25121. "dojo/query", // query
  25122. "./_Widget",
  25123. "./_TemplatedMixin",
  25124. "./_WidgetsInTemplateMixin",
  25125. "dojo/NodeList-dom"
  25126. ], function(array, connect, declare, lang, parser, query, _Widget, _TemplatedMixin, _WidgetsInTemplateMixin){
  25127. /*=====
  25128. var _Widget = dijit._Widget;
  25129. var _TemplatedMixin = dijit._TemplatedMixin;
  25130. var _WidgetsInTemplateMixin = dijit._WidgetsInTemplateMixin;
  25131. =====*/
  25132. // module:
  25133. // dijit/Declaration
  25134. // summary:
  25135. // The Declaration widget allows a developer to declare new widget
  25136. // classes directly from a snippet of markup.
  25137. return declare("dijit.Declaration", _Widget, {
  25138. // summary:
  25139. // The Declaration widget allows a developer to declare new widget
  25140. // classes directly from a snippet of markup.
  25141. // _noScript: [private] Boolean
  25142. // Flag to parser to leave alone the script tags contained inside of me
  25143. _noScript: true,
  25144. // stopParser: [private] Boolean
  25145. // Flag to parser to not try and parse widgets declared inside of me
  25146. stopParser: true,
  25147. // widgetClass: [const] String
  25148. // Name of class being declared, ex: "acme.myWidget"
  25149. widgetClass: "",
  25150. // propList: [const] Object
  25151. // Set of attributes for this widget along with default values, ex:
  25152. // {delay: 100, title: "hello world"}
  25153. defaults: null,
  25154. // mixins: [const] String[]
  25155. // List containing the prototype for this widget, and also any mixins,
  25156. // ex: ["dijit._Widget", "dijit._Container"]
  25157. mixins: [],
  25158. buildRendering: function(){
  25159. var src = this.srcNodeRef.parentNode.removeChild(this.srcNodeRef),
  25160. methods = query("> script[type^='dojo/method']", src).orphan(),
  25161. connects = query("> script[type^='dojo/connect']", src).orphan(),
  25162. srcType = src.nodeName;
  25163. var propList = this.defaults || {};
  25164. // For all methods defined like <script type="dojo/method" data-dojo-event="foo">,
  25165. // add that method to prototype.
  25166. // If there's no "event" specified then it's code to run on instantiation,
  25167. // so it becomes a connection to "postscript" (handled below).
  25168. array.forEach(methods, function(s){
  25169. var evt = s.getAttribute("event") || s.getAttribute("data-dojo-event"),
  25170. func = parser._functionFromScript(s);
  25171. if(evt){
  25172. propList[evt] = func;
  25173. }else{
  25174. connects.push(s);
  25175. }
  25176. });
  25177. // map array of strings like [ "dijit.form.Button" ] to array of mixin objects
  25178. // (note that array.map(this.mixins, lang.getObject) doesn't work because it passes
  25179. // a bogus third argument to getObject(), confusing it)
  25180. this.mixins = this.mixins.length ?
  25181. array.map(this.mixins, function(name){ return lang.getObject(name); } ) :
  25182. [ _Widget, _TemplatedMixin, _WidgetsInTemplateMixin ];
  25183. propList._skipNodeCache = true;
  25184. propList.templateString =
  25185. "<"+srcType+" class='"+src.className+"'" +
  25186. " data-dojo-attach-point='"+
  25187. (src.getAttribute("data-dojo-attach-point") || src.getAttribute("dojoAttachPoint") || '')+
  25188. "' data-dojo-attach-event='"+
  25189. (src.getAttribute("data-dojo-attach-event") || src.getAttribute("dojoAttachEvent") || '')+
  25190. "' >"+src.innerHTML.replace(/\%7B/g,"{").replace(/\%7D/g,"}")+"</"+srcType+">";
  25191. // create the new widget class
  25192. var wc = declare(
  25193. this.widgetClass,
  25194. this.mixins,
  25195. propList
  25196. );
  25197. // Handle <script> blocks of form:
  25198. // <script type="dojo/connect" data-dojo-event="foo">
  25199. // and
  25200. // <script type="dojo/method">
  25201. // (Note that the second one is just shorthand for a dojo/connect to postscript)
  25202. // Since this is a connect in the declaration, we are actually connection to the method
  25203. // in the _prototype_.
  25204. array.forEach(connects, function(s){
  25205. var evt = s.getAttribute("event") || s.getAttribute("data-dojo-event") || "postscript",
  25206. func = parser._functionFromScript(s);
  25207. connect.connect(wc.prototype, evt, func);
  25208. });
  25209. }
  25210. });
  25211. });
  25212. },
  25213. 'dijit/MenuSeparator':function(){
  25214. require({cache:{
  25215. 'url:dijit/templates/MenuSeparator.html':"<tr class=\"dijitMenuSeparator\">\n\t<td class=\"dijitMenuSeparatorIconCell\">\n\t\t<div class=\"dijitMenuSeparatorTop\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n\t<td colspan=\"3\" class=\"dijitMenuSeparatorLabelCell\">\n\t\t<div class=\"dijitMenuSeparatorTop dijitMenuSeparatorLabel\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n</tr>"}});
  25216. define("dijit/MenuSeparator", [
  25217. "dojo/_base/declare", // declare
  25218. "dojo/dom", // dom.setSelectable
  25219. "./_WidgetBase",
  25220. "./_TemplatedMixin",
  25221. "./_Contained",
  25222. "dojo/text!./templates/MenuSeparator.html"
  25223. ], function(declare, dom, _WidgetBase, _TemplatedMixin, _Contained, template){
  25224. /*=====
  25225. var _WidgetBase = dijit._WidgetBase;
  25226. var _TemplatedMixin = dijit._TemplatedMixin;
  25227. var _Contained = dijit._Contained;
  25228. =====*/
  25229. // module:
  25230. // dijit/MenuSeparator
  25231. // summary:
  25232. // A line between two menu items
  25233. return declare("dijit.MenuSeparator", [_WidgetBase, _TemplatedMixin, _Contained], {
  25234. // summary:
  25235. // A line between two menu items
  25236. templateString: template,
  25237. buildRendering: function(){
  25238. this.inherited(arguments);
  25239. dom.setSelectable(this.domNode, false);
  25240. },
  25241. isFocusable: function(){
  25242. // summary:
  25243. // Override to always return false
  25244. // tags:
  25245. // protected
  25246. return false; // Boolean
  25247. }
  25248. });
  25249. });
  25250. },
  25251. 'dijit/form/_ComboBoxMenu':function(){
  25252. define([
  25253. "dojo/_base/declare", // declare
  25254. "dojo/dom-class", // domClass.add domClass.remove
  25255. "dojo/dom-construct", // domConstruct.create
  25256. "dojo/dom-style", // domStyle.get
  25257. "dojo/keys", // keys.DOWN_ARROW keys.PAGE_DOWN keys.PAGE_UP keys.UP_ARROW
  25258. "../_WidgetBase",
  25259. "../_TemplatedMixin",
  25260. "./_ComboBoxMenuMixin",
  25261. "./_ListMouseMixin"
  25262. ], function(declare, domClass, domConstruct, domStyle, keys,
  25263. _WidgetBase, _TemplatedMixin, _ComboBoxMenuMixin, _ListMouseMixin){
  25264. /*=====
  25265. var _WidgetBase = dijit._WidgetBase;
  25266. var _TemplatedMixin = dijit._TemplatedMixin;
  25267. var _ComboBoxMenuMixin = dijit.form._ComboBoxMenuMixin;
  25268. var _ListMouseMixin = dijit.form._ListMouseMixin;
  25269. =====*/
  25270. // module:
  25271. // dijit/form/_ComboBoxMenu
  25272. // summary:
  25273. // Focus-less menu for internal use in `dijit.form.ComboBox`
  25274. return declare("dijit.form._ComboBoxMenu",[_WidgetBase, _TemplatedMixin, _ListMouseMixin, _ComboBoxMenuMixin], {
  25275. // summary:
  25276. // Focus-less menu for internal use in `dijit.form.ComboBox`
  25277. // Abstract methods that must be defined externally:
  25278. // onChange: item was explicitly chosen (mousedown somewhere on the menu and mouseup somewhere on the menu)
  25279. // onPage: next(1) or previous(-1) button pressed
  25280. // tags:
  25281. // private
  25282. templateString: "<div class='dijitReset dijitMenu' data-dojo-attach-point='containerNode' style='overflow: auto; overflow-x: hidden;'>"
  25283. +"<div class='dijitMenuItem dijitMenuPreviousButton' data-dojo-attach-point='previousButton' role='option'></div>"
  25284. +"<div class='dijitMenuItem dijitMenuNextButton' data-dojo-attach-point='nextButton' role='option'></div>"
  25285. +"</div>",
  25286. baseClass: "dijitComboBoxMenu",
  25287. postCreate: function(){
  25288. this.inherited(arguments);
  25289. if(!this.isLeftToRight()){
  25290. domClass.add(this.previousButton, "dijitMenuItemRtl");
  25291. domClass.add(this.nextButton, "dijitMenuItemRtl");
  25292. }
  25293. },
  25294. _createMenuItem: function(){
  25295. return domConstruct.create("div", {
  25296. "class": "dijitReset dijitMenuItem" +(this.isLeftToRight() ? "" : " dijitMenuItemRtl"),
  25297. role: "option"
  25298. });
  25299. },
  25300. onHover: function(/*DomNode*/ node){
  25301. // summary:
  25302. // Add hover CSS
  25303. domClass.add(node, "dijitMenuItemHover");
  25304. },
  25305. onUnhover: function(/*DomNode*/ node){
  25306. // summary:
  25307. // Remove hover CSS
  25308. domClass.remove(node, "dijitMenuItemHover");
  25309. },
  25310. onSelect: function(/*DomNode*/ node){
  25311. // summary:
  25312. // Add selected CSS
  25313. domClass.add(node, "dijitMenuItemSelected");
  25314. },
  25315. onDeselect: function(/*DomNode*/ node){
  25316. // summary:
  25317. // Remove selected CSS
  25318. domClass.remove(node, "dijitMenuItemSelected");
  25319. },
  25320. _page: function(/*Boolean*/ up){
  25321. // summary:
  25322. // Handles page-up and page-down keypresses
  25323. var scrollamount = 0;
  25324. var oldscroll = this.domNode.scrollTop;
  25325. var height = domStyle.get(this.domNode, "height");
  25326. // if no item is highlighted, highlight the first option
  25327. if(!this.getHighlightedOption()){
  25328. this.selectNextNode();
  25329. }
  25330. while(scrollamount<height){
  25331. var highlighted_option = this.getHighlightedOption();
  25332. if(up){
  25333. // stop at option 1
  25334. if(!highlighted_option.previousSibling ||
  25335. highlighted_option.previousSibling.style.display == "none"){
  25336. break;
  25337. }
  25338. this.selectPreviousNode();
  25339. }else{
  25340. // stop at last option
  25341. if(!highlighted_option.nextSibling ||
  25342. highlighted_option.nextSibling.style.display == "none"){
  25343. break;
  25344. }
  25345. this.selectNextNode();
  25346. }
  25347. // going backwards
  25348. var newscroll = this.domNode.scrollTop;
  25349. scrollamount += (newscroll-oldscroll)*(up ? -1:1);
  25350. oldscroll = newscroll;
  25351. }
  25352. },
  25353. handleKey: function(evt){
  25354. // summary:
  25355. // Handle keystroke event forwarded from ComboBox, returning false if it's
  25356. // a keystroke I recognize and process, true otherwise.
  25357. switch(evt.keyCode){
  25358. case keys.DOWN_ARROW:
  25359. this.selectNextNode();
  25360. return false;
  25361. case keys.PAGE_DOWN:
  25362. this._page(false);
  25363. return false;
  25364. case keys.UP_ARROW:
  25365. this.selectPreviousNode();
  25366. return false;
  25367. case keys.PAGE_UP:
  25368. this._page(true);
  25369. return false;
  25370. default:
  25371. return true;
  25372. }
  25373. }
  25374. });
  25375. });
  25376. },
  25377. 'url:dijit/layout/templates/ScrollingTabController.html':"<div class=\"dijitTabListContainer-${tabPosition}\" style=\"visibility:hidden\">\n\t<div data-dojo-type=\"dijit.layout._ScrollingTabControllerMenuButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_menuBtn\"\n\t\t\tdata-dojo-props=\"containerId: '${containerId}', iconClass: 'dijitTabStripMenuIcon',\n\t\t\t\t\tdropDownPosition: ['below-alt', 'above-alt']\"\n\t\t\tdata-dojo-attach-point=\"_menuBtn\" showLabel=\"false\" title=\"\">&#9660;</div>\n\t<div data-dojo-type=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_leftBtn\"\n\t\t\tdata-dojo-props=\"iconClass:'dijitTabStripSlideLeftIcon', showLabel:false, title:''\"\n\t\t\tdata-dojo-attach-point=\"_leftBtn\" data-dojo-attach-event=\"onClick: doSlideLeft\">&#9664;</div>\n\t<div data-dojo-type=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_rightBtn\"\n\t\t\tdata-dojo-props=\"iconClass:'dijitTabStripSlideRightIcon', showLabel:false, title:''\"\n\t\t\tdata-dojo-attach-point=\"_rightBtn\" data-dojo-attach-event=\"onClick: doSlideRight\">&#9654;</div>\n\t<div class='dijitTabListWrapper' data-dojo-attach-point='tablistWrapper'>\n\t\t<div role='tablist' data-dojo-attach-event='onkeypress:onkeypress'\n\t\t\t\tdata-dojo-attach-point='containerNode' class='nowrapTabStrip'></div>\n\t</div>\n</div>",
  25378. 'dijit/Dialog':function(){
  25379. require({cache:{
  25380. 'url:dijit/templates/Dialog.html':"<div class=\"dijitDialog\" role=\"dialog\" aria-labelledby=\"${id}_title\">\n\t<div data-dojo-attach-point=\"titleBar\" class=\"dijitDialogTitleBar\">\n\t<span data-dojo-attach-point=\"titleNode\" class=\"dijitDialogTitle\" id=\"${id}_title\"></span>\n\t<span data-dojo-attach-point=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" data-dojo-attach-event=\"ondijitclick: onCancel\" title=\"${buttonCancel}\" role=\"button\" tabIndex=\"0\">\n\t\t<span data-dojo-attach-point=\"closeText\" class=\"closeText\" title=\"${buttonCancel}\">x</span>\n\t</span>\n\t</div>\n\t\t<div data-dojo-attach-point=\"containerNode\" class=\"dijitDialogPaneContent\"></div>\n</div>\n"}});
  25381. define("dijit/Dialog", [
  25382. "require",
  25383. "dojo/_base/array", // array.forEach array.indexOf array.map
  25384. "dojo/_base/connect", // connect._keypress
  25385. "dojo/_base/declare", // declare
  25386. "dojo/_base/Deferred", // Deferred
  25387. "dojo/dom", // dom.isDescendant
  25388. "dojo/dom-class", // domClass.add domClass.contains
  25389. "dojo/dom-geometry", // domGeometry.position
  25390. "dojo/dom-style", // domStyle.set
  25391. "dojo/_base/event", // event.stop
  25392. "dojo/_base/fx", // fx.fadeIn fx.fadeOut
  25393. "dojo/i18n", // i18n.getLocalization
  25394. "dojo/_base/kernel", // kernel.isAsync
  25395. "dojo/keys",
  25396. "dojo/_base/lang", // lang.mixin lang.hitch
  25397. "dojo/on",
  25398. "dojo/ready",
  25399. "dojo/_base/sniff", // has("ie") has("opera")
  25400. "dojo/_base/window", // win.body
  25401. "dojo/window", // winUtils.getBox
  25402. "dojo/dnd/Moveable", // Moveable
  25403. "dojo/dnd/TimedMoveable", // TimedMoveable
  25404. "./focus",
  25405. "./_base/manager", // manager.defaultDuration
  25406. "./_Widget",
  25407. "./_TemplatedMixin",
  25408. "./_CssStateMixin",
  25409. "./form/_FormMixin",
  25410. "./_DialogMixin",
  25411. "./DialogUnderlay",
  25412. "./layout/ContentPane",
  25413. "dojo/text!./templates/Dialog.html",
  25414. ".", // for back-compat, exporting dijit._underlay (remove in 2.0)
  25415. "dojo/i18n!./nls/common"
  25416. ], function(require, array, connect, declare, Deferred,
  25417. dom, domClass, domGeometry, domStyle, event, fx, i18n, kernel, keys, lang, on, ready, has, win, winUtils,
  25418. Moveable, TimedMoveable, focus, manager, _Widget, _TemplatedMixin, _CssStateMixin, _FormMixin, _DialogMixin,
  25419. DialogUnderlay, ContentPane, template, dijit){
  25420. /*=====
  25421. var _Widget = dijit._Widget;
  25422. var _TemplatedMixin = dijit._TemplatedMixin;
  25423. var _CssStateMixin = dijit._CssStateMixin;
  25424. var _FormMixin = dijit.form._FormMixin;
  25425. var _DialogMixin = dijit._DialogMixin;
  25426. =====*/
  25427. // module:
  25428. // dijit/Dialog
  25429. // summary:
  25430. // A modal dialog Widget
  25431. /*=====
  25432. dijit._underlay = function(kwArgs){
  25433. // summary:
  25434. // A shared instance of a `dijit.DialogUnderlay`
  25435. //
  25436. // description:
  25437. // A shared instance of a `dijit.DialogUnderlay` created and
  25438. // used by `dijit.Dialog`, though never created until some Dialog
  25439. // or subclass thereof is shown.
  25440. };
  25441. =====*/
  25442. var _DialogBase = declare("dijit._DialogBase", [_TemplatedMixin, _FormMixin, _DialogMixin, _CssStateMixin], {
  25443. // summary:
  25444. // A modal dialog Widget
  25445. //
  25446. // description:
  25447. // Pops up a modal dialog window, blocking access to the screen
  25448. // and also graying out the screen Dialog is extended from
  25449. // ContentPane so it supports all the same parameters (href, etc.)
  25450. //
  25451. // example:
  25452. // | <div data-dojo-type="dijit.Dialog" data-dojo-props="href: 'test.html'"></div>
  25453. //
  25454. // example:
  25455. // | var foo = new dijit.Dialog({ title: "test dialog", content: "test content" };
  25456. // | dojo.body().appendChild(foo.domNode);
  25457. // | foo.startup();
  25458. templateString: template,
  25459. baseClass: "dijitDialog",
  25460. cssStateNodes: {
  25461. closeButtonNode: "dijitDialogCloseIcon"
  25462. },
  25463. // Map widget attributes to DOMNode attributes.
  25464. _setTitleAttr: [
  25465. { node: "titleNode", type: "innerHTML" },
  25466. { node: "titleBar", type: "attribute" }
  25467. ],
  25468. // open: [readonly] Boolean
  25469. // True if Dialog is currently displayed on screen.
  25470. open: false,
  25471. // duration: Integer
  25472. // The time in milliseconds it takes the dialog to fade in and out
  25473. duration: manager.defaultDuration,
  25474. // refocus: Boolean
  25475. // A Toggle to modify the default focus behavior of a Dialog, which
  25476. // is to re-focus the element which had focus before being opened.
  25477. // False will disable refocusing. Default: true
  25478. refocus: true,
  25479. // autofocus: Boolean
  25480. // A Toggle to modify the default focus behavior of a Dialog, which
  25481. // is to focus on the first dialog element after opening the dialog.
  25482. // False will disable autofocusing. Default: true
  25483. autofocus: true,
  25484. // _firstFocusItem: [private readonly] DomNode
  25485. // The pointer to the first focusable node in the dialog.
  25486. // Set by `dijit._DialogMixin._getFocusItems`.
  25487. _firstFocusItem: null,
  25488. // _lastFocusItem: [private readonly] DomNode
  25489. // The pointer to which node has focus prior to our dialog.
  25490. // Set by `dijit._DialogMixin._getFocusItems`.
  25491. _lastFocusItem: null,
  25492. // doLayout: [protected] Boolean
  25493. // Don't change this parameter from the default value.
  25494. // This ContentPane parameter doesn't make sense for Dialog, since Dialog
  25495. // is never a child of a layout container, nor can you specify the size of
  25496. // Dialog in order to control the size of an inner widget.
  25497. doLayout: false,
  25498. // draggable: Boolean
  25499. // Toggles the moveable aspect of the Dialog. If true, Dialog
  25500. // can be dragged by it's title. If false it will remain centered
  25501. // in the viewport.
  25502. draggable: true,
  25503. //aria-describedby: String
  25504. // Allows the user to add an aria-describedby attribute onto the dialog. The value should
  25505. // be the id of the container element of text that describes the dialog purpose (usually
  25506. // the first text in the dialog).
  25507. // <div data-dojo-type="dijit.Dialog" aria-describedby="intro" .....>
  25508. // <div id="intro">Introductory text</div>
  25509. // <div>rest of dialog contents</div>
  25510. // </div>
  25511. "aria-describedby":"",
  25512. postMixInProperties: function(){
  25513. var _nlsResources = i18n.getLocalization("dijit", "common");
  25514. lang.mixin(this, _nlsResources);
  25515. this.inherited(arguments);
  25516. },
  25517. postCreate: function(){
  25518. domStyle.set(this.domNode, {
  25519. display: "none",
  25520. position:"absolute"
  25521. });
  25522. win.body().appendChild(this.domNode);
  25523. this.inherited(arguments);
  25524. this.connect(this, "onExecute", "hide");
  25525. this.connect(this, "onCancel", "hide");
  25526. this._modalconnects = [];
  25527. },
  25528. onLoad: function(){
  25529. // summary:
  25530. // Called when data has been loaded from an href.
  25531. // Unlike most other callbacks, this function can be connected to (via `dojo.connect`)
  25532. // but should *not* be overridden.
  25533. // tags:
  25534. // callback
  25535. // when href is specified we need to reposition the dialog after the data is loaded
  25536. // and find the focusable elements
  25537. this._position();
  25538. if(this.autofocus && DialogLevelManager.isTop(this)){
  25539. this._getFocusItems(this.domNode);
  25540. focus.focus(this._firstFocusItem);
  25541. }
  25542. this.inherited(arguments);
  25543. },
  25544. _endDrag: function(){
  25545. // summary:
  25546. // Called after dragging the Dialog. Saves the position of the dialog in the viewport,
  25547. // and also adjust position to be fully within the viewport, so user doesn't lose access to handle
  25548. var nodePosition = domGeometry.position(this.domNode),
  25549. viewport = winUtils.getBox();
  25550. nodePosition.y = Math.min(Math.max(nodePosition.y, 0), (viewport.h - nodePosition.h));
  25551. nodePosition.x = Math.min(Math.max(nodePosition.x, 0), (viewport.w - nodePosition.w));
  25552. this._relativePosition = nodePosition;
  25553. this._position();
  25554. },
  25555. _setup: function(){
  25556. // summary:
  25557. // Stuff we need to do before showing the Dialog for the first
  25558. // time (but we defer it until right beforehand, for
  25559. // performance reasons).
  25560. // tags:
  25561. // private
  25562. var node = this.domNode;
  25563. if(this.titleBar && this.draggable){
  25564. this._moveable = new ((has("ie") == 6) ? TimedMoveable // prevent overload, see #5285
  25565. : Moveable)(node, { handle: this.titleBar });
  25566. this.connect(this._moveable, "onMoveStop", "_endDrag");
  25567. }else{
  25568. domClass.add(node,"dijitDialogFixed");
  25569. }
  25570. this.underlayAttrs = {
  25571. dialogId: this.id,
  25572. "class": array.map(this["class"].split(/\s/), function(s){ return s+"_underlay"; }).join(" ")
  25573. };
  25574. },
  25575. _size: function(){
  25576. // summary:
  25577. // If necessary, shrink dialog contents so dialog fits in viewport
  25578. // tags:
  25579. // private
  25580. this._checkIfSingleChild();
  25581. // If we resized the dialog contents earlier, reset them back to original size, so
  25582. // that if the user later increases the viewport size, the dialog can display w/out a scrollbar.
  25583. // Need to do this before the domGeometry.position(this.domNode) call below.
  25584. if(this._singleChild){
  25585. if(this._singleChildOriginalStyle){
  25586. this._singleChild.domNode.style.cssText = this._singleChildOriginalStyle;
  25587. }
  25588. delete this._singleChildOriginalStyle;
  25589. }else{
  25590. domStyle.set(this.containerNode, {
  25591. width:"auto",
  25592. height:"auto"
  25593. });
  25594. }
  25595. var bb = domGeometry.position(this.domNode);
  25596. var viewport = winUtils.getBox();
  25597. if(bb.w >= viewport.w || bb.h >= viewport.h){
  25598. // Reduce size of dialog contents so that dialog fits in viewport
  25599. var w = Math.min(bb.w, Math.floor(viewport.w * 0.75)),
  25600. h = Math.min(bb.h, Math.floor(viewport.h * 0.75));
  25601. if(this._singleChild && this._singleChild.resize){
  25602. this._singleChildOriginalStyle = this._singleChild.domNode.style.cssText;
  25603. this._singleChild.resize({w: w, h: h});
  25604. }else{
  25605. domStyle.set(this.containerNode, {
  25606. width: w + "px",
  25607. height: h + "px",
  25608. overflow: "auto",
  25609. position: "relative" // workaround IE bug moving scrollbar or dragging dialog
  25610. });
  25611. }
  25612. }else{
  25613. if(this._singleChild && this._singleChild.resize){
  25614. this._singleChild.resize();
  25615. }
  25616. }
  25617. },
  25618. _position: function(){
  25619. // summary:
  25620. // Position modal dialog in the viewport. If no relative offset
  25621. // in the viewport has been determined (by dragging, for instance),
  25622. // center the node. Otherwise, use the Dialog's stored relative offset,
  25623. // and position the node to top: left: values based on the viewport.
  25624. if(!domClass.contains(win.body(), "dojoMove")){ // don't do anything if called during auto-scroll
  25625. var node = this.domNode,
  25626. viewport = winUtils.getBox(),
  25627. p = this._relativePosition,
  25628. bb = p ? null : domGeometry.position(node),
  25629. l = Math.floor(viewport.l + (p ? p.x : (viewport.w - bb.w) / 2)),
  25630. t = Math.floor(viewport.t + (p ? p.y : (viewport.h - bb.h) / 2))
  25631. ;
  25632. domStyle.set(node,{
  25633. left: l + "px",
  25634. top: t + "px"
  25635. });
  25636. }
  25637. },
  25638. _onKey: function(/*Event*/ evt){
  25639. // summary:
  25640. // Handles the keyboard events for accessibility reasons
  25641. // tags:
  25642. // private
  25643. if(evt.charOrCode){
  25644. var node = evt.target;
  25645. if(evt.charOrCode === keys.TAB){
  25646. this._getFocusItems(this.domNode);
  25647. }
  25648. var singleFocusItem = (this._firstFocusItem == this._lastFocusItem);
  25649. // see if we are shift-tabbing from first focusable item on dialog
  25650. if(node == this._firstFocusItem && evt.shiftKey && evt.charOrCode === keys.TAB){
  25651. if(!singleFocusItem){
  25652. focus.focus(this._lastFocusItem); // send focus to last item in dialog
  25653. }
  25654. event.stop(evt);
  25655. }else if(node == this._lastFocusItem && evt.charOrCode === keys.TAB && !evt.shiftKey){
  25656. if(!singleFocusItem){
  25657. focus.focus(this._firstFocusItem); // send focus to first item in dialog
  25658. }
  25659. event.stop(evt);
  25660. }else{
  25661. // see if the key is for the dialog
  25662. while(node){
  25663. if(node == this.domNode || domClass.contains(node, "dijitPopup")){
  25664. if(evt.charOrCode == keys.ESCAPE){
  25665. this.onCancel();
  25666. }else{
  25667. return; // just let it go
  25668. }
  25669. }
  25670. node = node.parentNode;
  25671. }
  25672. // this key is for the disabled document window
  25673. if(evt.charOrCode !== keys.TAB){ // allow tabbing into the dialog for a11y
  25674. event.stop(evt);
  25675. // opera won't tab to a div
  25676. }else if(!has("opera")){
  25677. try{
  25678. this._firstFocusItem.focus();
  25679. }catch(e){ /*squelch*/ }
  25680. }
  25681. }
  25682. }
  25683. },
  25684. show: function(){
  25685. // summary:
  25686. // Display the dialog
  25687. // returns: dojo.Deferred
  25688. // Deferred object that resolves when the display animation is complete
  25689. if(this.open){ return; }
  25690. if(!this._started){
  25691. this.startup();
  25692. }
  25693. // first time we show the dialog, there's some initialization stuff to do
  25694. if(!this._alreadyInitialized){
  25695. this._setup();
  25696. this._alreadyInitialized=true;
  25697. }
  25698. if(this._fadeOutDeferred){
  25699. // There's a hide() operation in progress, so cancel it, but still call DialogLevelManager.hide()
  25700. // as though the hide() completed, in preparation for the DialogLevelManager.show() call below.
  25701. this._fadeOutDeferred.cancel();
  25702. DialogLevelManager.hide(this);
  25703. }
  25704. if(!has("touch")){
  25705. // If the user scrolls the display or resizes the viewport then reposition the Dialog. But don't do it
  25706. // for touch devices, because it will counteract when a keyboard pops up and then the browser
  25707. // auto-scrolls the focused node into view.
  25708. this._modalconnects.push(on(window, "scroll", lang.hitch(this, "layout")));
  25709. this._modalconnects.push(on(window, "resize", lang.hitch(this, function(){
  25710. // IE gives spurious resize events and can actually get stuck
  25711. // in an infinite loop if we don't ignore them
  25712. var viewport = winUtils.getBox();
  25713. if(!this._oldViewport ||
  25714. viewport.h != this._oldViewport.h ||
  25715. viewport.w != this._oldViewport.w){
  25716. this.layout();
  25717. this._oldViewport = viewport;
  25718. }
  25719. })));
  25720. }
  25721. this._modalconnects.push(on(this.domNode, connect._keypress, lang.hitch(this, "_onKey")));
  25722. domStyle.set(this.domNode, {
  25723. opacity:0,
  25724. display:""
  25725. });
  25726. this._set("open", true);
  25727. this._onShow(); // lazy load trigger
  25728. this._size();
  25729. this._position();
  25730. // fade-in Animation object, setup below
  25731. var fadeIn;
  25732. this._fadeInDeferred = new Deferred(lang.hitch(this, function(){
  25733. fadeIn.stop();
  25734. delete this._fadeInDeferred;
  25735. }));
  25736. fadeIn = fx.fadeIn({
  25737. node: this.domNode,
  25738. duration: this.duration,
  25739. beforeBegin: lang.hitch(this, function(){
  25740. DialogLevelManager.show(this, this.underlayAttrs);
  25741. }),
  25742. onEnd: lang.hitch(this, function(){
  25743. if(this.autofocus && DialogLevelManager.isTop(this)){
  25744. // find focusable items each time dialog is shown since if dialog contains a widget the
  25745. // first focusable items can change
  25746. this._getFocusItems(this.domNode);
  25747. focus.focus(this._firstFocusItem);
  25748. }
  25749. this._fadeInDeferred.callback(true);
  25750. delete this._fadeInDeferred;
  25751. })
  25752. }).play();
  25753. return this._fadeInDeferred;
  25754. },
  25755. hide: function(){
  25756. // summary:
  25757. // Hide the dialog
  25758. // returns: dojo.Deferred
  25759. // Deferred object that resolves when the hide animation is complete
  25760. // If we haven't been initialized yet then we aren't showing and we can just return.
  25761. // Likewise if we are already hidden, or are currently fading out.
  25762. if(!this._alreadyInitialized || !this.open){
  25763. return;
  25764. }
  25765. if(this._fadeInDeferred){
  25766. this._fadeInDeferred.cancel();
  25767. }
  25768. // fade-in Animation object, setup below
  25769. var fadeOut;
  25770. this._fadeOutDeferred = new Deferred(lang.hitch(this, function(){
  25771. fadeOut.stop();
  25772. delete this._fadeOutDeferred;
  25773. }));
  25774. // fire onHide when the promise resolves.
  25775. this._fadeOutDeferred.then(lang.hitch(this, 'onHide'));
  25776. fadeOut = fx.fadeOut({
  25777. node: this.domNode,
  25778. duration: this.duration,
  25779. onEnd: lang.hitch(this, function(){
  25780. this.domNode.style.display = "none";
  25781. DialogLevelManager.hide(this);
  25782. this._fadeOutDeferred.callback(true);
  25783. delete this._fadeOutDeferred;
  25784. })
  25785. }).play();
  25786. if(this._scrollConnected){
  25787. this._scrollConnected = false;
  25788. }
  25789. var h;
  25790. while(h = this._modalconnects.pop()){
  25791. h.remove();
  25792. }
  25793. if(this._relativePosition){
  25794. delete this._relativePosition;
  25795. }
  25796. this._set("open", false);
  25797. return this._fadeOutDeferred;
  25798. },
  25799. layout: function(){
  25800. // summary:
  25801. // Position the Dialog and the underlay
  25802. // tags:
  25803. // private
  25804. if(this.domNode.style.display != "none"){
  25805. if(dijit._underlay){ // avoid race condition during show()
  25806. dijit._underlay.layout();
  25807. }
  25808. this._position();
  25809. }
  25810. },
  25811. destroy: function(){
  25812. if(this._fadeInDeferred){
  25813. this._fadeInDeferred.cancel();
  25814. }
  25815. if(this._fadeOutDeferred){
  25816. this._fadeOutDeferred.cancel();
  25817. }
  25818. if(this._moveable){
  25819. this._moveable.destroy();
  25820. }
  25821. var h;
  25822. while(h = this._modalconnects.pop()){
  25823. h.remove();
  25824. }
  25825. DialogLevelManager.hide(this);
  25826. this.inherited(arguments);
  25827. }
  25828. });
  25829. var Dialog = declare("dijit.Dialog", [ContentPane, _DialogBase], {});
  25830. Dialog._DialogBase = _DialogBase; // for monkey patching
  25831. var DialogLevelManager = Dialog._DialogLevelManager = {
  25832. // summary:
  25833. // Controls the various active "levels" on the page, starting with the
  25834. // stuff initially visible on the page (at z-index 0), and then having an entry for
  25835. // each Dialog shown.
  25836. _beginZIndex: 950,
  25837. show: function(/*dijit._Widget*/ dialog, /*Object*/ underlayAttrs){
  25838. // summary:
  25839. // Call right before fade-in animation for new dialog.
  25840. // Saves current focus, displays/adjusts underlay for new dialog,
  25841. // and sets the z-index of the dialog itself.
  25842. //
  25843. // New dialog will be displayed on top of all currently displayed dialogs.
  25844. //
  25845. // Caller is responsible for setting focus in new dialog after the fade-in
  25846. // animation completes.
  25847. // Save current focus
  25848. ds[ds.length-1].focus = focus.curNode;
  25849. // Display the underlay, or if already displayed then adjust for this new dialog
  25850. var underlay = dijit._underlay;
  25851. if(!underlay || underlay._destroyed){
  25852. underlay = dijit._underlay = new DialogUnderlay(underlayAttrs);
  25853. }else{
  25854. underlay.set(dialog.underlayAttrs);
  25855. }
  25856. // Set z-index a bit above previous dialog
  25857. var zIndex = ds[ds.length-1].dialog ? ds[ds.length-1].zIndex + 2 : Dialog._DialogLevelManager._beginZIndex;
  25858. if(ds.length == 1){ // first dialog
  25859. underlay.show();
  25860. }
  25861. domStyle.set(dijit._underlay.domNode, 'zIndex', zIndex - 1);
  25862. // Dialog
  25863. domStyle.set(dialog.domNode, 'zIndex', zIndex);
  25864. ds.push({dialog: dialog, underlayAttrs: underlayAttrs, zIndex: zIndex});
  25865. },
  25866. hide: function(/*dijit._Widget*/ dialog){
  25867. // summary:
  25868. // Called when the specified dialog is hidden/destroyed, after the fade-out
  25869. // animation ends, in order to reset page focus, fix the underlay, etc.
  25870. // If the specified dialog isn't open then does nothing.
  25871. //
  25872. // Caller is responsible for either setting display:none on the dialog domNode,
  25873. // or calling dijit.popup.hide(), or removing it from the page DOM.
  25874. if(ds[ds.length-1].dialog == dialog){
  25875. // Removing the top (or only) dialog in the stack, return focus
  25876. // to previous dialog
  25877. ds.pop();
  25878. var pd = ds[ds.length-1]; // the new active dialog (or the base page itself)
  25879. // Adjust underlay
  25880. if(ds.length == 1){
  25881. // Returning to original page.
  25882. // Hide the underlay, unless the underlay widget has already been destroyed
  25883. // because we are being called during page unload (when all widgets are destroyed)
  25884. if(!dijit._underlay._destroyed){
  25885. dijit._underlay.hide();
  25886. }
  25887. }else{
  25888. // Popping back to previous dialog, adjust underlay
  25889. domStyle.set(dijit._underlay.domNode, 'zIndex', pd.zIndex - 1);
  25890. dijit._underlay.set(pd.underlayAttrs);
  25891. }
  25892. // Adjust focus
  25893. if(dialog.refocus){
  25894. // If we are returning control to a previous dialog but for some reason
  25895. // that dialog didn't have a focused field, set focus to first focusable item.
  25896. // This situation could happen if two dialogs appeared at nearly the same time,
  25897. // since a dialog doesn't set it's focus until the fade-in is finished.
  25898. var focus = pd.focus;
  25899. if(pd.dialog && (!focus || !dom.isDescendant(focus, pd.dialog.domNode))){
  25900. pd.dialog._getFocusItems(pd.dialog.domNode);
  25901. focus = pd.dialog._firstFocusItem;
  25902. }
  25903. if(focus){
  25904. // Refocus the button that spawned the Dialog. This will fail in corner cases including
  25905. // page unload on IE, because the dijit/form/Button that launched the Dialog may get destroyed
  25906. // before this code runs. (#15058)
  25907. try{
  25908. focus.focus();
  25909. }catch(e){}
  25910. }
  25911. }
  25912. }else{
  25913. // Removing a dialog out of order (#9944, #10705).
  25914. // Don't need to mess with underlay or z-index or anything.
  25915. var idx = array.indexOf(array.map(ds, function(elem){return elem.dialog}), dialog);
  25916. if(idx != -1){
  25917. ds.splice(idx, 1);
  25918. }
  25919. }
  25920. },
  25921. isTop: function(/*dijit._Widget*/ dialog){
  25922. // summary:
  25923. // Returns true if specified Dialog is the top in the task
  25924. return ds[ds.length-1].dialog == dialog;
  25925. }
  25926. };
  25927. // Stack representing the various active "levels" on the page, starting with the
  25928. // stuff initially visible on the page (at z-index 0), and then having an entry for
  25929. // each Dialog shown.
  25930. // Each element in stack has form {
  25931. // dialog: dialogWidget,
  25932. // focus: returnFromGetFocus(),
  25933. // underlayAttrs: attributes to set on underlay (when this widget is active)
  25934. // }
  25935. var ds = Dialog._dialogStack = [
  25936. {dialog: null, focus: null, underlayAttrs: null} // entry for stuff at z-index: 0
  25937. ];
  25938. // Back compat w/1.6, remove for 2.0
  25939. if(!kernel.isAsync){
  25940. ready(0, function(){
  25941. var requires = ["dijit/TooltipDialog"];
  25942. require(requires); // use indirection so modules not rolled into a build
  25943. });
  25944. }
  25945. return Dialog;
  25946. });
  25947. },
  25948. 'dijit/form/MultiSelect':function(){
  25949. define("dijit/form/MultiSelect", [
  25950. "dojo/_base/array", // array.indexOf, array.map
  25951. "dojo/_base/declare", // declare
  25952. "dojo/dom-geometry", // domGeometry.setMarginBox
  25953. "dojo/query", // query
  25954. "./_FormValueWidget"
  25955. ], function(array, declare, domGeometry, query, _FormValueWidget){
  25956. /*=====
  25957. var _FormValueWidget = dijit.form._FormValueWidget;
  25958. =====*/
  25959. // module:
  25960. // dijit/form/MultiSelect
  25961. // summary:
  25962. // Widget version of a <select multiple=true> element,
  25963. // for selecting multiple options.
  25964. return declare("dijit.form.MultiSelect", _FormValueWidget, {
  25965. // summary:
  25966. // Widget version of a <select multiple=true> element,
  25967. // for selecting multiple options.
  25968. // size: Number
  25969. // Number of elements to display on a page
  25970. // NOTE: may be removed in version 2.0, since elements may have variable height;
  25971. // set the size via style="..." or CSS class names instead.
  25972. size: 7,
  25973. templateString: "<select multiple='true' ${!nameAttrSetting} data-dojo-attach-point='containerNode,focusNode' data-dojo-attach-event='onchange: _onChange'></select>",
  25974. addSelected: function(/*dijit.form.MultiSelect*/ select){
  25975. // summary:
  25976. // Move the selected nodes of a passed Select widget
  25977. // instance to this Select widget.
  25978. //
  25979. // example:
  25980. // | // move all the selected values from "bar" to "foo"
  25981. // | dijit.byId("foo").addSelected(dijit.byId("bar"));
  25982. select.getSelected().forEach(function(n){
  25983. this.containerNode.appendChild(n);
  25984. // scroll to bottom to see item
  25985. // cannot use scrollIntoView since <option> tags don't support all attributes
  25986. // does not work on IE due to a bug where <select> always shows scrollTop = 0
  25987. this.domNode.scrollTop = this.domNode.offsetHeight; // overshoot will be ignored
  25988. // scrolling the source select is trickier esp. on safari who forgets to change the scrollbar size
  25989. var oldscroll = select.domNode.scrollTop;
  25990. select.domNode.scrollTop = 0;
  25991. select.domNode.scrollTop = oldscroll;
  25992. },this);
  25993. this._set('value', this.get('value'));
  25994. },
  25995. getSelected: function(){
  25996. // summary:
  25997. // Access the NodeList of the selected options directly
  25998. return query("option",this.containerNode).filter(function(n){
  25999. return n.selected; // Boolean
  26000. }); // dojo.NodeList
  26001. },
  26002. _getValueAttr: function(){
  26003. // summary:
  26004. // Hook so get('value') works.
  26005. // description:
  26006. // Returns an array of the selected options' values.
  26007. // Don't call getSelect.map() because it doesn't return a real array,
  26008. // and that messes up dojo.toJson() calls like in the Form.html test
  26009. return array.map(this.getSelected(), function(n){
  26010. return n.value;
  26011. });
  26012. },
  26013. multiple: true, // for Form
  26014. _setValueAttr: function(/*Array*/ values, /*Boolean?*/ priorityChange){
  26015. // summary:
  26016. // Hook so set('value', values) works.
  26017. // description:
  26018. // Set the value(s) of this Select based on passed values
  26019. query("option",this.containerNode).forEach(function(n){
  26020. n.selected = (array.indexOf(values,n.value) != -1);
  26021. });
  26022. this.inherited(arguments);
  26023. },
  26024. invertSelection: function(/*Boolean?*/ onChange){
  26025. // summary:
  26026. // Invert the selection
  26027. // onChange: Boolean
  26028. // If false, onChange is not fired.
  26029. var val = [];
  26030. query("option",this.containerNode).forEach(function(n){
  26031. if(!n.selected){ val.push(n.value); }
  26032. });
  26033. this._setValueAttr(val, !(onChange === false || onChange == null));
  26034. },
  26035. _onChange: function(/*Event*/){
  26036. this._handleOnChange(this.get('value'), true);
  26037. },
  26038. // for layout widgets:
  26039. resize: function(/*Object*/ size){
  26040. if(size){
  26041. domGeometry.setMarginBox(this.domNode, size);
  26042. }
  26043. },
  26044. postCreate: function(){
  26045. this._set('value', this.get('value'));
  26046. this.inherited(arguments);
  26047. }
  26048. });
  26049. });
  26050. },
  26051. 'dijit/form/_DateTimeTextBox':function(){
  26052. define([
  26053. "dojo/date", // date date.compare
  26054. "dojo/date/locale", // locale.regexp
  26055. "dojo/date/stamp", // stamp.fromISOString stamp.toISOString
  26056. "dojo/_base/declare", // declare
  26057. "dojo/_base/lang", // lang.getObject
  26058. "./RangeBoundTextBox",
  26059. "../_HasDropDown",
  26060. "dojo/text!./templates/DropDownBox.html"
  26061. ], function(date, locale, stamp, declare, lang, RangeBoundTextBox, _HasDropDown, template){
  26062. /*=====
  26063. var _HasDropDown = dijit._HasDropDown;
  26064. var RangeBoundTextBox = dijit.form.RangeBoundTextBox;
  26065. =====*/
  26066. // module:
  26067. // dijit/form/_DateTimeTextBox
  26068. // summary:
  26069. // Base class for validating, serializable, range-bound date or time text box.
  26070. new Date("X"); // workaround for #11279, new Date("") == NaN
  26071. /*=====
  26072. declare(
  26073. "dijit.form._DateTimeTextBox.__Constraints",
  26074. [RangeBoundTextBox.__Constraints, locale.__FormatOptions], {
  26075. // summary:
  26076. // Specifies both the rules on valid/invalid values (first/last date/time allowed),
  26077. // and also formatting options for how the date/time is displayed.
  26078. // example:
  26079. // To restrict to dates within 2004, displayed in a long format like "December 25, 2005":
  26080. // | {min:'2004-01-01',max:'2004-12-31', formatLength:'long'}
  26081. });
  26082. =====*/
  26083. var _DateTimeTextBox = declare("dijit.form._DateTimeTextBox", [RangeBoundTextBox, _HasDropDown], {
  26084. // summary:
  26085. // Base class for validating, serializable, range-bound date or time text box.
  26086. templateString: template,
  26087. // hasDownArrow: [const] Boolean
  26088. // Set this textbox to display a down arrow button, to open the drop down list.
  26089. hasDownArrow: true,
  26090. // openOnClick: [const] Boolean
  26091. // Set to true to open drop down upon clicking anywhere on the textbox.
  26092. openOnClick: true,
  26093. /*=====
  26094. // constraints: dijit.form._DateTimeTextBox.__Constraints
  26095. // Despite the name, this parameter specifies both constraints on the input
  26096. // (including starting/ending dates/times allowed) as well as
  26097. // formatting options like whether the date is displayed in long (ex: December 25, 2005)
  26098. // or short (ex: 12/25/2005) format. See `dijit.form._DateTimeTextBox.__Constraints` for details.
  26099. constraints: {},
  26100. ======*/
  26101. // Override ValidationTextBox.regExpGen().... we use a reg-ex generating function rather
  26102. // than a straight regexp to deal with locale (plus formatting options too?)
  26103. regExpGen: locale.regexp,
  26104. // datePackage: String
  26105. // JavaScript namespace to find calendar routines. Uses Gregorian calendar routines
  26106. // at dojo.date, by default.
  26107. datePackage: date,
  26108. postMixInProperties: function(){
  26109. this.inherited(arguments);
  26110. this._set("type", "text"); // in case type="date"|"time" was specified which messes up parse/format
  26111. },
  26112. // Override _FormWidget.compare() to work for dates/times
  26113. compare: function(/*Date*/ val1, /*Date*/ val2){
  26114. var isInvalid1 = this._isInvalidDate(val1);
  26115. var isInvalid2 = this._isInvalidDate(val2);
  26116. return isInvalid1 ? (isInvalid2 ? 0 : -1) : (isInvalid2 ? 1 : date.compare(val1, val2, this._selector));
  26117. },
  26118. // flag to _HasDropDown to make drop down Calendar width == <input> width
  26119. forceWidth: true,
  26120. format: function(/*Date*/ value, /*dojo.date.locale.__FormatOptions*/ constraints){
  26121. // summary:
  26122. // Formats the value as a Date, according to specified locale (second argument)
  26123. // tags:
  26124. // protected
  26125. if(!value){ return ''; }
  26126. return this.dateLocaleModule.format(value, constraints);
  26127. },
  26128. "parse": function(/*String*/ value, /*dojo.date.locale.__FormatOptions*/ constraints){
  26129. // summary:
  26130. // Parses as string as a Date, according to constraints
  26131. // tags:
  26132. // protected
  26133. return this.dateLocaleModule.parse(value, constraints) || (this._isEmpty(value) ? null : undefined); // Date
  26134. },
  26135. // Overrides ValidationTextBox.serialize() to serialize a date in canonical ISO format.
  26136. serialize: function(/*anything*/ val, /*Object?*/ options){
  26137. if(val.toGregorian){
  26138. val = val.toGregorian();
  26139. }
  26140. return stamp.toISOString(val, options);
  26141. },
  26142. // dropDownDefaultValue: Date
  26143. // The default value to focus in the popupClass widget when the textbox value is empty.
  26144. dropDownDefaultValue : new Date(),
  26145. // value: Date
  26146. // The value of this widget as a JavaScript Date object. Use get("value") / set("value", val) to manipulate.
  26147. // When passed to the parser in markup, must be specified according to `dojo.date.stamp.fromISOString`
  26148. value: new Date(""), // value.toString()="NaN"
  26149. _blankValue: null, // used by filter() when the textbox is blank
  26150. // popupClass: [protected extension] String
  26151. // Name of the popup widget class used to select a date/time.
  26152. // Subclasses should specify this.
  26153. popupClass: "", // default is no popup = text only
  26154. // _selector: [protected extension] String
  26155. // Specifies constraints.selector passed to dojo.date functions, should be either
  26156. // "date" or "time".
  26157. // Subclass must specify this.
  26158. _selector: "",
  26159. constructor: function(/*Object*/ args){
  26160. this.datePackage = args.datePackage || this.datePackage;
  26161. this.dateFuncObj = typeof this.datePackage == "string" ?
  26162. lang.getObject(this.datePackage, false) :// "string" part for back-compat, remove for 2.0
  26163. this.datePackage;
  26164. this.dateClassObj = this.dateFuncObj.Date || Date;
  26165. this.dateLocaleModule = lang.getObject("locale", false, this.dateFuncObj);
  26166. this.regExpGen = this.dateLocaleModule.regexp;
  26167. this._invalidDate = this.constructor.prototype.value.toString();
  26168. },
  26169. buildRendering: function(){
  26170. this.inherited(arguments);
  26171. if(!this.hasDownArrow){
  26172. this._buttonNode.style.display = "none";
  26173. }
  26174. // If openOnClick is true, we basically just want to treat the whole widget as the
  26175. // button. We need to do that also if the actual drop down button will be hidden,
  26176. // so that there's a mouse method for opening the drop down.
  26177. if(this.openOnClick || !this.hasDownArrow){
  26178. this._buttonNode = this.domNode;
  26179. this.baseClass += " dijitComboBoxOpenOnClick";
  26180. }
  26181. },
  26182. _setConstraintsAttr: function(/*Object*/ constraints){
  26183. constraints.selector = this._selector;
  26184. constraints.fullYear = true; // see #5465 - always format with 4-digit years
  26185. var fromISO = stamp.fromISOString;
  26186. if(typeof constraints.min == "string"){ constraints.min = fromISO(constraints.min); }
  26187. if(typeof constraints.max == "string"){ constraints.max = fromISO(constraints.max); }
  26188. this.inherited(arguments);
  26189. },
  26190. _isInvalidDate: function(/*Date*/ value){
  26191. // summary:
  26192. // Runs various tests on the value, checking for invalid conditions
  26193. // tags:
  26194. // private
  26195. return !value || isNaN(value) || typeof value != "object" || value.toString() == this._invalidDate;
  26196. },
  26197. _setValueAttr: function(/*Date|String*/ value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
  26198. // summary:
  26199. // Sets the date on this textbox. Note: value can be a JavaScript Date literal or a string to be parsed.
  26200. if(value !== undefined){
  26201. if(typeof value == "string"){
  26202. value = stamp.fromISOString(value);
  26203. }
  26204. if(this._isInvalidDate(value)){
  26205. value = null;
  26206. }
  26207. if(value instanceof Date && !(this.dateClassObj instanceof Date)){
  26208. value = new this.dateClassObj(value);
  26209. }
  26210. }
  26211. this.inherited(arguments);
  26212. if(this.value instanceof Date){
  26213. this.filterString = "";
  26214. }
  26215. if(this.dropDown){
  26216. this.dropDown.set('value', value, false);
  26217. }
  26218. },
  26219. _set: function(attr, value){
  26220. // Avoid spurious watch() notifications when value is changed to new Date object w/the same value
  26221. if(attr == "value" && this.value instanceof Date && this.compare(value, this.value) == 0){
  26222. return;
  26223. }
  26224. this.inherited(arguments);
  26225. },
  26226. _setDropDownDefaultValueAttr: function(/*Date*/ val){
  26227. if(this._isInvalidDate(val)){
  26228. // convert null setting into today's date, since there needs to be *some* default at all times.
  26229. val = new this.dateClassObj();
  26230. }
  26231. this.dropDownDefaultValue = val;
  26232. },
  26233. openDropDown: function(/*Function*/ callback){
  26234. // rebuild drop down every time, so that constraints get copied (#6002)
  26235. if(this.dropDown){
  26236. this.dropDown.destroy();
  26237. }
  26238. var PopupProto = lang.isString(this.popupClass) ? lang.getObject(this.popupClass, false) : this.popupClass,
  26239. textBox = this,
  26240. value = this.get("value");
  26241. this.dropDown = new PopupProto({
  26242. onChange: function(value){
  26243. // this will cause InlineEditBox and other handlers to do stuff so make sure it's last
  26244. textBox.set('value', value, true);
  26245. },
  26246. id: this.id + "_popup",
  26247. dir: textBox.dir,
  26248. lang: textBox.lang,
  26249. value: value,
  26250. currentFocus: !this._isInvalidDate(value) ? value : this.dropDownDefaultValue,
  26251. constraints: textBox.constraints,
  26252. filterString: textBox.filterString, // for TimeTextBox, to filter times shown
  26253. datePackage: textBox.datePackage,
  26254. isDisabledDate: function(/*Date*/ date){
  26255. // summary:
  26256. // disables dates outside of the min/max of the _DateTimeTextBox
  26257. return !textBox.rangeCheck(date, textBox.constraints);
  26258. }
  26259. });
  26260. this.inherited(arguments);
  26261. },
  26262. _getDisplayedValueAttr: function(){
  26263. return this.textbox.value;
  26264. },
  26265. _setDisplayedValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange){
  26266. this._setValueAttr(this.parse(value, this.constraints), priorityChange, value);
  26267. }
  26268. });
  26269. return _DateTimeTextBox;
  26270. });
  26271. },
  26272. 'dijit/form/_ToggleButtonMixin':function(){
  26273. define([
  26274. "dojo/_base/declare", // declare
  26275. "dojo/dom-attr" // domAttr.set
  26276. ], function(declare, domAttr){
  26277. // module:
  26278. // dijit/form/_ToggleButtonMixin
  26279. // summary:
  26280. // A mixin to provide functionality to allow a button that can be in two states (checked or not).
  26281. return declare("dijit.form._ToggleButtonMixin", null, {
  26282. // summary:
  26283. // A mixin to provide functionality to allow a button that can be in two states (checked or not).
  26284. // checked: Boolean
  26285. // Corresponds to the native HTML <input> element's attribute.
  26286. // In markup, specified as "checked='checked'" or just "checked".
  26287. // True if the button is depressed, or the checkbox is checked,
  26288. // or the radio button is selected, etc.
  26289. checked: false,
  26290. // aria-pressed for toggle buttons, and aria-checked for checkboxes
  26291. _aria_attr: "aria-pressed",
  26292. _onClick: function(/*Event*/ evt){
  26293. var original = this.checked;
  26294. this._set('checked', !original); // partially set the toggled value, assuming the toggle will work, so it can be overridden in the onclick handler
  26295. var ret = this.inherited(arguments); // the user could reset the value here
  26296. this.set('checked', ret ? this.checked : original); // officially set the toggled or user value, or reset it back
  26297. return ret;
  26298. },
  26299. _setCheckedAttr: function(/*Boolean*/ value, /*Boolean?*/ priorityChange){
  26300. this._set("checked", value);
  26301. domAttr.set(this.focusNode || this.domNode, "checked", value);
  26302. (this.focusNode || this.domNode).setAttribute(this._aria_attr, value ? "true" : "false"); // aria values should be strings
  26303. this._handleOnChange(value, priorityChange);
  26304. },
  26305. reset: function(){
  26306. // summary:
  26307. // Reset the widget's value to what it was at initialization time
  26308. this._hasBeenBlurred = false;
  26309. // set checked state to original setting
  26310. this.set('checked', this.params.checked || false);
  26311. }
  26312. });
  26313. });
  26314. },
  26315. 'dijit/Calendar':function(){
  26316. define([
  26317. "dojo/_base/array", // array.map
  26318. "dojo/date",
  26319. "dojo/date/locale",
  26320. "dojo/_base/declare", // declare
  26321. "dojo/dom-attr", // domAttr.get
  26322. "dojo/dom-class", // domClass.add domClass.contains domClass.remove domClass.toggle
  26323. "dojo/_base/event", // event.stop
  26324. "dojo/_base/kernel", // kernel.deprecated
  26325. "dojo/keys", // keys
  26326. "dojo/_base/lang", // lang.hitch
  26327. "dojo/_base/sniff", // has("ie")
  26328. "./CalendarLite",
  26329. "./_Widget",
  26330. "./_CssStateMixin",
  26331. "./_TemplatedMixin",
  26332. "./form/DropDownButton",
  26333. "./hccss" // not used directly, but sets CSS class on <body>
  26334. ], function(array, date, local, declare, domAttr, domClass, event, kernel, keys, lang, has,
  26335. CalendarLite, _Widget, _CssStateMixin, _TemplatedMixin, DropDownButton){
  26336. /*=====
  26337. var CalendarLite = dijit.CalendarLite;
  26338. var _CssStateMixin = dijit._CssStateMixin;
  26339. var _Widget = dijit._Widget;
  26340. var _TemplatedMixin = dijit._TemplatedMixin;
  26341. var DropDownButton = dijit.form.DropDownButton;
  26342. =====*/
  26343. // module:
  26344. // dijit/Calendar
  26345. // summary:
  26346. // A simple GUI for choosing a date in the context of a monthly calendar.
  26347. var Calendar = declare("dijit.Calendar",
  26348. [CalendarLite, _Widget, _CssStateMixin], // _Widget for deprecated methods like setAttribute()
  26349. {
  26350. // summary:
  26351. // A simple GUI for choosing a date in the context of a monthly calendar.
  26352. //
  26353. // description:
  26354. // See CalendarLite for general description. Calendar extends CalendarLite, adding:
  26355. // - month drop down list
  26356. // - keyboard navigation
  26357. // - CSS classes for hover/mousepress on date, month, and year nodes
  26358. // - support of deprecated methods (will be removed in 2.0)
  26359. // Set node classes for various mouse events, see dijit._CssStateMixin for more details
  26360. cssStateNodes: {
  26361. "decrementMonth": "dijitCalendarArrow",
  26362. "incrementMonth": "dijitCalendarArrow",
  26363. "previousYearLabelNode": "dijitCalendarPreviousYear",
  26364. "nextYearLabelNode": "dijitCalendarNextYear"
  26365. },
  26366. setValue: function(/*Date*/ value){
  26367. // summary:
  26368. // Deprecated. Use set('value', ...) instead.
  26369. // tags:
  26370. // deprecated
  26371. kernel.deprecated("dijit.Calendar:setValue() is deprecated. Use set('value', ...) instead.", "", "2.0");
  26372. this.set('value', value);
  26373. },
  26374. _createMonthWidget: function(){
  26375. // summary:
  26376. // Creates the drop down button that displays the current month and lets user pick a new one
  26377. return new Calendar._MonthDropDownButton({
  26378. id: this.id + "_mddb",
  26379. tabIndex: -1,
  26380. onMonthSelect: lang.hitch(this, "_onMonthSelect"),
  26381. lang: this.lang,
  26382. dateLocaleModule: this.dateLocaleModule
  26383. }, this.monthNode);
  26384. },
  26385. buildRendering: function(){
  26386. this.inherited(arguments);
  26387. // Events specific to Calendar, not used in CalendarLite
  26388. this.connect(this.domNode, "onkeydown", "_onKeyDown");
  26389. this.connect(this.dateRowsNode, "onmouseover", "_onDayMouseOver");
  26390. this.connect(this.dateRowsNode, "onmouseout", "_onDayMouseOut");
  26391. this.connect(this.dateRowsNode, "onmousedown", "_onDayMouseDown");
  26392. this.connect(this.dateRowsNode, "onmouseup", "_onDayMouseUp");
  26393. },
  26394. _onMonthSelect: function(/*Number*/ newMonth){
  26395. // summary:
  26396. // Handler for when user selects a month from the drop down list
  26397. // tags:
  26398. // protected
  26399. // move to selected month, bounding by the number of days in the month
  26400. // (ex: dec 31 --> jan 28, not jan 31)
  26401. this._setCurrentFocusAttr(this.dateFuncObj.add(this.currentFocus, "month",
  26402. newMonth - this.currentFocus.getMonth()));
  26403. },
  26404. _onDayMouseOver: function(/*Event*/ evt){
  26405. // summary:
  26406. // Handler for mouse over events on days, sets hovered style
  26407. // tags:
  26408. // protected
  26409. // event can occur on <td> or the <span> inside the td,
  26410. // set node to the <td>.
  26411. var node =
  26412. domClass.contains(evt.target, "dijitCalendarDateLabel") ?
  26413. evt.target.parentNode :
  26414. evt.target;
  26415. if(node && (
  26416. (node.dijitDateValue && !domClass.contains(node, "dijitCalendarDisabledDate"))
  26417. || node == this.previousYearLabelNode || node == this.nextYearLabelNode
  26418. )){
  26419. domClass.add(node, "dijitCalendarHoveredDate");
  26420. this._currentNode = node;
  26421. }
  26422. },
  26423. _onDayMouseOut: function(/*Event*/ evt){
  26424. // summary:
  26425. // Handler for mouse out events on days, clears hovered style
  26426. // tags:
  26427. // protected
  26428. if(!this._currentNode){ return; }
  26429. // if mouse out occurs moving from <td> to <span> inside <td>, ignore it
  26430. if(evt.relatedTarget && evt.relatedTarget.parentNode == this._currentNode){ return; }
  26431. var cls = "dijitCalendarHoveredDate";
  26432. if(domClass.contains(this._currentNode, "dijitCalendarActiveDate")){
  26433. cls += " dijitCalendarActiveDate";
  26434. }
  26435. domClass.remove(this._currentNode, cls);
  26436. this._currentNode = null;
  26437. },
  26438. _onDayMouseDown: function(/*Event*/ evt){
  26439. var node = evt.target.parentNode;
  26440. if(node && node.dijitDateValue && !domClass.contains(node, "dijitCalendarDisabledDate")){
  26441. domClass.add(node, "dijitCalendarActiveDate");
  26442. this._currentNode = node;
  26443. }
  26444. },
  26445. _onDayMouseUp: function(/*Event*/ evt){
  26446. var node = evt.target.parentNode;
  26447. if(node && node.dijitDateValue){
  26448. domClass.remove(node, "dijitCalendarActiveDate");
  26449. }
  26450. },
  26451. handleKey: function(/*Event*/ evt){
  26452. // summary:
  26453. // Provides keyboard navigation of calendar.
  26454. // description:
  26455. // Called from _onKeyDown() to handle keypress on a stand alone Calendar,
  26456. // and also from `dijit.form._DateTimeTextBox` to pass a keydown event
  26457. // from the `dijit.form.DateTextBox` to be handled in this widget
  26458. // returns:
  26459. // False if the key was recognized as a navigation key,
  26460. // to indicate that the event was handled by Calendar and shouldn't be propagated
  26461. // tags:
  26462. // protected
  26463. var increment = -1,
  26464. interval,
  26465. newValue = this.currentFocus;
  26466. switch(evt.keyCode){
  26467. case keys.RIGHT_ARROW:
  26468. increment = 1;
  26469. //fallthrough...
  26470. case keys.LEFT_ARROW:
  26471. interval = "day";
  26472. if(!this.isLeftToRight()){ increment *= -1; }
  26473. break;
  26474. case keys.DOWN_ARROW:
  26475. increment = 1;
  26476. //fallthrough...
  26477. case keys.UP_ARROW:
  26478. interval = "week";
  26479. break;
  26480. case keys.PAGE_DOWN:
  26481. increment = 1;
  26482. //fallthrough...
  26483. case keys.PAGE_UP:
  26484. interval = evt.ctrlKey || evt.altKey ? "year" : "month";
  26485. break;
  26486. case keys.END:
  26487. // go to the next month
  26488. newValue = this.dateFuncObj.add(newValue, "month", 1);
  26489. // subtract a day from the result when we're done
  26490. interval = "day";
  26491. //fallthrough...
  26492. case keys.HOME:
  26493. newValue = new this.dateClassObj(newValue);
  26494. newValue.setDate(1);
  26495. break;
  26496. case keys.ENTER:
  26497. case keys.SPACE:
  26498. this.set("value", this.currentFocus);
  26499. break;
  26500. default:
  26501. return true;
  26502. }
  26503. if(interval){
  26504. newValue = this.dateFuncObj.add(newValue, interval, increment);
  26505. }
  26506. this._setCurrentFocusAttr(newValue);
  26507. return false;
  26508. },
  26509. _onKeyDown: function(/*Event*/ evt){
  26510. // summary:
  26511. // For handling keypress events on a stand alone calendar
  26512. if(!this.handleKey(evt)){
  26513. event.stop(evt);
  26514. }
  26515. },
  26516. onValueSelected: function(/*Date*/ /*===== date =====*/){
  26517. // summary:
  26518. // Deprecated. Notification that a date cell was selected. It may be the same as the previous value.
  26519. // description:
  26520. // Formerly used by `dijit.form._DateTimeTextBox` (and thus `dijit.form.DateTextBox`)
  26521. // to get notification when the user has clicked a date. Now onExecute() (above) is used.
  26522. // tags:
  26523. // protected
  26524. },
  26525. onChange: function(value){
  26526. this.onValueSelected(value); // remove in 2.0
  26527. },
  26528. getClassForDate: function(/*===== dateObject, locale =====*/){
  26529. // summary:
  26530. // May be overridden to return CSS classes to associate with the date entry for the given dateObject,
  26531. // for example to indicate a holiday in specified locale.
  26532. // dateObject: Date
  26533. // locale: String?
  26534. // tags:
  26535. // extension
  26536. /*=====
  26537. return ""; // String
  26538. =====*/
  26539. }
  26540. });
  26541. Calendar._MonthDropDownButton = declare("dijit.Calendar._MonthDropDownButton", DropDownButton, {
  26542. // summary:
  26543. // DropDownButton for the current month. Displays name of current month
  26544. // and a list of month names in the drop down
  26545. onMonthSelect: function(){ },
  26546. postCreate: function(){
  26547. this.inherited(arguments);
  26548. this.dropDown = new Calendar._MonthDropDown({
  26549. id: this.id + "_mdd", //do not change this id because it is referenced in the template
  26550. onChange: this.onMonthSelect
  26551. });
  26552. },
  26553. _setMonthAttr: function(month){
  26554. // summary:
  26555. // Set the current month to display as a label
  26556. var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, month);
  26557. this.dropDown.set("months", monthNames);
  26558. // Set name of current month and also fill in spacer element with all the month names
  26559. // (invisible) so that the maximum width will affect layout. But not on IE6 because then
  26560. // the center <TH> overlaps the right <TH> (due to a browser bug).
  26561. this.containerNode.innerHTML =
  26562. (has("ie") == 6 ? "" : "<div class='dijitSpacer'>" + this.dropDown.domNode.innerHTML + "</div>") +
  26563. "<div class='dijitCalendarMonthLabel dijitCalendarCurrentMonthLabel'>" + monthNames[month.getMonth()] + "</div>";
  26564. }
  26565. });
  26566. Calendar._MonthDropDown = declare("dijit.Calendar._MonthDropDown", [_Widget, _TemplatedMixin], {
  26567. // summary:
  26568. // The list-of-months drop down from the MonthDropDownButton
  26569. // months: String[]
  26570. // List of names of months, possibly w/some undefined entries for Hebrew leap months
  26571. // (ex: ["January", "February", undefined, "April", ...])
  26572. months: [],
  26573. templateString: "<div class='dijitCalendarMonthMenu dijitMenu' " +
  26574. "data-dojo-attach-event='onclick:_onClick,onmouseover:_onMenuHover,onmouseout:_onMenuHover'></div>",
  26575. _setMonthsAttr: function(/*String[]*/ months){
  26576. this.domNode.innerHTML = array.map(months, function(month, idx){
  26577. return month ? "<div class='dijitCalendarMonthLabel' month='" + idx +"'>" + month + "</div>" : "";
  26578. }).join("");
  26579. },
  26580. _onClick: function(/*Event*/ evt){
  26581. this.onChange(domAttr.get(evt.target, "month"));
  26582. },
  26583. onChange: function(/*Number*/ /*===== month =====*/){
  26584. // summary:
  26585. // Callback when month is selected from drop down
  26586. },
  26587. _onMenuHover: function(evt){
  26588. domClass.toggle(evt.target, "dijitCalendarMonthLabelHover", evt.type == "mouseover");
  26589. }
  26590. });
  26591. return Calendar;
  26592. });
  26593. },
  26594. 'url:dijit/form/templates/Select.html':"<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tdata-dojo-attach-point=\"_buttonNode,tableNode,focusNode\" cellspacing='0' cellpadding='0'\n\trole=\"combobox\" aria-haspopup=\"true\"\n\t><tbody role=\"presentation\"><tr role=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonContents dijitButtonNode\" role=\"presentation\"\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\" data-dojo-attach-point=\"containerNode,_popupStateNode\"></span\n\t\t\t><input type=\"hidden\" ${!nameAttrSetting} data-dojo-attach-point=\"valueNode\" value=\"${value}\" aria-hidden=\"true\"\n\t\t/></td><td class=\"dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton\"\n\t\t\t\tdata-dojo-attach-point=\"titleNode\" role=\"presentation\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" role=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" role=\"presentation\">&#9660;</div\n\t\t></td\n\t></tr></tbody\n></table>\n",
  26595. 'dijit/_editor/selection':function(){
  26596. define([
  26597. "dojo/dom", // dom.byId
  26598. "dojo/_base/lang",
  26599. "dojo/_base/sniff", // has("ie") has("opera")
  26600. "dojo/_base/window", // win.body win.doc win.doc.createElement win.doc.selection win.doc.selection.createRange win.doc.selection.type.toLowerCase win.global win.global.getSelection
  26601. ".." // for exporting symbols to dijit._editor.selection (TODO: remove in 2.0)
  26602. ], function(dom, lang, has, win, dijit){
  26603. // module:
  26604. // dijit/_editor/selection
  26605. // summary:
  26606. // Text selection API
  26607. lang.getObject("_editor.selection", true, dijit);
  26608. // FIXME:
  26609. // all of these methods branch internally for IE. This is probably
  26610. // sub-optimal in terms of runtime performance. We should investigate the
  26611. // size difference for differentiating at definition time.
  26612. lang.mixin(dijit._editor.selection, {
  26613. getType: function(){
  26614. // summary:
  26615. // Get the selection type (like win.doc.select.type in IE).
  26616. if(!win.doc.getSelection){
  26617. // IE6-8
  26618. return win.doc.selection.type.toLowerCase();
  26619. }else{
  26620. // W3C
  26621. var stype = "text";
  26622. // Check if the actual selection is a CONTROL (IMG, TABLE, HR, etc...).
  26623. var oSel;
  26624. try{
  26625. oSel = win.global.getSelection();
  26626. }catch(e){ /*squelch*/ }
  26627. if(oSel && oSel.rangeCount == 1){
  26628. var oRange = oSel.getRangeAt(0);
  26629. if( (oRange.startContainer == oRange.endContainer) &&
  26630. ((oRange.endOffset - oRange.startOffset) == 1) &&
  26631. (oRange.startContainer.nodeType != 3 /* text node*/)
  26632. ){
  26633. stype = "control";
  26634. }
  26635. }
  26636. return stype; //String
  26637. }
  26638. },
  26639. getSelectedText: function(){
  26640. // summary:
  26641. // Return the text (no html tags) included in the current selection or null if no text is selected
  26642. if(!win.doc.getSelection){
  26643. // IE6-8
  26644. if(dijit._editor.selection.getType() == 'control'){
  26645. return null;
  26646. }
  26647. return win.doc.selection.createRange().text;
  26648. }else{
  26649. // W3C
  26650. var selection = win.global.getSelection();
  26651. if(selection){
  26652. return selection.toString(); //String
  26653. }
  26654. }
  26655. return '';
  26656. },
  26657. getSelectedHtml: function(){
  26658. // summary:
  26659. // Return the html text of the current selection or null if unavailable
  26660. if(!win.doc.getSelection){
  26661. // IE6-8
  26662. if(dijit._editor.selection.getType() == 'control'){
  26663. return null;
  26664. }
  26665. return win.doc.selection.createRange().htmlText;
  26666. }else{
  26667. // W3C
  26668. var selection = win.global.getSelection();
  26669. if(selection && selection.rangeCount){
  26670. var i;
  26671. var html = "";
  26672. for(i = 0; i < selection.rangeCount; i++){
  26673. //Handle selections spanning ranges, such as Opera
  26674. var frag = selection.getRangeAt(i).cloneContents();
  26675. var div = win.doc.createElement("div");
  26676. div.appendChild(frag);
  26677. html += div.innerHTML;
  26678. }
  26679. return html; //String
  26680. }
  26681. return null;
  26682. }
  26683. },
  26684. getSelectedElement: function(){
  26685. // summary:
  26686. // Retrieves the selected element (if any), just in the case that
  26687. // a single element (object like and image or a table) is
  26688. // selected.
  26689. if(dijit._editor.selection.getType() == "control"){
  26690. if(!win.doc.getSelection){
  26691. // IE6-8
  26692. var range = win.doc.selection.createRange();
  26693. if(range && range.item){
  26694. return win.doc.selection.createRange().item(0);
  26695. }
  26696. }else{
  26697. // W3C
  26698. var selection = win.global.getSelection();
  26699. return selection.anchorNode.childNodes[ selection.anchorOffset ];
  26700. }
  26701. }
  26702. return null;
  26703. },
  26704. getParentElement: function(){
  26705. // summary:
  26706. // Get the parent element of the current selection
  26707. if(dijit._editor.selection.getType() == "control"){
  26708. var p = this.getSelectedElement();
  26709. if(p){ return p.parentNode; }
  26710. }else{
  26711. if(!win.doc.getSelection){
  26712. // IE6-8
  26713. var r = win.doc.selection.createRange();
  26714. r.collapse(true);
  26715. return r.parentElement();
  26716. }else{
  26717. // W3C
  26718. var selection = win.global.getSelection();
  26719. if(selection){
  26720. var node = selection.anchorNode;
  26721. while(node && (node.nodeType != 1)){ // not an element
  26722. node = node.parentNode;
  26723. }
  26724. return node;
  26725. }
  26726. }
  26727. }
  26728. return null;
  26729. },
  26730. hasAncestorElement: function(/*String*/tagName /* ... */){
  26731. // summary:
  26732. // Check whether current selection has a parent element which is
  26733. // of type tagName (or one of the other specified tagName)
  26734. // tagName: String
  26735. // The tag name to determine if it has an ancestor of.
  26736. return this.getAncestorElement.apply(this, arguments) != null; //Boolean
  26737. },
  26738. getAncestorElement: function(/*String*/tagName /* ... */){
  26739. // summary:
  26740. // Return the parent element of the current selection which is of
  26741. // type tagName (or one of the other specified tagName)
  26742. // tagName: String
  26743. // The tag name to determine if it has an ancestor of.
  26744. var node = this.getSelectedElement() || this.getParentElement();
  26745. return this.getParentOfType(node, arguments); //DOMNode
  26746. },
  26747. isTag: function(/*DomNode*/ node, /*String[]*/ tags){
  26748. // summary:
  26749. // Function to determine if a node is one of an array of tags.
  26750. // node:
  26751. // The node to inspect.
  26752. // tags:
  26753. // An array of tag name strings to check to see if the node matches.
  26754. if(node && node.tagName){
  26755. var _nlc = node.tagName.toLowerCase();
  26756. for(var i=0; i<tags.length; i++){
  26757. var _tlc = String(tags[i]).toLowerCase();
  26758. if(_nlc == _tlc){
  26759. return _tlc; // String
  26760. }
  26761. }
  26762. }
  26763. return "";
  26764. },
  26765. getParentOfType: function(/*DomNode*/ node, /*String[]*/ tags){
  26766. // summary:
  26767. // Function to locate a parent node that matches one of a set of tags
  26768. // node:
  26769. // The node to inspect.
  26770. // tags:
  26771. // An array of tag name strings to check to see if the node matches.
  26772. while(node){
  26773. if(this.isTag(node, tags).length){
  26774. return node; // DOMNode
  26775. }
  26776. node = node.parentNode;
  26777. }
  26778. return null;
  26779. },
  26780. collapse: function(/*Boolean*/beginning){
  26781. // summary:
  26782. // Function to collapse (clear), the current selection
  26783. // beginning: Boolean
  26784. // Boolean to indicate whether to collapse the cursor to the beginning of the selection or end.
  26785. if(window.getSelection){
  26786. var selection = win.global.getSelection();
  26787. if(selection.removeAllRanges){ // Mozilla
  26788. if(beginning){
  26789. selection.collapseToStart();
  26790. }else{
  26791. selection.collapseToEnd();
  26792. }
  26793. }else{ // Safari
  26794. // pulled from WebCore/ecma/kjs_window.cpp, line 2536
  26795. selection.collapse(beginning);
  26796. }
  26797. }else if(has("ie")){ // IE
  26798. var range = win.doc.selection.createRange();
  26799. range.collapse(beginning);
  26800. range.select();
  26801. }
  26802. },
  26803. remove: function(){
  26804. // summary:
  26805. // Function to delete the currently selected content from the document.
  26806. var sel = win.doc.selection;
  26807. if(!win.doc.getSelection){
  26808. // IE6-8
  26809. if(sel.type.toLowerCase() != "none"){
  26810. sel.clear();
  26811. }
  26812. return sel; //Selection
  26813. }else{
  26814. // W3C
  26815. sel = win.global.getSelection();
  26816. sel.deleteFromDocument();
  26817. return sel; //Selection
  26818. }
  26819. },
  26820. selectElementChildren: function(/*DomNode*/element,/*Boolean?*/nochangefocus){
  26821. // summary:
  26822. // clear previous selection and select the content of the node
  26823. // (excluding the node itself)
  26824. // element: DOMNode
  26825. // The element you wish to select the children content of.
  26826. // nochangefocus: Boolean
  26827. // Boolean to indicate if the foxus should change or not.
  26828. var global = win.global;
  26829. var doc = win.doc;
  26830. var range;
  26831. element = dom.byId(element);
  26832. if(doc.selection && !doc.getSelection && win.body().createTextRange){
  26833. // IE6-8
  26834. range = element.ownerDocument.body.createTextRange();
  26835. range.moveToElementText(element);
  26836. if(!nochangefocus){
  26837. try{
  26838. range.select(); // IE throws an exception here if the widget is hidden. See #5439
  26839. }catch(e){ /* squelch */}
  26840. }
  26841. }else if(global.getSelection){
  26842. // W3C
  26843. var selection = win.global.getSelection();
  26844. if(has("opera")){
  26845. //Opera's selectAllChildren doesn't seem to work right
  26846. //against <body> nodes and possibly others ... so
  26847. //we use the W3C range API
  26848. if(selection.rangeCount){
  26849. range = selection.getRangeAt(0);
  26850. }else{
  26851. range = doc.createRange();
  26852. }
  26853. range.setStart(element, 0);
  26854. range.setEnd(element,(element.nodeType == 3)?element.length:element.childNodes.length);
  26855. selection.addRange(range);
  26856. }else{
  26857. selection.selectAllChildren(element);
  26858. }
  26859. }
  26860. },
  26861. selectElement: function(/*DomNode*/element,/*Boolean?*/nochangefocus){
  26862. // summary:
  26863. // clear previous selection and select element (including all its children)
  26864. // element: DOMNode
  26865. // The element to select.
  26866. // nochangefocus: Boolean
  26867. // Boolean indicating if the focus should be changed. IE only.
  26868. var range;
  26869. var doc = win.doc;
  26870. var global = win.global;
  26871. element = dom.byId(element);
  26872. if(!doc.getSelection && win.body().createTextRange){
  26873. // IE6-8
  26874. try{
  26875. var tg = element.tagName ? element.tagName.toLowerCase() : "";
  26876. if(tg === "img" || tg === "table"){
  26877. range = win.body().createControlRange();
  26878. }else{
  26879. range = win.body().createRange();
  26880. }
  26881. range.addElement(element);
  26882. if(!nochangefocus){
  26883. range.select();
  26884. }
  26885. }catch(e){
  26886. this.selectElementChildren(element,nochangefocus);
  26887. }
  26888. }else if(global.getSelection){
  26889. // W3C
  26890. var selection = global.getSelection();
  26891. range = doc.createRange();
  26892. if(selection.removeAllRanges){ // Mozilla
  26893. // FIXME: does this work on Safari?
  26894. if(has("opera")){
  26895. //Opera works if you use the current range on
  26896. //the selection if present.
  26897. if(selection.getRangeAt(0)){
  26898. range = selection.getRangeAt(0);
  26899. }
  26900. }
  26901. range.selectNode(element);
  26902. selection.removeAllRanges();
  26903. selection.addRange(range);
  26904. }
  26905. }
  26906. },
  26907. inSelection: function(node){
  26908. // summary:
  26909. // This function determines if 'node' is
  26910. // in the current selection.
  26911. // tags:
  26912. // public
  26913. if(node){
  26914. var newRange;
  26915. var doc = win.doc;
  26916. var range;
  26917. if(win.global.getSelection){
  26918. //WC3
  26919. var sel = win.global.getSelection();
  26920. if(sel && sel.rangeCount > 0){
  26921. range = sel.getRangeAt(0);
  26922. }
  26923. if(range && range.compareBoundaryPoints && doc.createRange){
  26924. try{
  26925. newRange = doc.createRange();
  26926. newRange.setStart(node, 0);
  26927. if(range.compareBoundaryPoints(range.START_TO_END, newRange) === 1){
  26928. return true;
  26929. }
  26930. }catch(e){ /* squelch */}
  26931. }
  26932. }else if(doc.selection){
  26933. // Probably IE, so we can't use the range object as the pseudo
  26934. // range doesn't implement the boundry checking, we have to
  26935. // use IE specific crud.
  26936. range = doc.selection.createRange();
  26937. try{
  26938. newRange = node.ownerDocument.body.createControlRange();
  26939. if(newRange){
  26940. newRange.addElement(node);
  26941. }
  26942. }catch(e1){
  26943. try{
  26944. newRange = node.ownerDocument.body.createTextRange();
  26945. newRange.moveToElementText(node);
  26946. }catch(e2){/* squelch */}
  26947. }
  26948. if(range && newRange){
  26949. // We can finally compare similar to W3C
  26950. if(range.compareEndPoints("EndToStart", newRange) === 1){
  26951. return true;
  26952. }
  26953. }
  26954. }
  26955. }
  26956. return false; // boolean
  26957. }
  26958. });
  26959. return dijit._editor.selection;
  26960. });
  26961. },
  26962. 'dojo/fx':function(){
  26963. define([
  26964. "./_base/lang",
  26965. "./Evented",
  26966. "./_base/kernel",
  26967. "./_base/array",
  26968. "./_base/connect",
  26969. "./_base/fx",
  26970. "./dom",
  26971. "./dom-style",
  26972. "./dom-geometry",
  26973. "./ready",
  26974. "require" // for context sensitive loading of Toggler
  26975. ], function(lang, Evented, dojo, arrayUtil, connect, baseFx, dom, domStyle, geom, ready, require) {
  26976. // module:
  26977. // dojo/fx
  26978. // summary:
  26979. // TODOC
  26980. /*=====
  26981. dojo.fx = {
  26982. // summary: Effects library on top of Base animations
  26983. };
  26984. var coreFx = dojo.fx;
  26985. =====*/
  26986. // For back-compat, remove in 2.0.
  26987. if(!dojo.isAsync){
  26988. ready(0, function(){
  26989. var requires = ["./fx/Toggler"];
  26990. require(requires); // use indirection so modules not rolled into a build
  26991. });
  26992. }
  26993. var coreFx = dojo.fx = {};
  26994. var _baseObj = {
  26995. _fire: function(evt, args){
  26996. if(this[evt]){
  26997. this[evt].apply(this, args||[]);
  26998. }
  26999. return this;
  27000. }
  27001. };
  27002. var _chain = function(animations){
  27003. this._index = -1;
  27004. this._animations = animations||[];
  27005. this._current = this._onAnimateCtx = this._onEndCtx = null;
  27006. this.duration = 0;
  27007. arrayUtil.forEach(this._animations, function(a){
  27008. this.duration += a.duration;
  27009. if(a.delay){ this.duration += a.delay; }
  27010. }, this);
  27011. };
  27012. _chain.prototype = new Evented();
  27013. lang.extend(_chain, {
  27014. _onAnimate: function(){
  27015. this._fire("onAnimate", arguments);
  27016. },
  27017. _onEnd: function(){
  27018. connect.disconnect(this._onAnimateCtx);
  27019. connect.disconnect(this._onEndCtx);
  27020. this._onAnimateCtx = this._onEndCtx = null;
  27021. if(this._index + 1 == this._animations.length){
  27022. this._fire("onEnd");
  27023. }else{
  27024. // switch animations
  27025. this._current = this._animations[++this._index];
  27026. this._onAnimateCtx = connect.connect(this._current, "onAnimate", this, "_onAnimate");
  27027. this._onEndCtx = connect.connect(this._current, "onEnd", this, "_onEnd");
  27028. this._current.play(0, true);
  27029. }
  27030. },
  27031. play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
  27032. if(!this._current){ this._current = this._animations[this._index = 0]; }
  27033. if(!gotoStart && this._current.status() == "playing"){ return this; }
  27034. var beforeBegin = connect.connect(this._current, "beforeBegin", this, function(){
  27035. this._fire("beforeBegin");
  27036. }),
  27037. onBegin = connect.connect(this._current, "onBegin", this, function(arg){
  27038. this._fire("onBegin", arguments);
  27039. }),
  27040. onPlay = connect.connect(this._current, "onPlay", this, function(arg){
  27041. this._fire("onPlay", arguments);
  27042. connect.disconnect(beforeBegin);
  27043. connect.disconnect(onBegin);
  27044. connect.disconnect(onPlay);
  27045. });
  27046. if(this._onAnimateCtx){
  27047. connect.disconnect(this._onAnimateCtx);
  27048. }
  27049. this._onAnimateCtx = connect.connect(this._current, "onAnimate", this, "_onAnimate");
  27050. if(this._onEndCtx){
  27051. connect.disconnect(this._onEndCtx);
  27052. }
  27053. this._onEndCtx = connect.connect(this._current, "onEnd", this, "_onEnd");
  27054. this._current.play.apply(this._current, arguments);
  27055. return this;
  27056. },
  27057. pause: function(){
  27058. if(this._current){
  27059. var e = connect.connect(this._current, "onPause", this, function(arg){
  27060. this._fire("onPause", arguments);
  27061. connect.disconnect(e);
  27062. });
  27063. this._current.pause();
  27064. }
  27065. return this;
  27066. },
  27067. gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
  27068. this.pause();
  27069. var offset = this.duration * percent;
  27070. this._current = null;
  27071. arrayUtil.some(this._animations, function(a){
  27072. if(a.duration <= offset){
  27073. this._current = a;
  27074. return true;
  27075. }
  27076. offset -= a.duration;
  27077. return false;
  27078. });
  27079. if(this._current){
  27080. this._current.gotoPercent(offset / this._current.duration, andPlay);
  27081. }
  27082. return this;
  27083. },
  27084. stop: function(/*boolean?*/ gotoEnd){
  27085. if(this._current){
  27086. if(gotoEnd){
  27087. for(; this._index + 1 < this._animations.length; ++this._index){
  27088. this._animations[this._index].stop(true);
  27089. }
  27090. this._current = this._animations[this._index];
  27091. }
  27092. var e = connect.connect(this._current, "onStop", this, function(arg){
  27093. this._fire("onStop", arguments);
  27094. connect.disconnect(e);
  27095. });
  27096. this._current.stop();
  27097. }
  27098. return this;
  27099. },
  27100. status: function(){
  27101. return this._current ? this._current.status() : "stopped";
  27102. },
  27103. destroy: function(){
  27104. if(this._onAnimateCtx){ connect.disconnect(this._onAnimateCtx); }
  27105. if(this._onEndCtx){ connect.disconnect(this._onEndCtx); }
  27106. }
  27107. });
  27108. lang.extend(_chain, _baseObj);
  27109. coreFx.chain = /*===== dojo.fx.chain = =====*/ function(/*dojo.Animation[]*/ animations){
  27110. // summary:
  27111. // Chain a list of `dojo.Animation`s to run in sequence
  27112. //
  27113. // description:
  27114. // Return a `dojo.Animation` which will play all passed
  27115. // `dojo.Animation` instances in sequence, firing its own
  27116. // synthesized events simulating a single animation. (eg:
  27117. // onEnd of this animation means the end of the chain,
  27118. // not the individual animations within)
  27119. //
  27120. // example:
  27121. // Once `node` is faded out, fade in `otherNode`
  27122. // | dojo.fx.chain([
  27123. // | dojo.fadeIn({ node:node }),
  27124. // | dojo.fadeOut({ node:otherNode })
  27125. // | ]).play();
  27126. //
  27127. return new _chain(animations); // dojo.Animation
  27128. };
  27129. var _combine = function(animations){
  27130. this._animations = animations||[];
  27131. this._connects = [];
  27132. this._finished = 0;
  27133. this.duration = 0;
  27134. arrayUtil.forEach(animations, function(a){
  27135. var duration = a.duration;
  27136. if(a.delay){ duration += a.delay; }
  27137. if(this.duration < duration){ this.duration = duration; }
  27138. this._connects.push(connect.connect(a, "onEnd", this, "_onEnd"));
  27139. }, this);
  27140. this._pseudoAnimation = new baseFx.Animation({curve: [0, 1], duration: this.duration});
  27141. var self = this;
  27142. arrayUtil.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"],
  27143. function(evt){
  27144. self._connects.push(connect.connect(self._pseudoAnimation, evt,
  27145. function(){ self._fire(evt, arguments); }
  27146. ));
  27147. }
  27148. );
  27149. };
  27150. lang.extend(_combine, {
  27151. _doAction: function(action, args){
  27152. arrayUtil.forEach(this._animations, function(a){
  27153. a[action].apply(a, args);
  27154. });
  27155. return this;
  27156. },
  27157. _onEnd: function(){
  27158. if(++this._finished > this._animations.length){
  27159. this._fire("onEnd");
  27160. }
  27161. },
  27162. _call: function(action, args){
  27163. var t = this._pseudoAnimation;
  27164. t[action].apply(t, args);
  27165. },
  27166. play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
  27167. this._finished = 0;
  27168. this._doAction("play", arguments);
  27169. this._call("play", arguments);
  27170. return this;
  27171. },
  27172. pause: function(){
  27173. this._doAction("pause", arguments);
  27174. this._call("pause", arguments);
  27175. return this;
  27176. },
  27177. gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
  27178. var ms = this.duration * percent;
  27179. arrayUtil.forEach(this._animations, function(a){
  27180. a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay);
  27181. });
  27182. this._call("gotoPercent", arguments);
  27183. return this;
  27184. },
  27185. stop: function(/*boolean?*/ gotoEnd){
  27186. this._doAction("stop", arguments);
  27187. this._call("stop", arguments);
  27188. return this;
  27189. },
  27190. status: function(){
  27191. return this._pseudoAnimation.status();
  27192. },
  27193. destroy: function(){
  27194. arrayUtil.forEach(this._connects, connect.disconnect);
  27195. }
  27196. });
  27197. lang.extend(_combine, _baseObj);
  27198. coreFx.combine = /*===== dojo.fx.combine = =====*/ function(/*dojo.Animation[]*/ animations){
  27199. // summary:
  27200. // Combine a list of `dojo.Animation`s to run in parallel
  27201. //
  27202. // description:
  27203. // Combine an array of `dojo.Animation`s to run in parallel,
  27204. // providing a new `dojo.Animation` instance encompasing each
  27205. // animation, firing standard animation events.
  27206. //
  27207. // example:
  27208. // Fade out `node` while fading in `otherNode` simultaneously
  27209. // | dojo.fx.combine([
  27210. // | dojo.fadeIn({ node:node }),
  27211. // | dojo.fadeOut({ node:otherNode })
  27212. // | ]).play();
  27213. //
  27214. // example:
  27215. // When the longest animation ends, execute a function:
  27216. // | var anim = dojo.fx.combine([
  27217. // | dojo.fadeIn({ node: n, duration:700 }),
  27218. // | dojo.fadeOut({ node: otherNode, duration: 300 })
  27219. // | ]);
  27220. // | dojo.connect(anim, "onEnd", function(){
  27221. // | // overall animation is done.
  27222. // | });
  27223. // | anim.play(); // play the animation
  27224. //
  27225. return new _combine(animations); // dojo.Animation
  27226. };
  27227. coreFx.wipeIn = /*===== dojo.fx.wipeIn = =====*/ function(/*Object*/ args){
  27228. // summary:
  27229. // Expand a node to it's natural height.
  27230. //
  27231. // description:
  27232. // Returns an animation that will expand the
  27233. // node defined in 'args' object from it's current height to
  27234. // it's natural height (with no scrollbar).
  27235. // Node must have no margin/border/padding.
  27236. //
  27237. // args: Object
  27238. // A hash-map of standard `dojo.Animation` constructor properties
  27239. // (such as easing: node: duration: and so on)
  27240. //
  27241. // example:
  27242. // | dojo.fx.wipeIn({
  27243. // | node:"someId"
  27244. // | }).play()
  27245. var node = args.node = dom.byId(args.node), s = node.style, o;
  27246. var anim = baseFx.animateProperty(lang.mixin({
  27247. properties: {
  27248. height: {
  27249. // wrapped in functions so we wait till the last second to query (in case value has changed)
  27250. start: function(){
  27251. // start at current [computed] height, but use 1px rather than 0
  27252. // because 0 causes IE to display the whole panel
  27253. o = s.overflow;
  27254. s.overflow = "hidden";
  27255. if(s.visibility == "hidden" || s.display == "none"){
  27256. s.height = "1px";
  27257. s.display = "";
  27258. s.visibility = "";
  27259. return 1;
  27260. }else{
  27261. var height = domStyle.get(node, "height");
  27262. return Math.max(height, 1);
  27263. }
  27264. },
  27265. end: function(){
  27266. return node.scrollHeight;
  27267. }
  27268. }
  27269. }
  27270. }, args));
  27271. var fini = function(){
  27272. s.height = "auto";
  27273. s.overflow = o;
  27274. };
  27275. connect.connect(anim, "onStop", fini);
  27276. connect.connect(anim, "onEnd", fini);
  27277. return anim; // dojo.Animation
  27278. };
  27279. coreFx.wipeOut = /*===== dojo.fx.wipeOut = =====*/ function(/*Object*/ args){
  27280. // summary:
  27281. // Shrink a node to nothing and hide it.
  27282. //
  27283. // description:
  27284. // Returns an animation that will shrink node defined in "args"
  27285. // from it's current height to 1px, and then hide it.
  27286. //
  27287. // args: Object
  27288. // A hash-map of standard `dojo.Animation` constructor properties
  27289. // (such as easing: node: duration: and so on)
  27290. //
  27291. // example:
  27292. // | dojo.fx.wipeOut({ node:"someId" }).play()
  27293. var node = args.node = dom.byId(args.node), s = node.style, o;
  27294. var anim = baseFx.animateProperty(lang.mixin({
  27295. properties: {
  27296. height: {
  27297. end: 1 // 0 causes IE to display the whole panel
  27298. }
  27299. }
  27300. }, args));
  27301. connect.connect(anim, "beforeBegin", function(){
  27302. o = s.overflow;
  27303. s.overflow = "hidden";
  27304. s.display = "";
  27305. });
  27306. var fini = function(){
  27307. s.overflow = o;
  27308. s.height = "auto";
  27309. s.display = "none";
  27310. };
  27311. connect.connect(anim, "onStop", fini);
  27312. connect.connect(anim, "onEnd", fini);
  27313. return anim; // dojo.Animation
  27314. };
  27315. coreFx.slideTo = /*===== dojo.fx.slideTo = =====*/ function(/*Object*/ args){
  27316. // summary:
  27317. // Slide a node to a new top/left position
  27318. //
  27319. // description:
  27320. // Returns an animation that will slide "node"
  27321. // defined in args Object from its current position to
  27322. // the position defined by (args.left, args.top).
  27323. //
  27324. // args: Object
  27325. // A hash-map of standard `dojo.Animation` constructor properties
  27326. // (such as easing: node: duration: and so on). Special args members
  27327. // are `top` and `left`, which indicate the new position to slide to.
  27328. //
  27329. // example:
  27330. // | .slideTo({ node: node, left:"40", top:"50", units:"px" }).play()
  27331. var node = args.node = dom.byId(args.node),
  27332. top = null, left = null;
  27333. var init = (function(n){
  27334. return function(){
  27335. var cs = domStyle.getComputedStyle(n);
  27336. var pos = cs.position;
  27337. top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0);
  27338. left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0);
  27339. if(pos != 'absolute' && pos != 'relative'){
  27340. var ret = geom.position(n, true);
  27341. top = ret.y;
  27342. left = ret.x;
  27343. n.style.position="absolute";
  27344. n.style.top=top+"px";
  27345. n.style.left=left+"px";
  27346. }
  27347. };
  27348. })(node);
  27349. init();
  27350. var anim = baseFx.animateProperty(lang.mixin({
  27351. properties: {
  27352. top: args.top || 0,
  27353. left: args.left || 0
  27354. }
  27355. }, args));
  27356. connect.connect(anim, "beforeBegin", anim, init);
  27357. return anim; // dojo.Animation
  27358. };
  27359. return coreFx;
  27360. });
  27361. },
  27362. 'dijit/_DialogMixin':function(){
  27363. define("dijit/_DialogMixin", [
  27364. "dojo/_base/declare", // declare
  27365. "./a11y" // _getTabNavigable
  27366. ], function(declare, a11y){
  27367. // module:
  27368. // dijit/_DialogMixin
  27369. // summary:
  27370. // _DialogMixin provides functions useful to Dialog and TooltipDialog
  27371. return declare("dijit._DialogMixin", null, {
  27372. // summary:
  27373. // This provides functions useful to Dialog and TooltipDialog
  27374. execute: function(/*Object*/ /*===== formContents =====*/){
  27375. // summary:
  27376. // Callback when the user hits the submit button.
  27377. // Override this method to handle Dialog execution.
  27378. // description:
  27379. // After the user has pressed the submit button, the Dialog
  27380. // first calls onExecute() to notify the container to hide the
  27381. // dialog and restore focus to wherever it used to be.
  27382. //
  27383. // *Then* this method is called.
  27384. // type:
  27385. // callback
  27386. },
  27387. onCancel: function(){
  27388. // summary:
  27389. // Called when user has pressed the Dialog's cancel button, to notify container.
  27390. // description:
  27391. // Developer shouldn't override or connect to this method;
  27392. // it's a private communication device between the TooltipDialog
  27393. // and the thing that opened it (ex: `dijit.form.DropDownButton`)
  27394. // type:
  27395. // protected
  27396. },
  27397. onExecute: function(){
  27398. // summary:
  27399. // Called when user has pressed the dialog's OK button, to notify container.
  27400. // description:
  27401. // Developer shouldn't override or connect to this method;
  27402. // it's a private communication device between the TooltipDialog
  27403. // and the thing that opened it (ex: `dijit.form.DropDownButton`)
  27404. // type:
  27405. // protected
  27406. },
  27407. _onSubmit: function(){
  27408. // summary:
  27409. // Callback when user hits submit button
  27410. // type:
  27411. // protected
  27412. this.onExecute(); // notify container that we are about to execute
  27413. this.execute(this.get('value'));
  27414. },
  27415. _getFocusItems: function(){
  27416. // summary:
  27417. // Finds focusable items in dialog,
  27418. // and sets this._firstFocusItem and this._lastFocusItem
  27419. // tags:
  27420. // protected
  27421. var elems = a11y._getTabNavigable(this.containerNode);
  27422. this._firstFocusItem = elems.lowest || elems.first || this.closeButtonNode || this.domNode;
  27423. this._lastFocusItem = elems.last || elems.highest || this._firstFocusItem;
  27424. }
  27425. });
  27426. });
  27427. },
  27428. 'dijit/Tree':function(){
  27429. define([
  27430. "dojo/_base/array", // array.filter array.forEach array.map
  27431. "dojo/_base/connect", // connect.isCopyKey()
  27432. "dojo/cookie", // cookie
  27433. "dojo/_base/declare", // declare
  27434. "dojo/_base/Deferred", // Deferred
  27435. "dojo/DeferredList", // DeferredList
  27436. "dojo/dom", // dom.isDescendant
  27437. "dojo/dom-class", // domClass.add domClass.remove domClass.replace domClass.toggle
  27438. "dojo/dom-geometry", // domGeometry.setMarginBox domGeometry.position
  27439. "dojo/dom-style",// domStyle.set
  27440. "dojo/_base/event", // event.stop
  27441. "dojo/fx", // fxUtils.wipeIn fxUtils.wipeOut
  27442. "dojo/_base/kernel", // kernel.deprecated
  27443. "dojo/keys", // arrows etc.
  27444. "dojo/_base/lang", // lang.getObject lang.mixin lang.hitch
  27445. "dojo/on",
  27446. "dojo/topic",
  27447. "./focus",
  27448. "./registry", // registry.getEnclosingWidget(), manager.defaultDuration
  27449. "./_base/manager", // manager.getEnclosingWidget(), manager.defaultDuration
  27450. "./_Widget",
  27451. "./_TemplatedMixin",
  27452. "./_Container",
  27453. "./_Contained",
  27454. "./_CssStateMixin",
  27455. "dojo/text!./templates/TreeNode.html",
  27456. "dojo/text!./templates/Tree.html",
  27457. "./tree/TreeStoreModel",
  27458. "./tree/ForestStoreModel",
  27459. "./tree/_dndSelector"
  27460. ], function(array, connect, cookie, declare, Deferred, DeferredList,
  27461. dom, domClass, domGeometry, domStyle, event, fxUtils, kernel, keys, lang, on, topic,
  27462. focus, registry, manager, _Widget, _TemplatedMixin, _Container, _Contained, _CssStateMixin,
  27463. treeNodeTemplate, treeTemplate, TreeStoreModel, ForestStoreModel, _dndSelector){
  27464. /*=====
  27465. var _Widget = dijit._Widget;
  27466. var _TemplatedMixin = dijit._TemplatedMixin;
  27467. var _CssStateMixin = dijit._CssStateMixin;
  27468. var _Container = dijit._Container;
  27469. var _Contained = dijit._Contained;
  27470. =====*/
  27471. // module:
  27472. // dijit/Tree
  27473. // summary:
  27474. // dijit.Tree widget, and internal dijit._TreeNode widget
  27475. var TreeNode = declare(
  27476. "dijit._TreeNode",
  27477. [_Widget, _TemplatedMixin, _Container, _Contained, _CssStateMixin],
  27478. {
  27479. // summary:
  27480. // Single node within a tree. This class is used internally
  27481. // by Tree and should not be accessed directly.
  27482. // tags:
  27483. // private
  27484. // item: [const] Item
  27485. // the dojo.data entry this tree represents
  27486. item: null,
  27487. // isTreeNode: [protected] Boolean
  27488. // Indicates that this is a TreeNode. Used by `dijit.Tree` only,
  27489. // should not be accessed directly.
  27490. isTreeNode: true,
  27491. // label: String
  27492. // Text of this tree node
  27493. label: "",
  27494. _setLabelAttr: {node: "labelNode", type: "innerText"},
  27495. // isExpandable: [private] Boolean
  27496. // This node has children, so show the expando node (+ sign)
  27497. isExpandable: null,
  27498. // isExpanded: [readonly] Boolean
  27499. // This node is currently expanded (ie, opened)
  27500. isExpanded: false,
  27501. // state: [private] String
  27502. // Dynamic loading-related stuff.
  27503. // When an empty folder node appears, it is "UNCHECKED" first,
  27504. // then after dojo.data query it becomes "LOADING" and, finally "LOADED"
  27505. state: "UNCHECKED",
  27506. templateString: treeNodeTemplate,
  27507. baseClass: "dijitTreeNode",
  27508. // For hover effect for tree node, and focus effect for label
  27509. cssStateNodes: {
  27510. rowNode: "dijitTreeRow",
  27511. labelNode: "dijitTreeLabel"
  27512. },
  27513. // Tooltip is defined in _WidgetBase but we need to handle the mapping to DOM here
  27514. _setTooltipAttr: {node: "rowNode", type: "attribute", attribute: "title"},
  27515. buildRendering: function(){
  27516. this.inherited(arguments);
  27517. // set expand icon for leaf
  27518. this._setExpando();
  27519. // set icon and label class based on item
  27520. this._updateItemClasses(this.item);
  27521. if(this.isExpandable){
  27522. this.labelNode.setAttribute("aria-expanded", this.isExpanded);
  27523. }
  27524. //aria-selected should be false on all selectable elements.
  27525. this.setSelected(false);
  27526. },
  27527. _setIndentAttr: function(indent){
  27528. // summary:
  27529. // Tell this node how many levels it should be indented
  27530. // description:
  27531. // 0 for top level nodes, 1 for their children, 2 for their
  27532. // grandchildren, etc.
  27533. // Math.max() is to prevent negative padding on hidden root node (when indent == -1)
  27534. var pixels = (Math.max(indent, 0) * this.tree._nodePixelIndent) + "px";
  27535. domStyle.set(this.domNode, "backgroundPosition", pixels + " 0px");
  27536. domStyle.set(this.rowNode, this.isLeftToRight() ? "paddingLeft" : "paddingRight", pixels);
  27537. array.forEach(this.getChildren(), function(child){
  27538. child.set("indent", indent+1);
  27539. });
  27540. this._set("indent", indent);
  27541. },
  27542. markProcessing: function(){
  27543. // summary:
  27544. // Visually denote that tree is loading data, etc.
  27545. // tags:
  27546. // private
  27547. this.state = "LOADING";
  27548. this._setExpando(true);
  27549. },
  27550. unmarkProcessing: function(){
  27551. // summary:
  27552. // Clear markup from markProcessing() call
  27553. // tags:
  27554. // private
  27555. this._setExpando(false);
  27556. },
  27557. _updateItemClasses: function(item){
  27558. // summary:
  27559. // Set appropriate CSS classes for icon and label dom node
  27560. // (used to allow for item updates to change respective CSS)
  27561. // tags:
  27562. // private
  27563. var tree = this.tree, model = tree.model;
  27564. if(tree._v10Compat && item === model.root){
  27565. // For back-compat with 1.0, need to use null to specify root item (TODO: remove in 2.0)
  27566. item = null;
  27567. }
  27568. this._applyClassAndStyle(item, "icon", "Icon");
  27569. this._applyClassAndStyle(item, "label", "Label");
  27570. this._applyClassAndStyle(item, "row", "Row");
  27571. },
  27572. _applyClassAndStyle: function(item, lower, upper){
  27573. // summary:
  27574. // Set the appropriate CSS classes and styles for labels, icons and rows.
  27575. //
  27576. // item:
  27577. // The data item.
  27578. //
  27579. // lower:
  27580. // The lower case attribute to use, e.g. 'icon', 'label' or 'row'.
  27581. //
  27582. // upper:
  27583. // The upper case attribute to use, e.g. 'Icon', 'Label' or 'Row'.
  27584. //
  27585. // tags:
  27586. // private
  27587. var clsName = "_" + lower + "Class";
  27588. var nodeName = lower + "Node";
  27589. var oldCls = this[clsName];
  27590. this[clsName] = this.tree["get" + upper + "Class"](item, this.isExpanded);
  27591. domClass.replace(this[nodeName], this[clsName] || "", oldCls || "");
  27592. domStyle.set(this[nodeName], this.tree["get" + upper + "Style"](item, this.isExpanded) || {});
  27593. },
  27594. _updateLayout: function(){
  27595. // summary:
  27596. // Set appropriate CSS classes for this.domNode
  27597. // tags:
  27598. // private
  27599. var parent = this.getParent();
  27600. if(!parent || !parent.rowNode || parent.rowNode.style.display == "none"){
  27601. /* if we are hiding the root node then make every first level child look like a root node */
  27602. domClass.add(this.domNode, "dijitTreeIsRoot");
  27603. }else{
  27604. domClass.toggle(this.domNode, "dijitTreeIsLast", !this.getNextSibling());
  27605. }
  27606. },
  27607. _setExpando: function(/*Boolean*/ processing){
  27608. // summary:
  27609. // Set the right image for the expando node
  27610. // tags:
  27611. // private
  27612. var styles = ["dijitTreeExpandoLoading", "dijitTreeExpandoOpened",
  27613. "dijitTreeExpandoClosed", "dijitTreeExpandoLeaf"],
  27614. _a11yStates = ["*","-","+","*"],
  27615. idx = processing ? 0 : (this.isExpandable ? (this.isExpanded ? 1 : 2) : 3);
  27616. // apply the appropriate class to the expando node
  27617. domClass.replace(this.expandoNode, styles[idx], styles);
  27618. // provide a non-image based indicator for images-off mode
  27619. this.expandoNodeText.innerHTML = _a11yStates[idx];
  27620. },
  27621. expand: function(){
  27622. // summary:
  27623. // Show my children
  27624. // returns:
  27625. // Deferred that fires when expansion is complete
  27626. // If there's already an expand in progress or we are already expanded, just return
  27627. if(this._expandDeferred){
  27628. return this._expandDeferred; // dojo.Deferred
  27629. }
  27630. // cancel in progress collapse operation
  27631. this._wipeOut && this._wipeOut.stop();
  27632. // All the state information for when a node is expanded, maybe this should be
  27633. // set when the animation completes instead
  27634. this.isExpanded = true;
  27635. this.labelNode.setAttribute("aria-expanded", "true");
  27636. if(this.tree.showRoot || this !== this.tree.rootNode){
  27637. this.containerNode.setAttribute("role", "group");
  27638. }
  27639. domClass.add(this.contentNode,'dijitTreeContentExpanded');
  27640. this._setExpando();
  27641. this._updateItemClasses(this.item);
  27642. if(this == this.tree.rootNode){
  27643. this.tree.domNode.setAttribute("aria-expanded", "true");
  27644. }
  27645. var def,
  27646. wipeIn = fxUtils.wipeIn({
  27647. node: this.containerNode, duration: manager.defaultDuration,
  27648. onEnd: function(){
  27649. def.callback(true);
  27650. }
  27651. });
  27652. // Deferred that fires when expand is complete
  27653. def = (this._expandDeferred = new Deferred(function(){
  27654. // Canceller
  27655. wipeIn.stop();
  27656. }));
  27657. wipeIn.play();
  27658. return def; // dojo.Deferred
  27659. },
  27660. collapse: function(){
  27661. // summary:
  27662. // Collapse this node (if it's expanded)
  27663. if(!this.isExpanded){ return; }
  27664. // cancel in progress expand operation
  27665. if(this._expandDeferred){
  27666. this._expandDeferred.cancel();
  27667. delete this._expandDeferred;
  27668. }
  27669. this.isExpanded = false;
  27670. this.labelNode.setAttribute("aria-expanded", "false");
  27671. if(this == this.tree.rootNode){
  27672. this.tree.domNode.setAttribute("aria-expanded", "false");
  27673. }
  27674. domClass.remove(this.contentNode,'dijitTreeContentExpanded');
  27675. this._setExpando();
  27676. this._updateItemClasses(this.item);
  27677. if(!this._wipeOut){
  27678. this._wipeOut = fxUtils.wipeOut({
  27679. node: this.containerNode, duration: manager.defaultDuration
  27680. });
  27681. }
  27682. this._wipeOut.play();
  27683. },
  27684. // indent: Integer
  27685. // Levels from this node to the root node
  27686. indent: 0,
  27687. setChildItems: function(/* Object[] */ items){
  27688. // summary:
  27689. // Sets the child items of this node, removing/adding nodes
  27690. // from current children to match specified items[] array.
  27691. // Also, if this.persist == true, expands any children that were previously
  27692. // opened.
  27693. // returns:
  27694. // Deferred object that fires after all previously opened children
  27695. // have been expanded again (or fires instantly if there are no such children).
  27696. var tree = this.tree,
  27697. model = tree.model,
  27698. defs = []; // list of deferreds that need to fire before I am complete
  27699. // Orphan all my existing children.
  27700. // If items contains some of the same items as before then we will reattach them.
  27701. // Don't call this.removeChild() because that will collapse the tree etc.
  27702. array.forEach(this.getChildren(), function(child){
  27703. _Container.prototype.removeChild.call(this, child);
  27704. }, this);
  27705. this.state = "LOADED";
  27706. if(items && items.length > 0){
  27707. this.isExpandable = true;
  27708. // Create _TreeNode widget for each specified tree node, unless one already
  27709. // exists and isn't being used (presumably it's from a DnD move and was recently
  27710. // released
  27711. array.forEach(items, function(item){
  27712. var id = model.getIdentity(item),
  27713. existingNodes = tree._itemNodesMap[id],
  27714. node;
  27715. if(existingNodes){
  27716. for(var i=0;i<existingNodes.length;i++){
  27717. if(existingNodes[i] && !existingNodes[i].getParent()){
  27718. node = existingNodes[i];
  27719. node.set('indent', this.indent+1);
  27720. break;
  27721. }
  27722. }
  27723. }
  27724. if(!node){
  27725. node = this.tree._createTreeNode({
  27726. item: item,
  27727. tree: tree,
  27728. isExpandable: model.mayHaveChildren(item),
  27729. label: tree.getLabel(item),
  27730. tooltip: tree.getTooltip(item),
  27731. dir: tree.dir,
  27732. lang: tree.lang,
  27733. textDir: tree.textDir,
  27734. indent: this.indent + 1
  27735. });
  27736. if(existingNodes){
  27737. existingNodes.push(node);
  27738. }else{
  27739. tree._itemNodesMap[id] = [node];
  27740. }
  27741. }
  27742. this.addChild(node);
  27743. // If node was previously opened then open it again now (this may trigger
  27744. // more data store accesses, recursively)
  27745. if(this.tree.autoExpand || this.tree._state(node)){
  27746. defs.push(tree._expandNode(node));
  27747. }
  27748. }, this);
  27749. // note that updateLayout() needs to be called on each child after
  27750. // _all_ the children exist
  27751. array.forEach(this.getChildren(), function(child){
  27752. child._updateLayout();
  27753. });
  27754. }else{
  27755. this.isExpandable=false;
  27756. }
  27757. if(this._setExpando){
  27758. // change expando to/from dot or + icon, as appropriate
  27759. this._setExpando(false);
  27760. }
  27761. // Set leaf icon or folder icon, as appropriate
  27762. this._updateItemClasses(this.item);
  27763. // On initial tree show, make the selected TreeNode as either the root node of the tree,
  27764. // or the first child, if the root node is hidden
  27765. if(this == tree.rootNode){
  27766. var fc = this.tree.showRoot ? this : this.getChildren()[0];
  27767. if(fc){
  27768. fc.setFocusable(true);
  27769. tree.lastFocused = fc;
  27770. }else{
  27771. // fallback: no nodes in tree so focus on Tree <div> itself
  27772. tree.domNode.setAttribute("tabIndex", "0");
  27773. }
  27774. }
  27775. return new DeferredList(defs); // dojo.Deferred
  27776. },
  27777. getTreePath: function(){
  27778. var node = this;
  27779. var path = [];
  27780. while(node && node !== this.tree.rootNode){
  27781. path.unshift(node.item);
  27782. node = node.getParent();
  27783. }
  27784. path.unshift(this.tree.rootNode.item);
  27785. return path;
  27786. },
  27787. getIdentity: function(){
  27788. return this.tree.model.getIdentity(this.item);
  27789. },
  27790. removeChild: function(/* treeNode */ node){
  27791. this.inherited(arguments);
  27792. var children = this.getChildren();
  27793. if(children.length == 0){
  27794. this.isExpandable = false;
  27795. this.collapse();
  27796. }
  27797. array.forEach(children, function(child){
  27798. child._updateLayout();
  27799. });
  27800. },
  27801. makeExpandable: function(){
  27802. // summary:
  27803. // if this node wasn't already showing the expando node,
  27804. // turn it into one and call _setExpando()
  27805. // TODO: hmm this isn't called from anywhere, maybe should remove it for 2.0
  27806. this.isExpandable = true;
  27807. this._setExpando(false);
  27808. },
  27809. _onLabelFocus: function(){
  27810. // summary:
  27811. // Called when this row is focused (possibly programatically)
  27812. // Note that we aren't using _onFocus() builtin to dijit
  27813. // because it's called when focus is moved to a descendant TreeNode.
  27814. // tags:
  27815. // private
  27816. this.tree._onNodeFocus(this);
  27817. },
  27818. setSelected: function(/*Boolean*/ selected){
  27819. // summary:
  27820. // A Tree has a (single) currently selected node.
  27821. // Mark that this node is/isn't that currently selected node.
  27822. // description:
  27823. // In particular, setting a node as selected involves setting tabIndex
  27824. // so that when user tabs to the tree, focus will go to that node (only).
  27825. this.labelNode.setAttribute("aria-selected", selected);
  27826. domClass.toggle(this.rowNode, "dijitTreeRowSelected", selected);
  27827. },
  27828. setFocusable: function(/*Boolean*/ selected){
  27829. // summary:
  27830. // A Tree has a (single) node that's focusable.
  27831. // Mark that this node is/isn't that currently focsuable node.
  27832. // description:
  27833. // In particular, setting a node as selected involves setting tabIndex
  27834. // so that when user tabs to the tree, focus will go to that node (only).
  27835. this.labelNode.setAttribute("tabIndex", selected ? "0" : "-1");
  27836. },
  27837. _onClick: function(evt){
  27838. // summary:
  27839. // Handler for onclick event on a node
  27840. // tags:
  27841. // private
  27842. this.tree._onClick(this, evt);
  27843. },
  27844. _onDblClick: function(evt){
  27845. // summary:
  27846. // Handler for ondblclick event on a node
  27847. // tags:
  27848. // private
  27849. this.tree._onDblClick(this, evt);
  27850. },
  27851. _onMouseEnter: function(evt){
  27852. // summary:
  27853. // Handler for onmouseenter event on a node
  27854. // tags:
  27855. // private
  27856. this.tree._onNodeMouseEnter(this, evt);
  27857. },
  27858. _onMouseLeave: function(evt){
  27859. // summary:
  27860. // Handler for onmouseenter event on a node
  27861. // tags:
  27862. // private
  27863. this.tree._onNodeMouseLeave(this, evt);
  27864. },
  27865. _setTextDirAttr: function(textDir){
  27866. if(textDir &&((this.textDir != textDir) || !this._created)){
  27867. this._set("textDir", textDir);
  27868. this.applyTextDir(this.labelNode, this.labelNode.innerText || this.labelNode.textContent || "");
  27869. array.forEach(this.getChildren(), function(childNode){
  27870. childNode.set("textDir", textDir);
  27871. }, this);
  27872. }
  27873. }
  27874. });
  27875. var Tree = declare("dijit.Tree", [_Widget, _TemplatedMixin], {
  27876. // summary:
  27877. // This widget displays hierarchical data from a store.
  27878. // store: [deprecated] String||dojo.data.Store
  27879. // Deprecated. Use "model" parameter instead.
  27880. // The store to get data to display in the tree.
  27881. store: null,
  27882. // model: dijit.Tree.model
  27883. // Interface to read tree data, get notifications of changes to tree data,
  27884. // and for handling drop operations (i.e drag and drop onto the tree)
  27885. model: null,
  27886. // query: [deprecated] anything
  27887. // Deprecated. User should specify query to the model directly instead.
  27888. // Specifies datastore query to return the root item or top items for the tree.
  27889. query: null,
  27890. // label: [deprecated] String
  27891. // Deprecated. Use dijit.tree.ForestStoreModel directly instead.
  27892. // Used in conjunction with query parameter.
  27893. // If a query is specified (rather than a root node id), and a label is also specified,
  27894. // then a fake root node is created and displayed, with this label.
  27895. label: "",
  27896. // showRoot: [const] Boolean
  27897. // Should the root node be displayed, or hidden?
  27898. showRoot: true,
  27899. // childrenAttr: [deprecated] String[]
  27900. // Deprecated. This information should be specified in the model.
  27901. // One ore more attributes that holds children of a tree node
  27902. childrenAttr: ["children"],
  27903. // paths: String[][] or Item[][]
  27904. // Full paths from rootNode to selected nodes expressed as array of items or array of ids.
  27905. // Since setting the paths may be asynchronous (because ofwaiting on dojo.data), set("paths", ...)
  27906. // returns a Deferred to indicate when the set is complete.
  27907. paths: [],
  27908. // path: String[] or Item[]
  27909. // Backward compatible singular variant of paths.
  27910. path: [],
  27911. // selectedItems: [readonly] Item[]
  27912. // The currently selected items in this tree.
  27913. // This property can only be set (via set('selectedItems', ...)) when that item is already
  27914. // visible in the tree. (I.e. the tree has already been expanded to show that node.)
  27915. // Should generally use `paths` attribute to set the selected items instead.
  27916. selectedItems: null,
  27917. // selectedItem: [readonly] Item
  27918. // Backward compatible singular variant of selectedItems.
  27919. selectedItem: null,
  27920. // openOnClick: Boolean
  27921. // If true, clicking a folder node's label will open it, rather than calling onClick()
  27922. openOnClick: false,
  27923. // openOnDblClick: Boolean
  27924. // If true, double-clicking a folder node's label will open it, rather than calling onDblClick()
  27925. openOnDblClick: false,
  27926. templateString: treeTemplate,
  27927. // persist: Boolean
  27928. // Enables/disables use of cookies for state saving.
  27929. persist: true,
  27930. // autoExpand: Boolean
  27931. // Fully expand the tree on load. Overrides `persist`.
  27932. autoExpand: false,
  27933. // dndController: [protected] Function|String
  27934. // Class to use as as the dnd controller. Specifying this class enables DnD.
  27935. // Generally you should specify this as dijit.tree.dndSource.
  27936. // Setting of dijit.tree._dndSelector handles selection only (no actual DnD).
  27937. dndController: _dndSelector,
  27938. // parameters to pull off of the tree and pass on to the dndController as its params
  27939. dndParams: ["onDndDrop","itemCreator","onDndCancel","checkAcceptance", "checkItemAcceptance", "dragThreshold", "betweenThreshold"],
  27940. //declare the above items so they can be pulled from the tree's markup
  27941. // onDndDrop: [protected] Function
  27942. // Parameter to dndController, see `dijit.tree.dndSource.onDndDrop`.
  27943. // Generally this doesn't need to be set.
  27944. onDndDrop: null,
  27945. /*=====
  27946. itemCreator: function(nodes, target, source){
  27947. // summary:
  27948. // Returns objects passed to `Tree.model.newItem()` based on DnD nodes
  27949. // dropped onto the tree. Developer must override this method to enable
  27950. // dropping from external sources onto this Tree, unless the Tree.model's items
  27951. // happen to look like {id: 123, name: "Apple" } with no other attributes.
  27952. // description:
  27953. // For each node in nodes[], which came from source, create a hash of name/value
  27954. // pairs to be passed to Tree.model.newItem(). Returns array of those hashes.
  27955. // nodes: DomNode[]
  27956. // The DOMNodes dragged from the source container
  27957. // target: DomNode
  27958. // The target TreeNode.rowNode
  27959. // source: dojo.dnd.Source
  27960. // The source container the nodes were dragged from, perhaps another Tree or a plain dojo.dnd.Source
  27961. // returns: Object[]
  27962. // Array of name/value hashes for each new item to be added to the Tree, like:
  27963. // | [
  27964. // | { id: 123, label: "apple", foo: "bar" },
  27965. // | { id: 456, label: "pear", zaz: "bam" }
  27966. // | ]
  27967. // tags:
  27968. // extension
  27969. return [{}];
  27970. },
  27971. =====*/
  27972. itemCreator: null,
  27973. // onDndCancel: [protected] Function
  27974. // Parameter to dndController, see `dijit.tree.dndSource.onDndCancel`.
  27975. // Generally this doesn't need to be set.
  27976. onDndCancel: null,
  27977. /*=====
  27978. checkAcceptance: function(source, nodes){
  27979. // summary:
  27980. // Checks if the Tree itself can accept nodes from this source
  27981. // source: dijit.tree._dndSource
  27982. // The source which provides items
  27983. // nodes: DOMNode[]
  27984. // Array of DOM nodes corresponding to nodes being dropped, dijitTreeRow nodes if
  27985. // source is a dijit.Tree.
  27986. // tags:
  27987. // extension
  27988. return true; // Boolean
  27989. },
  27990. =====*/
  27991. checkAcceptance: null,
  27992. /*=====
  27993. checkItemAcceptance: function(target, source, position){
  27994. // summary:
  27995. // Stub function to be overridden if one wants to check for the ability to drop at the node/item level
  27996. // description:
  27997. // In the base case, this is called to check if target can become a child of source.
  27998. // When betweenThreshold is set, position="before" or "after" means that we
  27999. // are asking if the source node can be dropped before/after the target node.
  28000. // target: DOMNode
  28001. // The dijitTreeRoot DOM node inside of the TreeNode that we are dropping on to
  28002. // Use dijit.getEnclosingWidget(target) to get the TreeNode.
  28003. // source: dijit.tree.dndSource
  28004. // The (set of) nodes we are dropping
  28005. // position: String
  28006. // "over", "before", or "after"
  28007. // tags:
  28008. // extension
  28009. return true; // Boolean
  28010. },
  28011. =====*/
  28012. checkItemAcceptance: null,
  28013. // dragThreshold: Integer
  28014. // Number of pixels mouse moves before it's considered the start of a drag operation
  28015. dragThreshold: 5,
  28016. // betweenThreshold: Integer
  28017. // Set to a positive value to allow drag and drop "between" nodes.
  28018. //
  28019. // If during DnD mouse is over a (target) node but less than betweenThreshold
  28020. // pixels from the bottom edge, dropping the the dragged node will make it
  28021. // the next sibling of the target node, rather than the child.
  28022. //
  28023. // Similarly, if mouse is over a target node but less that betweenThreshold
  28024. // pixels from the top edge, dropping the dragged node will make it
  28025. // the target node's previous sibling rather than the target node's child.
  28026. betweenThreshold: 0,
  28027. // _nodePixelIndent: Integer
  28028. // Number of pixels to indent tree nodes (relative to parent node).
  28029. // Default is 19 but can be overridden by setting CSS class dijitTreeIndent
  28030. // and calling resize() or startup() on tree after it's in the DOM.
  28031. _nodePixelIndent: 19,
  28032. _publish: function(/*String*/ topicName, /*Object*/ message){
  28033. // summary:
  28034. // Publish a message for this widget/topic
  28035. topic.publish(this.id, lang.mixin({tree: this, event: topicName}, message || {})); // publish
  28036. },
  28037. postMixInProperties: function(){
  28038. this.tree = this;
  28039. if(this.autoExpand){
  28040. // There's little point in saving opened/closed state of nodes for a Tree
  28041. // that initially opens all it's nodes.
  28042. this.persist = false;
  28043. }
  28044. this._itemNodesMap={};
  28045. if(!this.cookieName && this.id){
  28046. this.cookieName = this.id + "SaveStateCookie";
  28047. }
  28048. this._loadDeferred = new Deferred();
  28049. this.inherited(arguments);
  28050. },
  28051. postCreate: function(){
  28052. this._initState();
  28053. // Catch events on TreeNodes
  28054. var self = this;
  28055. this._connects.push(
  28056. on(this.domNode, on.selector(".dijitTreeNode", "keypress"), function(evt){
  28057. self._onKeyPress(registry.byNode(this), evt);
  28058. }),
  28059. on(this.domNode, on.selector(".dijitTreeNode", "keydown"), function(evt){
  28060. self._onKeyDown(registry.byNode(this), evt);
  28061. })
  28062. );
  28063. // Create glue between store and Tree, if not specified directly by user
  28064. if(!this.model){
  28065. this._store2model();
  28066. }
  28067. // monitor changes to items
  28068. this.connect(this.model, "onChange", "_onItemChange");
  28069. this.connect(this.model, "onChildrenChange", "_onItemChildrenChange");
  28070. this.connect(this.model, "onDelete", "_onItemDelete");
  28071. this._load();
  28072. this.inherited(arguments);
  28073. if(this.dndController){
  28074. if(lang.isString(this.dndController)){
  28075. this.dndController = lang.getObject(this.dndController);
  28076. }
  28077. var params={};
  28078. for(var i=0; i<this.dndParams.length;i++){
  28079. if(this[this.dndParams[i]]){
  28080. params[this.dndParams[i]] = this[this.dndParams[i]];
  28081. }
  28082. }
  28083. this.dndController = new this.dndController(this, params);
  28084. }
  28085. },
  28086. _store2model: function(){
  28087. // summary:
  28088. // User specified a store&query rather than model, so create model from store/query
  28089. this._v10Compat = true;
  28090. kernel.deprecated("Tree: from version 2.0, should specify a model object rather than a store/query");
  28091. var modelParams = {
  28092. id: this.id + "_ForestStoreModel",
  28093. store: this.store,
  28094. query: this.query,
  28095. childrenAttrs: this.childrenAttr
  28096. };
  28097. // Only override the model's mayHaveChildren() method if the user has specified an override
  28098. if(this.params.mayHaveChildren){
  28099. modelParams.mayHaveChildren = lang.hitch(this, "mayHaveChildren");
  28100. }
  28101. if(this.params.getItemChildren){
  28102. modelParams.getChildren = lang.hitch(this, function(item, onComplete, onError){
  28103. this.getItemChildren((this._v10Compat && item === this.model.root) ? null : item, onComplete, onError);
  28104. });
  28105. }
  28106. this.model = new ForestStoreModel(modelParams);
  28107. // For backwards compatibility, the visibility of the root node is controlled by
  28108. // whether or not the user has specified a label
  28109. this.showRoot = Boolean(this.label);
  28110. },
  28111. onLoad: function(){
  28112. // summary:
  28113. // Called when tree finishes loading and expanding.
  28114. // description:
  28115. // If persist == true the loading may encompass many levels of fetches
  28116. // from the data store, each asynchronous. Waits for all to finish.
  28117. // tags:
  28118. // callback
  28119. },
  28120. _load: function(){
  28121. // summary:
  28122. // Initial load of the tree.
  28123. // Load root node (possibly hidden) and it's children.
  28124. this.model.getRoot(
  28125. lang.hitch(this, function(item){
  28126. var rn = (this.rootNode = this.tree._createTreeNode({
  28127. item: item,
  28128. tree: this,
  28129. isExpandable: true,
  28130. label: this.label || this.getLabel(item),
  28131. textDir: this.textDir,
  28132. indent: this.showRoot ? 0 : -1
  28133. }));
  28134. if(!this.showRoot){
  28135. rn.rowNode.style.display="none";
  28136. // if root is not visible, move tree role to the invisible
  28137. // root node's containerNode, see #12135
  28138. this.domNode.setAttribute("role", "presentation");
  28139. rn.labelNode.setAttribute("role", "presentation");
  28140. rn.containerNode.setAttribute("role", "tree");
  28141. }
  28142. this.domNode.appendChild(rn.domNode);
  28143. var identity = this.model.getIdentity(item);
  28144. if(this._itemNodesMap[identity]){
  28145. this._itemNodesMap[identity].push(rn);
  28146. }else{
  28147. this._itemNodesMap[identity] = [rn];
  28148. }
  28149. rn._updateLayout(); // sets "dijitTreeIsRoot" CSS classname
  28150. // load top level children and then fire onLoad() event
  28151. this._expandNode(rn).addCallback(lang.hitch(this, function(){
  28152. this._loadDeferred.callback(true);
  28153. this.onLoad();
  28154. }));
  28155. }),
  28156. function(err){
  28157. console.error(this, ": error loading root: ", err);
  28158. }
  28159. );
  28160. },
  28161. getNodesByItem: function(/*Item or id*/ item){
  28162. // summary:
  28163. // Returns all tree nodes that refer to an item
  28164. // returns:
  28165. // Array of tree nodes that refer to passed item
  28166. if(!item){ return []; }
  28167. var identity = lang.isString(item) ? item : this.model.getIdentity(item);
  28168. // return a copy so widget don't get messed up by changes to returned array
  28169. return [].concat(this._itemNodesMap[identity]);
  28170. },
  28171. _setSelectedItemAttr: function(/*Item or id*/ item){
  28172. this.set('selectedItems', [item]);
  28173. },
  28174. _setSelectedItemsAttr: function(/*Items or ids*/ items){
  28175. // summary:
  28176. // Select tree nodes related to passed items.
  28177. // WARNING: if model use multi-parented items or desired tree node isn't already loaded
  28178. // behavior is undefined. Use set('paths', ...) instead.
  28179. var tree = this;
  28180. this._loadDeferred.addCallback( lang.hitch(this, function(){
  28181. var identities = array.map(items, function(item){
  28182. return (!item || lang.isString(item)) ? item : tree.model.getIdentity(item);
  28183. });
  28184. var nodes = [];
  28185. array.forEach(identities, function(id){
  28186. nodes = nodes.concat(tree._itemNodesMap[id] || []);
  28187. });
  28188. this.set('selectedNodes', nodes);
  28189. }));
  28190. },
  28191. _setPathAttr: function(/*Item[] || String[]*/ path){
  28192. // summary:
  28193. // Singular variant of _setPathsAttr
  28194. if(path.length){
  28195. return this.set("paths", [path]);
  28196. }else{
  28197. // Empty list is interpreted as "select nothing"
  28198. return this.set("paths", []);
  28199. }
  28200. },
  28201. _setPathsAttr: function(/*Item[][] || String[][]*/ paths){
  28202. // summary:
  28203. // Select the tree nodes identified by passed paths.
  28204. // paths:
  28205. // Array of arrays of items or item id's
  28206. // returns:
  28207. // Deferred to indicate when the set is complete
  28208. var tree = this;
  28209. // We may need to wait for some nodes to expand, so setting
  28210. // each path will involve a Deferred. We bring those deferreds
  28211. // together witha DeferredList.
  28212. return new DeferredList(array.map(paths, function(path){
  28213. var d = new Deferred();
  28214. // normalize path to use identity
  28215. path = array.map(path, function(item){
  28216. return lang.isString(item) ? item : tree.model.getIdentity(item);
  28217. });
  28218. if(path.length){
  28219. // Wait for the tree to load, if it hasn't already.
  28220. tree._loadDeferred.addCallback(function(){ selectPath(path, [tree.rootNode], d); });
  28221. }else{
  28222. d.errback("Empty path");
  28223. }
  28224. return d;
  28225. })).addCallback(setNodes);
  28226. function selectPath(path, nodes, def){
  28227. // Traverse path; the next path component should be among "nodes".
  28228. var nextPath = path.shift();
  28229. var nextNode = array.filter(nodes, function(node){
  28230. return node.getIdentity() == nextPath;
  28231. })[0];
  28232. if(!!nextNode){
  28233. if(path.length){
  28234. tree._expandNode(nextNode).addCallback(function(){ selectPath(path, nextNode.getChildren(), def); });
  28235. }else{
  28236. //Successfully reached the end of this path
  28237. def.callback(nextNode);
  28238. }
  28239. }else{
  28240. def.errback("Could not expand path at " + nextPath);
  28241. }
  28242. }
  28243. function setNodes(newNodes){
  28244. //After all expansion is finished, set the selection to
  28245. //the set of nodes successfully found.
  28246. tree.set("selectedNodes", array.map(
  28247. array.filter(newNodes,function(x){return x[0];}),
  28248. function(x){return x[1];}));
  28249. }
  28250. },
  28251. _setSelectedNodeAttr: function(node){
  28252. this.set('selectedNodes', [node]);
  28253. },
  28254. _setSelectedNodesAttr: function(nodes){
  28255. this._loadDeferred.addCallback( lang.hitch(this, function(){
  28256. this.dndController.setSelection(nodes);
  28257. }));
  28258. },
  28259. ////////////// Data store related functions //////////////////////
  28260. // These just get passed to the model; they are here for back-compat
  28261. mayHaveChildren: function(/*dojo.data.Item*/ /*===== item =====*/){
  28262. // summary:
  28263. // Deprecated. This should be specified on the model itself.
  28264. //
  28265. // Overridable function to tell if an item has or may have children.
  28266. // Controls whether or not +/- expando icon is shown.
  28267. // (For efficiency reasons we may not want to check if an element actually
  28268. // has children until user clicks the expando node)
  28269. // tags:
  28270. // deprecated
  28271. },
  28272. getItemChildren: function(/*===== parentItem, onComplete =====*/){
  28273. // summary:
  28274. // Deprecated. This should be specified on the model itself.
  28275. //
  28276. // Overridable function that return array of child items of given parent item,
  28277. // or if parentItem==null then return top items in tree
  28278. // tags:
  28279. // deprecated
  28280. },
  28281. ///////////////////////////////////////////////////////
  28282. // Functions for converting an item to a TreeNode
  28283. getLabel: function(/*dojo.data.Item*/ item){
  28284. // summary:
  28285. // Overridable function to get the label for a tree node (given the item)
  28286. // tags:
  28287. // extension
  28288. return this.model.getLabel(item); // String
  28289. },
  28290. getIconClass: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
  28291. // summary:
  28292. // Overridable function to return CSS class name to display icon
  28293. // tags:
  28294. // extension
  28295. return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "dijitLeaf"
  28296. },
  28297. getLabelClass: function(/*===== item, opened =====*/){
  28298. // summary:
  28299. // Overridable function to return CSS class name to display label
  28300. // item: dojo.data.Item
  28301. // opened: Boolean
  28302. // returns: String
  28303. // CSS class name
  28304. // tags:
  28305. // extension
  28306. },
  28307. getRowClass: function(/*===== item, opened =====*/){
  28308. // summary:
  28309. // Overridable function to return CSS class name to display row
  28310. // item: dojo.data.Item
  28311. // opened: Boolean
  28312. // returns: String
  28313. // CSS class name
  28314. // tags:
  28315. // extension
  28316. },
  28317. getIconStyle: function(/*===== item, opened =====*/){
  28318. // summary:
  28319. // Overridable function to return CSS styles to display icon
  28320. // item: dojo.data.Item
  28321. // opened: Boolean
  28322. // returns: Object
  28323. // Object suitable for input to dojo.style() like {backgroundImage: "url(...)"}
  28324. // tags:
  28325. // extension
  28326. },
  28327. getLabelStyle: function(/*===== item, opened =====*/){
  28328. // summary:
  28329. // Overridable function to return CSS styles to display label
  28330. // item: dojo.data.Item
  28331. // opened: Boolean
  28332. // returns:
  28333. // Object suitable for input to dojo.style() like {color: "red", background: "green"}
  28334. // tags:
  28335. // extension
  28336. },
  28337. getRowStyle: function(/*===== item, opened =====*/){
  28338. // summary:
  28339. // Overridable function to return CSS styles to display row
  28340. // item: dojo.data.Item
  28341. // opened: Boolean
  28342. // returns:
  28343. // Object suitable for input to dojo.style() like {background-color: "#bbb"}
  28344. // tags:
  28345. // extension
  28346. },
  28347. getTooltip: function(/*dojo.data.Item*/ /*===== item =====*/){
  28348. // summary:
  28349. // Overridable function to get the tooltip for a tree node (given the item)
  28350. // tags:
  28351. // extension
  28352. return ""; // String
  28353. },
  28354. /////////// Keyboard and Mouse handlers ////////////////////
  28355. _onKeyPress: function(/*dijit.TreeNode*/ treeNode, /*Event*/ e){
  28356. // summary:
  28357. // Handles keystrokes for printable keys, doing search navigation
  28358. if(e.charCode <= 32){
  28359. // Avoid duplicate events on firefox (this is an arrow key that will be handled by keydown handler)
  28360. return;
  28361. }
  28362. if(!e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey){
  28363. var c = String.fromCharCode(e.charCode);
  28364. this._onLetterKeyNav( { node: treeNode, key: c.toLowerCase() } );
  28365. event.stop(e);
  28366. }
  28367. },
  28368. _onKeyDown: function(/*dijit.TreeNode*/ treeNode, /*Event*/ e){
  28369. // summary:
  28370. // Handles arrow, space, and enter keys
  28371. var key = e.keyCode;
  28372. var map = this._keyHandlerMap;
  28373. if(!map){
  28374. // setup table mapping keys to events
  28375. map = {};
  28376. map[keys.ENTER]="_onEnterKey";
  28377. //On WebKit based browsers, the combination ctrl-enter
  28378. //does not get passed through. To allow accessible
  28379. //multi-select on those browsers, the space key is
  28380. //also used for selection.
  28381. map[keys.SPACE]= map[" "] = "_onEnterKey";
  28382. map[this.isLeftToRight() ? keys.LEFT_ARROW : keys.RIGHT_ARROW]="_onLeftArrow";
  28383. map[this.isLeftToRight() ? keys.RIGHT_ARROW : keys.LEFT_ARROW]="_onRightArrow";
  28384. map[keys.UP_ARROW]="_onUpArrow";
  28385. map[keys.DOWN_ARROW]="_onDownArrow";
  28386. map[keys.HOME]="_onHomeKey";
  28387. map[keys.END]="_onEndKey";
  28388. this._keyHandlerMap = map;
  28389. }
  28390. if(this._keyHandlerMap[key]){
  28391. // clear record of recent printables (being saved for multi-char letter navigation),
  28392. // because "a", down-arrow, "b" shouldn't search for "ab"
  28393. if(this._curSearch){
  28394. clearTimeout(this._curSearch.timer);
  28395. delete this._curSearch;
  28396. }
  28397. this[this._keyHandlerMap[key]]( { node: treeNode, item: treeNode.item, evt: e } );
  28398. event.stop(e);
  28399. }
  28400. },
  28401. _onEnterKey: function(/*Object*/ message){
  28402. this._publish("execute", { item: message.item, node: message.node } );
  28403. this.dndController.userSelect(message.node, connect.isCopyKey( message.evt ), message.evt.shiftKey);
  28404. this.onClick(message.item, message.node, message.evt);
  28405. },
  28406. _onDownArrow: function(/*Object*/ message){
  28407. // summary:
  28408. // down arrow pressed; get next visible node, set focus there
  28409. var node = this._getNextNode(message.node);
  28410. if(node && node.isTreeNode){
  28411. this.focusNode(node);
  28412. }
  28413. },
  28414. _onUpArrow: function(/*Object*/ message){
  28415. // summary:
  28416. // Up arrow pressed; move to previous visible node
  28417. var node = message.node;
  28418. // if younger siblings
  28419. var previousSibling = node.getPreviousSibling();
  28420. if(previousSibling){
  28421. node = previousSibling;
  28422. // if the previous node is expanded, dive in deep
  28423. while(node.isExpandable && node.isExpanded && node.hasChildren()){
  28424. // move to the last child
  28425. var children = node.getChildren();
  28426. node = children[children.length-1];
  28427. }
  28428. }else{
  28429. // if this is the first child, return the parent
  28430. // unless the parent is the root of a tree with a hidden root
  28431. var parent = node.getParent();
  28432. if(!(!this.showRoot && parent === this.rootNode)){
  28433. node = parent;
  28434. }
  28435. }
  28436. if(node && node.isTreeNode){
  28437. this.focusNode(node);
  28438. }
  28439. },
  28440. _onRightArrow: function(/*Object*/ message){
  28441. // summary:
  28442. // Right arrow pressed; go to child node
  28443. var node = message.node;
  28444. // if not expanded, expand, else move to 1st child
  28445. if(node.isExpandable && !node.isExpanded){
  28446. this._expandNode(node);
  28447. }else if(node.hasChildren()){
  28448. node = node.getChildren()[0];
  28449. if(node && node.isTreeNode){
  28450. this.focusNode(node);
  28451. }
  28452. }
  28453. },
  28454. _onLeftArrow: function(/*Object*/ message){
  28455. // summary:
  28456. // Left arrow pressed.
  28457. // If not collapsed, collapse, else move to parent.
  28458. var node = message.node;
  28459. if(node.isExpandable && node.isExpanded){
  28460. this._collapseNode(node);
  28461. }else{
  28462. var parent = node.getParent();
  28463. if(parent && parent.isTreeNode && !(!this.showRoot && parent === this.rootNode)){
  28464. this.focusNode(parent);
  28465. }
  28466. }
  28467. },
  28468. _onHomeKey: function(){
  28469. // summary:
  28470. // Home key pressed; get first visible node, and set focus there
  28471. var node = this._getRootOrFirstNode();
  28472. if(node){
  28473. this.focusNode(node);
  28474. }
  28475. },
  28476. _onEndKey: function(){
  28477. // summary:
  28478. // End key pressed; go to last visible node.
  28479. var node = this.rootNode;
  28480. while(node.isExpanded){
  28481. var c = node.getChildren();
  28482. node = c[c.length - 1];
  28483. }
  28484. if(node && node.isTreeNode){
  28485. this.focusNode(node);
  28486. }
  28487. },
  28488. // multiCharSearchDuration: Number
  28489. // If multiple characters are typed where each keystroke happens within
  28490. // multiCharSearchDuration of the previous keystroke,
  28491. // search for nodes matching all the keystrokes.
  28492. //
  28493. // For example, typing "ab" will search for entries starting with
  28494. // "ab" unless the delay between "a" and "b" is greater than multiCharSearchDuration.
  28495. multiCharSearchDuration: 250,
  28496. _onLetterKeyNav: function(message){
  28497. // summary:
  28498. // Called when user presses a prinatable key; search for node starting with recently typed letters.
  28499. // message: Object
  28500. // Like { node: TreeNode, key: 'a' } where key is the key the user pressed.
  28501. // Branch depending on whether this key starts a new search, or modifies an existing search
  28502. var cs = this._curSearch;
  28503. if(cs){
  28504. // We are continuing a search. Ex: user has pressed 'a', and now has pressed
  28505. // 'b', so we want to search for nodes starting w/"ab".
  28506. cs.pattern = cs.pattern + message.key;
  28507. clearTimeout(cs.timer);
  28508. }else{
  28509. // We are starting a new search
  28510. cs = this._curSearch = {
  28511. pattern: message.key,
  28512. startNode: message.node
  28513. };
  28514. }
  28515. // set/reset timer to forget recent keystrokes
  28516. var self = this;
  28517. cs.timer = setTimeout(function(){
  28518. delete self._curSearch;
  28519. }, this.multiCharSearchDuration);
  28520. // Navigate to TreeNode matching keystrokes [entered so far].
  28521. var node = cs.startNode;
  28522. do{
  28523. node = this._getNextNode(node);
  28524. //check for last node, jump to first node if necessary
  28525. if(!node){
  28526. node = this._getRootOrFirstNode();
  28527. }
  28528. }while(node !== cs.startNode && (node.label.toLowerCase().substr(0, cs.pattern.length) != cs.pattern));
  28529. if(node && node.isTreeNode){
  28530. // no need to set focus if back where we started
  28531. if(node !== cs.startNode){
  28532. this.focusNode(node);
  28533. }
  28534. }
  28535. },
  28536. isExpandoNode: function(node, widget){
  28537. // summary:
  28538. // check whether a dom node is the expandoNode for a particular TreeNode widget
  28539. return dom.isDescendant(node, widget.expandoNode);
  28540. },
  28541. _onClick: function(/*TreeNode*/ nodeWidget, /*Event*/ e){
  28542. // summary:
  28543. // Translates click events into commands for the controller to process
  28544. var domElement = e.target,
  28545. isExpandoClick = this.isExpandoNode(domElement, nodeWidget);
  28546. if( (this.openOnClick && nodeWidget.isExpandable) || isExpandoClick ){
  28547. // expando node was clicked, or label of a folder node was clicked; open it
  28548. if(nodeWidget.isExpandable){
  28549. this._onExpandoClick({node:nodeWidget});
  28550. }
  28551. }else{
  28552. this._publish("execute", { item: nodeWidget.item, node: nodeWidget, evt: e } );
  28553. this.onClick(nodeWidget.item, nodeWidget, e);
  28554. this.focusNode(nodeWidget);
  28555. }
  28556. event.stop(e);
  28557. },
  28558. _onDblClick: function(/*TreeNode*/ nodeWidget, /*Event*/ e){
  28559. // summary:
  28560. // Translates double-click events into commands for the controller to process
  28561. var domElement = e.target,
  28562. isExpandoClick = (domElement == nodeWidget.expandoNode || domElement == nodeWidget.expandoNodeText);
  28563. if( (this.openOnDblClick && nodeWidget.isExpandable) ||isExpandoClick ){
  28564. // expando node was clicked, or label of a folder node was clicked; open it
  28565. if(nodeWidget.isExpandable){
  28566. this._onExpandoClick({node:nodeWidget});
  28567. }
  28568. }else{
  28569. this._publish("execute", { item: nodeWidget.item, node: nodeWidget, evt: e } );
  28570. this.onDblClick(nodeWidget.item, nodeWidget, e);
  28571. this.focusNode(nodeWidget);
  28572. }
  28573. event.stop(e);
  28574. },
  28575. _onExpandoClick: function(/*Object*/ message){
  28576. // summary:
  28577. // User clicked the +/- icon; expand or collapse my children.
  28578. var node = message.node;
  28579. // If we are collapsing, we might be hiding the currently focused node.
  28580. // Also, clicking the expando node might have erased focus from the current node.
  28581. // For simplicity's sake just focus on the node with the expando.
  28582. this.focusNode(node);
  28583. if(node.isExpanded){
  28584. this._collapseNode(node);
  28585. }else{
  28586. this._expandNode(node);
  28587. }
  28588. },
  28589. onClick: function(/*===== item, node, evt =====*/){
  28590. // summary:
  28591. // Callback when a tree node is clicked
  28592. // item: dojo.data.Item
  28593. // node: TreeNode
  28594. // evt: Event
  28595. // tags:
  28596. // callback
  28597. },
  28598. onDblClick: function(/*===== item, node, evt =====*/){
  28599. // summary:
  28600. // Callback when a tree node is double-clicked
  28601. // item: dojo.data.Item
  28602. // node: TreeNode
  28603. // evt: Event
  28604. // tags:
  28605. // callback
  28606. },
  28607. onOpen: function(/*===== item, node =====*/){
  28608. // summary:
  28609. // Callback when a node is opened
  28610. // item: dojo.data.Item
  28611. // node: TreeNode
  28612. // tags:
  28613. // callback
  28614. },
  28615. onClose: function(/*===== item, node =====*/){
  28616. // summary:
  28617. // Callback when a node is closed
  28618. // item: dojo.data.Item
  28619. // node: TreeNode
  28620. // tags:
  28621. // callback
  28622. },
  28623. _getNextNode: function(node){
  28624. // summary:
  28625. // Get next visible node
  28626. if(node.isExpandable && node.isExpanded && node.hasChildren()){
  28627. // if this is an expanded node, get the first child
  28628. return node.getChildren()[0]; // _TreeNode
  28629. }else{
  28630. // find a parent node with a sibling
  28631. while(node && node.isTreeNode){
  28632. var returnNode = node.getNextSibling();
  28633. if(returnNode){
  28634. return returnNode; // _TreeNode
  28635. }
  28636. node = node.getParent();
  28637. }
  28638. return null;
  28639. }
  28640. },
  28641. _getRootOrFirstNode: function(){
  28642. // summary:
  28643. // Get first visible node
  28644. return this.showRoot ? this.rootNode : this.rootNode.getChildren()[0];
  28645. },
  28646. _collapseNode: function(/*_TreeNode*/ node){
  28647. // summary:
  28648. // Called when the user has requested to collapse the node
  28649. if(node._expandNodeDeferred){
  28650. delete node._expandNodeDeferred;
  28651. }
  28652. if(node.isExpandable){
  28653. if(node.state == "LOADING"){
  28654. // ignore clicks while we are in the process of loading data
  28655. return;
  28656. }
  28657. node.collapse();
  28658. this.onClose(node.item, node);
  28659. this._state(node, false);
  28660. }
  28661. },
  28662. _expandNode: function(/*_TreeNode*/ node, /*Boolean?*/ recursive){
  28663. // summary:
  28664. // Called when the user has requested to expand the node
  28665. // recursive:
  28666. // Internal flag used when _expandNode() calls itself, don't set.
  28667. // returns:
  28668. // Deferred that fires when the node is loaded and opened and (if persist=true) all it's descendants
  28669. // that were previously opened too
  28670. if(node._expandNodeDeferred && !recursive){
  28671. // there's already an expand in progress (or completed), so just return
  28672. return node._expandNodeDeferred; // dojo.Deferred
  28673. }
  28674. var model = this.model,
  28675. item = node.item,
  28676. _this = this;
  28677. switch(node.state){
  28678. case "UNCHECKED":
  28679. // need to load all the children, and then expand
  28680. node.markProcessing();
  28681. // Setup deferred to signal when the load and expand are finished.
  28682. // Save that deferred in this._expandDeferred as a flag that operation is in progress.
  28683. var def = (node._expandNodeDeferred = new Deferred());
  28684. // Get the children
  28685. model.getChildren(
  28686. item,
  28687. function(items){
  28688. node.unmarkProcessing();
  28689. // Display the children and also start expanding any children that were previously expanded
  28690. // (if this.persist == true). The returned Deferred will fire when those expansions finish.
  28691. var scid = node.setChildItems(items);
  28692. // Call _expandNode() again but this time it will just to do the animation (default branch).
  28693. // The returned Deferred will fire when the animation completes.
  28694. // TODO: seems like I can avoid recursion and just use a deferred to sequence the events?
  28695. var ed = _this._expandNode(node, true);
  28696. // After the above two tasks (setChildItems() and recursive _expandNode()) finish,
  28697. // signal that I am done.
  28698. scid.addCallback(function(){
  28699. ed.addCallback(function(){
  28700. def.callback();
  28701. })
  28702. });
  28703. },
  28704. function(err){
  28705. console.error(_this, ": error loading root children: ", err);
  28706. }
  28707. );
  28708. break;
  28709. default: // "LOADED"
  28710. // data is already loaded; just expand node
  28711. def = (node._expandNodeDeferred = node.expand());
  28712. this.onOpen(node.item, node);
  28713. this._state(node, true);
  28714. }
  28715. return def; // dojo.Deferred
  28716. },
  28717. ////////////////// Miscellaneous functions ////////////////
  28718. focusNode: function(/* _tree.Node */ node){
  28719. // summary:
  28720. // Focus on the specified node (which must be visible)
  28721. // tags:
  28722. // protected
  28723. // set focus so that the label will be voiced using screen readers
  28724. focus.focus(node.labelNode);
  28725. },
  28726. _onNodeFocus: function(/*dijit._Widget*/ node){
  28727. // summary:
  28728. // Called when a TreeNode gets focus, either by user clicking
  28729. // it, or programatically by arrow key handling code.
  28730. // description:
  28731. // It marks that the current node is the selected one, and the previously
  28732. // selected node no longer is.
  28733. if(node && node != this.lastFocused){
  28734. if(this.lastFocused && !this.lastFocused._destroyed){
  28735. // mark that the previously focsable node is no longer focusable
  28736. this.lastFocused.setFocusable(false);
  28737. }
  28738. // mark that the new node is the currently selected one
  28739. node.setFocusable(true);
  28740. this.lastFocused = node;
  28741. }
  28742. },
  28743. _onNodeMouseEnter: function(/*dijit._Widget*/ /*===== node =====*/){
  28744. // summary:
  28745. // Called when mouse is over a node (onmouseenter event),
  28746. // this is monitored by the DND code
  28747. },
  28748. _onNodeMouseLeave: function(/*dijit._Widget*/ /*===== node =====*/){
  28749. // summary:
  28750. // Called when mouse leaves a node (onmouseleave event),
  28751. // this is monitored by the DND code
  28752. },
  28753. //////////////// Events from the model //////////////////////////
  28754. _onItemChange: function(/*Item*/ item){
  28755. // summary:
  28756. // Processes notification of a change to an item's scalar values like label
  28757. var model = this.model,
  28758. identity = model.getIdentity(item),
  28759. nodes = this._itemNodesMap[identity];
  28760. if(nodes){
  28761. var label = this.getLabel(item),
  28762. tooltip = this.getTooltip(item);
  28763. array.forEach(nodes, function(node){
  28764. node.set({
  28765. item: item, // theoretically could be new JS Object representing same item
  28766. label: label,
  28767. tooltip: tooltip
  28768. });
  28769. node._updateItemClasses(item);
  28770. });
  28771. }
  28772. },
  28773. _onItemChildrenChange: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
  28774. // summary:
  28775. // Processes notification of a change to an item's children
  28776. var model = this.model,
  28777. identity = model.getIdentity(parent),
  28778. parentNodes = this._itemNodesMap[identity];
  28779. if(parentNodes){
  28780. array.forEach(parentNodes,function(parentNode){
  28781. parentNode.setChildItems(newChildrenList);
  28782. });
  28783. }
  28784. },
  28785. _onItemDelete: function(/*Item*/ item){
  28786. // summary:
  28787. // Processes notification of a deletion of an item
  28788. var model = this.model,
  28789. identity = model.getIdentity(item),
  28790. nodes = this._itemNodesMap[identity];
  28791. if(nodes){
  28792. array.forEach(nodes,function(node){
  28793. // Remove node from set of selected nodes (if it's selected)
  28794. this.dndController.removeTreeNode(node);
  28795. var parent = node.getParent();
  28796. if(parent){
  28797. // if node has not already been orphaned from a _onSetItem(parent, "children", ..) call...
  28798. parent.removeChild(node);
  28799. }
  28800. node.destroyRecursive();
  28801. }, this);
  28802. delete this._itemNodesMap[identity];
  28803. }
  28804. },
  28805. /////////////// Miscellaneous funcs
  28806. _initState: function(){
  28807. // summary:
  28808. // Load in which nodes should be opened automatically
  28809. this._openedNodes = {};
  28810. if(this.persist && this.cookieName){
  28811. var oreo = cookie(this.cookieName);
  28812. if(oreo){
  28813. array.forEach(oreo.split(','), function(item){
  28814. this._openedNodes[item] = true;
  28815. }, this);
  28816. }
  28817. }
  28818. },
  28819. _state: function(node, expanded){
  28820. // summary:
  28821. // Query or set expanded state for an node
  28822. if(!this.persist){
  28823. return false;
  28824. }
  28825. var path = array.map(node.getTreePath(), function(item){
  28826. return this.model.getIdentity(item);
  28827. }, this).join("/");
  28828. if(arguments.length === 1){
  28829. return this._openedNodes[path];
  28830. }else{
  28831. if(expanded){
  28832. this._openedNodes[path] = true;
  28833. }else{
  28834. delete this._openedNodes[path];
  28835. }
  28836. var ary = [];
  28837. for(var id in this._openedNodes){
  28838. ary.push(id);
  28839. }
  28840. cookie(this.cookieName, ary.join(","), {expires:365});
  28841. }
  28842. },
  28843. destroy: function(){
  28844. if(this._curSearch){
  28845. clearTimeout(this._curSearch.timer);
  28846. delete this._curSearch;
  28847. }
  28848. if(this.rootNode){
  28849. this.rootNode.destroyRecursive();
  28850. }
  28851. if(this.dndController && !lang.isString(this.dndController)){
  28852. this.dndController.destroy();
  28853. }
  28854. this.rootNode = null;
  28855. this.inherited(arguments);
  28856. },
  28857. destroyRecursive: function(){
  28858. // A tree is treated as a leaf, not as a node with children (like a grid),
  28859. // but defining destroyRecursive for back-compat.
  28860. this.destroy();
  28861. },
  28862. resize: function(changeSize){
  28863. if(changeSize){
  28864. domGeometry.setMarginBox(this.domNode, changeSize);
  28865. }
  28866. // The only JS sizing involved w/tree is the indentation, which is specified
  28867. // in CSS and read in through this dummy indentDetector node (tree must be
  28868. // visible and attached to the DOM to read this)
  28869. this._nodePixelIndent = domGeometry.position(this.tree.indentDetector).w;
  28870. if(this.tree.rootNode){
  28871. // If tree has already loaded, then reset indent for all the nodes
  28872. this.tree.rootNode.set('indent', this.showRoot ? 0 : -1);
  28873. }
  28874. },
  28875. _createTreeNode: function(/*Object*/ args){
  28876. // summary:
  28877. // creates a TreeNode
  28878. // description:
  28879. // Developers can override this method to define their own TreeNode class;
  28880. // However it will probably be removed in a future release in favor of a way
  28881. // of just specifying a widget for the label, rather than one that contains
  28882. // the children too.
  28883. return new TreeNode(args);
  28884. },
  28885. _setTextDirAttr: function(textDir){
  28886. if(textDir && this.textDir!= textDir){
  28887. this._set("textDir",textDir);
  28888. this.rootNode.set("textDir", textDir);
  28889. }
  28890. }
  28891. });
  28892. Tree._TreeNode = TreeNode; // for monkey patching
  28893. return Tree;
  28894. });
  28895. },
  28896. 'dijit/form/HorizontalSlider':function(){
  28897. define([
  28898. "dojo/_base/array", // array.forEach
  28899. "dojo/_base/declare", // declare
  28900. "dojo/dnd/move",
  28901. "dojo/_base/event", // event.stop
  28902. "dojo/_base/fx", // fx.animateProperty
  28903. "dojo/dom-geometry", // domGeometry.position
  28904. "dojo/dom-style", // domStyle.getComputedStyle
  28905. "dojo/keys", // keys.DOWN_ARROW keys.END keys.HOME keys.LEFT_ARROW keys.PAGE_DOWN keys.PAGE_UP keys.RIGHT_ARROW keys.UP_ARROW
  28906. "dojo/_base/lang", // lang.hitch
  28907. "dojo/_base/sniff", // has("ie") has("mozilla")
  28908. "dojo/dnd/Moveable", // Moveable
  28909. "dojo/dnd/Mover", // Mover Mover.prototype.destroy.apply
  28910. "dojo/query", // query
  28911. "../registry", // registry.findWidgets
  28912. "../focus", // focus.focus()
  28913. "../typematic",
  28914. "./Button",
  28915. "./_FormValueWidget",
  28916. "../_Container",
  28917. "dojo/text!./templates/HorizontalSlider.html"
  28918. ], function(array, declare, move, event, fx, domGeometry, domStyle, keys, lang, has, Moveable, Mover, query,
  28919. registry, focus, typematic, Button, _FormValueWidget, _Container, template){
  28920. /*=====
  28921. var Button = dijit.form.Button;
  28922. var _FormValueWidget = dijit.form._FormValueWidget;
  28923. var _Container = dijit._Container;
  28924. =====*/
  28925. // module:
  28926. // dijit/form/HorizontalSlider
  28927. // summary:
  28928. // A form widget that allows one to select a value with a horizontally draggable handle
  28929. var _SliderMover = declare("dijit.form._SliderMover", Mover, {
  28930. onMouseMove: function(e){
  28931. var widget = this.widget;
  28932. var abspos = widget._abspos;
  28933. if(!abspos){
  28934. abspos = widget._abspos = domGeometry.position(widget.sliderBarContainer, true);
  28935. widget._setPixelValue_ = lang.hitch(widget, "_setPixelValue");
  28936. widget._isReversed_ = widget._isReversed();
  28937. }
  28938. var pixelValue = e[widget._mousePixelCoord] - abspos[widget._startingPixelCoord];
  28939. widget._setPixelValue_(widget._isReversed_ ? (abspos[widget._pixelCount]-pixelValue) : pixelValue, abspos[widget._pixelCount], false);
  28940. },
  28941. destroy: function(e){
  28942. Mover.prototype.destroy.apply(this, arguments);
  28943. var widget = this.widget;
  28944. widget._abspos = null;
  28945. widget._setValueAttr(widget.value, true);
  28946. }
  28947. });
  28948. var HorizontalSlider = declare("dijit.form.HorizontalSlider", [_FormValueWidget, _Container], {
  28949. // summary:
  28950. // A form widget that allows one to select a value with a horizontally draggable handle
  28951. templateString: template,
  28952. // Overrides FormValueWidget.value to indicate numeric value
  28953. value: 0,
  28954. // showButtons: [const] Boolean
  28955. // Show increment/decrement buttons at the ends of the slider?
  28956. showButtons: true,
  28957. // minimum:: [const] Integer
  28958. // The minimum value the slider can be set to.
  28959. minimum: 0,
  28960. // maximum: [const] Integer
  28961. // The maximum value the slider can be set to.
  28962. maximum: 100,
  28963. // discreteValues: Integer
  28964. // If specified, indicates that the slider handle has only 'discreteValues' possible positions,
  28965. // and that after dragging the handle, it will snap to the nearest possible position.
  28966. // Thus, the slider has only 'discreteValues' possible values.
  28967. //
  28968. // For example, if minimum=10, maxiumum=30, and discreteValues=3, then the slider handle has
  28969. // three possible positions, representing values 10, 20, or 30.
  28970. //
  28971. // If discreteValues is not specified or if it's value is higher than the number of pixels
  28972. // in the slider bar, then the slider handle can be moved freely, and the slider's value will be
  28973. // computed/reported based on pixel position (in this case it will likely be fractional,
  28974. // such as 123.456789).
  28975. discreteValues: Infinity,
  28976. // pageIncrement: Integer
  28977. // If discreteValues is also specified, this indicates the amount of clicks (ie, snap positions)
  28978. // that the slider handle is moved via pageup/pagedown keys.
  28979. // If discreteValues is not specified, it indicates the number of pixels.
  28980. pageIncrement: 2,
  28981. // clickSelect: Boolean
  28982. // If clicking the slider bar changes the value or not
  28983. clickSelect: true,
  28984. // slideDuration: Number
  28985. // The time in ms to take to animate the slider handle from 0% to 100%,
  28986. // when clicking the slider bar to make the handle move.
  28987. slideDuration: registry.defaultDuration,
  28988. // Map widget attributes to DOMNode attributes.
  28989. _setIdAttr: "", // Override _FormWidget which sends id to focusNode
  28990. baseClass: "dijitSlider",
  28991. // Apply CSS classes to up/down arrows and handle per mouse state
  28992. cssStateNodes: {
  28993. incrementButton: "dijitSliderIncrementButton",
  28994. decrementButton: "dijitSliderDecrementButton",
  28995. focusNode: "dijitSliderThumb"
  28996. },
  28997. _mousePixelCoord: "pageX",
  28998. _pixelCount: "w",
  28999. _startingPixelCoord: "x",
  29000. _handleOffsetCoord: "left",
  29001. _progressPixelSize: "width",
  29002. _onKeyUp: function(/*Event*/ e){
  29003. if(this.disabled || this.readOnly || e.altKey || e.ctrlKey || e.metaKey){ return; }
  29004. this._setValueAttr(this.value, true);
  29005. },
  29006. _onKeyPress: function(/*Event*/ e){
  29007. if(this.disabled || this.readOnly || e.altKey || e.ctrlKey || e.metaKey){ return; }
  29008. switch(e.charOrCode){
  29009. case keys.HOME:
  29010. this._setValueAttr(this.minimum, false);
  29011. break;
  29012. case keys.END:
  29013. this._setValueAttr(this.maximum, false);
  29014. break;
  29015. // this._descending === false: if ascending vertical (min on top)
  29016. // (this._descending || this.isLeftToRight()): if left-to-right horizontal or descending vertical
  29017. case ((this._descending || this.isLeftToRight()) ? keys.RIGHT_ARROW : keys.LEFT_ARROW):
  29018. case (this._descending === false ? keys.DOWN_ARROW : keys.UP_ARROW):
  29019. case (this._descending === false ? keys.PAGE_DOWN : keys.PAGE_UP):
  29020. this.increment(e);
  29021. break;
  29022. case ((this._descending || this.isLeftToRight()) ? keys.LEFT_ARROW : keys.RIGHT_ARROW):
  29023. case (this._descending === false ? keys.UP_ARROW : keys.DOWN_ARROW):
  29024. case (this._descending === false ? keys.PAGE_UP : keys.PAGE_DOWN):
  29025. this.decrement(e);
  29026. break;
  29027. default:
  29028. return;
  29029. }
  29030. event.stop(e);
  29031. },
  29032. _onHandleClick: function(e){
  29033. if(this.disabled || this.readOnly){ return; }
  29034. if(!has("ie")){
  29035. // make sure you get focus when dragging the handle
  29036. // (but don't do on IE because it causes a flicker on mouse up (due to blur then focus)
  29037. focus.focus(this.sliderHandle);
  29038. }
  29039. event.stop(e);
  29040. },
  29041. _isReversed: function(){
  29042. // summary:
  29043. // Returns true if direction is from right to left
  29044. // tags:
  29045. // protected extension
  29046. return !this.isLeftToRight();
  29047. },
  29048. _onBarClick: function(e){
  29049. if(this.disabled || this.readOnly || !this.clickSelect){ return; }
  29050. focus.focus(this.sliderHandle);
  29051. event.stop(e);
  29052. var abspos = domGeometry.position(this.sliderBarContainer, true);
  29053. var pixelValue = e[this._mousePixelCoord] - abspos[this._startingPixelCoord];
  29054. this._setPixelValue(this._isReversed() ? (abspos[this._pixelCount] - pixelValue) : pixelValue, abspos[this._pixelCount], true);
  29055. this._movable.onMouseDown(e);
  29056. },
  29057. _setPixelValue: function(/*Number*/ pixelValue, /*Number*/ maxPixels, /*Boolean?*/ priorityChange){
  29058. if(this.disabled || this.readOnly){ return; }
  29059. var count = this.discreteValues;
  29060. if(count <= 1 || count == Infinity){ count = maxPixels; }
  29061. count--;
  29062. var pixelsPerValue = maxPixels / count;
  29063. var wholeIncrements = Math.round(pixelValue / pixelsPerValue);
  29064. this._setValueAttr(Math.max(Math.min((this.maximum-this.minimum)*wholeIncrements/count + this.minimum, this.maximum), this.minimum), priorityChange);
  29065. },
  29066. _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange){
  29067. // summary:
  29068. // Hook so set('value', value) works.
  29069. this._set("value", value);
  29070. this.valueNode.value = value;
  29071. this.focusNode.setAttribute("aria-valuenow", value);
  29072. this.inherited(arguments);
  29073. var percent = (value - this.minimum) / (this.maximum - this.minimum);
  29074. var progressBar = (this._descending === false) ? this.remainingBar : this.progressBar;
  29075. var remainingBar = (this._descending === false) ? this.progressBar : this.remainingBar;
  29076. if(this._inProgressAnim && this._inProgressAnim.status != "stopped"){
  29077. this._inProgressAnim.stop(true);
  29078. }
  29079. if(priorityChange && this.slideDuration > 0 && progressBar.style[this._progressPixelSize]){
  29080. // animate the slider
  29081. var _this = this;
  29082. var props = {};
  29083. var start = parseFloat(progressBar.style[this._progressPixelSize]);
  29084. var duration = this.slideDuration * (percent-start/100);
  29085. if(duration == 0){ return; }
  29086. if(duration < 0){ duration = 0 - duration; }
  29087. props[this._progressPixelSize] = { start: start, end: percent*100, units:"%" };
  29088. this._inProgressAnim = fx.animateProperty({ node: progressBar, duration: duration,
  29089. onAnimate: function(v){
  29090. remainingBar.style[_this._progressPixelSize] = (100 - parseFloat(v[_this._progressPixelSize])) + "%";
  29091. },
  29092. onEnd: function(){
  29093. delete _this._inProgressAnim;
  29094. },
  29095. properties: props
  29096. });
  29097. this._inProgressAnim.play();
  29098. }else{
  29099. progressBar.style[this._progressPixelSize] = (percent*100) + "%";
  29100. remainingBar.style[this._progressPixelSize] = ((1-percent)*100) + "%";
  29101. }
  29102. },
  29103. _bumpValue: function(signedChange, /*Boolean?*/ priorityChange){
  29104. if(this.disabled || this.readOnly){ return; }
  29105. var s = domStyle.getComputedStyle(this.sliderBarContainer);
  29106. var c = domGeometry.getContentBox(this.sliderBarContainer, s);
  29107. var count = this.discreteValues;
  29108. if(count <= 1 || count == Infinity){ count = c[this._pixelCount]; }
  29109. count--;
  29110. var value = (this.value - this.minimum) * count / (this.maximum - this.minimum) + signedChange;
  29111. if(value < 0){ value = 0; }
  29112. if(value > count){ value = count; }
  29113. value = value * (this.maximum - this.minimum) / count + this.minimum;
  29114. this._setValueAttr(value, priorityChange);
  29115. },
  29116. _onClkBumper: function(val){
  29117. if(this.disabled || this.readOnly || !this.clickSelect){ return; }
  29118. this._setValueAttr(val, true);
  29119. },
  29120. _onClkIncBumper: function(){
  29121. this._onClkBumper(this._descending === false ? this.minimum : this.maximum);
  29122. },
  29123. _onClkDecBumper: function(){
  29124. this._onClkBumper(this._descending === false ? this.maximum : this.minimum);
  29125. },
  29126. decrement: function(/*Event*/ e){
  29127. // summary:
  29128. // Decrement slider
  29129. // tags:
  29130. // private
  29131. this._bumpValue(e.charOrCode == keys.PAGE_DOWN ? -this.pageIncrement : -1);
  29132. },
  29133. increment: function(/*Event*/ e){
  29134. // summary:
  29135. // Increment slider
  29136. // tags:
  29137. // private
  29138. this._bumpValue(e.charOrCode == keys.PAGE_UP ? this.pageIncrement : 1);
  29139. },
  29140. _mouseWheeled: function(/*Event*/ evt){
  29141. // summary:
  29142. // Event handler for mousewheel where supported
  29143. event.stop(evt);
  29144. var janky = !has("mozilla");
  29145. var scroll = evt[(janky ? "wheelDelta" : "detail")] * (janky ? 1 : -1);
  29146. this._bumpValue(scroll < 0 ? -1 : 1, true); // negative scroll acts like a decrement
  29147. },
  29148. startup: function(){
  29149. if(this._started){ return; }
  29150. array.forEach(this.getChildren(), function(child){
  29151. if(this[child.container] != this.containerNode){
  29152. this[child.container].appendChild(child.domNode);
  29153. }
  29154. }, this);
  29155. this.inherited(arguments);
  29156. },
  29157. _typematicCallback: function(/*Number*/ count, /*Object*/ button, /*Event*/ e){
  29158. if(count == -1){
  29159. this._setValueAttr(this.value, true);
  29160. }else{
  29161. this[(button == (this._descending? this.incrementButton : this.decrementButton)) ? "decrement" : "increment"](e);
  29162. }
  29163. },
  29164. buildRendering: function(){
  29165. this.inherited(arguments);
  29166. if(this.showButtons){
  29167. this.incrementButton.style.display="";
  29168. this.decrementButton.style.display="";
  29169. }
  29170. // find any associated label element and add to slider focusnode.
  29171. var label = query('label[for="'+this.id+'"]');
  29172. if(label.length){
  29173. label[0].id = (this.id+"_label");
  29174. this.focusNode.setAttribute("aria-labelledby", label[0].id);
  29175. }
  29176. this.focusNode.setAttribute("aria-valuemin", this.minimum);
  29177. this.focusNode.setAttribute("aria-valuemax", this.maximum);
  29178. },
  29179. postCreate: function(){
  29180. this.inherited(arguments);
  29181. if(this.showButtons){
  29182. this._connects.push(typematic.addMouseListener(
  29183. this.decrementButton, this, "_typematicCallback", 25, 500));
  29184. this._connects.push(typematic.addMouseListener(
  29185. this.incrementButton, this, "_typematicCallback", 25, 500));
  29186. }
  29187. this.connect(this.domNode, !has("mozilla") ? "onmousewheel" : "DOMMouseScroll", "_mouseWheeled");
  29188. // define a custom constructor for a SliderMover that points back to me
  29189. var mover = declare(_SliderMover, {
  29190. widget: this
  29191. });
  29192. this._movable = new Moveable(this.sliderHandle, {mover: mover});
  29193. this._layoutHackIE7();
  29194. },
  29195. destroy: function(){
  29196. this._movable.destroy();
  29197. if(this._inProgressAnim && this._inProgressAnim.status != "stopped"){
  29198. this._inProgressAnim.stop(true);
  29199. }
  29200. this._supportingWidgets = registry.findWidgets(this.domNode); // tells destroy about pseudo-child widgets (ruler/labels)
  29201. this.inherited(arguments);
  29202. }
  29203. });
  29204. HorizontalSlider._Mover = _SliderMover; // for monkey patching
  29205. return HorizontalSlider;
  29206. });
  29207. },
  29208. '*now':function(r){r(['dojo/i18n!*preload*dijit/nls/dijit-all*["ar","ca","cs","da","de","el","en-gb","en-us","es-es","fi-fi","fr-fr","he-il","hu","it-it","ja-jp","ko-kr","nl-nl","nb","pl","pt-br","pt-pt","ru","sk","sl","sv","th","tr","zh-tw","zh-cn","ROOT"]']);}
  29209. }});
  29210. define("dijit/dijit-all", [
  29211. ".",
  29212. "./dijit",
  29213. "./ColorPalette",
  29214. "./Declaration",
  29215. "./Dialog",
  29216. "./DialogUnderlay",
  29217. "./TooltipDialog",
  29218. "./Editor",
  29219. "./_editor/plugins/FontChoice",
  29220. "./_editor/plugins/LinkDialog",
  29221. "./Menu",
  29222. "./MenuItem",
  29223. "./PopupMenuItem",
  29224. "./CheckedMenuItem",
  29225. "./MenuBar",
  29226. "./MenuBarItem",
  29227. "./PopupMenuBarItem",
  29228. "./MenuSeparator",
  29229. "./ProgressBar",
  29230. "./TitlePane",
  29231. "./Toolbar",
  29232. "./Tooltip",
  29233. "./Tree",
  29234. "./InlineEditBox",
  29235. "./form/Form",
  29236. "./form/Button",
  29237. "./form/DropDownButton",
  29238. "./form/ComboButton",
  29239. "./form/ToggleButton",
  29240. "./form/CheckBox",
  29241. "./form/RadioButton",
  29242. "./form/TextBox",
  29243. "./form/ValidationTextBox",
  29244. "./form/CurrencyTextBox",
  29245. "./form/DateTextBox",
  29246. "./form/TimeTextBox",
  29247. "./form/NumberSpinner",
  29248. "./form/NumberTextBox",
  29249. "./form/ComboBox",
  29250. "./form/FilteringSelect",
  29251. "./form/MultiSelect",
  29252. "./form/Select",
  29253. "./form/HorizontalSlider",
  29254. "./form/VerticalSlider",
  29255. "./form/HorizontalRule",
  29256. "./form/VerticalRule",
  29257. "./form/HorizontalRuleLabels",
  29258. "./form/VerticalRuleLabels",
  29259. "./form/SimpleTextarea",
  29260. "./form/Textarea",
  29261. "./layout/AccordionContainer",
  29262. "./layout/ContentPane",
  29263. "./layout/BorderContainer",
  29264. "./layout/LayoutContainer",
  29265. "./layout/LinkPane",
  29266. "./layout/SplitContainer",
  29267. "./layout/StackContainer",
  29268. "./layout/TabContainer"
  29269. ], function(dijit){
  29270. // module:
  29271. // dijit/dijit-all
  29272. // summary:
  29273. // A rollup that includes every dijit. You probably don't need this.
  29274. console.warn("dijit-all may include much more code than your application actually requires. We strongly recommend that you investigate a custom build or the web build tool");
  29275. return dijit;
  29276. });