pddojo.js.uncompressed.js 1.4 MB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223262242622526226262272622826229262302623126232262332623426235262362623726238262392624026241262422624326244262452624626247262482624926250262512625226253262542625526256262572625826259262602626126262262632626426265262662626726268262692627026271262722627326274262752627626277262782627926280262812628226283262842628526286262872628826289262902629126292262932629426295262962629726298262992630026301263022630326304263052630626307263082630926310263112631226313263142631526316263172631826319263202632126322263232632426325263262632726328263292633026331263322633326334263352633626337263382633926340263412634226343263442634526346263472634826349263502635126352263532635426355263562635726358263592636026361263622636326364263652636626367263682636926370263712637226373263742637526376263772637826379263802638126382263832638426385263862638726388263892639026391263922639326394263952639626397263982639926400264012640226403264042640526406264072640826409264102641126412264132641426415264162641726418264192642026421264222642326424264252642626427264282642926430264312643226433264342643526436264372643826439264402644126442264432644426445264462644726448264492645026451264522645326454264552645626457264582645926460264612646226463264642646526466264672646826469264702647126472264732647426475264762647726478264792648026481264822648326484264852648626487264882648926490264912649226493264942649526496264972649826499265002650126502265032650426505265062650726508265092651026511265122651326514265152651626517265182651926520265212652226523265242652526526265272652826529265302653126532265332653426535265362653726538265392654026541265422654326544265452654626547265482654926550265512655226553265542655526556265572655826559265602656126562265632656426565265662656726568265692657026571265722657326574265752657626577265782657926580265812658226583265842658526586265872658826589265902659126592265932659426595265962659726598265992660026601266022660326604266052660626607266082660926610266112661226613266142661526616266172661826619266202662126622266232662426625266262662726628266292663026631266322663326634266352663626637266382663926640266412664226643266442664526646266472664826649266502665126652266532665426655266562665726658266592666026661266622666326664266652666626667266682666926670266712667226673266742667526676266772667826679266802668126682266832668426685266862668726688266892669026691266922669326694266952669626697266982669926700267012670226703267042670526706267072670826709267102671126712267132671426715267162671726718267192672026721267222672326724267252672626727267282672926730267312673226733267342673526736267372673826739267402674126742267432674426745267462674726748267492675026751267522675326754267552675626757267582675926760267612676226763267642676526766267672676826769267702677126772267732677426775267762677726778267792678026781267822678326784267852678626787267882678926790267912679226793267942679526796267972679826799268002680126802268032680426805268062680726808268092681026811268122681326814268152681626817268182681926820268212682226823268242682526826268272682826829268302683126832268332683426835268362683726838268392684026841268422684326844268452684626847268482684926850268512685226853268542685526856268572685826859268602686126862268632686426865268662686726868268692687026871268722687326874268752687626877268782687926880268812688226883268842688526886268872688826889268902689126892268932689426895268962689726898268992690026901269022690326904269052690626907269082690926910269112691226913269142691526916269172691826919269202692126922269232692426925269262692726928269292693026931269322693326934269352693626937269382693926940269412694226943269442694526946269472694826949269502695126952269532695426955269562695726958269592696026961269622696326964269652696626967269682696926970269712697226973269742697526976269772697826979269802698126982269832698426985269862698726988269892699026991269922699326994269952699626997269982699927000270012700227003270042700527006270072700827009270102701127012270132701427015270162701727018270192702027021270222702327024270252702627027270282702927030270312703227033270342703527036270372703827039270402704127042270432704427045270462704727048270492705027051270522705327054270552705627057270582705927060270612706227063270642706527066270672706827069270702707127072270732707427075270762707727078270792708027081270822708327084270852708627087270882708927090270912709227093270942709527096270972709827099271002710127102271032710427105271062710727108271092711027111271122711327114271152711627117271182711927120271212712227123271242712527126271272712827129271302713127132271332713427135271362713727138271392714027141271422714327144271452714627147271482714927150271512715227153271542715527156271572715827159271602716127162271632716427165271662716727168271692717027171271722717327174271752717627177271782717927180271812718227183271842718527186271872718827189271902719127192271932719427195271962719727198271992720027201272022720327204272052720627207272082720927210272112721227213272142721527216272172721827219272202722127222272232722427225272262722727228272292723027231272322723327234272352723627237272382723927240272412724227243272442724527246272472724827249272502725127252272532725427255272562725727258272592726027261272622726327264272652726627267272682726927270272712727227273272742727527276272772727827279272802728127282272832728427285272862728727288272892729027291272922729327294272952729627297272982729927300273012730227303273042730527306273072730827309273102731127312273132731427315273162731727318273192732027321273222732327324273252732627327273282732927330273312733227333273342733527336273372733827339273402734127342273432734427345273462734727348273492735027351273522735327354273552735627357273582735927360273612736227363273642736527366273672736827369273702737127372273732737427375273762737727378273792738027381273822738327384273852738627387273882738927390273912739227393273942739527396273972739827399274002740127402274032740427405274062740727408274092741027411274122741327414274152741627417274182741927420274212742227423274242742527426274272742827429274302743127432274332743427435274362743727438274392744027441274422744327444274452744627447274482744927450274512745227453274542745527456274572745827459274602746127462274632746427465274662746727468274692747027471274722747327474274752747627477274782747927480274812748227483274842748527486274872748827489274902749127492274932749427495274962749727498274992750027501275022750327504275052750627507275082750927510275112751227513275142751527516275172751827519275202752127522275232752427525275262752727528275292753027531275322753327534275352753627537275382753927540275412754227543275442754527546275472754827549275502755127552275532755427555275562755727558275592756027561275622756327564275652756627567275682756927570275712757227573275742757527576275772757827579275802758127582275832758427585275862758727588275892759027591275922759327594275952759627597275982759927600276012760227603276042760527606276072760827609276102761127612276132761427615276162761727618276192762027621276222762327624276252762627627276282762927630276312763227633276342763527636276372763827639276402764127642276432764427645276462764727648276492765027651276522765327654276552765627657276582765927660276612766227663276642766527666276672766827669276702767127672276732767427675276762767727678276792768027681276822768327684276852768627687276882768927690276912769227693276942769527696276972769827699277002770127702277032770427705277062770727708277092771027711277122771327714277152771627717277182771927720277212772227723277242772527726277272772827729277302773127732277332773427735277362773727738277392774027741277422774327744277452774627747277482774927750277512775227753277542775527756277572775827759277602776127762277632776427765277662776727768277692777027771277722777327774277752777627777277782777927780277812778227783277842778527786277872778827789277902779127792277932779427795277962779727798277992780027801278022780327804278052780627807278082780927810278112781227813278142781527816278172781827819278202782127822278232782427825278262782727828278292783027831278322783327834278352783627837278382783927840278412784227843278442784527846278472784827849278502785127852278532785427855278562785727858278592786027861278622786327864278652786627867278682786927870278712787227873278742787527876278772787827879278802788127882278832788427885278862788727888278892789027891278922789327894278952789627897278982789927900279012790227903279042790527906279072790827909279102791127912279132791427915279162791727918279192792027921279222792327924279252792627927279282792927930279312793227933279342793527936279372793827939279402794127942279432794427945279462794727948279492795027951279522795327954279552795627957279582795927960279612796227963279642796527966279672796827969279702797127972279732797427975279762797727978279792798027981279822798327984279852798627987279882798927990279912799227993279942799527996279972799827999280002800128002280032800428005280062800728008280092801028011280122801328014280152801628017280182801928020280212802228023280242802528026280272802828029280302803128032280332803428035280362803728038280392804028041280422804328044280452804628047280482804928050280512805228053280542805528056280572805828059280602806128062280632806428065280662806728068280692807028071280722807328074280752807628077280782807928080280812808228083280842808528086280872808828089280902809128092280932809428095280962809728098280992810028101281022810328104281052810628107281082810928110281112811228113281142811528116281172811828119281202812128122281232812428125281262812728128281292813028131281322813328134281352813628137281382813928140281412814228143281442814528146281472814828149281502815128152281532815428155281562815728158281592816028161281622816328164281652816628167281682816928170281712817228173281742817528176281772817828179281802818128182281832818428185281862818728188281892819028191281922819328194281952819628197281982819928200282012820228203282042820528206282072820828209282102821128212282132821428215282162821728218282192822028221282222822328224282252822628227282282822928230282312823228233282342823528236282372823828239282402824128242282432824428245282462824728248282492825028251282522825328254282552825628257282582825928260282612826228263282642826528266282672826828269282702827128272282732827428275282762827728278282792828028281282822828328284282852828628287282882828928290282912829228293282942829528296282972829828299283002830128302283032830428305283062830728308283092831028311283122831328314283152831628317283182831928320283212832228323283242832528326283272832828329283302833128332283332833428335283362833728338283392834028341283422834328344283452834628347283482834928350283512835228353283542835528356283572835828359283602836128362283632836428365283662836728368283692837028371283722837328374283752837628377283782837928380283812838228383283842838528386283872838828389283902839128392283932839428395283962839728398283992840028401284022840328404284052840628407284082840928410284112841228413284142841528416284172841828419284202842128422284232842428425284262842728428284292843028431284322843328434284352843628437284382843928440284412844228443284442844528446284472844828449284502845128452284532845428455284562845728458284592846028461284622846328464284652846628467284682846928470284712847228473284742847528476284772847828479284802848128482284832848428485284862848728488284892849028491284922849328494284952849628497284982849928500285012850228503285042850528506285072850828509285102851128512285132851428515285162851728518285192852028521285222852328524285252852628527285282852928530285312853228533285342853528536285372853828539285402854128542285432854428545285462854728548285492855028551285522855328554285552855628557285582855928560285612856228563285642856528566285672856828569285702857128572285732857428575285762857728578285792858028581285822858328584285852858628587285882858928590285912859228593285942859528596285972859828599286002860128602286032860428605286062860728608286092861028611286122861328614286152861628617286182861928620286212862228623286242862528626286272862828629286302863128632286332863428635286362863728638286392864028641286422864328644286452864628647286482864928650286512865228653286542865528656286572865828659286602866128662286632866428665286662866728668286692867028671286722867328674286752867628677286782867928680286812868228683286842868528686286872868828689286902869128692286932869428695286962869728698286992870028701287022870328704287052870628707287082870928710287112871228713287142871528716287172871828719287202872128722287232872428725287262872728728287292873028731287322873328734287352873628737287382873928740287412874228743287442874528746287472874828749287502875128752287532875428755287562875728758287592876028761287622876328764287652876628767287682876928770287712877228773287742877528776287772877828779287802878128782287832878428785287862878728788287892879028791287922879328794287952879628797287982879928800288012880228803288042880528806288072880828809288102881128812288132881428815288162881728818288192882028821288222882328824288252882628827288282882928830288312883228833288342883528836288372883828839288402884128842288432884428845288462884728848288492885028851288522885328854288552885628857288582885928860288612886228863288642886528866288672886828869288702887128872288732887428875288762887728878288792888028881288822888328884288852888628887288882888928890288912889228893288942889528896288972889828899289002890128902289032890428905289062890728908289092891028911289122891328914289152891628917289182891928920289212892228923289242892528926289272892828929289302893128932289332893428935289362893728938289392894028941289422894328944289452894628947289482894928950289512895228953289542895528956289572895828959289602896128962289632896428965289662896728968289692897028971289722897328974289752897628977289782897928980289812898228983289842898528986289872898828989289902899128992289932899428995289962899728998289992900029001290022900329004290052900629007290082900929010290112901229013290142901529016290172901829019290202902129022290232902429025290262902729028290292903029031290322903329034290352903629037290382903929040290412904229043290442904529046290472904829049290502905129052290532905429055290562905729058290592906029061290622906329064290652906629067290682906929070290712907229073290742907529076290772907829079290802908129082290832908429085290862908729088290892909029091290922909329094290952909629097290982909929100291012910229103291042910529106291072910829109291102911129112291132911429115291162911729118291192912029121291222912329124291252912629127291282912929130291312913229133291342913529136291372913829139291402914129142291432914429145291462914729148291492915029151291522915329154291552915629157291582915929160291612916229163291642916529166291672916829169291702917129172291732917429175291762917729178291792918029181291822918329184291852918629187291882918929190291912919229193291942919529196291972919829199292002920129202292032920429205292062920729208292092921029211292122921329214292152921629217292182921929220292212922229223292242922529226292272922829229292302923129232292332923429235292362923729238292392924029241292422924329244292452924629247292482924929250292512925229253292542925529256292572925829259292602926129262292632926429265292662926729268292692927029271292722927329274292752927629277292782927929280292812928229283292842928529286292872928829289292902929129292292932929429295292962929729298292992930029301293022930329304293052930629307293082930929310293112931229313293142931529316293172931829319293202932129322293232932429325293262932729328293292933029331293322933329334293352933629337293382933929340293412934229343293442934529346293472934829349293502935129352293532935429355293562935729358293592936029361293622936329364293652936629367293682936929370293712937229373293742937529376293772937829379293802938129382293832938429385293862938729388293892939029391293922939329394293952939629397293982939929400294012940229403294042940529406294072940829409294102941129412294132941429415294162941729418294192942029421294222942329424294252942629427294282942929430294312943229433294342943529436294372943829439294402944129442294432944429445294462944729448294492945029451294522945329454294552945629457294582945929460294612946229463294642946529466294672946829469294702947129472294732947429475294762947729478294792948029481294822948329484294852948629487294882948929490294912949229493294942949529496294972949829499295002950129502295032950429505295062950729508295092951029511295122951329514295152951629517295182951929520295212952229523295242952529526295272952829529295302953129532295332953429535295362953729538295392954029541295422954329544295452954629547295482954929550295512955229553295542955529556295572955829559295602956129562295632956429565295662956729568295692957029571295722957329574295752957629577295782957929580295812958229583295842958529586295872958829589295902959129592295932959429595295962959729598295992960029601296022960329604296052960629607296082960929610296112961229613296142961529616296172961829619296202962129622296232962429625296262962729628296292963029631296322963329634296352963629637296382963929640296412964229643296442964529646296472964829649296502965129652296532965429655296562965729658296592966029661296622966329664296652966629667296682966929670296712967229673296742967529676296772967829679296802968129682296832968429685296862968729688296892969029691296922969329694296952969629697296982969929700297012970229703297042970529706297072970829709297102971129712297132971429715297162971729718297192972029721297222972329724297252972629727297282972929730297312973229733297342973529736297372973829739297402974129742297432974429745297462974729748297492975029751297522975329754297552975629757297582975929760297612976229763297642976529766297672976829769297702977129772297732977429775297762977729778297792978029781297822978329784297852978629787297882978929790297912979229793297942979529796297972979829799298002980129802298032980429805298062980729808298092981029811298122981329814298152981629817298182981929820298212982229823298242982529826298272982829829298302983129832298332983429835298362983729838298392984029841298422984329844298452984629847298482984929850298512985229853298542985529856298572985829859298602986129862298632986429865298662986729868298692987029871298722987329874298752987629877298782987929880298812988229883298842988529886298872988829889298902989129892298932989429895298962989729898298992990029901299022990329904299052990629907299082990929910299112991229913299142991529916299172991829919299202992129922299232992429925299262992729928299292993029931299322993329934299352993629937299382993929940299412994229943299442994529946299472994829949299502995129952299532995429955299562995729958299592996029961299622996329964299652996629967299682996929970299712997229973299742997529976299772997829979299802998129982299832998429985299862998729988299892999029991299922999329994299952999629997299982999930000300013000230003300043000530006300073000830009300103001130012300133001430015300163001730018300193002030021300223002330024300253002630027300283002930030300313003230033300343003530036300373003830039300403004130042300433004430045300463004730048300493005030051300523005330054300553005630057300583005930060300613006230063300643006530066300673006830069300703007130072300733007430075300763007730078300793008030081300823008330084300853008630087300883008930090300913009230093300943009530096300973009830099301003010130102301033010430105301063010730108301093011030111301123011330114301153011630117301183011930120301213012230123301243012530126301273012830129301303013130132301333013430135301363013730138301393014030141301423014330144301453014630147301483014930150301513015230153301543015530156301573015830159301603016130162301633016430165301663016730168301693017030171301723017330174301753017630177301783017930180301813018230183301843018530186301873018830189301903019130192301933019430195301963019730198301993020030201302023020330204302053020630207302083020930210302113021230213302143021530216302173021830219302203022130222302233022430225302263022730228302293023030231302323023330234302353023630237302383023930240302413024230243302443024530246302473024830249302503025130252302533025430255302563025730258302593026030261302623026330264302653026630267302683026930270302713027230273302743027530276302773027830279302803028130282302833028430285302863028730288302893029030291302923029330294302953029630297302983029930300303013030230303303043030530306303073030830309303103031130312303133031430315303163031730318303193032030321303223032330324303253032630327303283032930330303313033230333303343033530336303373033830339303403034130342303433034430345303463034730348303493035030351303523035330354303553035630357303583035930360303613036230363303643036530366303673036830369303703037130372303733037430375303763037730378303793038030381303823038330384303853038630387303883038930390303913039230393303943039530396303973039830399304003040130402304033040430405304063040730408304093041030411304123041330414304153041630417304183041930420304213042230423304243042530426304273042830429304303043130432304333043430435304363043730438304393044030441304423044330444304453044630447304483044930450304513045230453304543045530456304573045830459304603046130462304633046430465304663046730468304693047030471304723047330474304753047630477304783047930480304813048230483304843048530486304873048830489304903049130492304933049430495304963049730498304993050030501305023050330504305053050630507305083050930510305113051230513305143051530516305173051830519305203052130522305233052430525305263052730528305293053030531305323053330534305353053630537305383053930540305413054230543305443054530546305473054830549305503055130552305533055430555305563055730558305593056030561305623056330564305653056630567305683056930570305713057230573305743057530576305773057830579305803058130582305833058430585305863058730588305893059030591305923059330594305953059630597305983059930600306013060230603306043060530606306073060830609306103061130612306133061430615306163061730618306193062030621306223062330624306253062630627306283062930630306313063230633306343063530636306373063830639306403064130642306433064430645306463064730648306493065030651306523065330654306553065630657306583065930660306613066230663306643066530666306673066830669306703067130672306733067430675306763067730678306793068030681306823068330684306853068630687306883068930690306913069230693306943069530696306973069830699307003070130702307033070430705307063070730708307093071030711307123071330714307153071630717307183071930720307213072230723307243072530726307273072830729307303073130732307333073430735307363073730738307393074030741307423074330744307453074630747307483074930750307513075230753307543075530756307573075830759307603076130762307633076430765307663076730768307693077030771307723077330774307753077630777307783077930780307813078230783307843078530786307873078830789307903079130792307933079430795307963079730798307993080030801308023080330804308053080630807308083080930810308113081230813308143081530816308173081830819308203082130822308233082430825308263082730828308293083030831308323083330834308353083630837308383083930840308413084230843308443084530846308473084830849308503085130852308533085430855308563085730858308593086030861308623086330864308653086630867308683086930870308713087230873308743087530876308773087830879308803088130882308833088430885308863088730888308893089030891308923089330894308953089630897308983089930900309013090230903309043090530906309073090830909309103091130912309133091430915309163091730918309193092030921309223092330924309253092630927309283092930930309313093230933309343093530936309373093830939309403094130942309433094430945309463094730948309493095030951309523095330954309553095630957309583095930960309613096230963309643096530966309673096830969309703097130972309733097430975309763097730978309793098030981309823098330984309853098630987309883098930990309913099230993309943099530996309973099830999310003100131002310033100431005310063100731008310093101031011310123101331014310153101631017310183101931020310213102231023310243102531026310273102831029310303103131032310333103431035310363103731038310393104031041310423104331044310453104631047310483104931050310513105231053310543105531056310573105831059310603106131062310633106431065310663106731068310693107031071310723107331074310753107631077310783107931080310813108231083310843108531086310873108831089310903109131092310933109431095310963109731098310993110031101311023110331104311053110631107311083110931110311113111231113311143111531116311173111831119311203112131122311233112431125311263112731128311293113031131311323113331134311353113631137311383113931140311413114231143311443114531146311473114831149311503115131152311533115431155311563115731158311593116031161311623116331164311653116631167311683116931170311713117231173311743117531176311773117831179311803118131182311833118431185311863118731188311893119031191311923119331194311953119631197311983119931200312013120231203312043120531206312073120831209312103121131212312133121431215312163121731218312193122031221312223122331224312253122631227312283122931230312313123231233312343123531236312373123831239312403124131242312433124431245312463124731248312493125031251312523125331254312553125631257312583125931260312613126231263312643126531266312673126831269312703127131272312733127431275312763127731278312793128031281312823128331284312853128631287312883128931290312913129231293312943129531296312973129831299313003130131302313033130431305313063130731308313093131031311313123131331314313153131631317313183131931320313213132231323313243132531326313273132831329313303133131332313333133431335313363133731338313393134031341313423134331344313453134631347313483134931350313513135231353313543135531356313573135831359313603136131362313633136431365313663136731368313693137031371313723137331374313753137631377313783137931380313813138231383313843138531386313873138831389313903139131392313933139431395313963139731398313993140031401314023140331404314053140631407314083140931410314113141231413314143141531416314173141831419314203142131422314233142431425314263142731428314293143031431314323143331434314353143631437314383143931440314413144231443314443144531446314473144831449314503145131452314533145431455314563145731458314593146031461314623146331464314653146631467314683146931470314713147231473314743147531476314773147831479314803148131482314833148431485314863148731488314893149031491314923149331494314953149631497314983149931500315013150231503315043150531506315073150831509315103151131512315133151431515315163151731518315193152031521315223152331524315253152631527315283152931530315313153231533315343153531536315373153831539315403154131542315433154431545315463154731548315493155031551315523155331554315553155631557315583155931560315613156231563315643156531566315673156831569315703157131572315733157431575315763157731578315793158031581315823158331584315853158631587315883158931590315913159231593315943159531596315973159831599316003160131602316033160431605316063160731608316093161031611316123161331614316153161631617316183161931620316213162231623316243162531626316273162831629316303163131632316333163431635316363163731638316393164031641316423164331644316453164631647316483164931650316513165231653316543165531656316573165831659316603166131662316633166431665316663166731668316693167031671316723167331674316753167631677316783167931680316813168231683316843168531686316873168831689316903169131692316933169431695316963169731698316993170031701317023170331704317053170631707317083170931710317113171231713317143171531716317173171831719317203172131722317233172431725317263172731728317293173031731317323173331734317353173631737317383173931740317413174231743317443174531746317473174831749317503175131752317533175431755317563175731758317593176031761317623176331764317653176631767317683176931770317713177231773317743177531776317773177831779317803178131782317833178431785317863178731788317893179031791317923179331794317953179631797317983179931800318013180231803318043180531806318073180831809318103181131812318133181431815318163181731818318193182031821318223182331824318253182631827318283182931830318313183231833318343183531836318373183831839318403184131842318433184431845318463184731848318493185031851318523185331854318553185631857318583185931860318613186231863318643186531866318673186831869318703187131872318733187431875318763187731878318793188031881318823188331884318853188631887318883188931890318913189231893318943189531896318973189831899319003190131902319033190431905319063190731908319093191031911319123191331914319153191631917319183191931920319213192231923319243192531926319273192831929319303193131932319333193431935319363193731938319393194031941319423194331944319453194631947319483194931950319513195231953319543195531956319573195831959319603196131962319633196431965319663196731968319693197031971319723197331974319753197631977319783197931980319813198231983319843198531986319873198831989319903199131992319933199431995319963199731998319993200032001320023200332004320053200632007320083200932010320113201232013320143201532016320173201832019320203202132022320233202432025320263202732028320293203032031320323203332034320353203632037320383203932040320413204232043320443204532046320473204832049320503205132052320533205432055320563205732058320593206032061320623206332064320653206632067320683206932070320713207232073320743207532076320773207832079320803208132082320833208432085320863208732088320893209032091320923209332094320953209632097320983209932100321013210232103321043210532106321073210832109321103211132112321133211432115321163211732118321193212032121321223212332124321253212632127321283212932130321313213232133321343213532136321373213832139321403214132142321433214432145321463214732148321493215032151321523215332154321553215632157321583215932160321613216232163321643216532166321673216832169321703217132172321733217432175321763217732178321793218032181321823218332184321853218632187321883218932190321913219232193321943219532196321973219832199322003220132202322033220432205322063220732208322093221032211322123221332214322153221632217322183221932220322213222232223322243222532226322273222832229322303223132232322333223432235322363223732238322393224032241322423224332244322453224632247322483224932250322513225232253322543225532256322573225832259322603226132262322633226432265322663226732268322693227032271322723227332274322753227632277322783227932280322813228232283322843228532286322873228832289322903229132292322933229432295322963229732298322993230032301323023230332304323053230632307323083230932310323113231232313323143231532316323173231832319323203232132322323233232432325323263232732328323293233032331323323233332334323353233632337323383233932340323413234232343323443234532346323473234832349323503235132352323533235432355323563235732358323593236032361323623236332364323653236632367323683236932370323713237232373323743237532376323773237832379323803238132382323833238432385323863238732388323893239032391323923239332394323953239632397323983239932400324013240232403324043240532406324073240832409324103241132412324133241432415324163241732418324193242032421324223242332424324253242632427324283242932430324313243232433324343243532436324373243832439324403244132442324433244432445324463244732448324493245032451324523245332454324553245632457324583245932460324613246232463324643246532466324673246832469324703247132472324733247432475324763247732478324793248032481324823248332484324853248632487324883248932490324913249232493324943249532496324973249832499325003250132502325033250432505325063250732508325093251032511325123251332514325153251632517325183251932520325213252232523325243252532526325273252832529325303253132532325333253432535325363253732538325393254032541325423254332544325453254632547325483254932550325513255232553325543255532556325573255832559325603256132562325633256432565325663256732568325693257032571325723257332574325753257632577325783257932580325813258232583325843258532586325873258832589325903259132592325933259432595325963259732598325993260032601326023260332604326053260632607326083260932610326113261232613326143261532616326173261832619326203262132622326233262432625326263262732628326293263032631326323263332634326353263632637326383263932640326413264232643326443264532646326473264832649326503265132652326533265432655326563265732658326593266032661326623266332664326653266632667326683266932670326713267232673326743267532676326773267832679326803268132682326833268432685326863268732688326893269032691326923269332694326953269632697326983269932700327013270232703327043270532706327073270832709327103271132712327133271432715327163271732718327193272032721327223272332724327253272632727327283272932730327313273232733327343273532736327373273832739327403274132742327433274432745327463274732748327493275032751327523275332754327553275632757327583275932760327613276232763327643276532766327673276832769327703277132772327733277432775327763277732778327793278032781327823278332784327853278632787327883278932790327913279232793327943279532796327973279832799328003280132802328033280432805328063280732808328093281032811328123281332814328153281632817328183281932820328213282232823328243282532826328273282832829328303283132832328333283432835328363283732838328393284032841328423284332844328453284632847328483284932850328513285232853328543285532856328573285832859328603286132862328633286432865328663286732868328693287032871328723287332874328753287632877328783287932880328813288232883328843288532886328873288832889328903289132892328933289432895328963289732898328993290032901329023290332904329053290632907329083290932910329113291232913329143291532916329173291832919329203292132922329233292432925329263292732928329293293032931329323293332934329353293632937329383293932940329413294232943329443294532946329473294832949329503295132952329533295432955329563295732958329593296032961329623296332964329653296632967329683296932970329713297232973329743297532976329773297832979329803298132982329833298432985329863298732988329893299032991329923299332994329953299632997329983299933000330013300233003330043300533006330073300833009330103301133012330133301433015330163301733018330193302033021330223302333024330253302633027330283302933030330313303233033330343303533036330373303833039330403304133042330433304433045330463304733048330493305033051330523305333054330553305633057330583305933060330613306233063330643306533066330673306833069330703307133072330733307433075330763307733078330793308033081330823308333084330853308633087330883308933090330913309233093330943309533096330973309833099331003310133102331033310433105331063310733108331093311033111331123311333114331153311633117331183311933120331213312233123331243312533126331273312833129331303313133132331333313433135331363313733138331393314033141331423314333144331453314633147331483314933150331513315233153331543315533156331573315833159331603316133162331633316433165331663316733168331693317033171331723317333174331753317633177331783317933180331813318233183331843318533186331873318833189331903319133192331933319433195331963319733198331993320033201332023320333204332053320633207332083320933210332113321233213332143321533216332173321833219332203322133222332233322433225332263322733228332293323033231332323323333234332353323633237332383323933240332413324233243332443324533246332473324833249332503325133252332533325433255332563325733258332593326033261332623326333264332653326633267332683326933270332713327233273332743327533276332773327833279332803328133282332833328433285332863328733288332893329033291332923329333294332953329633297332983329933300333013330233303333043330533306333073330833309333103331133312333133331433315333163331733318333193332033321333223332333324333253332633327333283332933330333313333233333333343333533336333373333833339333403334133342333433334433345333463334733348333493335033351333523335333354333553335633357333583335933360333613336233363333643336533366333673336833369333703337133372333733337433375333763337733378333793338033381333823338333384333853338633387333883338933390333913339233393333943339533396333973339833399334003340133402334033340433405334063340733408334093341033411334123341333414334153341633417334183341933420334213342233423334243342533426334273342833429334303343133432334333343433435334363343733438334393344033441334423344333444334453344633447334483344933450334513345233453334543345533456334573345833459334603346133462334633346433465334663346733468334693347033471334723347333474334753347633477334783347933480334813348233483334843348533486334873348833489334903349133492334933349433495334963349733498334993350033501335023350333504335053350633507335083350933510335113351233513335143351533516335173351833519335203352133522335233352433525335263352733528335293353033531335323353333534335353353633537335383353933540335413354233543335443354533546335473354833549335503355133552335533355433555335563355733558335593356033561335623356333564335653356633567335683356933570335713357233573335743357533576335773357833579335803358133582335833358433585335863358733588335893359033591335923359333594335953359633597335983359933600336013360233603336043360533606336073360833609336103361133612336133361433615336163361733618336193362033621336223362333624336253362633627336283362933630336313363233633336343363533636336373363833639336403364133642336433364433645336463364733648336493365033651336523365333654336553365633657336583365933660336613366233663336643366533666336673366833669336703367133672336733367433675336763367733678336793368033681336823368333684336853368633687336883368933690336913369233693336943369533696336973369833699337003370133702337033370433705337063370733708337093371033711337123371333714337153371633717337183371933720337213372233723337243372533726337273372833729337303373133732337333373433735337363373733738337393374033741337423374333744337453374633747337483374933750337513375233753337543375533756337573375833759337603376133762337633376433765337663376733768337693377033771337723377333774337753377633777337783377933780337813378233783337843378533786337873378833789337903379133792337933379433795337963379733798337993380033801338023380333804338053380633807338083380933810338113381233813338143381533816338173381833819338203382133822338233382433825338263382733828338293383033831338323383333834338353383633837338383383933840338413384233843338443384533846338473384833849338503385133852338533385433855338563385733858338593386033861338623386333864338653386633867338683386933870338713387233873338743387533876338773387833879338803388133882338833388433885338863388733888338893389033891338923389333894338953389633897338983389933900339013390233903339043390533906339073390833909339103391133912339133391433915339163391733918339193392033921339223392333924339253392633927339283392933930339313393233933339343393533936339373393833939339403394133942339433394433945339463394733948339493395033951339523395333954339553395633957339583395933960339613396233963339643396533966339673396833969339703397133972339733397433975339763397733978339793398033981339823398333984339853398633987339883398933990339913399233993339943399533996339973399833999340003400134002340033400434005340063400734008340093401034011340123401334014340153401634017340183401934020340213402234023340243402534026340273402834029340303403134032340333403434035340363403734038340393404034041340423404334044340453404634047340483404934050340513405234053340543405534056340573405834059340603406134062340633406434065340663406734068340693407034071340723407334074340753407634077340783407934080340813408234083340843408534086340873408834089340903409134092340933409434095340963409734098340993410034101341023410334104341053410634107341083410934110341113411234113341143411534116341173411834119341203412134122341233412434125341263412734128341293413034131341323413334134341353413634137341383413934140341413414234143341443414534146341473414834149341503415134152341533415434155341563415734158341593416034161341623416334164341653416634167341683416934170341713417234173341743417534176341773417834179341803418134182341833418434185341863418734188341893419034191341923419334194341953419634197341983419934200342013420234203342043420534206342073420834209342103421134212342133421434215342163421734218342193422034221342223422334224342253422634227342283422934230342313423234233342343423534236342373423834239342403424134242342433424434245342463424734248342493425034251342523425334254342553425634257342583425934260342613426234263342643426534266342673426834269342703427134272342733427434275342763427734278342793428034281342823428334284342853428634287342883428934290342913429234293342943429534296342973429834299343003430134302343033430434305343063430734308343093431034311343123431334314343153431634317343183431934320343213432234323343243432534326343273432834329343303433134332343333433434335343363433734338343393434034341343423434334344343453434634347343483434934350343513435234353343543435534356343573435834359343603436134362343633436434365343663436734368343693437034371343723437334374343753437634377343783437934380343813438234383343843438534386343873438834389343903439134392343933439434395343963439734398343993440034401344023440334404344053440634407344083440934410344113441234413344143441534416344173441834419344203442134422344233442434425344263442734428344293443034431344323443334434344353443634437344383443934440344413444234443344443444534446344473444834449344503445134452344533445434455344563445734458344593446034461344623446334464344653446634467344683446934470344713447234473344743447534476344773447834479344803448134482344833448434485344863448734488344893449034491344923449334494344953449634497344983449934500345013450234503345043450534506345073450834509345103451134512345133451434515345163451734518345193452034521345223452334524345253452634527345283452934530345313453234533345343453534536345373453834539345403454134542345433454434545345463454734548345493455034551345523455334554345553455634557345583455934560345613456234563345643456534566345673456834569345703457134572345733457434575345763457734578345793458034581345823458334584345853458634587345883458934590345913459234593345943459534596345973459834599346003460134602346033460434605346063460734608346093461034611346123461334614346153461634617346183461934620346213462234623346243462534626346273462834629346303463134632346333463434635346363463734638346393464034641346423464334644346453464634647346483464934650346513465234653346543465534656346573465834659346603466134662346633466434665346663466734668346693467034671346723467334674346753467634677346783467934680346813468234683346843468534686346873468834689346903469134692346933469434695346963469734698346993470034701347023470334704347053470634707347083470934710347113471234713347143471534716347173471834719347203472134722347233472434725347263472734728347293473034731347323473334734347353473634737347383473934740347413474234743347443474534746347473474834749347503475134752347533475434755347563475734758347593476034761347623476334764347653476634767347683476934770347713477234773347743477534776347773477834779347803478134782347833478434785347863478734788347893479034791347923479334794347953479634797347983479934800348013480234803348043480534806348073480834809348103481134812348133481434815348163481734818348193482034821348223482334824348253482634827348283482934830348313483234833348343483534836348373483834839348403484134842348433484434845348463484734848348493485034851348523485334854348553485634857348583485934860348613486234863348643486534866348673486834869348703487134872348733487434875348763487734878348793488034881348823488334884348853488634887348883488934890348913489234893348943489534896348973489834899349003490134902349033490434905349063490734908349093491034911349123491334914349153491634917349183491934920349213492234923349243492534926349273492834929349303493134932349333493434935349363493734938349393494034941349423494334944349453494634947349483494934950349513495234953349543495534956349573495834959349603496134962349633496434965349663496734968349693497034971349723497334974349753497634977349783497934980349813498234983349843498534986349873498834989349903499134992349933499434995349963499734998349993500035001350023500335004350053500635007350083500935010350113501235013350143501535016350173501835019350203502135022350233502435025350263502735028350293503035031350323503335034350353503635037350383503935040350413504235043350443504535046350473504835049350503505135052350533505435055350563505735058350593506035061350623506335064350653506635067350683506935070350713507235073350743507535076350773507835079350803508135082350833508435085350863508735088350893509035091350923509335094350953509635097350983509935100351013510235103351043510535106351073510835109351103511135112351133511435115351163511735118351193512035121351223512335124351253512635127351283512935130351313513235133351343513535136351373513835139351403514135142351433514435145351463514735148351493515035151351523515335154351553515635157351583515935160351613516235163351643516535166351673516835169351703517135172351733517435175351763517735178351793518035181351823518335184351853518635187351883518935190351913519235193351943519535196351973519835199352003520135202352033520435205352063520735208352093521035211352123521335214352153521635217352183521935220352213522235223352243522535226352273522835229352303523135232352333523435235352363523735238352393524035241352423524335244352453524635247352483524935250352513525235253352543525535256352573525835259352603526135262352633526435265352663526735268352693527035271352723527335274352753527635277352783527935280352813528235283352843528535286352873528835289352903529135292352933529435295352963529735298352993530035301353023530335304353053530635307353083530935310353113531235313353143531535316353173531835319353203532135322353233532435325353263532735328353293533035331353323533335334353353533635337353383533935340353413534235343353443534535346353473534835349353503535135352353533535435355353563535735358353593536035361353623536335364353653536635367353683536935370353713537235373353743537535376353773537835379353803538135382353833538435385353863538735388353893539035391353923539335394353953539635397353983539935400354013540235403354043540535406354073540835409354103541135412354133541435415354163541735418354193542035421354223542335424354253542635427354283542935430354313543235433354343543535436354373543835439354403544135442354433544435445354463544735448354493545035451354523545335454354553545635457354583545935460354613546235463354643546535466354673546835469354703547135472354733547435475354763547735478354793548035481354823548335484354853548635487354883548935490354913549235493354943549535496354973549835499355003550135502355033550435505355063550735508355093551035511355123551335514355153551635517355183551935520355213552235523355243552535526355273552835529355303553135532355333553435535355363553735538355393554035541355423554335544355453554635547355483554935550355513555235553355543555535556355573555835559355603556135562355633556435565355663556735568355693557035571355723557335574355753557635577355783557935580355813558235583355843558535586355873558835589355903559135592355933559435595355963559735598355993560035601356023560335604356053560635607356083560935610356113561235613356143561535616356173561835619356203562135622356233562435625356263562735628356293563035631356323563335634356353563635637356383563935640356413564235643356443564535646356473564835649356503565135652356533565435655356563565735658356593566035661356623566335664356653566635667356683566935670356713567235673356743567535676356773567835679356803568135682356833568435685356863568735688356893569035691356923569335694356953569635697356983569935700357013570235703357043570535706357073570835709357103571135712357133571435715357163571735718357193572035721357223572335724357253572635727357283572935730357313573235733357343573535736357373573835739357403574135742357433574435745357463574735748357493575035751357523575335754357553575635757357583575935760357613576235763357643576535766357673576835769357703577135772357733577435775357763577735778357793578035781357823578335784357853578635787357883578935790357913579235793357943579535796357973579835799358003580135802358033580435805358063580735808358093581035811358123581335814358153581635817358183581935820358213582235823358243582535826358273582835829358303583135832358333583435835358363583735838358393584035841358423584335844358453584635847358483584935850358513585235853358543585535856358573585835859358603586135862358633586435865358663586735868358693587035871358723587335874358753587635877358783587935880358813588235883358843588535886358873588835889358903589135892358933589435895358963589735898358993590035901359023590335904359053590635907359083590935910359113591235913359143591535916359173591835919359203592135922359233592435925359263592735928359293593035931359323593335934359353593635937359383593935940359413594235943359443594535946359473594835949359503595135952359533595435955359563595735958359593596035961359623596335964359653596635967359683596935970359713597235973359743597535976359773597835979359803598135982359833598435985359863598735988359893599035991359923599335994359953599635997359983599936000360013600236003360043600536006360073600836009360103601136012360133601436015360163601736018360193602036021360223602336024360253602636027360283602936030360313603236033360343603536036360373603836039360403604136042360433604436045360463604736048360493605036051360523605336054360553605636057360583605936060360613606236063360643606536066360673606836069360703607136072360733607436075360763607736078360793608036081360823608336084360853608636087360883608936090360913609236093360943609536096360973609836099361003610136102361033610436105361063610736108361093611036111361123611336114361153611636117361183611936120361213612236123361243612536126361273612836129361303613136132361333613436135361363613736138361393614036141361423614336144361453614636147361483614936150361513615236153361543615536156361573615836159361603616136162361633616436165361663616736168361693617036171361723617336174361753617636177361783617936180361813618236183361843618536186361873618836189361903619136192361933619436195361963619736198361993620036201362023620336204362053620636207362083620936210362113621236213362143621536216362173621836219362203622136222362233622436225362263622736228362293623036231362323623336234362353623636237362383623936240362413624236243362443624536246362473624836249362503625136252362533625436255362563625736258362593626036261362623626336264362653626636267362683626936270362713627236273362743627536276362773627836279362803628136282362833628436285362863628736288362893629036291362923629336294362953629636297362983629936300363013630236303363043630536306363073630836309363103631136312363133631436315363163631736318363193632036321363223632336324363253632636327363283632936330363313633236333363343633536336363373633836339363403634136342363433634436345363463634736348363493635036351363523635336354363553635636357363583635936360363613636236363363643636536366363673636836369363703637136372363733637436375363763637736378363793638036381363823638336384363853638636387363883638936390363913639236393363943639536396363973639836399364003640136402364033640436405364063640736408364093641036411364123641336414364153641636417364183641936420364213642236423364243642536426364273642836429364303643136432364333643436435364363643736438364393644036441364423644336444364453644636447364483644936450364513645236453364543645536456364573645836459364603646136462364633646436465364663646736468364693647036471364723647336474364753647636477364783647936480364813648236483364843648536486364873648836489364903649136492364933649436495364963649736498364993650036501365023650336504365053650636507365083650936510365113651236513365143651536516365173651836519365203652136522365233652436525365263652736528365293653036531365323653336534365353653636537365383653936540365413654236543365443654536546365473654836549365503655136552365533655436555365563655736558365593656036561365623656336564365653656636567365683656936570365713657236573365743657536576365773657836579365803658136582365833658436585365863658736588365893659036591365923659336594365953659636597365983659936600366013660236603366043660536606366073660836609366103661136612366133661436615366163661736618366193662036621366223662336624366253662636627366283662936630366313663236633366343663536636366373663836639366403664136642366433664436645366463664736648366493665036651366523665336654366553665636657366583665936660366613666236663366643666536666366673666836669366703667136672366733667436675366763667736678366793668036681366823668336684366853668636687366883668936690366913669236693366943669536696366973669836699367003670136702367033670436705367063670736708367093671036711367123671336714367153671636717367183671936720367213672236723367243672536726367273672836729367303673136732367333673436735367363673736738367393674036741367423674336744367453674636747367483674936750367513675236753367543675536756367573675836759367603676136762367633676436765367663676736768367693677036771367723677336774367753677636777367783677936780367813678236783367843678536786367873678836789367903679136792367933679436795367963679736798367993680036801368023680336804368053680636807368083680936810368113681236813368143681536816368173681836819368203682136822368233682436825368263682736828368293683036831368323683336834368353683636837368383683936840368413684236843368443684536846368473684836849368503685136852368533685436855368563685736858368593686036861368623686336864368653686636867368683686936870368713687236873368743687536876368773687836879368803688136882368833688436885368863688736888368893689036891368923689336894368953689636897368983689936900369013690236903369043690536906369073690836909369103691136912369133691436915369163691736918369193692036921369223692336924369253692636927369283692936930369313693236933369343693536936369373693836939369403694136942369433694436945369463694736948369493695036951369523695336954369553695636957369583695936960369613696236963369643696536966369673696836969369703697136972369733697436975369763697736978369793698036981369823698336984369853698636987369883698936990369913699236993369943699536996369973699836999370003700137002370033700437005370063700737008370093701037011370123701337014370153701637017370183701937020370213702237023370243702537026370273702837029370303703137032370333703437035370363703737038370393704037041370423704337044370453704637047370483704937050370513705237053370543705537056370573705837059370603706137062370633706437065370663706737068370693707037071370723707337074370753707637077370783707937080370813708237083370843708537086370873708837089370903709137092370933709437095370963709737098370993710037101371023710337104371053710637107371083710937110371113711237113371143711537116371173711837119371203712137122371233712437125371263712737128371293713037131371323713337134371353713637137371383713937140371413714237143371443714537146371473714837149371503715137152371533715437155371563715737158371593716037161371623716337164371653716637167371683716937170371713717237173371743717537176371773717837179371803718137182371833718437185371863718737188371893719037191371923719337194371953719637197371983719937200372013720237203372043720537206372073720837209372103721137212372133721437215372163721737218372193722037221372223722337224372253722637227372283722937230372313723237233372343723537236372373723837239372403724137242372433724437245372463724737248372493725037251372523725337254372553725637257372583725937260372613726237263372643726537266372673726837269372703727137272372733727437275372763727737278372793728037281372823728337284372853728637287372883728937290372913729237293372943729537296372973729837299373003730137302373033730437305373063730737308373093731037311373123731337314373153731637317373183731937320373213732237323373243732537326373273732837329373303733137332373333733437335373363733737338373393734037341373423734337344373453734637347373483734937350373513735237353373543735537356373573735837359373603736137362373633736437365373663736737368373693737037371373723737337374373753737637377373783737937380373813738237383373843738537386373873738837389373903739137392373933739437395373963739737398373993740037401374023740337404374053740637407374083740937410374113741237413374143741537416374173741837419374203742137422374233742437425374263742737428374293743037431374323743337434374353743637437374383743937440374413744237443374443744537446374473744837449374503745137452374533745437455374563745737458374593746037461374623746337464374653746637467374683746937470374713747237473374743747537476374773747837479374803748137482374833748437485374863748737488374893749037491374923749337494374953749637497374983749937500375013750237503375043750537506375073750837509375103751137512375133751437515375163751737518375193752037521375223752337524375253752637527375283752937530375313753237533375343753537536375373753837539375403754137542375433754437545375463754737548375493755037551375523755337554375553755637557375583755937560375613756237563375643756537566375673756837569375703757137572375733757437575375763757737578375793758037581375823758337584375853758637587375883758937590375913759237593375943759537596375973759837599376003760137602376033760437605376063760737608376093761037611376123761337614376153761637617376183761937620376213762237623376243762537626376273762837629376303763137632376333763437635376363763737638376393764037641376423764337644376453764637647376483764937650376513765237653376543765537656376573765837659376603766137662376633766437665376663766737668376693767037671376723767337674376753767637677376783767937680376813768237683376843768537686376873768837689376903769137692376933769437695376963769737698376993770037701377023770337704377053770637707377083770937710377113771237713377143771537716377173771837719377203772137722377233772437725377263772737728377293773037731377323773337734377353773637737377383773937740377413774237743377443774537746377473774837749377503775137752377533775437755377563775737758377593776037761377623776337764377653776637767377683776937770377713777237773377743777537776377773777837779377803778137782377833778437785377863778737788377893779037791377923779337794377953779637797377983779937800378013780237803378043780537806378073780837809378103781137812378133781437815378163781737818378193782037821378223782337824378253782637827378283782937830378313783237833378343783537836378373783837839378403784137842378433784437845378463784737848378493785037851378523785337854378553785637857378583785937860378613786237863378643786537866378673786837869378703787137872378733787437875378763787737878378793788037881378823788337884378853788637887378883788937890378913789237893378943789537896378973789837899379003790137902379033790437905379063790737908379093791037911379123791337914379153791637917379183791937920379213792237923379243792537926379273792837929379303793137932379333793437935379363793737938379393794037941379423794337944379453794637947379483794937950379513795237953379543795537956379573795837959379603796137962379633796437965379663796737968379693797037971379723797337974379753797637977379783797937980379813798237983379843798537986379873798837989379903799137992379933799437995379963799737998379993800038001380023800338004380053800638007380083800938010380113801238013380143801538016380173801838019380203802138022380233802438025380263802738028380293803038031380323803338034380353803638037380383803938040380413804238043380443804538046380473804838049380503805138052380533805438055380563805738058380593806038061380623806338064380653806638067380683806938070380713807238073380743807538076380773807838079380803808138082380833808438085380863808738088380893809038091380923809338094380953809638097380983809938100381013810238103381043810538106381073810838109381103811138112381133811438115381163811738118381193812038121381223812338124381253812638127381283812938130381313813238133381343813538136381373813838139381403814138142381433814438145381463814738148381493815038151381523815338154381553815638157381583815938160381613816238163381643816538166381673816838169381703817138172381733817438175381763817738178381793818038181381823818338184381853818638187381883818938190381913819238193381943819538196381973819838199382003820138202382033820438205382063820738208382093821038211382123821338214382153821638217382183821938220382213822238223382243822538226382273822838229382303823138232382333823438235382363823738238382393824038241382423824338244382453824638247382483824938250382513825238253382543825538256382573825838259382603826138262382633826438265382663826738268382693827038271382723827338274382753827638277382783827938280382813828238283382843828538286382873828838289382903829138292382933829438295382963829738298382993830038301383023830338304383053830638307383083830938310383113831238313383143831538316383173831838319383203832138322383233832438325383263832738328383293833038331383323833338334383353833638337383383833938340383413834238343383443834538346383473834838349383503835138352383533835438355383563835738358383593836038361383623836338364383653836638367383683836938370383713837238373383743837538376383773837838379383803838138382383833838438385383863838738388383893839038391383923839338394383953839638397383983839938400384013840238403384043840538406384073840838409384103841138412384133841438415384163841738418384193842038421384223842338424384253842638427384283842938430384313843238433384343843538436384373843838439384403844138442384433844438445384463844738448384493845038451384523845338454384553845638457384583845938460384613846238463384643846538466384673846838469384703847138472384733847438475384763847738478384793848038481384823848338484384853848638487384883848938490384913849238493384943849538496384973849838499385003850138502385033850438505385063850738508385093851038511385123851338514385153851638517385183851938520385213852238523385243852538526385273852838529385303853138532385333853438535385363853738538385393854038541385423854338544385453854638547385483854938550385513855238553385543855538556385573855838559385603856138562385633856438565385663856738568385693857038571385723857338574385753857638577385783857938580385813858238583385843858538586385873858838589385903859138592385933859438595385963859738598385993860038601386023860338604386053860638607386083860938610386113861238613386143861538616386173861838619386203862138622386233862438625386263862738628386293863038631386323863338634386353863638637386383863938640386413864238643386443864538646386473864838649386503865138652386533865438655386563865738658386593866038661386623866338664386653866638667386683866938670386713867238673386743867538676386773867838679386803868138682386833868438685386863868738688386893869038691386923869338694386953869638697386983869938700387013870238703387043870538706387073870838709387103871138712387133871438715387163871738718387193872038721387223872338724387253872638727387283872938730387313873238733387343873538736387373873838739387403874138742387433874438745387463874738748387493875038751387523875338754387553875638757387583875938760387613876238763387643876538766387673876838769387703877138772387733877438775387763877738778387793878038781387823878338784387853878638787387883878938790387913879238793387943879538796387973879838799388003880138802388033880438805388063880738808388093881038811388123881338814388153881638817388183881938820388213882238823388243882538826388273882838829388303883138832388333883438835388363883738838388393884038841388423884338844388453884638847388483884938850388513885238853388543885538856388573885838859388603886138862388633886438865388663886738868388693887038871388723887338874388753887638877388783887938880388813888238883388843888538886388873888838889388903889138892388933889438895388963889738898388993890038901389023890338904389053890638907389083890938910389113891238913389143891538916389173891838919389203892138922389233892438925389263892738928389293893038931389323893338934389353893638937389383893938940389413894238943389443894538946389473894838949389503895138952389533895438955389563895738958389593896038961389623896338964389653896638967389683896938970389713897238973389743897538976389773897838979389803898138982389833898438985389863898738988389893899038991389923899338994389953899638997389983899939000390013900239003390043900539006390073900839009390103901139012390133901439015390163901739018390193902039021390223902339024390253902639027390283902939030390313903239033390343903539036390373903839039390403904139042390433904439045390463904739048390493905039051390523905339054390553905639057390583905939060390613906239063390643906539066390673906839069390703907139072390733907439075390763907739078390793908039081390823908339084390853908639087390883908939090390913909239093390943909539096390973909839099391003910139102391033910439105391063910739108391093911039111391123911339114391153911639117391183911939120391213912239123391243912539126391273912839129391303913139132391333913439135391363913739138391393914039141391423914339144391453914639147391483914939150391513915239153391543915539156391573915839159391603916139162391633916439165391663916739168391693917039171391723917339174391753917639177391783917939180391813918239183391843918539186391873918839189391903919139192391933919439195391963919739198391993920039201392023920339204392053920639207392083920939210392113921239213392143921539216392173921839219392203922139222392233922439225392263922739228392293923039231392323923339234392353923639237392383923939240392413924239243392443924539246392473924839249392503925139252392533925439255392563925739258392593926039261392623926339264392653926639267392683926939270392713927239273392743927539276392773927839279392803928139282392833928439285392863928739288392893929039291392923929339294392953929639297392983929939300393013930239303393043930539306393073930839309393103931139312393133931439315393163931739318393193932039321393223932339324393253932639327393283932939330393313933239333393343933539336393373933839339393403934139342393433934439345393463934739348393493935039351393523935339354393553935639357393583935939360393613936239363393643936539366393673936839369393703937139372393733937439375393763937739378393793938039381393823938339384393853938639387393883938939390393913939239393393943939539396393973939839399394003940139402394033940439405394063940739408394093941039411394123941339414394153941639417394183941939420394213942239423394243942539426394273942839429394303943139432394333943439435394363943739438394393944039441394423944339444394453944639447394483944939450394513945239453394543945539456394573945839459394603946139462394633946439465394663946739468394693947039471394723947339474394753947639477394783947939480394813948239483394843948539486394873948839489394903949139492394933949439495394963949739498394993950039501395023950339504395053950639507395083950939510395113951239513395143951539516395173951839519395203952139522395233952439525395263952739528395293953039531395323953339534395353953639537395383953939540395413954239543395443954539546395473954839549395503955139552395533955439555395563955739558395593956039561395623956339564395653956639567395683956939570395713957239573395743957539576395773957839579395803958139582395833958439585395863958739588395893959039591395923959339594395953959639597395983959939600396013960239603396043960539606396073960839609396103961139612396133961439615396163961739618396193962039621396223962339624396253962639627396283962939630396313963239633396343963539636396373963839639396403964139642396433964439645396463964739648396493965039651396523965339654396553965639657396583965939660396613966239663396643966539666396673966839669396703967139672396733967439675396763967739678396793968039681396823968339684396853968639687396883968939690396913969239693396943969539696396973969839699397003970139702397033970439705397063970739708397093971039711397123971339714397153971639717397183971939720397213972239723397243972539726397273972839729397303973139732397333973439735397363973739738397393974039741397423974339744397453974639747397483974939750397513975239753397543975539756397573975839759397603976139762397633976439765397663976739768397693977039771397723977339774397753977639777397783977939780397813978239783397843978539786397873978839789397903979139792397933979439795397963979739798397993980039801398023980339804398053980639807398083980939810398113981239813398143981539816398173981839819398203982139822398233982439825398263982739828398293983039831398323983339834398353983639837398383983939840398413984239843398443984539846398473984839849398503985139852398533985439855398563985739858398593986039861398623986339864398653986639867398683986939870398713987239873398743987539876398773987839879398803988139882398833988439885398863988739888398893989039891398923989339894398953989639897398983989939900399013990239903399043990539906399073990839909399103991139912399133991439915399163991739918399193992039921399223992339924399253992639927399283992939930399313993239933399343993539936399373993839939399403994139942399433994439945399463994739948399493995039951399523995339954399553995639957399583995939960399613996239963399643996539966399673996839969399703997139972399733997439975399763997739978399793998039981399823998339984399853998639987399883998939990399913999239993399943999539996399973999839999400004000140002400034000440005400064000740008400094001040011400124001340014400154001640017400184001940020400214002240023400244002540026400274002840029400304003140032400334003440035400364003740038400394004040041400424004340044400454004640047400484004940050400514005240053400544005540056400574005840059400604006140062400634006440065400664006740068400694007040071400724007340074400754007640077400784007940080400814008240083400844008540086400874008840089400904009140092400934009440095400964009740098400994010040101401024010340104401054010640107401084010940110401114011240113401144011540116401174011840119401204012140122401234012440125401264012740128401294013040131401324013340134401354013640137401384013940140401414014240143401444014540146401474014840149401504015140152401534015440155401564015740158401594016040161401624016340164401654016640167401684016940170401714017240173401744017540176401774017840179401804018140182401834018440185401864018740188401894019040191401924019340194401954019640197401984019940200402014020240203402044020540206402074020840209402104021140212402134021440215402164021740218402194022040221402224022340224402254022640227402284022940230402314023240233402344023540236402374023840239402404024140242402434024440245402464024740248402494025040251402524025340254402554025640257402584025940260402614026240263402644026540266402674026840269402704027140272402734027440275402764027740278402794028040281402824028340284402854028640287402884028940290402914029240293402944029540296402974029840299403004030140302403034030440305403064030740308403094031040311403124031340314403154031640317403184031940320403214032240323403244032540326403274032840329403304033140332403334033440335403364033740338403394034040341403424034340344403454034640347403484034940350403514035240353403544035540356403574035840359403604036140362403634036440365403664036740368403694037040371403724037340374403754037640377403784037940380403814038240383403844038540386403874038840389403904039140392403934039440395403964039740398403994040040401404024040340404404054040640407404084040940410404114041240413404144041540416404174041840419404204042140422404234042440425404264042740428404294043040431404324043340434404354043640437404384043940440404414044240443404444044540446404474044840449404504045140452404534045440455404564045740458404594046040461404624046340464404654046640467404684046940470404714047240473404744047540476404774047840479404804048140482404834048440485404864048740488404894049040491404924049340494404954049640497404984049940500405014050240503405044050540506405074050840509405104051140512405134051440515405164051740518405194052040521405224052340524405254052640527405284052940530405314053240533405344053540536405374053840539405404054140542405434054440545405464054740548405494055040551405524055340554405554055640557405584055940560405614056240563405644056540566405674056840569405704057140572405734057440575405764057740578405794058040581405824058340584405854058640587405884058940590405914059240593405944059540596405974059840599406004060140602406034060440605406064060740608406094061040611406124061340614406154061640617406184061940620406214062240623406244062540626406274062840629406304063140632406334063440635406364063740638406394064040641406424064340644406454064640647406484064940650406514065240653406544065540656406574065840659406604066140662406634066440665406664066740668406694067040671406724067340674406754067640677406784067940680406814068240683406844068540686406874068840689406904069140692406934069440695406964069740698406994070040701407024070340704407054070640707407084070940710407114071240713407144071540716407174071840719407204072140722407234072440725407264072740728407294073040731407324073340734407354073640737407384073940740407414074240743407444074540746407474074840749407504075140752407534075440755407564075740758407594076040761407624076340764407654076640767407684076940770407714077240773407744077540776407774077840779407804078140782407834078440785407864078740788407894079040791407924079340794407954079640797407984079940800408014080240803408044080540806408074080840809408104081140812408134081440815408164081740818408194082040821408224082340824408254082640827408284082940830408314083240833408344083540836408374083840839408404084140842408434084440845408464084740848408494085040851408524085340854408554085640857408584085940860408614086240863408644086540866408674086840869408704087140872408734087440875408764087740878408794088040881408824088340884408854088640887408884088940890408914089240893408944089540896408974089840899409004090140902409034090440905409064090740908409094091040911409124091340914409154091640917409184091940920409214092240923409244092540926409274092840929409304093140932409334093440935409364093740938409394094040941409424094340944409454094640947409484094940950409514095240953409544095540956409574095840959409604096140962409634096440965409664096740968409694097040971409724097340974409754097640977409784097940980409814098240983409844098540986409874098840989409904099140992409934099440995409964099740998409994100041001410024100341004410054100641007410084100941010410114101241013410144101541016410174101841019410204102141022410234102441025410264102741028410294103041031410324103341034410354103641037410384103941040410414104241043410444104541046410474104841049410504105141052410534105441055410564105741058410594106041061410624106341064410654106641067410684106941070410714107241073410744107541076410774107841079410804108141082410834108441085410864108741088410894109041091410924109341094410954109641097410984109941100411014110241103411044110541106411074110841109411104111141112411134111441115411164111741118411194112041121411224112341124411254112641127411284112941130411314113241133411344113541136411374113841139411404114141142411434114441145411464114741148411494115041151411524115341154411554115641157411584115941160411614116241163411644116541166411674116841169411704117141172411734117441175411764117741178411794118041181411824118341184411854118641187411884118941190411914119241193411944119541196411974119841199412004120141202412034120441205412064120741208412094121041211412124121341214412154121641217412184121941220412214122241223412244122541226412274122841229412304123141232412334123441235412364123741238412394124041241412424124341244412454124641247412484124941250412514125241253412544125541256412574125841259412604126141262412634126441265412664126741268412694127041271412724127341274412754127641277412784127941280412814128241283412844128541286412874128841289412904129141292412934129441295412964129741298412994130041301413024130341304413054130641307413084130941310413114131241313413144131541316413174131841319413204132141322413234132441325413264132741328413294133041331413324133341334413354133641337413384133941340413414134241343413444134541346413474134841349413504135141352413534135441355413564135741358413594136041361413624136341364413654136641367413684136941370413714137241373413744137541376413774137841379413804138141382413834138441385413864138741388413894139041391413924139341394413954139641397413984139941400414014140241403414044140541406414074140841409414104141141412414134141441415414164141741418414194142041421414224142341424414254142641427414284142941430414314143241433414344143541436414374143841439414404144141442414434144441445414464144741448414494145041451414524145341454414554145641457414584145941460414614146241463414644146541466414674146841469414704147141472414734147441475414764147741478414794148041481414824148341484414854148641487414884148941490414914149241493414944149541496414974149841499415004150141502415034150441505415064150741508415094151041511415124151341514415154151641517415184151941520415214152241523415244152541526415274152841529415304153141532415334153441535415364153741538415394154041541415424154341544415454154641547415484154941550415514155241553415544155541556415574155841559415604156141562415634156441565415664156741568415694157041571415724157341574415754157641577415784157941580415814158241583415844158541586415874158841589415904159141592415934159441595415964159741598415994160041601416024160341604416054160641607416084160941610416114161241613416144161541616416174161841619416204162141622416234162441625416264162741628416294163041631416324163341634416354163641637416384163941640416414164241643416444164541646416474164841649416504165141652416534165441655416564165741658416594166041661416624166341664416654166641667416684166941670416714167241673416744167541676416774167841679416804168141682416834168441685416864168741688416894169041691416924169341694416954169641697416984169941700417014170241703417044170541706417074170841709417104171141712417134171441715417164171741718417194172041721417224172341724417254172641727417284172941730417314173241733417344173541736417374173841739417404174141742417434174441745417464174741748417494175041751417524175341754417554175641757417584175941760417614176241763417644176541766417674176841769417704177141772417734177441775417764177741778417794178041781417824178341784417854178641787417884178941790417914179241793417944179541796417974179841799418004180141802418034180441805418064180741808418094181041811418124181341814418154181641817418184181941820418214182241823418244182541826418274182841829418304183141832418334183441835418364183741838418394184041841418424184341844418454184641847418484184941850418514185241853418544185541856418574185841859418604186141862418634186441865418664186741868418694187041871418724187341874418754187641877418784187941880418814188241883418844188541886418874188841889418904189141892418934189441895418964189741898418994190041901419024190341904419054190641907419084190941910419114191241913419144191541916419174191841919419204192141922419234192441925419264192741928419294193041931419324193341934419354193641937419384193941940419414194241943419444194541946419474194841949419504195141952419534195441955419564195741958419594196041961419624196341964419654196641967419684196941970419714197241973419744197541976419774197841979419804198141982419834198441985419864198741988419894199041991419924199341994419954199641997419984199942000420014200242003420044200542006420074200842009420104201142012420134201442015420164201742018420194202042021420224202342024420254202642027420284202942030420314203242033420344203542036420374203842039420404204142042420434204442045420464204742048420494205042051420524205342054420554205642057420584205942060420614206242063420644206542066420674206842069420704207142072420734207442075420764207742078420794208042081420824208342084420854208642087420884208942090420914209242093420944209542096420974209842099421004210142102421034210442105421064210742108421094211042111421124211342114421154211642117421184211942120421214212242123421244212542126421274212842129421304213142132421334213442135421364213742138421394214042141421424214342144421454214642147421484214942150421514215242153421544215542156421574215842159421604216142162421634216442165421664216742168421694217042171421724217342174421754217642177421784217942180421814218242183421844218542186421874218842189421904219142192421934219442195421964219742198421994220042201422024220342204422054220642207422084220942210422114221242213422144221542216422174221842219422204222142222422234222442225422264222742228422294223042231422324223342234422354223642237422384223942240422414224242243422444224542246422474224842249422504225142252422534225442255422564225742258422594226042261422624226342264422654226642267422684226942270422714227242273422744227542276422774227842279422804228142282422834228442285422864228742288422894229042291422924229342294422954229642297422984229942300423014230242303423044230542306423074230842309423104231142312423134231442315423164231742318423194232042321423224232342324423254232642327423284232942330423314233242333423344233542336423374233842339423404234142342423434234442345423464234742348423494235042351423524235342354423554235642357423584235942360423614236242363423644236542366423674236842369423704237142372423734237442375423764237742378423794238042381423824238342384423854238642387423884238942390423914239242393423944239542396423974239842399424004240142402424034240442405424064240742408424094241042411424124241342414424154241642417424184241942420424214242242423424244242542426424274242842429424304243142432424334243442435424364243742438424394244042441424424244342444424454244642447424484244942450424514245242453424544245542456424574245842459424604246142462424634246442465424664246742468424694247042471424724247342474424754247642477424784247942480424814248242483424844248542486424874248842489424904249142492424934249442495424964249742498424994250042501425024250342504425054250642507425084250942510425114251242513425144251542516425174251842519425204252142522425234252442525425264252742528425294253042531425324253342534425354253642537425384253942540425414254242543425444254542546425474254842549425504255142552425534255442555425564255742558425594256042561425624256342564425654256642567425684256942570425714257242573425744257542576425774257842579425804258142582425834258442585425864258742588425894259042591425924259342594425954259642597425984259942600426014260242603426044260542606426074260842609426104261142612426134261442615426164261742618426194262042621426224262342624426254262642627426284262942630426314263242633426344263542636426374263842639426404264142642426434264442645426464264742648426494265042651426524265342654426554265642657426584265942660426614266242663426644266542666426674266842669426704267142672426734267442675426764267742678426794268042681426824268342684426854268642687426884268942690426914269242693426944269542696426974269842699427004270142702427034270442705427064270742708427094271042711427124271342714427154271642717427184271942720427214272242723427244272542726427274272842729427304273142732427334273442735427364273742738427394274042741427424274342744427454274642747427484274942750427514275242753427544275542756427574275842759427604276142762427634276442765427664276742768427694277042771427724277342774427754277642777427784277942780427814278242783427844278542786427874278842789427904279142792427934279442795427964279742798427994280042801428024280342804428054280642807428084280942810428114281242813428144281542816428174281842819428204282142822428234282442825428264282742828428294283042831428324283342834428354283642837428384283942840428414284242843428444284542846428474284842849428504285142852428534285442855428564285742858428594286042861428624286342864428654286642867428684286942870428714287242873428744287542876428774287842879428804288142882428834288442885428864288742888428894289042891428924289342894428954289642897428984289942900429014290242903429044290542906429074290842909429104291142912429134291442915429164291742918429194292042921429224292342924429254292642927429284292942930429314293242933429344293542936429374293842939429404294142942429434294442945429464294742948429494295042951429524295342954429554295642957429584295942960429614296242963429644296542966429674296842969429704297142972429734297442975429764297742978429794298042981429824298342984429854298642987429884298942990429914299242993429944299542996429974299842999430004300143002430034300443005430064300743008430094301043011430124301343014430154301643017430184301943020430214302243023430244302543026430274302843029430304303143032430334303443035430364303743038430394304043041430424304343044430454304643047430484304943050430514305243053430544305543056430574305843059430604306143062430634306443065430664306743068430694307043071430724307343074430754307643077430784307943080430814308243083430844308543086430874308843089430904309143092430934309443095430964309743098430994310043101431024310343104431054310643107431084310943110431114311243113431144311543116431174311843119431204312143122431234312443125431264312743128431294313043131431324313343134431354313643137431384313943140431414314243143431444314543146431474314843149431504315143152431534315443155431564315743158431594316043161431624316343164431654316643167431684316943170431714317243173431744317543176431774317843179431804318143182431834318443185431864318743188431894319043191431924319343194431954319643197431984319943200432014320243203432044320543206432074320843209432104321143212432134321443215432164321743218432194322043221432224322343224432254322643227432284322943230432314323243233432344323543236432374323843239432404324143242432434324443245432464324743248432494325043251432524325343254432554325643257432584325943260432614326243263432644326543266432674326843269432704327143272432734327443275432764327743278432794328043281432824328343284432854328643287432884328943290432914329243293432944329543296432974329843299433004330143302433034330443305433064330743308433094331043311433124331343314433154331643317433184331943320433214332243323433244332543326433274332843329433304333143332433334333443335433364333743338433394334043341433424334343344433454334643347433484334943350433514335243353433544335543356433574335843359433604336143362433634336443365433664336743368433694337043371433724337343374433754337643377433784337943380433814338243383433844338543386433874338843389433904339143392433934339443395433964339743398433994340043401434024340343404434054340643407434084340943410434114341243413434144341543416434174341843419434204342143422434234342443425434264342743428434294343043431434324343343434434354343643437434384343943440434414344243443434444344543446434474344843449434504345143452434534345443455434564345743458434594346043461434624346343464434654346643467434684346943470434714347243473434744347543476434774347843479434804348143482434834348443485434864348743488434894349043491434924349343494434954349643497434984349943500435014350243503435044350543506435074350843509435104351143512435134351443515435164351743518435194352043521435224352343524435254352643527435284352943530435314353243533435344353543536435374353843539435404354143542435434354443545435464354743548435494355043551435524355343554435554355643557435584355943560435614356243563435644356543566435674356843569435704357143572435734357443575435764357743578435794358043581435824358343584435854358643587435884358943590435914359243593435944359543596435974359843599436004360143602436034360443605436064360743608436094361043611436124361343614436154361643617436184361943620436214362243623436244362543626436274362843629436304363143632436334363443635436364363743638436394364043641436424364343644436454364643647436484364943650436514365243653436544365543656436574365843659436604366143662436634366443665436664366743668436694367043671436724367343674436754367643677436784367943680436814368243683436844368543686436874368843689436904369143692436934369443695436964369743698436994370043701437024370343704437054370643707437084370943710437114371243713437144371543716437174371843719437204372143722437234372443725437264372743728437294373043731437324373343734437354373643737437384373943740437414374243743437444374543746437474374843749437504375143752437534375443755437564375743758437594376043761437624376343764437654376643767437684376943770437714377243773437744377543776437774377843779437804378143782437834378443785437864378743788437894379043791437924379343794437954379643797437984379943800438014380243803438044380543806438074380843809438104381143812438134381443815438164381743818438194382043821438224382343824438254382643827438284382943830438314383243833438344383543836438374383843839438404384143842438434384443845438464384743848438494385043851438524385343854438554385643857438584385943860438614386243863438644386543866438674386843869438704387143872438734387443875438764387743878438794388043881438824388343884438854388643887438884388943890438914389243893438944389543896438974389843899439004390143902439034390443905439064390743908439094391043911439124391343914439154391643917439184391943920439214392243923439244392543926439274392843929439304393143932439334393443935439364393743938439394394043941439424394343944439454394643947439484394943950439514395243953439544395543956439574395843959439604396143962439634396443965439664396743968439694397043971439724397343974439754397643977439784397943980439814398243983439844398543986439874398843989439904399143992439934399443995439964399743998439994400044001440024400344004440054400644007440084400944010440114401244013440144401544016440174401844019440204402144022440234402444025440264402744028440294403044031440324403344034440354403644037440384403944040440414404244043440444404544046440474404844049440504405144052440534405444055440564405744058440594406044061440624406344064440654406644067440684406944070440714407244073440744407544076440774407844079440804408144082440834408444085440864408744088440894409044091440924409344094440954409644097440984409944100441014410244103441044410544106441074410844109441104411144112441134411444115441164411744118441194412044121441224412344124441254412644127441284412944130441314413244133441344413544136441374413844139441404414144142441434414444145441464414744148441494415044151441524415344154441554415644157441584415944160441614416244163441644416544166441674416844169441704417144172441734417444175441764417744178441794418044181441824418344184441854418644187441884418944190441914419244193441944419544196441974419844199442004420144202442034420444205442064420744208442094421044211442124421344214442154421644217442184421944220442214422244223442244422544226442274422844229442304423144232442334423444235442364423744238442394424044241442424424344244442454424644247442484424944250442514425244253442544425544256442574425844259442604426144262442634426444265442664426744268442694427044271442724427344274442754427644277442784427944280442814428244283442844428544286442874428844289442904429144292442934429444295442964429744298442994430044301443024430344304443054430644307443084430944310443114431244313443144431544316443174431844319443204432144322443234432444325443264432744328443294433044331443324433344334443354433644337443384433944340443414434244343
  1. require({cache:{
  2. 'url:dijit/templates/CheckedMenuItem.html':"<tr class=\"dijitReset dijitMenuItem\" data-dojo-attach-point=\"focusNode\" role=\"menuitemcheckbox\" tabIndex=\"-1\"\r\n\t\tdata-dojo-attach-event=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\r\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\r\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuItemIcon dijitCheckedMenuItemIcon\" data-dojo-attach-point=\"iconNode\"/>\r\n\t\t<span class=\"dijitCheckedMenuItemIconChar\">&#10003;</span>\r\n\t</td>\r\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" data-dojo-attach-point=\"containerNode,labelNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" data-dojo-attach-point=\"accelKeyNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">&#160;</td>\r\n</tr>\r\n",
  3. 'dijit/form/TextBox':function(){
  4. require({cache:{
  5. 'url:dijit/form/templates/TextBox.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\" id=\"widget_${id}\" role=\"presentation\"\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class=\"dijitReset dijitInputInner\" data-dojo-attach-point='textbox,focusNode' autocomplete=\"off\"\r\n\t\t\t${!nameAttrSetting} type='${type}'\r\n\t/></div\r\n></div>\r\n"}});
  6. define("dijit/form/TextBox", [
  7. "dojo/_base/declare", // declare
  8. "dojo/dom-construct", // domConstruct.create
  9. "dojo/dom-style", // domStyle.getComputedStyle
  10. "dojo/_base/kernel", // kernel.deprecated
  11. "dojo/_base/lang", // lang.hitch
  12. "dojo/_base/sniff", // has("ie") has("mozilla")
  13. "dojo/_base/window", // win.doc.selection.createRange
  14. "./_FormValueWidget",
  15. "./_TextBoxMixin",
  16. "dojo/text!./templates/TextBox.html",
  17. ".." // to export dijit._setSelectionRange, remove in 2.0
  18. ], function(declare, domConstruct, domStyle, kernel, lang, has, win,
  19. _FormValueWidget, _TextBoxMixin, template, dijit){
  20. /*=====
  21. var _FormValueWidget = dijit.form._FormValueWidget;
  22. var _TextBoxMixin = dijit.form._TextBoxMixin;
  23. =====*/
  24. // module:
  25. // dijit/form/TextBox
  26. // summary:
  27. // A base class for textbox form inputs
  28. var TextBox = declare(/*====="dijit.form.TextBox", =====*/ [_FormValueWidget, _TextBoxMixin], {
  29. // summary:
  30. // A base class for textbox form inputs
  31. templateString: template,
  32. _singleNodeTemplate: '<input class="dijit dijitReset dijitLeft dijitInputField" data-dojo-attach-point="textbox,focusNode" autocomplete="off" type="${type}" ${!nameAttrSetting} />',
  33. _buttonInputDisabled: has("ie") ? "disabled" : "", // allows IE to disallow focus, but Firefox cannot be disabled for mousedown events
  34. baseClass: "dijitTextBox",
  35. postMixInProperties: function(){
  36. var type = this.type.toLowerCase();
  37. if(this.templateString && this.templateString.toLowerCase() == "input" || ((type == "hidden" || type == "file") && this.templateString == this.constructor.prototype.templateString)){
  38. this.templateString = this._singleNodeTemplate;
  39. }
  40. this.inherited(arguments);
  41. },
  42. _onInput: function(e){
  43. this.inherited(arguments);
  44. if(this.intermediateChanges){ // _TextBoxMixin uses onInput
  45. var _this = this;
  46. // the setTimeout allows the key to post to the widget input box
  47. setTimeout(function(){ _this._handleOnChange(_this.get('value'), false); }, 0);
  48. }
  49. },
  50. _setPlaceHolderAttr: function(v){
  51. this._set("placeHolder", v);
  52. if(!this._phspan){
  53. this._attachPoints.push('_phspan');
  54. // dijitInputField class gives placeHolder same padding as the input field
  55. // parent node already has dijitInputField class but it doesn't affect this <span>
  56. // since it's position: absolute.
  57. this._phspan = domConstruct.create('span',{className:'dijitPlaceHolder dijitInputField'},this.textbox,'after');
  58. }
  59. this._phspan.innerHTML="";
  60. this._phspan.appendChild(document.createTextNode(v));
  61. this._updatePlaceHolder();
  62. },
  63. _updatePlaceHolder: function(){
  64. if(this._phspan){
  65. this._phspan.style.display=(this.placeHolder&&!this.focused&&!this.textbox.value)?"":"none";
  66. }
  67. },
  68. _setValueAttr: function(value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
  69. this.inherited(arguments);
  70. this._updatePlaceHolder();
  71. },
  72. getDisplayedValue: function(){
  73. // summary:
  74. // Deprecated. Use get('displayedValue') instead.
  75. // tags:
  76. // deprecated
  77. kernel.deprecated(this.declaredClass+"::getDisplayedValue() is deprecated. Use set('displayedValue') instead.", "", "2.0");
  78. return this.get('displayedValue');
  79. },
  80. setDisplayedValue: function(/*String*/ value){
  81. // summary:
  82. // Deprecated. Use set('displayedValue', ...) instead.
  83. // tags:
  84. // deprecated
  85. kernel.deprecated(this.declaredClass+"::setDisplayedValue() is deprecated. Use set('displayedValue', ...) instead.", "", "2.0");
  86. this.set('displayedValue', value);
  87. },
  88. _onBlur: function(e){
  89. if(this.disabled){ return; }
  90. this.inherited(arguments);
  91. this._updatePlaceHolder();
  92. },
  93. _onFocus: function(/*String*/ by){
  94. if(this.disabled || this.readOnly){ return; }
  95. this.inherited(arguments);
  96. this._updatePlaceHolder();
  97. }
  98. });
  99. if(has("ie")){
  100. TextBox = declare(/*===== "dijit.form.TextBox.IEMixin", =====*/ TextBox, {
  101. declaredClass: "dijit.form.TextBox", // for user code referencing declaredClass
  102. _isTextSelected: function(){
  103. var range = win.doc.selection.createRange();
  104. var parent = range.parentElement();
  105. return parent == this.textbox && range.text.length == 0;
  106. },
  107. postCreate: function(){
  108. this.inherited(arguments);
  109. // IE INPUT tag fontFamily has to be set directly using STYLE
  110. // the setTimeout gives IE a chance to render the TextBox and to deal with font inheritance
  111. setTimeout(lang.hitch(this, function(){
  112. try{
  113. var s = domStyle.getComputedStyle(this.domNode); // can throw an exception if widget is immediately destroyed
  114. if(s){
  115. var ff = s.fontFamily;
  116. if(ff){
  117. var inputs = this.domNode.getElementsByTagName("INPUT");
  118. if(inputs){
  119. for(var i=0; i < inputs.length; i++){
  120. inputs[i].style.fontFamily = ff;
  121. }
  122. }
  123. }
  124. }
  125. }catch(e){/*when used in a Dialog, and this is called before the dialog is
  126. shown, s.fontFamily would trigger "Invalid Argument" error.*/}
  127. }), 0);
  128. }
  129. });
  130. // Overrides definition of _setSelectionRange from _TextBoxMixin (TODO: move to _TextBoxMixin.js?)
  131. dijit._setSelectionRange = _TextBoxMixin._setSelectionRange = function(/*DomNode*/ element, /*Number?*/ start, /*Number?*/ stop){
  132. if(element.createTextRange){
  133. var r = element.createTextRange();
  134. r.collapse(true);
  135. r.moveStart("character", -99999); // move to 0
  136. r.moveStart("character", start); // delta from 0 is the correct position
  137. r.moveEnd("character", stop-start);
  138. r.select();
  139. }
  140. }
  141. }else if(has("mozilla")){
  142. TextBox = declare(/*===== "dijit.form.TextBox.MozMixin", =====*/TextBox, {
  143. declaredClass: "dijit.form.TextBox", // for user code referencing declaredClass
  144. _onBlur: function(e){
  145. this.inherited(arguments);
  146. if(this.selectOnClick){
  147. // clear selection so that the next mouse click doesn't reselect
  148. this.textbox.selectionStart = this.textbox.selectionEnd = undefined;
  149. }
  150. }
  151. });
  152. }else{
  153. TextBox.prototype.declaredClass = "dijit.form.TextBox";
  154. }
  155. lang.setObject("dijit.form.TextBox", TextBox); // don't do direct assignment, it confuses API doc parser
  156. return TextBox;
  157. });
  158. },
  159. 'dojox/grid/DataGrid':function(){
  160. define("dojox/grid/DataGrid", [
  161. "../main",
  162. "dojo/_base/array",
  163. "dojo/_base/lang",
  164. "dojo/_base/json",
  165. "dojo/_base/sniff",
  166. "dojo/_base/declare",
  167. "./_Grid",
  168. "./DataSelection",
  169. "dojo/_base/html"
  170. ], function(dojox, array, lang, json, has, declare, _Grid, DataSelection, html){
  171. /*=====
  172. declare("dojox.grid.__DataCellDef", dojox.grid.__CellDef, {
  173. constructor: function(){
  174. // field: String?
  175. // The attribute to read from the dojo.data item for the row.
  176. // fields: String[]?
  177. // An array of fields to grab the values of and pass as an array to the grid
  178. // get: Function?
  179. // function(rowIndex, item?){} rowIndex is of type Integer, item is of type
  180. // Object. This function will be called when a cell requests data. Returns
  181. // the unformatted data for the cell.
  182. }
  183. });
  184. =====*/
  185. /*=====
  186. declare("dojox.grid.__DataViewDef", dojox.grid.__ViewDef, {
  187. constructor: function(){
  188. // cells: dojox.grid.__DataCellDef[]|Array[dojox.grid.__DataCellDef[]]?
  189. // The structure of the cells within this grid.
  190. // defaultCell: dojox.grid.__DataCellDef?
  191. // A cell definition with default values for all cells in this view. If
  192. // a property is defined in a cell definition in the "cells" array and
  193. // this property, the cell definition's property will override this
  194. // property's property.
  195. }
  196. });
  197. =====*/
  198. var DataGrid = declare("dojox.grid.DataGrid", _Grid, {
  199. store: null,
  200. query: null,
  201. queryOptions: null,
  202. fetchText: '...',
  203. sortFields: null,
  204. // updateDelay: int
  205. // Time, in milliseconds, to delay updates automatically so that multiple
  206. // calls to onSet/onNew/onDelete don't keep rerendering the grid. Set
  207. // to 0 to immediately cause updates. A higher value will result in
  208. // better performance at the expense of responsiveness of the grid.
  209. updateDelay: 1,
  210. /*=====
  211. // structure: dojox.grid.__DataViewDef|dojox.grid.__DataViewDef[]|dojox.grid.__DataCellDef[]|Array[dojox.grid.__DataCellDef[]]
  212. // View layout defintion.
  213. structure: '',
  214. =====*/
  215. // You can specify items instead of a query, if you like. They do not need
  216. // to be loaded - but the must be items in the store
  217. items: null,
  218. _store_connects: null,
  219. _by_idty: null,
  220. _by_idx: null,
  221. _cache: null,
  222. _pages: null,
  223. _pending_requests: null,
  224. _bop: -1,
  225. _eop: -1,
  226. _requests: 0,
  227. rowCount: 0,
  228. _isLoaded: false,
  229. _isLoading: false,
  230. //keepSelection: Boolean
  231. // Whether keep selection after sort, filter etc.
  232. keepSelection: false,
  233. postCreate: function(){
  234. this._pages = [];
  235. this._store_connects = [];
  236. this._by_idty = {};
  237. this._by_idx = [];
  238. this._cache = [];
  239. this._pending_requests = {};
  240. this._setStore(this.store);
  241. this.inherited(arguments);
  242. },
  243. destroy: function(){
  244. this.selection.destroy();
  245. this.inherited(arguments);
  246. },
  247. createSelection: function(){
  248. this.selection = new DataSelection(this);
  249. },
  250. get: function(inRowIndex, inItem){
  251. // summary: Default data getter.
  252. // description:
  253. // Provides data to display in a grid cell. Called in grid cell context.
  254. // So this.cell.index is the column index.
  255. // inRowIndex: Integer
  256. // Row for which to provide data
  257. // returns:
  258. // Data to display for a given grid cell.
  259. if(inItem && this.field == "_item" && !this.fields){
  260. return inItem;
  261. }else if(inItem && this.fields){
  262. var ret = [];
  263. var s = this.grid.store;
  264. array.forEach(this.fields, function(f){
  265. ret = ret.concat(s.getValues(inItem, f));
  266. });
  267. return ret;
  268. }else if(!inItem && typeof inRowIndex === "string"){
  269. return this.inherited(arguments);
  270. }
  271. return (!inItem ? this.defaultValue : (!this.field ? this.value : (this.field == "_item" ? inItem : this.grid.store.getValue(inItem, this.field))));
  272. },
  273. _checkUpdateStatus: function(){
  274. if(this.updateDelay > 0){
  275. var iStarted = false;
  276. if(this._endUpdateDelay){
  277. clearTimeout(this._endUpdateDelay);
  278. delete this._endUpdateDelay;
  279. iStarted = true;
  280. }
  281. if(!this.updating){
  282. this.beginUpdate();
  283. iStarted = true;
  284. }
  285. if(iStarted){
  286. var _this = this;
  287. this._endUpdateDelay = setTimeout(function(){
  288. delete _this._endUpdateDelay;
  289. _this.endUpdate();
  290. }, this.updateDelay);
  291. }
  292. }
  293. },
  294. _onSet: function(item, attribute, oldValue, newValue){
  295. this._checkUpdateStatus();
  296. var idx = this.getItemIndex(item);
  297. if(idx>-1){
  298. this.updateRow(idx);
  299. }
  300. },
  301. _createItem: function(item, index){
  302. var idty = this._hasIdentity ? this.store.getIdentity(item) : json.toJson(this.query) + ":idx:" + index + ":sort:" + json.toJson(this.getSortProps());
  303. var o = this._by_idty[idty] = { idty: idty, item: item };
  304. return o;
  305. },
  306. _addItem: function(item, index, noUpdate){
  307. this._by_idx[index] = this._createItem(item, index);
  308. if(!noUpdate){
  309. this.updateRow(index);
  310. }
  311. },
  312. _onNew: function(item, parentInfo){
  313. this._checkUpdateStatus();
  314. var rowCount = this.get('rowCount');
  315. this._addingItem = true;
  316. this.updateRowCount(rowCount+1);
  317. this._addingItem = false;
  318. this._addItem(item, rowCount);
  319. this.showMessage();
  320. },
  321. _onDelete: function(item){
  322. this._checkUpdateStatus();
  323. var idx = this._getItemIndex(item, true);
  324. if(idx >= 0){
  325. // When a row is deleted, all rest rows are shifted down,
  326. // and migrate from page to page. If some page is not
  327. // loaded yet empty rows can migrate to initialized pages
  328. // without refreshing. It causes empty rows in some pages, see:
  329. // http://bugs.dojotoolkit.org/ticket/6818
  330. // this code fix this problem by reseting loaded page info
  331. this._pages = [];
  332. this._bop = -1;
  333. this._eop = -1;
  334. var o = this._by_idx[idx];
  335. this._by_idx.splice(idx, 1);
  336. delete this._by_idty[o.idty];
  337. this.updateRowCount(this.get('rowCount')-1);
  338. if(this.get('rowCount') === 0){
  339. this.showMessage(this.noDataMessage);
  340. }
  341. }
  342. if(this.selection.isSelected(idx)){
  343. this.selection.deselect(idx);
  344. this.selection.selected.splice(idx, 1);
  345. }
  346. },
  347. _onRevert: function(){
  348. this._refresh();
  349. },
  350. setStore: function(store, query, queryOptions){
  351. if(this._requestsPending(0)){
  352. return;
  353. }
  354. this._setQuery(query, queryOptions);
  355. this._setStore(store);
  356. this._refresh(true);
  357. },
  358. setQuery: function(query, queryOptions){
  359. if(this._requestsPending(0)){
  360. return;
  361. }
  362. this._setQuery(query, queryOptions);
  363. this._refresh(true);
  364. },
  365. setItems: function(items){
  366. this.items = items;
  367. this._setStore(this.store);
  368. this._refresh(true);
  369. },
  370. _setQuery: function(query, queryOptions){
  371. this.query = query;
  372. this.queryOptions = queryOptions || this.queryOptions;
  373. },
  374. _setStore: function(store){
  375. if(this.store && this._store_connects){
  376. array.forEach(this._store_connects, this.disconnect, this);
  377. }
  378. this.store = store;
  379. if(this.store){
  380. var f = this.store.getFeatures();
  381. var h = [];
  382. this._canEdit = !!f["dojo.data.api.Write"] && !!f["dojo.data.api.Identity"];
  383. this._hasIdentity = !!f["dojo.data.api.Identity"];
  384. if(!!f["dojo.data.api.Notification"] && !this.items){
  385. h.push(this.connect(this.store, "onSet", "_onSet"));
  386. h.push(this.connect(this.store, "onNew", "_onNew"));
  387. h.push(this.connect(this.store, "onDelete", "_onDelete"));
  388. }
  389. if(this._canEdit){
  390. h.push(this.connect(this.store, "revert", "_onRevert"));
  391. }
  392. this._store_connects = h;
  393. }
  394. },
  395. _onFetchBegin: function(size, req){
  396. if(!this.scroller){ return; }
  397. if(this.rowCount != size){
  398. if(req.isRender){
  399. this.scroller.init(size, this.keepRows, this.rowsPerPage);
  400. this.rowCount = size;
  401. this._setAutoHeightAttr(this.autoHeight, true);
  402. this._skipRowRenormalize = true;
  403. this.prerender();
  404. this._skipRowRenormalize = false;
  405. }else{
  406. this.updateRowCount(size);
  407. }
  408. }
  409. if(!size){
  410. this.views.render();
  411. this._resize();
  412. this.showMessage(this.noDataMessage);
  413. this.focus.initFocusView();
  414. }else{
  415. this.showMessage();
  416. }
  417. },
  418. _onFetchComplete: function(items, req){
  419. if(!this.scroller){ return; }
  420. if(items && items.length > 0){
  421. //console.log(items);
  422. array.forEach(items, function(item, idx){
  423. this._addItem(item, req.start+idx, true);
  424. }, this);
  425. this.updateRows(req.start, items.length);
  426. if(req.isRender){
  427. this.setScrollTop(0);
  428. this.postrender();
  429. }else if(this._lastScrollTop){
  430. this.setScrollTop(this._lastScrollTop);
  431. }
  432. if(has("ie")){
  433. html.setSelectable(this.domNode, this.selectable);
  434. }
  435. }
  436. delete this._lastScrollTop;
  437. if(!this._isLoaded){
  438. this._isLoading = false;
  439. this._isLoaded = true;
  440. }
  441. this._pending_requests[req.start] = false;
  442. },
  443. _onFetchError: function(err, req){
  444. console.log(err);
  445. delete this._lastScrollTop;
  446. if(!this._isLoaded){
  447. this._isLoading = false;
  448. this._isLoaded = true;
  449. this.showMessage(this.errorMessage);
  450. }
  451. this._pending_requests[req.start] = false;
  452. this.onFetchError(err, req);
  453. },
  454. onFetchError: function(err, req){
  455. },
  456. _fetch: function(start, isRender){
  457. start = start || 0;
  458. if(this.store && !this._pending_requests[start]){
  459. if(!this._isLoaded && !this._isLoading){
  460. this._isLoading = true;
  461. this.showMessage(this.loadingMessage);
  462. }
  463. this._pending_requests[start] = true;
  464. //console.log("fetch: ", start);
  465. try{
  466. if(this.items){
  467. var items = this.items;
  468. var store = this.store;
  469. this.rowsPerPage = items.length;
  470. var req = {
  471. start: start,
  472. count: this.rowsPerPage,
  473. isRender: isRender
  474. };
  475. this._onFetchBegin(items.length, req);
  476. // Load them if we need to
  477. var waitCount = 0;
  478. array.forEach(items, function(i){
  479. if(!store.isItemLoaded(i)){ waitCount++; }
  480. });
  481. if(waitCount === 0){
  482. this._onFetchComplete(items, req);
  483. }else{
  484. var onItem = function(item){
  485. waitCount--;
  486. if(waitCount === 0){
  487. this._onFetchComplete(items, req);
  488. }
  489. };
  490. array.forEach(items, function(i){
  491. if(!store.isItemLoaded(i)){
  492. store.loadItem({item: i, onItem: onItem, scope: this});
  493. }
  494. }, this);
  495. }
  496. }else{
  497. this.store.fetch({
  498. start: start,
  499. count: this.rowsPerPage,
  500. query: this.query,
  501. sort: this.getSortProps(),
  502. queryOptions: this.queryOptions,
  503. isRender: isRender,
  504. onBegin: lang.hitch(this, "_onFetchBegin"),
  505. onComplete: lang.hitch(this, "_onFetchComplete"),
  506. onError: lang.hitch(this, "_onFetchError")
  507. });
  508. }
  509. }catch(e){
  510. this._onFetchError(e, {start: start, count: this.rowsPerPage});
  511. }
  512. }
  513. },
  514. _clearData: function(){
  515. this.updateRowCount(0);
  516. this._by_idty = {};
  517. this._by_idx = [];
  518. this._pages = [];
  519. this._bop = this._eop = -1;
  520. this._isLoaded = false;
  521. this._isLoading = false;
  522. },
  523. getItem: function(idx){
  524. var data = this._by_idx[idx];
  525. if(!data||(data&&!data.item)){
  526. this._preparePage(idx);
  527. return null;
  528. }
  529. return data.item;
  530. },
  531. getItemIndex: function(item){
  532. return this._getItemIndex(item, false);
  533. },
  534. _getItemIndex: function(item, isDeleted){
  535. if(!isDeleted && !this.store.isItem(item)){
  536. return -1;
  537. }
  538. var idty = this._hasIdentity ? this.store.getIdentity(item) : null;
  539. for(var i=0, l=this._by_idx.length; i<l; i++){
  540. var d = this._by_idx[i];
  541. if(d && ((idty && d.idty == idty) || (d.item === item))){
  542. return i;
  543. }
  544. }
  545. return -1;
  546. },
  547. filter: function(query, reRender){
  548. this.query = query;
  549. if(reRender){
  550. this._clearData();
  551. }
  552. this._fetch();
  553. },
  554. _getItemAttr: function(idx, attr){
  555. var item = this.getItem(idx);
  556. return (!item ? this.fetchText : this.store.getValue(item, attr));
  557. },
  558. // rendering
  559. _render: function(){
  560. if(this.domNode.parentNode){
  561. this.scroller.init(this.get('rowCount'), this.keepRows, this.rowsPerPage);
  562. this.prerender();
  563. this._fetch(0, true);
  564. }
  565. },
  566. // paging
  567. _requestsPending: function(inRowIndex){
  568. return this._pending_requests[inRowIndex];
  569. },
  570. _rowToPage: function(inRowIndex){
  571. return (this.rowsPerPage ? Math.floor(inRowIndex / this.rowsPerPage) : inRowIndex);
  572. },
  573. _pageToRow: function(inPageIndex){
  574. return (this.rowsPerPage ? this.rowsPerPage * inPageIndex : inPageIndex);
  575. },
  576. _preparePage: function(inRowIndex){
  577. if((inRowIndex < this._bop || inRowIndex >= this._eop) && !this._addingItem){
  578. var pageIndex = this._rowToPage(inRowIndex);
  579. this._needPage(pageIndex);
  580. this._bop = pageIndex * this.rowsPerPage;
  581. this._eop = this._bop + (this.rowsPerPage || this.get('rowCount'));
  582. }
  583. },
  584. _needPage: function(inPageIndex){
  585. if(!this._pages[inPageIndex]){
  586. this._pages[inPageIndex] = true;
  587. this._requestPage(inPageIndex);
  588. }
  589. },
  590. _requestPage: function(inPageIndex){
  591. var row = this._pageToRow(inPageIndex);
  592. var count = Math.min(this.rowsPerPage, this.get('rowCount') - row);
  593. if(count > 0){
  594. this._requests++;
  595. if(!this._requestsPending(row)){
  596. setTimeout(lang.hitch(this, "_fetch", row, false), 1);
  597. //this.requestRows(row, count);
  598. }
  599. }
  600. },
  601. getCellName: function(inCell){
  602. return inCell.field;
  603. //console.log(inCell);
  604. },
  605. _refresh: function(isRender){
  606. this._clearData();
  607. this._fetch(0, isRender);
  608. },
  609. sort: function(){
  610. this.edit.apply();
  611. this._lastScrollTop = this.scrollTop;
  612. this._refresh();
  613. },
  614. canSort: function(){
  615. return (!this._isLoading);
  616. },
  617. getSortProps: function(){
  618. var c = this.getCell(this.getSortIndex());
  619. if(!c){
  620. if(this.sortFields){
  621. return this.sortFields;
  622. }
  623. return null;
  624. }else{
  625. var desc = c["sortDesc"];
  626. var si = !(this.sortInfo>0);
  627. if(typeof desc == "undefined"){
  628. desc = si;
  629. }else{
  630. desc = si ? !desc : desc;
  631. }
  632. return [{ attribute: c.field, descending: desc }];
  633. }
  634. },
  635. styleRowState: function(inRow){
  636. // summary: Perform row styling
  637. if(this.store && this.store.getState){
  638. var states=this.store.getState(inRow.index), c='';
  639. for(var i=0, ss=["inflight", "error", "inserting"], s; s=ss[i]; i++){
  640. if(states[s]){
  641. c = ' dojoxGridRow-' + s;
  642. break;
  643. }
  644. }
  645. inRow.customClasses += c;
  646. }
  647. },
  648. onStyleRow: function(inRow){
  649. this.styleRowState(inRow);
  650. this.inherited(arguments);
  651. },
  652. // editing
  653. canEdit: function(inCell, inRowIndex){
  654. return this._canEdit;
  655. },
  656. _copyAttr: function(idx, attr){
  657. var row = {};
  658. var backstop = {};
  659. var src = this.getItem(idx);
  660. return this.store.getValue(src, attr);
  661. },
  662. doStartEdit: function(inCell, inRowIndex){
  663. if(!this._cache[inRowIndex]){
  664. this._cache[inRowIndex] = this._copyAttr(inRowIndex, inCell.field);
  665. }
  666. this.onStartEdit(inCell, inRowIndex);
  667. },
  668. doApplyCellEdit: function(inValue, inRowIndex, inAttrName){
  669. this.store.fetchItemByIdentity({
  670. identity: this._by_idx[inRowIndex].idty,
  671. onItem: lang.hitch(this, function(item){
  672. var oldValue = this.store.getValue(item, inAttrName);
  673. if(typeof oldValue == 'number'){
  674. inValue = isNaN(inValue) ? inValue : parseFloat(inValue);
  675. }else if(typeof oldValue == 'boolean'){
  676. inValue = inValue == 'true' ? true : inValue == 'false' ? false : inValue;
  677. }else if(oldValue instanceof Date){
  678. var asDate = new Date(inValue);
  679. inValue = isNaN(asDate.getTime()) ? inValue : asDate;
  680. }
  681. this.store.setValue(item, inAttrName, inValue);
  682. this.onApplyCellEdit(inValue, inRowIndex, inAttrName);
  683. })
  684. });
  685. },
  686. doCancelEdit: function(inRowIndex){
  687. var cache = this._cache[inRowIndex];
  688. if(cache){
  689. this.updateRow(inRowIndex);
  690. delete this._cache[inRowIndex];
  691. }
  692. this.onCancelEdit.apply(this, arguments);
  693. },
  694. doApplyEdit: function(inRowIndex, inDataAttr){
  695. var cache = this._cache[inRowIndex];
  696. /*if(cache){
  697. var data = this.getItem(inRowIndex);
  698. if(this.store.getValue(data, inDataAttr) != cache){
  699. this.update(cache, data, inRowIndex);
  700. }
  701. delete this._cache[inRowIndex];
  702. }*/
  703. this.onApplyEdit(inRowIndex);
  704. },
  705. removeSelectedRows: function(){
  706. // summary:
  707. // Remove the selected rows from the grid.
  708. if(this._canEdit){
  709. this.edit.apply();
  710. var fx = lang.hitch(this, function(items){
  711. if(items.length){
  712. array.forEach(items, this.store.deleteItem, this.store);
  713. this.selection.clear();
  714. }
  715. });
  716. if(this.allItemsSelected){
  717. this.store.fetch({
  718. query: this.query,
  719. queryOptions: this.queryOptions,
  720. onComplete: fx});
  721. }else{
  722. fx(this.selection.getSelected());
  723. }
  724. }
  725. }
  726. });
  727. DataGrid.cell_markupFactory = function(cellFunc, node, cellDef){
  728. var field = lang.trim(html.attr(node, "field")||"");
  729. if(field){
  730. cellDef.field = field;
  731. }
  732. cellDef.field = cellDef.field||cellDef.name;
  733. var fields = lang.trim(html.attr(node, "fields")||"");
  734. if(fields){
  735. cellDef.fields = fields.split(",");
  736. }
  737. if(cellFunc){
  738. cellFunc(node, cellDef);
  739. }
  740. };
  741. DataGrid.markupFactory = function(props, node, ctor, cellFunc){
  742. return _Grid.markupFactory(props, node, ctor,
  743. lang.partial(DataGrid.cell_markupFactory, cellFunc));
  744. };
  745. return DataGrid;
  746. });
  747. },
  748. 'dijit/_TemplatedMixin':function(){
  749. define("dijit/_TemplatedMixin", [
  750. "dojo/_base/lang", // lang.getObject
  751. "dojo/touch",
  752. "./_WidgetBase",
  753. "dojo/string", // string.substitute string.trim
  754. "dojo/cache", // dojo.cache
  755. "dojo/_base/array", // array.forEach
  756. "dojo/_base/declare", // declare
  757. "dojo/dom-construct", // domConstruct.destroy, domConstruct.toDom
  758. "dojo/_base/sniff", // has("ie")
  759. "dojo/_base/unload", // unload.addOnWindowUnload
  760. "dojo/_base/window" // win.doc
  761. ], function(lang, touch, _WidgetBase, string, cache, array, declare, domConstruct, has, unload, win) {
  762. /*=====
  763. var _WidgetBase = dijit._WidgetBase;
  764. =====*/
  765. // module:
  766. // dijit/_TemplatedMixin
  767. // summary:
  768. // Mixin for widgets that are instantiated from a template
  769. var _TemplatedMixin = declare("dijit._TemplatedMixin", null, {
  770. // summary:
  771. // Mixin for widgets that are instantiated from a template
  772. // templateString: [protected] String
  773. // A string that represents the widget template.
  774. // Use in conjunction with dojo.cache() to load from a file.
  775. templateString: null,
  776. // templatePath: [protected deprecated] String
  777. // Path to template (HTML file) for this widget relative to dojo.baseUrl.
  778. // Deprecated: use templateString with require([... "dojo/text!..."], ...) instead
  779. templatePath: null,
  780. // skipNodeCache: [protected] Boolean
  781. // If using a cached widget template nodes poses issues for a
  782. // particular widget class, it can set this property to ensure
  783. // that its template is always re-built from a string
  784. _skipNodeCache: false,
  785. // _earlyTemplatedStartup: Boolean
  786. // A fallback to preserve the 1.0 - 1.3 behavior of children in
  787. // templates having their startup called before the parent widget
  788. // fires postCreate. Defaults to 'false', causing child widgets to
  789. // have their .startup() called immediately before a parent widget
  790. // .startup(), but always after the parent .postCreate(). Set to
  791. // 'true' to re-enable to previous, arguably broken, behavior.
  792. _earlyTemplatedStartup: false,
  793. /*=====
  794. // _attachPoints: [private] String[]
  795. // List of widget attribute names associated with data-dojo-attach-point=... in the
  796. // template, ex: ["containerNode", "labelNode"]
  797. _attachPoints: [],
  798. =====*/
  799. /*=====
  800. // _attachEvents: [private] Handle[]
  801. // List of connections associated with data-dojo-attach-event=... in the
  802. // template
  803. _attachEvents: [],
  804. =====*/
  805. constructor: function(){
  806. this._attachPoints = [];
  807. this._attachEvents = [];
  808. },
  809. _stringRepl: function(tmpl){
  810. // summary:
  811. // Does substitution of ${foo} type properties in template string
  812. // tags:
  813. // private
  814. var className = this.declaredClass, _this = this;
  815. // Cache contains a string because we need to do property replacement
  816. // do the property replacement
  817. return string.substitute(tmpl, this, function(value, key){
  818. if(key.charAt(0) == '!'){ value = lang.getObject(key.substr(1), false, _this); }
  819. if(typeof value == "undefined"){ throw new Error(className+" template:"+key); } // a debugging aide
  820. if(value == null){ return ""; }
  821. // Substitution keys beginning with ! will skip the transform step,
  822. // in case a user wishes to insert unescaped markup, e.g. ${!foo}
  823. return key.charAt(0) == "!" ? value :
  824. // Safer substitution, see heading "Attribute values" in
  825. // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
  826. value.toString().replace(/"/g,"&quot;"); //TODO: add &amp? use encodeXML method?
  827. }, this);
  828. },
  829. buildRendering: function(){
  830. // summary:
  831. // Construct the UI for this widget from a template, setting this.domNode.
  832. // tags:
  833. // protected
  834. if(!this.templateString){
  835. this.templateString = cache(this.templatePath, {sanitize: true});
  836. }
  837. // Lookup cached version of template, and download to cache if it
  838. // isn't there already. Returns either a DomNode or a string, depending on
  839. // whether or not the template contains ${foo} replacement parameters.
  840. var cached = _TemplatedMixin.getCachedTemplate(this.templateString, this._skipNodeCache);
  841. var node;
  842. if(lang.isString(cached)){
  843. node = domConstruct.toDom(this._stringRepl(cached));
  844. if(node.nodeType != 1){
  845. // Flag common problems such as templates with multiple top level nodes (nodeType == 11)
  846. throw new Error("Invalid template: " + cached);
  847. }
  848. }else{
  849. // if it's a node, all we have to do is clone it
  850. node = cached.cloneNode(true);
  851. }
  852. this.domNode = node;
  853. // Call down to _Widget.buildRendering() to get base classes assigned
  854. // TODO: change the baseClass assignment to _setBaseClassAttr
  855. this.inherited(arguments);
  856. // recurse through the node, looking for, and attaching to, our
  857. // attachment points and events, which should be defined on the template node.
  858. this._attachTemplateNodes(node, function(n,p){ return n.getAttribute(p); });
  859. this._beforeFillContent(); // hook for _WidgetsInTemplateMixin
  860. this._fillContent(this.srcNodeRef);
  861. },
  862. _beforeFillContent: function(){
  863. },
  864. _fillContent: function(/*DomNode*/ source){
  865. // summary:
  866. // Relocate source contents to templated container node.
  867. // this.containerNode must be able to receive children, or exceptions will be thrown.
  868. // tags:
  869. // protected
  870. var dest = this.containerNode;
  871. if(source && dest){
  872. while(source.hasChildNodes()){
  873. dest.appendChild(source.firstChild);
  874. }
  875. }
  876. },
  877. _attachTemplateNodes: function(rootNode, getAttrFunc){
  878. // summary:
  879. // Iterate through the template and attach functions and nodes accordingly.
  880. // Alternately, if rootNode is an array of widgets, then will process data-dojo-attach-point
  881. // etc. for those widgets.
  882. // description:
  883. // Map widget properties and functions to the handlers specified in
  884. // the dom node and it's descendants. This function iterates over all
  885. // nodes and looks for these properties:
  886. // * dojoAttachPoint/data-dojo-attach-point
  887. // * dojoAttachEvent/data-dojo-attach-event
  888. // rootNode: DomNode|Widget[]
  889. // the node to search for properties. All children will be searched.
  890. // getAttrFunc: Function
  891. // a function which will be used to obtain property for a given
  892. // DomNode/Widget
  893. // tags:
  894. // private
  895. var nodes = lang.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*"));
  896. var x = lang.isArray(rootNode) ? 0 : -1;
  897. for(; x<nodes.length; x++){
  898. var baseNode = (x == -1) ? rootNode : nodes[x];
  899. if(this.widgetsInTemplate && (getAttrFunc(baseNode, "dojoType") || getAttrFunc(baseNode, "data-dojo-type"))){
  900. continue;
  901. }
  902. // Process data-dojo-attach-point
  903. var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint") || getAttrFunc(baseNode, "data-dojo-attach-point");
  904. if(attachPoint){
  905. var point, points = attachPoint.split(/\s*,\s*/);
  906. while((point = points.shift())){
  907. if(lang.isArray(this[point])){
  908. this[point].push(baseNode);
  909. }else{
  910. this[point]=baseNode;
  911. }
  912. this._attachPoints.push(point);
  913. }
  914. }
  915. // Process data-dojo-attach-event
  916. var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent") || getAttrFunc(baseNode, "data-dojo-attach-event");
  917. if(attachEvent){
  918. // NOTE: we want to support attributes that have the form
  919. // "domEvent: nativeEvent; ..."
  920. var event, events = attachEvent.split(/\s*,\s*/);
  921. var trim = lang.trim;
  922. while((event = events.shift())){
  923. if(event){
  924. var thisFunc = null;
  925. if(event.indexOf(":") != -1){
  926. // oh, if only JS had tuple assignment
  927. var funcNameArr = event.split(":");
  928. event = trim(funcNameArr[0]);
  929. thisFunc = trim(funcNameArr[1]);
  930. }else{
  931. event = trim(event);
  932. }
  933. if(!thisFunc){
  934. thisFunc = event;
  935. }
  936. // Map "press", "move" and "release" to keys.touch, keys.move, keys.release
  937. this._attachEvents.push(this.connect(baseNode, touch[event] || event, thisFunc));
  938. }
  939. }
  940. }
  941. }
  942. },
  943. destroyRendering: function(){
  944. // Delete all attach points to prevent IE6 memory leaks.
  945. array.forEach(this._attachPoints, function(point){
  946. delete this[point];
  947. }, this);
  948. this._attachPoints = [];
  949. // And same for event handlers
  950. array.forEach(this._attachEvents, this.disconnect, this);
  951. this._attachEvents = [];
  952. this.inherited(arguments);
  953. }
  954. });
  955. // key is templateString; object is either string or DOM tree
  956. _TemplatedMixin._templateCache = {};
  957. _TemplatedMixin.getCachedTemplate = function(templateString, alwaysUseString){
  958. // summary:
  959. // Static method to get a template based on the templatePath or
  960. // templateString key
  961. // templateString: String
  962. // The template
  963. // alwaysUseString: Boolean
  964. // Don't cache the DOM tree for this template, even if it doesn't have any variables
  965. // returns: Mixed
  966. // Either string (if there are ${} variables that need to be replaced) or just
  967. // a DOM tree (if the node can be cloned directly)
  968. // is it already cached?
  969. var tmplts = _TemplatedMixin._templateCache;
  970. var key = templateString;
  971. var cached = tmplts[key];
  972. if(cached){
  973. try{
  974. // if the cached value is an innerHTML string (no ownerDocument) or a DOM tree created within the current document, then use the current cached value
  975. if(!cached.ownerDocument || cached.ownerDocument == win.doc){
  976. // string or node of the same document
  977. return cached;
  978. }
  979. }catch(e){ /* squelch */ } // IE can throw an exception if cached.ownerDocument was reloaded
  980. domConstruct.destroy(cached);
  981. }
  982. templateString = string.trim(templateString);
  983. if(alwaysUseString || templateString.match(/\$\{([^\}]+)\}/g)){
  984. // there are variables in the template so all we can do is cache the string
  985. return (tmplts[key] = templateString); //String
  986. }else{
  987. // there are no variables in the template so we can cache the DOM tree
  988. var node = domConstruct.toDom(templateString);
  989. if(node.nodeType != 1){
  990. throw new Error("Invalid template: " + templateString);
  991. }
  992. return (tmplts[key] = node); //Node
  993. }
  994. };
  995. if(has("ie")){
  996. unload.addOnWindowUnload(function(){
  997. var cache = _TemplatedMixin._templateCache;
  998. for(var key in cache){
  999. var value = cache[key];
  1000. if(typeof value == "object"){ // value is either a string or a DOM node template
  1001. domConstruct.destroy(value);
  1002. }
  1003. delete cache[key];
  1004. }
  1005. });
  1006. }
  1007. // These arguments can be specified for widgets which are used in templates.
  1008. // Since any widget can be specified as sub widgets in template, mix it
  1009. // into the base widget class. (This is a hack, but it's effective.)
  1010. lang.extend(_WidgetBase,{
  1011. dojoAttachEvent: "",
  1012. dojoAttachPoint: ""
  1013. });
  1014. return _TemplatedMixin;
  1015. });
  1016. },
  1017. 'dojox/grid/_FocusManager':function(){
  1018. define("dojox/grid/_FocusManager", [
  1019. "dojo/_base/array",
  1020. "dojo/_base/lang",
  1021. "dojo/_base/declare",
  1022. "dojo/_base/connect",
  1023. "dojo/_base/event",
  1024. "dojo/_base/sniff",
  1025. "dojo/query",
  1026. "./util",
  1027. "dojo/_base/html"
  1028. ], function(array, lang, declare, connect, event, has, query, util, html){
  1029. // focus management
  1030. return declare("dojox.grid._FocusManager", null, {
  1031. // summary:
  1032. // Controls grid cell focus. Owned by grid and used internally for focusing.
  1033. // Note: grid cell actually receives keyboard input only when cell is being edited.
  1034. constructor: function(inGrid){
  1035. this.grid = inGrid;
  1036. this.cell = null;
  1037. this.rowIndex = -1;
  1038. this._connects = [];
  1039. this._headerConnects = [];
  1040. this.headerMenu = this.grid.headerMenu;
  1041. this._connects.push(connect.connect(this.grid.domNode, "onfocus", this, "doFocus"));
  1042. this._connects.push(connect.connect(this.grid.domNode, "onblur", this, "doBlur"));
  1043. this._connects.push(connect.connect(this.grid.domNode, "mousedown", this, "_mouseDown"));
  1044. this._connects.push(connect.connect(this.grid.domNode, "mouseup", this, "_mouseUp"));
  1045. this._connects.push(connect.connect(this.grid.domNode, "oncontextmenu", this, "doContextMenu"));
  1046. this._connects.push(connect.connect(this.grid.lastFocusNode, "onfocus", this, "doLastNodeFocus"));
  1047. this._connects.push(connect.connect(this.grid.lastFocusNode, "onblur", this, "doLastNodeBlur"));
  1048. this._connects.push(connect.connect(this.grid,"_onFetchComplete", this, "_delayedCellFocus"));
  1049. this._connects.push(connect.connect(this.grid,"postrender", this, "_delayedHeaderFocus"));
  1050. },
  1051. destroy: function(){
  1052. array.forEach(this._connects, connect.disconnect);
  1053. array.forEach(this._headerConnects, connect.disconnect);
  1054. delete this.grid;
  1055. delete this.cell;
  1056. },
  1057. _colHeadNode: null,
  1058. _colHeadFocusIdx: null,
  1059. _contextMenuBindNode: null,
  1060. tabbingOut: false,
  1061. focusClass: "dojoxGridCellFocus",
  1062. focusView: null,
  1063. initFocusView: function(){
  1064. this.focusView = this.grid.views.getFirstScrollingView() || this.focusView || this.grid.views.views[0];
  1065. this._initColumnHeaders();
  1066. },
  1067. isFocusCell: function(inCell, inRowIndex){
  1068. // summary:
  1069. // states if the given cell is focused
  1070. // inCell: object
  1071. // grid cell object
  1072. // inRowIndex: int
  1073. // grid row index
  1074. // returns:
  1075. // true of the given grid cell is focused
  1076. return (this.cell == inCell) && (this.rowIndex == inRowIndex);
  1077. },
  1078. isLastFocusCell: function(){
  1079. if(this.cell){
  1080. return (this.rowIndex == this.grid.rowCount-1) && (this.cell.index == this.grid.layout.cellCount-1);
  1081. }
  1082. return false;
  1083. },
  1084. isFirstFocusCell: function(){
  1085. if(this.cell){
  1086. return (this.rowIndex === 0) && (this.cell.index === 0);
  1087. }
  1088. return false;
  1089. },
  1090. isNoFocusCell: function(){
  1091. return (this.rowIndex < 0) || !this.cell;
  1092. },
  1093. isNavHeader: function(){
  1094. // summary:
  1095. // states whether currently navigating among column headers.
  1096. // returns:
  1097. // true if focus is on a column header; false otherwise.
  1098. return (!!this._colHeadNode);
  1099. },
  1100. getHeaderIndex: function(){
  1101. // summary:
  1102. // if one of the column headers currently has focus, return its index.
  1103. // returns:
  1104. // index of the focused column header, or -1 if none have focus.
  1105. if(this._colHeadNode){
  1106. return array.indexOf(this._findHeaderCells(), this._colHeadNode);
  1107. }else{
  1108. return -1;
  1109. }
  1110. },
  1111. _focusifyCellNode: function(inBork){
  1112. var n = this.cell && this.cell.getNode(this.rowIndex);
  1113. if(n){
  1114. html.toggleClass(n, this.focusClass, inBork);
  1115. if(inBork){
  1116. var sl = this.scrollIntoView();
  1117. try{
  1118. if(!this.grid.edit.isEditing()){
  1119. util.fire(n, "focus");
  1120. if(sl){ this.cell.view.scrollboxNode.scrollLeft = sl; }
  1121. }
  1122. }catch(e){}
  1123. }
  1124. }
  1125. },
  1126. _delayedCellFocus: function(){
  1127. if(this.isNavHeader()||!this.grid.focused){
  1128. return;
  1129. }
  1130. var n = this.cell && this.cell.getNode(this.rowIndex);
  1131. if(n){
  1132. try{
  1133. if(!this.grid.edit.isEditing()){
  1134. html.toggleClass(n, this.focusClass, true);
  1135. if(this._colHeadNode){
  1136. this.blurHeader();
  1137. }
  1138. util.fire(n, "focus");
  1139. }
  1140. }
  1141. catch(e){}
  1142. }
  1143. },
  1144. _delayedHeaderFocus: function(){
  1145. if(this.isNavHeader()){
  1146. this.focusHeader();
  1147. this.grid.domNode.focus();
  1148. }
  1149. },
  1150. _initColumnHeaders: function(){
  1151. array.forEach(this._headerConnects, connect.disconnect);
  1152. this._headerConnects = [];
  1153. var headers = this._findHeaderCells();
  1154. for(var i = 0; i < headers.length; i++){
  1155. this._headerConnects.push(connect.connect(headers[i], "onfocus", this, "doColHeaderFocus"));
  1156. this._headerConnects.push(connect.connect(headers[i], "onblur", this, "doColHeaderBlur"));
  1157. }
  1158. },
  1159. _findHeaderCells: function(){
  1160. // This should be a one liner:
  1161. // query("th[tabindex=-1]", this.grid.viewsHeaderNode);
  1162. // But there is a bug in query() for IE -- see trac #7037.
  1163. var allHeads = query("th", this.grid.viewsHeaderNode);
  1164. var headers = [];
  1165. for (var i = 0; i < allHeads.length; i++){
  1166. var aHead = allHeads[i];
  1167. var hasTabIdx = html.hasAttr(aHead, "tabIndex");
  1168. var tabindex = html.attr(aHead, "tabIndex");
  1169. if (hasTabIdx && tabindex < 0) {
  1170. headers.push(aHead);
  1171. }
  1172. }
  1173. return headers;
  1174. },
  1175. _setActiveColHeader: function(/*Node*/colHeaderNode, /*Integer*/colFocusIdx, /*Integer*/ prevColFocusIdx){
  1176. //console.log("setActiveColHeader() - colHeaderNode:colFocusIdx:prevColFocusIdx = " + colHeaderNode + ":" + colFocusIdx + ":" + prevColFocusIdx);
  1177. this.grid.domNode.setAttribute("aria-activedescendant",colHeaderNode.id);
  1178. if (prevColFocusIdx != null && prevColFocusIdx >= 0 && prevColFocusIdx != colFocusIdx){
  1179. html.toggleClass(this._findHeaderCells()[prevColFocusIdx],this.focusClass,false);
  1180. }
  1181. html.toggleClass(colHeaderNode,this.focusClass, true);
  1182. this._colHeadNode = colHeaderNode;
  1183. this._colHeadFocusIdx = colFocusIdx;
  1184. this._scrollHeader(this._colHeadFocusIdx);
  1185. },
  1186. scrollIntoView: function(){
  1187. var info = (this.cell ? this._scrollInfo(this.cell) : null);
  1188. if(!info || !info.s){
  1189. return null;
  1190. }
  1191. var rt = this.grid.scroller.findScrollTop(this.rowIndex);
  1192. // place cell within horizontal view
  1193. if(info.n && info.sr){
  1194. if(info.n.offsetLeft + info.n.offsetWidth > info.sr.l + info.sr.w){
  1195. info.s.scrollLeft = info.n.offsetLeft + info.n.offsetWidth - info.sr.w;
  1196. }else if(info.n.offsetLeft < info.sr.l){
  1197. info.s.scrollLeft = info.n.offsetLeft;
  1198. }
  1199. }
  1200. // place cell within vertical view
  1201. if(info.r && info.sr){
  1202. if(rt + info.r.offsetHeight > info.sr.t + info.sr.h){
  1203. this.grid.setScrollTop(rt + info.r.offsetHeight - info.sr.h);
  1204. }else if(rt < info.sr.t){
  1205. this.grid.setScrollTop(rt);
  1206. }
  1207. }
  1208. return info.s.scrollLeft;
  1209. },
  1210. _scrollInfo: function(cell, domNode){
  1211. if(cell){
  1212. var cl = cell,
  1213. sbn = cl.view.scrollboxNode,
  1214. sbnr = {
  1215. w: sbn.clientWidth,
  1216. l: sbn.scrollLeft,
  1217. t: sbn.scrollTop,
  1218. h: sbn.clientHeight
  1219. },
  1220. rn = cl.view.getRowNode(this.rowIndex);
  1221. return {
  1222. c: cl,
  1223. s: sbn,
  1224. sr: sbnr,
  1225. n: (domNode ? domNode : cell.getNode(this.rowIndex)),
  1226. r: rn
  1227. };
  1228. }
  1229. return null;
  1230. },
  1231. _scrollHeader: function(currentIdx){
  1232. var info = null;
  1233. if(this._colHeadNode){
  1234. var cell = this.grid.getCell(currentIdx);
  1235. if(!cell){ return; }
  1236. info = this._scrollInfo(cell, cell.getNode(0));
  1237. }
  1238. if(info && info.s && info.sr && info.n){
  1239. // scroll horizontally as needed.
  1240. var scroll = info.sr.l + info.sr.w;
  1241. if(info.n.offsetLeft + info.n.offsetWidth > scroll){
  1242. info.s.scrollLeft = info.n.offsetLeft + info.n.offsetWidth - info.sr.w;
  1243. }else if(info.n.offsetLeft < info.sr.l){
  1244. info.s.scrollLeft = info.n.offsetLeft;
  1245. }else if(has("ie") <= 7 && cell && cell.view.headerNode){
  1246. // Trac 7158: scroll dojoxGridHeader for IE7 and lower
  1247. cell.view.headerNode.scrollLeft = info.s.scrollLeft;
  1248. }
  1249. }
  1250. },
  1251. _isHeaderHidden: function(){
  1252. // summary:
  1253. // determine if the grid headers are hidden
  1254. // relies on documented technique of setting .dojoxGridHeader { display:none; }
  1255. // returns: Boolean
  1256. // true if headers are hidden
  1257. // false if headers are not hidden
  1258. var curView = this.focusView;
  1259. if (!curView){
  1260. // find one so we can determine if headers are hidden
  1261. // there is no focusView after adding items to empty grid (test_data_grid_empty.html)
  1262. for (var i = 0, cView; (cView = this.grid.views.views[i]); i++) {
  1263. if(cView.headerNode ){
  1264. curView=cView;
  1265. break;
  1266. }
  1267. }
  1268. }
  1269. return (curView && html.getComputedStyle(curView.headerNode).display == "none");
  1270. },
  1271. colSizeAdjust: function (e, colIdx, delta){ // adjust the column specified by colIdx by the specified delta px
  1272. var headers = this._findHeaderCells();
  1273. var view = this.focusView;
  1274. if (!view) {
  1275. for (var i = 0, cView; (cView = this.grid.views.views[i]); i++) {
  1276. // find first view with a tableMap in order to work with empty grid
  1277. if(cView.header.tableMap.map ){
  1278. view=cView;
  1279. break;
  1280. }
  1281. }
  1282. }
  1283. var curHeader = headers[colIdx];
  1284. if (!view || (colIdx == headers.length-1 && colIdx === 0)){
  1285. return; // can't adjust single col. grid
  1286. }
  1287. view.content.baseDecorateEvent(e);
  1288. // need to adjust event with header cell info since focus is no longer on header cell
  1289. e.cellNode = curHeader; //this.findCellTarget(e.target, e.rowNode);
  1290. e.cellIndex = view.content.getCellNodeIndex(e.cellNode);
  1291. e.cell = (e.cellIndex >= 0 ? this.grid.getCell(e.cellIndex) : null);
  1292. if (view.header.canResize(e)){
  1293. var deltaObj = {
  1294. l: delta
  1295. };
  1296. var drag = view.header.colResizeSetup(e,false);
  1297. view.header.doResizeColumn(drag, null, deltaObj);
  1298. view.update();
  1299. }
  1300. },
  1301. styleRow: function(inRow){
  1302. return;
  1303. },
  1304. setFocusIndex: function(inRowIndex, inCellIndex){
  1305. // summary:
  1306. // focuses the given grid cell
  1307. // inRowIndex: int
  1308. // grid row index
  1309. // inCellIndex: int
  1310. // grid cell index
  1311. this.setFocusCell(this.grid.getCell(inCellIndex), inRowIndex);
  1312. },
  1313. setFocusCell: function(inCell, inRowIndex){
  1314. // summary:
  1315. // focuses the given grid cell
  1316. // inCell: object
  1317. // grid cell object
  1318. // inRowIndex: int
  1319. // grid row index
  1320. if(inCell && !this.isFocusCell(inCell, inRowIndex)){
  1321. this.tabbingOut = false;
  1322. if (this._colHeadNode){
  1323. this.blurHeader();
  1324. }
  1325. this._colHeadNode = this._colHeadFocusIdx = null;
  1326. this.focusGridView();
  1327. this._focusifyCellNode(false);
  1328. this.cell = inCell;
  1329. this.rowIndex = inRowIndex;
  1330. this._focusifyCellNode(true);
  1331. }
  1332. // even if this cell isFocusCell, the document focus may need to be rejiggered
  1333. // call opera on delay to prevent keypress from altering focus
  1334. if(has("opera")){
  1335. setTimeout(lang.hitch(this.grid, 'onCellFocus', this.cell, this.rowIndex), 1);
  1336. }else{
  1337. this.grid.onCellFocus(this.cell, this.rowIndex);
  1338. }
  1339. },
  1340. next: function(){
  1341. // summary:
  1342. // focus next grid cell
  1343. if(this.cell){
  1344. var row=this.rowIndex, col=this.cell.index+1, cc=this.grid.layout.cellCount-1, rc=this.grid.rowCount-1;
  1345. if(col > cc){
  1346. col = 0;
  1347. row++;
  1348. }
  1349. if(row > rc){
  1350. col = cc;
  1351. row = rc;
  1352. }
  1353. if(this.grid.edit.isEditing()){ //when editing, only navigate to editable cells
  1354. var nextCell = this.grid.getCell(col);
  1355. if (!this.isLastFocusCell() && (!nextCell.editable ||
  1356. this.grid.canEdit && !this.grid.canEdit(nextCell, row))){
  1357. this.cell=nextCell;
  1358. this.rowIndex=row;
  1359. this.next();
  1360. return;
  1361. }
  1362. }
  1363. this.setFocusIndex(row, col);
  1364. }
  1365. },
  1366. previous: function(){
  1367. // summary:
  1368. // focus previous grid cell
  1369. if(this.cell){
  1370. var row=(this.rowIndex || 0), col=(this.cell.index || 0) - 1;
  1371. if(col < 0){
  1372. col = this.grid.layout.cellCount-1;
  1373. row--;
  1374. }
  1375. if(row < 0){
  1376. row = 0;
  1377. col = 0;
  1378. }
  1379. if(this.grid.edit.isEditing()){ //when editing, only navigate to editable cells
  1380. var prevCell = this.grid.getCell(col);
  1381. if (!this.isFirstFocusCell() && !prevCell.editable){
  1382. this.cell=prevCell;
  1383. this.rowIndex=row;
  1384. this.previous();
  1385. return;
  1386. }
  1387. }
  1388. this.setFocusIndex(row, col);
  1389. }
  1390. },
  1391. move: function(inRowDelta, inColDelta) {
  1392. // summary:
  1393. // focus grid cell or simulate focus to column header based on position relative to current focus
  1394. // inRowDelta: int
  1395. // vertical distance from current focus
  1396. // inColDelta: int
  1397. // horizontal distance from current focus
  1398. var colDir = inColDelta < 0 ? -1 : 1;
  1399. // Handle column headers.
  1400. if(this.isNavHeader()){
  1401. var headers = this._findHeaderCells();
  1402. var savedIdx = currentIdx = array.indexOf(headers, this._colHeadNode);
  1403. currentIdx += inColDelta;
  1404. while(currentIdx >=0 && currentIdx < headers.length && headers[currentIdx].style.display == "none"){
  1405. // skip over hidden column headers
  1406. currentIdx += colDir;
  1407. }
  1408. if((currentIdx >= 0) && (currentIdx < headers.length)){
  1409. this._setActiveColHeader(headers[currentIdx],currentIdx, savedIdx);
  1410. }
  1411. }else{
  1412. if(this.cell){
  1413. // Handle grid proper.
  1414. var sc = this.grid.scroller,
  1415. r = this.rowIndex,
  1416. rc = this.grid.rowCount-1,
  1417. row = Math.min(rc, Math.max(0, r+inRowDelta));
  1418. if(inRowDelta){
  1419. if(inRowDelta>0){
  1420. if(row > sc.getLastPageRow(sc.page)){
  1421. //need to load additional data, let scroller do that
  1422. this.grid.setScrollTop(this.grid.scrollTop+sc.findScrollTop(row)-sc.findScrollTop(r));
  1423. }
  1424. }else if(inRowDelta<0){
  1425. if(row <= sc.getPageRow(sc.page)){
  1426. //need to load additional data, let scroller do that
  1427. this.grid.setScrollTop(this.grid.scrollTop-sc.findScrollTop(r)-sc.findScrollTop(row));
  1428. }
  1429. }
  1430. }
  1431. var cc = this.grid.layout.cellCount-1,
  1432. i = this.cell.index,
  1433. col = Math.min(cc, Math.max(0, i+inColDelta));
  1434. var cell = this.grid.getCell(col);
  1435. while(col>=0 && col < cc && cell && cell.hidden === true){
  1436. // skip hidden cells
  1437. col += colDir;
  1438. cell = this.grid.getCell(col);
  1439. }
  1440. if (!cell || cell.hidden === true){
  1441. // don't change col if would move to hidden
  1442. col = i;
  1443. }
  1444. //skip hidden row|cell
  1445. var n = cell.getNode(row);
  1446. if(!n && inRowDelta){
  1447. if((row + inRowDelta) >= 0 && (row + inRowDelta) <= rc){
  1448. this.move(inRowDelta > 0 ? ++inRowDelta : --inRowDelta, inColDelta);
  1449. }
  1450. return;
  1451. }else if((!n || html.style(n, "display") === "none") && inColDelta){
  1452. if((col + inColDelta) >= 0 && (col + inColDelta) <= cc){
  1453. this.move(inRowDelta, inColDelta > 0 ? ++inColDelta : --inColDelta);
  1454. }
  1455. return;
  1456. }
  1457. this.setFocusIndex(row, col);
  1458. if(inRowDelta){
  1459. this.grid.updateRow(r);
  1460. }
  1461. }
  1462. }
  1463. },
  1464. previousKey: function(e){
  1465. if(this.grid.edit.isEditing()){
  1466. event.stop(e);
  1467. this.previous();
  1468. }else if(!this.isNavHeader() && !this._isHeaderHidden()) {
  1469. this.grid.domNode.focus(); // will call doFocus and set focus into header.
  1470. event.stop(e);
  1471. }else{
  1472. this.tabOut(this.grid.domNode);
  1473. if (this._colHeadFocusIdx != null) { // clear grid header focus
  1474. html.toggleClass(this._findHeaderCells()[this._colHeadFocusIdx], this.focusClass, false);
  1475. this._colHeadFocusIdx = null;
  1476. }
  1477. this._focusifyCellNode(false);
  1478. }
  1479. },
  1480. nextKey: function(e) {
  1481. var isEmpty = (this.grid.rowCount === 0);
  1482. if(e.target === this.grid.domNode && this._colHeadFocusIdx == null){
  1483. this.focusHeader();
  1484. event.stop(e);
  1485. }else if(this.isNavHeader()){
  1486. // if tabbing from col header, then go to grid proper.
  1487. this.blurHeader();
  1488. if(!this.findAndFocusGridCell()){
  1489. this.tabOut(this.grid.lastFocusNode);
  1490. }
  1491. this._colHeadNode = this._colHeadFocusIdx= null;
  1492. }else if(this.grid.edit.isEditing()){
  1493. event.stop(e);
  1494. this.next();
  1495. }else{
  1496. this.tabOut(this.grid.lastFocusNode);
  1497. }
  1498. },
  1499. tabOut: function(inFocusNode){
  1500. this.tabbingOut = true;
  1501. inFocusNode.focus();
  1502. },
  1503. focusGridView: function(){
  1504. util.fire(this.focusView, "focus");
  1505. },
  1506. focusGrid: function(inSkipFocusCell){
  1507. this.focusGridView();
  1508. this._focusifyCellNode(true);
  1509. },
  1510. findAndFocusGridCell: function(){
  1511. // summary:
  1512. // find the first focusable grid cell
  1513. // returns: Boolean
  1514. // true if focus was set to a cell
  1515. // false if no cell found to set focus onto
  1516. var didFocus = true;
  1517. var isEmpty = (this.grid.rowCount === 0); // If grid is empty this.grid.rowCount == 0
  1518. if (this.isNoFocusCell() && !isEmpty){
  1519. var cellIdx = 0;
  1520. var cell = this.grid.getCell(cellIdx);
  1521. if (cell.hidden) {
  1522. // if first cell isn't visible, use _colHeadFocusIdx
  1523. // could also use a while loop to find first visible cell - not sure that is worth it
  1524. cellIdx = this.isNavHeader() ? this._colHeadFocusIdx : 0;
  1525. }
  1526. this.setFocusIndex(0, cellIdx);
  1527. }
  1528. else if (this.cell && !isEmpty){
  1529. if (this.focusView && !this.focusView.rowNodes[this.rowIndex]){
  1530. // if rowNode for current index is undefined (likely as a result of a sort and because of #7304)
  1531. // scroll to that row
  1532. this.grid.scrollToRow(this.rowIndex);
  1533. }
  1534. this.focusGrid();
  1535. }else {
  1536. didFocus = false;
  1537. }
  1538. this._colHeadNode = this._colHeadFocusIdx= null;
  1539. return didFocus;
  1540. },
  1541. focusHeader: function(){
  1542. var headerNodes = this._findHeaderCells();
  1543. var saveColHeadFocusIdx = this._colHeadFocusIdx;
  1544. if (this._isHeaderHidden()){
  1545. // grid header is hidden, focus a cell
  1546. this.findAndFocusGridCell();
  1547. }
  1548. else if (!this._colHeadFocusIdx) {
  1549. if (this.isNoFocusCell()) {
  1550. this._colHeadFocusIdx = 0;
  1551. }
  1552. else {
  1553. this._colHeadFocusIdx = this.cell.index;
  1554. }
  1555. }
  1556. this._colHeadNode = headerNodes[this._colHeadFocusIdx];
  1557. while(this._colHeadNode && this._colHeadFocusIdx >=0 && this._colHeadFocusIdx < headerNodes.length &&
  1558. this._colHeadNode.style.display == "none"){
  1559. // skip over hidden column headers
  1560. this._colHeadFocusIdx++;
  1561. this._colHeadNode = headerNodes[this._colHeadFocusIdx];
  1562. }
  1563. if(this._colHeadNode && this._colHeadNode.style.display != "none"){
  1564. // Column header cells know longer receive actual focus. So, for keyboard invocation of
  1565. // contextMenu to work, the contextMenu must be bound to the grid.domNode rather than the viewsHeaderNode.
  1566. // unbind the contextmenu from the viewsHeaderNode and to the grid when header cells are active. Reset
  1567. // the binding back to the viewsHeaderNode when header cells are no longer acive (in blurHeader) #10483
  1568. if (this.headerMenu && this._contextMenuBindNode != this.grid.domNode){
  1569. this.headerMenu.unBindDomNode(this.grid.viewsHeaderNode);
  1570. this.headerMenu.bindDomNode(this.grid.domNode);
  1571. this._contextMenuBindNode = this.grid.domNode;
  1572. }
  1573. this._setActiveColHeader(this._colHeadNode, this._colHeadFocusIdx, saveColHeadFocusIdx);
  1574. this._scrollHeader(this._colHeadFocusIdx);
  1575. this._focusifyCellNode(false);
  1576. }else {
  1577. // all col head nodes are hidden - focus the grid
  1578. this.findAndFocusGridCell();
  1579. }
  1580. },
  1581. blurHeader: function(){
  1582. html.removeClass(this._colHeadNode, this.focusClass);
  1583. html.removeAttr(this.grid.domNode,"aria-activedescendant");
  1584. // reset contextMenu onto viewsHeaderNode so right mouse on header will invoke (see focusHeader)
  1585. if (this.headerMenu && this._contextMenuBindNode == this.grid.domNode) {
  1586. var viewsHeader = this.grid.viewsHeaderNode;
  1587. this.headerMenu.unBindDomNode(this.grid.domNode);
  1588. this.headerMenu.bindDomNode(viewsHeader);
  1589. this._contextMenuBindNode = viewsHeader;
  1590. }
  1591. },
  1592. doFocus: function(e){
  1593. // trap focus only for grid dom node
  1594. if(e && e.target != e.currentTarget){
  1595. event.stop(e);
  1596. return;
  1597. }
  1598. // don't change focus if clicking on scroller bar
  1599. if(this._clickFocus){
  1600. return;
  1601. }
  1602. // do not focus for scrolling if grid is about to blur
  1603. if(!this.tabbingOut){
  1604. this.focusHeader();
  1605. }
  1606. this.tabbingOut = false;
  1607. event.stop(e);
  1608. },
  1609. doBlur: function(e){
  1610. event.stop(e); // FF2
  1611. },
  1612. doContextMenu: function(e){
  1613. //stop contextMenu event if no header Menu to prevent default/browser contextMenu
  1614. if (!this.headerMenu){
  1615. event.stop(e);
  1616. }
  1617. },
  1618. doLastNodeFocus: function(e){
  1619. if (this.tabbingOut){
  1620. this._focusifyCellNode(false);
  1621. }else if(this.grid.rowCount >0){
  1622. if (this.isNoFocusCell()){
  1623. this.setFocusIndex(0,0);
  1624. }
  1625. this._focusifyCellNode(true);
  1626. }else {
  1627. this.focusHeader();
  1628. }
  1629. this.tabbingOut = false;
  1630. event.stop(e); // FF2
  1631. },
  1632. doLastNodeBlur: function(e){
  1633. event.stop(e); // FF2
  1634. },
  1635. doColHeaderFocus: function(e){
  1636. this._setActiveColHeader(e.target,html.attr(e.target, "idx"),this._colHeadFocusIdx);
  1637. this._scrollHeader(this.getHeaderIndex());
  1638. event.stop(e);
  1639. },
  1640. doColHeaderBlur: function(e){
  1641. html.toggleClass(e.target, this.focusClass, false);
  1642. },
  1643. _mouseDown: function(e){
  1644. // a flag indicating grid is being focused by clicking
  1645. this._clickFocus = dojo.some(this.grid.views.views, function(v){
  1646. return v.scrollboxNode === e.target;
  1647. });
  1648. },
  1649. _mouseUp: function(e){
  1650. this._clickFocus = false;
  1651. }
  1652. });
  1653. });
  1654. },
  1655. 'dojox/grid/EnhancedGrid':function(){
  1656. define("dojox/grid/EnhancedGrid", [
  1657. "dojo/_base/kernel",
  1658. "../main",
  1659. "dojo/_base/declare",
  1660. "dojo/_base/lang",
  1661. "dojo/_base/array",
  1662. "dojo/_base/sniff",
  1663. "dojo/dom",
  1664. "dojo/dom-geometry",
  1665. "dojo/i18n",
  1666. "./DataGrid",
  1667. "./DataSelection",
  1668. "./enhanced/_PluginManager",
  1669. "./enhanced/plugins/_SelectionPreserver",//default loaded plugin
  1670. "dojo/i18n!./enhanced/nls/EnhancedGrid"
  1671. ], function(dojo, dojox, declare, lang, array, has, dom, domGeometry, i18n,
  1672. DataGrid, DataSelection, _PluginManager, _SelectionPreserver){
  1673. dojo.experimental("dojox.grid.EnhancedGrid");
  1674. var EnhancedGrid = declare("dojox.grid.EnhancedGrid", DataGrid, {
  1675. // summary:
  1676. // Provides enhanced features based on DataGrid
  1677. //
  1678. // description:
  1679. // EnhancedGrid features are implemented as plugins that could be loaded on demand.
  1680. // Explicit dojo.require() is needed to use these feature plugins.
  1681. //
  1682. // example:
  1683. // A quick sample to use EnhancedGrid features:
  1684. //
  1685. // Step 1. Load EnhancedGrid and required features
  1686. // | <script type="text/javascript">
  1687. // | dojo.require("dojox.grid.EnhancedGrid");
  1688. // | dojo.require("dojox.grid.enhanced.plugins.DnD");
  1689. // | dojo.require("dojox.grid.enhanced.plugins.Menu");
  1690. // | dojo.require("dojox.grid.enhanced.plugins.NestedSorting");
  1691. // | dojo.require("dojox.grid.enhanced.plugins.IndirectSelection");
  1692. // | </script>
  1693. //
  1694. // Step 2. Use EnhancedGrid
  1695. // - Via HTML markup
  1696. // | <div dojoType="dojox.grid.EnhancedGrid" ...
  1697. // | plugins="{nestedSorting: true, dnd: true, indirectSelection: true,
  1698. // | menus:{headerMenu:"headerMenuId", rowMenu:"rowMenuId", cellMenu:"cellMenuId",
  1699. // | selectedRegionMenu:"selectedRegionMenuId"}}">
  1700. // | ...
  1701. // | </div>
  1702. //
  1703. // - Or via JavaScript
  1704. // | <script type="text/javascript">
  1705. // | var grid = new dojox.grid.EnhancedGrid({plugins : {nestedSorting: true, dnd: true, indirectSelection: true,
  1706. // | menus:{headerMenu:"headerMenuId", rowMenu:"rowMenuId", cellMenu:"cellMenuId",selectedRegionMenu:"selectedRegionMenuId"}},
  1707. // | ... }, dojo.byId('gridDiv'));
  1708. // | grid.startup();
  1709. // | </script>
  1710. //
  1711. //
  1712. // Plugin Support
  1713. // [Note: Plugin support is still experimental]
  1714. //
  1715. // You can either customize the default plugins or add new ones, more details please see
  1716. // - dojox.grid.enhanced._PluginManager
  1717. // - dojox.grid.enhanced._Plugin
  1718. // - dojox.grid.enhanced.plugins.*
  1719. //plugins: Object
  1720. // Plugin properties, e.g. {nestedSorting: true, dnd: true, ...}
  1721. plugins: null,
  1722. //pluginMgr: Object
  1723. // Singleton plugin manager
  1724. pluginMgr: null,
  1725. //_pluginMgrClass: Object
  1726. // Default plugin manager class
  1727. _pluginMgrClass: _PluginManager,
  1728. postMixInProperties: function(){
  1729. //load nls bundle
  1730. this._nls = i18n.getLocalization("dojox.grid.enhanced", "EnhancedGrid", this.lang);
  1731. this.inherited(arguments);
  1732. },
  1733. postCreate: function(){
  1734. //create plugin manager
  1735. this.pluginMgr = new this._pluginMgrClass(this);
  1736. this.pluginMgr.preInit();
  1737. this.inherited(arguments);
  1738. this.pluginMgr.postInit();
  1739. },
  1740. plugin: function(/*String*/name){
  1741. // summary:
  1742. // An easier way for getting a plugin, e.g. grid.plugin('dnd')
  1743. return this.pluginMgr.getPlugin(name);
  1744. },
  1745. startup: function(){
  1746. this.inherited(arguments);
  1747. this.pluginMgr.startup();
  1748. },
  1749. createSelection: function(){
  1750. this.selection = new dojox.grid.enhanced.DataSelection(this);
  1751. },
  1752. canSort: function(colIndex, field){
  1753. // summary:
  1754. // Overwritten
  1755. return true;
  1756. },
  1757. doKeyEvent: function(e){
  1758. // summary:
  1759. // Overwritten, see _Grid.doKeyEvent()
  1760. try{
  1761. var view = this.focus.focusView;
  1762. view.content.decorateEvent(e);
  1763. if(!e.cell){ view.header.decorateEvent(e); }
  1764. }catch(e){}
  1765. this.inherited(arguments);
  1766. },
  1767. doApplyCellEdit: function(inValue, inRowIndex, inAttrName){
  1768. // summary:
  1769. // Overwritten, see DataGrid.doApplyCellEdit()
  1770. if(!inAttrName){
  1771. this.invalidated[inRowIndex] = true;
  1772. return;
  1773. }
  1774. this.inherited(arguments);
  1775. },
  1776. mixin: function(target, source){
  1777. var props = {};
  1778. for(var p in source){
  1779. if(p == '_inherited' || p == 'declaredClass' || p == 'constructor' ||
  1780. source['privates'] && source['privates'][p]){
  1781. continue;
  1782. }
  1783. props[p] = source[p];
  1784. }
  1785. lang.mixin(target, props);
  1786. },
  1787. _copyAttr: function(idx, attr){
  1788. // summary:
  1789. // Overwritten, see DataGrid._copyAttr()
  1790. // Fix cell TAB navigation for single click editing
  1791. if(!attr){ return; }
  1792. return this.inherited(arguments);
  1793. },
  1794. _getHeaderHeight: function(){
  1795. // summary:
  1796. // Overwritten, see _Grid._getHeaderHeight()
  1797. // Should include borders/margins of this.viewsHeaderNode
  1798. this.inherited(arguments);
  1799. return domGeometry.getMarginBox(this.viewsHeaderNode).h;
  1800. },
  1801. _fetch: function(start, isRender){
  1802. // summary:
  1803. // Overwritten, see DataGrid._fetch()
  1804. if(this.items){
  1805. return this.inherited(arguments);
  1806. }
  1807. start = start || 0;
  1808. if(this.store && !this._pending_requests[start]){
  1809. if(!this._isLoaded && !this._isLoading){
  1810. this._isLoading = true;
  1811. this.showMessage(this.loadingMessage);
  1812. }
  1813. this._pending_requests[start] = true;
  1814. try{
  1815. var req = {
  1816. start: start,
  1817. count: this.rowsPerPage,
  1818. query: this.query,
  1819. sort: this.getSortProps(),
  1820. queryOptions: this.queryOptions,
  1821. isRender: isRender,
  1822. onBegin: lang.hitch(this, "_onFetchBegin"),
  1823. onComplete: lang.hitch(this, "_onFetchComplete"),
  1824. onError: lang.hitch(this, "_onFetchError")
  1825. };
  1826. this._storeLayerFetch(req);
  1827. }catch(e){
  1828. this._onFetchError(e, {start: start, count: this.rowsPerPage});
  1829. }
  1830. }
  1831. return 0;
  1832. },
  1833. _storeLayerFetch: function(req){
  1834. // summary:
  1835. // Extracted fetch specifically for store layer use
  1836. this.store.fetch(req);
  1837. },
  1838. getCellByField: function(field){
  1839. return array.filter(this.layout.cells, function(cell){
  1840. return cell.field == field;
  1841. })[0];
  1842. },
  1843. onMouseUp: function(e){ },
  1844. createView: function(){
  1845. // summary
  1846. // Overwrite: rewrite getCellX of view.header
  1847. var view = this.inherited(arguments);
  1848. if(has("mozilla")){
  1849. var ascendDom = function(inNode, inWhile){
  1850. for(var n = inNode; n && inWhile(n); n = n.parentNode){}
  1851. return n;
  1852. };//copied from dojox.grid._Builder
  1853. var makeNotTagName = function(inTagName){
  1854. var name = inTagName.toUpperCase();
  1855. return function(node){ return node.tagName != name; };
  1856. };//copied from dojox.grid._Builder
  1857. var func = view.header.getCellX;
  1858. view.header.getCellX = function(e){
  1859. var x = func.call(view.header, e);
  1860. var n = ascendDom(e.target, makeNotTagName("th"));
  1861. if(n && n !== e.target && dom.isDescendant(e.target, n)){ x += n.firstChild.offsetLeft; }
  1862. return x;
  1863. };
  1864. }
  1865. return view;
  1866. },
  1867. destroy: function(){
  1868. // summary:
  1869. // Destroy all resources
  1870. delete this._nls;
  1871. this.pluginMgr.destroy();
  1872. this.inherited(arguments);
  1873. }
  1874. });
  1875. declare("dojox.grid.enhanced.DataSelection", DataSelection, {
  1876. constructor: function(grid){
  1877. if(grid.keepSelection){
  1878. if(this.preserver){
  1879. this.preserver.destroy();
  1880. }
  1881. this.preserver = new _SelectionPreserver(this);
  1882. }
  1883. },
  1884. _range: function(inFrom, inTo){
  1885. this.grid._selectingRange = true;
  1886. this.inherited(arguments);
  1887. this.grid._selectingRange = false;
  1888. this.onChanged();
  1889. },
  1890. deselectAll: function(inItemOrIndex){
  1891. this.grid._selectingRange = true;
  1892. this.inherited(arguments);
  1893. this.grid._selectingRange = false;
  1894. this.onChanged();
  1895. }
  1896. });
  1897. EnhancedGrid.markupFactory = function(props, node, ctor, cellFunc){
  1898. return dojox.grid._Grid.markupFactory(props, node, ctor,
  1899. lang.partial(DataGrid.cell_markupFactory, cellFunc));
  1900. };
  1901. EnhancedGrid.registerPlugin = function(clazz, props){
  1902. _PluginManager.registerPlugin(clazz, props);
  1903. };
  1904. return EnhancedGrid;
  1905. });
  1906. },
  1907. 'dijit/_CssStateMixin':function(){
  1908. define("dijit/_CssStateMixin", [
  1909. "dojo/touch",
  1910. "dojo/_base/array", // array.forEach array.map
  1911. "dojo/_base/declare", // declare
  1912. "dojo/dom-class", // domClass.toggle
  1913. "dojo/_base/lang", // lang.hitch
  1914. "dojo/_base/window" // win.body
  1915. ], function(touch, array, declare, domClass, lang, win){
  1916. // module:
  1917. // dijit/_CssStateMixin
  1918. // summary:
  1919. // Mixin for widgets to set CSS classes on the widget DOM nodes depending on hover/mouse press/focus
  1920. // state changes, and also higher-level state changes such becoming disabled or selected.
  1921. return declare("dijit._CssStateMixin", [], {
  1922. // summary:
  1923. // Mixin for widgets to set CSS classes on the widget DOM nodes depending on hover/mouse press/focus
  1924. // state changes, and also higher-level state changes such becoming disabled or selected.
  1925. //
  1926. // description:
  1927. // By mixing this class into your widget, and setting the this.baseClass attribute, it will automatically
  1928. // maintain CSS classes on the widget root node (this.domNode) depending on hover,
  1929. // active, focus, etc. state. Ex: with a baseClass of dijitButton, it will apply the classes
  1930. // dijitButtonHovered and dijitButtonActive, as the user moves the mouse over the widget and clicks it.
  1931. //
  1932. // It also sets CSS like dijitButtonDisabled based on widget semantic state.
  1933. //
  1934. // By setting the cssStateNodes attribute, a widget can also track events on subnodes (like buttons
  1935. // within the widget).
  1936. // cssStateNodes: [protected] Object
  1937. // List of sub-nodes within the widget that need CSS classes applied on mouse hover/press and focus
  1938. //.
  1939. // Each entry in the hash is a an attachpoint names (like "upArrowButton") mapped to a CSS class names
  1940. // (like "dijitUpArrowButton"). Example:
  1941. // | {
  1942. // | "upArrowButton": "dijitUpArrowButton",
  1943. // | "downArrowButton": "dijitDownArrowButton"
  1944. // | }
  1945. // The above will set the CSS class dijitUpArrowButton to the this.upArrowButton DOMNode when it
  1946. // is hovered, etc.
  1947. cssStateNodes: {},
  1948. // hovering: [readonly] Boolean
  1949. // True if cursor is over this widget
  1950. hovering: false,
  1951. // active: [readonly] Boolean
  1952. // True if mouse was pressed while over this widget, and hasn't been released yet
  1953. active: false,
  1954. _applyAttributes: function(){
  1955. // This code would typically be in postCreate(), but putting in _applyAttributes() for
  1956. // performance: so the class changes happen before DOM is inserted into the document.
  1957. // Change back to postCreate() in 2.0. See #11635.
  1958. this.inherited(arguments);
  1959. // Automatically monitor mouse events (essentially :hover and :active) on this.domNode
  1960. array.forEach(["onmouseenter", "onmouseleave", touch.press], function(e){
  1961. this.connect(this.domNode, e, "_cssMouseEvent");
  1962. }, this);
  1963. // Monitoring changes to disabled, readonly, etc. state, and update CSS class of root node
  1964. array.forEach(["disabled", "readOnly", "checked", "selected", "focused", "state", "hovering", "active"], function(attr){
  1965. this.watch(attr, lang.hitch(this, "_setStateClass"));
  1966. }, this);
  1967. // Events on sub nodes within the widget
  1968. for(var ap in this.cssStateNodes){
  1969. this._trackMouseState(this[ap], this.cssStateNodes[ap]);
  1970. }
  1971. // Set state initially; there's probably no hover/active/focus state but widget might be
  1972. // disabled/readonly/checked/selected so we want to set CSS classes for those conditions.
  1973. this._setStateClass();
  1974. },
  1975. _cssMouseEvent: function(/*Event*/ event){
  1976. // summary:
  1977. // Sets hovering and active properties depending on mouse state,
  1978. // which triggers _setStateClass() to set appropriate CSS classes for this.domNode.
  1979. if(!this.disabled){
  1980. switch(event.type){
  1981. case "mouseenter":
  1982. case "mouseover": // generated on non-IE browsers even though we connected to mouseenter
  1983. this._set("hovering", true);
  1984. this._set("active", this._mouseDown);
  1985. break;
  1986. case "mouseleave":
  1987. case "mouseout": // generated on non-IE browsers even though we connected to mouseleave
  1988. this._set("hovering", false);
  1989. this._set("active", false);
  1990. break;
  1991. case "mousedown":
  1992. case "touchpress":
  1993. this._set("active", true);
  1994. this._mouseDown = true;
  1995. // Set a global event to handle mouseup, so it fires properly
  1996. // even if the cursor leaves this.domNode before the mouse up event.
  1997. // Alternately could set active=false on mouseout.
  1998. var mouseUpConnector = this.connect(win.body(), touch.release, function(){
  1999. this._mouseDown = false;
  2000. this._set("active", false);
  2001. this.disconnect(mouseUpConnector);
  2002. });
  2003. break;
  2004. }
  2005. }
  2006. },
  2007. _setStateClass: function(){
  2008. // summary:
  2009. // Update the visual state of the widget by setting the css classes on this.domNode
  2010. // (or this.stateNode if defined) by combining this.baseClass with
  2011. // various suffixes that represent the current widget state(s).
  2012. //
  2013. // description:
  2014. // In the case where a widget has multiple
  2015. // states, it sets the class based on all possible
  2016. // combinations. For example, an invalid form widget that is being hovered
  2017. // will be "dijitInput dijitInputInvalid dijitInputHover dijitInputInvalidHover".
  2018. //
  2019. // The widget may have one or more of the following states, determined
  2020. // by this.state, this.checked, this.valid, and this.selected:
  2021. // - Error - ValidationTextBox sets this.state to "Error" if the current input value is invalid
  2022. // - Incomplete - ValidationTextBox sets this.state to "Incomplete" if the current input value is not finished yet
  2023. // - Checked - ex: a checkmark or a ToggleButton in a checked state, will have this.checked==true
  2024. // - Selected - ex: currently selected tab will have this.selected==true
  2025. //
  2026. // In addition, it may have one or more of the following states,
  2027. // based on this.disabled and flags set in _onMouse (this.active, this.hovering) and from focus manager (this.focused):
  2028. // - Disabled - if the widget is disabled
  2029. // - Active - if the mouse (or space/enter key?) is being pressed down
  2030. // - Focused - if the widget has focus
  2031. // - Hover - if the mouse is over the widget
  2032. // Compute new set of classes
  2033. var newStateClasses = this.baseClass.split(" ");
  2034. function multiply(modifier){
  2035. newStateClasses = newStateClasses.concat(array.map(newStateClasses, function(c){ return c+modifier; }), "dijit"+modifier);
  2036. }
  2037. if(!this.isLeftToRight()){
  2038. // For RTL mode we need to set an addition class like dijitTextBoxRtl.
  2039. multiply("Rtl");
  2040. }
  2041. var checkedState = this.checked == "mixed" ? "Mixed" : (this.checked ? "Checked" : "");
  2042. if(this.checked){
  2043. multiply(checkedState);
  2044. }
  2045. if(this.state){
  2046. multiply(this.state);
  2047. }
  2048. if(this.selected){
  2049. multiply("Selected");
  2050. }
  2051. if(this.disabled){
  2052. multiply("Disabled");
  2053. }else if(this.readOnly){
  2054. multiply("ReadOnly");
  2055. }else{
  2056. if(this.active){
  2057. multiply("Active");
  2058. }else if(this.hovering){
  2059. multiply("Hover");
  2060. }
  2061. }
  2062. if(this.focused){
  2063. multiply("Focused");
  2064. }
  2065. // Remove old state classes and add new ones.
  2066. // For performance concerns we only write into domNode.className once.
  2067. var tn = this.stateNode || this.domNode,
  2068. classHash = {}; // set of all classes (state and otherwise) for node
  2069. array.forEach(tn.className.split(" "), function(c){ classHash[c] = true; });
  2070. if("_stateClasses" in this){
  2071. array.forEach(this._stateClasses, function(c){ delete classHash[c]; });
  2072. }
  2073. array.forEach(newStateClasses, function(c){ classHash[c] = true; });
  2074. var newClasses = [];
  2075. for(var c in classHash){
  2076. newClasses.push(c);
  2077. }
  2078. tn.className = newClasses.join(" ");
  2079. this._stateClasses = newStateClasses;
  2080. },
  2081. _trackMouseState: function(/*DomNode*/ node, /*String*/ clazz){
  2082. // summary:
  2083. // Track mouse/focus events on specified node and set CSS class on that node to indicate
  2084. // current state. Usually not called directly, but via cssStateNodes attribute.
  2085. // description:
  2086. // Given class=foo, will set the following CSS class on the node
  2087. // - fooActive: if the user is currently pressing down the mouse button while over the node
  2088. // - fooHover: if the user is hovering the mouse over the node, but not pressing down a button
  2089. // - fooFocus: if the node is focused
  2090. //
  2091. // Note that it won't set any classes if the widget is disabled.
  2092. // node: DomNode
  2093. // Should be a sub-node of the widget, not the top node (this.domNode), since the top node
  2094. // is handled specially and automatically just by mixing in this class.
  2095. // clazz: String
  2096. // CSS class name (ex: dijitSliderUpArrow).
  2097. // Current state of node (initially false)
  2098. // NB: setting specifically to false because domClass.toggle() needs true boolean as third arg
  2099. var hovering=false, active=false, focused=false;
  2100. var self = this,
  2101. cn = lang.hitch(this, "connect", node);
  2102. function setClass(){
  2103. var disabled = ("disabled" in self && self.disabled) || ("readonly" in self && self.readonly);
  2104. domClass.toggle(node, clazz+"Hover", hovering && !active && !disabled);
  2105. domClass.toggle(node, clazz+"Active", active && !disabled);
  2106. domClass.toggle(node, clazz+"Focused", focused && !disabled);
  2107. }
  2108. // Mouse
  2109. cn("onmouseenter", function(){
  2110. hovering = true;
  2111. setClass();
  2112. });
  2113. cn("onmouseleave", function(){
  2114. hovering = false;
  2115. active = false;
  2116. setClass();
  2117. });
  2118. cn(touch.press, function(){
  2119. active = true;
  2120. setClass();
  2121. });
  2122. cn(touch.release, function(){
  2123. active = false;
  2124. setClass();
  2125. });
  2126. // Focus
  2127. cn("onfocus", function(){
  2128. focused = true;
  2129. setClass();
  2130. });
  2131. cn("onblur", function(){
  2132. focused = false;
  2133. setClass();
  2134. });
  2135. // Just in case widget is enabled/disabled while it has focus/hover/active state.
  2136. // Maybe this is overkill.
  2137. this.watch("disabled", setClass);
  2138. this.watch("readOnly", setClass);
  2139. }
  2140. });
  2141. });
  2142. },
  2143. 'dojo/currency':function(){
  2144. define("dojo/currency", ["./_base/kernel", "./_base/lang", "./_base/array", "./number", "./i18n", "./i18n!./cldr/nls/currency", "./cldr/monetary"], function(dojo, lang, darray, dnumber, i18n, nlsCurrency, cldrMonetary) {
  2145. // module:
  2146. // dojo/currency
  2147. // summary:
  2148. // TODOC
  2149. lang.getObject("currency", true, dojo);
  2150. /*=====
  2151. dojo.currency = {
  2152. // summary: localized formatting and parsing routines for currencies
  2153. //
  2154. // description: extends dojo.number to provide culturally-appropriate formatting of values
  2155. // in various world currencies, including use of a currency symbol. The currencies are specified
  2156. // by a three-letter international symbol in all uppercase, and support for the currencies is
  2157. // provided by the data in `dojo.cldr`. The scripts generating dojo.cldr specify which
  2158. // currency support is included. A fixed number of decimal places is determined based
  2159. // on the currency type and is not determined by the 'pattern' argument. The fractional
  2160. // portion is optional, by default, and variable length decimals are not supported.
  2161. }
  2162. =====*/
  2163. dojo.currency._mixInDefaults = function(options){
  2164. options = options || {};
  2165. options.type = "currency";
  2166. // Get locale-dependent currency data, like the symbol
  2167. var bundle = i18n.getLocalization("dojo.cldr", "currency", options.locale) || {};
  2168. // Mixin locale-independent currency data, like # of places
  2169. var iso = options.currency;
  2170. var data = cldrMonetary.getData(iso);
  2171. darray.forEach(["displayName","symbol","group","decimal"], function(prop){
  2172. data[prop] = bundle[iso+"_"+prop];
  2173. });
  2174. data.fractional = [true, false];
  2175. // Mixin with provided options
  2176. return lang.mixin(data, options);
  2177. };
  2178. /*=====
  2179. dojo.declare("dojo.currency.__FormatOptions", [dojo.number.__FormatOptions], {
  2180. // type: String?
  2181. // Should not be set. Value is assumed to be "currency".
  2182. // symbol: String?
  2183. // localized currency symbol. The default will be looked up in table of supported currencies in `dojo.cldr`
  2184. // A [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code will be used if not found.
  2185. // currency: String?
  2186. // an [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code, a three letter sequence like "USD".
  2187. // For use with dojo.currency only.
  2188. // places: Number?
  2189. // number of decimal places to show. Default is defined based on which currency is used.
  2190. type: "",
  2191. symbol: "",
  2192. currency: "",
  2193. places: ""
  2194. });
  2195. =====*/
  2196. dojo.currency.format = function(/*Number*/value, /*dojo.currency.__FormatOptions?*/options){
  2197. // summary:
  2198. // Format a Number as a currency, using locale-specific settings
  2199. //
  2200. // description:
  2201. // Create a string from a Number using a known, localized pattern.
  2202. // [Formatting patterns](http://www.unicode.org/reports/tr35/#Number_Elements)
  2203. // appropriate to the locale are chosen from the [CLDR](http://unicode.org/cldr)
  2204. // as well as the appropriate symbols and delimiters and number of decimal places.
  2205. //
  2206. // value:
  2207. // the number to be formatted.
  2208. return dnumber.format(value, dojo.currency._mixInDefaults(options));
  2209. };
  2210. dojo.currency.regexp = function(/*dojo.number.__RegexpOptions?*/options){
  2211. //
  2212. // summary:
  2213. // Builds the regular needed to parse a currency value
  2214. //
  2215. // description:
  2216. // Returns regular expression with positive and negative match, group and decimal separators
  2217. // Note: the options.places default, the number of decimal places to accept, is defined by the currency type.
  2218. return dnumber.regexp(dojo.currency._mixInDefaults(options)); // String
  2219. };
  2220. /*=====
  2221. dojo.declare("dojo.currency.__ParseOptions", [dojo.number.__ParseOptions], {
  2222. // type: String?
  2223. // Should not be set. Value is assumed to be currency.
  2224. // currency: String?
  2225. // an [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code, a three letter sequence like "USD".
  2226. // For use with dojo.currency only.
  2227. // symbol: String?
  2228. // localized currency symbol. The default will be looked up in table of supported currencies in `dojo.cldr`
  2229. // A [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code will be used if not found.
  2230. // places: Number?
  2231. // fixed number of decimal places to accept. The default is determined based on which currency is used.
  2232. // fractional: Boolean?|Array?
  2233. // Whether to include the fractional portion, where the number of decimal places are implied by the currency
  2234. // or explicit 'places' parameter. The value [true,false] makes the fractional portion optional.
  2235. // By default for currencies, it the fractional portion is optional.
  2236. type: "",
  2237. currency: "",
  2238. symbol: "",
  2239. places: "",
  2240. fractional: ""
  2241. });
  2242. =====*/
  2243. dojo.currency.parse = function(/*String*/expression, /*dojo.currency.__ParseOptions?*/options){
  2244. //
  2245. // summary:
  2246. // Convert a properly formatted currency string to a primitive Number,
  2247. // using locale-specific settings.
  2248. //
  2249. // description:
  2250. // Create a Number from a string using a known, localized pattern.
  2251. // [Formatting patterns](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  2252. // are chosen appropriate to the locale, as well as the appropriate symbols and delimiters
  2253. // and number of decimal places.
  2254. //
  2255. // expression: A string representation of a currency value
  2256. return dnumber.parse(expression, dojo.currency._mixInDefaults(options));
  2257. };
  2258. return dojo.currency;
  2259. });
  2260. },
  2261. 'dijit/_editor/html':function(){
  2262. define("dijit/_editor/html", [
  2263. "dojo/_base/lang", // lang.isString
  2264. "dojo/_base/sniff", // has("ie")
  2265. ".." // for exporting symbols to dijit._editor (remove for 2.0)
  2266. ], function(lang, has, dijit){
  2267. // module:
  2268. // dijit/_editor/html
  2269. // summary:
  2270. // Utility functions used by editor
  2271. lang.getObject("_editor", true, dijit);
  2272. dijit._editor.escapeXml=function(/*String*/str, /*Boolean?*/noSingleQuotes){
  2273. // summary:
  2274. // Adds escape sequences for special characters in XML: &<>"'
  2275. // Optionally skips escapes for single quotes
  2276. str = str.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;");
  2277. if(!noSingleQuotes){
  2278. str = str.replace(/'/gm, "&#39;");
  2279. }
  2280. return str; // string
  2281. };
  2282. dijit._editor.getNodeHtml=function(/* DomNode */node){
  2283. var output;
  2284. switch(node.nodeType){
  2285. case 1: //element node
  2286. var lName = node.nodeName.toLowerCase();
  2287. if(!lName || lName.charAt(0) == "/"){
  2288. // IE does some strange things with malformed HTML input, like
  2289. // treating a close tag </span> without an open tag <span>, as
  2290. // a new tag with tagName of /span. Corrupts output HTML, remove
  2291. // them. Other browsers don't prefix tags that way, so will
  2292. // never show up.
  2293. return "";
  2294. }
  2295. output = '<' + lName;
  2296. //store the list of attributes and sort it to have the
  2297. //attributes appear in the dictionary order
  2298. var attrarray = [];
  2299. var attr;
  2300. if(has("ie") && node.outerHTML){
  2301. var s = node.outerHTML;
  2302. s = s.substr(0, s.indexOf('>'))
  2303. .replace(/(['"])[^"']*\1/g, ''); //to make the following regexp safe
  2304. var reg = /(\b\w+)\s?=/g;
  2305. var m, key;
  2306. while((m = reg.exec(s))){
  2307. key = m[1];
  2308. if(key.substr(0,3) != '_dj'){
  2309. if(key == 'src' || key == 'href'){
  2310. if(node.getAttribute('_djrealurl')){
  2311. attrarray.push([key,node.getAttribute('_djrealurl')]);
  2312. continue;
  2313. }
  2314. }
  2315. var val, match;
  2316. switch(key){
  2317. case 'style':
  2318. val = node.style.cssText.toLowerCase();
  2319. break;
  2320. case 'class':
  2321. val = node.className;
  2322. break;
  2323. case 'width':
  2324. if(lName === "img"){
  2325. // This somehow gets lost on IE for IMG tags and the like
  2326. // and we have to find it in outerHTML, known IE oddity.
  2327. match=/width=(\S+)/i.exec(s);
  2328. if(match){
  2329. val = match[1];
  2330. }
  2331. break;
  2332. }
  2333. case 'height':
  2334. if(lName === "img"){
  2335. // This somehow gets lost on IE for IMG tags and the like
  2336. // and we have to find it in outerHTML, known IE oddity.
  2337. match=/height=(\S+)/i.exec(s);
  2338. if(match){
  2339. val = match[1];
  2340. }
  2341. break;
  2342. }
  2343. default:
  2344. val = node.getAttribute(key);
  2345. }
  2346. if(val != null){
  2347. attrarray.push([key, val.toString()]);
  2348. }
  2349. }
  2350. }
  2351. }else{
  2352. var i = 0;
  2353. while((attr = node.attributes[i++])){
  2354. //ignore all attributes starting with _dj which are
  2355. //internal temporary attributes used by the editor
  2356. var n = attr.name;
  2357. if(n.substr(0,3) != '_dj' /*&&
  2358. (attr.specified == undefined || attr.specified)*/){
  2359. var v = attr.value;
  2360. if(n == 'src' || n == 'href'){
  2361. if(node.getAttribute('_djrealurl')){
  2362. v = node.getAttribute('_djrealurl');
  2363. }
  2364. }
  2365. attrarray.push([n,v]);
  2366. }
  2367. }
  2368. }
  2369. attrarray.sort(function(a,b){
  2370. return a[0] < b[0] ? -1 : (a[0] == b[0] ? 0 : 1);
  2371. });
  2372. var j = 0;
  2373. while((attr = attrarray[j++])){
  2374. output += ' ' + attr[0] + '="' +
  2375. (lang.isString(attr[1]) ? dijit._editor.escapeXml(attr[1], true) : attr[1]) + '"';
  2376. }
  2377. if(lName === "script"){
  2378. // Browsers handle script tags differently in how you get content,
  2379. // but innerHTML always seems to work, so insert its content that way
  2380. // Yes, it's bad to allow script tags in the editor code, but some people
  2381. // seem to want to do it, so we need to at least return them right.
  2382. // other plugins/filters can strip them.
  2383. output += '>' + node.innerHTML +'</' + lName + '>';
  2384. }else{
  2385. if(node.childNodes.length){
  2386. output += '>' + dijit._editor.getChildrenHtml(node)+'</' + lName +'>';
  2387. }else{
  2388. switch(lName){
  2389. case 'br':
  2390. case 'hr':
  2391. case 'img':
  2392. case 'input':
  2393. case 'base':
  2394. case 'meta':
  2395. case 'area':
  2396. case 'basefont':
  2397. // These should all be singly closed
  2398. output += ' />';
  2399. break;
  2400. default:
  2401. // Assume XML style separate closure for everything else.
  2402. output += '></' + lName + '>';
  2403. }
  2404. }
  2405. }
  2406. break;
  2407. case 4: // cdata
  2408. case 3: // text
  2409. // FIXME:
  2410. output = dijit._editor.escapeXml(node.nodeValue, true);
  2411. break;
  2412. case 8: //comment
  2413. // FIXME:
  2414. output = '<!--' + dijit._editor.escapeXml(node.nodeValue, true) + '-->';
  2415. break;
  2416. default:
  2417. output = "<!-- Element not recognized - Type: " + node.nodeType + " Name: " + node.nodeName + "-->";
  2418. }
  2419. return output;
  2420. };
  2421. dijit._editor.getChildrenHtml = function(/* DomNode */dom){
  2422. // summary:
  2423. // Returns the html content of a DomNode and children
  2424. var out = "";
  2425. if(!dom){ return out; }
  2426. var nodes = dom["childNodes"] || dom;
  2427. //IE issue.
  2428. //If we have an actual node we can check parent relationships on for IE,
  2429. //We should check, as IE sometimes builds invalid DOMS. If no parent, we can't check
  2430. //And should just process it and hope for the best.
  2431. var checkParent = !has("ie") || nodes !== dom;
  2432. var node, i = 0;
  2433. while((node = nodes[i++])){
  2434. //IE is broken. DOMs are supposed to be a tree. But in the case of malformed HTML, IE generates a graph
  2435. //meaning one node ends up with multiple references (multiple parents). This is totally wrong and invalid, but
  2436. //such is what it is. We have to keep track and check for this because otherise the source output HTML will have dups.
  2437. //No other browser generates a graph. Leave it to IE to break a fundamental DOM rule. So, we check the parent if we can
  2438. //If we can't, nothing more we can do other than walk it.
  2439. if(!checkParent || node.parentNode == dom){
  2440. out += dijit._editor.getNodeHtml(node);
  2441. }
  2442. }
  2443. return out; // String
  2444. };
  2445. return dijit._editor;
  2446. });
  2447. },
  2448. 'dijit/place':function(){
  2449. define("dijit/place", [
  2450. "dojo/_base/array", // array.forEach array.map array.some
  2451. "dojo/dom-geometry", // domGeometry.getMarginBox domGeometry.position
  2452. "dojo/dom-style", // domStyle.getComputedStyle
  2453. "dojo/_base/kernel", // kernel.deprecated
  2454. "dojo/_base/window", // win.body
  2455. "dojo/window", // winUtils.getBox
  2456. "." // dijit (defining dijit.place to match API doc)
  2457. ], function(array, domGeometry, domStyle, kernel, win, winUtils, dijit){
  2458. // module:
  2459. // dijit/place
  2460. // summary:
  2461. // Code to place a popup relative to another node
  2462. function _place(/*DomNode*/ node, choices, layoutNode, aroundNodeCoords){
  2463. // summary:
  2464. // Given a list of spots to put node, put it at the first spot where it fits,
  2465. // of if it doesn't fit anywhere then the place with the least overflow
  2466. // choices: Array
  2467. // Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} }
  2468. // Above example says to put the top-left corner of the node at (10,20)
  2469. // layoutNode: Function(node, aroundNodeCorner, nodeCorner, size)
  2470. // for things like tooltip, they are displayed differently (and have different dimensions)
  2471. // based on their orientation relative to the parent. This adjusts the popup based on orientation.
  2472. // It also passes in the available size for the popup, which is useful for tooltips to
  2473. // tell them that their width is limited to a certain amount. layoutNode() may return a value expressing
  2474. // how much the popup had to be modified to fit into the available space. This is used to determine
  2475. // what the best placement is.
  2476. // aroundNodeCoords: Object
  2477. // Size of aroundNode, ex: {w: 200, h: 50}
  2478. // get {x: 10, y: 10, w: 100, h:100} type obj representing position of
  2479. // viewport over document
  2480. var view = winUtils.getBox();
  2481. // This won't work if the node is inside a <div style="position: relative">,
  2482. // so reattach it to win.doc.body. (Otherwise, the positioning will be wrong
  2483. // and also it might get cutoff)
  2484. if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){
  2485. win.body().appendChild(node);
  2486. }
  2487. var best = null;
  2488. array.some(choices, function(choice){
  2489. var corner = choice.corner;
  2490. var pos = choice.pos;
  2491. var overflow = 0;
  2492. // calculate amount of space available given specified position of node
  2493. var spaceAvailable = {
  2494. w: {
  2495. 'L': view.l + view.w - pos.x,
  2496. 'R': pos.x - view.l,
  2497. 'M': view.w
  2498. }[corner.charAt(1)],
  2499. h: {
  2500. 'T': view.t + view.h - pos.y,
  2501. 'B': pos.y - view.t,
  2502. 'M': view.h
  2503. }[corner.charAt(0)]
  2504. };
  2505. // configure node to be displayed in given position relative to button
  2506. // (need to do this in order to get an accurate size for the node, because
  2507. // a tooltip's size changes based on position, due to triangle)
  2508. if(layoutNode){
  2509. var res = layoutNode(node, choice.aroundCorner, corner, spaceAvailable, aroundNodeCoords);
  2510. overflow = typeof res == "undefined" ? 0 : res;
  2511. }
  2512. // get node's size
  2513. var style = node.style;
  2514. var oldDisplay = style.display;
  2515. var oldVis = style.visibility;
  2516. if(style.display == "none"){
  2517. style.visibility = "hidden";
  2518. style.display = "";
  2519. }
  2520. var mb = domGeometry. getMarginBox(node);
  2521. style.display = oldDisplay;
  2522. style.visibility = oldVis;
  2523. // coordinates and size of node with specified corner placed at pos,
  2524. // and clipped by viewport
  2525. var
  2526. startXpos = {
  2527. 'L': pos.x,
  2528. 'R': pos.x - mb.w,
  2529. 'M': Math.max(view.l, Math.min(view.l + view.w, pos.x + (mb.w >> 1)) - mb.w) // M orientation is more flexible
  2530. }[corner.charAt(1)],
  2531. startYpos = {
  2532. 'T': pos.y,
  2533. 'B': pos.y - mb.h,
  2534. 'M': Math.max(view.t, Math.min(view.t + view.h, pos.y + (mb.h >> 1)) - mb.h)
  2535. }[corner.charAt(0)],
  2536. startX = Math.max(view.l, startXpos),
  2537. startY = Math.max(view.t, startYpos),
  2538. endX = Math.min(view.l + view.w, startXpos + mb.w),
  2539. endY = Math.min(view.t + view.h, startYpos + mb.h),
  2540. width = endX - startX,
  2541. height = endY - startY;
  2542. overflow += (mb.w - width) + (mb.h - height);
  2543. if(best == null || overflow < best.overflow){
  2544. best = {
  2545. corner: corner,
  2546. aroundCorner: choice.aroundCorner,
  2547. x: startX,
  2548. y: startY,
  2549. w: width,
  2550. h: height,
  2551. overflow: overflow,
  2552. spaceAvailable: spaceAvailable
  2553. };
  2554. }
  2555. return !overflow;
  2556. });
  2557. // In case the best position is not the last one we checked, need to call
  2558. // layoutNode() again.
  2559. if(best.overflow && layoutNode){
  2560. layoutNode(node, best.aroundCorner, best.corner, best.spaceAvailable, aroundNodeCoords);
  2561. }
  2562. // And then position the node. Do this last, after the layoutNode() above
  2563. // has sized the node, due to browser quirks when the viewport is scrolled
  2564. // (specifically that a Tooltip will shrink to fit as though the window was
  2565. // scrolled to the left).
  2566. //
  2567. // In RTL mode, set style.right rather than style.left so in the common case,
  2568. // window resizes move the popup along with the aroundNode.
  2569. var l = domGeometry.isBodyLtr(),
  2570. s = node.style;
  2571. s.top = best.y + "px";
  2572. s[l ? "left" : "right"] = (l ? best.x : view.w - best.x - best.w) + "px";
  2573. s[l ? "right" : "left"] = "auto"; // needed for FF or else tooltip goes to far left
  2574. return best;
  2575. }
  2576. /*=====
  2577. dijit.place.__Position = function(){
  2578. // x: Integer
  2579. // horizontal coordinate in pixels, relative to document body
  2580. // y: Integer
  2581. // vertical coordinate in pixels, relative to document body
  2582. this.x = x;
  2583. this.y = y;
  2584. };
  2585. =====*/
  2586. /*=====
  2587. dijit.place.__Rectangle = function(){
  2588. // x: Integer
  2589. // horizontal offset in pixels, relative to document body
  2590. // y: Integer
  2591. // vertical offset in pixels, relative to document body
  2592. // w: Integer
  2593. // width in pixels. Can also be specified as "width" for backwards-compatibility.
  2594. // h: Integer
  2595. // height in pixels. Can also be specified as "height" from backwards-compatibility.
  2596. this.x = x;
  2597. this.y = y;
  2598. this.w = w;
  2599. this.h = h;
  2600. };
  2601. =====*/
  2602. return (dijit.place = {
  2603. // summary:
  2604. // Code to place a DOMNode relative to another DOMNode.
  2605. // Load using require(["dijit/place"], function(place){ ... }).
  2606. at: function(node, pos, corners, padding){
  2607. // summary:
  2608. // Positions one of the node's corners at specified position
  2609. // such that node is fully visible in viewport.
  2610. // description:
  2611. // NOTE: node is assumed to be absolutely or relatively positioned.
  2612. // node: DOMNode
  2613. // The node to position
  2614. // pos: dijit.place.__Position
  2615. // Object like {x: 10, y: 20}
  2616. // corners: String[]
  2617. // Array of Strings representing order to try corners in, like ["TR", "BL"].
  2618. // Possible values are:
  2619. // * "BL" - bottom left
  2620. // * "BR" - bottom right
  2621. // * "TL" - top left
  2622. // * "TR" - top right
  2623. // padding: dijit.place.__Position?
  2624. // optional param to set padding, to put some buffer around the element you want to position.
  2625. // example:
  2626. // Try to place node's top right corner at (10,20).
  2627. // If that makes node go (partially) off screen, then try placing
  2628. // bottom left corner at (10,20).
  2629. // | place(node, {x: 10, y: 20}, ["TR", "BL"])
  2630. var choices = array.map(corners, function(corner){
  2631. var c = { corner: corner, pos: {x:pos.x,y:pos.y} };
  2632. if(padding){
  2633. c.pos.x += corner.charAt(1) == 'L' ? padding.x : -padding.x;
  2634. c.pos.y += corner.charAt(0) == 'T' ? padding.y : -padding.y;
  2635. }
  2636. return c;
  2637. });
  2638. return _place(node, choices);
  2639. },
  2640. around: function(
  2641. /*DomNode*/ node,
  2642. /*DomNode || dijit.place.__Rectangle*/ anchor,
  2643. /*String[]*/ positions,
  2644. /*Boolean*/ leftToRight,
  2645. /*Function?*/ layoutNode){
  2646. // summary:
  2647. // Position node adjacent or kitty-corner to anchor
  2648. // such that it's fully visible in viewport.
  2649. //
  2650. // description:
  2651. // Place node such that corner of node touches a corner of
  2652. // aroundNode, and that node is fully visible.
  2653. //
  2654. // anchor:
  2655. // Either a DOMNode or a __Rectangle (object with x, y, width, height).
  2656. //
  2657. // positions:
  2658. // Ordered list of positions to try matching up.
  2659. // * before: places drop down to the left of the anchor node/widget, or to the right in the case
  2660. // of RTL scripts like Hebrew and Arabic; aligns either the top of the drop down
  2661. // with the top of the anchor, or the bottom of the drop down with bottom of the anchor.
  2662. // * after: places drop down to the right of the anchor node/widget, or to the left in the case
  2663. // of RTL scripts like Hebrew and Arabic; aligns either the top of the drop down
  2664. // with the top of the anchor, or the bottom of the drop down with bottom of the anchor.
  2665. // * before-centered: centers drop down to the left of the anchor node/widget, or to the right
  2666. // in the case of RTL scripts like Hebrew and Arabic
  2667. // * after-centered: centers drop down to the right of the anchor node/widget, or to the left
  2668. // in the case of RTL scripts like Hebrew and Arabic
  2669. // * above-centered: drop down is centered above anchor node
  2670. // * above: drop down goes above anchor node, left sides aligned
  2671. // * above-alt: drop down goes above anchor node, right sides aligned
  2672. // * below-centered: drop down is centered above anchor node
  2673. // * below: drop down goes below anchor node
  2674. // * below-alt: drop down goes below anchor node, right sides aligned
  2675. //
  2676. // layoutNode: Function(node, aroundNodeCorner, nodeCorner)
  2677. // For things like tooltip, they are displayed differently (and have different dimensions)
  2678. // based on their orientation relative to the parent. This adjusts the popup based on orientation.
  2679. //
  2680. // leftToRight:
  2681. // True if widget is LTR, false if widget is RTL. Affects the behavior of "above" and "below"
  2682. // positions slightly.
  2683. //
  2684. // example:
  2685. // | placeAroundNode(node, aroundNode, {'BL':'TL', 'TR':'BR'});
  2686. // This will try to position node such that node's top-left corner is at the same position
  2687. // as the bottom left corner of the aroundNode (ie, put node below
  2688. // aroundNode, with left edges aligned). If that fails it will try to put
  2689. // the bottom-right corner of node where the top right corner of aroundNode is
  2690. // (ie, put node above aroundNode, with right edges aligned)
  2691. //
  2692. // if around is a DOMNode (or DOMNode id), convert to coordinates
  2693. var aroundNodePos = (typeof anchor == "string" || "offsetWidth" in anchor)
  2694. ? domGeometry.position(anchor, true)
  2695. : anchor;
  2696. // Compute position and size of visible part of anchor (it may be partially hidden by ancestor nodes w/scrollbars)
  2697. if(anchor.parentNode){
  2698. // ignore nodes between position:relative and position:absolute
  2699. var sawPosAbsolute = domStyle.getComputedStyle(anchor).position == "absolute";
  2700. var parent = anchor.parentNode;
  2701. while(parent && parent.nodeType == 1 && parent.nodeName != "BODY"){ //ignoring the body will help performance
  2702. var parentPos = domGeometry.position(parent, true),
  2703. pcs = domStyle.getComputedStyle(parent);
  2704. if(/relative|absolute/.test(pcs.position)){
  2705. sawPosAbsolute = false;
  2706. }
  2707. if(!sawPosAbsolute && /hidden|auto|scroll/.test(pcs.overflow)){
  2708. var bottomYCoord = Math.min(aroundNodePos.y + aroundNodePos.h, parentPos.y + parentPos.h);
  2709. var rightXCoord = Math.min(aroundNodePos.x + aroundNodePos.w, parentPos.x + parentPos.w);
  2710. aroundNodePos.x = Math.max(aroundNodePos.x, parentPos.x);
  2711. aroundNodePos.y = Math.max(aroundNodePos.y, parentPos.y);
  2712. aroundNodePos.h = bottomYCoord - aroundNodePos.y;
  2713. aroundNodePos.w = rightXCoord - aroundNodePos.x;
  2714. }
  2715. if(pcs.position == "absolute"){
  2716. sawPosAbsolute = true;
  2717. }
  2718. parent = parent.parentNode;
  2719. }
  2720. }
  2721. var x = aroundNodePos.x,
  2722. y = aroundNodePos.y,
  2723. width = "w" in aroundNodePos ? aroundNodePos.w : (aroundNodePos.w = aroundNodePos.width),
  2724. height = "h" in aroundNodePos ? aroundNodePos.h : (kernel.deprecated("place.around: dijit.place.__Rectangle: { x:"+x+", y:"+y+", height:"+aroundNodePos.height+", width:"+width+" } has been deprecated. Please use { x:"+x+", y:"+y+", h:"+aroundNodePos.height+", w:"+width+" }", "", "2.0"), aroundNodePos.h = aroundNodePos.height);
  2725. // Convert positions arguments into choices argument for _place()
  2726. var choices = [];
  2727. function push(aroundCorner, corner){
  2728. choices.push({
  2729. aroundCorner: aroundCorner,
  2730. corner: corner,
  2731. pos: {
  2732. x: {
  2733. 'L': x,
  2734. 'R': x + width,
  2735. 'M': x + (width >> 1)
  2736. }[aroundCorner.charAt(1)],
  2737. y: {
  2738. 'T': y,
  2739. 'B': y + height,
  2740. 'M': y + (height >> 1)
  2741. }[aroundCorner.charAt(0)]
  2742. }
  2743. })
  2744. }
  2745. array.forEach(positions, function(pos){
  2746. var ltr = leftToRight;
  2747. switch(pos){
  2748. case "above-centered":
  2749. push("TM", "BM");
  2750. break;
  2751. case "below-centered":
  2752. push("BM", "TM");
  2753. break;
  2754. case "after-centered":
  2755. ltr = !ltr;
  2756. // fall through
  2757. case "before-centered":
  2758. push(ltr ? "ML" : "MR", ltr ? "MR" : "ML");
  2759. break;
  2760. case "after":
  2761. ltr = !ltr;
  2762. // fall through
  2763. case "before":
  2764. push(ltr ? "TL" : "TR", ltr ? "TR" : "TL");
  2765. push(ltr ? "BL" : "BR", ltr ? "BR" : "BL");
  2766. break;
  2767. case "below-alt":
  2768. ltr = !ltr;
  2769. // fall through
  2770. case "below":
  2771. // first try to align left borders, next try to align right borders (or reverse for RTL mode)
  2772. push(ltr ? "BL" : "BR", ltr ? "TL" : "TR");
  2773. push(ltr ? "BR" : "BL", ltr ? "TR" : "TL");
  2774. break;
  2775. case "above-alt":
  2776. ltr = !ltr;
  2777. // fall through
  2778. case "above":
  2779. // first try to align left borders, next try to align right borders (or reverse for RTL mode)
  2780. push(ltr ? "TL" : "TR", ltr ? "BL" : "BR");
  2781. push(ltr ? "TR" : "TL", ltr ? "BR" : "BL");
  2782. break;
  2783. default:
  2784. // To assist dijit/_base/place, accept arguments of type {aroundCorner: "BL", corner: "TL"}.
  2785. // Not meant to be used directly.
  2786. push(pos.aroundCorner, pos.corner);
  2787. }
  2788. });
  2789. var position = _place(node, choices, layoutNode, {w: width, h: height});
  2790. position.aroundNodePos = aroundNodePos;
  2791. return position;
  2792. }
  2793. });
  2794. });
  2795. },
  2796. 'dijit/_HasDropDown':function(){
  2797. define("dijit/_HasDropDown", [
  2798. "dojo/_base/declare", // declare
  2799. "dojo/_base/Deferred",
  2800. "dojo/_base/event", // event.stop
  2801. "dojo/dom", // dom.isDescendant
  2802. "dojo/dom-attr", // domAttr.set
  2803. "dojo/dom-class", // domClass.add domClass.contains domClass.remove
  2804. "dojo/dom-geometry", // domGeometry.marginBox domGeometry.position
  2805. "dojo/dom-style", // domStyle.set
  2806. "dojo/has",
  2807. "dojo/keys", // keys.DOWN_ARROW keys.ENTER keys.ESCAPE
  2808. "dojo/_base/lang", // lang.hitch lang.isFunction
  2809. "dojo/touch",
  2810. "dojo/_base/window", // win.doc
  2811. "dojo/window", // winUtils.getBox
  2812. "./registry", // registry.byNode()
  2813. "./focus",
  2814. "./popup",
  2815. "./_FocusMixin"
  2816. ], function(declare, Deferred, event,dom, domAttr, domClass, domGeometry, domStyle, has, keys, lang, touch,
  2817. win, winUtils, registry, focus, popup, _FocusMixin){
  2818. /*=====
  2819. var _FocusMixin = dijit._FocusMixin;
  2820. =====*/
  2821. // module:
  2822. // dijit/_HasDropDown
  2823. // summary:
  2824. // Mixin for widgets that need drop down ability.
  2825. return declare("dijit._HasDropDown", _FocusMixin, {
  2826. // summary:
  2827. // Mixin for widgets that need drop down ability.
  2828. // _buttonNode: [protected] DomNode
  2829. // The button/icon/node to click to display the drop down.
  2830. // Can be set via a data-dojo-attach-point assignment.
  2831. // If missing, then either focusNode or domNode (if focusNode is also missing) will be used.
  2832. _buttonNode: null,
  2833. // _arrowWrapperNode: [protected] DomNode
  2834. // Will set CSS class dijitUpArrow, dijitDownArrow, dijitRightArrow etc. on this node depending
  2835. // on where the drop down is set to be positioned.
  2836. // Can be set via a data-dojo-attach-point assignment.
  2837. // If missing, then _buttonNode will be used.
  2838. _arrowWrapperNode: null,
  2839. // _popupStateNode: [protected] DomNode
  2840. // The node to set the popupActive class on.
  2841. // Can be set via a data-dojo-attach-point assignment.
  2842. // If missing, then focusNode or _buttonNode (if focusNode is missing) will be used.
  2843. _popupStateNode: null,
  2844. // _aroundNode: [protected] DomNode
  2845. // The node to display the popup around.
  2846. // Can be set via a data-dojo-attach-point assignment.
  2847. // If missing, then domNode will be used.
  2848. _aroundNode: null,
  2849. // dropDown: [protected] Widget
  2850. // The widget to display as a popup. This widget *must* be
  2851. // defined before the startup function is called.
  2852. dropDown: null,
  2853. // autoWidth: [protected] Boolean
  2854. // Set to true to make the drop down at least as wide as this
  2855. // widget. Set to false if the drop down should just be its
  2856. // default width
  2857. autoWidth: true,
  2858. // forceWidth: [protected] Boolean
  2859. // Set to true to make the drop down exactly as wide as this
  2860. // widget. Overrides autoWidth.
  2861. forceWidth: false,
  2862. // maxHeight: [protected] Integer
  2863. // The max height for our dropdown.
  2864. // Any dropdown taller than this will have scrollbars.
  2865. // Set to 0 for no max height, or -1 to limit height to available space in viewport
  2866. maxHeight: 0,
  2867. // dropDownPosition: [const] String[]
  2868. // This variable controls the position of the drop down.
  2869. // It's an array of strings with the following values:
  2870. //
  2871. // * before: places drop down to the left of the target node/widget, or to the right in
  2872. // the case of RTL scripts like Hebrew and Arabic
  2873. // * after: places drop down to the right of the target node/widget, or to the left in
  2874. // the case of RTL scripts like Hebrew and Arabic
  2875. // * above: drop down goes above target node
  2876. // * below: drop down goes below target node
  2877. //
  2878. // The list is positions is tried, in order, until a position is found where the drop down fits
  2879. // within the viewport.
  2880. //
  2881. dropDownPosition: ["below","above"],
  2882. // _stopClickEvents: Boolean
  2883. // When set to false, the click events will not be stopped, in
  2884. // case you want to use them in your subwidget
  2885. _stopClickEvents: true,
  2886. _onDropDownMouseDown: function(/*Event*/ e){
  2887. // summary:
  2888. // Callback when the user mousedown's on the arrow icon
  2889. if(this.disabled || this.readOnly){ return; }
  2890. // Prevent default to stop things like text selection, but don't stop propogation, so that:
  2891. // 1. TimeTextBox etc. can focusthe <input> on mousedown
  2892. // 2. dropDownButtonActive class applied by _CssStateMixin (on button depress)
  2893. // 3. user defined onMouseDown handler fires
  2894. e.preventDefault();
  2895. this._docHandler = this.connect(win.doc, touch.release, "_onDropDownMouseUp");
  2896. this.toggleDropDown();
  2897. },
  2898. _onDropDownMouseUp: function(/*Event?*/ e){
  2899. // summary:
  2900. // Callback when the user lifts their mouse after mouse down on the arrow icon.
  2901. // If the drop down is a simple menu and the mouse is over the menu, we execute it, otherwise, we focus our
  2902. // drop down widget. If the event is missing, then we are not
  2903. // a mouseup event.
  2904. //
  2905. // This is useful for the common mouse movement pattern
  2906. // with native browser <select> nodes:
  2907. // 1. mouse down on the select node (probably on the arrow)
  2908. // 2. move mouse to a menu item while holding down the mouse button
  2909. // 3. mouse up. this selects the menu item as though the user had clicked it.
  2910. if(e && this._docHandler){
  2911. this.disconnect(this._docHandler);
  2912. }
  2913. var dropDown = this.dropDown, overMenu = false;
  2914. if(e && this._opened){
  2915. // This code deals with the corner-case when the drop down covers the original widget,
  2916. // because it's so large. In that case mouse-up shouldn't select a value from the menu.
  2917. // Find out if our target is somewhere in our dropdown widget,
  2918. // but not over our _buttonNode (the clickable node)
  2919. var c = domGeometry.position(this._buttonNode, true);
  2920. if(!(e.pageX >= c.x && e.pageX <= c.x + c.w) ||
  2921. !(e.pageY >= c.y && e.pageY <= c.y + c.h)){
  2922. var t = e.target;
  2923. while(t && !overMenu){
  2924. if(domClass.contains(t, "dijitPopup")){
  2925. overMenu = true;
  2926. }else{
  2927. t = t.parentNode;
  2928. }
  2929. }
  2930. if(overMenu){
  2931. t = e.target;
  2932. if(dropDown.onItemClick){
  2933. var menuItem;
  2934. while(t && !(menuItem = registry.byNode(t))){
  2935. t = t.parentNode;
  2936. }
  2937. if(menuItem && menuItem.onClick && menuItem.getParent){
  2938. menuItem.getParent().onItemClick(menuItem, e);
  2939. }
  2940. }
  2941. return;
  2942. }
  2943. }
  2944. }
  2945. if(this._opened){
  2946. if(dropDown.focus && dropDown.autoFocus !== false){
  2947. // Focus the dropdown widget - do it on a delay so that we
  2948. // don't steal our own focus.
  2949. window.setTimeout(lang.hitch(dropDown, "focus"), 1);
  2950. }
  2951. }else{
  2952. // The drop down arrow icon probably can't receive focus, but widget itself should get focus.
  2953. // setTimeout() needed to make it work on IE (test DateTextBox)
  2954. setTimeout(lang.hitch(this, "focus"), 0);
  2955. }
  2956. if(has("ios")){
  2957. this._justGotMouseUp = true;
  2958. setTimeout(lang.hitch(this, function(){
  2959. this._justGotMouseUp = false;
  2960. }), 0);
  2961. }
  2962. },
  2963. _onDropDownClick: function(/*Event*/ e){
  2964. if(has("ios") && !this._justGotMouseUp){
  2965. // This branch fires on iPhone for ComboBox, because the button node is an <input> and doesn't
  2966. // generate touchstart/touchend events. Pretend we just got a mouse down / mouse up.
  2967. // The if(has("ios") is necessary since IE and desktop safari get spurious onclick events
  2968. // when there are nested tables (specifically, clicking on a table that holds a dijit.form.Select,
  2969. // but not on the Select itself, causes an onclick event on the Select)
  2970. this._onDropDownMouseDown(e);
  2971. this._onDropDownMouseUp(e);
  2972. }
  2973. // The drop down was already opened on mousedown/keydown; just need to call stopEvent().
  2974. if(this._stopClickEvents){
  2975. event.stop(e);
  2976. }
  2977. },
  2978. buildRendering: function(){
  2979. this.inherited(arguments);
  2980. this._buttonNode = this._buttonNode || this.focusNode || this.domNode;
  2981. this._popupStateNode = this._popupStateNode || this.focusNode || this._buttonNode;
  2982. // Add a class to the "dijitDownArrowButton" type class to _buttonNode so theme can set direction of arrow
  2983. // based on where drop down will normally appear
  2984. var defaultPos = {
  2985. "after" : this.isLeftToRight() ? "Right" : "Left",
  2986. "before" : this.isLeftToRight() ? "Left" : "Right",
  2987. "above" : "Up",
  2988. "below" : "Down",
  2989. "left" : "Left",
  2990. "right" : "Right"
  2991. }[this.dropDownPosition[0]] || this.dropDownPosition[0] || "Down";
  2992. domClass.add(this._arrowWrapperNode || this._buttonNode, "dijit" + defaultPos + "ArrowButton");
  2993. },
  2994. postCreate: function(){
  2995. // summary:
  2996. // set up nodes and connect our mouse and keypress events
  2997. this.inherited(arguments);
  2998. this.connect(this._buttonNode, touch.press, "_onDropDownMouseDown");
  2999. this.connect(this._buttonNode, "onclick", "_onDropDownClick");
  3000. this.connect(this.focusNode, "onkeypress", "_onKey");
  3001. this.connect(this.focusNode, "onkeyup", "_onKeyUp");
  3002. },
  3003. destroy: function(){
  3004. if(this.dropDown){
  3005. // Destroy the drop down, unless it's already been destroyed. This can happen because
  3006. // the drop down is a direct child of <body> even though it's logically my child.
  3007. if(!this.dropDown._destroyed){
  3008. this.dropDown.destroyRecursive();
  3009. }
  3010. delete this.dropDown;
  3011. }
  3012. this.inherited(arguments);
  3013. },
  3014. _onKey: function(/*Event*/ e){
  3015. // summary:
  3016. // Callback when the user presses a key while focused on the button node
  3017. if(this.disabled || this.readOnly){ return; }
  3018. var d = this.dropDown, target = e.target;
  3019. if(d && this._opened && d.handleKey){
  3020. if(d.handleKey(e) === false){
  3021. /* false return code means that the drop down handled the key */
  3022. event.stop(e);
  3023. return;
  3024. }
  3025. }
  3026. if(d && this._opened && e.charOrCode == keys.ESCAPE){
  3027. this.closeDropDown();
  3028. event.stop(e);
  3029. }else if(!this._opened &&
  3030. (e.charOrCode == keys.DOWN_ARROW ||
  3031. ( (e.charOrCode == keys.ENTER || e.charOrCode == " ") &&
  3032. //ignore enter and space if the event is for a text input
  3033. ((target.tagName || "").toLowerCase() !== 'input' ||
  3034. (target.type && target.type.toLowerCase() !== 'text'))))){
  3035. // Toggle the drop down, but wait until keyup so that the drop down doesn't
  3036. // get a stray keyup event, or in the case of key-repeat (because user held
  3037. // down key for too long), stray keydown events
  3038. this._toggleOnKeyUp = true;
  3039. event.stop(e);
  3040. }
  3041. },
  3042. _onKeyUp: function(){
  3043. if(this._toggleOnKeyUp){
  3044. delete this._toggleOnKeyUp;
  3045. this.toggleDropDown();
  3046. var d = this.dropDown; // drop down may not exist until toggleDropDown() call
  3047. if(d && d.focus){
  3048. setTimeout(lang.hitch(d, "focus"), 1);
  3049. }
  3050. }
  3051. },
  3052. _onBlur: function(){
  3053. // summary:
  3054. // Called magically when focus has shifted away from this widget and it's dropdown
  3055. // Don't focus on button if the user has explicitly focused on something else (happens
  3056. // when user clicks another control causing the current popup to close)..
  3057. // But if focus is inside of the drop down then reset focus to me, because IE doesn't like
  3058. // it when you display:none a node with focus.
  3059. var focusMe = focus.curNode && this.dropDown && dom.isDescendant(focus.curNode, this.dropDown.domNode);
  3060. this.closeDropDown(focusMe);
  3061. this.inherited(arguments);
  3062. },
  3063. isLoaded: function(){
  3064. // summary:
  3065. // Returns true if the dropdown exists and it's data is loaded. This can
  3066. // be overridden in order to force a call to loadDropDown().
  3067. // tags:
  3068. // protected
  3069. return true;
  3070. },
  3071. loadDropDown: function(/*Function*/ loadCallback){
  3072. // summary:
  3073. // Creates the drop down if it doesn't exist, loads the data
  3074. // if there's an href and it hasn't been loaded yet, and then calls
  3075. // the given callback.
  3076. // tags:
  3077. // protected
  3078. // TODO: for 2.0, change API to return a Deferred, instead of calling loadCallback?
  3079. loadCallback();
  3080. },
  3081. loadAndOpenDropDown: function(){
  3082. // summary:
  3083. // Creates the drop down if it doesn't exist, loads the data
  3084. // if there's an href and it hasn't been loaded yet, and
  3085. // then opens the drop down. This is basically a callback when the
  3086. // user presses the down arrow button to open the drop down.
  3087. // returns: Deferred
  3088. // Deferred for the drop down widget that
  3089. // fires when drop down is created and loaded
  3090. // tags:
  3091. // protected
  3092. var d = new Deferred(),
  3093. afterLoad = lang.hitch(this, function(){
  3094. this.openDropDown();
  3095. d.resolve(this.dropDown);
  3096. });
  3097. if(!this.isLoaded()){
  3098. this.loadDropDown(afterLoad);
  3099. }else{
  3100. afterLoad();
  3101. }
  3102. return d;
  3103. },
  3104. toggleDropDown: function(){
  3105. // summary:
  3106. // Callback when the user presses the down arrow button or presses
  3107. // the down arrow key to open/close the drop down.
  3108. // Toggle the drop-down widget; if it is up, close it, if not, open it
  3109. // tags:
  3110. // protected
  3111. if(this.disabled || this.readOnly){ return; }
  3112. if(!this._opened){
  3113. this.loadAndOpenDropDown();
  3114. }else{
  3115. this.closeDropDown();
  3116. }
  3117. },
  3118. openDropDown: function(){
  3119. // summary:
  3120. // Opens the dropdown for this widget. To be called only when this.dropDown
  3121. // has been created and is ready to display (ie, it's data is loaded).
  3122. // returns:
  3123. // return value of dijit.popup.open()
  3124. // tags:
  3125. // protected
  3126. var dropDown = this.dropDown,
  3127. ddNode = dropDown.domNode,
  3128. aroundNode = this._aroundNode || this.domNode,
  3129. self = this;
  3130. // Prepare our popup's height and honor maxHeight if it exists.
  3131. // TODO: isn't maxHeight dependent on the return value from dijit.popup.open(),
  3132. // ie, dependent on how much space is available (BK)
  3133. if(!this._preparedNode){
  3134. this._preparedNode = true;
  3135. // Check if we have explicitly set width and height on the dropdown widget dom node
  3136. if(ddNode.style.width){
  3137. this._explicitDDWidth = true;
  3138. }
  3139. if(ddNode.style.height){
  3140. this._explicitDDHeight = true;
  3141. }
  3142. }
  3143. // Code for resizing dropdown (height limitation, or increasing width to match my width)
  3144. if(this.maxHeight || this.forceWidth || this.autoWidth){
  3145. var myStyle = {
  3146. display: "",
  3147. visibility: "hidden"
  3148. };
  3149. if(!this._explicitDDWidth){
  3150. myStyle.width = "";
  3151. }
  3152. if(!this._explicitDDHeight){
  3153. myStyle.height = "";
  3154. }
  3155. domStyle.set(ddNode, myStyle);
  3156. // Figure out maximum height allowed (if there is a height restriction)
  3157. var maxHeight = this.maxHeight;
  3158. if(maxHeight == -1){
  3159. // limit height to space available in viewport either above or below my domNode
  3160. // (whichever side has more room)
  3161. var viewport = winUtils.getBox(),
  3162. position = domGeometry.position(aroundNode, false);
  3163. maxHeight = Math.floor(Math.max(position.y, viewport.h - (position.y + position.h)));
  3164. }
  3165. // Attach dropDown to DOM and make make visibility:hidden rather than display:none
  3166. // so we call startup() and also get the size
  3167. popup.moveOffScreen(dropDown);
  3168. if(dropDown.startup && !dropDown._started){
  3169. dropDown.startup(); // this has to be done after being added to the DOM
  3170. }
  3171. // Get size of drop down, and determine if vertical scroll bar needed
  3172. var mb = domGeometry.getMarginSize(ddNode);
  3173. var overHeight = (maxHeight && mb.h > maxHeight);
  3174. domStyle.set(ddNode, {
  3175. overflowX: "hidden",
  3176. overflowY: overHeight ? "auto" : "hidden"
  3177. });
  3178. if(overHeight){
  3179. mb.h = maxHeight;
  3180. if("w" in mb){
  3181. mb.w += 16; // room for vertical scrollbar
  3182. }
  3183. }else{
  3184. delete mb.h;
  3185. }
  3186. // Adjust dropdown width to match or be larger than my width
  3187. if(this.forceWidth){
  3188. mb.w = aroundNode.offsetWidth;
  3189. }else if(this.autoWidth){
  3190. mb.w = Math.max(mb.w, aroundNode.offsetWidth);
  3191. }else{
  3192. delete mb.w;
  3193. }
  3194. // And finally, resize the dropdown to calculated height and width
  3195. if(lang.isFunction(dropDown.resize)){
  3196. dropDown.resize(mb);
  3197. }else{
  3198. domGeometry.setMarginBox(ddNode, mb);
  3199. }
  3200. }
  3201. var retVal = popup.open({
  3202. parent: this,
  3203. popup: dropDown,
  3204. around: aroundNode,
  3205. orient: this.dropDownPosition,
  3206. onExecute: function(){
  3207. self.closeDropDown(true);
  3208. },
  3209. onCancel: function(){
  3210. self.closeDropDown(true);
  3211. },
  3212. onClose: function(){
  3213. domAttr.set(self._popupStateNode, "popupActive", false);
  3214. domClass.remove(self._popupStateNode, "dijitHasDropDownOpen");
  3215. self._opened = false;
  3216. }
  3217. });
  3218. domAttr.set(this._popupStateNode, "popupActive", "true");
  3219. domClass.add(self._popupStateNode, "dijitHasDropDownOpen");
  3220. this._opened=true;
  3221. // TODO: set this.checked and call setStateClass(), to affect button look while drop down is shown
  3222. return retVal;
  3223. },
  3224. closeDropDown: function(/*Boolean*/ focus){
  3225. // summary:
  3226. // Closes the drop down on this widget
  3227. // focus:
  3228. // If true, refocuses the button widget
  3229. // tags:
  3230. // protected
  3231. if(this._opened){
  3232. if(focus){ this.focus(); }
  3233. popup.close(this.dropDown);
  3234. this._opened = false;
  3235. }
  3236. }
  3237. });
  3238. });
  3239. },
  3240. 'dijit/_editor/plugins/EnterKeyHandling':function(){
  3241. define("dijit/_editor/plugins/EnterKeyHandling", [
  3242. "dojo/_base/declare", // declare
  3243. "dojo/dom-construct", // domConstruct.destroy domConstruct.place
  3244. "dojo/_base/event", // event.stop
  3245. "dojo/keys", // keys.ENTER
  3246. "dojo/_base/lang",
  3247. "dojo/_base/sniff", // has("ie") has("mozilla") has("webkit")
  3248. "dojo/_base/window", // win.global win.withGlobal
  3249. "dojo/window", // winUtils.scrollIntoView
  3250. "../_Plugin",
  3251. "../RichText",
  3252. "../range",
  3253. "../selection"
  3254. ], function(declare, domConstruct, event, keys, lang, has, win, winUtils, _Plugin, RichText, rangeapi, selectionapi){
  3255. /*=====
  3256. var _Plugin = dijit._editor._Plugin;
  3257. =====*/
  3258. // module:
  3259. // dijit/_editor/plugins/EnterKeyHandling
  3260. // summary:
  3261. // This plugin tries to make all browsers behave consistently with regard to
  3262. // how ENTER behaves in the editor window. It traps the ENTER key and alters
  3263. // the way DOM is constructed in certain cases to try to commonize the generated
  3264. // DOM and behaviors across browsers.
  3265. return declare("dijit._editor.plugins.EnterKeyHandling", _Plugin, {
  3266. // summary:
  3267. // This plugin tries to make all browsers behave consistently with regard to
  3268. // how ENTER behaves in the editor window. It traps the ENTER key and alters
  3269. // the way DOM is constructed in certain cases to try to commonize the generated
  3270. // DOM and behaviors across browsers.
  3271. //
  3272. // description:
  3273. // This plugin has three modes:
  3274. //
  3275. // * blockNodeForEnter=BR
  3276. // * blockNodeForEnter=DIV
  3277. // * blockNodeForEnter=P
  3278. //
  3279. // In blockNodeForEnter=P, the ENTER key starts a new
  3280. // paragraph, and shift-ENTER starts a new line in the current paragraph.
  3281. // For example, the input:
  3282. //
  3283. // | first paragraph <shift-ENTER>
  3284. // | second line of first paragraph <ENTER>
  3285. // | second paragraph
  3286. //
  3287. // will generate:
  3288. //
  3289. // | <p>
  3290. // | first paragraph
  3291. // | <br/>
  3292. // | second line of first paragraph
  3293. // | </p>
  3294. // | <p>
  3295. // | second paragraph
  3296. // | </p>
  3297. //
  3298. // In BR and DIV mode, the ENTER key conceptually goes to a new line in the
  3299. // current paragraph, and users conceptually create a new paragraph by pressing ENTER twice.
  3300. // For example, if the user enters text into an editor like this:
  3301. //
  3302. // | one <ENTER>
  3303. // | two <ENTER>
  3304. // | three <ENTER>
  3305. // | <ENTER>
  3306. // | four <ENTER>
  3307. // | five <ENTER>
  3308. // | six <ENTER>
  3309. //
  3310. // It will appear on the screen as two 'paragraphs' of three lines each. Markupwise, this generates:
  3311. //
  3312. // BR:
  3313. // | one<br/>
  3314. // | two<br/>
  3315. // | three<br/>
  3316. // | <br/>
  3317. // | four<br/>
  3318. // | five<br/>
  3319. // | six<br/>
  3320. //
  3321. // DIV:
  3322. // | <div>one</div>
  3323. // | <div>two</div>
  3324. // | <div>three</div>
  3325. // | <div>&nbsp;</div>
  3326. // | <div>four</div>
  3327. // | <div>five</div>
  3328. // | <div>six</div>
  3329. // blockNodeForEnter: String
  3330. // This property decides the behavior of Enter key. It can be either P,
  3331. // DIV, BR, or empty (which means disable this feature). Anything else
  3332. // will trigger errors. The default is 'BR'
  3333. //
  3334. // See class description for more details.
  3335. blockNodeForEnter: 'BR',
  3336. constructor: function(args){
  3337. if(args){
  3338. if("blockNodeForEnter" in args){
  3339. args.blockNodeForEnter = args.blockNodeForEnter.toUpperCase();
  3340. }
  3341. lang.mixin(this,args);
  3342. }
  3343. },
  3344. setEditor: function(editor){
  3345. // Overrides _Plugin.setEditor().
  3346. if(this.editor === editor){ return; }
  3347. this.editor = editor;
  3348. if(this.blockNodeForEnter == 'BR'){
  3349. // While Moz has a mode tht mostly works, it's still a little different,
  3350. // So, try to just have a common mode and be consistent. Which means
  3351. // we need to enable customUndo, if not already enabled.
  3352. this.editor.customUndo = true;
  3353. editor.onLoadDeferred.then(lang.hitch(this,function(d){
  3354. this.connect(editor.document, "onkeypress", function(e){
  3355. if(e.charOrCode == keys.ENTER){
  3356. // Just do it manually. The handleEnterKey has a shift mode that
  3357. // Always acts like <br>, so just use it.
  3358. var ne = lang.mixin({},e);
  3359. ne.shiftKey = true;
  3360. if(!this.handleEnterKey(ne)){
  3361. event.stop(e);
  3362. }
  3363. }
  3364. });
  3365. if(has("ie") == 9){
  3366. this.connect(editor.document, "onpaste", function(e){
  3367. setTimeout(dojo.hitch(this, function(){
  3368. // Use the old range/selection code to kick IE 9 into updating
  3369. // its range by moving it back, then forward, one 'character'.
  3370. var r = this.editor.document.selection.createRange();
  3371. r.move('character',-1);
  3372. r.select();
  3373. r.move('character',1);
  3374. r.select();
  3375. }),0);
  3376. });
  3377. }
  3378. return d;
  3379. }));
  3380. }else if(this.blockNodeForEnter){
  3381. // add enter key handler
  3382. // FIXME: need to port to the new event code!!
  3383. var h = lang.hitch(this,this.handleEnterKey);
  3384. editor.addKeyHandler(13, 0, 0, h); //enter
  3385. editor.addKeyHandler(13, 0, 1, h); //shift+enter
  3386. this.connect(this.editor,'onKeyPressed','onKeyPressed');
  3387. }
  3388. },
  3389. onKeyPressed: function(){
  3390. // summary:
  3391. // Handler for keypress events.
  3392. // tags:
  3393. // private
  3394. if(this._checkListLater){
  3395. if(win.withGlobal(this.editor.window, 'isCollapsed', dijit)){
  3396. var liparent=win.withGlobal(this.editor.window, 'getAncestorElement', selectionapi, ['LI']);
  3397. if(!liparent){
  3398. // circulate the undo detection code by calling RichText::execCommand directly
  3399. RichText.prototype.execCommand.call(this.editor, 'formatblock',this.blockNodeForEnter);
  3400. // set the innerHTML of the new block node
  3401. var block = win.withGlobal(this.editor.window, 'getAncestorElement', selectionapi, [this.blockNodeForEnter]);
  3402. if(block){
  3403. block.innerHTML=this.bogusHtmlContent;
  3404. if(has("ie")){
  3405. // move to the start by moving backwards one char
  3406. var r = this.editor.document.selection.createRange();
  3407. r.move('character',-1);
  3408. r.select();
  3409. }
  3410. }else{
  3411. console.error('onKeyPressed: Cannot find the new block node'); // FIXME
  3412. }
  3413. }else{
  3414. if(has("mozilla")){
  3415. if(liparent.parentNode.parentNode.nodeName == 'LI'){
  3416. liparent=liparent.parentNode.parentNode;
  3417. }
  3418. }
  3419. var fc=liparent.firstChild;
  3420. if(fc && fc.nodeType == 1 && (fc.nodeName == 'UL' || fc.nodeName == 'OL')){
  3421. liparent.insertBefore(fc.ownerDocument.createTextNode('\xA0'),fc);
  3422. var newrange = rangeapi.create(this.editor.window);
  3423. newrange.setStart(liparent.firstChild,0);
  3424. var selection = rangeapi.getSelection(this.editor.window, true);
  3425. selection.removeAllRanges();
  3426. selection.addRange(newrange);
  3427. }
  3428. }
  3429. }
  3430. this._checkListLater = false;
  3431. }
  3432. if(this._pressedEnterInBlock){
  3433. // the new created is the original current P, so we have previousSibling below
  3434. if(this._pressedEnterInBlock.previousSibling){
  3435. this.removeTrailingBr(this._pressedEnterInBlock.previousSibling);
  3436. }
  3437. delete this._pressedEnterInBlock;
  3438. }
  3439. },
  3440. // bogusHtmlContent: [private] String
  3441. // HTML to stick into a new empty block
  3442. bogusHtmlContent: '&#160;', // &nbsp;
  3443. // blockNodes: [private] Regex
  3444. // Regex for testing if a given tag is a block level (display:block) tag
  3445. blockNodes: /^(?:P|H1|H2|H3|H4|H5|H6|LI)$/,
  3446. handleEnterKey: function(e){
  3447. // summary:
  3448. // Handler for enter key events when blockNodeForEnter is DIV or P.
  3449. // description:
  3450. // Manually handle enter key event to make the behavior consistent across
  3451. // all supported browsers. See class description for details.
  3452. // tags:
  3453. // private
  3454. var selection, range, newrange, startNode, endNode, brNode, doc=this.editor.document,br,rs,txt;
  3455. if(e.shiftKey){ // shift+enter always generates <br>
  3456. var parent = win.withGlobal(this.editor.window, "getParentElement", selectionapi);
  3457. var header = rangeapi.getAncestor(parent,this.blockNodes);
  3458. if(header){
  3459. if(header.tagName == 'LI'){
  3460. return true; // let browser handle
  3461. }
  3462. selection = rangeapi.getSelection(this.editor.window);
  3463. range = selection.getRangeAt(0);
  3464. if(!range.collapsed){
  3465. range.deleteContents();
  3466. selection = rangeapi.getSelection(this.editor.window);
  3467. range = selection.getRangeAt(0);
  3468. }
  3469. if(rangeapi.atBeginningOfContainer(header, range.startContainer, range.startOffset)){
  3470. br=doc.createElement('br');
  3471. newrange = rangeapi.create(this.editor.window);
  3472. header.insertBefore(br,header.firstChild);
  3473. newrange.setStartAfter(br);
  3474. selection.removeAllRanges();
  3475. selection.addRange(newrange);
  3476. }else if(rangeapi.atEndOfContainer(header, range.startContainer, range.startOffset)){
  3477. newrange = rangeapi.create(this.editor.window);
  3478. br=doc.createElement('br');
  3479. header.appendChild(br);
  3480. header.appendChild(doc.createTextNode('\xA0'));
  3481. newrange.setStart(header.lastChild,0);
  3482. selection.removeAllRanges();
  3483. selection.addRange(newrange);
  3484. }else{
  3485. rs = range.startContainer;
  3486. if(rs && rs.nodeType == 3){
  3487. // Text node, we have to split it.
  3488. txt = rs.nodeValue;
  3489. win.withGlobal(this.editor.window, function(){
  3490. startNode = doc.createTextNode(txt.substring(0, range.startOffset));
  3491. endNode = doc.createTextNode(txt.substring(range.startOffset));
  3492. brNode = doc.createElement("br");
  3493. if(endNode.nodeValue == "" && has("webkit")){
  3494. endNode = doc.createTextNode('\xA0')
  3495. }
  3496. domConstruct.place(startNode, rs, "after");
  3497. domConstruct.place(brNode, startNode, "after");
  3498. domConstruct.place(endNode, brNode, "after");
  3499. domConstruct.destroy(rs);
  3500. newrange = rangeapi.create();
  3501. newrange.setStart(endNode,0);
  3502. selection.removeAllRanges();
  3503. selection.addRange(newrange);
  3504. });
  3505. return false;
  3506. }
  3507. return true; // let browser handle
  3508. }
  3509. }else{
  3510. selection = rangeapi.getSelection(this.editor.window);
  3511. if(selection.rangeCount){
  3512. range = selection.getRangeAt(0);
  3513. if(range && range.startContainer){
  3514. if(!range.collapsed){
  3515. range.deleteContents();
  3516. selection = rangeapi.getSelection(this.editor.window);
  3517. range = selection.getRangeAt(0);
  3518. }
  3519. rs = range.startContainer;
  3520. if(rs && rs.nodeType == 3){
  3521. // Text node, we have to split it.
  3522. win.withGlobal(this.editor.window, lang.hitch(this, function(){
  3523. var endEmpty = false;
  3524. var offset = range.startOffset;
  3525. if(rs.length < offset){
  3526. //We are not splitting the right node, try to locate the correct one
  3527. ret = this._adjustNodeAndOffset(rs, offset);
  3528. rs = ret.node;
  3529. offset = ret.offset;
  3530. }
  3531. txt = rs.nodeValue;
  3532. startNode = doc.createTextNode(txt.substring(0, offset));
  3533. endNode = doc.createTextNode(txt.substring(offset));
  3534. brNode = doc.createElement("br");
  3535. if(!endNode.length){
  3536. endNode = doc.createTextNode('\xA0');
  3537. endEmpty = true;
  3538. }
  3539. if(startNode.length){
  3540. domConstruct.place(startNode, rs, "after");
  3541. }else{
  3542. startNode = rs;
  3543. }
  3544. domConstruct.place(brNode, startNode, "after");
  3545. domConstruct.place(endNode, brNode, "after");
  3546. domConstruct.destroy(rs);
  3547. newrange = rangeapi.create();
  3548. newrange.setStart(endNode,0);
  3549. newrange.setEnd(endNode, endNode.length);
  3550. selection.removeAllRanges();
  3551. selection.addRange(newrange);
  3552. if(endEmpty && !has("webkit")){
  3553. selectionapi.remove();
  3554. }else{
  3555. selectionapi.collapse(true);
  3556. }
  3557. }));
  3558. }else{
  3559. var targetNode;
  3560. if(range.startOffset >= 0){
  3561. targetNode = rs.childNodes[range.startOffset];
  3562. }
  3563. win.withGlobal(this.editor.window, lang.hitch(this, function(){
  3564. var brNode = doc.createElement("br");
  3565. var endNode = doc.createTextNode('\xA0');
  3566. if(!targetNode){
  3567. rs.appendChild(brNode);
  3568. rs.appendChild(endNode);
  3569. }else{
  3570. domConstruct.place(brNode, targetNode, "before");
  3571. domConstruct.place(endNode, brNode, "after");
  3572. }
  3573. newrange = rangeapi.create(win.global);
  3574. newrange.setStart(endNode,0);
  3575. newrange.setEnd(endNode, endNode.length);
  3576. selection.removeAllRanges();
  3577. selection.addRange(newrange);
  3578. selectionapi.collapse(true);
  3579. }));
  3580. }
  3581. }
  3582. }else{
  3583. // don't change this: do not call this.execCommand, as that may have other logic in subclass
  3584. RichText.prototype.execCommand.call(this.editor, 'inserthtml', '<br>');
  3585. }
  3586. }
  3587. return false;
  3588. }
  3589. var _letBrowserHandle = true;
  3590. // first remove selection
  3591. selection = rangeapi.getSelection(this.editor.window);
  3592. range = selection.getRangeAt(0);
  3593. if(!range.collapsed){
  3594. range.deleteContents();
  3595. selection = rangeapi.getSelection(this.editor.window);
  3596. range = selection.getRangeAt(0);
  3597. }
  3598. var block = rangeapi.getBlockAncestor(range.endContainer, null, this.editor.editNode);
  3599. var blockNode = block.blockNode;
  3600. // if this is under a LI or the parent of the blockNode is LI, just let browser to handle it
  3601. if((this._checkListLater = (blockNode && (blockNode.nodeName == 'LI' || blockNode.parentNode.nodeName == 'LI')))){
  3602. if(has("mozilla")){
  3603. // press enter in middle of P may leave a trailing <br/>, let's remove it later
  3604. this._pressedEnterInBlock = blockNode;
  3605. }
  3606. // if this li only contains spaces, set the content to empty so the browser will outdent this item
  3607. if(/^(\s|&nbsp;|&#160;|\xA0|<span\b[^>]*\bclass=['"]Apple-style-span['"][^>]*>(\s|&nbsp;|&#160;|\xA0)<\/span>)?(<br>)?$/.test(blockNode.innerHTML)){
  3608. // empty LI node
  3609. blockNode.innerHTML = '';
  3610. if(has("webkit")){ // WebKit tosses the range when innerHTML is reset
  3611. newrange = rangeapi.create(this.editor.window);
  3612. newrange.setStart(blockNode, 0);
  3613. selection.removeAllRanges();
  3614. selection.addRange(newrange);
  3615. }
  3616. this._checkListLater = false; // nothing to check since the browser handles outdent
  3617. }
  3618. return true;
  3619. }
  3620. // text node directly under body, let's wrap them in a node
  3621. if(!block.blockNode || block.blockNode===this.editor.editNode){
  3622. try{
  3623. RichText.prototype.execCommand.call(this.editor, 'formatblock',this.blockNodeForEnter);
  3624. }catch(e2){ /*squelch FF3 exception bug when editor content is a single BR*/ }
  3625. // get the newly created block node
  3626. // FIXME
  3627. block = {blockNode:win.withGlobal(this.editor.window, "getAncestorElement", selectionapi, [this.blockNodeForEnter]),
  3628. blockContainer: this.editor.editNode};
  3629. if(block.blockNode){
  3630. if(block.blockNode != this.editor.editNode &&
  3631. (!(block.blockNode.textContent || block.blockNode.innerHTML).replace(/^\s+|\s+$/g, "").length)){
  3632. this.removeTrailingBr(block.blockNode);
  3633. return false;
  3634. }
  3635. }else{ // we shouldn't be here if formatblock worked
  3636. block.blockNode = this.editor.editNode;
  3637. }
  3638. selection = rangeapi.getSelection(this.editor.window);
  3639. range = selection.getRangeAt(0);
  3640. }
  3641. var newblock = doc.createElement(this.blockNodeForEnter);
  3642. newblock.innerHTML=this.bogusHtmlContent;
  3643. this.removeTrailingBr(block.blockNode);
  3644. var endOffset = range.endOffset;
  3645. var node = range.endContainer;
  3646. if(node.length < endOffset){
  3647. //We are not checking the right node, try to locate the correct one
  3648. var ret = this._adjustNodeAndOffset(node, endOffset);
  3649. node = ret.node;
  3650. endOffset = ret.offset;
  3651. }
  3652. if(rangeapi.atEndOfContainer(block.blockNode, node, endOffset)){
  3653. if(block.blockNode === block.blockContainer){
  3654. block.blockNode.appendChild(newblock);
  3655. }else{
  3656. domConstruct.place(newblock, block.blockNode, "after");
  3657. }
  3658. _letBrowserHandle = false;
  3659. // lets move caret to the newly created block
  3660. newrange = rangeapi.create(this.editor.window);
  3661. newrange.setStart(newblock, 0);
  3662. selection.removeAllRanges();
  3663. selection.addRange(newrange);
  3664. if(this.editor.height){
  3665. winUtils.scrollIntoView(newblock);
  3666. }
  3667. }else if(rangeapi.atBeginningOfContainer(block.blockNode,
  3668. range.startContainer, range.startOffset)){
  3669. domConstruct.place(newblock, block.blockNode, block.blockNode === block.blockContainer ? "first" : "before");
  3670. if(newblock.nextSibling && this.editor.height){
  3671. // position input caret - mostly WebKit needs this
  3672. newrange = rangeapi.create(this.editor.window);
  3673. newrange.setStart(newblock.nextSibling, 0);
  3674. selection.removeAllRanges();
  3675. selection.addRange(newrange);
  3676. // browser does not scroll the caret position into view, do it manually
  3677. winUtils.scrollIntoView(newblock.nextSibling);
  3678. }
  3679. _letBrowserHandle = false;
  3680. }else{ //press enter in the middle of P/DIV/Whatever/
  3681. if(block.blockNode === block.blockContainer){
  3682. block.blockNode.appendChild(newblock);
  3683. }else{
  3684. domConstruct.place(newblock, block.blockNode, "after");
  3685. }
  3686. _letBrowserHandle = false;
  3687. // Clone any block level styles.
  3688. if(block.blockNode.style){
  3689. if(newblock.style){
  3690. if(block.blockNode.style.cssText){
  3691. newblock.style.cssText = block.blockNode.style.cssText;
  3692. }
  3693. }
  3694. }
  3695. // Okay, we probably have to split.
  3696. rs = range.startContainer;
  3697. var firstNodeMoved;
  3698. if(rs && rs.nodeType == 3){
  3699. // Text node, we have to split it.
  3700. var nodeToMove, tNode;
  3701. endOffset = range.endOffset;
  3702. if(rs.length < endOffset){
  3703. //We are not splitting the right node, try to locate the correct one
  3704. ret = this._adjustNodeAndOffset(rs, endOffset);
  3705. rs = ret.node;
  3706. endOffset = ret.offset;
  3707. }
  3708. txt = rs.nodeValue;
  3709. startNode = doc.createTextNode(txt.substring(0, endOffset));
  3710. endNode = doc.createTextNode(txt.substring(endOffset, txt.length));
  3711. // Place the split, then remove original nodes.
  3712. domConstruct.place(startNode, rs, "before");
  3713. domConstruct.place(endNode, rs, "after");
  3714. domConstruct.destroy(rs);
  3715. // Okay, we split the text. Now we need to see if we're
  3716. // parented to the block element we're splitting and if
  3717. // not, we have to split all the way up. Ugh.
  3718. var parentC = startNode.parentNode;
  3719. while(parentC !== block.blockNode){
  3720. var tg = parentC.tagName;
  3721. var newTg = doc.createElement(tg);
  3722. // Clone over any 'style' data.
  3723. if(parentC.style){
  3724. if(newTg.style){
  3725. if(parentC.style.cssText){
  3726. newTg.style.cssText = parentC.style.cssText;
  3727. }
  3728. }
  3729. }
  3730. // If font also need to clone over any font data.
  3731. if(parentC.tagName === "FONT"){
  3732. if(parentC.color){
  3733. newTg.color = parentC.color;
  3734. }
  3735. if(parentC.face){
  3736. newTg.face = parentC.face;
  3737. }
  3738. if(parentC.size){ // this check was necessary on IE
  3739. newTg.size = parentC.size;
  3740. }
  3741. }
  3742. nodeToMove = endNode;
  3743. while(nodeToMove){
  3744. tNode = nodeToMove.nextSibling;
  3745. newTg.appendChild(nodeToMove);
  3746. nodeToMove = tNode;
  3747. }
  3748. domConstruct.place(newTg, parentC, "after");
  3749. startNode = parentC;
  3750. endNode = newTg;
  3751. parentC = parentC.parentNode;
  3752. }
  3753. // Lastly, move the split out tags to the new block.
  3754. // as they should now be split properly.
  3755. nodeToMove = endNode;
  3756. if(nodeToMove.nodeType == 1 || (nodeToMove.nodeType == 3 && nodeToMove.nodeValue)){
  3757. // Non-blank text and non-text nodes need to clear out that blank space
  3758. // before moving the contents.
  3759. newblock.innerHTML = "";
  3760. }
  3761. firstNodeMoved = nodeToMove;
  3762. while(nodeToMove){
  3763. tNode = nodeToMove.nextSibling;
  3764. newblock.appendChild(nodeToMove);
  3765. nodeToMove = tNode;
  3766. }
  3767. }
  3768. //lets move caret to the newly created block
  3769. newrange = rangeapi.create(this.editor.window);
  3770. var nodeForCursor;
  3771. var innerMostFirstNodeMoved = firstNodeMoved;
  3772. if(this.blockNodeForEnter !== 'BR'){
  3773. while(innerMostFirstNodeMoved){
  3774. nodeForCursor = innerMostFirstNodeMoved;
  3775. tNode = innerMostFirstNodeMoved.firstChild;
  3776. innerMostFirstNodeMoved = tNode;
  3777. }
  3778. if(nodeForCursor && nodeForCursor.parentNode){
  3779. newblock = nodeForCursor.parentNode;
  3780. newrange.setStart(newblock, 0);
  3781. selection.removeAllRanges();
  3782. selection.addRange(newrange);
  3783. if(this.editor.height){
  3784. winUtils.scrollIntoView(newblock);
  3785. }
  3786. if(has("mozilla")){
  3787. // press enter in middle of P may leave a trailing <br/>, let's remove it later
  3788. this._pressedEnterInBlock = block.blockNode;
  3789. }
  3790. }else{
  3791. _letBrowserHandle = true;
  3792. }
  3793. }else{
  3794. newrange.setStart(newblock, 0);
  3795. selection.removeAllRanges();
  3796. selection.addRange(newrange);
  3797. if(this.editor.height){
  3798. winUtils.scrollIntoView(newblock);
  3799. }
  3800. if(has("mozilla")){
  3801. // press enter in middle of P may leave a trailing <br/>, let's remove it later
  3802. this._pressedEnterInBlock = block.blockNode;
  3803. }
  3804. }
  3805. }
  3806. return _letBrowserHandle;
  3807. },
  3808. _adjustNodeAndOffset: function(/*DomNode*/node, /*Int*/offset){
  3809. // summary:
  3810. // 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
  3811. // the next text sibling until it locates the text node in which the offset refers to
  3812. // node:
  3813. // The node to check.
  3814. // offset:
  3815. // The position to find within the text node
  3816. // tags:
  3817. // private.
  3818. while(node.length < offset && node.nextSibling && node.nextSibling.nodeType==3){
  3819. //Adjust the offset and node in the case of multiple text nodes in a row
  3820. offset = offset - node.length;
  3821. node = node.nextSibling;
  3822. }
  3823. return {"node": node, "offset": offset};
  3824. },
  3825. removeTrailingBr: function(container){
  3826. // summary:
  3827. // If last child of container is a <br>, then remove it.
  3828. // tags:
  3829. // private
  3830. var para = /P|DIV|LI/i.test(container.tagName) ?
  3831. container : selectionapi.getParentOfType(container,['P','DIV','LI']);
  3832. if(!para){ return; }
  3833. if(para.lastChild){
  3834. if((para.childNodes.length > 1 && para.lastChild.nodeType == 3 && /^[\s\xAD]*$/.test(para.lastChild.nodeValue)) ||
  3835. para.lastChild.tagName=='BR'){
  3836. domConstruct.destroy(para.lastChild);
  3837. }
  3838. }
  3839. if(!para.childNodes.length){
  3840. para.innerHTML=this.bogusHtmlContent;
  3841. }
  3842. }
  3843. });
  3844. });
  3845. },
  3846. 'dojo/dnd/Selector':function(){
  3847. define("dojo/dnd/Selector", ["../main", "./common", "./Container"], function(dojo) {
  3848. // module:
  3849. // dojo/dnd/Selector
  3850. // summary:
  3851. // TODOC
  3852. /*
  3853. Container item states:
  3854. "" - an item is not selected
  3855. "Selected" - an item is selected
  3856. "Anchor" - an item is selected, and is an anchor for a "shift" selection
  3857. */
  3858. /*=====
  3859. dojo.declare("dojo.dnd.__SelectorArgs", [dojo.dnd.__ContainerArgs], {
  3860. // singular: Boolean
  3861. // allows selection of only one element, if true
  3862. singular: false,
  3863. // autoSync: Boolean
  3864. // autosynchronizes the source with its list of DnD nodes,
  3865. autoSync: false
  3866. });
  3867. =====*/
  3868. dojo.declare("dojo.dnd.Selector", dojo.dnd.Container, {
  3869. // summary:
  3870. // a Selector object, which knows how to select its children
  3871. /*=====
  3872. // selection: Set<String>
  3873. // The set of id's that are currently selected, such that this.selection[id] == 1
  3874. // if the node w/that id is selected. Can iterate over selected node's id's like:
  3875. // | for(var id in this.selection)
  3876. selection: {},
  3877. =====*/
  3878. constructor: function(node, params){
  3879. // summary:
  3880. // constructor of the Selector
  3881. // node: Node||String
  3882. // node or node's id to build the selector on
  3883. // params: dojo.dnd.__SelectorArgs?
  3884. // a dictionary of parameters
  3885. if(!params){ params = {}; }
  3886. this.singular = params.singular;
  3887. this.autoSync = params.autoSync;
  3888. // class-specific variables
  3889. this.selection = {};
  3890. this.anchor = null;
  3891. this.simpleSelection = false;
  3892. // set up events
  3893. this.events.push(
  3894. dojo.connect(this.node, "onmousedown", this, "onMouseDown"),
  3895. dojo.connect(this.node, "onmouseup", this, "onMouseUp"));
  3896. },
  3897. // object attributes (for markup)
  3898. singular: false, // is singular property
  3899. // methods
  3900. getSelectedNodes: function(){
  3901. // summary:
  3902. // returns a list (an array) of selected nodes
  3903. var t = new dojo.NodeList();
  3904. var e = dojo.dnd._empty;
  3905. for(var i in this.selection){
  3906. if(i in e){ continue; }
  3907. t.push(dojo.byId(i));
  3908. }
  3909. return t; // NodeList
  3910. },
  3911. selectNone: function(){
  3912. // summary:
  3913. // unselects all items
  3914. return this._removeSelection()._removeAnchor(); // self
  3915. },
  3916. selectAll: function(){
  3917. // summary:
  3918. // selects all items
  3919. this.forInItems(function(data, id){
  3920. this._addItemClass(dojo.byId(id), "Selected");
  3921. this.selection[id] = 1;
  3922. }, this);
  3923. return this._removeAnchor(); // self
  3924. },
  3925. deleteSelectedNodes: function(){
  3926. // summary:
  3927. // deletes all selected items
  3928. var e = dojo.dnd._empty;
  3929. for(var i in this.selection){
  3930. if(i in e){ continue; }
  3931. var n = dojo.byId(i);
  3932. this.delItem(i);
  3933. dojo.destroy(n);
  3934. }
  3935. this.anchor = null;
  3936. this.selection = {};
  3937. return this; // self
  3938. },
  3939. forInSelectedItems: function(/*Function*/ f, /*Object?*/ o){
  3940. // summary:
  3941. // iterates over selected items;
  3942. // see `dojo.dnd.Container.forInItems()` for details
  3943. o = o || dojo.global;
  3944. var s = this.selection, e = dojo.dnd._empty;
  3945. for(var i in s){
  3946. if(i in e){ continue; }
  3947. f.call(o, this.getItem(i), i, this);
  3948. }
  3949. },
  3950. sync: function(){
  3951. // summary:
  3952. // sync up the node list with the data map
  3953. dojo.dnd.Selector.superclass.sync.call(this);
  3954. // fix the anchor
  3955. if(this.anchor){
  3956. if(!this.getItem(this.anchor.id)){
  3957. this.anchor = null;
  3958. }
  3959. }
  3960. // fix the selection
  3961. var t = [], e = dojo.dnd._empty;
  3962. for(var i in this.selection){
  3963. if(i in e){ continue; }
  3964. if(!this.getItem(i)){
  3965. t.push(i);
  3966. }
  3967. }
  3968. dojo.forEach(t, function(i){
  3969. delete this.selection[i];
  3970. }, this);
  3971. return this; // self
  3972. },
  3973. insertNodes: function(addSelected, data, before, anchor){
  3974. // summary:
  3975. // inserts new data items (see `dojo.dnd.Container.insertNodes()` method for details)
  3976. // addSelected: Boolean
  3977. // all new nodes will be added to selected items, if true, no selection change otherwise
  3978. // data: Array
  3979. // a list of data items, which should be processed by the creator function
  3980. // before: Boolean
  3981. // insert before the anchor, if true, and after the anchor otherwise
  3982. // anchor: Node
  3983. // the anchor node to be used as a point of insertion
  3984. var oldCreator = this._normalizedCreator;
  3985. this._normalizedCreator = function(item, hint){
  3986. var t = oldCreator.call(this, item, hint);
  3987. if(addSelected){
  3988. if(!this.anchor){
  3989. this.anchor = t.node;
  3990. this._removeItemClass(t.node, "Selected");
  3991. this._addItemClass(this.anchor, "Anchor");
  3992. }else if(this.anchor != t.node){
  3993. this._removeItemClass(t.node, "Anchor");
  3994. this._addItemClass(t.node, "Selected");
  3995. }
  3996. this.selection[t.node.id] = 1;
  3997. }else{
  3998. this._removeItemClass(t.node, "Selected");
  3999. this._removeItemClass(t.node, "Anchor");
  4000. }
  4001. return t;
  4002. };
  4003. dojo.dnd.Selector.superclass.insertNodes.call(this, data, before, anchor);
  4004. this._normalizedCreator = oldCreator;
  4005. return this; // self
  4006. },
  4007. destroy: function(){
  4008. // summary:
  4009. // prepares the object to be garbage-collected
  4010. dojo.dnd.Selector.superclass.destroy.call(this);
  4011. this.selection = this.anchor = null;
  4012. },
  4013. // mouse events
  4014. onMouseDown: function(e){
  4015. // summary:
  4016. // event processor for onmousedown
  4017. // e: Event
  4018. // mouse event
  4019. if(this.autoSync){ this.sync(); }
  4020. if(!this.current){ return; }
  4021. if(!this.singular && !dojo.isCopyKey(e) && !e.shiftKey && (this.current.id in this.selection)){
  4022. this.simpleSelection = true;
  4023. if(e.button === dojo.mouseButtons.LEFT){
  4024. // accept the left button and stop the event
  4025. // for IE we don't stop event when multiple buttons are pressed
  4026. dojo.stopEvent(e);
  4027. }
  4028. return;
  4029. }
  4030. if(!this.singular && e.shiftKey){
  4031. if(!dojo.isCopyKey(e)){
  4032. this._removeSelection();
  4033. }
  4034. var c = this.getAllNodes();
  4035. if(c.length){
  4036. if(!this.anchor){
  4037. this.anchor = c[0];
  4038. this._addItemClass(this.anchor, "Anchor");
  4039. }
  4040. this.selection[this.anchor.id] = 1;
  4041. if(this.anchor != this.current){
  4042. var i = 0;
  4043. for(; i < c.length; ++i){
  4044. var node = c[i];
  4045. if(node == this.anchor || node == this.current){ break; }
  4046. }
  4047. for(++i; i < c.length; ++i){
  4048. var node = c[i];
  4049. if(node == this.anchor || node == this.current){ break; }
  4050. this._addItemClass(node, "Selected");
  4051. this.selection[node.id] = 1;
  4052. }
  4053. this._addItemClass(this.current, "Selected");
  4054. this.selection[this.current.id] = 1;
  4055. }
  4056. }
  4057. }else{
  4058. if(this.singular){
  4059. if(this.anchor == this.current){
  4060. if(dojo.isCopyKey(e)){
  4061. this.selectNone();
  4062. }
  4063. }else{
  4064. this.selectNone();
  4065. this.anchor = this.current;
  4066. this._addItemClass(this.anchor, "Anchor");
  4067. this.selection[this.current.id] = 1;
  4068. }
  4069. }else{
  4070. if(dojo.isCopyKey(e)){
  4071. if(this.anchor == this.current){
  4072. delete this.selection[this.anchor.id];
  4073. this._removeAnchor();
  4074. }else{
  4075. if(this.current.id in this.selection){
  4076. this._removeItemClass(this.current, "Selected");
  4077. delete this.selection[this.current.id];
  4078. }else{
  4079. if(this.anchor){
  4080. this._removeItemClass(this.anchor, "Anchor");
  4081. this._addItemClass(this.anchor, "Selected");
  4082. }
  4083. this.anchor = this.current;
  4084. this._addItemClass(this.current, "Anchor");
  4085. this.selection[this.current.id] = 1;
  4086. }
  4087. }
  4088. }else{
  4089. if(!(this.current.id in this.selection)){
  4090. this.selectNone();
  4091. this.anchor = this.current;
  4092. this._addItemClass(this.current, "Anchor");
  4093. this.selection[this.current.id] = 1;
  4094. }
  4095. }
  4096. }
  4097. }
  4098. dojo.stopEvent(e);
  4099. },
  4100. onMouseUp: function(e){
  4101. // summary:
  4102. // event processor for onmouseup
  4103. // e: Event
  4104. // mouse event
  4105. if(!this.simpleSelection){ return; }
  4106. this.simpleSelection = false;
  4107. this.selectNone();
  4108. if(this.current){
  4109. this.anchor = this.current;
  4110. this._addItemClass(this.anchor, "Anchor");
  4111. this.selection[this.current.id] = 1;
  4112. }
  4113. },
  4114. onMouseMove: function(e){
  4115. // summary:
  4116. // event processor for onmousemove
  4117. // e: Event
  4118. // mouse event
  4119. this.simpleSelection = false;
  4120. },
  4121. // utilities
  4122. onOverEvent: function(){
  4123. // summary:
  4124. // this function is called once, when mouse is over our container
  4125. this.onmousemoveEvent = dojo.connect(this.node, "onmousemove", this, "onMouseMove");
  4126. },
  4127. onOutEvent: function(){
  4128. // summary:
  4129. // this function is called once, when mouse is out of our container
  4130. dojo.disconnect(this.onmousemoveEvent);
  4131. delete this.onmousemoveEvent;
  4132. },
  4133. _removeSelection: function(){
  4134. // summary:
  4135. // unselects all items
  4136. var e = dojo.dnd._empty;
  4137. for(var i in this.selection){
  4138. if(i in e){ continue; }
  4139. var node = dojo.byId(i);
  4140. if(node){ this._removeItemClass(node, "Selected"); }
  4141. }
  4142. this.selection = {};
  4143. return this; // self
  4144. },
  4145. _removeAnchor: function(){
  4146. if(this.anchor){
  4147. this._removeItemClass(this.anchor, "Anchor");
  4148. this.anchor = null;
  4149. }
  4150. return this; // self
  4151. }
  4152. });
  4153. return dojo.dnd.Selector;
  4154. });
  4155. },
  4156. 'dijit/focus':function(){
  4157. define("dijit/focus", [
  4158. "dojo/aspect",
  4159. "dojo/_base/declare", // declare
  4160. "dojo/dom", // domAttr.get dom.isDescendant
  4161. "dojo/dom-attr", // domAttr.get dom.isDescendant
  4162. "dojo/dom-construct", // connect to domConstruct.empty, domConstruct.destroy
  4163. "dojo/Evented",
  4164. "dojo/_base/lang", // lang.hitch
  4165. "dojo/on",
  4166. "dojo/ready",
  4167. "dojo/_base/sniff", // has("ie")
  4168. "dojo/Stateful",
  4169. "dojo/_base/unload", // unload.addOnWindowUnload
  4170. "dojo/_base/window", // win.body
  4171. "dojo/window", // winUtils.get
  4172. "./a11y", // a11y.isTabNavigable
  4173. "./registry", // registry.byId
  4174. "." // to set dijit.focus
  4175. ], function(aspect, declare, dom, domAttr, domConstruct, Evented, lang, on, ready, has, Stateful, unload, win, winUtils,
  4176. a11y, registry, dijit){
  4177. // module:
  4178. // dijit/focus
  4179. // summary:
  4180. // Returns a singleton that tracks the currently focused node, and which widgets are currently "active".
  4181. /*=====
  4182. dijit.focus = {
  4183. // summary:
  4184. // Tracks the currently focused node, and which widgets are currently "active".
  4185. // Access via require(["dijit/focus"], function(focus){ ... }).
  4186. //
  4187. // A widget is considered active if it or a descendant widget has focus,
  4188. // or if a non-focusable node of this widget or a descendant was recently clicked.
  4189. //
  4190. // Call focus.watch("curNode", callback) to track the current focused DOMNode,
  4191. // or focus.watch("activeStack", callback) to track the currently focused stack of widgets.
  4192. //
  4193. // Call focus.on("widget-blur", func) or focus.on("widget-focus", ...) to monitor when
  4194. // when widgets become active/inactive
  4195. //
  4196. // Finally, focus(node) will focus a node, suppressing errors if the node doesn't exist.
  4197. // curNode: DomNode
  4198. // Currently focused item on screen
  4199. curNode: null,
  4200. // activeStack: dijit._Widget[]
  4201. // List of currently active widgets (focused widget and it's ancestors)
  4202. activeStack: [],
  4203. registerIframe: function(iframe){
  4204. // summary:
  4205. // Registers listeners on the specified iframe so that any click
  4206. // or focus event on that iframe (or anything in it) is reported
  4207. // as a focus/click event on the <iframe> itself.
  4208. // description:
  4209. // Currently only used by editor.
  4210. // returns:
  4211. // Handle with remove() method to deregister.
  4212. },
  4213. registerWin: function(targetWindow, effectiveNode){
  4214. // summary:
  4215. // Registers listeners on the specified window (either the main
  4216. // window or an iframe's window) to detect when the user has clicked somewhere
  4217. // or focused somewhere.
  4218. // description:
  4219. // Users should call registerIframe() instead of this method.
  4220. // targetWindow: Window?
  4221. // If specified this is the window associated with the iframe,
  4222. // i.e. iframe.contentWindow.
  4223. // effectiveNode: DOMNode?
  4224. // If specified, report any focus events inside targetWindow as
  4225. // an event on effectiveNode, rather than on evt.target.
  4226. // returns:
  4227. // Handle with remove() method to deregister.
  4228. }
  4229. };
  4230. =====*/
  4231. var FocusManager = declare([Stateful, Evented], {
  4232. // curNode: DomNode
  4233. // Currently focused item on screen
  4234. curNode: null,
  4235. // activeStack: dijit._Widget[]
  4236. // List of currently active widgets (focused widget and it's ancestors)
  4237. activeStack: [],
  4238. constructor: function(){
  4239. // Don't leave curNode/prevNode pointing to bogus elements
  4240. var check = lang.hitch(this, function(node){
  4241. if(dom.isDescendant(this.curNode, node)){
  4242. this.set("curNode", null);
  4243. }
  4244. if(dom.isDescendant(this.prevNode, node)){
  4245. this.set("prevNode", null);
  4246. }
  4247. });
  4248. aspect.before(domConstruct, "empty", check);
  4249. aspect.before(domConstruct, "destroy", check);
  4250. },
  4251. registerIframe: function(/*DomNode*/ iframe){
  4252. // summary:
  4253. // Registers listeners on the specified iframe so that any click
  4254. // or focus event on that iframe (or anything in it) is reported
  4255. // as a focus/click event on the <iframe> itself.
  4256. // description:
  4257. // Currently only used by editor.
  4258. // returns:
  4259. // Handle with remove() method to deregister.
  4260. return this.registerWin(iframe.contentWindow, iframe);
  4261. },
  4262. registerWin: function(/*Window?*/targetWindow, /*DomNode?*/ effectiveNode){
  4263. // summary:
  4264. // Registers listeners on the specified window (either the main
  4265. // window or an iframe's window) to detect when the user has clicked somewhere
  4266. // or focused somewhere.
  4267. // description:
  4268. // Users should call registerIframe() instead of this method.
  4269. // targetWindow:
  4270. // If specified this is the window associated with the iframe,
  4271. // i.e. iframe.contentWindow.
  4272. // effectiveNode:
  4273. // If specified, report any focus events inside targetWindow as
  4274. // an event on effectiveNode, rather than on evt.target.
  4275. // returns:
  4276. // Handle with remove() method to deregister.
  4277. // TODO: make this function private in 2.0; Editor/users should call registerIframe(),
  4278. var _this = this;
  4279. var mousedownListener = function(evt){
  4280. _this._justMouseDowned = true;
  4281. setTimeout(function(){ _this._justMouseDowned = false; }, 0);
  4282. // workaround weird IE bug where the click is on an orphaned node
  4283. // (first time clicking a Select/DropDownButton inside a TooltipDialog)
  4284. if(has("ie") && evt && evt.srcElement && evt.srcElement.parentNode == null){
  4285. return;
  4286. }
  4287. _this._onTouchNode(effectiveNode || evt.target || evt.srcElement, "mouse");
  4288. };
  4289. // Listen for blur and focus events on targetWindow's document.
  4290. // IIRC, I'm using attachEvent() rather than dojo.connect() because focus/blur events don't bubble
  4291. // through dojo.connect(), and also maybe to catch the focus events early, before onfocus handlers
  4292. // fire.
  4293. // Connect to <html> (rather than document) on IE to avoid memory leaks, but document on other browsers because
  4294. // (at least for FF) the focus event doesn't fire on <html> or <body>.
  4295. var doc = has("ie") ? targetWindow.document.documentElement : targetWindow.document;
  4296. if(doc){
  4297. if(has("ie")){
  4298. targetWindow.document.body.attachEvent('onmousedown', mousedownListener);
  4299. var activateListener = function(evt){
  4300. // IE reports that nodes like <body> have gotten focus, even though they have tabIndex=-1,
  4301. // ignore those events
  4302. var tag = evt.srcElement.tagName.toLowerCase();
  4303. if(tag == "#document" || tag == "body"){ return; }
  4304. // Previous code called _onTouchNode() for any activate event on a non-focusable node. Can
  4305. // probably just ignore such an event as it will be handled by onmousedown handler above, but
  4306. // leaving the code for now.
  4307. if(a11y.isTabNavigable(evt.srcElement)){
  4308. _this._onFocusNode(effectiveNode || evt.srcElement);
  4309. }else{
  4310. _this._onTouchNode(effectiveNode || evt.srcElement);
  4311. }
  4312. };
  4313. doc.attachEvent('onactivate', activateListener);
  4314. var deactivateListener = function(evt){
  4315. _this._onBlurNode(effectiveNode || evt.srcElement);
  4316. };
  4317. doc.attachEvent('ondeactivate', deactivateListener);
  4318. return {
  4319. remove: function(){
  4320. targetWindow.document.detachEvent('onmousedown', mousedownListener);
  4321. doc.detachEvent('onactivate', activateListener);
  4322. doc.detachEvent('ondeactivate', deactivateListener);
  4323. doc = null; // prevent memory leak (apparent circular reference via closure)
  4324. }
  4325. };
  4326. }else{
  4327. doc.body.addEventListener('mousedown', mousedownListener, true);
  4328. doc.body.addEventListener('touchstart', mousedownListener, true);
  4329. var focusListener = function(evt){
  4330. _this._onFocusNode(effectiveNode || evt.target);
  4331. };
  4332. doc.addEventListener('focus', focusListener, true);
  4333. var blurListener = function(evt){
  4334. _this._onBlurNode(effectiveNode || evt.target);
  4335. };
  4336. doc.addEventListener('blur', blurListener, true);
  4337. return {
  4338. remove: function(){
  4339. doc.body.removeEventListener('mousedown', mousedownListener, true);
  4340. doc.body.removeEventListener('touchstart', mousedownListener, true);
  4341. doc.removeEventListener('focus', focusListener, true);
  4342. doc.removeEventListener('blur', blurListener, true);
  4343. doc = null; // prevent memory leak (apparent circular reference via closure)
  4344. }
  4345. };
  4346. }
  4347. }
  4348. },
  4349. _onBlurNode: function(/*DomNode*/ /*===== node =====*/){
  4350. // summary:
  4351. // Called when focus leaves a node.
  4352. // Usually ignored, _unless_ it *isn't* followed by touching another node,
  4353. // which indicates that we tabbed off the last field on the page,
  4354. // in which case every widget is marked inactive
  4355. this.set("prevNode", this.curNode);
  4356. this.set("curNode", null);
  4357. if(this._justMouseDowned){
  4358. // the mouse down caused a new widget to be marked as active; this blur event
  4359. // is coming late, so ignore it.
  4360. return;
  4361. }
  4362. // if the blur event isn't followed by a focus event then mark all widgets as inactive.
  4363. if(this._clearActiveWidgetsTimer){
  4364. clearTimeout(this._clearActiveWidgetsTimer);
  4365. }
  4366. this._clearActiveWidgetsTimer = setTimeout(lang.hitch(this, function(){
  4367. delete this._clearActiveWidgetsTimer;
  4368. this._setStack([]);
  4369. this.prevNode = null;
  4370. }), 100);
  4371. },
  4372. _onTouchNode: function(/*DomNode*/ node, /*String*/ by){
  4373. // summary:
  4374. // Callback when node is focused or mouse-downed
  4375. // node:
  4376. // The node that was touched.
  4377. // by:
  4378. // "mouse" if the focus/touch was caused by a mouse down event
  4379. // ignore the recent blurNode event
  4380. if(this._clearActiveWidgetsTimer){
  4381. clearTimeout(this._clearActiveWidgetsTimer);
  4382. delete this._clearActiveWidgetsTimer;
  4383. }
  4384. // compute stack of active widgets (ex: ComboButton --> Menu --> MenuItem)
  4385. var newStack=[];
  4386. try{
  4387. while(node){
  4388. var popupParent = domAttr.get(node, "dijitPopupParent");
  4389. if(popupParent){
  4390. node=registry.byId(popupParent).domNode;
  4391. }else if(node.tagName && node.tagName.toLowerCase() == "body"){
  4392. // is this the root of the document or just the root of an iframe?
  4393. if(node === win.body()){
  4394. // node is the root of the main document
  4395. break;
  4396. }
  4397. // otherwise, find the iframe this node refers to (can't access it via parentNode,
  4398. // need to do this trick instead). window.frameElement is supported in IE/FF/Webkit
  4399. node=winUtils.get(node.ownerDocument).frameElement;
  4400. }else{
  4401. // if this node is the root node of a widget, then add widget id to stack,
  4402. // except ignore clicks on disabled widgets (actually focusing a disabled widget still works,
  4403. // to support MenuItem)
  4404. var id = node.getAttribute && node.getAttribute("widgetId"),
  4405. widget = id && registry.byId(id);
  4406. if(widget && !(by == "mouse" && widget.get("disabled"))){
  4407. newStack.unshift(id);
  4408. }
  4409. node=node.parentNode;
  4410. }
  4411. }
  4412. }catch(e){ /* squelch */ }
  4413. this._setStack(newStack, by);
  4414. },
  4415. _onFocusNode: function(/*DomNode*/ node){
  4416. // summary:
  4417. // Callback when node is focused
  4418. if(!node){
  4419. return;
  4420. }
  4421. if(node.nodeType == 9){
  4422. // Ignore focus events on the document itself. This is here so that
  4423. // (for example) clicking the up/down arrows of a spinner
  4424. // (which don't get focus) won't cause that widget to blur. (FF issue)
  4425. return;
  4426. }
  4427. this._onTouchNode(node);
  4428. if(node == this.curNode){ return; }
  4429. this.set("curNode", node);
  4430. },
  4431. _setStack: function(/*String[]*/ newStack, /*String*/ by){
  4432. // summary:
  4433. // The stack of active widgets has changed. Send out appropriate events and records new stack.
  4434. // newStack:
  4435. // array of widget id's, starting from the top (outermost) widget
  4436. // by:
  4437. // "mouse" if the focus/touch was caused by a mouse down event
  4438. var oldStack = this.activeStack;
  4439. this.set("activeStack", newStack);
  4440. // compare old stack to new stack to see how many elements they have in common
  4441. for(var nCommon=0; nCommon<Math.min(oldStack.length, newStack.length); nCommon++){
  4442. if(oldStack[nCommon] != newStack[nCommon]){
  4443. break;
  4444. }
  4445. }
  4446. var widget;
  4447. // for all elements that have gone out of focus, set focused=false
  4448. for(var i=oldStack.length-1; i>=nCommon; i--){
  4449. widget = registry.byId(oldStack[i]);
  4450. if(widget){
  4451. widget._hasBeenBlurred = true; // TODO: used by form widgets, should be moved there
  4452. widget.set("focused", false);
  4453. if(widget._focusManager == this){
  4454. widget._onBlur(by);
  4455. }
  4456. this.emit("widget-blur", widget, by);
  4457. }
  4458. }
  4459. // for all element that have come into focus, set focused=true
  4460. for(i=nCommon; i<newStack.length; i++){
  4461. widget = registry.byId(newStack[i]);
  4462. if(widget){
  4463. widget.set("focused", true);
  4464. if(widget._focusManager == this){
  4465. widget._onFocus(by);
  4466. }
  4467. this.emit("widget-focus", widget, by);
  4468. }
  4469. }
  4470. },
  4471. focus: function(node){
  4472. // summary:
  4473. // Focus the specified node, suppressing errors if they occur
  4474. if(node){
  4475. try{ node.focus(); }catch(e){/*quiet*/}
  4476. }
  4477. }
  4478. });
  4479. var singleton = new FocusManager();
  4480. // register top window and all the iframes it contains
  4481. ready(function(){
  4482. var handle = singleton.registerWin(win.doc.parentWindow || win.doc.defaultView);
  4483. if(has("ie")){
  4484. unload.addOnWindowUnload(function(){
  4485. handle.remove();
  4486. handle = null;
  4487. })
  4488. }
  4489. });
  4490. // Setup dijit.focus as a pointer to the singleton but also (for backwards compatibility)
  4491. // as a function to set focus.
  4492. dijit.focus = function(node){
  4493. singleton.focus(node); // indirection here allows dijit/_base/focus.js to override behavior
  4494. };
  4495. for(var attr in singleton){
  4496. if(!/^_/.test(attr)){
  4497. dijit.focus[attr] = typeof singleton[attr] == "function" ? lang.hitch(singleton, attr) : singleton[attr];
  4498. }
  4499. }
  4500. singleton.watch(function(attr, oldVal, newVal){
  4501. dijit.focus[attr] = newVal;
  4502. });
  4503. return singleton;
  4504. });
  4505. },
  4506. 'dojo/i18n':function(){
  4507. define("dojo/i18n", ["./_base/kernel", "require", "./has", "./_base/array", "./_base/config", "./_base/lang", "./_base/xhr", "./json"],
  4508. function(dojo, require, has, array, config, lang, xhr, json) {
  4509. // module:
  4510. // dojo/i18n
  4511. // summary:
  4512. // This module implements the !dojo/i18n plugin and the v1.6- i18n API
  4513. // description:
  4514. // We choose to include our own plugin to leverage functionality already contained in dojo
  4515. // and thereby reduce the size of the plugin compared to various loader implementations. Also, this
  4516. // allows foreign AMD loaders to be used without their plugins.
  4517. has.add("dojo-preload-i18n-Api",
  4518. // if true, define the preload localizations machinery
  4519. 1
  4520. );
  4521. true || has.add("dojo-v1x-i18n-Api",
  4522. // if true, define the v1.x i18n functions
  4523. 1
  4524. );
  4525. var
  4526. thisModule= dojo.i18n=
  4527. // the dojo.i18n module
  4528. {},
  4529. nlsRe=
  4530. // regexp for reconstructing the master bundle name from parts of the regexp match
  4531. // nlsRe.exec("foo/bar/baz/nls/en-ca/foo") gives:
  4532. // ["foo/bar/baz/nls/en-ca/foo", "foo/bar/baz/nls/", "/", "/", "en-ca", "foo"]
  4533. // nlsRe.exec("foo/bar/baz/nls/foo") gives:
  4534. // ["foo/bar/baz/nls/foo", "foo/bar/baz/nls/", "/", "/", "foo", ""]
  4535. // so, if match[5] is blank, it means this is the top bundle definition.
  4536. // courtesy of http://requirejs.org
  4537. /(^.*(^|\/)nls)(\/|$)([^\/]*)\/?([^\/]*)/,
  4538. getAvailableLocales= function(
  4539. root,
  4540. locale,
  4541. bundlePath,
  4542. bundleName
  4543. ){
  4544. // return a vector of module ids containing all available locales with respect to the target locale
  4545. // For example, assuming:
  4546. // * the root bundle indicates specific bundles for "fr" and "fr-ca",
  4547. // * bundlePath is "myPackage/nls"
  4548. // * bundleName is "myBundle"
  4549. // Then a locale argument of "fr-ca" would return
  4550. // ["myPackage/nls/myBundle", "myPackage/nls/fr/myBundle", "myPackage/nls/fr-ca/myBundle"]
  4551. // Notice that bundles are returned least-specific to most-specific, starting with the root.
  4552. //
  4553. // If root===false indicates we're working with a pre-AMD i18n bundle that doesn't tell about the available locales;
  4554. // therefore, assume everything is available and get 404 errors that indicate a particular localization is not available
  4555. //
  4556. for(var result= [bundlePath + bundleName], localeParts= locale.split("-"), current= "", i= 0; i<localeParts.length; i++){
  4557. current+= (current ? "-" : "") + localeParts[i];
  4558. if(!root || root[current]){
  4559. result.push(bundlePath + current + "/" + bundleName);
  4560. }
  4561. }
  4562. return result;
  4563. },
  4564. cache= {},
  4565. getL10nName= dojo.getL10nName = function(moduleName, bundleName, locale){
  4566. locale = locale ? locale.toLowerCase() : dojo.locale;
  4567. moduleName = "dojo/i18n!" + moduleName.replace(/\./g, "/");
  4568. bundleName = bundleName.replace(/\./g, "/");
  4569. return (/root/i.test(locale)) ?
  4570. (moduleName + "/nls/" + bundleName) :
  4571. (moduleName + "/nls/" + locale + "/" + bundleName);
  4572. },
  4573. doLoad = function(require, bundlePathAndName, bundlePath, bundleName, locale, load){
  4574. // get the root bundle which instructs which other bundles are required to construct the localized bundle
  4575. require([bundlePathAndName], function(root){
  4576. var current= lang.clone(root.root),
  4577. availableLocales= getAvailableLocales(!root._v1x && root, locale, bundlePath, bundleName);
  4578. require(availableLocales, function(){
  4579. for (var i= 1; i<availableLocales.length; i++){
  4580. current= lang.mixin(lang.clone(current), arguments[i]);
  4581. }
  4582. // target may not have been resolve (e.g., maybe only "fr" exists when "fr-ca" was requested)
  4583. var target= bundlePathAndName + "/" + locale;
  4584. cache[target]= current;
  4585. load();
  4586. });
  4587. });
  4588. },
  4589. normalize = function(id, toAbsMid){
  4590. // id may be relative
  4591. // preload has form *preload*<path>/nls/<module>*<flattened locales> and
  4592. // therefore never looks like a relative
  4593. return /^\./.test(id) ? toAbsMid(id) : id;
  4594. },
  4595. getLocalesToLoad = function(targetLocale){
  4596. var list = config.extraLocale || [];
  4597. list = lang.isArray(list) ? list : [list];
  4598. list.push(targetLocale);
  4599. return list;
  4600. },
  4601. load = function(id, require, load){
  4602. //
  4603. // id is in one of the following formats
  4604. //
  4605. // 1. <path>/nls/<bundle>
  4606. // => load the bundle, localized to config.locale; load all bundles localized to
  4607. // config.extraLocale (if any); return the loaded bundle localized to config.locale.
  4608. //
  4609. // 2. <path>/nls/<locale>/<bundle>
  4610. // => load then return the bundle localized to <locale>
  4611. //
  4612. // 3. *preload*<path>/nls/<module>*<JSON array of available locales>
  4613. // => for config.locale and all config.extraLocale, load all bundles found
  4614. // in the best-matching bundle rollup. A value of 1 is returned, which
  4615. // is meaningless other than to say the plugin is executing the requested
  4616. // preloads
  4617. //
  4618. // In cases 1 and 2, <path> is always normalized to an absolute module id upon entry; see
  4619. // normalize. In case 3, it <path> is assumed to be absolue; this is arranged by the builder.
  4620. //
  4621. // To load a bundle means to insert the bundle into the plugin's cache and publish the bundle
  4622. // value to the loader. Given <path>, <bundle>, and a particular <locale>, the cache key
  4623. //
  4624. // <path>/nls/<bundle>/<locale>
  4625. //
  4626. // will hold the value. Similarly, then plugin will publish this value to the loader by
  4627. //
  4628. // define("<path>/nls/<bundle>/<locale>", <bundle-value>);
  4629. //
  4630. // Given this algorithm, other machinery can provide fast load paths be preplacing
  4631. // values in the plugin's cache, which is public. When a load is demanded the
  4632. // cache is inspected before starting any loading. Explicitly placing values in the plugin
  4633. // cache is an advanced/experimental feature that should not be needed; use at your own risk.
  4634. //
  4635. // For the normal AMD algorithm, the root bundle is loaded first, which instructs the
  4636. // plugin what additional localized bundles are required for a particular locale. These
  4637. // additional locales are loaded and a mix of the root and each progressively-specific
  4638. // locale is returned. For example:
  4639. //
  4640. // 1. The client demands "dojo/i18n!some/path/nls/someBundle
  4641. //
  4642. // 2. The loader demands load(some/path/nls/someBundle)
  4643. //
  4644. // 3. This plugin require's "some/path/nls/someBundle", which is the root bundle.
  4645. //
  4646. // 4. Assuming config.locale is "ab-cd-ef" and the root bundle indicates that localizations
  4647. // are available for "ab" and "ab-cd-ef" (note the missing "ab-cd", then the plugin
  4648. // requires "some/path/nls/ab/someBundle" and "some/path/nls/ab-cd-ef/someBundle"
  4649. //
  4650. // 5. Upon receiving all required bundles, the plugin constructs the value of the bundle
  4651. // ab-cd-ef as...
  4652. //
  4653. // mixin(mixin(mixin({}, require("some/path/nls/someBundle"),
  4654. // require("some/path/nls/ab/someBundle")),
  4655. // require("some/path/nls/ab-cd-ef/someBundle"));
  4656. //
  4657. // This value is inserted into the cache and published to the loader at the
  4658. // key/module-id some/path/nls/someBundle/ab-cd-ef.
  4659. //
  4660. // The special preload signature (case 3) instructs the plugin to stop servicing all normal requests
  4661. // (further preload requests will be serviced) until all ongoing preloading has completed.
  4662. //
  4663. // The preload signature instructs the plugin that a special rollup module is available that contains
  4664. // one or more flattened, localized bundles. The JSON array of available locales indicates which locales
  4665. // are available. Here is an example:
  4666. //
  4667. // *preload*some/path/nls/someModule*["root", "ab", "ab-cd-ef"]
  4668. //
  4669. // This indicates the following rollup modules are available:
  4670. //
  4671. // some/path/nls/someModule_ROOT
  4672. // some/path/nls/someModule_ab
  4673. // some/path/nls/someModule_ab-cd-ef
  4674. //
  4675. // Each of these modules is a normal AMD module that contains one or more flattened bundles in a hash.
  4676. // For example, assume someModule contained the bundles some/bundle/path/someBundle and
  4677. // some/bundle/path/someOtherBundle, then some/path/nls/someModule_ab would be expressed as folllows:
  4678. //
  4679. // define({
  4680. // some/bundle/path/someBundle:<value of someBundle, flattened with respect to locale ab>,
  4681. // some/bundle/path/someOtherBundle:<value of someOtherBundle, flattened with respect to locale ab>,
  4682. // });
  4683. //
  4684. // E.g., given this design, preloading for locale=="ab" can execute the following algorithm:
  4685. //
  4686. // require(["some/path/nls/someModule_ab"], function(rollup){
  4687. // for(var p in rollup){
  4688. // var id = p + "/ab",
  4689. // cache[id] = rollup[p];
  4690. // define(id, rollup[p]);
  4691. // }
  4692. // });
  4693. //
  4694. // Similarly, if "ab-cd" is requested, the algorithm can determine that "ab" is the best available and
  4695. // load accordingly.
  4696. //
  4697. // The builder will write such rollups for every layer if a non-empty localeList profile property is
  4698. // provided. Further, the builder will include the following cache entry in the cache associated with
  4699. // any layer.
  4700. //
  4701. // "*now":function(r){r(['dojo/i18n!*preload*<path>/nls/<module>*<JSON array of available locales>']);}
  4702. //
  4703. // The *now special cache module instructs the loader to apply the provided function to context-require
  4704. // with respect to the particular layer being defined. This causes the plugin to hold all normal service
  4705. // requests until all preloading is complete.
  4706. //
  4707. // Notice that this algorithm is rarely better than the standard AMD load algorithm. Consider the normal case
  4708. // where the target locale has a single segment and a layer depends on a single bundle:
  4709. //
  4710. // Without Preloads:
  4711. //
  4712. // 1. Layer loads root bundle.
  4713. // 2. bundle is demanded; plugin loads single localized bundle.
  4714. //
  4715. // With Preloads:
  4716. //
  4717. // 1. Layer causes preloading of target bundle.
  4718. // 2. bundle is demanded; service is delayed until preloading complete; bundle is returned.
  4719. //
  4720. // In each case a single transaction is required to load the target bundle. In cases where multiple bundles
  4721. // are required and/or the locale has multiple segments, preloads still requires a single transaction whereas
  4722. // the normal path requires an additional transaction for each additional bundle/locale-segment. However all
  4723. // of these additional transactions can be done concurrently. Owing to this analysis, the entire preloading
  4724. // algorithm can be discard during a build by setting the has feature dojo-preload-i18n-Api to false.
  4725. //
  4726. if(has("dojo-preload-i18n-Api")){
  4727. var split = id.split("*"),
  4728. preloadDemand = split[1]=="preload";
  4729. if(preloadDemand){
  4730. if(!cache[id]){
  4731. // use cache[id] to prevent multiple preloads of the same preload; this shouldn't happen, but
  4732. // who knows what over-aggressive human optimizers may attempt
  4733. cache[id] = 1;
  4734. preloadL10n(split[2], json.parse(split[3]), 1);
  4735. }
  4736. // don't stall the loader!
  4737. load(1);
  4738. }
  4739. if(preloadDemand || waitForPreloads(id, require, load)){
  4740. return;
  4741. }
  4742. }
  4743. var match= nlsRe.exec(id),
  4744. bundlePath= match[1] + "/",
  4745. bundleName= match[5] || match[4],
  4746. bundlePathAndName= bundlePath + bundleName,
  4747. localeSpecified = (match[5] && match[4]),
  4748. targetLocale= localeSpecified || dojo.locale,
  4749. loadTarget= bundlePathAndName + "/" + targetLocale,
  4750. loadList = localeSpecified ? [targetLocale] : getLocalesToLoad(targetLocale),
  4751. remaining = loadList.length,
  4752. finish = function(){
  4753. if(!--remaining){
  4754. load(lang.delegate(cache[loadTarget]));
  4755. }
  4756. };
  4757. array.forEach(loadList, function(locale){
  4758. var target = bundlePathAndName + "/" + locale;
  4759. if(has("dojo-preload-i18n-Api")){
  4760. checkForLegacyModules(target);
  4761. }
  4762. if(!cache[target]){
  4763. doLoad(require, bundlePathAndName, bundlePath, bundleName, locale, finish);
  4764. }else{
  4765. finish();
  4766. }
  4767. });
  4768. };
  4769. if(has("dojo-unit-tests")){
  4770. var unitTests = thisModule.unitTests = [];
  4771. }
  4772. if(has("dojo-preload-i18n-Api") || 1){
  4773. var normalizeLocale = thisModule.normalizeLocale= function(locale){
  4774. var result = locale ? locale.toLowerCase() : dojo.locale;
  4775. return result == "root" ? "ROOT" : result;
  4776. },
  4777. isXd = function(mid){
  4778. return (1 && 1) ?
  4779. require.isXdUrl(require.toUrl(mid + ".js")) :
  4780. true;
  4781. },
  4782. preloading = 0,
  4783. preloadWaitQueue = [],
  4784. preloadL10n = thisModule._preloadLocalizations = function(/*String*/bundlePrefix, /*Array*/localesGenerated, /*boolean*/ guaranteedAmdFormat){
  4785. // summary:
  4786. // Load available flattened resource bundles associated with a particular module for dojo.locale and all dojo.config.extraLocale (if any)
  4787. //
  4788. // descirption:
  4789. // Only called by built layer files. The entire locale hierarchy is loaded. For example,
  4790. // if locale=="ab-cd", then ROOT, "ab", and "ab-cd" are loaded. This is different than v1.6-
  4791. // in that the v1.6- would lonly load ab-cd...which was *always* flattened.
  4792. //
  4793. // If guaranteedAmdFormat is true, then the module can be loaded with require thereby circumventing the detection algorithm
  4794. // and the extra possible extra transaction.
  4795. //
  4796. function forEachLocale(locale, func){
  4797. // given locale= "ab-cd-ef", calls func on "ab-cd-ef", "ab-cd", "ab", "ROOT"; stops calling the first time func returns truthy
  4798. var parts = locale.split("-");
  4799. while(parts.length){
  4800. if(func(parts.join("-"))){
  4801. return true;
  4802. }
  4803. parts.pop();
  4804. }
  4805. return func("ROOT");
  4806. }
  4807. function preload(locale){
  4808. locale = normalizeLocale(locale);
  4809. forEachLocale(locale, function(loc){
  4810. if(array.indexOf(localesGenerated, loc)>=0){
  4811. var mid = bundlePrefix.replace(/\./g, "/")+"_"+loc;
  4812. preloading++;
  4813. (isXd(mid) || guaranteedAmdFormat ? require : syncRequire)([mid], function(rollup){
  4814. for(var p in rollup){
  4815. cache[p + "/" + loc] = rollup[p];
  4816. }
  4817. --preloading;
  4818. while(!preloading && preloadWaitQueue.length){
  4819. load.apply(null, preloadWaitQueue.shift());
  4820. }
  4821. });
  4822. return true;
  4823. }
  4824. return false;
  4825. });
  4826. }
  4827. preload();
  4828. array.forEach(dojo.config.extraLocale, preload);
  4829. },
  4830. waitForPreloads = function(id, require, load){
  4831. if(preloading){
  4832. preloadWaitQueue.push([id, require, load]);
  4833. }
  4834. return preloading;
  4835. };
  4836. }
  4837. if(1){
  4838. // this code path assumes the dojo loader and won't work with a standard AMD loader
  4839. var evalBundle=
  4840. // use the function ctor to keep the minifiers away (also come close to global scope, but this is secondary)
  4841. new Function(
  4842. "__bundle", // the bundle to evalutate
  4843. "__checkForLegacyModules", // a function that checks if __bundle defined __mid in the global space
  4844. "__mid", // the mid that __bundle is intended to define
  4845. // returns one of:
  4846. // 1 => the bundle was an AMD bundle
  4847. // a legacy bundle object that is the value of __mid
  4848. // instance of Error => could not figure out how to evaluate bundle
  4849. // used to detect when __bundle calls define
  4850. "var define = function(){define.called = 1;},"
  4851. + " require = function(){define.called = 1;};"
  4852. + "try{"
  4853. + "define.called = 0;"
  4854. + "eval(__bundle);"
  4855. + "if(define.called==1)"
  4856. // bundle called define; therefore signal it's an AMD bundle
  4857. + "return 1;"
  4858. + "if((__checkForLegacyModules = __checkForLegacyModules(__mid)))"
  4859. // bundle was probably a v1.6- built NLS flattened NLS bundle that defined __mid in the global space
  4860. + "return __checkForLegacyModules;"
  4861. + "}catch(e){}"
  4862. // evaulating the bundle was *neither* an AMD *nor* a legacy flattened bundle
  4863. // either way, re-eval *after* surrounding with parentheses
  4864. + "try{"
  4865. + "return eval('('+__bundle+')');"
  4866. + "}catch(e){"
  4867. + "return e;"
  4868. + "}"
  4869. ),
  4870. syncRequire= function(deps, callback){
  4871. var results= [];
  4872. array.forEach(deps, function(mid){
  4873. var url= require.toUrl(mid + ".js");
  4874. function load(text){
  4875. var result = evalBundle(text, checkForLegacyModules, mid);
  4876. if(result===1){
  4877. // the bundle was an AMD module; re-inject it through the normal AMD path
  4878. // we gotta do this since it could be an anonymous module and simply evaluating
  4879. // the text here won't provide the loader with the context to know what
  4880. // module is being defined()'d. With browser caching, this should be free; further
  4881. // this entire code path can be circumvented by using the AMD format to begin with
  4882. require([mid], function(bundle){
  4883. results.push(cache[url]= bundle);
  4884. });
  4885. }else{
  4886. if(result instanceof Error){
  4887. console.error("failed to evaluate i18n bundle; url=" + url, result);
  4888. result = {};
  4889. }
  4890. // nls/<locale>/<bundle-name> indicates not the root.
  4891. results.push(cache[url] = (/nls\/[^\/]+\/[^\/]+$/.test(url) ? result : {root:result, _v1x:1}));
  4892. }
  4893. }
  4894. if(cache[url]){
  4895. results.push(cache[url]);
  4896. }else{
  4897. var bundle= require.syncLoadNls(mid);
  4898. // don't need to check for legacy since syncLoadNls returns a module if the module
  4899. // (1) was already loaded, or (2) was in the cache. In case 1, if syncRequire is called
  4900. // from getLocalization --> load, then load will have called checkForLegacyModules() before
  4901. // calling syncRequire; if syncRequire is called from preloadLocalizations, then we
  4902. // don't care about checkForLegacyModules() because that will be done when a particular
  4903. // bundle is actually demanded. In case 2, checkForLegacyModules() is never relevant
  4904. // because cached modules are always v1.7+ built modules.
  4905. if(bundle){
  4906. results.push(bundle);
  4907. }else{
  4908. if(!xhr){
  4909. try{
  4910. require.getText(url, true, load);
  4911. }catch(e){
  4912. results.push(cache[url]= {});
  4913. }
  4914. }else{
  4915. xhr.get({
  4916. url:url,
  4917. sync:true,
  4918. load:load,
  4919. error:function(){
  4920. results.push(cache[url]= {});
  4921. }
  4922. });
  4923. }
  4924. }
  4925. }
  4926. });
  4927. callback && callback.apply(null, results);
  4928. },
  4929. checkForLegacyModules = function(target){
  4930. // legacy code may have already loaded [e.g] the raw bundle x/y/z at x.y.z; when true, push into the cache
  4931. for(var result, names = target.split("/"), object = dojo.global[names[0]], i = 1; object && i<names.length-1; object = object[names[i++]]){}
  4932. if(object){
  4933. result = object[names[i]];
  4934. if(!result){
  4935. // fallback for incorrect bundle build of 1.6
  4936. result = object[names[i].replace(/-/g,"_")];
  4937. }
  4938. if(result){
  4939. cache[target] = result;
  4940. }
  4941. }
  4942. return result;
  4943. };
  4944. thisModule.getLocalization= function(moduleName, bundleName, locale){
  4945. var result,
  4946. l10nName= getL10nName(moduleName, bundleName, locale).substring(10);
  4947. load(l10nName, (!isXd(l10nName) ? syncRequire : require), function(result_){ result= result_; });
  4948. return result;
  4949. };
  4950. if(has("dojo-unit-tests")){
  4951. unitTests.push(function(doh){
  4952. doh.register("tests.i18n.unit", function(t){
  4953. var check;
  4954. check = evalBundle("{prop:1}");
  4955. t.is({prop:1}, check); t.is(undefined, check[1]);
  4956. check = evalBundle("({prop:1})");
  4957. t.is({prop:1}, check); t.is(undefined, check[1]);
  4958. check = evalBundle("{'prop-x':1}");
  4959. t.is({'prop-x':1}, check); t.is(undefined, check[1]);
  4960. check = evalBundle("({'prop-x':1})");
  4961. t.is({'prop-x':1}, check); t.is(undefined, check[1]);
  4962. check = evalBundle("define({'prop-x':1})");
  4963. t.is(1, check);
  4964. check = evalBundle("this is total nonsense and should throw an error");
  4965. t.is(check instanceof Error, true);
  4966. });
  4967. });
  4968. }
  4969. }
  4970. return lang.mixin(thisModule, {
  4971. dynamic:true,
  4972. normalize:normalize,
  4973. load:load,
  4974. cache:cache
  4975. });
  4976. });
  4977. },
  4978. 'dijit/hccss':function(){
  4979. define("dijit/hccss", [
  4980. "require", // require.toUrl
  4981. "dojo/_base/config", // config.blankGif
  4982. "dojo/dom-class", // domClass.add domConstruct.create domStyle.getComputedStyle
  4983. "dojo/dom-construct", // domClass.add domConstruct.create domStyle.getComputedStyle
  4984. "dojo/dom-style", // domClass.add domConstruct.create domStyle.getComputedStyle
  4985. "dojo/ready", // ready
  4986. "dojo/_base/sniff", // has("ie") has("mozilla")
  4987. "dojo/_base/window" // win.body
  4988. ], function(require, config, domClass, domConstruct, domStyle, ready, has, win){
  4989. // module:
  4990. // dijit/hccss
  4991. // summary:
  4992. // Test if computer is in high contrast mode, and sets dijit_a11y flag on <body> if it is.
  4993. if(has("ie") || has("mozilla")){ // NOTE: checking in Safari messes things up
  4994. // priority is 90 to run ahead of parser priority of 100
  4995. ready(90, function(){
  4996. // summary:
  4997. // Detects if we are in high-contrast mode or not
  4998. // create div for testing if high contrast mode is on or images are turned off
  4999. var div = domConstruct.create("div",{
  5000. id: "a11yTestNode",
  5001. style:{
  5002. cssText:'border: 1px solid;'
  5003. + 'border-color:red green;'
  5004. + 'position: absolute;'
  5005. + 'height: 5px;'
  5006. + 'top: -999px;'
  5007. + 'background-image: url("' + (config.blankGif || require.toUrl("dojo/resources/blank.gif")) + '");'
  5008. }
  5009. }, win.body());
  5010. // test it
  5011. var cs = domStyle.getComputedStyle(div);
  5012. if(cs){
  5013. var bkImg = cs.backgroundImage;
  5014. var needsA11y = (cs.borderTopColor == cs.borderRightColor) || (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" ));
  5015. if(needsA11y){
  5016. domClass.add(win.body(), "dijit_a11y");
  5017. }
  5018. if(has("ie")){
  5019. div.outerHTML = ""; // prevent mixed-content warning, see http://support.microsoft.com/kb/925014
  5020. }else{
  5021. win.body().removeChild(div);
  5022. }
  5023. }
  5024. });
  5025. }
  5026. });
  5027. },
  5028. 'dojox/html/metrics':function(){
  5029. define("dojox/html/metrics", ["dojo/_base/kernel","dojo/_base/lang", "dojo/_base/sniff", "dojo/ready", "dojo/_base/unload",
  5030. "dojo/_base/window", "dojo/dom-geometry"],
  5031. function(kernel,lang,has,ready,UnloadUtil,Window,DOMGeom){
  5032. var dhm = lang.getObject("dojox.html.metrics",true);
  5033. var dojox = lang.getObject("dojox");
  5034. // derived from Morris John's emResized measurer
  5035. dhm.getFontMeasurements = function(){
  5036. // summary
  5037. // Returns an object that has pixel equivilents of standard font size values.
  5038. var heights = {
  5039. '1em':0, '1ex':0, '100%':0, '12pt':0, '16px':0, 'xx-small':0, 'x-small':0,
  5040. 'small':0, 'medium':0, 'large':0, 'x-large':0, 'xx-large':0
  5041. };
  5042. if(has("ie")){
  5043. // we do a font-size fix if and only if one isn't applied already.
  5044. // NOTE: If someone set the fontSize on the HTML Element, this will kill it.
  5045. Window.doc.documentElement.style.fontSize="100%";
  5046. }
  5047. // set up the measuring node.
  5048. var div=Window.doc.createElement("div");
  5049. var ds = div.style;
  5050. ds.position="absolute";
  5051. ds.left="-100px";
  5052. ds.top="0";
  5053. ds.width="30px";
  5054. ds.height="1000em";
  5055. ds.borderWidth="0";
  5056. ds.margin="0";
  5057. ds.padding="0";
  5058. ds.outline="0";
  5059. ds.lineHeight="1";
  5060. ds.overflow="hidden";
  5061. Window.body().appendChild(div);
  5062. // do the measurements.
  5063. for(var p in heights){
  5064. ds.fontSize = p;
  5065. heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000;
  5066. }
  5067. Window.body().removeChild(div);
  5068. div = null;
  5069. return heights; // object
  5070. };
  5071. var fontMeasurements = null;
  5072. dhm.getCachedFontMeasurements = function(recalculate){
  5073. if(recalculate || !fontMeasurements){
  5074. fontMeasurements = dhm.getFontMeasurements();
  5075. }
  5076. return fontMeasurements;
  5077. };
  5078. var measuringNode = null, empty = {};
  5079. dhm.getTextBox = function(/* String */ text, /* Object */ style, /* String? */ className){
  5080. var m, s;
  5081. if(!measuringNode){
  5082. m = measuringNode = Window.doc.createElement("div");
  5083. // Container that we can set contraints on so that it doesn't
  5084. // trigger a scrollbar.
  5085. var c = Window.doc.createElement("div");
  5086. c.appendChild(m);
  5087. s = c.style;
  5088. s.overflow='scroll';
  5089. s.position = "absolute";
  5090. s.left = "0px";
  5091. s.top = "-10000px";
  5092. s.width = "1px";
  5093. s.height = "1px";
  5094. s.visibility = "hidden";
  5095. s.borderWidth = "0";
  5096. s.margin = "0";
  5097. s.padding = "0";
  5098. s.outline = "0";
  5099. Window.body().appendChild(c);
  5100. }else{
  5101. m = measuringNode;
  5102. }
  5103. // reset styles
  5104. m.className = "";
  5105. s = m.style;
  5106. s.borderWidth = "0";
  5107. s.margin = "0";
  5108. s.padding = "0";
  5109. s.outline = "0";
  5110. // set new style
  5111. if(arguments.length > 1 && style){
  5112. for(var i in style){
  5113. if(i in empty){ continue; }
  5114. s[i] = style[i];
  5115. }
  5116. }
  5117. // set classes
  5118. if(arguments.length > 2 && className){
  5119. m.className = className;
  5120. }
  5121. // take a measure
  5122. m.innerHTML = text;
  5123. var box = DOMGeom.position(m);
  5124. // position doesn't report right (reports 1, since parent is 1)
  5125. // So we have to look at the scrollWidth to get the real width
  5126. // Height is right.
  5127. box.w = m.parentNode.scrollWidth;
  5128. return box;
  5129. };
  5130. // determine the scrollbar sizes on load.
  5131. var scroll={ w:16, h:16 };
  5132. dhm.getScrollbar=function(){ return { w:scroll.w, h:scroll.h }; };
  5133. dhm._fontResizeNode = null;
  5134. dhm.initOnFontResize = function(interval){
  5135. var f = dhm._fontResizeNode = Window.doc.createElement("iframe");
  5136. var fs = f.style;
  5137. fs.position = "absolute";
  5138. fs.width = "5em";
  5139. fs.height = "10em";
  5140. fs.top = "-10000px";
  5141. if(has("ie")){
  5142. f.onreadystatechange = function(){
  5143. if(f.contentWindow.document.readyState == "complete"){
  5144. f.onresize = f.contentWindow.parent[dojox._scopeName].html.metrics._fontresize;
  5145. }
  5146. };
  5147. }else{
  5148. f.onload = function(){
  5149. f.contentWindow.onresize = f.contentWindow.parent[dojox._scopeName].html.metrics._fontresize;
  5150. };
  5151. }
  5152. //The script tag is to work around a known firebug race condition. See comments in bug #9046
  5153. f.setAttribute("src", "javascript:'<html><head><script>if(\"loadFirebugConsole\" in window){window.loadFirebugConsole();}</script></head><body></body></html>'");
  5154. Window.body().appendChild(f);
  5155. dhm.initOnFontResize = function(){};
  5156. };
  5157. dhm.onFontResize = function(){};
  5158. dhm._fontresize = function(){
  5159. dhm.onFontResize();
  5160. }
  5161. UnloadUtil.addOnUnload(function(){
  5162. // destroy our font resize iframe if we have one
  5163. var f = dhm._fontResizeNode;
  5164. if(f){
  5165. if(has("ie") && f.onresize){
  5166. f.onresize = null;
  5167. }else if(f.contentWindow && f.contentWindow.onresize){
  5168. f.contentWindow.onresize = null;
  5169. }
  5170. dhm._fontResizeNode = null;
  5171. }
  5172. });
  5173. ready(function(){
  5174. // getScrollbar metrics node
  5175. try{
  5176. var n=Window.doc.createElement("div");
  5177. n.style.cssText = "top:0;left:0;width:100px;height:100px;overflow:scroll;position:absolute;visibility:hidden;";
  5178. Window.body().appendChild(n);
  5179. scroll.w = n.offsetWidth - n.clientWidth;
  5180. scroll.h = n.offsetHeight - n.clientHeight;
  5181. Window.body().removeChild(n);
  5182. //console.log("Scroll bar dimensions: ", scroll);
  5183. delete n;
  5184. }catch(e){}
  5185. // text size poll setup
  5186. if("fontSizeWatch" in kernel.config && !!kernel.config.fontSizeWatch){
  5187. dhm.initOnFontResize();
  5188. }
  5189. });
  5190. return dhm;
  5191. });
  5192. },
  5193. 'dijit/TitlePane':function(){
  5194. require({cache:{
  5195. 'url:dijit/templates/TitlePane.html':"<div>\r\n\t<div data-dojo-attach-event=\"onclick:_onTitleClick, onkeypress:_onTitleKey\"\r\n\t\t\tclass=\"dijitTitlePaneTitle\" data-dojo-attach-point=\"titleBarNode\">\r\n\t\t<div class=\"dijitTitlePaneTitleFocus\" data-dojo-attach-point=\"focusNode\">\r\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" data-dojo-attach-point=\"arrowNode\" class=\"dijitArrowNode\" role=\"presentation\"\r\n\t\t\t/><span data-dojo-attach-point=\"arrowNodeInner\" class=\"dijitArrowNodeInner\"></span\r\n\t\t\t><span data-dojo-attach-point=\"titleNode\" class=\"dijitTitlePaneTextNode\"></span>\r\n\t\t</div>\r\n\t</div>\r\n\t<div class=\"dijitTitlePaneContentOuter\" data-dojo-attach-point=\"hideNode\" role=\"presentation\">\r\n\t\t<div class=\"dijitReset\" data-dojo-attach-point=\"wipeNode\" role=\"presentation\">\r\n\t\t\t<div class=\"dijitTitlePaneContentInner\" data-dojo-attach-point=\"containerNode\" role=\"region\" id=\"${id}_pane\">\r\n\t\t\t\t<!-- nested divs because wipeIn()/wipeOut() doesn't work right on node w/padding etc. Put padding on inner div. -->\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n</div>\r\n"}});
  5196. define("dijit/TitlePane", [
  5197. "dojo/_base/array", // array.forEach
  5198. "dojo/_base/declare", // declare
  5199. "dojo/dom", // dom.setSelectable
  5200. "dojo/dom-attr", // domAttr.set or get domAttr.remove
  5201. "dojo/dom-class", // domClass.replace
  5202. "dojo/dom-geometry", // domGeometry.setMarginBox domGeometry.getMarginBox
  5203. "dojo/_base/event", // event.stop
  5204. "dojo/fx", // fxUtils.wipeIn fxUtils.wipeOut
  5205. "dojo/_base/kernel", // kernel.deprecated
  5206. "dojo/keys", // keys.DOWN_ARROW keys.ENTER
  5207. "./_CssStateMixin",
  5208. "./_TemplatedMixin",
  5209. "./layout/ContentPane",
  5210. "dojo/text!./templates/TitlePane.html",
  5211. "./_base/manager" // defaultDuration
  5212. ], function(array, declare, dom, domAttr, domClass, domGeometry, event, fxUtils, kernel, keys,
  5213. _CssStateMixin, _TemplatedMixin, ContentPane, template, manager){
  5214. /*=====
  5215. var _Widget = dijit._Widget;
  5216. var _TemplatedMixin = dijit._TemplatedMixin;
  5217. var _CssStateMixin = dijit._CssStateMixin;
  5218. var ContentPane = dijit.layout.ContentPane;
  5219. =====*/
  5220. // module:
  5221. // dijit/TitlePane
  5222. // summary:
  5223. // A pane with a title on top, that can be expanded or collapsed.
  5224. return declare("dijit.TitlePane", [ContentPane, _TemplatedMixin, _CssStateMixin], {
  5225. // summary:
  5226. // A pane with a title on top, that can be expanded or collapsed.
  5227. //
  5228. // description:
  5229. // An accessible container with a title Heading, and a content
  5230. // section that slides open and closed. TitlePane is an extension to
  5231. // `dijit.layout.ContentPane`, providing all the useful content-control aspects from it.
  5232. //
  5233. // example:
  5234. // | // load a TitlePane from remote file:
  5235. // | var foo = new dijit.TitlePane({ href: "foobar.html", title:"Title" });
  5236. // | foo.startup();
  5237. //
  5238. // example:
  5239. // | <!-- markup href example: -->
  5240. // | <div data-dojo-type="dijit.TitlePane" data-dojo-props="href: 'foobar.html', title: 'Title'"></div>
  5241. //
  5242. // example:
  5243. // | <!-- markup with inline data -->
  5244. // | <div data-dojo-type="dijit.TitlePane" title="Title">
  5245. // | <p>I am content</p>
  5246. // | </div>
  5247. // title: String
  5248. // Title of the pane
  5249. title: "",
  5250. _setTitleAttr: { node: "titleNode", type: "innerHTML" }, // override default where title becomes a hover tooltip
  5251. // open: Boolean
  5252. // Whether pane is opened or closed.
  5253. open: true,
  5254. // toggleable: Boolean
  5255. // Whether pane can be opened or closed by clicking the title bar.
  5256. toggleable: true,
  5257. // tabIndex: String
  5258. // Tabindex setting for the title (so users can tab to the title then
  5259. // use space/enter to open/close the title pane)
  5260. tabIndex: "0",
  5261. // duration: Integer
  5262. // Time in milliseconds to fade in/fade out
  5263. duration: manager.defaultDuration,
  5264. // baseClass: [protected] String
  5265. // The root className to be placed on this widget's domNode.
  5266. baseClass: "dijitTitlePane",
  5267. templateString: template,
  5268. // doLayout: [protected] Boolean
  5269. // Don't change this parameter from the default value.
  5270. // This ContentPane parameter doesn't make sense for TitlePane, since TitlePane
  5271. // is never a child of a layout container, nor should TitlePane try to control
  5272. // the size of an inner widget.
  5273. doLayout: false,
  5274. // Tooltip is defined in _WidgetBase but we need to handle the mapping to DOM here
  5275. _setTooltipAttr: {node: "focusNode", type: "attribute", attribute: "title"}, // focusNode spans the entire width, titleNode doesn't
  5276. buildRendering: function(){
  5277. this.inherited(arguments);
  5278. dom.setSelectable(this.titleNode, false);
  5279. },
  5280. postCreate: function(){
  5281. this.inherited(arguments);
  5282. // Hover and focus effect on title bar, except for non-toggleable TitlePanes
  5283. // This should really be controlled from _setToggleableAttr() but _CssStateMixin
  5284. // doesn't provide a way to disconnect a previous _trackMouseState() call
  5285. if(this.toggleable){
  5286. this._trackMouseState(this.titleBarNode, "dijitTitlePaneTitle");
  5287. }
  5288. // setup open/close animations
  5289. var hideNode = this.hideNode, wipeNode = this.wipeNode;
  5290. this._wipeIn = fxUtils.wipeIn({
  5291. node: wipeNode,
  5292. duration: this.duration,
  5293. beforeBegin: function(){
  5294. hideNode.style.display="";
  5295. }
  5296. });
  5297. this._wipeOut = fxUtils.wipeOut({
  5298. node: wipeNode,
  5299. duration: this.duration,
  5300. onEnd: function(){
  5301. hideNode.style.display="none";
  5302. }
  5303. });
  5304. },
  5305. _setOpenAttr: function(/*Boolean*/ open, /*Boolean*/ animate){
  5306. // summary:
  5307. // Hook to make set("open", boolean) control the open/closed state of the pane.
  5308. // open: Boolean
  5309. // True if you want to open the pane, false if you want to close it.
  5310. array.forEach([this._wipeIn, this._wipeOut], function(animation){
  5311. if(animation && animation.status() == "playing"){
  5312. animation.stop();
  5313. }
  5314. });
  5315. if(animate){
  5316. var anim = this[open ? "_wipeIn" : "_wipeOut"];
  5317. anim.play();
  5318. }else{
  5319. this.hideNode.style.display = this.wipeNode.style.display = open ? "" : "none";
  5320. }
  5321. // load content (if this is the first time we are opening the TitlePane
  5322. // and content is specified as an href, or href was set when hidden)
  5323. if(this._started){
  5324. if(open){
  5325. this._onShow();
  5326. }else{
  5327. this.onHide();
  5328. }
  5329. }
  5330. this.arrowNodeInner.innerHTML = open ? "-" : "+";
  5331. this.containerNode.setAttribute("aria-hidden", open ? "false" : "true");
  5332. this.focusNode.setAttribute("aria-pressed", open ? "true" : "false");
  5333. this._set("open", open);
  5334. this._setCss();
  5335. },
  5336. _setToggleableAttr: function(/*Boolean*/ canToggle){
  5337. // summary:
  5338. // Hook to make set("toggleable", boolean) work.
  5339. // canToggle: Boolean
  5340. // True to allow user to open/close pane by clicking title bar.
  5341. this.focusNode.setAttribute("role", canToggle ? "button" : "heading");
  5342. if(canToggle){
  5343. // TODO: if canToggle is switched from true to false shouldn't we remove this setting?
  5344. this.focusNode.setAttribute("aria-controls", this.id+"_pane");
  5345. domAttr.set(this.focusNode, "tabIndex", this.tabIndex);
  5346. }else{
  5347. domAttr.remove(this.focusNode, "tabIndex");
  5348. }
  5349. this._set("toggleable", canToggle);
  5350. this._setCss();
  5351. },
  5352. _setContentAttr: function(/*String|DomNode|Nodelist*/ content){
  5353. // summary:
  5354. // Hook to make set("content", ...) work.
  5355. // Typically called when an href is loaded. Our job is to make the animation smooth.
  5356. if(!this.open || !this._wipeOut || this._wipeOut.status() == "playing"){
  5357. // we are currently *closing* the pane (or the pane is closed), so just let that continue
  5358. this.inherited(arguments);
  5359. }else{
  5360. if(this._wipeIn && this._wipeIn.status() == "playing"){
  5361. this._wipeIn.stop();
  5362. }
  5363. // freeze container at current height so that adding new content doesn't make it jump
  5364. domGeometry.setMarginBox(this.wipeNode, { h: domGeometry.getMarginBox(this.wipeNode).h });
  5365. // add the new content (erasing the old content, if any)
  5366. this.inherited(arguments);
  5367. // call _wipeIn.play() to animate from current height to new height
  5368. if(this._wipeIn){
  5369. this._wipeIn.play();
  5370. }else{
  5371. this.hideNode.style.display = "";
  5372. }
  5373. }
  5374. },
  5375. toggle: function(){
  5376. // summary:
  5377. // Switches between opened and closed state
  5378. // tags:
  5379. // private
  5380. this._setOpenAttr(!this.open, true);
  5381. },
  5382. _setCss: function(){
  5383. // summary:
  5384. // Set the open/close css state for the TitlePane
  5385. // tags:
  5386. // private
  5387. var node = this.titleBarNode || this.focusNode;
  5388. var oldCls = this._titleBarClass;
  5389. this._titleBarClass = "dijit" + (this.toggleable ? "" : "Fixed") + (this.open ? "Open" : "Closed");
  5390. domClass.replace(node, this._titleBarClass, oldCls || "");
  5391. this.arrowNodeInner.innerHTML = this.open ? "-" : "+";
  5392. },
  5393. _onTitleKey: function(/*Event*/ e){
  5394. // summary:
  5395. // Handler for when user hits a key
  5396. // tags:
  5397. // private
  5398. if(e.charOrCode == keys.ENTER || e.charOrCode == ' '){
  5399. if(this.toggleable){
  5400. this.toggle();
  5401. }
  5402. event.stop(e);
  5403. }else if(e.charOrCode == keys.DOWN_ARROW && this.open){
  5404. this.containerNode.focus();
  5405. e.preventDefault();
  5406. }
  5407. },
  5408. _onTitleClick: function(){
  5409. // summary:
  5410. // Handler when user clicks the title bar
  5411. // tags:
  5412. // private
  5413. if(this.toggleable){
  5414. this.toggle();
  5415. }
  5416. },
  5417. setTitle: function(/*String*/ title){
  5418. // summary:
  5419. // Deprecated. Use set('title', ...) instead.
  5420. // tags:
  5421. // deprecated
  5422. kernel.deprecated("dijit.TitlePane.setTitle() is deprecated. Use set('title', ...) instead.", "", "2.0");
  5423. this.set("title", title);
  5424. }
  5425. });
  5426. });
  5427. },
  5428. 'dijit/form/_ComboBoxMenuMixin':function(){
  5429. define("dijit/form/_ComboBoxMenuMixin", [
  5430. "dojo/_base/array", // array.forEach
  5431. "dojo/_base/declare", // declare
  5432. "dojo/dom-attr", // domAttr.set
  5433. "dojo/i18n", // i18n.getLocalization
  5434. "dojo/_base/window", // win.doc.createTextNode
  5435. "dojo/i18n!./nls/ComboBox"
  5436. ], function(array, declare, domAttr, i18n, win){
  5437. // module:
  5438. // dijit/form/_ComboBoxMenuMixin
  5439. // summary:
  5440. // Focus-less menu for internal use in `dijit.form.ComboBox`
  5441. return declare( "dijit.form._ComboBoxMenuMixin", null, {
  5442. // summary:
  5443. // Focus-less menu for internal use in `dijit.form.ComboBox`
  5444. // tags:
  5445. // private
  5446. // _messages: Object
  5447. // Holds "next" and "previous" text for paging buttons on drop down
  5448. _messages: null,
  5449. postMixInProperties: function(){
  5450. this.inherited(arguments);
  5451. this._messages = i18n.getLocalization("dijit.form", "ComboBox", this.lang);
  5452. },
  5453. buildRendering: function(){
  5454. this.inherited(arguments);
  5455. // fill in template with i18n messages
  5456. this.previousButton.innerHTML = this._messages["previousMessage"];
  5457. this.nextButton.innerHTML = this._messages["nextMessage"];
  5458. },
  5459. _setValueAttr: function(/*Object*/ value){
  5460. this.value = value;
  5461. this.onChange(value);
  5462. },
  5463. onClick: function(/*DomNode*/ node){
  5464. if(node == this.previousButton){
  5465. this._setSelectedAttr(null);
  5466. this.onPage(-1);
  5467. }else if(node == this.nextButton){
  5468. this._setSelectedAttr(null);
  5469. this.onPage(1);
  5470. }else{
  5471. this.onChange(node);
  5472. }
  5473. },
  5474. // stubs
  5475. onChange: function(/*Number*/ /*===== direction =====*/){
  5476. // summary:
  5477. // Notifies ComboBox/FilteringSelect that user selected an option.
  5478. // tags:
  5479. // callback
  5480. },
  5481. onPage: function(/*Number*/ /*===== direction =====*/){
  5482. // summary:
  5483. // Notifies ComboBox/FilteringSelect that user clicked to advance to next/previous page.
  5484. // tags:
  5485. // callback
  5486. },
  5487. onClose: function(){
  5488. // summary:
  5489. // Callback from dijit.popup code to this widget, notifying it that it closed
  5490. // tags:
  5491. // private
  5492. this._setSelectedAttr(null);
  5493. },
  5494. _createOption: function(/*Object*/ item, labelFunc){
  5495. // summary:
  5496. // Creates an option to appear on the popup menu subclassed by
  5497. // `dijit.form.FilteringSelect`.
  5498. var menuitem = this._createMenuItem();
  5499. var labelObject = labelFunc(item);
  5500. if(labelObject.html){
  5501. menuitem.innerHTML = labelObject.label;
  5502. }else{
  5503. menuitem.appendChild(
  5504. win.doc.createTextNode(labelObject.label)
  5505. );
  5506. }
  5507. // #3250: in blank options, assign a normal height
  5508. if(menuitem.innerHTML == ""){
  5509. menuitem.innerHTML = "&#160;"; // &nbsp;
  5510. }
  5511. // update menuitem.dir if BidiSupport was required
  5512. this.applyTextDir(menuitem, (menuitem.innerText || menuitem.textContent || ""));
  5513. menuitem.item=item;
  5514. return menuitem;
  5515. },
  5516. createOptions: function(results, options, labelFunc){
  5517. // summary:
  5518. // Fills in the items in the drop down list
  5519. // results:
  5520. // Array of items
  5521. // options:
  5522. // The options to the query function of the store
  5523. //
  5524. // labelFunc:
  5525. // Function to produce a label in the drop down list from a dojo.data item
  5526. this.items = results;
  5527. // display "Previous . . ." button
  5528. this.previousButton.style.display = (options.start == 0) ? "none" : "";
  5529. domAttr.set(this.previousButton, "id", this.id + "_prev");
  5530. // create options using _createOption function defined by parent
  5531. // ComboBox (or FilteringSelect) class
  5532. // #2309:
  5533. // iterate over cache nondestructively
  5534. array.forEach(results, function(item, i){
  5535. var menuitem = this._createOption(item, labelFunc);
  5536. menuitem.setAttribute("item", i); // index to this.items; use indirection to avoid mem leak
  5537. domAttr.set(menuitem, "id", this.id + i);
  5538. this.nextButton.parentNode.insertBefore(menuitem, this.nextButton);
  5539. }, this);
  5540. // display "Next . . ." button
  5541. var displayMore = false;
  5542. // Try to determine if we should show 'more'...
  5543. if(results.total && !results.total.then && results.total != -1){
  5544. if((options.start + options.count) < results.total){
  5545. displayMore = true;
  5546. }else if((options.start + options.count) > results.total && options.count == results.length){
  5547. // Weird return from a data store, where a start + count > maxOptions
  5548. // implies maxOptions isn't really valid and we have to go into faking it.
  5549. // And more or less assume more if count == results.length
  5550. displayMore = true;
  5551. }
  5552. }else if(options.count == results.length){
  5553. //Don't know the size, so we do the best we can based off count alone.
  5554. //So, if we have an exact match to count, assume more.
  5555. displayMore = true;
  5556. }
  5557. this.nextButton.style.display = displayMore ? "" : "none";
  5558. domAttr.set(this.nextButton,"id", this.id + "_next");
  5559. },
  5560. clearResultList: function(){
  5561. // summary:
  5562. // Clears the entries in the drop down list, but of course keeps the previous and next buttons.
  5563. var container = this.containerNode;
  5564. while(container.childNodes.length > 2){
  5565. container.removeChild(container.childNodes[container.childNodes.length-2]);
  5566. }
  5567. this._setSelectedAttr(null);
  5568. },
  5569. highlightFirstOption: function(){
  5570. // summary:
  5571. // Highlight the first real item in the list (not Previous Choices).
  5572. this.selectFirstNode();
  5573. },
  5574. highlightLastOption: function(){
  5575. // summary:
  5576. // Highlight the last real item in the list (not More Choices).
  5577. this.selectLastNode();
  5578. },
  5579. selectFirstNode: function(){
  5580. this.inherited(arguments);
  5581. if(this.getHighlightedOption() == this.previousButton){
  5582. this.selectNextNode();
  5583. }
  5584. },
  5585. selectLastNode: function(){
  5586. this.inherited(arguments);
  5587. if(this.getHighlightedOption() == this.nextButton){
  5588. this.selectPreviousNode();
  5589. }
  5590. },
  5591. getHighlightedOption: function(){
  5592. return this._getSelectedAttr();
  5593. }
  5594. });
  5595. });
  5596. },
  5597. 'dojox/grid/_RowSelector':function(){
  5598. define("dojox/grid/_RowSelector", [
  5599. "dojo/_base/declare",
  5600. "./_View"
  5601. ], function(declare, _View){
  5602. return declare('dojox.grid._RowSelector', _View, {
  5603. // summary:
  5604. // Custom grid view. If used in a grid structure, provides a small selectable region for grid rows.
  5605. defaultWidth: "2em",
  5606. noscroll: true,
  5607. padBorderWidth: 2,
  5608. buildRendering: function(){
  5609. this.inherited('buildRendering', arguments);
  5610. this.scrollboxNode.style.overflow = "hidden";
  5611. this.headerNode.style.visibility = "hidden";
  5612. },
  5613. getWidth: function(){
  5614. return this.viewWidth || this.defaultWidth;
  5615. },
  5616. buildRowContent: function(inRowIndex, inRowNode){
  5617. var w = this.contentWidth || 0;
  5618. inRowNode.innerHTML = '<table class="dojoxGridRowbarTable" style="width:' + w + 'px;height:1px;" border="0" cellspacing="0" cellpadding="0" role="presentation"><tr><td class="dojoxGridRowbarInner">&nbsp;</td></tr></table>';
  5619. },
  5620. renderHeader: function(){
  5621. },
  5622. updateRow: function(){
  5623. },
  5624. resize: function(){
  5625. this.adaptHeight();
  5626. },
  5627. adaptWidth: function(){
  5628. // Only calculate this here - rather than every call to buildRowContent
  5629. if(!("contentWidth" in this) && this.contentNode){
  5630. this.contentWidth = this.contentNode.offsetWidth - this.padBorderWidth;
  5631. }
  5632. },
  5633. // styling
  5634. doStyleRowNode: function(inRowIndex, inRowNode){
  5635. var n = [ "dojoxGridRowbar dojoxGridNonNormalizedCell" ];
  5636. if(this.grid.rows.isOver(inRowIndex)){
  5637. n.push("dojoxGridRowbarOver");
  5638. }
  5639. if(this.grid.selection.isSelected(inRowIndex)){
  5640. n.push("dojoxGridRowbarSelected");
  5641. }
  5642. inRowNode.className = n.join(" ");
  5643. },
  5644. // event handlers
  5645. domouseover: function(e){
  5646. this.grid.onMouseOverRow(e);
  5647. },
  5648. domouseout: function(e){
  5649. if(!this.isIntraRowEvent(e)){
  5650. this.grid.onMouseOutRow(e);
  5651. }
  5652. }
  5653. });
  5654. });
  5655. },
  5656. 'dojo/parser':function(){
  5657. define(
  5658. "dojo/parser", ["./_base/kernel", "./_base/lang", "./_base/array", "./_base/config", "./_base/html", "./_base/window", "./_base/url",
  5659. "./_base/json", "./aspect", "./date/stamp", "./has", "./query", "./on", "./ready"],
  5660. function(dojo, dlang, darray, config, dhtml, dwindow, _Url, djson, aspect, dates, has, query, don, ready){
  5661. // module:
  5662. // dojo/parser
  5663. // summary:
  5664. // The Dom/Widget parsing package
  5665. new Date("X"); // workaround for #11279, new Date("") == NaN
  5666. if (1) {
  5667. var form = document.createElement("form");
  5668. // Test if DOMNode.attributes only lists the attributes the user specified, not attributes w/default values.
  5669. has.add("dom-attributes-explicit", form.attributes.length == 0);
  5670. // IE8 will erroneously list a few attributes that weren't specified,
  5671. // but we know to skip them because they have a specified flag which is false
  5672. has.add("dom-attributes-specified-flag", form.attributes.length < 40);
  5673. // Otherwise, it's IE6-7 form.attributes will list hundreds of values, need to do outerHTML instead.
  5674. }
  5675. dojo.parser = new function(){
  5676. // summary:
  5677. // The Dom/Widget parsing package
  5678. var _nameMap = {
  5679. // Map from widget name (ex: "dijit.form.Button") to structure mapping
  5680. // lowercase version of attribute names to the version in the widget ex:
  5681. // {
  5682. // label: "label",
  5683. // onclick: "onClick"
  5684. // }
  5685. };
  5686. function getNameMap(proto){
  5687. // summary:
  5688. // Returns map from lowercase name to attribute name in class, ex: {onclick: "onClick"}
  5689. var map = {};
  5690. for(var name in proto){
  5691. if(name.charAt(0)=="_"){ continue; } // skip internal properties
  5692. map[name.toLowerCase()] = name;
  5693. }
  5694. return map;
  5695. }
  5696. // Widgets like BorderContainer add properties to _Widget via dojo.extend().
  5697. // If BorderContainer is loaded after _Widget's parameter list has been cached,
  5698. // we need to refresh that parameter list (for _Widget and all widgets that extend _Widget).
  5699. aspect.after(dlang, "extend", function(){
  5700. _nameMap = {};
  5701. }, true);
  5702. // Map from widget name (ex: "dijit.form.Button") to a map of { "list-of-mixins": ctor }
  5703. // if "list-of-mixins" is "__type" this is the raw type without mixins
  5704. var _ctorMap = {};
  5705. function getCtor(type){
  5706. var map = _ctorMap[type] || (_ctorMap[type] = {});
  5707. return map["__type"] || (map["__type"] = (dlang.getObject(type) || require(type)));
  5708. }
  5709. this._functionFromScript = function(script, attrData){
  5710. // summary:
  5711. // Convert a <script type="dojo/method" args="a, b, c"> ... </script>
  5712. // into a function
  5713. // script: DOMNode
  5714. // The <script> DOMNode
  5715. // attrData: String
  5716. // For HTML5 compliance, searches for attrData + "args" (typically
  5717. // "data-dojo-args") instead of "args"
  5718. var preamble = "";
  5719. var suffix = "";
  5720. var argsStr = (script.getAttribute(attrData + "args") || script.getAttribute("args"));
  5721. if(argsStr){
  5722. darray.forEach(argsStr.split(/\s*,\s*/), function(part, idx){
  5723. preamble += "var "+part+" = arguments["+idx+"]; ";
  5724. });
  5725. }
  5726. var withStr = script.getAttribute("with");
  5727. if(withStr && withStr.length){
  5728. darray.forEach(withStr.split(/\s*,\s*/), function(part){
  5729. preamble += "with("+part+"){";
  5730. suffix += "}";
  5731. });
  5732. }
  5733. return new Function(preamble+script.innerHTML+suffix);
  5734. };
  5735. this.instantiate = /*====== dojo.parser.instantiate= ======*/ function(nodes, mixin, options) {
  5736. // summary:
  5737. // Takes array of nodes, and turns them into class instances and
  5738. // potentially calls a startup method to allow them to connect with
  5739. // any children.
  5740. // nodes: Array
  5741. // Array of DOM nodes
  5742. // mixin: Object?
  5743. // An object that will be mixed in with each node in the array.
  5744. // Values in the mixin will override values in the node, if they
  5745. // exist.
  5746. // options: Object?
  5747. // An object used to hold kwArgs for instantiation.
  5748. // See parse.options argument for details.
  5749. mixin = mixin || {};
  5750. options = options || {};
  5751. var dojoType = (options.scope || dojo._scopeName) + "Type", // typically "dojoType"
  5752. attrData = "data-" + (options.scope || dojo._scopeName) + "-",// typically "data-dojo-"
  5753. dataDojoType = attrData + "type"; // typically "data-dojo-type"
  5754. var list = [];
  5755. darray.forEach(nodes, function(node){
  5756. var type = dojoType in mixin ? mixin[dojoType] : node.getAttribute(dataDojoType) || node.getAttribute(dojoType);
  5757. if(type){
  5758. list.push({
  5759. node: node,
  5760. "type": type
  5761. });
  5762. }
  5763. });
  5764. // Instantiate the nodes and return the objects
  5765. return this._instantiate(list, mixin, options);
  5766. };
  5767. this._instantiate = /*====== dojo.parser.instantiate= ======*/ function(nodes, mixin, options){
  5768. // summary:
  5769. // Takes array of objects representing nodes, and turns them into class instances and
  5770. // potentially calls a startup method to allow them to connect with
  5771. // any children.
  5772. // nodes: Array
  5773. // Array of objects like
  5774. // | {
  5775. // | type: "dijit.form.Button",
  5776. // | node: DOMNode,
  5777. // | scripts: [ ... ], // array of <script type="dojo/..."> children of node
  5778. // | inherited: { ... } // settings inherited from ancestors like dir, theme, etc.
  5779. // | }
  5780. // mixin: Object
  5781. // An object that will be mixed in with each node in the array.
  5782. // Values in the mixin will override values in the node, if they
  5783. // exist.
  5784. // options: Object
  5785. // An options object used to hold kwArgs for instantiation.
  5786. // See parse.options argument for details.
  5787. var thelist = [];
  5788. // Precompute names of special attributes we are looking for
  5789. // TODO: for 2.0 default to data-dojo- regardless of scopeName (or maybe scopeName won't exist in 2.0)
  5790. var dojoType = (options.scope || dojo._scopeName) + "Type", // typically "dojoType"
  5791. attrData = "data-" + (options.scope || dojo._scopeName) + "-",// typically "data-dojo-"
  5792. dataDojoType = attrData + "type", // typically "data-dojo-type"
  5793. dataDojoProps = attrData + "props", // typically "data-dojo-props"
  5794. dataDojoAttachPoint = attrData + "attach-point",
  5795. dataDojoAttachEvent = attrData + "attach-event",
  5796. dataDojoId = attrData + "id",
  5797. dataDojoMixins = attrData + "mixins";
  5798. // And make hash to quickly check if a given attribute is special, and to map the name to something friendly
  5799. var specialAttrs = {};
  5800. darray.forEach([dataDojoProps, dataDojoType, dojoType, dataDojoId, "jsId", dataDojoAttachPoint,
  5801. dataDojoAttachEvent, "dojoAttachPoint", "dojoAttachEvent", "class", "style", dataDojoMixins], function(name){
  5802. specialAttrs[name.toLowerCase()] = name.replace(options.scope, "dojo");
  5803. });
  5804. function extend(type, mixins){
  5805. return type.createSubclass && type.createSubclass(mixins) || type.extend.apply(type, mixins);
  5806. }
  5807. darray.forEach(nodes, function(obj){
  5808. if(!obj){ return; }
  5809. var node = obj.node,
  5810. type = obj.type,
  5811. mixins = node.getAttribute(dataDojoMixins), ctor;
  5812. if(mixins){
  5813. var map = _ctorMap[type];
  5814. // remove whitespaces
  5815. mixins = mixins.replace(/ /g, "");
  5816. ctor = map && map[mixins];
  5817. if(!ctor){
  5818. // first get ctor for raw type (& create _ctorMap[type] if needed (should not be))
  5819. ctor = getCtor(type);
  5820. // then do the mixin
  5821. ctor = _ctorMap[type][mixins] = extend(ctor, darray.map(mixins.split(","), getCtor));
  5822. }
  5823. }else{
  5824. ctor = getCtor(type);
  5825. }
  5826. var proto = ctor && ctor.prototype;
  5827. // Setup hash to hold parameter settings for this widget. Start with the parameter
  5828. // settings inherited from ancestors ("dir" and "lang").
  5829. // Inherited setting may later be overridden by explicit settings on node itself.
  5830. var params = {};
  5831. if(options.defaults){
  5832. // settings for the document itself (or whatever subtree is being parsed)
  5833. dlang.mixin(params, options.defaults);
  5834. }
  5835. if(obj.inherited){
  5836. // settings from dir=rtl or lang=... on a node above this node
  5837. dlang.mixin(params, obj.inherited);
  5838. }
  5839. // Get list of attributes explicitly listed in the markup
  5840. var attributes;
  5841. if(has("dom-attributes-explicit")){
  5842. // Standard path to get list of user specified attributes
  5843. attributes = node.attributes;
  5844. }else if(has("dom-attributes-specified-flag")){
  5845. // Special processing needed for IE8, to skip a few faux values in attributes[]
  5846. attributes = darray.filter(node.attributes, function(a){ return a.specified;});
  5847. }else{
  5848. // Special path for IE6-7, avoid (sometimes >100) bogus entries in node.attributes
  5849. var clone = /^input$|^img$/i.test(node.nodeName) ? node : node.cloneNode(false),
  5850. attrs = clone.outerHTML.replace(/=[^\s"']+|="[^"]*"|='[^']*'/g, "").replace(/^\s*<[a-zA-Z0-9]*\s*/, "").replace(/\s*>.*$/, "");
  5851. attributes = darray.map(attrs.split(/\s+/), function(name){
  5852. var lcName = name.toLowerCase();
  5853. return {
  5854. name: name,
  5855. // getAttribute() doesn't work for button.value, returns innerHTML of button.
  5856. // but getAttributeNode().value doesn't work for the form.encType or li.value
  5857. value: (node.nodeName == "LI" && name == "value") || lcName == "enctype" ?
  5858. node.getAttribute(lcName) : node.getAttributeNode(lcName).value
  5859. };
  5860. });
  5861. }
  5862. // Read in attributes and process them, including data-dojo-props, data-dojo-type,
  5863. // dojoAttachPoint, etc., as well as normal foo=bar attributes.
  5864. var i=0, item;
  5865. while(item = attributes[i++]){
  5866. var name = item.name,
  5867. lcName = name.toLowerCase(),
  5868. value = item.value;
  5869. if(lcName in specialAttrs){
  5870. switch(specialAttrs[lcName]){
  5871. // Data-dojo-props. Save for later to make sure it overrides direct foo=bar settings
  5872. case "data-dojo-props":
  5873. var extra = value;
  5874. break;
  5875. // data-dojo-id or jsId. TODO: drop jsId in 2.0
  5876. case "data-dojo-id":
  5877. case "jsId":
  5878. var jsname = value;
  5879. break;
  5880. // For the benefit of _Templated
  5881. case "data-dojo-attach-point":
  5882. case "dojoAttachPoint":
  5883. params.dojoAttachPoint = value;
  5884. break;
  5885. case "data-dojo-attach-event":
  5886. case "dojoAttachEvent":
  5887. params.dojoAttachEvent = value;
  5888. break;
  5889. // Special parameter handling needed for IE
  5890. case "class":
  5891. params["class"] = node.className;
  5892. break;
  5893. case "style":
  5894. params["style"] = node.style && node.style.cssText;
  5895. break;
  5896. }
  5897. }else{
  5898. // Normal attribute, ex: value="123"
  5899. // Find attribute in widget corresponding to specified name.
  5900. // May involve case conversion, ex: onclick --> onClick
  5901. if(!(name in proto)){
  5902. var map = (_nameMap[type] || (_nameMap[type] = getNameMap(proto)));
  5903. name = map[lcName] || name;
  5904. }
  5905. // Set params[name] to value, doing type conversion
  5906. if(name in proto){
  5907. switch(typeof proto[name]){
  5908. case "string":
  5909. params[name] = value;
  5910. break;
  5911. case "number":
  5912. params[name] = value.length ? Number(value) : NaN;
  5913. break;
  5914. case "boolean":
  5915. // for checked/disabled value might be "" or "checked". interpret as true.
  5916. params[name] = value.toLowerCase() != "false";
  5917. break;
  5918. case "function":
  5919. if(value === "" || value.search(/[^\w\.]+/i) != -1){
  5920. // The user has specified some text for a function like "return x+5"
  5921. params[name] = new Function(value);
  5922. }else{
  5923. // The user has specified the name of a function like "myOnClick"
  5924. // or a single word function "return"
  5925. params[name] = dlang.getObject(value, false) || new Function(value);
  5926. }
  5927. break;
  5928. default:
  5929. var pVal = proto[name];
  5930. params[name] =
  5931. (pVal && "length" in pVal) ? (value ? value.split(/\s*,\s*/) : []) : // array
  5932. (pVal instanceof Date) ?
  5933. (value == "" ? new Date("") : // the NaN of dates
  5934. value == "now" ? new Date() : // current date
  5935. dates.fromISOString(value)) :
  5936. (pVal instanceof dojo._Url) ? (dojo.baseUrl + value) :
  5937. djson.fromJson(value);
  5938. }
  5939. }else{
  5940. params[name] = value;
  5941. }
  5942. }
  5943. }
  5944. // Mix things found in data-dojo-props into the params, overriding any direct settings
  5945. if(extra){
  5946. try{
  5947. extra = djson.fromJson.call(options.propsThis, "{" + extra + "}");
  5948. dlang.mixin(params, extra);
  5949. }catch(e){
  5950. // give the user a pointer to their invalid parameters. FIXME: can we kill this in production?
  5951. throw new Error(e.toString() + " in data-dojo-props='" + extra + "'");
  5952. }
  5953. }
  5954. // Any parameters specified in "mixin" override everything else.
  5955. dlang.mixin(params, mixin);
  5956. var scripts = obj.scripts || (ctor && (ctor._noScript || proto._noScript) ? [] :
  5957. query("> script[type^='dojo/']", node));
  5958. // Process <script type="dojo/*"> script tags
  5959. // <script type="dojo/method" event="foo"> tags are added to params, and passed to
  5960. // the widget on instantiation.
  5961. // <script type="dojo/method"> tags (with no event) are executed after instantiation
  5962. // <script type="dojo/connect" data-dojo-event="foo"> tags are dojo.connected after instantiation
  5963. // <script type="dojo/watch" data-dojo-prop="foo"> tags are dojo.watch after instantiation
  5964. // <script type="dojo/on" data-dojo-event="foo"> tags are dojo.on after instantiation
  5965. // note: dojo/* script tags cannot exist in self closing widgets, like <input />
  5966. var connects = [], // functions to connect after instantiation
  5967. calls = [], // functions to call after instantiation
  5968. watch = [], //functions to watch after instantiation
  5969. on = []; //functions to on after instantiation
  5970. if(scripts){
  5971. for(i=0; i<scripts.length; i++){
  5972. var script = scripts[i];
  5973. node.removeChild(script);
  5974. // FIXME: drop event="" support in 2.0. use data-dojo-event="" instead
  5975. var event = (script.getAttribute(attrData + "event") || script.getAttribute("event")),
  5976. prop = script.getAttribute(attrData + "prop"),
  5977. scriptType = script.getAttribute("type"),
  5978. nf = this._functionFromScript(script, attrData);
  5979. if(event){
  5980. if(scriptType == "dojo/connect"){
  5981. connects.push({event: event, func: nf});
  5982. }else if(scriptType == "dojo/on"){
  5983. on.push({event: event, func: nf});
  5984. }else{
  5985. params[event] = nf;
  5986. }
  5987. }else if(scriptType == "dojo/watch"){
  5988. watch.push({prop: prop, func: nf});
  5989. }else{
  5990. calls.push(nf);
  5991. }
  5992. }
  5993. }
  5994. // create the instance
  5995. var markupFactory = ctor.markupFactory || proto.markupFactory;
  5996. var instance = markupFactory ? markupFactory(params, node, ctor) : new ctor(params, node);
  5997. thelist.push(instance);
  5998. // map it to the JS namespace if that makes sense
  5999. if(jsname){
  6000. dlang.setObject(jsname, instance);
  6001. }
  6002. // process connections and startup functions
  6003. for(i=0; i<connects.length; i++){
  6004. aspect.after(instance, connects[i].event, dojo.hitch(instance, connects[i].func), true);
  6005. }
  6006. for(i=0; i<calls.length; i++){
  6007. calls[i].call(instance);
  6008. }
  6009. for(i=0; i<watch.length; i++){
  6010. instance.watch(watch[i].prop, watch[i].func);
  6011. }
  6012. for(i=0; i<on.length; i++){
  6013. don(instance, on[i].event, on[i].func);
  6014. }
  6015. }, this);
  6016. // Call startup on each top level instance if it makes sense (as for
  6017. // widgets). Parent widgets will recursively call startup on their
  6018. // (non-top level) children
  6019. if(!mixin._started){
  6020. darray.forEach(thelist, function(instance){
  6021. if( !options.noStart && instance &&
  6022. dlang.isFunction(instance.startup) &&
  6023. !instance._started
  6024. ){
  6025. instance.startup();
  6026. }
  6027. });
  6028. }
  6029. return thelist;
  6030. };
  6031. this.scan = /*====== dojo.parser.scan= ======*/ function(root, options){
  6032. // summary:
  6033. // Scan a DOM tree and return an array of objects representing the DOMNodes
  6034. // that need to be turned into widgets.
  6035. // description:
  6036. // Search specified node (or document root node) recursively for class instances
  6037. // and return an array of objects that represent potential widgets to be
  6038. // instantiated. Searches for either data-dojo-type="MID" or dojoType="MID" where
  6039. // "MID" is a module ID like "dijit/form/Button" or a fully qualified Class name
  6040. // like "dijit.form.Button".
  6041. //
  6042. // See parser.parse() for details of markup.
  6043. // root: DomNode?
  6044. // A default starting root node from which to start the parsing. Can be
  6045. // omitted, defaulting to the entire document. If omitted, the `options`
  6046. // object can be passed in this place. If the `options` object has a
  6047. // `rootNode` member, that is used.
  6048. // options: Object
  6049. // a kwArgs options object, see parse() for details
  6050. // Output list
  6051. var list = [];
  6052. var dojoType = (options.scope || dojo._scopeName) + "Type", // typically "dojoType"
  6053. attrData = "data-" + (options.scope || dojo._scopeName) + "-", // typically "data-dojo-"
  6054. dataDojoType = attrData + "type", // typically "data-dojo-type"
  6055. dataDojoTextDir = attrData + "textdir"; // typically "data-dojo-textdir"
  6056. // Info on DOMNode currently being processed
  6057. var node = root.firstChild;
  6058. // Info on parent of DOMNode currently being processed
  6059. // - inherited: dir, lang, and textDir setting of parent, or inherited by parent
  6060. // - parent: pointer to identical structure for my parent (or null if no parent)
  6061. // - scripts: if specified, collects <script type="dojo/..."> type nodes from children
  6062. var inherited = options.inherited;
  6063. if(!inherited){
  6064. function findAncestorAttr(node, attr){
  6065. return (node.getAttribute && node.getAttribute(attr)) ||
  6066. (node !== dwindow.doc && node !== dwindow.doc.documentElement && node.parentNode ? findAncestorAttr(node.parentNode, attr) : null);
  6067. }
  6068. inherited = {
  6069. dir: findAncestorAttr(root, "dir"),
  6070. lang: findAncestorAttr(root, "lang"),
  6071. textDir: findAncestorAttr(root, dataDojoTextDir)
  6072. };
  6073. for(var key in inherited){
  6074. if(!inherited[key]){ delete inherited[key]; }
  6075. }
  6076. }
  6077. var parent = {
  6078. inherited: inherited
  6079. };
  6080. // For collecting <script type="dojo/..."> type nodes (when null, we don't need to collect)
  6081. var scripts;
  6082. // when true, only look for <script type="dojo/..."> tags, and don't recurse to children
  6083. var scriptsOnly;
  6084. function getEffective(parent){
  6085. // summary:
  6086. // Get effective dir, lang, textDir settings for specified obj
  6087. // (matching "parent" object structure above), and do caching.
  6088. // Take care not to return null entries.
  6089. if(!parent.inherited){
  6090. parent.inherited = {};
  6091. var node = parent.node,
  6092. grandparent = getEffective(parent.parent);
  6093. var inherited = {
  6094. dir: node.getAttribute("dir") || grandparent.dir,
  6095. lang: node.getAttribute("lang") || grandparent.lang,
  6096. textDir: node.getAttribute(dataDojoTextDir) || grandparent.textDir
  6097. };
  6098. for(var key in inherited){
  6099. if(inherited[key]){
  6100. parent.inherited[key] = inherited[key];
  6101. }
  6102. }
  6103. }
  6104. return parent.inherited;
  6105. }
  6106. // DFS on DOM tree, collecting nodes with data-dojo-type specified.
  6107. while(true){
  6108. if(!node){
  6109. // Finished this level, continue to parent's next sibling
  6110. if(!parent || !parent.node){
  6111. break;
  6112. }
  6113. node = parent.node.nextSibling;
  6114. scripts = parent.scripts;
  6115. scriptsOnly = false;
  6116. parent = parent.parent;
  6117. continue;
  6118. }
  6119. if(node.nodeType != 1){
  6120. // Text or comment node, skip to next sibling
  6121. node = node.nextSibling;
  6122. continue;
  6123. }
  6124. if(scripts && node.nodeName.toLowerCase() == "script"){
  6125. // Save <script type="dojo/..."> for parent, then continue to next sibling
  6126. type = node.getAttribute("type");
  6127. if(type && /^dojo\/\w/i.test(type)){
  6128. scripts.push(node);
  6129. }
  6130. node = node.nextSibling;
  6131. continue;
  6132. }
  6133. if(scriptsOnly){
  6134. node = node.nextSibling;
  6135. continue;
  6136. }
  6137. // Check for data-dojo-type attribute, fallback to backward compatible dojoType
  6138. var type = node.getAttribute(dataDojoType) || node.getAttribute(dojoType);
  6139. // Short circuit for leaf nodes containing nothing [but text]
  6140. var firstChild = node.firstChild;
  6141. if(!type && (!firstChild || (firstChild.nodeType == 3 && !firstChild.nextSibling))){
  6142. node = node.nextSibling;
  6143. continue;
  6144. }
  6145. // Setup data structure to save info on current node for when we return from processing descendant nodes
  6146. var current = {
  6147. node: node,
  6148. scripts: scripts,
  6149. parent: parent
  6150. };
  6151. // If dojoType/data-dojo-type specified, add to output array of nodes to instantiate
  6152. // Note: won't find classes declared via dojo.Declaration, so use try/catch to avoid throw from require()
  6153. // We don't care yet about mixins ctors, we check script stop only on main class
  6154. var ctor;
  6155. try{
  6156. ctor = type && getCtor(type);
  6157. }catch(e){
  6158. }
  6159. var childScripts = ctor && !ctor.prototype._noScript ? [] : null; // <script> nodes that are parent's children
  6160. if(type){
  6161. list.push({
  6162. "type": type,
  6163. node: node,
  6164. scripts: childScripts,
  6165. inherited: getEffective(current) // dir & lang settings for current node, explicit or inherited
  6166. });
  6167. }
  6168. // Recurse, collecting <script type="dojo/..."> children, and also looking for
  6169. // descendant nodes with dojoType specified (unless the widget has the stopParser flag).
  6170. // When finished with children, go to my next sibling.
  6171. node = firstChild;
  6172. scripts = childScripts;
  6173. scriptsOnly = ctor && ctor.prototype.stopParser && !(options.template);
  6174. parent = current;
  6175. }
  6176. return list;
  6177. };
  6178. this.parse = /*====== dojo.parser.parse= ======*/ function(rootNode, options){
  6179. // summary:
  6180. // Scan the DOM for class instances, and instantiate them.
  6181. //
  6182. // description:
  6183. // Search specified node (or root node) recursively for class instances,
  6184. // and instantiate them. Searches for either data-dojo-type="Class" or
  6185. // dojoType="Class" where "Class" is a a fully qualified class name,
  6186. // like `dijit.form.Button`
  6187. //
  6188. // Using `data-dojo-type`:
  6189. // Attributes using can be mixed into the parameters used to instantiate the
  6190. // Class by using a `data-dojo-props` attribute on the node being converted.
  6191. // `data-dojo-props` should be a string attribute to be converted from JSON.
  6192. //
  6193. // Using `dojoType`:
  6194. // Attributes are read from the original domNode and converted to appropriate
  6195. // types by looking up the Class prototype values. This is the default behavior
  6196. // from Dojo 1.0 to Dojo 1.5. `dojoType` support is deprecated, and will
  6197. // go away in Dojo 2.0.
  6198. //
  6199. // rootNode: DomNode?
  6200. // A default starting root node from which to start the parsing. Can be
  6201. // omitted, defaulting to the entire document. If omitted, the `options`
  6202. // object can be passed in this place. If the `options` object has a
  6203. // `rootNode` member, that is used.
  6204. //
  6205. // options: Object?
  6206. // A hash of options.
  6207. //
  6208. // * noStart: Boolean?
  6209. // when set will prevent the parser from calling .startup()
  6210. // when locating the nodes.
  6211. // * rootNode: DomNode?
  6212. // identical to the function's `rootNode` argument, though
  6213. // allowed to be passed in via this `options object.
  6214. // * template: Boolean
  6215. // If true, ignores ContentPane's stopParser flag and parses contents inside of
  6216. // a ContentPane inside of a template. This allows dojoAttachPoint on widgets/nodes
  6217. // nested inside the ContentPane to work.
  6218. // * inherited: Object
  6219. // Hash possibly containing dir and lang settings to be applied to
  6220. // parsed widgets, unless there's another setting on a sub-node that overrides
  6221. // * scope: String
  6222. // Root for attribute names to search for. If scopeName is dojo,
  6223. // will search for data-dojo-type (or dojoType). For backwards compatibility
  6224. // reasons defaults to dojo._scopeName (which is "dojo" except when
  6225. // multi-version support is used, when it will be something like dojo16, dojo20, etc.)
  6226. // * propsThis: Object
  6227. // If specified, "this" referenced from data-dojo-props will refer to propsThis.
  6228. // Intended for use from the widgets-in-template feature of `dijit._WidgetsInTemplateMixin`
  6229. //
  6230. // example:
  6231. // Parse all widgets on a page:
  6232. // | dojo.parser.parse();
  6233. //
  6234. // example:
  6235. // Parse all classes within the node with id="foo"
  6236. // | dojo.parser.parse(dojo.byId('foo'));
  6237. //
  6238. // example:
  6239. // Parse all classes in a page, but do not call .startup() on any
  6240. // child
  6241. // | dojo.parser.parse({ noStart: true })
  6242. //
  6243. // example:
  6244. // Parse all classes in a node, but do not call .startup()
  6245. // | dojo.parser.parse(someNode, { noStart:true });
  6246. // | // or
  6247. // | dojo.parser.parse({ noStart:true, rootNode: someNode });
  6248. // determine the root node and options based on the passed arguments.
  6249. var root;
  6250. if(!options && rootNode && rootNode.rootNode){
  6251. options = rootNode;
  6252. root = options.rootNode;
  6253. }else if(rootNode && dlang.isObject(rootNode) && !("nodeType" in rootNode)){
  6254. options = rootNode;
  6255. }else{
  6256. root = rootNode;
  6257. }
  6258. root = root ? dhtml.byId(root) : dwindow.body();
  6259. options = options || {};
  6260. // List of all nodes on page w/dojoType specified
  6261. var list = this.scan(root, options);
  6262. // go build the object instances
  6263. var mixin = options.template ? {template: true} : {};
  6264. return this._instantiate(list, mixin, options); // Array
  6265. };
  6266. }();
  6267. //Register the parser callback. It should be the first callback
  6268. //after the a11y test.
  6269. if(config.parseOnLoad){
  6270. ready(100, dojo.parser, "parse");
  6271. }
  6272. return dojo.parser;
  6273. });
  6274. },
  6275. 'dojox/form/Uploader':function(){
  6276. require({cache:{
  6277. 'url:dojox/form/resources/Uploader.html':"<span class=\"dijit dijitReset dijitInline\"\r\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\r\n\t\tdojoAttachEvent=\"ondijitclick:_onClick\"\r\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\r\n\t\t\tdojoAttachPoint=\"titleNode,focusNode\"\r\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\r\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\"></span\r\n\t\t\t><span class=\"dijitReset dijitToggleButtonIconChar\">&#x25CF;</span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\r\n\t\t\t\tid=\"${id}_label\"\r\n\t\t\t\tdojoAttachPoint=\"containerNode\"\r\n\t\t\t></span\r\n\t\t></span\r\n\t></span\r\n\t><!--no need to have this for Uploader \r\n\t<input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\" tabIndex=\"-1\"\r\n\t\tdojoAttachPoint=\"valueNode\"\r\n/--></span>\r\n"}});
  6278. define("dojox/form/Uploader", [
  6279. "dojo/_base/kernel",
  6280. "dojo/_base/declare",
  6281. "dojo/_base/lang",
  6282. "dojo/_base/array",
  6283. "dojo/_base/connect",
  6284. "dojo/_base/window",
  6285. "dojo/dom-style",
  6286. "dojo/dom-geometry",
  6287. "dojo/dom-attr",
  6288. "dojo/dom-construct",
  6289. "dojo/dom-form",
  6290. "dijit",
  6291. "dijit/form/Button",
  6292. "dojox/form/uploader/Base",
  6293. "dojo/i18n!./nls/Uploader",
  6294. "dojo/text!./resources/Uploader.html"
  6295. ],function(kernel, declare, lang, array, connect, win, domStyle, domGeometry, domAttr, domConstruct, domForm, dijit, Button, uploader, res, template){
  6296. kernel.experimental("dojox.form.Uploader");
  6297. //
  6298. // TODO:
  6299. // i18n
  6300. // label via innerHTML
  6301. // Doc and or test what can be extended.
  6302. // Doc custom file events
  6303. // Use new FileReader() for thumbnails
  6304. // flashFieldName should default to Flash
  6305. // get('value'); and set warning
  6306. // Make it so URL can change (current set to Flash on build)
  6307. //
  6308. /*=====
  6309. uploader = dojox.form.uploader.Base;
  6310. WidgetsInTemplateMixin = dijit._WidgetsInTemplateMixin;
  6311. =====*/
  6312. declare("dojox.form.Uploader", [uploader, Button], {
  6313. //
  6314. // Version: 1.6
  6315. //
  6316. // summary:
  6317. // A widget that creates a stylable file-input button, with optional multi-file selection,
  6318. // using only HTML elements. Non-HTML5 browsers have fallback options of Flash or an iframe.
  6319. //
  6320. // description:
  6321. // A bare-bones, stylable file-input button, with optional multi-file selection. The list
  6322. // of files is not displayed, that is for you to handle by connecting to the onChange
  6323. // event, or use the dojox.form.uploader.FileList.
  6324. //
  6325. // Uploader without plugins does not have any ability to upload - it is for use in forms
  6326. // where you handle the upload either by a standard POST or with Ajax using an iFrame. This
  6327. // class is for convenience of multiple files only. No progress events are available.
  6328. //
  6329. // If the browser supports a file-input with the "multiple" attribute, that will be used.
  6330. // If the browser does not support "multiple" (ergo, IE) multiple inputs are used,
  6331. // one for each selection.
  6332. //
  6333. //
  6334. // uploadOnSelect: Boolean
  6335. // If true, uploads imediately after a file has been selected. If false,
  6336. // waits for upload() to be called.
  6337. uploadOnSelect:false,
  6338. // tabIndex: Number|String
  6339. // The tab order in the DOM.
  6340. tabIndex:0,
  6341. // multiple: Boolean
  6342. // If true and flash mode, multiple files may be selected from the dialog.
  6343. multiple:false,
  6344. //
  6345. // label: String
  6346. // The text used in the button that when clicked, opens a system Browse Dialog.
  6347. label:res.label,
  6348. //
  6349. // url: String
  6350. // The url targeted for upload. An absolute URL is preferred. Relative URLs are
  6351. // changed to absolute.
  6352. url:"",
  6353. //
  6354. // name: String
  6355. // The name attribute needs to end with square brackets: [] as this is the standard way
  6356. // of handling an attribute "array". This requires a slightly different technique on the
  6357. // server.
  6358. name:"uploadedfile",
  6359. //
  6360. // flashFieldName: String
  6361. // If set, this will be the name of the field of the flash uploaded files that the server
  6362. // is expecting. If not set, "Flash" is appended to the "name" property.
  6363. flashFieldName:"",
  6364. //
  6365. // uploadType: String [readonly]
  6366. // The type of uploader being used. As an alternative to determining the upload type on the
  6367. // server based on the fieldName, this property could be sent to the server to help
  6368. // determine what type of parsing should be used.
  6369. uploadType:"form",
  6370. //
  6371. // showInput: String [const]
  6372. // Position to show an input which shows selected filename(s). Possible
  6373. // values are "before", "after", which specifies where the input should
  6374. // be placed with reference to the containerNode which contains the
  6375. // label). By default, this is empty string (no such input will be
  6376. // shown). Specify showInput="before" to mimic the look&feel of a
  6377. // native file input element.
  6378. showInput: "",
  6379. _nameIndex:0,
  6380. templateString: template,
  6381. baseClass: 'dijitUploader '+Button.prototype.baseClass,
  6382. postMixInProperties: function(){
  6383. this._inputs = [];
  6384. this._cons = [];
  6385. this.inherited(arguments);
  6386. },
  6387. buildRendering: function(){
  6388. console.warn("buildRendering", this.id)
  6389. this.inherited(arguments);
  6390. domStyle.set(this.domNode, {
  6391. overflow:"hidden",
  6392. position:"relative"
  6393. });
  6394. this._buildDisplay();
  6395. //change the button node not occupy tabIndex: the real file input
  6396. //will have tabIndex set
  6397. domAttr.set(this.titleNode, 'tabIndex', -1);
  6398. },
  6399. _buildDisplay: function(){
  6400. if(this.showInput){
  6401. this.displayInput = dojo.create('input', {
  6402. 'class':'dijitUploadDisplayInput',
  6403. 'tabIndex':-1, 'autocomplete':'off'},
  6404. this.containerNode, this.showInput);
  6405. //schedule the attachpoint to be cleaned up on destroy
  6406. this._attachPoints.push('displayInput');
  6407. this.connect(this,'onChange', function(files){
  6408. var i=0,l=files.length, f, r=[];
  6409. while((f=files[i++])){
  6410. if(f && f.name){
  6411. r.push(f.name);
  6412. }
  6413. }
  6414. this.displayInput.value = r.join(', ');
  6415. });
  6416. this.connect(this,'reset', function(){
  6417. this.displayInput.value = '';
  6418. });
  6419. }
  6420. },
  6421. startup: function(){
  6422. if(this._buildInitialized){
  6423. return;
  6424. }
  6425. this._buildInitialized = true;
  6426. this._getButtonStyle(this.domNode);
  6427. this._setButtonStyle();
  6428. this.inherited(arguments);
  6429. },
  6430. /*************************
  6431. * Public Events *
  6432. *************************/
  6433. onChange: function(/* Array */fileArray){
  6434. // summary:
  6435. // stub to connect
  6436. // Fires when files are selected
  6437. // Event is an array of last files selected
  6438. },
  6439. onBegin: function(/* Array */dataArray){
  6440. // summary:
  6441. // Fires when upload begins
  6442. },
  6443. onProgress: function(/* Object */customEvent){
  6444. // summary:
  6445. // Stub to connect
  6446. // Fires on upload progress. Event is a normalized object of common properties
  6447. // from HTML5 uploaders and the Flash uploader. Will not fire for IFrame.
  6448. // customEvent:
  6449. // bytesLoaded: Number
  6450. // Amount of bytes uploaded so far of entire payload (all files)
  6451. // bytesTotal: Number
  6452. // Amount of bytes of entire payload (all files)
  6453. // type: String
  6454. // Type of event (progress or load)
  6455. // timeStamp: Number
  6456. // Timestamp of when event occurred
  6457. },
  6458. onComplete: function(/* Object */customEvent){
  6459. // summary:
  6460. // stub to connect
  6461. // Fires when all files have uploaded
  6462. // Event is an array of all files
  6463. this.reset();
  6464. },
  6465. onCancel: function(){
  6466. // summary:
  6467. // Stub to connect
  6468. // Fires when dialog box has been closed
  6469. // without a file selection
  6470. },
  6471. onAbort: function(){
  6472. // summary:
  6473. // Stub to connect
  6474. // Fires when upload in progress was canceled
  6475. },
  6476. onError: function(/* Object or String */evtObject){
  6477. // summary:
  6478. // Fires on errors
  6479. //
  6480. //FIXME: Unsure of a standard form of error events
  6481. },
  6482. /*************************
  6483. * Public Methods *
  6484. *************************/
  6485. upload: function(/*Object ? */formData){
  6486. // summary:
  6487. // When called, begins file upload. Only supported with plugins.
  6488. },
  6489. submit: function(/* form Node ? */form){
  6490. // summary:
  6491. // If Uploader is in a form, and other data should be sent along with the files, use
  6492. // this instead of form submit.
  6493. form = !!form ? form.tagName ? form : this.getForm() : this.getForm();
  6494. var data = domForm.toObject(form);
  6495. this.upload(data);
  6496. },
  6497. reset: function(){
  6498. // summary
  6499. // Resets entire input, clearing all files.
  6500. // NOTE:
  6501. // Removing individual files is not yet supported, because the HTML5 uploaders can't
  6502. // be edited.
  6503. // TODO:
  6504. // Add this ability by effectively, not uploading them
  6505. //
  6506. delete this._files;
  6507. this._disconnectButton();
  6508. array.forEach(this._inputs, domConstruct.destroy, dojo);
  6509. this._inputs = [];
  6510. this._nameIndex = 0;
  6511. this._createInput();
  6512. },
  6513. getFileList: function(){
  6514. // summary:
  6515. // Returns a list of selected files.
  6516. //
  6517. var fileArray = [];
  6518. if(this.supports("multiple")){
  6519. array.forEach(this._files, function(f, i){
  6520. fileArray.push({
  6521. index:i,
  6522. name:f.name,
  6523. size:f.size,
  6524. type:f.type
  6525. });
  6526. }, this);
  6527. }else{
  6528. array.forEach(this._inputs, function(n, i){
  6529. if(n.value){
  6530. fileArray.push({
  6531. index:i,
  6532. name:n.value.substring(n.value.lastIndexOf("\\")+1),
  6533. size:0,
  6534. type:n.value.substring(n.value.lastIndexOf(".")+1)
  6535. });
  6536. }
  6537. }, this);
  6538. }
  6539. return fileArray; // Array
  6540. },
  6541. /*********************************************
  6542. * Private Property. Get off my lawn. *
  6543. *********************************************/
  6544. _getValueAttr: function(){
  6545. // summary:
  6546. // Internal. To get disabled use: uploader.get("disabled");
  6547. return this.getFileList();
  6548. },
  6549. _setValueAttr: function(disabled){
  6550. console.error("Uploader value is read only");
  6551. },
  6552. _setDisabledAttr: function(disabled){
  6553. // summary:
  6554. // Internal. To set disabled use: uploader.set("disabled", true);
  6555. if(this._disabled == disabled){ return; }
  6556. this.inherited(arguments);
  6557. domStyle.set(this.inputNode, "display", disabled ? "none" : "");
  6558. },
  6559. _getButtonStyle: function(node){
  6560. this.btnSize = {w:domStyle.get(node,'width'), h:domStyle.get(node,'height')};
  6561. },
  6562. _setButtonStyle: function(){
  6563. this.inputNodeFontSize = Math.max(2, Math.max(Math.ceil(this.btnSize.w / 60), Math.ceil(this.btnSize.h / 15)));
  6564. this._createInput();
  6565. },
  6566. _createInput: function(){
  6567. if(this._inputs.length){
  6568. domStyle.set(this.inputNode, {
  6569. top:"500px"
  6570. });
  6571. this._disconnectButton();
  6572. this._nameIndex++;
  6573. }
  6574. var name;
  6575. if(this.supports("multiple")){
  6576. // FF3.5+, WebKit
  6577. name = this.name+"s[]";
  6578. }else{
  6579. // <=IE8
  6580. name = this.name + (this.multiple ? this._nameIndex : "");
  6581. }
  6582. // reset focusNode to the inputNode, so when the button is clicked,
  6583. // the focus is properly moved to the input element
  6584. this.focusNode = this.inputNode = domConstruct.create("input", {type:"file", name:name}, this.domNode, "first");
  6585. if(this.supports("multiple") && this.multiple){
  6586. domAttr.set(this.inputNode, "multiple", true);
  6587. }
  6588. this._inputs.push(this.inputNode);
  6589. domStyle.set(this.inputNode, {
  6590. position:"absolute",
  6591. fontSize:this.inputNodeFontSize+"em",
  6592. top:"-3px",
  6593. right:"-3px",
  6594. opacity:0
  6595. });
  6596. this._connectButton();
  6597. },
  6598. _connectButton: function(){
  6599. this._cons.push(connect.connect(this.inputNode, "change", this, function(evt){
  6600. this._files = this.inputNode.files;
  6601. this.onChange(this.getFileList(evt));
  6602. if(!this.supports("multiple") && this.multiple) this._createInput();
  6603. }));
  6604. if(this.tabIndex > -1){
  6605. this.inputNode.tabIndex = this.tabIndex;
  6606. this._cons.push(connect.connect(this.inputNode, "focus", this, function(){
  6607. this.titleNode.style.outline= "1px dashed #ccc";
  6608. }));
  6609. this._cons.push(connect.connect(this.inputNode, "blur", this, function(){
  6610. this.titleNode.style.outline = "";
  6611. }));
  6612. }
  6613. },
  6614. _disconnectButton: function(){
  6615. array.forEach(this._cons, connect.disconnect);
  6616. this._cons.splice(0,this._cons.length);
  6617. }
  6618. });
  6619. dojox.form.UploaderOrg = dojox.form.Uploader;
  6620. var extensions = [dojox.form.UploaderOrg];
  6621. dojox.form.addUploaderPlugin = function(plug){
  6622. // summary:
  6623. // Handle Uploader plugins. When the dojox.form.addUploaderPlugin() function is called,
  6624. // the dojox.form.Uploader is recreated using the new plugin (mixin).
  6625. //
  6626. extensions.push(plug);
  6627. declare("dojox.form.Uploader", extensions, {});
  6628. }
  6629. return dojox.form.Uploader;
  6630. });
  6631. },
  6632. 'url:dijit/form/templates/DropDownButton.html':"<span class=\"dijit dijitReset dijitInline\"\r\n\t><span class='dijitReset dijitInline dijitButtonNode'\r\n\t\tdata-dojo-attach-event=\"ondijitclick:_onClick\" data-dojo-attach-point=\"_buttonNode\"\r\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\r\n\t\t\tdata-dojo-attach-point=\"focusNode,titleNode,_arrowWrapperNode\"\r\n\t\t\trole=\"button\" aria-haspopup=\"true\" aria-labelledby=\"${id}_label\"\r\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\"\r\n\t\t\t\tdata-dojo-attach-point=\"iconNode\"\r\n\t\t\t></span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\r\n\t\t\t\tdata-dojo-attach-point=\"containerNode,_popupStateNode\"\r\n\t\t\t\tid=\"${id}_label\"\r\n\t\t\t></span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonInner\"></span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonChar\">&#9660;</span\r\n\t\t></span\r\n\t></span\r\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\" tabIndex=\"-1\"\r\n\t\tdata-dojo-attach-point=\"valueNode\"\r\n/></span>\r\n",
  6633. 'dojo/dnd/Manager':function(){
  6634. define("dojo/dnd/Manager", ["../main", "../Evented", "./common", "./autoscroll", "./Avatar"], function(dojo, Evented) {
  6635. // module:
  6636. // dojo/dnd/Manager
  6637. // summary:
  6638. // TODOC
  6639. var Manager = dojo.declare("dojo.dnd.Manager", [Evented], {
  6640. // summary:
  6641. // the manager of DnD operations (usually a singleton)
  6642. constructor: function(){
  6643. this.avatar = null;
  6644. this.source = null;
  6645. this.nodes = [];
  6646. this.copy = true;
  6647. this.target = null;
  6648. this.canDropFlag = false;
  6649. this.events = [];
  6650. },
  6651. // avatar's offset from the mouse
  6652. OFFSET_X: 16,
  6653. OFFSET_Y: 16,
  6654. // methods
  6655. overSource: function(source){
  6656. // summary:
  6657. // called when a source detected a mouse-over condition
  6658. // source: Object
  6659. // the reporter
  6660. if(this.avatar){
  6661. this.target = (source && source.targetState != "Disabled") ? source : null;
  6662. this.canDropFlag = Boolean(this.target);
  6663. this.avatar.update();
  6664. }
  6665. dojo.publish("/dnd/source/over", [source]);
  6666. },
  6667. outSource: function(source){
  6668. // summary:
  6669. // called when a source detected a mouse-out condition
  6670. // source: Object
  6671. // the reporter
  6672. if(this.avatar){
  6673. if(this.target == source){
  6674. this.target = null;
  6675. this.canDropFlag = false;
  6676. this.avatar.update();
  6677. dojo.publish("/dnd/source/over", [null]);
  6678. }
  6679. }else{
  6680. dojo.publish("/dnd/source/over", [null]);
  6681. }
  6682. },
  6683. startDrag: function(source, nodes, copy){
  6684. // summary:
  6685. // called to initiate the DnD operation
  6686. // source: Object
  6687. // the source which provides items
  6688. // nodes: Array
  6689. // the list of transferred items
  6690. // copy: Boolean
  6691. // copy items, if true, move items otherwise
  6692. this.source = source;
  6693. this.nodes = nodes;
  6694. this.copy = Boolean(copy); // normalizing to true boolean
  6695. this.avatar = this.makeAvatar();
  6696. dojo.body().appendChild(this.avatar.node);
  6697. dojo.publish("/dnd/start", [source, nodes, this.copy]);
  6698. this.events = [
  6699. dojo.connect(dojo.doc, "onmousemove", this, "onMouseMove"),
  6700. dojo.connect(dojo.doc, "onmouseup", this, "onMouseUp"),
  6701. dojo.connect(dojo.doc, "onkeydown", this, "onKeyDown"),
  6702. dojo.connect(dojo.doc, "onkeyup", this, "onKeyUp"),
  6703. // cancel text selection and text dragging
  6704. dojo.connect(dojo.doc, "ondragstart", dojo.stopEvent),
  6705. dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent)
  6706. ];
  6707. var c = "dojoDnd" + (copy ? "Copy" : "Move");
  6708. dojo.addClass(dojo.body(), c);
  6709. },
  6710. canDrop: function(flag){
  6711. // summary:
  6712. // called to notify if the current target can accept items
  6713. var canDropFlag = Boolean(this.target && flag);
  6714. if(this.canDropFlag != canDropFlag){
  6715. this.canDropFlag = canDropFlag;
  6716. this.avatar.update();
  6717. }
  6718. },
  6719. stopDrag: function(){
  6720. // summary:
  6721. // stop the DnD in progress
  6722. dojo.removeClass(dojo.body(), ["dojoDndCopy", "dojoDndMove"]);
  6723. dojo.forEach(this.events, dojo.disconnect);
  6724. this.events = [];
  6725. this.avatar.destroy();
  6726. this.avatar = null;
  6727. this.source = this.target = null;
  6728. this.nodes = [];
  6729. },
  6730. makeAvatar: function(){
  6731. // summary:
  6732. // makes the avatar; it is separate to be overwritten dynamically, if needed
  6733. return new dojo.dnd.Avatar(this);
  6734. },
  6735. updateAvatar: function(){
  6736. // summary:
  6737. // updates the avatar; it is separate to be overwritten dynamically, if needed
  6738. this.avatar.update();
  6739. },
  6740. // mouse event processors
  6741. onMouseMove: function(e){
  6742. // summary:
  6743. // event processor for onmousemove
  6744. // e: Event
  6745. // mouse event
  6746. var a = this.avatar;
  6747. if(a){
  6748. dojo.dnd.autoScrollNodes(e);
  6749. //dojo.dnd.autoScroll(e);
  6750. var s = a.node.style;
  6751. s.left = (e.pageX + this.OFFSET_X) + "px";
  6752. s.top = (e.pageY + this.OFFSET_Y) + "px";
  6753. var copy = Boolean(this.source.copyState(dojo.isCopyKey(e)));
  6754. if(this.copy != copy){
  6755. this._setCopyStatus(copy);
  6756. }
  6757. }
  6758. },
  6759. onMouseUp: function(e){
  6760. // summary:
  6761. // event processor for onmouseup
  6762. // e: Event
  6763. // mouse event
  6764. if(this.avatar){
  6765. if(this.target && this.canDropFlag){
  6766. var copy = Boolean(this.source.copyState(dojo.isCopyKey(e))),
  6767. params = [this.source, this.nodes, copy, this.target, e];
  6768. dojo.publish("/dnd/drop/before", params);
  6769. dojo.publish("/dnd/drop", params);
  6770. }else{
  6771. dojo.publish("/dnd/cancel");
  6772. }
  6773. this.stopDrag();
  6774. }
  6775. },
  6776. // keyboard event processors
  6777. onKeyDown: function(e){
  6778. // summary:
  6779. // event processor for onkeydown:
  6780. // watching for CTRL for copy/move status, watching for ESCAPE to cancel the drag
  6781. // e: Event
  6782. // keyboard event
  6783. if(this.avatar){
  6784. switch(e.keyCode){
  6785. case dojo.keys.CTRL:
  6786. var copy = Boolean(this.source.copyState(true));
  6787. if(this.copy != copy){
  6788. this._setCopyStatus(copy);
  6789. }
  6790. break;
  6791. case dojo.keys.ESCAPE:
  6792. dojo.publish("/dnd/cancel");
  6793. this.stopDrag();
  6794. break;
  6795. }
  6796. }
  6797. },
  6798. onKeyUp: function(e){
  6799. // summary:
  6800. // event processor for onkeyup, watching for CTRL for copy/move status
  6801. // e: Event
  6802. // keyboard event
  6803. if(this.avatar && e.keyCode == dojo.keys.CTRL){
  6804. var copy = Boolean(this.source.copyState(false));
  6805. if(this.copy != copy){
  6806. this._setCopyStatus(copy);
  6807. }
  6808. }
  6809. },
  6810. // utilities
  6811. _setCopyStatus: function(copy){
  6812. // summary:
  6813. // changes the copy status
  6814. // copy: Boolean
  6815. // the copy status
  6816. this.copy = copy;
  6817. this.source._markDndStatus(this.copy);
  6818. this.updateAvatar();
  6819. dojo.replaceClass(dojo.body(),
  6820. "dojoDnd" + (this.copy ? "Copy" : "Move"),
  6821. "dojoDnd" + (this.copy ? "Move" : "Copy"));
  6822. }
  6823. });
  6824. // dojo.dnd._manager:
  6825. // The manager singleton variable. Can be overwritten if needed.
  6826. dojo.dnd._manager = null;
  6827. Manager.manager = dojo.dnd.manager = function(){
  6828. // summary:
  6829. // Returns the current DnD manager. Creates one if it is not created yet.
  6830. if(!dojo.dnd._manager){
  6831. dojo.dnd._manager = new dojo.dnd.Manager();
  6832. }
  6833. return dojo.dnd._manager; // Object
  6834. };
  6835. return Manager;
  6836. });
  6837. },
  6838. 'dijit/form/ToggleButton':function(){
  6839. define("dijit/form/ToggleButton", [
  6840. "dojo/_base/declare", // declare
  6841. "dojo/_base/kernel", // kernel.deprecated
  6842. "./Button",
  6843. "./_ToggleButtonMixin"
  6844. ], function(declare, kernel, Button, _ToggleButtonMixin){
  6845. /*=====
  6846. var Button = dijit.form.Button;
  6847. var _ToggleButtonMixin = dijit.form._ToggleButtonMixin;
  6848. =====*/
  6849. // module:
  6850. // dijit/form/ToggleButton
  6851. // summary:
  6852. // A templated button widget that can be in two states (checked or not).
  6853. return declare("dijit.form.ToggleButton", [Button, _ToggleButtonMixin], {
  6854. // summary:
  6855. // A templated button widget that can be in two states (checked or not).
  6856. // Can be base class for things like tabs or checkbox or radio buttons
  6857. baseClass: "dijitToggleButton",
  6858. setChecked: function(/*Boolean*/ checked){
  6859. // summary:
  6860. // Deprecated. Use set('checked', true/false) instead.
  6861. kernel.deprecated("setChecked("+checked+") is deprecated. Use set('checked',"+checked+") instead.", "", "2.0");
  6862. this.set('checked', checked);
  6863. }
  6864. });
  6865. });
  6866. },
  6867. 'dojo/date/stamp':function(){
  6868. define("dojo/date/stamp", ["../_base/kernel", "../_base/lang", "../_base/array"], function(dojo, lang, array) {
  6869. // module:
  6870. // dojo/date/stamp
  6871. // summary:
  6872. // TODOC
  6873. lang.getObject("date.stamp", true, dojo);
  6874. // Methods to convert dates to or from a wire (string) format using well-known conventions
  6875. dojo.date.stamp.fromISOString = function(/*String*/formattedString, /*Number?*/defaultTime){
  6876. // summary:
  6877. // Returns a Date object given a string formatted according to a subset of the ISO-8601 standard.
  6878. //
  6879. // description:
  6880. // Accepts a string formatted according to a profile of ISO8601 as defined by
  6881. // [RFC3339](http://www.ietf.org/rfc/rfc3339.txt), except that partial input is allowed.
  6882. // Can also process dates as specified [by the W3C](http://www.w3.org/TR/NOTE-datetime)
  6883. // The following combinations are valid:
  6884. //
  6885. // * dates only
  6886. // | * yyyy
  6887. // | * yyyy-MM
  6888. // | * yyyy-MM-dd
  6889. // * times only, with an optional time zone appended
  6890. // | * THH:mm
  6891. // | * THH:mm:ss
  6892. // | * THH:mm:ss.SSS
  6893. // * and "datetimes" which could be any combination of the above
  6894. //
  6895. // timezones may be specified as Z (for UTC) or +/- followed by a time expression HH:mm
  6896. // Assumes the local time zone if not specified. Does not validate. Improperly formatted
  6897. // input may return null. Arguments which are out of bounds will be handled
  6898. // by the Date constructor (e.g. January 32nd typically gets resolved to February 1st)
  6899. // Only years between 100 and 9999 are supported.
  6900. //
  6901. // formattedString:
  6902. // A string such as 2005-06-30T08:05:00-07:00 or 2005-06-30 or T08:05:00
  6903. //
  6904. // defaultTime:
  6905. // Used for defaults for fields omitted in the formattedString.
  6906. // Uses 1970-01-01T00:00:00.0Z by default.
  6907. if(!dojo.date.stamp._isoRegExp){
  6908. dojo.date.stamp._isoRegExp =
  6909. //TODO: could be more restrictive and check for 00-59, etc.
  6910. /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/;
  6911. }
  6912. var match = dojo.date.stamp._isoRegExp.exec(formattedString),
  6913. result = null;
  6914. if(match){
  6915. match.shift();
  6916. if(match[1]){match[1]--;} // Javascript Date months are 0-based
  6917. if(match[6]){match[6] *= 1000;} // Javascript Date expects fractional seconds as milliseconds
  6918. if(defaultTime){
  6919. // mix in defaultTime. Relatively expensive, so use || operators for the fast path of defaultTime === 0
  6920. defaultTime = new Date(defaultTime);
  6921. array.forEach(array.map(["FullYear", "Month", "Date", "Hours", "Minutes", "Seconds", "Milliseconds"], function(prop){
  6922. return defaultTime["get" + prop]();
  6923. }), function(value, index){
  6924. match[index] = match[index] || value;
  6925. });
  6926. }
  6927. result = new Date(match[0]||1970, match[1]||0, match[2]||1, match[3]||0, match[4]||0, match[5]||0, match[6]||0); //TODO: UTC defaults
  6928. if(match[0] < 100){
  6929. result.setFullYear(match[0] || 1970);
  6930. }
  6931. var offset = 0,
  6932. zoneSign = match[7] && match[7].charAt(0);
  6933. if(zoneSign != 'Z'){
  6934. offset = ((match[8] || 0) * 60) + (Number(match[9]) || 0);
  6935. if(zoneSign != '-'){ offset *= -1; }
  6936. }
  6937. if(zoneSign){
  6938. offset -= result.getTimezoneOffset();
  6939. }
  6940. if(offset){
  6941. result.setTime(result.getTime() + offset * 60000);
  6942. }
  6943. }
  6944. return result; // Date or null
  6945. };
  6946. /*=====
  6947. dojo.date.stamp.__Options = function(){
  6948. // selector: String
  6949. // "date" or "time" for partial formatting of the Date object.
  6950. // Both date and time will be formatted by default.
  6951. // zulu: Boolean
  6952. // if true, UTC/GMT is used for a timezone
  6953. // milliseconds: Boolean
  6954. // if true, output milliseconds
  6955. this.selector = selector;
  6956. this.zulu = zulu;
  6957. this.milliseconds = milliseconds;
  6958. }
  6959. =====*/
  6960. dojo.date.stamp.toISOString = function(/*Date*/dateObject, /*dojo.date.stamp.__Options?*/options){
  6961. // summary:
  6962. // Format a Date object as a string according a subset of the ISO-8601 standard
  6963. //
  6964. // description:
  6965. // When options.selector is omitted, output follows [RFC3339](http://www.ietf.org/rfc/rfc3339.txt)
  6966. // The local time zone is included as an offset from GMT, except when selector=='time' (time without a date)
  6967. // Does not check bounds. Only years between 100 and 9999 are supported.
  6968. //
  6969. // dateObject:
  6970. // A Date object
  6971. var _ = function(n){ return (n < 10) ? "0" + n : n; };
  6972. options = options || {};
  6973. var formattedDate = [],
  6974. getter = options.zulu ? "getUTC" : "get",
  6975. date = "";
  6976. if(options.selector != "time"){
  6977. var year = dateObject[getter+"FullYear"]();
  6978. date = ["0000".substr((year+"").length)+year, _(dateObject[getter+"Month"]()+1), _(dateObject[getter+"Date"]())].join('-');
  6979. }
  6980. formattedDate.push(date);
  6981. if(options.selector != "date"){
  6982. var time = [_(dateObject[getter+"Hours"]()), _(dateObject[getter+"Minutes"]()), _(dateObject[getter+"Seconds"]())].join(':');
  6983. var millis = dateObject[getter+"Milliseconds"]();
  6984. if(options.milliseconds){
  6985. time += "."+ (millis < 100 ? "0" : "") + _(millis);
  6986. }
  6987. if(options.zulu){
  6988. time += "Z";
  6989. }else if(options.selector != "time"){
  6990. var timezoneOffset = dateObject.getTimezoneOffset();
  6991. var absOffset = Math.abs(timezoneOffset);
  6992. time += (timezoneOffset > 0 ? "-" : "+") +
  6993. _(Math.floor(absOffset/60)) + ":" + _(absOffset%60);
  6994. }
  6995. formattedDate.push(time);
  6996. }
  6997. return formattedDate.join('T'); // String
  6998. };
  6999. return dojo.date.stamp;
  7000. });
  7001. },
  7002. 'dijit/form/NumberSpinner':function(){
  7003. define("dijit/form/NumberSpinner", [
  7004. "dojo/_base/declare", // declare
  7005. "dojo/_base/event", // event.stop
  7006. "dojo/keys", // keys.END keys.HOME
  7007. "./_Spinner",
  7008. "./NumberTextBox"
  7009. ], function(declare, event, keys, _Spinner, NumberTextBox){
  7010. /*=====
  7011. var _Spinner = dijit.form._Spinner;
  7012. var NumberTextBox = dijit.form.NumberTextBox;
  7013. =====*/
  7014. // module:
  7015. // dijit/form/NumberSpinner
  7016. // summary:
  7017. // Extends NumberTextBox to add up/down arrows and pageup/pagedown for incremental change to the value
  7018. return declare("dijit.form.NumberSpinner", [_Spinner, NumberTextBox.Mixin], {
  7019. // summary:
  7020. // Extends NumberTextBox to add up/down arrows and pageup/pagedown for incremental change to the value
  7021. //
  7022. // description:
  7023. // A `dijit.form.NumberTextBox` extension to provide keyboard accessible value selection
  7024. // as well as icons for spinning direction. When using the keyboard, the typematic rules
  7025. // apply, meaning holding the key will gradually increase or decrease the value and
  7026. // accelerate.
  7027. //
  7028. // example:
  7029. // | new dijit.form.NumberSpinner({ constraints:{ max:300, min:100 }}, "someInput");
  7030. adjust: function(/*Object*/ val, /*Number*/ delta){
  7031. // summary:
  7032. // Change Number val by the given amount
  7033. // tags:
  7034. // protected
  7035. var tc = this.constraints,
  7036. v = isNaN(val),
  7037. gotMax = !isNaN(tc.max),
  7038. gotMin = !isNaN(tc.min)
  7039. ;
  7040. if(v && delta != 0){ // blank or invalid value and they want to spin, so create defaults
  7041. val = (delta > 0) ?
  7042. gotMin ? tc.min : gotMax ? tc.max : 0 :
  7043. gotMax ? this.constraints.max : gotMin ? tc.min : 0
  7044. ;
  7045. }
  7046. var newval = val + delta;
  7047. if(v || isNaN(newval)){ return val; }
  7048. if(gotMax && (newval > tc.max)){
  7049. newval = tc.max;
  7050. }
  7051. if(gotMin && (newval < tc.min)){
  7052. newval = tc.min;
  7053. }
  7054. return newval;
  7055. },
  7056. _onKeyPress: function(e){
  7057. if((e.charOrCode == keys.HOME || e.charOrCode == keys.END) && !(e.ctrlKey || e.altKey || e.metaKey)
  7058. && typeof this.get('value') != 'undefined' /* gibberish, so HOME and END are default editing keys*/){
  7059. var value = this.constraints[(e.charOrCode == keys.HOME ? "min" : "max")];
  7060. if(typeof value == "number"){
  7061. this._setValueAttr(value, false);
  7062. }
  7063. // eat home or end key whether we change the value or not
  7064. event.stop(e);
  7065. }
  7066. }
  7067. });
  7068. });
  7069. },
  7070. 'dojo/Stateful':function(){
  7071. define("dojo/Stateful", ["./_base/declare", "./_base/lang", "./_base/array"], function(declare, lang, array) {
  7072. // module:
  7073. // dojo/Stateful
  7074. // summary:
  7075. // TODOC
  7076. return declare("dojo.Stateful", null, {
  7077. // summary:
  7078. // Base class for objects that provide named properties with optional getter/setter
  7079. // control and the ability to watch for property changes
  7080. // example:
  7081. // | var obj = new dojo.Stateful();
  7082. // | obj.watch("foo", function(){
  7083. // | console.log("foo changed to " + this.get("foo"));
  7084. // | });
  7085. // | obj.set("foo","bar");
  7086. postscript: function(mixin){
  7087. if(mixin){
  7088. lang.mixin(this, mixin);
  7089. }
  7090. },
  7091. get: function(/*String*/name){
  7092. // summary:
  7093. // Get a property on a Stateful instance.
  7094. // name:
  7095. // The property to get.
  7096. // returns:
  7097. // The property value on this Stateful instance.
  7098. // description:
  7099. // Get a named property on a Stateful object. The property may
  7100. // potentially be retrieved via a getter method in subclasses. In the base class
  7101. // this just retrieves the object's property.
  7102. // For example:
  7103. // | stateful = new dojo.Stateful({foo: 3});
  7104. // | stateful.get("foo") // returns 3
  7105. // | stateful.foo // returns 3
  7106. return this[name]; //Any
  7107. },
  7108. set: function(/*String*/name, /*Object*/value){
  7109. // summary:
  7110. // Set a property on a Stateful instance
  7111. // name:
  7112. // The property to set.
  7113. // value:
  7114. // The value to set in the property.
  7115. // returns:
  7116. // The function returns this dojo.Stateful instance.
  7117. // description:
  7118. // Sets named properties on a stateful object and notifies any watchers of
  7119. // the property. A programmatic setter may be defined in subclasses.
  7120. // For example:
  7121. // | stateful = new dojo.Stateful();
  7122. // | stateful.watch(function(name, oldValue, value){
  7123. // | // this will be called on the set below
  7124. // | }
  7125. // | stateful.set(foo, 5);
  7126. //
  7127. // set() may also be called with a hash of name/value pairs, ex:
  7128. // | myObj.set({
  7129. // | foo: "Howdy",
  7130. // | bar: 3
  7131. // | })
  7132. // This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
  7133. if(typeof name === "object"){
  7134. for(var x in name){
  7135. if(name.hasOwnProperty(x) && x !="_watchCallbacks"){
  7136. this.set(x, name[x]);
  7137. }
  7138. }
  7139. return this;
  7140. }
  7141. var oldValue = this[name];
  7142. this[name] = value;
  7143. if(this._watchCallbacks){
  7144. this._watchCallbacks(name, oldValue, value);
  7145. }
  7146. return this; //dojo.Stateful
  7147. },
  7148. watch: function(/*String?*/name, /*Function*/callback){
  7149. // summary:
  7150. // Watches a property for changes
  7151. // name:
  7152. // Indicates the property to watch. This is optional (the callback may be the
  7153. // only parameter), and if omitted, all the properties will be watched
  7154. // returns:
  7155. // An object handle for the watch. The unwatch method of this object
  7156. // can be used to discontinue watching this property:
  7157. // | var watchHandle = obj.watch("foo", callback);
  7158. // | watchHandle.unwatch(); // callback won't be called now
  7159. // callback:
  7160. // The function to execute when the property changes. This will be called after
  7161. // the property has been changed. The callback will be called with the |this|
  7162. // set to the instance, the first argument as the name of the property, the
  7163. // second argument as the old value and the third argument as the new value.
  7164. var callbacks = this._watchCallbacks;
  7165. if(!callbacks){
  7166. var self = this;
  7167. callbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){
  7168. var notify = function(propertyCallbacks){
  7169. if(propertyCallbacks){
  7170. propertyCallbacks = propertyCallbacks.slice();
  7171. for(var i = 0, l = propertyCallbacks.length; i < l; i++){
  7172. propertyCallbacks[i].call(self, name, oldValue, value);
  7173. }
  7174. }
  7175. };
  7176. notify(callbacks['_' + name]);
  7177. if(!ignoreCatchall){
  7178. notify(callbacks["*"]); // the catch-all
  7179. }
  7180. }; // we use a function instead of an object so it will be ignored by JSON conversion
  7181. }
  7182. if(!callback && typeof name === "function"){
  7183. callback = name;
  7184. name = "*";
  7185. }else{
  7186. // prepend with dash to prevent name conflicts with function (like "name" property)
  7187. name = '_' + name;
  7188. }
  7189. var propertyCallbacks = callbacks[name];
  7190. if(typeof propertyCallbacks !== "object"){
  7191. propertyCallbacks = callbacks[name] = [];
  7192. }
  7193. propertyCallbacks.push(callback);
  7194. return {
  7195. unwatch: function(){
  7196. propertyCallbacks.splice(array.indexOf(propertyCallbacks, callback), 1);
  7197. }
  7198. }; //Object
  7199. }
  7200. });
  7201. });
  7202. },
  7203. 'dijit/form/DateTextBox':function(){
  7204. define("dijit/form/DateTextBox", [
  7205. "dojo/_base/declare", // declare
  7206. "../Calendar",
  7207. "./_DateTimeTextBox"
  7208. ], function(declare, Calendar, _DateTimeTextBox){
  7209. /*=====
  7210. var Calendar = dijit.Calendar;
  7211. var _DateTimeTextBox = dijit.form._DateTimeTextBox;
  7212. =====*/
  7213. // module:
  7214. // dijit/form/DateTextBox
  7215. // summary:
  7216. // A validating, serializable, range-bound date text box with a drop down calendar
  7217. return declare("dijit.form.DateTextBox", _DateTimeTextBox, {
  7218. // summary:
  7219. // A validating, serializable, range-bound date text box with a drop down calendar
  7220. //
  7221. // Example:
  7222. // | new dijit.form.DateTextBox({value: new Date(2009, 0, 20)})
  7223. //
  7224. // Example:
  7225. // | <input data-dojo-type='dijit.form.DateTextBox' value='2009-01-20'>
  7226. baseClass: "dijitTextBox dijitComboBox dijitDateTextBox",
  7227. popupClass: Calendar,
  7228. _selector: "date",
  7229. // value: Date
  7230. // The value of this widget as a JavaScript Date object, with only year/month/day specified.
  7231. // If specified in markup, use the format specified in `stamp.fromISOString`.
  7232. // set("value", ...) accepts either a Date object or a string.
  7233. value: new Date("") // value.toString()="NaN"
  7234. });
  7235. });
  7236. },
  7237. 'dojox/xml/parser':function(){
  7238. define("dojox/xml/parser", ['dojo/_base/kernel', 'dojo/_base/lang', 'dojo/_base/array', 'dojo/_base/window', 'dojo/_base/sniff'], function(dojo){
  7239. dojo.getObject("xml.parser", true, dojox);
  7240. //DOM type to int value for reference.
  7241. //Ints make for more compact code than full constant names.
  7242. //ELEMENT_NODE = 1;
  7243. //ATTRIBUTE_NODE = 2;
  7244. //TEXT_NODE = 3;
  7245. //CDATA_SECTION_NODE = 4;
  7246. //ENTITY_REFERENCE_NODE = 5;
  7247. //ENTITY_NODE = 6;
  7248. //PROCESSING_INSTRUCTION_NODE = 7;
  7249. //COMMENT_NODE = 8;
  7250. //DOCUMENT_NODE = 9;
  7251. //DOCUMENT_TYPE_NODE = 10;
  7252. //DOCUMENT_FRAGMENT_NODE = 11;
  7253. //NOTATION_NODE = 12;
  7254. dojox.xml.parser.parse = function(/*String?*/ str, /*String?*/ mimetype){
  7255. // summary:
  7256. // cross-browser implementation of creating an XML document object from null, empty string, and XML text..
  7257. //
  7258. // str:
  7259. // Optional text to create the document from. If not provided, an empty XML document will be created.
  7260. // If str is empty string "", then a new empty document will be created.
  7261. // mimetype:
  7262. // Optional mimetype of the text. Typically, this is text/xml. Will be defaulted to text/xml if not provided.
  7263. var _document = dojo.doc;
  7264. var doc;
  7265. mimetype = mimetype || "text/xml";
  7266. if(str && dojo.trim(str) && "DOMParser" in dojo.global){
  7267. //Handle parsing the text on Mozilla based browsers etc..
  7268. var parser = new DOMParser();
  7269. doc = parser.parseFromString(str, mimetype);
  7270. var de = doc.documentElement;
  7271. var errorNS = "http://www.mozilla.org/newlayout/xml/parsererror.xml";
  7272. if(de.nodeName == "parsererror" && de.namespaceURI == errorNS){
  7273. var sourceText = de.getElementsByTagNameNS(errorNS, 'sourcetext')[0];
  7274. if(sourceText){
  7275. sourceText = sourceText.firstChild.data;
  7276. }
  7277. throw new Error("Error parsing text " + de.firstChild.data + " \n" + sourceText);
  7278. }
  7279. return doc;
  7280. }else if("ActiveXObject" in dojo.global){
  7281. //Handle IE.
  7282. var ms = function(n){ return "MSXML" + n + ".DOMDocument"; };
  7283. var dp = ["Microsoft.XMLDOM", ms(6), ms(4), ms(3), ms(2)];
  7284. dojo.some(dp, function(p){
  7285. try{
  7286. doc = new ActiveXObject(p);
  7287. }catch(e){ return false; }
  7288. return true;
  7289. });
  7290. if(str && doc){
  7291. doc.async = false;
  7292. doc.loadXML(str);
  7293. var pe = doc.parseError;
  7294. if(pe.errorCode !== 0){
  7295. throw new Error("Line: " + pe.line + "\n" +
  7296. "Col: " + pe.linepos + "\n" +
  7297. "Reason: " + pe.reason + "\n" +
  7298. "Error Code: " + pe.errorCode + "\n" +
  7299. "Source: " + pe.srcText);
  7300. }
  7301. }
  7302. if(doc){
  7303. return doc; //DOMDocument
  7304. }
  7305. }else if(_document.implementation && _document.implementation.createDocument){
  7306. if(str && dojo.trim(str) && _document.createElement){
  7307. //Everyone else that we couldn't get to work. Fallback case.
  7308. // FIXME: this may change all tags to uppercase!
  7309. var tmp = _document.createElement("xml");
  7310. tmp.innerHTML = str;
  7311. var xmlDoc = _document.implementation.createDocument("foo", "", null);
  7312. dojo.forEach(tmp.childNodes, function(child){
  7313. xmlDoc.importNode(child, true);
  7314. });
  7315. return xmlDoc; // DOMDocument
  7316. }else{
  7317. return _document.implementation.createDocument("", "", null); // DOMDocument
  7318. }
  7319. }
  7320. return null; // null
  7321. };
  7322. dojox.xml.parser.textContent = function(/*Node*/node, /*String?*/text){
  7323. // summary:
  7324. // Implementation of the DOM Level 3 attribute; scan node for text
  7325. // description:
  7326. // Implementation of the DOM Level 3 attribute; scan node for text
  7327. // This function can also update the text of a node by replacing all child
  7328. // content of the node.
  7329. // node:
  7330. // The node to get the text off of or set the text on.
  7331. // text:
  7332. // Optional argument of the text to apply to the node.
  7333. if(arguments.length>1){
  7334. var _document = node.ownerDocument || dojo.doc; //Preference is to get the node owning doc first or it may fail
  7335. dojox.xml.parser.replaceChildren(node, _document.createTextNode(text));
  7336. return text; // String
  7337. }else{
  7338. if(node.textContent !== undefined){ //FF 1.5 -- remove?
  7339. return node.textContent; // String
  7340. }
  7341. var _result = "";
  7342. if(node){
  7343. dojo.forEach(node.childNodes, function(child){
  7344. switch(child.nodeType){
  7345. case 1: // ELEMENT_NODE
  7346. case 5: // ENTITY_REFERENCE_NODE
  7347. _result += dojox.xml.parser.textContent(child);
  7348. break;
  7349. case 3: // TEXT_NODE
  7350. case 2: // ATTRIBUTE_NODE
  7351. case 4: // CDATA_SECTION_NODE
  7352. _result += child.nodeValue;
  7353. }
  7354. });
  7355. }
  7356. return _result; // String
  7357. }
  7358. };
  7359. dojox.xml.parser.replaceChildren = function(/*Element*/node, /*Node || Array*/ newChildren){
  7360. // summary:
  7361. // Removes all children of node and appends newChild. All the existing
  7362. // children will be destroyed.
  7363. // description:
  7364. // Removes all children of node and appends newChild. All the existing
  7365. // children will be destroyed.
  7366. // node:
  7367. // The node to modify the children on
  7368. // newChildren:
  7369. // The children to add to the node. It can either be a single Node or an
  7370. // array of Nodes.
  7371. var nodes = [];
  7372. if(dojo.isIE){
  7373. dojo.forEach(node.childNodes, function(child){
  7374. nodes.push(child);
  7375. });
  7376. }
  7377. dojox.xml.parser.removeChildren(node);
  7378. dojo.forEach(nodes, dojo.destroy);
  7379. if(!dojo.isArray(newChildren)){
  7380. node.appendChild(newChildren);
  7381. }else{
  7382. dojo.forEach(newChildren, function(child){
  7383. node.appendChild(child);
  7384. });
  7385. }
  7386. };
  7387. dojox.xml.parser.removeChildren = function(/*Element*/node){
  7388. // summary:
  7389. // removes all children from node and returns the count of children removed.
  7390. // The children nodes are not destroyed. Be sure to call dojo.destroy on them
  7391. // after they are not used anymore.
  7392. // node:
  7393. // The node to remove all the children from.
  7394. var count = node.childNodes.length;
  7395. while(node.hasChildNodes()){
  7396. node.removeChild(node.firstChild);
  7397. }
  7398. return count; // int
  7399. };
  7400. dojox.xml.parser.innerXML = function(/*Node*/node){
  7401. // summary:
  7402. // Implementation of MS's innerXML function.
  7403. // node:
  7404. // The node from which to generate the XML text representation.
  7405. if(node.innerXML){
  7406. return node.innerXML; // String
  7407. }else if(node.xml){
  7408. return node.xml; // String
  7409. }else if(typeof XMLSerializer != "undefined"){
  7410. return (new XMLSerializer()).serializeToString(node); // String
  7411. }
  7412. return null;
  7413. };
  7414. return dojox.xml.parser;
  7415. });
  7416. },
  7417. 'url:dijit/templates/Calendar.html':"<table cellspacing=\"0\" cellpadding=\"0\" class=\"dijitCalendarContainer\" role=\"grid\" aria-labelledby=\"${id}_mddb ${id}_year\">\r\n\t<thead>\r\n\t\t<tr class=\"dijitReset dijitCalendarMonthContainer\" valign=\"top\">\r\n\t\t\t<th class='dijitReset dijitCalendarArrow' data-dojo-attach-point=\"decrementMonth\">\r\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarDecrease\" role=\"presentation\"/>\r\n\t\t\t\t<span data-dojo-attach-point=\"decreaseArrowNode\" class=\"dijitA11ySideArrow\">-</span>\r\n\t\t\t</th>\r\n\t\t\t<th class='dijitReset' colspan=\"5\">\r\n\t\t\t\t<div data-dojo-attach-point=\"monthNode\">\r\n\t\t\t\t</div>\r\n\t\t\t</th>\r\n\t\t\t<th class='dijitReset dijitCalendarArrow' data-dojo-attach-point=\"incrementMonth\">\r\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarIncrease\" role=\"presentation\"/>\r\n\t\t\t\t<span data-dojo-attach-point=\"increaseArrowNode\" class=\"dijitA11ySideArrow\">+</span>\r\n\t\t\t</th>\r\n\t\t</tr>\r\n\t\t<tr>\r\n\t\t\t${!dayCellsHtml}\r\n\t\t</tr>\r\n\t</thead>\r\n\t<tbody data-dojo-attach-point=\"dateRowsNode\" data-dojo-attach-event=\"onclick: _onDayClick\" class=\"dijitReset dijitCalendarBodyContainer\">\r\n\t\t\t${!dateRowsHtml}\r\n\t</tbody>\r\n\t<tfoot class=\"dijitReset dijitCalendarYearContainer\">\r\n\t\t<tr>\r\n\t\t\t<td class='dijitReset' valign=\"top\" colspan=\"7\" role=\"presentation\">\r\n\t\t\t\t<div class=\"dijitCalendarYearLabel\">\r\n\t\t\t\t\t<span data-dojo-attach-point=\"previousYearLabelNode\" class=\"dijitInline dijitCalendarPreviousYear\" role=\"button\"></span>\r\n\t\t\t\t\t<span data-dojo-attach-point=\"currentYearLabelNode\" class=\"dijitInline dijitCalendarSelectedYear\" role=\"button\" id=\"${id}_year\"></span>\r\n\t\t\t\t\t<span data-dojo-attach-point=\"nextYearLabelNode\" class=\"dijitInline dijitCalendarNextYear\" role=\"button\"></span>\r\n\t\t\t\t</div>\r\n\t\t\t</td>\r\n\t\t</tr>\r\n\t</tfoot>\r\n</table>\r\n",
  7418. 'dijit/form/_AutoCompleterMixin':function(){
  7419. define("dijit/form/_AutoCompleterMixin", [
  7420. "dojo/_base/connect", // keys keys.SHIFT
  7421. "dojo/data/util/filter", // patternToRegExp
  7422. "dojo/_base/declare", // declare
  7423. "dojo/_base/Deferred", // Deferred.when
  7424. "dojo/dom-attr", // domAttr.get
  7425. "dojo/_base/event", // event.stop
  7426. "dojo/keys",
  7427. "dojo/_base/lang", // lang.clone lang.hitch
  7428. "dojo/query", // query
  7429. "dojo/regexp", // regexp.escapeString
  7430. "dojo/_base/sniff", // has("ie")
  7431. "dojo/string", // string.substitute
  7432. "dojo/_base/window", // win.doc.selection.createRange
  7433. "./DataList",
  7434. "../registry", // registry.byId
  7435. "./_TextBoxMixin" // defines _TextBoxMixin.selectInputText
  7436. ], function(connect, filter, declare, Deferred, domAttr, event, keys, lang, query, regexp, has, string, win,
  7437. DataList, registry, _TextBoxMixin){
  7438. // module:
  7439. // dijit/form/_AutoCompleterMixin
  7440. // summary:
  7441. // A mixin that implements the base functionality for `dijit.form.ComboBox`/`dijit.form.FilteringSelect`
  7442. return declare("dijit.form._AutoCompleterMixin", null, {
  7443. // summary:
  7444. // A mixin that implements the base functionality for `dijit.form.ComboBox`/`dijit.form.FilteringSelect`
  7445. // description:
  7446. // All widgets that mix in dijit.form._AutoCompleterMixin must extend `dijit.form._FormValueWidget`.
  7447. // tags:
  7448. // protected
  7449. // item: Object
  7450. // This is the item returned by the dojo.data.store implementation that
  7451. // provides the data for this ComboBox, it's the currently selected item.
  7452. item: null,
  7453. // pageSize: Integer
  7454. // Argument to data provider.
  7455. // Specifies number of search results per page (before hitting "next" button)
  7456. pageSize: Infinity,
  7457. // store: [const] dojo.store.api.Store
  7458. // Reference to data provider object used by this ComboBox
  7459. store: null,
  7460. // fetchProperties: Object
  7461. // Mixin to the store's fetch.
  7462. // For example, to set the sort order of the ComboBox menu, pass:
  7463. // | { sort: [{attribute:"name",descending: true}] }
  7464. // To override the default queryOptions so that deep=false, do:
  7465. // | { queryOptions: {ignoreCase: true, deep: false} }
  7466. fetchProperties:{},
  7467. // query: Object
  7468. // A query that can be passed to 'store' to initially filter the items,
  7469. // before doing further filtering based on `searchAttr` and the key.
  7470. // Any reference to the `searchAttr` is ignored.
  7471. query: {},
  7472. // autoComplete: Boolean
  7473. // If user types in a partial string, and then tab out of the `<input>` box,
  7474. // automatically copy the first entry displayed in the drop down list to
  7475. // the `<input>` field
  7476. autoComplete: true,
  7477. // highlightMatch: String
  7478. // One of: "first", "all" or "none".
  7479. //
  7480. // If the ComboBox/FilteringSelect opens with the search results and the searched
  7481. // string can be found, it will be highlighted. If set to "all"
  7482. // then will probably want to change `queryExpr` parameter to '*${0}*'
  7483. //
  7484. // Highlighting is only performed when `labelType` is "text", so as to not
  7485. // interfere with any HTML markup an HTML label might contain.
  7486. highlightMatch: "first",
  7487. // searchDelay: Integer
  7488. // Delay in milliseconds between when user types something and we start
  7489. // searching based on that value
  7490. searchDelay: 100,
  7491. // searchAttr: String
  7492. // Search for items in the data store where this attribute (in the item)
  7493. // matches what the user typed
  7494. searchAttr: "name",
  7495. // labelAttr: String?
  7496. // The entries in the drop down list come from this attribute in the
  7497. // dojo.data items.
  7498. // If not specified, the searchAttr attribute is used instead.
  7499. labelAttr: "",
  7500. // labelType: String
  7501. // Specifies how to interpret the labelAttr in the data store items.
  7502. // Can be "html" or "text".
  7503. labelType: "text",
  7504. // queryExpr: String
  7505. // This specifies what query ComboBox/FilteringSelect sends to the data store,
  7506. // based on what the user has typed. Changing this expression will modify
  7507. // whether the drop down shows only exact matches, a "starting with" match,
  7508. // etc. Use it in conjunction with highlightMatch.
  7509. // dojo.data query expression pattern.
  7510. // `${0}` will be substituted for the user text.
  7511. // `*` is used for wildcards.
  7512. // `${0}*` means "starts with", `*${0}*` means "contains", `${0}` means "is"
  7513. queryExpr: "${0}*",
  7514. // ignoreCase: Boolean
  7515. // Set true if the ComboBox/FilteringSelect should ignore case when matching possible items
  7516. ignoreCase: true,
  7517. // Flags to _HasDropDown to limit height of drop down to make it fit in viewport
  7518. maxHeight: -1,
  7519. // For backwards compatibility let onClick events propagate, even clicks on the down arrow button
  7520. _stopClickEvents: false,
  7521. _getCaretPos: function(/*DomNode*/ element){
  7522. // khtml 3.5.2 has selection* methods as does webkit nightlies from 2005-06-22
  7523. var pos = 0;
  7524. if(typeof(element.selectionStart) == "number"){
  7525. // FIXME: this is totally borked on Moz < 1.3. Any recourse?
  7526. pos = element.selectionStart;
  7527. }else if(has("ie")){
  7528. // in the case of a mouse click in a popup being handled,
  7529. // then the win.doc.selection is not the textarea, but the popup
  7530. // var r = win.doc.selection.createRange();
  7531. // hack to get IE 6 to play nice. What a POS browser.
  7532. var tr = win.doc.selection.createRange().duplicate();
  7533. var ntr = element.createTextRange();
  7534. tr.move("character",0);
  7535. ntr.move("character",0);
  7536. try{
  7537. // If control doesn't have focus, you get an exception.
  7538. // Seems to happen on reverse-tab, but can also happen on tab (seems to be a race condition - only happens sometimes).
  7539. // There appears to be no workaround for this - googled for quite a while.
  7540. ntr.setEndPoint("EndToEnd", tr);
  7541. pos = String(ntr.text).replace(/\r/g,"").length;
  7542. }catch(e){
  7543. // If focus has shifted, 0 is fine for caret pos.
  7544. }
  7545. }
  7546. return pos;
  7547. },
  7548. _setCaretPos: function(/*DomNode*/ element, /*Number*/ location){
  7549. location = parseInt(location);
  7550. _TextBoxMixin.selectInputText(element, location, location);
  7551. },
  7552. _setDisabledAttr: function(/*Boolean*/ value){
  7553. // Additional code to set disabled state of ComboBox node.
  7554. // Overrides _FormValueWidget._setDisabledAttr() or ValidationTextBox._setDisabledAttr().
  7555. this.inherited(arguments);
  7556. this.domNode.setAttribute("aria-disabled", value);
  7557. },
  7558. _abortQuery: function(){
  7559. // stop in-progress query
  7560. if(this.searchTimer){
  7561. clearTimeout(this.searchTimer);
  7562. this.searchTimer = null;
  7563. }
  7564. if(this._fetchHandle){
  7565. if(this._fetchHandle.cancel){
  7566. this._cancelingQuery = true;
  7567. this._fetchHandle.cancel();
  7568. this._cancelingQuery = false;
  7569. }
  7570. this._fetchHandle = null;
  7571. }
  7572. },
  7573. _onInput: function(/*Event*/ evt){
  7574. // summary:
  7575. // Handles paste events
  7576. this.inherited(arguments);
  7577. if(evt.charOrCode == 229){ // IME or cut/paste event
  7578. this._onKey(evt);
  7579. }
  7580. },
  7581. _onKey: function(/*Event*/ evt){
  7582. // summary:
  7583. // Handles keyboard events
  7584. if(this.disabled || this.readOnly){ return; }
  7585. var key = evt.charOrCode;
  7586. // except for cutting/pasting case - ctrl + x/v
  7587. if(evt.altKey || ((evt.ctrlKey || evt.metaKey) && (key != 'x' && key != 'v')) || key == keys.SHIFT){
  7588. return; // throw out weird key combinations and spurious events
  7589. }
  7590. var doSearch = false;
  7591. var pw = this.dropDown;
  7592. var highlighted = null;
  7593. this._prev_key_backspace = false;
  7594. this._abortQuery();
  7595. // _HasDropDown will do some of the work:
  7596. // 1. when drop down is not yet shown:
  7597. // - if user presses the down arrow key, call loadDropDown()
  7598. // 2. when drop down is already displayed:
  7599. // - on ESC key, call closeDropDown()
  7600. // - otherwise, call dropDown.handleKey() to process the keystroke
  7601. this.inherited(arguments);
  7602. if(this._opened){
  7603. highlighted = pw.getHighlightedOption();
  7604. }
  7605. switch(key){
  7606. case keys.PAGE_DOWN:
  7607. case keys.DOWN_ARROW:
  7608. case keys.PAGE_UP:
  7609. case keys.UP_ARROW:
  7610. // Keystroke caused ComboBox_menu to move to a different item.
  7611. // Copy new item to <input> box.
  7612. if(this._opened){
  7613. this._announceOption(highlighted);
  7614. }
  7615. event.stop(evt);
  7616. break;
  7617. case keys.ENTER:
  7618. // prevent submitting form if user presses enter. Also
  7619. // prevent accepting the value if either Next or Previous
  7620. // are selected
  7621. if(highlighted){
  7622. // only stop event on prev/next
  7623. if(highlighted == pw.nextButton){
  7624. this._nextSearch(1);
  7625. event.stop(evt);
  7626. break;
  7627. }else if(highlighted == pw.previousButton){
  7628. this._nextSearch(-1);
  7629. event.stop(evt);
  7630. break;
  7631. }
  7632. }else{
  7633. // Update 'value' (ex: KY) according to currently displayed text
  7634. this._setBlurValue(); // set value if needed
  7635. this._setCaretPos(this.focusNode, this.focusNode.value.length); // move cursor to end and cancel highlighting
  7636. }
  7637. // default case:
  7638. // if enter pressed while drop down is open, or for FilteringSelect,
  7639. // if we are in the middle of a query to convert a directly typed in value to an item,
  7640. // prevent submit
  7641. if(this._opened || this._fetchHandle){
  7642. event.stop(evt);
  7643. }
  7644. // fall through
  7645. case keys.TAB:
  7646. var newvalue = this.get('displayedValue');
  7647. // if the user had More Choices selected fall into the
  7648. // _onBlur handler
  7649. if(pw && (
  7650. newvalue == pw._messages["previousMessage"] ||
  7651. newvalue == pw._messages["nextMessage"])
  7652. ){
  7653. break;
  7654. }
  7655. if(highlighted){
  7656. this._selectOption(highlighted);
  7657. }
  7658. // fall through
  7659. case keys.ESCAPE:
  7660. if(this._opened){
  7661. this._lastQuery = null; // in case results come back later
  7662. this.closeDropDown();
  7663. }
  7664. break;
  7665. case ' ':
  7666. if(highlighted){
  7667. // user is effectively clicking a choice in the drop down menu
  7668. event.stop(evt);
  7669. this._selectOption(highlighted);
  7670. this.closeDropDown();
  7671. }else{
  7672. // user typed a space into the input box, treat as normal character
  7673. doSearch = true;
  7674. }
  7675. break;
  7676. case keys.DELETE:
  7677. case keys.BACKSPACE:
  7678. this._prev_key_backspace = true;
  7679. doSearch = true;
  7680. break;
  7681. default:
  7682. // Non char keys (F1-F12 etc..) shouldn't open list.
  7683. // Ascii characters and IME input (Chinese, Japanese etc.) should.
  7684. //IME input produces keycode == 229.
  7685. doSearch = typeof key == 'string' || key == 229;
  7686. }
  7687. if(doSearch){
  7688. // need to wait a tad before start search so that the event
  7689. // bubbles through DOM and we have value visible
  7690. this.item = undefined; // undefined means item needs to be set
  7691. this.searchTimer = setTimeout(lang.hitch(this, "_startSearchFromInput"),1);
  7692. }
  7693. },
  7694. _autoCompleteText: function(/*String*/ text){
  7695. // summary:
  7696. // Fill in the textbox with the first item from the drop down
  7697. // list, and highlight the characters that were
  7698. // auto-completed. For example, if user typed "CA" and the
  7699. // drop down list appeared, the textbox would be changed to
  7700. // "California" and "ifornia" would be highlighted.
  7701. var fn = this.focusNode;
  7702. // IE7: clear selection so next highlight works all the time
  7703. _TextBoxMixin.selectInputText(fn, fn.value.length);
  7704. // does text autoComplete the value in the textbox?
  7705. var caseFilter = this.ignoreCase? 'toLowerCase' : 'substr';
  7706. if(text[caseFilter](0).indexOf(this.focusNode.value[caseFilter](0)) == 0){
  7707. var cpos = this.autoComplete ? this._getCaretPos(fn) : fn.value.length;
  7708. // only try to extend if we added the last character at the end of the input
  7709. if((cpos+1) > fn.value.length){
  7710. // only add to input node as we would overwrite Capitalisation of chars
  7711. // actually, that is ok
  7712. fn.value = text;//.substr(cpos);
  7713. // visually highlight the autocompleted characters
  7714. _TextBoxMixin.selectInputText(fn, cpos);
  7715. }
  7716. }else{
  7717. // text does not autoComplete; replace the whole value and highlight
  7718. fn.value = text;
  7719. _TextBoxMixin.selectInputText(fn);
  7720. }
  7721. },
  7722. _openResultList: function(/*Object*/ results, /*Object*/ query, /*Object*/ options){
  7723. // summary:
  7724. // Callback when a search completes.
  7725. // description:
  7726. // 1. generates drop-down list and calls _showResultList() to display it
  7727. // 2. if this result list is from user pressing "more choices"/"previous choices"
  7728. // then tell screen reader to announce new option
  7729. this._fetchHandle = null;
  7730. if( this.disabled ||
  7731. this.readOnly ||
  7732. (query[this.searchAttr] !== this._lastQuery) // TODO: better way to avoid getting unwanted notify
  7733. ){
  7734. return;
  7735. }
  7736. var wasSelected = this.dropDown.getHighlightedOption();
  7737. this.dropDown.clearResultList();
  7738. if(!results.length && options.start == 0){ // if no results and not just the previous choices button
  7739. this.closeDropDown();
  7740. return;
  7741. }
  7742. // Fill in the textbox with the first item from the drop down list,
  7743. // and highlight the characters that were auto-completed. For
  7744. // example, if user typed "CA" and the drop down list appeared, the
  7745. // textbox would be changed to "California" and "ifornia" would be
  7746. // highlighted.
  7747. this.dropDown.createOptions(
  7748. results,
  7749. options,
  7750. lang.hitch(this, "_getMenuLabelFromItem")
  7751. );
  7752. // show our list (only if we have content, else nothing)
  7753. this._showResultList();
  7754. // #4091:
  7755. // tell the screen reader that the paging callback finished by
  7756. // shouting the next choice
  7757. if(options.direction){
  7758. if(1 == options.direction){
  7759. this.dropDown.highlightFirstOption();
  7760. }else if(-1 == options.direction){
  7761. this.dropDown.highlightLastOption();
  7762. }
  7763. if(wasSelected){
  7764. this._announceOption(this.dropDown.getHighlightedOption());
  7765. }
  7766. }else if(this.autoComplete && !this._prev_key_backspace
  7767. // when the user clicks the arrow button to show the full list,
  7768. // startSearch looks for "*".
  7769. // it does not make sense to autocomplete
  7770. // if they are just previewing the options available.
  7771. && !/^[*]+$/.test(query[this.searchAttr].toString())){
  7772. this._announceOption(this.dropDown.containerNode.firstChild.nextSibling); // 1st real item
  7773. }
  7774. },
  7775. _showResultList: function(){
  7776. // summary:
  7777. // Display the drop down if not already displayed, or if it is displayed, then
  7778. // reposition it if necessary (reposition may be necessary if drop down's height changed).
  7779. this.closeDropDown(true);
  7780. this.openDropDown();
  7781. this.domNode.setAttribute("aria-expanded", "true");
  7782. },
  7783. loadDropDown: function(/*Function*/ /*===== callback =====*/){
  7784. // Overrides _HasDropDown.loadDropDown().
  7785. // This is called when user has pressed button icon or pressed the down arrow key
  7786. // to open the drop down.
  7787. this._startSearchAll();
  7788. },
  7789. isLoaded: function(){
  7790. // signal to _HasDropDown that it needs to call loadDropDown() to load the
  7791. // drop down asynchronously before displaying it
  7792. return false;
  7793. },
  7794. closeDropDown: function(){
  7795. // Overrides _HasDropDown.closeDropDown(). Closes the drop down (assuming that it's open).
  7796. // This method is the callback when the user types ESC or clicking
  7797. // the button icon while the drop down is open. It's also called by other code.
  7798. this._abortQuery();
  7799. if(this._opened){
  7800. this.inherited(arguments);
  7801. this.domNode.setAttribute("aria-expanded", "false");
  7802. this.focusNode.removeAttribute("aria-activedescendant");
  7803. }
  7804. },
  7805. _setBlurValue: function(){
  7806. // if the user clicks away from the textbox OR tabs away, set the
  7807. // value to the textbox value
  7808. // #4617:
  7809. // if value is now more choices or previous choices, revert
  7810. // the value
  7811. var newvalue = this.get('displayedValue');
  7812. var pw = this.dropDown;
  7813. if(pw && (
  7814. newvalue == pw._messages["previousMessage"] ||
  7815. newvalue == pw._messages["nextMessage"]
  7816. )
  7817. ){
  7818. this._setValueAttr(this._lastValueReported, true);
  7819. }else if(typeof this.item == "undefined"){
  7820. // Update 'value' (ex: KY) according to currently displayed text
  7821. this.item = null;
  7822. this.set('displayedValue', newvalue);
  7823. }else{
  7824. if(this.value != this._lastValueReported){
  7825. this._handleOnChange(this.value, true);
  7826. }
  7827. this._refreshState();
  7828. }
  7829. },
  7830. _setItemAttr: function(/*item*/ item, /*Boolean?*/ priorityChange, /*String?*/ displayedValue){
  7831. // summary:
  7832. // Set the displayed valued in the input box, and the hidden value
  7833. // that gets submitted, based on a dojo.data store item.
  7834. // description:
  7835. // Users shouldn't call this function; they should be calling
  7836. // set('item', value)
  7837. // tags:
  7838. // private
  7839. var value = '';
  7840. if(item){
  7841. if(!displayedValue){
  7842. displayedValue = this.store._oldAPI ? // remove getValue() for 2.0 (old dojo.data API)
  7843. this.store.getValue(item, this.searchAttr) : item[this.searchAttr];
  7844. }
  7845. value = this._getValueField() != this.searchAttr ? this.store.getIdentity(item) : displayedValue;
  7846. }
  7847. this.set('value', value, priorityChange, displayedValue, item);
  7848. },
  7849. _announceOption: function(/*Node*/ node){
  7850. // summary:
  7851. // a11y code that puts the highlighted option in the textbox.
  7852. // This way screen readers will know what is happening in the
  7853. // menu.
  7854. if(!node){
  7855. return;
  7856. }
  7857. // pull the text value from the item attached to the DOM node
  7858. var newValue;
  7859. if(node == this.dropDown.nextButton ||
  7860. node == this.dropDown.previousButton){
  7861. newValue = node.innerHTML;
  7862. this.item = undefined;
  7863. this.value = '';
  7864. }else{
  7865. var item = this.dropDown.items[node.getAttribute("item")];
  7866. newValue = (this.store._oldAPI ? // remove getValue() for 2.0 (old dojo.data API)
  7867. this.store.getValue(item, this.searchAttr) : item[this.searchAttr]).toString();
  7868. this.set('item', item, false, newValue);
  7869. }
  7870. // get the text that the user manually entered (cut off autocompleted text)
  7871. this.focusNode.value = this.focusNode.value.substring(0, this._lastInput.length);
  7872. // set up ARIA activedescendant
  7873. this.focusNode.setAttribute("aria-activedescendant", domAttr.get(node, "id"));
  7874. // autocomplete the rest of the option to announce change
  7875. this._autoCompleteText(newValue);
  7876. },
  7877. _selectOption: function(/*DomNode*/ target){
  7878. // summary:
  7879. // Menu callback function, called when an item in the menu is selected.
  7880. this.closeDropDown();
  7881. if(target){
  7882. this._announceOption(target);
  7883. }
  7884. this._setCaretPos(this.focusNode, this.focusNode.value.length);
  7885. this._handleOnChange(this.value, true);
  7886. },
  7887. _startSearchAll: function(){
  7888. this._startSearch('');
  7889. },
  7890. _startSearchFromInput: function(){
  7891. this._startSearch(this.focusNode.value.replace(/([\\\*\?])/g, "\\$1"));
  7892. },
  7893. _getQueryString: function(/*String*/ text){
  7894. return string.substitute(this.queryExpr, [text]);
  7895. },
  7896. _startSearch: function(/*String*/ key){
  7897. // summary:
  7898. // Starts a search for elements matching key (key=="" means to return all items),
  7899. // and calls _openResultList() when the search completes, to display the results.
  7900. if(!this.dropDown){
  7901. var popupId = this.id + "_popup",
  7902. dropDownConstructor = lang.isString(this.dropDownClass) ?
  7903. lang.getObject(this.dropDownClass, false) : this.dropDownClass;
  7904. this.dropDown = new dropDownConstructor({
  7905. onChange: lang.hitch(this, this._selectOption),
  7906. id: popupId,
  7907. dir: this.dir,
  7908. textDir: this.textDir
  7909. });
  7910. this.focusNode.removeAttribute("aria-activedescendant");
  7911. this.textbox.setAttribute("aria-owns",popupId); // associate popup with textbox
  7912. }
  7913. this._lastInput = key; // Store exactly what was entered by the user.
  7914. // Setup parameters to be passed to store.query().
  7915. // Create a new query to prevent accidentally querying for a hidden
  7916. // value from FilteringSelect's keyField
  7917. var query = lang.clone(this.query); // #5970
  7918. var options = {
  7919. start: 0,
  7920. count: this.pageSize,
  7921. queryOptions: { // remove for 2.0
  7922. ignoreCase: this.ignoreCase,
  7923. deep: true
  7924. }
  7925. };
  7926. lang.mixin(options, this.fetchProperties);
  7927. // Generate query
  7928. var qs = this._getQueryString(key), q;
  7929. if(this.store._oldAPI){
  7930. // remove this branch for 2.0
  7931. q = qs;
  7932. }else{
  7933. // Query on searchAttr is a regex for benefit of dojo.store.Memory,
  7934. // but with a toString() method to help dojo.store.JsonRest.
  7935. // Search string like "Co*" converted to regex like /^Co.*$/i.
  7936. q = filter.patternToRegExp(qs, this.ignoreCase);
  7937. q.toString = function(){ return qs; };
  7938. }
  7939. this._lastQuery = query[this.searchAttr] = q;
  7940. // Function to run the query, wait for the results, and then call _openResultList()
  7941. var _this = this,
  7942. startQuery = function(){
  7943. var resPromise = _this._fetchHandle = _this.store.query(query, options);
  7944. Deferred.when(resPromise, function(res){
  7945. _this._fetchHandle = null;
  7946. res.total = resPromise.total;
  7947. _this._openResultList(res, query, options);
  7948. }, function(err){
  7949. _this._fetchHandle = null;
  7950. if(!_this._cancelingQuery){ // don't treat canceled query as an error
  7951. console.error(_this.declaredClass + ' ' + err.toString());
  7952. _this.closeDropDown();
  7953. }
  7954. });
  7955. };
  7956. // #5970: set _lastQuery, *then* start the timeout
  7957. // otherwise, if the user types and the last query returns before the timeout,
  7958. // _lastQuery won't be set and their input gets rewritten
  7959. this.searchTimer = setTimeout(lang.hitch(this, function(query, _this){
  7960. this.searchTimer = null;
  7961. startQuery();
  7962. // Setup method to handle clicking next/previous buttons to page through results
  7963. this._nextSearch = this.dropDown.onPage = function(direction){
  7964. options.start += options.count * direction;
  7965. // tell callback the direction of the paging so the screen
  7966. // reader knows which menu option to shout
  7967. options.direction = direction;
  7968. startQuery();
  7969. _this.focus();
  7970. };
  7971. }, query, this), this.searchDelay);
  7972. },
  7973. _getValueField: function(){
  7974. // summary:
  7975. // Helper for postMixInProperties() to set this.value based on data inlined into the markup.
  7976. // Returns the attribute name in the item (in dijit.form._ComboBoxDataStore) to use as the value.
  7977. return this.searchAttr;
  7978. },
  7979. //////////// INITIALIZATION METHODS ///////////////////////////////////////
  7980. constructor: function(){
  7981. this.query={};
  7982. this.fetchProperties={};
  7983. },
  7984. postMixInProperties: function(){
  7985. if(!this.store){
  7986. var srcNodeRef = this.srcNodeRef;
  7987. var list = this.list;
  7988. if(list){
  7989. this.store = registry.byId(list);
  7990. }else{
  7991. // if user didn't specify store, then assume there are option tags
  7992. this.store = new DataList({}, srcNodeRef);
  7993. }
  7994. // if there is no value set and there is an option list, set
  7995. // the value to the first value to be consistent with native Select
  7996. // Firefox and Safari set value
  7997. // IE6 and Opera set selectedIndex, which is automatically set
  7998. // by the selected attribute of an option tag
  7999. // IE6 does not set value, Opera sets value = selectedIndex
  8000. if(!("value" in this.params)){
  8001. var item = (this.item = this.store.fetchSelectedItem());
  8002. if(item){
  8003. var valueField = this._getValueField();
  8004. // remove getValue() for 2.0 (old dojo.data API)
  8005. this.value = this.store._oldAPI ? this.store.getValue(item, valueField) : item[valueField];
  8006. }
  8007. }
  8008. }
  8009. this.inherited(arguments);
  8010. },
  8011. postCreate: function(){
  8012. // summary:
  8013. // Subclasses must call this method from their postCreate() methods
  8014. // tags:
  8015. // protected
  8016. // find any associated label element and add to ComboBox node.
  8017. var label=query('label[for="'+this.id+'"]');
  8018. if(label.length){
  8019. label[0].id = (this.id+"_label");
  8020. this.domNode.setAttribute("aria-labelledby", label[0].id);
  8021. }
  8022. this.inherited(arguments);
  8023. },
  8024. _getMenuLabelFromItem: function(/*Item*/ item){
  8025. var label = this.labelFunc(item, this.store),
  8026. labelType = this.labelType;
  8027. // If labelType is not "text" we don't want to screw any markup ot whatever.
  8028. if(this.highlightMatch != "none" && this.labelType == "text" && this._lastInput){
  8029. label = this.doHighlight(label, this._escapeHtml(this._lastInput));
  8030. labelType = "html";
  8031. }
  8032. return {html: labelType == "html", label: label};
  8033. },
  8034. doHighlight: function(/*String*/ label, /*String*/ find){
  8035. // summary:
  8036. // Highlights the string entered by the user in the menu. By default this
  8037. // highlights the first occurrence found. Override this method
  8038. // to implement your custom highlighting.
  8039. // tags:
  8040. // protected
  8041. var
  8042. // Add (g)lobal modifier when this.highlightMatch == "all" and (i)gnorecase when this.ignoreCase == true
  8043. modifiers = (this.ignoreCase ? "i" : "") + (this.highlightMatch == "all" ? "g" : ""),
  8044. i = this.queryExpr.indexOf("${0}");
  8045. find = regexp.escapeString(find); // escape regexp special chars
  8046. return this._escapeHtml(label).replace(
  8047. // prepend ^ when this.queryExpr == "${0}*" and append $ when this.queryExpr == "*${0}"
  8048. new RegExp((i == 0 ? "^" : "") + "("+ find +")" + (i == (this.queryExpr.length - 4) ? "$" : ""), modifiers),
  8049. '<span class="dijitComboBoxHighlightMatch">$1</span>'
  8050. ); // returns String, (almost) valid HTML (entities encoded)
  8051. },
  8052. _escapeHtml: function(/*String*/ str){
  8053. // TODO Should become dojo.html.entities(), when exists use instead
  8054. // summary:
  8055. // Adds escape sequences for special characters in XML: &<>"'
  8056. str = String(str).replace(/&/gm, "&amp;").replace(/</gm, "&lt;")
  8057. .replace(/>/gm, "&gt;").replace(/"/gm, "&quot;"); //balance"
  8058. return str; // string
  8059. },
  8060. reset: function(){
  8061. // Overrides the _FormWidget.reset().
  8062. // Additionally reset the .item (to clean up).
  8063. this.item = null;
  8064. this.inherited(arguments);
  8065. },
  8066. labelFunc: function(/*item*/ item, /*dojo.store.api.Store*/ store){
  8067. // summary:
  8068. // Computes the label to display based on the dojo.data store item.
  8069. // returns:
  8070. // The label that the ComboBox should display
  8071. // tags:
  8072. // private
  8073. // Use toString() because XMLStore returns an XMLItem whereas this
  8074. // method is expected to return a String (#9354).
  8075. // Remove getValue() for 2.0 (old dojo.data API)
  8076. return (store._oldAPI ? store.getValue(item, this.labelAttr || this.searchAttr) :
  8077. item[this.labelAttr || this.searchAttr]).toString(); // String
  8078. },
  8079. _setValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange, /*String?*/ displayedValue, /*item?*/ item){
  8080. // summary:
  8081. // Hook so set('value', value) works.
  8082. // description:
  8083. // Sets the value of the select.
  8084. this._set("item", item||null); // value not looked up in store
  8085. if(!value){ value = ''; } // null translates to blank
  8086. this.inherited(arguments);
  8087. },
  8088. _setTextDirAttr: function(/*String*/ textDir){
  8089. // summary:
  8090. // Setter for textDir, needed for the dropDown's textDir update.
  8091. // description:
  8092. // Users shouldn't call this function; they should be calling
  8093. // set('textDir', value)
  8094. // tags:
  8095. // private
  8096. this.inherited(arguments);
  8097. // update the drop down also (_ComboBoxMenuMixin)
  8098. if(this.dropDown){
  8099. this.dropDown._set("textDir", textDir);
  8100. }
  8101. }
  8102. });
  8103. });
  8104. },
  8105. 'dojox/grid/Selection':function(){
  8106. define("dojox/grid/Selection", [
  8107. "dojo/_base/declare",
  8108. "dojo/_base/array",
  8109. "dojo/_base/lang",
  8110. "dojo/dom-attr"
  8111. ], function(declare, array, lang, domAttr){
  8112. return declare("dojox.grid.Selection", null, {
  8113. // summary:
  8114. // Manages row selection for grid. Owned by grid and used internally
  8115. // for selection. Override to implement custom selection.
  8116. constructor: function(inGrid){
  8117. this.grid = inGrid;
  8118. this.selected = [];
  8119. this.setMode(inGrid.selectionMode);
  8120. },
  8121. mode: 'extended',
  8122. selected: null,
  8123. updating: 0,
  8124. selectedIndex: -1,
  8125. setMode: function(mode){
  8126. if(this.selected.length){
  8127. this.deselectAll();
  8128. }
  8129. if(mode != 'extended' && mode != 'multiple' && mode != 'single' && mode != 'none'){
  8130. this.mode = 'extended';
  8131. }else{
  8132. this.mode = mode;
  8133. }
  8134. },
  8135. onCanSelect: function(inIndex){
  8136. return this.grid.onCanSelect(inIndex);
  8137. },
  8138. onCanDeselect: function(inIndex){
  8139. return this.grid.onCanDeselect(inIndex);
  8140. },
  8141. onSelected: function(inIndex){
  8142. },
  8143. onDeselected: function(inIndex){
  8144. },
  8145. //onSetSelected: function(inIndex, inSelect) { };
  8146. onChanging: function(){
  8147. },
  8148. onChanged: function(){
  8149. },
  8150. isSelected: function(inIndex){
  8151. if(this.mode == 'none'){
  8152. return false;
  8153. }
  8154. return this.selected[inIndex];
  8155. },
  8156. getFirstSelected: function(){
  8157. if(!this.selected.length||this.mode == 'none'){ return -1; }
  8158. for(var i=0, l=this.selected.length; i<l; i++){
  8159. if(this.selected[i]){
  8160. return i;
  8161. }
  8162. }
  8163. return -1;
  8164. },
  8165. getNextSelected: function(inPrev){
  8166. if(this.mode == 'none'){ return -1; }
  8167. for(var i=inPrev+1, l=this.selected.length; i<l; i++){
  8168. if(this.selected[i]){
  8169. return i;
  8170. }
  8171. }
  8172. return -1;
  8173. },
  8174. getSelected: function(){
  8175. var result = [];
  8176. for(var i=0, l=this.selected.length; i<l; i++){
  8177. if(this.selected[i]){
  8178. result.push(i);
  8179. }
  8180. }
  8181. return result;
  8182. },
  8183. getSelectedCount: function(){
  8184. var c = 0;
  8185. for(var i=0; i<this.selected.length; i++){
  8186. if(this.selected[i]){
  8187. c++;
  8188. }
  8189. }
  8190. return c;
  8191. },
  8192. _beginUpdate: function(){
  8193. if(this.updating === 0){
  8194. this.onChanging();
  8195. }
  8196. this.updating++;
  8197. },
  8198. _endUpdate: function(){
  8199. this.updating--;
  8200. if(this.updating === 0){
  8201. this.onChanged();
  8202. }
  8203. },
  8204. select: function(inIndex){
  8205. if(this.mode == 'none'){ return; }
  8206. if(this.mode != 'multiple'){
  8207. this.deselectAll(inIndex);
  8208. this.addToSelection(inIndex);
  8209. }else{
  8210. this.toggleSelect(inIndex);
  8211. }
  8212. },
  8213. addToSelection: function(inIndex){
  8214. if(this.mode == 'none'){ return; }
  8215. if(lang.isArray(inIndex)){
  8216. array.forEach(inIndex, this.addToSelection, this);
  8217. return;
  8218. }
  8219. inIndex = Number(inIndex);
  8220. if(this.selected[inIndex]){
  8221. this.selectedIndex = inIndex;
  8222. }else{
  8223. if(this.onCanSelect(inIndex) !== false){
  8224. this.selectedIndex = inIndex;
  8225. var rowNode = this.grid.getRowNode(inIndex);
  8226. if(rowNode){
  8227. domAttr.set(rowNode, "aria-selected", "true");
  8228. }
  8229. this._beginUpdate();
  8230. this.selected[inIndex] = true;
  8231. //this.grid.onSelected(inIndex);
  8232. this.onSelected(inIndex);
  8233. //this.onSetSelected(inIndex, true);
  8234. this._endUpdate();
  8235. }
  8236. }
  8237. },
  8238. deselect: function(inIndex){
  8239. if(this.mode == 'none'){ return; }
  8240. if(lang.isArray(inIndex)){
  8241. array.forEach(inIndex, this.deselect, this);
  8242. return;
  8243. }
  8244. inIndex = Number(inIndex);
  8245. if(this.selectedIndex == inIndex){
  8246. this.selectedIndex = -1;
  8247. }
  8248. if(this.selected[inIndex]){
  8249. if(this.onCanDeselect(inIndex) === false){
  8250. return;
  8251. }
  8252. var rowNode = this.grid.getRowNode(inIndex);
  8253. if(rowNode){
  8254. domAttr.set(rowNode, "aria-selected", "false");
  8255. }
  8256. this._beginUpdate();
  8257. delete this.selected[inIndex];
  8258. //this.grid.onDeselected(inIndex);
  8259. this.onDeselected(inIndex);
  8260. //this.onSetSelected(inIndex, false);
  8261. this._endUpdate();
  8262. }
  8263. },
  8264. setSelected: function(inIndex, inSelect){
  8265. this[(inSelect ? 'addToSelection' : 'deselect')](inIndex);
  8266. },
  8267. toggleSelect: function(inIndex){
  8268. if(lang.isArray(inIndex)){
  8269. array.forEach(inIndex, this.toggleSelect, this);
  8270. return;
  8271. }
  8272. this.setSelected(inIndex, !this.selected[inIndex]);
  8273. },
  8274. _range: function(inFrom, inTo, func){
  8275. var s = (inFrom >= 0 ? inFrom : inTo), e = inTo;
  8276. if(s > e){
  8277. e = s;
  8278. s = inTo;
  8279. }
  8280. for(var i=s; i<=e; i++){
  8281. func(i);
  8282. }
  8283. },
  8284. selectRange: function(inFrom, inTo){
  8285. this._range(inFrom, inTo, lang.hitch(this, "addToSelection"));
  8286. },
  8287. deselectRange: function(inFrom, inTo){
  8288. this._range(inFrom, inTo, lang.hitch(this, "deselect"));
  8289. },
  8290. insert: function(inIndex){
  8291. this.selected.splice(inIndex, 0, false);
  8292. if(this.selectedIndex >= inIndex){
  8293. this.selectedIndex++;
  8294. }
  8295. },
  8296. remove: function(inIndex){
  8297. this.selected.splice(inIndex, 1);
  8298. if(this.selectedIndex >= inIndex){
  8299. this.selectedIndex--;
  8300. }
  8301. },
  8302. deselectAll: function(inExcept){
  8303. for(var i in this.selected){
  8304. if((i!=inExcept)&&(this.selected[i]===true)){
  8305. this.deselect(i);
  8306. }
  8307. }
  8308. },
  8309. clickSelect: function(inIndex, inCtrlKey, inShiftKey){
  8310. if(this.mode == 'none'){ return; }
  8311. this._beginUpdate();
  8312. if(this.mode != 'extended'){
  8313. this.select(inIndex);
  8314. }else{
  8315. var lastSelected = this.selectedIndex;
  8316. if(!inCtrlKey){
  8317. this.deselectAll(inIndex);
  8318. }
  8319. if(inShiftKey){
  8320. this.selectRange(lastSelected, inIndex);
  8321. }else if(inCtrlKey){
  8322. this.toggleSelect(inIndex);
  8323. }else{
  8324. this.addToSelection(inIndex);
  8325. }
  8326. }
  8327. this._endUpdate();
  8328. },
  8329. clickSelectEvent: function(e){
  8330. this.clickSelect(e.rowIndex, dojo.isCopyKey(e), e.shiftKey);
  8331. },
  8332. clear: function(){
  8333. this._beginUpdate();
  8334. this.deselectAll();
  8335. this._endUpdate();
  8336. }
  8337. });
  8338. });
  8339. },
  8340. 'dijit/form/MappedTextBox':function(){
  8341. define("dijit/form/MappedTextBox", [
  8342. "dojo/_base/declare", // declare
  8343. "dojo/dom-construct", // domConstruct.place
  8344. "./ValidationTextBox"
  8345. ], function(declare, domConstruct, ValidationTextBox){
  8346. /*=====
  8347. var ValidationTextBox = dijit.form.ValidationTextBox;
  8348. =====*/
  8349. // module:
  8350. // dijit/form/MappedTextBox
  8351. // summary:
  8352. // A dijit.form.ValidationTextBox subclass which provides a base class for widgets that have
  8353. // a visible formatted display value, and a serializable
  8354. // value in a hidden input field which is actually sent to the server.
  8355. return declare("dijit.form.MappedTextBox", ValidationTextBox, {
  8356. // summary:
  8357. // A dijit.form.ValidationTextBox subclass which provides a base class for widgets that have
  8358. // a visible formatted display value, and a serializable
  8359. // value in a hidden input field which is actually sent to the server.
  8360. // description:
  8361. // The visible display may
  8362. // be locale-dependent and interactive. The value sent to the server is stored in a hidden
  8363. // input field which uses the `name` attribute declared by the original widget. That value sent
  8364. // to the server is defined by the dijit.form.MappedTextBox.serialize method and is typically
  8365. // locale-neutral.
  8366. // tags:
  8367. // protected
  8368. postMixInProperties: function(){
  8369. this.inherited(arguments);
  8370. // we want the name attribute to go to the hidden <input>, not the displayed <input>,
  8371. // so override _FormWidget.postMixInProperties() setting of nameAttrSetting
  8372. this.nameAttrSetting = "";
  8373. },
  8374. // Override default behavior to assign name to focusNode
  8375. _setNameAttr: null,
  8376. serialize: function(val /*=====, options =====*/){
  8377. // summary:
  8378. // Overridable function used to convert the get('value') result to a canonical
  8379. // (non-localized) string. For example, will print dates in ISO format, and
  8380. // numbers the same way as they are represented in javascript.
  8381. // val: anything
  8382. // options: Object?
  8383. // tags:
  8384. // protected extension
  8385. return val.toString ? val.toString() : ""; // String
  8386. },
  8387. toString: function(){
  8388. // summary:
  8389. // Returns widget as a printable string using the widget's value
  8390. // tags:
  8391. // protected
  8392. var val = this.filter(this.get('value')); // call filter in case value is nonstring and filter has been customized
  8393. return val != null ? (typeof val == "string" ? val : this.serialize(val, this.constraints)) : ""; // String
  8394. },
  8395. validate: function(){
  8396. // Overrides `dijit.form.TextBox.validate`
  8397. this.valueNode.value = this.toString();
  8398. return this.inherited(arguments);
  8399. },
  8400. buildRendering: function(){
  8401. // Overrides `dijit._TemplatedMixin.buildRendering`
  8402. this.inherited(arguments);
  8403. // Create a hidden <input> node with the serialized value used for submit
  8404. // (as opposed to the displayed value).
  8405. // Passing in name as markup rather than calling domConstruct.create() with an attrs argument
  8406. // to make query(input[name=...]) work on IE. (see #8660)
  8407. this.valueNode = domConstruct.place("<input type='hidden'" + (this.name ? " name='" + this.name.replace(/'/g, "&quot;") + "'" : "") + "/>", this.textbox, "after");
  8408. },
  8409. reset: function(){
  8410. // Overrides `dijit.form.ValidationTextBox.reset` to
  8411. // reset the hidden textbox value to ''
  8412. this.valueNode.value = '';
  8413. this.inherited(arguments);
  8414. }
  8415. });
  8416. });
  8417. },
  8418. 'dijit/form/ComboBoxMixin':function(){
  8419. require({cache:{
  8420. 'url:dijit/form/templates/DropDownBox.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\"\r\n\tid=\"widget_${id}\"\r\n\trole=\"combobox\"\r\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\r\n\t\tdata-dojo-attach-point=\"_buttonNode, _popupStateNode\" role=\"presentation\"\r\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t\t${_buttonInputDisabled}\r\n\t/></div\r\n\t><div class='dijitReset dijitValidationContainer'\r\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t/></div\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\r\n\t\t\tdata-dojo-attach-point=\"textbox,focusNode\" role=\"textbox\" aria-haspopup=\"true\"\r\n\t/></div\r\n></div>\r\n"}});
  8421. define("dijit/form/ComboBoxMixin", [
  8422. "dojo/_base/declare", // declare
  8423. "dojo/_base/Deferred",
  8424. "dojo/_base/kernel", // kernel.deprecated
  8425. "dojo/_base/lang", // lang.mixin
  8426. "dojo/store/util/QueryResults", // dojo.store.util.QueryResults
  8427. "./_AutoCompleterMixin",
  8428. "./_ComboBoxMenu",
  8429. "../_HasDropDown",
  8430. "dojo/text!./templates/DropDownBox.html"
  8431. ], function(declare, Deferred, kernel, lang, QueryResults, _AutoCompleterMixin, _ComboBoxMenu, _HasDropDown, template){
  8432. /*=====
  8433. var _AutoCompleterMixin = dijit.form._AutoCompleterMixin;
  8434. var _ComboBoxMenu = dijit.form._ComboBoxMenu;
  8435. var _HasDropDown = dijit._HasDropDown;
  8436. =====*/
  8437. // module:
  8438. // dijit/form/ComboBoxMixin
  8439. // summary:
  8440. // Provides main functionality of ComboBox widget
  8441. return declare("dijit.form.ComboBoxMixin", [_HasDropDown, _AutoCompleterMixin], {
  8442. // summary:
  8443. // Provides main functionality of ComboBox widget
  8444. // dropDownClass: [protected extension] Function String
  8445. // Dropdown widget class used to select a date/time.
  8446. // Subclasses should specify this.
  8447. dropDownClass: _ComboBoxMenu,
  8448. // hasDownArrow: Boolean
  8449. // Set this textbox to have a down arrow button, to display the drop down list.
  8450. // Defaults to true.
  8451. hasDownArrow: true,
  8452. templateString: template,
  8453. baseClass: "dijitTextBox dijitComboBox",
  8454. /*=====
  8455. // store: [const] dojo.store.api.Store || dojo.data.api.Read
  8456. // Reference to data provider object used by this ComboBox.
  8457. //
  8458. // Should be dojo.store.api.Store, but dojo.data.api.Read supported
  8459. // for backwards compatibility.
  8460. store: null,
  8461. =====*/
  8462. // Set classes like dijitDownArrowButtonHover depending on
  8463. // mouse action over button node
  8464. cssStateNodes: {
  8465. "_buttonNode": "dijitDownArrowButton"
  8466. },
  8467. _setHasDownArrowAttr: function(/*Boolean*/ val){
  8468. this._set("hasDownArrow", val);
  8469. this._buttonNode.style.display = val ? "" : "none";
  8470. },
  8471. _showResultList: function(){
  8472. // hide the tooltip
  8473. this.displayMessage("");
  8474. this.inherited(arguments);
  8475. },
  8476. _setStoreAttr: function(store){
  8477. // For backwards-compatibility, accept dojo.data store in addition to dojo.store.store. Remove in 2.0.
  8478. if(!store.get){
  8479. lang.mixin(store, {
  8480. _oldAPI: true,
  8481. get: function(id){
  8482. // summary:
  8483. // Retrieves an object by it's identity. This will trigger a fetchItemByIdentity.
  8484. // Like dojo.store.DataStore.get() except returns native item.
  8485. var deferred = new Deferred();
  8486. this.fetchItemByIdentity({
  8487. identity: id,
  8488. onItem: function(object){
  8489. deferred.resolve(object);
  8490. },
  8491. onError: function(error){
  8492. deferred.reject(error);
  8493. }
  8494. });
  8495. return deferred.promise;
  8496. },
  8497. query: function(query, options){
  8498. // summary:
  8499. // Queries the store for objects. Like dojo.store.DataStore.query()
  8500. // except returned Deferred contains array of native items.
  8501. var deferred = new Deferred(function(){ fetchHandle.abort && fetchHandle.abort(); });
  8502. var fetchHandle = this.fetch(lang.mixin({
  8503. query: query,
  8504. onBegin: function(count){
  8505. deferred.total = count;
  8506. },
  8507. onComplete: function(results){
  8508. deferred.resolve(results);
  8509. },
  8510. onError: function(error){
  8511. deferred.reject(error);
  8512. }
  8513. }, options));
  8514. return QueryResults(deferred);
  8515. }
  8516. });
  8517. }
  8518. this._set("store", store);
  8519. },
  8520. postMixInProperties: function(){
  8521. // Since _setValueAttr() depends on this.store, _setStoreAttr() needs to execute first.
  8522. // Unfortunately, without special code, it ends up executing second.
  8523. if(this.params.store){
  8524. this._setStoreAttr(this.params.store);
  8525. }
  8526. this.inherited(arguments);
  8527. // User may try to access this.store.getValue() etc. in a custom labelFunc() function.
  8528. // It's not available with the new data store for handling inline <option> tags, so add it.
  8529. if(!this.params.store){
  8530. var clazz = this.declaredClass;
  8531. lang.mixin(this.store, {
  8532. getValue: function(item, attr){
  8533. kernel.deprecated(clazz + ".store.getValue(item, attr) is deprecated for builtin store. Use item.attr directly", "", "2.0");
  8534. return item[attr];
  8535. },
  8536. getLabel: function(item){
  8537. kernel.deprecated(clazz + ".store.getLabel(item) is deprecated for builtin store. Use item.label directly", "", "2.0");
  8538. return item.name;
  8539. },
  8540. fetch: function(args){
  8541. kernel.deprecated(clazz + ".store.fetch() is deprecated for builtin store.", "Use store.query()", "2.0");
  8542. var shim = ["dojo/data/ObjectStore"]; // indirection so it doesn't get rolled into a build
  8543. require(shim, lang.hitch(this, function(ObjectStore){
  8544. new ObjectStore({objectStore: this}).fetch(args);
  8545. }));
  8546. }
  8547. });
  8548. }
  8549. }
  8550. });
  8551. });
  8552. },
  8553. 'dijit/form/_TextBoxMixin':function(){
  8554. define("dijit/form/_TextBoxMixin", [
  8555. "dojo/_base/array", // array.forEach
  8556. "dojo/_base/declare", // declare
  8557. "dojo/dom", // dom.byId
  8558. "dojo/_base/event", // event.stop
  8559. "dojo/keys", // keys.ALT keys.CAPS_LOCK keys.CTRL keys.META keys.SHIFT
  8560. "dojo/_base/lang", // lang.mixin
  8561. ".." // for exporting dijit._setSelectionRange, dijit.selectInputText
  8562. ], function(array, declare, dom, event, keys, lang, dijit){
  8563. // module:
  8564. // dijit/form/_TextBoxMixin
  8565. // summary:
  8566. // A mixin for textbox form input widgets
  8567. var _TextBoxMixin = declare("dijit.form._TextBoxMixin", null, {
  8568. // summary:
  8569. // A mixin for textbox form input widgets
  8570. // trim: Boolean
  8571. // Removes leading and trailing whitespace if true. Default is false.
  8572. trim: false,
  8573. // uppercase: Boolean
  8574. // Converts all characters to uppercase if true. Default is false.
  8575. uppercase: false,
  8576. // lowercase: Boolean
  8577. // Converts all characters to lowercase if true. Default is false.
  8578. lowercase: false,
  8579. // propercase: Boolean
  8580. // Converts the first character of each word to uppercase if true.
  8581. propercase: false,
  8582. // maxLength: String
  8583. // HTML INPUT tag maxLength declaration.
  8584. maxLength: "",
  8585. // selectOnClick: [const] Boolean
  8586. // If true, all text will be selected when focused with mouse
  8587. selectOnClick: false,
  8588. // placeHolder: String
  8589. // Defines a hint to help users fill out the input field (as defined in HTML 5).
  8590. // This should only contain plain text (no html markup).
  8591. placeHolder: "",
  8592. _getValueAttr: function(){
  8593. // summary:
  8594. // Hook so get('value') works as we like.
  8595. // description:
  8596. // For `dijit.form.TextBox` this basically returns the value of the <input>.
  8597. //
  8598. // For `dijit.form.MappedTextBox` subclasses, which have both
  8599. // a "displayed value" and a separate "submit value",
  8600. // This treats the "displayed value" as the master value, computing the
  8601. // submit value from it via this.parse().
  8602. return this.parse(this.get('displayedValue'), this.constraints);
  8603. },
  8604. _setValueAttr: function(value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
  8605. // summary:
  8606. // Hook so set('value', ...) works.
  8607. //
  8608. // description:
  8609. // Sets the value of the widget to "value" which can be of
  8610. // any type as determined by the widget.
  8611. //
  8612. // value:
  8613. // The visual element value is also set to a corresponding,
  8614. // but not necessarily the same, value.
  8615. //
  8616. // formattedValue:
  8617. // If specified, used to set the visual element value,
  8618. // otherwise a computed visual value is used.
  8619. //
  8620. // priorityChange:
  8621. // If true, an onChange event is fired immediately instead of
  8622. // waiting for the next blur event.
  8623. var filteredValue;
  8624. if(value !== undefined){
  8625. // TODO: this is calling filter() on both the display value and the actual value.
  8626. // I added a comment to the filter() definition about this, but it should be changed.
  8627. filteredValue = this.filter(value);
  8628. if(typeof formattedValue != "string"){
  8629. if(filteredValue !== null && ((typeof filteredValue != "number") || !isNaN(filteredValue))){
  8630. formattedValue = this.filter(this.format(filteredValue, this.constraints));
  8631. }else{ formattedValue = ''; }
  8632. }
  8633. }
  8634. if(formattedValue != null && formattedValue != undefined && ((typeof formattedValue) != "number" || !isNaN(formattedValue)) && this.textbox.value != formattedValue){
  8635. this.textbox.value = formattedValue;
  8636. this._set("displayedValue", this.get("displayedValue"));
  8637. }
  8638. if(this.textDir == "auto"){
  8639. this.applyTextDir(this.focusNode, formattedValue);
  8640. }
  8641. this.inherited(arguments, [filteredValue, priorityChange]);
  8642. },
  8643. // displayedValue: String
  8644. // For subclasses like ComboBox where the displayed value
  8645. // (ex: Kentucky) and the serialized value (ex: KY) are different,
  8646. // this represents the displayed value.
  8647. //
  8648. // Setting 'displayedValue' through set('displayedValue', ...)
  8649. // updates 'value', and vice-versa. Otherwise 'value' is updated
  8650. // from 'displayedValue' periodically, like onBlur etc.
  8651. //
  8652. // TODO: move declaration to MappedTextBox?
  8653. // Problem is that ComboBox references displayedValue,
  8654. // for benefit of FilteringSelect.
  8655. displayedValue: "",
  8656. _getDisplayedValueAttr: function(){
  8657. // summary:
  8658. // Hook so get('displayedValue') works.
  8659. // description:
  8660. // Returns the displayed value (what the user sees on the screen),
  8661. // after filtering (ie, trimming spaces etc.).
  8662. //
  8663. // For some subclasses of TextBox (like ComboBox), the displayed value
  8664. // is different from the serialized value that's actually
  8665. // sent to the server (see dijit.form.ValidationTextBox.serialize)
  8666. // TODO: maybe we should update this.displayedValue on every keystroke so that we don't need
  8667. // this method
  8668. // TODO: this isn't really the displayed value when the user is typing
  8669. return this.filter(this.textbox.value);
  8670. },
  8671. _setDisplayedValueAttr: function(/*String*/ value){
  8672. // summary:
  8673. // Hook so set('displayedValue', ...) works.
  8674. // description:
  8675. // Sets the value of the visual element to the string "value".
  8676. // The widget value is also set to a corresponding,
  8677. // but not necessarily the same, value.
  8678. if(value === null || value === undefined){ value = '' }
  8679. else if(typeof value != "string"){ value = String(value) }
  8680. this.textbox.value = value;
  8681. // sets the serialized value to something corresponding to specified displayedValue
  8682. // (if possible), and also updates the textbox.value, for example converting "123"
  8683. // to "123.00"
  8684. this._setValueAttr(this.get('value'), undefined);
  8685. this._set("displayedValue", this.get('displayedValue'));
  8686. // textDir support
  8687. if(this.textDir == "auto"){
  8688. this.applyTextDir(this.focusNode, value);
  8689. }
  8690. },
  8691. format: function(value /*=====, constraints =====*/){
  8692. // summary:
  8693. // Replaceable function to convert a value to a properly formatted string.
  8694. // value: String
  8695. // constraints: Object
  8696. // tags:
  8697. // protected extension
  8698. return ((value == null || value == undefined) ? "" : (value.toString ? value.toString() : value));
  8699. },
  8700. parse: function(value /*=====, constraints =====*/){
  8701. // summary:
  8702. // Replaceable function to convert a formatted string to a value
  8703. // value: String
  8704. // constraints: Object
  8705. // tags:
  8706. // protected extension
  8707. return value; // String
  8708. },
  8709. _refreshState: function(){
  8710. // summary:
  8711. // After the user types some characters, etc., this method is
  8712. // called to check the field for validity etc. The base method
  8713. // in `dijit.form.TextBox` does nothing, but subclasses override.
  8714. // tags:
  8715. // protected
  8716. },
  8717. /*=====
  8718. onInput: function(event){
  8719. // summary:
  8720. // Connect to this function to receive notifications of various user data-input events.
  8721. // Return false to cancel the event and prevent it from being processed.
  8722. // event:
  8723. // keydown | keypress | cut | paste | input
  8724. // tags:
  8725. // callback
  8726. },
  8727. =====*/
  8728. onInput: function(){},
  8729. __skipInputEvent: false,
  8730. _onInput: function(){
  8731. // summary:
  8732. // Called AFTER the input event has happened
  8733. // set text direction according to textDir that was defined in creation
  8734. if(this.textDir == "auto"){
  8735. this.applyTextDir(this.focusNode, this.focusNode.value);
  8736. }
  8737. this._refreshState();
  8738. // In case someone is watch()'ing for changes to displayedValue
  8739. this._set("displayedValue", this.get("displayedValue"));
  8740. },
  8741. postCreate: function(){
  8742. // setting the value here is needed since value="" in the template causes "undefined"
  8743. // and setting in the DOM (instead of the JS object) helps with form reset actions
  8744. this.textbox.setAttribute("value", this.textbox.value); // DOM and JS values should be the same
  8745. this.inherited(arguments);
  8746. // normalize input events to reduce spurious event processing
  8747. // onkeydown: do not forward modifier keys
  8748. // set charOrCode to numeric keycode
  8749. // onkeypress: do not forward numeric charOrCode keys (already sent through onkeydown)
  8750. // onpaste & oncut: set charOrCode to 229 (IME)
  8751. // oninput: if primary event not already processed, set charOrCode to 229 (IME), else do not forward
  8752. var handleEvent = function(e){
  8753. var charCode = e.charOrCode || e.keyCode || 229;
  8754. if(e.type == "keydown"){
  8755. switch(charCode){ // ignore "state" keys
  8756. case keys.SHIFT:
  8757. case keys.ALT:
  8758. case keys.CTRL:
  8759. case keys.META:
  8760. case keys.CAPS_LOCK:
  8761. return;
  8762. default:
  8763. if(charCode >= 65 && charCode <= 90){ return; } // keydown for A-Z can be processed with keypress
  8764. }
  8765. }
  8766. if(e.type == "keypress" && typeof charCode != "string"){ return; }
  8767. if(e.type == "input"){
  8768. if(this.__skipInputEvent){ // duplicate event
  8769. this.__skipInputEvent = false;
  8770. return;
  8771. }
  8772. }else{
  8773. this.__skipInputEvent = true;
  8774. }
  8775. // create fake event to set charOrCode and to know if preventDefault() was called
  8776. var faux = lang.mixin({}, e, {
  8777. charOrCode: charCode,
  8778. wasConsumed: false,
  8779. preventDefault: function(){
  8780. faux.wasConsumed = true;
  8781. e.preventDefault();
  8782. },
  8783. stopPropagation: function(){ e.stopPropagation(); }
  8784. });
  8785. // give web page author a chance to consume the event
  8786. if(this.onInput(faux) === false){
  8787. event.stop(faux); // return false means stop
  8788. }
  8789. if(faux.wasConsumed){ return; } // if preventDefault was called
  8790. setTimeout(lang.hitch(this, "_onInput", faux), 0); // widget notification after key has posted
  8791. };
  8792. array.forEach([ "onkeydown", "onkeypress", "onpaste", "oncut", "oninput", "oncompositionend" ], function(event){
  8793. this.connect(this.textbox, event, handleEvent);
  8794. }, this);
  8795. },
  8796. _blankValue: '', // if the textbox is blank, what value should be reported
  8797. filter: function(val){
  8798. // summary:
  8799. // Auto-corrections (such as trimming) that are applied to textbox
  8800. // value on blur or form submit.
  8801. // description:
  8802. // For MappedTextBox subclasses, this is called twice
  8803. // - once with the display value
  8804. // - once the value as set/returned by set('value', ...)
  8805. // and get('value'), ex: a Number for NumberTextBox.
  8806. //
  8807. // In the latter case it does corrections like converting null to NaN. In
  8808. // the former case the NumberTextBox.filter() method calls this.inherited()
  8809. // to execute standard trimming code in TextBox.filter().
  8810. //
  8811. // TODO: break this into two methods in 2.0
  8812. //
  8813. // tags:
  8814. // protected extension
  8815. if(val === null){ return this._blankValue; }
  8816. if(typeof val != "string"){ return val; }
  8817. if(this.trim){
  8818. val = lang.trim(val);
  8819. }
  8820. if(this.uppercase){
  8821. val = val.toUpperCase();
  8822. }
  8823. if(this.lowercase){
  8824. val = val.toLowerCase();
  8825. }
  8826. if(this.propercase){
  8827. val = val.replace(/[^\s]+/g, function(word){
  8828. return word.substring(0,1).toUpperCase() + word.substring(1);
  8829. });
  8830. }
  8831. return val;
  8832. },
  8833. _setBlurValue: function(){
  8834. this._setValueAttr(this.get('value'), true);
  8835. },
  8836. _onBlur: function(e){
  8837. if(this.disabled){ return; }
  8838. this._setBlurValue();
  8839. this.inherited(arguments);
  8840. if(this._selectOnClickHandle){
  8841. this.disconnect(this._selectOnClickHandle);
  8842. }
  8843. },
  8844. _isTextSelected: function(){
  8845. return this.textbox.selectionStart == this.textbox.selectionEnd;
  8846. },
  8847. _onFocus: function(/*String*/ by){
  8848. if(this.disabled || this.readOnly){ return; }
  8849. // Select all text on focus via click if nothing already selected.
  8850. // Since mouse-up will clear the selection need to defer selection until after mouse-up.
  8851. // Don't do anything on focus by tabbing into the widget since there's no associated mouse-up event.
  8852. if(this.selectOnClick && by == "mouse"){
  8853. this._selectOnClickHandle = this.connect(this.domNode, "onmouseup", function(){
  8854. // Only select all text on first click; otherwise users would have no way to clear
  8855. // the selection.
  8856. this.disconnect(this._selectOnClickHandle);
  8857. // Check if the user selected some text manually (mouse-down, mouse-move, mouse-up)
  8858. // and if not, then select all the text
  8859. if(this._isTextSelected()){
  8860. _TextBoxMixin.selectInputText(this.textbox);
  8861. }
  8862. });
  8863. }
  8864. // call this.inherited() before refreshState(), since this.inherited() will possibly scroll the viewport
  8865. // (to scroll the TextBox into view), which will affect how _refreshState() positions the tooltip
  8866. this.inherited(arguments);
  8867. this._refreshState();
  8868. },
  8869. reset: function(){
  8870. // Overrides dijit._FormWidget.reset().
  8871. // Additionally resets the displayed textbox value to ''
  8872. this.textbox.value = '';
  8873. this.inherited(arguments);
  8874. },
  8875. _setTextDirAttr: function(/*String*/ textDir){
  8876. // summary:
  8877. // Setter for textDir.
  8878. // description:
  8879. // Users shouldn't call this function; they should be calling
  8880. // set('textDir', value)
  8881. // tags:
  8882. // private
  8883. // only if new textDir is different from the old one
  8884. // and on widgets creation.
  8885. if(!this._created
  8886. || this.textDir != textDir){
  8887. this._set("textDir", textDir);
  8888. // so the change of the textDir will take place immediately.
  8889. this.applyTextDir(this.focusNode, this.focusNode.value);
  8890. }
  8891. }
  8892. });
  8893. _TextBoxMixin._setSelectionRange = dijit._setSelectionRange = function(/*DomNode*/ element, /*Number?*/ start, /*Number?*/ stop){
  8894. if(element.setSelectionRange){
  8895. element.setSelectionRange(start, stop);
  8896. }
  8897. };
  8898. _TextBoxMixin.selectInputText = dijit.selectInputText = function(/*DomNode*/ element, /*Number?*/ start, /*Number?*/ stop){
  8899. // summary:
  8900. // Select text in the input element argument, from start (default 0), to stop (default end).
  8901. // TODO: use functions in _editor/selection.js?
  8902. element = dom.byId(element);
  8903. if(isNaN(start)){ start = 0; }
  8904. if(isNaN(stop)){ stop = element.value ? element.value.length : 0; }
  8905. try{
  8906. element.focus();
  8907. _TextBoxMixin._setSelectionRange(element, start, stop);
  8908. }catch(e){ /* squelch random errors (esp. on IE) from unexpected focus changes or DOM nodes being hidden */ }
  8909. };
  8910. return _TextBoxMixin;
  8911. });
  8912. },
  8913. 'dijit/_TimePicker':function(){
  8914. require({cache:{
  8915. 'url:dijit/templates/TimePicker.html':"<div id=\"widget_${id}\" class=\"dijitMenu\"\r\n ><div data-dojo-attach-point=\"upArrow\" class=\"dijitButtonNode dijitUpArrowButton\" data-dojo-attach-event=\"onmouseenter:_buttonMouse,onmouseleave:_buttonMouse\"\r\n\t\t><div class=\"dijitReset dijitInline dijitArrowButtonInner\" role=\"presentation\">&#160;</div\r\n\t\t><div class=\"dijitArrowButtonChar\">&#9650;</div></div\r\n ><div data-dojo-attach-point=\"timeMenu,focusNode\" data-dojo-attach-event=\"onclick:_onOptionSelected,onmouseover,onmouseout\"></div\r\n ><div data-dojo-attach-point=\"downArrow\" class=\"dijitButtonNode dijitDownArrowButton\" data-dojo-attach-event=\"onmouseenter:_buttonMouse,onmouseleave:_buttonMouse\"\r\n\t\t><div class=\"dijitReset dijitInline dijitArrowButtonInner\" role=\"presentation\">&#160;</div\r\n\t\t><div class=\"dijitArrowButtonChar\">&#9660;</div></div\r\n></div>\r\n"}});
  8916. define("dijit/_TimePicker", [
  8917. "dojo/_base/array", // array.forEach
  8918. "dojo/date", // date.compare
  8919. "dojo/date/locale", // locale.format
  8920. "dojo/date/stamp", // stamp.fromISOString stamp.toISOString
  8921. "dojo/_base/declare", // declare
  8922. "dojo/dom-class", // domClass.add domClass.contains domClass.toggle
  8923. "dojo/dom-construct", // domConstruct.create
  8924. "dojo/_base/event", // event.stop
  8925. "dojo/_base/kernel", // deprecated
  8926. "dojo/keys", // keys
  8927. "dojo/_base/lang", // lang.mixin
  8928. "dojo/_base/sniff", // has(...)
  8929. "dojo/query", // query
  8930. "./typematic",
  8931. "./_Widget",
  8932. "./_TemplatedMixin",
  8933. "./form/_FormValueWidget",
  8934. "dojo/text!./templates/TimePicker.html"
  8935. ], function(array, ddate, locale, stamp, declare, domClass, domConstruct, event, kernel, keys, lang, has, query,
  8936. typematic, _Widget, _TemplatedMixin, _FormValueWidget, template){
  8937. /*=====
  8938. var _Widget = dijit._Widget;
  8939. var _TemplatedMixin = dijit._TemplatedMixin;
  8940. var _FormValueWidget = dijit.form._FormValueWidget;
  8941. =====*/
  8942. // module:
  8943. // dijit/_TimePicker
  8944. // summary:
  8945. // A graphical time picker.
  8946. /*=====
  8947. declare(
  8948. "dijit._TimePicker.__Constraints",
  8949. locale.__FormatOptions,
  8950. {
  8951. // clickableIncrement: String
  8952. // See `dijit._TimePicker.clickableIncrement`
  8953. clickableIncrement: "T00:15:00",
  8954. // visibleIncrement: String
  8955. // See `dijit._TimePicker.visibleIncrement`
  8956. visibleIncrement: "T01:00:00",
  8957. // visibleRange: String
  8958. // See `dijit._TimePicker.visibleRange`
  8959. visibleRange: "T05:00:00"
  8960. }
  8961. );
  8962. =====*/
  8963. return declare("dijit._TimePicker", [_Widget, _TemplatedMixin], {
  8964. // summary:
  8965. // A graphical time picker.
  8966. // This widget is used internally by other widgets and is not available
  8967. // as a standalone widget due to lack of accessibility support.
  8968. templateString: template,
  8969. // baseClass: [protected] String
  8970. // The root className to use for the various states of this widget
  8971. baseClass: "dijitTimePicker",
  8972. // clickableIncrement: String
  8973. // ISO-8601 string representing the amount by which
  8974. // every clickable element in the time picker increases.
  8975. // Set in local time, without a time zone.
  8976. // Example: `T00:15:00` creates 15 minute increments
  8977. // Must divide dijit._TimePicker.visibleIncrement evenly
  8978. clickableIncrement: "T00:15:00",
  8979. // visibleIncrement: String
  8980. // ISO-8601 string representing the amount by which
  8981. // every element with a visible time in the time picker increases.
  8982. // Set in local time, without a time zone.
  8983. // Example: `T01:00:00` creates text in every 1 hour increment
  8984. visibleIncrement: "T01:00:00",
  8985. // visibleRange: String
  8986. // ISO-8601 string representing the range of this TimePicker.
  8987. // The TimePicker will only display times in this range.
  8988. // Example: `T05:00:00` displays 5 hours of options
  8989. visibleRange: "T05:00:00",
  8990. // value: String
  8991. // Date to display.
  8992. // Defaults to current time and date.
  8993. // Can be a Date object or an ISO-8601 string.
  8994. // If you specify the GMT time zone (`-01:00`),
  8995. // the time will be converted to the local time in the local time zone.
  8996. // Otherwise, the time is considered to be in the local time zone.
  8997. // If you specify the date and isDate is true, the date is used.
  8998. // Example: if your local time zone is `GMT -05:00`,
  8999. // `T10:00:00` becomes `T10:00:00-05:00` (considered to be local time),
  9000. // `T10:00:00-01:00` becomes `T06:00:00-05:00` (4 hour difference),
  9001. // `T10:00:00Z` becomes `T05:00:00-05:00` (5 hour difference between Zulu and local time)
  9002. // `yyyy-mm-ddThh:mm:ss` is the format to set the date and time
  9003. // Example: `2007-06-01T09:00:00`
  9004. value: new Date(),
  9005. _visibleIncrement:2,
  9006. _clickableIncrement:1,
  9007. _totalIncrements:10,
  9008. // constraints: dijit._TimePicker.__Constraints
  9009. // Specifies valid range of times (start time, end time)
  9010. constraints:{},
  9011. /*=====
  9012. serialize: function(val, options){
  9013. // summary:
  9014. // User overridable function used to convert the attr('value') result to a String
  9015. // val: Date
  9016. // The current value
  9017. // options: Object?
  9018. // tags:
  9019. // protected
  9020. },
  9021. =====*/
  9022. serialize: stamp.toISOString,
  9023. /*=====
  9024. // filterString: string
  9025. // The string to filter by
  9026. filterString: "",
  9027. =====*/
  9028. setValue: function(/*Date*/ value){
  9029. // summary:
  9030. // Deprecated. Used set('value') instead.
  9031. // tags:
  9032. // deprecated
  9033. kernel.deprecated("dijit._TimePicker:setValue() is deprecated. Use set('value', ...) instead.", "", "2.0");
  9034. this.set('value', value);
  9035. },
  9036. _setValueAttr: function(/*Date*/ date){
  9037. // summary:
  9038. // Hook so set('value', ...) works.
  9039. // description:
  9040. // Set the value of the TimePicker.
  9041. // Redraws the TimePicker around the new date.
  9042. // tags:
  9043. // protected
  9044. this._set("value", date);
  9045. this._showText();
  9046. },
  9047. _setFilterStringAttr: function(val){
  9048. // summary:
  9049. // Called by TimeTextBox to filter the values shown in my list
  9050. this._set("filterString", val);
  9051. this._showText();
  9052. },
  9053. isDisabledDate: function(/*===== dateObject, locale =====*/){
  9054. // summary:
  9055. // May be overridden to disable certain dates in the TimePicker e.g. `isDisabledDate=locale.isWeekend`
  9056. // dateObject: Date
  9057. // locale: String?
  9058. // type:
  9059. // extension
  9060. return false; // Boolean
  9061. },
  9062. _getFilteredNodes: function(/*number*/ start, /*number*/ maxNum, /*Boolean*/ before, /*DOMnode*/ lastNode){
  9063. // summary:
  9064. // Returns an array of nodes with the filter applied. At most maxNum nodes
  9065. // will be returned - but fewer may be returned as well. If the
  9066. // before parameter is set to true, then it will return the elements
  9067. // before the given index
  9068. // tags:
  9069. // private
  9070. var
  9071. nodes = [],
  9072. lastValue = lastNode ? lastNode.date : this._refDate,
  9073. n,
  9074. i = start,
  9075. max = this._maxIncrement + Math.abs(i),
  9076. chk = before ? -1 : 1,
  9077. dec = before ? 1 : 0,
  9078. inc = 1 - dec;
  9079. do{
  9080. i -= dec;
  9081. n = this._createOption(i);
  9082. if(n){
  9083. if((before && n.date > lastValue) || (!before && n.date < lastValue)){
  9084. break; // don't wrap
  9085. }
  9086. nodes[before ? "unshift" : "push"](n);
  9087. lastValue = n.date;
  9088. }
  9089. i += inc;
  9090. }while(nodes.length < maxNum && (i*chk) < max);
  9091. return nodes;
  9092. },
  9093. _showText: function(){
  9094. // summary:
  9095. // Displays the relevant choices in the drop down list
  9096. // tags:
  9097. // private
  9098. var fromIso = stamp.fromISOString;
  9099. this.timeMenu.innerHTML = "";
  9100. this._clickableIncrementDate=fromIso(this.clickableIncrement);
  9101. this._visibleIncrementDate=fromIso(this.visibleIncrement);
  9102. this._visibleRangeDate=fromIso(this.visibleRange);
  9103. // get the value of the increments and the range in seconds (since 00:00:00) to find out how many divs to create
  9104. var
  9105. sinceMidnight = function(/*Date*/ date){
  9106. return date.getHours() * 60 * 60 + date.getMinutes() * 60 + date.getSeconds();
  9107. },
  9108. clickableIncrementSeconds = sinceMidnight(this._clickableIncrementDate),
  9109. visibleIncrementSeconds = sinceMidnight(this._visibleIncrementDate),
  9110. visibleRangeSeconds = sinceMidnight(this._visibleRangeDate),
  9111. // round reference date to previous visible increment
  9112. time = (this.value || this.currentFocus).getTime();
  9113. this._refDate = new Date(time - time % (clickableIncrementSeconds*1000));
  9114. this._refDate.setFullYear(1970,0,1); // match parse defaults
  9115. // assume clickable increment is the smallest unit
  9116. this._clickableIncrement = 1;
  9117. // divide the visible range by the clickable increment to get the number of divs to create
  9118. // example: 10:00:00/00:15:00 -> display 40 divs
  9119. this._totalIncrements = visibleRangeSeconds / clickableIncrementSeconds;
  9120. // divide the visible increments by the clickable increments to get how often to display the time inline
  9121. // example: 01:00:00/00:15:00 -> display the time every 4 divs
  9122. this._visibleIncrement = visibleIncrementSeconds / clickableIncrementSeconds;
  9123. // divide the number of seconds in a day by the clickable increment in seconds to get the
  9124. // absolute max number of increments.
  9125. this._maxIncrement = (60 * 60 * 24) / clickableIncrementSeconds;
  9126. var
  9127. // Find the nodes we should display based on our filter.
  9128. // Limit to 10 nodes displayed as a half-hearted attempt to stop drop down from overlapping <input>.
  9129. count = Math.min(this._totalIncrements, 10),
  9130. after = this._getFilteredNodes(0, (count >> 1) + 1, false),
  9131. moreAfter = [],
  9132. estBeforeLength = count - after.length,
  9133. before = this._getFilteredNodes(0, estBeforeLength, true, after[0]);
  9134. if(before.length < estBeforeLength && after.length > 0){
  9135. moreAfter = this._getFilteredNodes(after.length, estBeforeLength - before.length, false, after[after.length-1]);
  9136. }
  9137. array.forEach(before.concat(after, moreAfter), function(n){ this.timeMenu.appendChild(n); }, this);
  9138. },
  9139. constructor: function(){
  9140. this.constraints = {}; // create instance object
  9141. },
  9142. postMixInProperties: function(){
  9143. this.inherited(arguments);
  9144. this._setConstraintsAttr(this.constraints); // this needs to happen now (and later) due to codependency on _set*Attr calls
  9145. },
  9146. _setConstraintsAttr: function(/* Object */ constraints){
  9147. // brings in visibleRange, increments, etc.
  9148. lang.mixin(this, constraints);
  9149. // locale needs the lang in the constraints as locale
  9150. if(!constraints.locale){
  9151. constraints.locale = this.lang;
  9152. }
  9153. },
  9154. postCreate: function(){
  9155. // assign typematic mouse listeners to the arrow buttons
  9156. this.connect(this.timeMenu, has("mozilla") ? 'DOMMouseScroll' : "onmousewheel", "_mouseWheeled");
  9157. this._connects.push(typematic.addMouseListener(this.upArrow, this, "_onArrowUp", 33, 250));
  9158. this._connects.push(typematic.addMouseListener(this.downArrow, this, "_onArrowDown", 33, 250));
  9159. this.inherited(arguments);
  9160. },
  9161. _buttonMouse: function(/*Event*/ e){
  9162. // summary:
  9163. // Handler for hover (and unhover) on up/down arrows
  9164. // tags:
  9165. // private
  9166. // in non-IE browser the "mouseenter" event will become "mouseover",
  9167. // but in IE it's still "mouseenter"
  9168. domClass.toggle(e.currentTarget, e.currentTarget == this.upArrow ? "dijitUpArrowHover" : "dijitDownArrowHover",
  9169. e.type == "mouseenter" || e.type == "mouseover");
  9170. },
  9171. _createOption: function(/*Number*/ index){
  9172. // summary:
  9173. // Creates a clickable time option
  9174. // tags:
  9175. // private
  9176. var date = new Date(this._refDate);
  9177. var incrementDate = this._clickableIncrementDate;
  9178. date.setTime(date.getTime()
  9179. + incrementDate.getHours() * index * 3600000
  9180. + incrementDate.getMinutes() * index * 60000
  9181. + incrementDate.getSeconds() * index * 1000);
  9182. if(this.constraints.selector == "time"){
  9183. date.setFullYear(1970,0,1); // make sure each time is for the same date
  9184. }
  9185. var dateString = locale.format(date, this.constraints);
  9186. if(this.filterString && dateString.toLowerCase().indexOf(this.filterString) !== 0){
  9187. // Doesn't match the filter - return null
  9188. return null;
  9189. }
  9190. var div = domConstruct.create("div", {"class": this.baseClass+"Item"});
  9191. div.date = date;
  9192. div.idx = index;
  9193. domConstruct.create('div',{
  9194. "class": this.baseClass + "ItemInner",
  9195. innerHTML: dateString
  9196. }, div);
  9197. if(index%this._visibleIncrement<1 && index%this._visibleIncrement>-1){
  9198. domClass.add(div, this.baseClass+"Marker");
  9199. }else if(!(index%this._clickableIncrement)){
  9200. domClass.add(div, this.baseClass+"Tick");
  9201. }
  9202. if(this.isDisabledDate(date)){
  9203. // set disabled
  9204. domClass.add(div, this.baseClass+"ItemDisabled");
  9205. }
  9206. if(this.value && !ddate.compare(this.value, date, this.constraints.selector)){
  9207. div.selected = true;
  9208. domClass.add(div, this.baseClass+"ItemSelected");
  9209. if(domClass.contains(div, this.baseClass+"Marker")){
  9210. domClass.add(div, this.baseClass+"MarkerSelected");
  9211. }else{
  9212. domClass.add(div, this.baseClass+"TickSelected");
  9213. }
  9214. // Initially highlight the current value. User can change highlight by up/down arrow keys
  9215. // or mouse movement.
  9216. this._highlightOption(div, true);
  9217. }
  9218. return div;
  9219. },
  9220. _onOptionSelected: function(/*Object*/ tgt){
  9221. // summary:
  9222. // Called when user clicks an option in the drop down list
  9223. // tags:
  9224. // private
  9225. var tdate = tgt.target.date || tgt.target.parentNode.date;
  9226. if(!tdate || this.isDisabledDate(tdate)){ return; }
  9227. this._highlighted_option = null;
  9228. this.set('value', tdate);
  9229. this.onChange(tdate);
  9230. },
  9231. onChange: function(/*Date*/ /*===== time =====*/){
  9232. // summary:
  9233. // Notification that a time was selected. It may be the same as the previous value.
  9234. // tags:
  9235. // public
  9236. },
  9237. _highlightOption: function(/*node*/ node, /*Boolean*/ highlight){
  9238. // summary:
  9239. // Turns on/off highlight effect on a node based on mouse out/over event
  9240. // tags:
  9241. // private
  9242. if(!node){return;}
  9243. if(highlight){
  9244. if(this._highlighted_option){
  9245. this._highlightOption(this._highlighted_option, false);
  9246. }
  9247. this._highlighted_option = node;
  9248. }else if(this._highlighted_option !== node){
  9249. return;
  9250. }else{
  9251. this._highlighted_option = null;
  9252. }
  9253. domClass.toggle(node, this.baseClass+"ItemHover", highlight);
  9254. if(domClass.contains(node, this.baseClass+"Marker")){
  9255. domClass.toggle(node, this.baseClass+"MarkerHover", highlight);
  9256. }else{
  9257. domClass.toggle(node, this.baseClass+"TickHover", highlight);
  9258. }
  9259. },
  9260. onmouseover: function(/*Event*/ e){
  9261. // summary:
  9262. // Handler for onmouseover event
  9263. // tags:
  9264. // private
  9265. this._keyboardSelected = null;
  9266. var tgr = (e.target.parentNode === this.timeMenu) ? e.target : e.target.parentNode;
  9267. // if we aren't targeting an item, then we return
  9268. if(!domClass.contains(tgr, this.baseClass+"Item")){return;}
  9269. this._highlightOption(tgr, true);
  9270. },
  9271. onmouseout: function(/*Event*/ e){
  9272. // summary:
  9273. // Handler for onmouseout event
  9274. // tags:
  9275. // private
  9276. this._keyboardSelected = null;
  9277. var tgr = (e.target.parentNode === this.timeMenu) ? e.target : e.target.parentNode;
  9278. this._highlightOption(tgr, false);
  9279. },
  9280. _mouseWheeled: function(/*Event*/ e){
  9281. // summary:
  9282. // Handle the mouse wheel events
  9283. // tags:
  9284. // private
  9285. this._keyboardSelected = null;
  9286. event.stop(e);
  9287. // we're not _measuring_ the scroll amount, just direction
  9288. var scrollAmount = has("mozilla") ? -e.detail : e.wheelDelta;
  9289. this[(scrollAmount>0 ? "_onArrowUp" : "_onArrowDown")](); // yes, we're making a new dom node every time you mousewheel, or click
  9290. },
  9291. _onArrowUp: function(count){
  9292. // summary:
  9293. // Handler for up arrow key.
  9294. // description:
  9295. // Removes the bottom time and add one to the top
  9296. // tags:
  9297. // private
  9298. if(count === -1){
  9299. domClass.remove(this.upArrow, "dijitUpArrowActive");
  9300. return;
  9301. }else if(count === 0){
  9302. domClass.add(this.upArrow, "dijitUpArrowActive");
  9303. } // typematic end
  9304. if(!this.timeMenu.childNodes.length){ return; }
  9305. var index = this.timeMenu.childNodes[0].idx;
  9306. var divs = this._getFilteredNodes(index, 1, true, this.timeMenu.childNodes[0]);
  9307. if(divs.length){
  9308. this.timeMenu.removeChild(this.timeMenu.childNodes[this.timeMenu.childNodes.length - 1]);
  9309. this.timeMenu.insertBefore(divs[0], this.timeMenu.childNodes[0]);
  9310. }
  9311. },
  9312. _onArrowDown: function(count){
  9313. // summary:
  9314. // Handler for up arrow key.
  9315. // description:
  9316. // Remove the top time and add one to the bottom
  9317. // tags:
  9318. // private
  9319. if(count === -1){
  9320. domClass.remove(this.downArrow, "dijitDownArrowActive");
  9321. return;
  9322. }else if(count === 0){
  9323. domClass.add(this.downArrow, "dijitDownArrowActive");
  9324. } // typematic end
  9325. if(!this.timeMenu.childNodes.length){ return; }
  9326. var index = this.timeMenu.childNodes[this.timeMenu.childNodes.length - 1].idx + 1;
  9327. var divs = this._getFilteredNodes(index, 1, false, this.timeMenu.childNodes[this.timeMenu.childNodes.length - 1]);
  9328. if(divs.length){
  9329. this.timeMenu.removeChild(this.timeMenu.childNodes[0]);
  9330. this.timeMenu.appendChild(divs[0]);
  9331. }
  9332. },
  9333. handleKey: function(/*Event*/ e){
  9334. // summary:
  9335. // Called from `dijit.form._DateTimeTextBox` to pass a keypress event
  9336. // from the `dijit.form.TimeTextBox` to be handled in this widget
  9337. // tags:
  9338. // protected
  9339. if(e.charOrCode == keys.DOWN_ARROW || e.charOrCode == keys.UP_ARROW){
  9340. event.stop(e);
  9341. // Figure out which option to highlight now and then highlight it
  9342. if(this._highlighted_option && !this._highlighted_option.parentNode){
  9343. this._highlighted_option = null;
  9344. }
  9345. var timeMenu = this.timeMenu,
  9346. tgt = this._highlighted_option || query("." + this.baseClass + "ItemSelected", timeMenu)[0];
  9347. if(!tgt){
  9348. tgt = timeMenu.childNodes[0];
  9349. }else if(timeMenu.childNodes.length){
  9350. if(e.charOrCode == keys.DOWN_ARROW && !tgt.nextSibling){
  9351. this._onArrowDown();
  9352. }else if(e.charOrCode == keys.UP_ARROW && !tgt.previousSibling){
  9353. this._onArrowUp();
  9354. }
  9355. if(e.charOrCode == keys.DOWN_ARROW){
  9356. tgt = tgt.nextSibling;
  9357. }else{
  9358. tgt = tgt.previousSibling;
  9359. }
  9360. }
  9361. this._highlightOption(tgt, true);
  9362. this._keyboardSelected = tgt;
  9363. return false;
  9364. }else if(e.charOrCode == keys.ENTER || e.charOrCode === keys.TAB){
  9365. // mouse hover followed by TAB is NO selection
  9366. if(!this._keyboardSelected && e.charOrCode === keys.TAB){
  9367. return true; // true means don't call stopEvent()
  9368. }
  9369. // Accept the currently-highlighted option as the value
  9370. if(this._highlighted_option){
  9371. this._onOptionSelected({target: this._highlighted_option});
  9372. }
  9373. // Call stopEvent() for ENTER key so that form doesn't submit,
  9374. // but not for TAB, so that TAB does switch focus
  9375. return e.charOrCode === keys.TAB;
  9376. }
  9377. return undefined;
  9378. }
  9379. });
  9380. });
  9381. },
  9382. '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\"\r\n\trole=\"presentation\"\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t\t><td data-dojo-attach-point=\"topDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationT dijitSliderDecorationH\"></td\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\r\n\t\t\t><div class=\"dijitSliderDecrementIconH\" style=\"display:none\" data-dojo-attach-point=\"decrementButton\"><span class=\"dijitSliderButtonInner\">-</span></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderLeftBumper\" data-dojo-attach-event=\"press:_onClkDecBumper\"></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><input data-dojo-attach-point=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\r\n\t\t\t/><div class=\"dijitReset dijitSliderBarContainerH\" role=\"presentation\" data-dojo-attach-point=\"sliderBarContainer\"\r\n\t\t\t\t><div role=\"presentation\" data-dojo-attach-point=\"progressBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderProgressBar dijitSliderProgressBarH\" data-dojo-attach-event=\"press:_onBarClick\"\r\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableH\"\r\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\r\n\t\t\t\t\t></div\r\n\t\t\t\t></div\r\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\r\n\t\t\t></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderRightBumper\" data-dojo-attach-event=\"press:_onClkIncBumper\"></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\r\n\t\t\t><div class=\"dijitSliderIncrementIconH\" style=\"display:none\" data-dojo-attach-point=\"incrementButton\"><span class=\"dijitSliderButtonInner\">+</span></div\r\n\t\t></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t\t><td data-dojo-attach-point=\"containerNode,bottomDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationB dijitSliderDecorationH\"></td\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t></tr\r\n></table>\r\n",
  9383. 'url:dijit/templates/TimePicker.html':"<div id=\"widget_${id}\" class=\"dijitMenu\"\r\n ><div data-dojo-attach-point=\"upArrow\" class=\"dijitButtonNode dijitUpArrowButton\" data-dojo-attach-event=\"onmouseenter:_buttonMouse,onmouseleave:_buttonMouse\"\r\n\t\t><div class=\"dijitReset dijitInline dijitArrowButtonInner\" role=\"presentation\">&#160;</div\r\n\t\t><div class=\"dijitArrowButtonChar\">&#9650;</div></div\r\n ><div data-dojo-attach-point=\"timeMenu,focusNode\" data-dojo-attach-event=\"onclick:_onOptionSelected,onmouseover,onmouseout\"></div\r\n ><div data-dojo-attach-point=\"downArrow\" class=\"dijitButtonNode dijitDownArrowButton\" data-dojo-attach-event=\"onmouseenter:_buttonMouse,onmouseleave:_buttonMouse\"\r\n\t\t><div class=\"dijitReset dijitInline dijitArrowButtonInner\" role=\"presentation\">&#160;</div\r\n\t\t><div class=\"dijitArrowButtonChar\">&#9660;</div></div\r\n></div>\r\n",
  9384. 'dijit/main':function(){
  9385. define("dijit/main", [
  9386. "dojo/_base/kernel"
  9387. ], function(dojo){
  9388. // module:
  9389. // dijit
  9390. // summary:
  9391. // The dijit package main module
  9392. return dojo.dijit;
  9393. });
  9394. },
  9395. 'dojox/grid/enhanced/_PluginManager':function(){
  9396. define("dojox/grid/enhanced/_PluginManager", [
  9397. "dojo/_base/kernel",
  9398. "dojo/_base/lang",
  9399. "dojo/_base/declare",
  9400. "dojo/_base/array",
  9401. "dojo/_base/connect",
  9402. "./_Events",
  9403. "./_FocusManager",
  9404. "../util"
  9405. ], function(dojo, lang, declare, array, connect, _Events, _FocusManager, util){
  9406. var _PluginManager = declare("dojox.grid.enhanced._PluginManager", null, {
  9407. // summary:
  9408. // Singleton plugin manager
  9409. //
  9410. // description:
  9411. // Plugin manager is responsible for
  9412. // 1. Loading required plugins
  9413. // 2. Handling collaborat ion and dependencies among plugins
  9414. //
  9415. // Some plugin dependencies:
  9416. // - "columnReordering" attribute won't work when either DnD or Indirect Selections plugin is on.
  9417. //_options: Object
  9418. // Normalized plugin options
  9419. _options: null,
  9420. //_plugins: Array
  9421. // Plugin list
  9422. _plugins: null,
  9423. //_connects: Array
  9424. // Connection list
  9425. _connects: null,
  9426. constructor: function(inGrid){
  9427. this.grid = inGrid;
  9428. this._store = inGrid.store;
  9429. this._options = {};
  9430. this._plugins = [];
  9431. this._connects = [];
  9432. this._parseProps(this.grid.plugins);
  9433. inGrid.connect(inGrid, "_setStore", lang.hitch(this, function(store){
  9434. if(this._store !== store){
  9435. this.forEach('onSetStore', [store, this._store]);
  9436. this._store = store;
  9437. }
  9438. }));
  9439. },
  9440. startup: function(){
  9441. this.forEach('onStartUp');
  9442. },
  9443. preInit: function(){
  9444. // summary:
  9445. // Load appropriate plugins before DataGrid.postCreate().
  9446. // See EnhancedGrid.postCreate()
  9447. this.grid.focus.destroy();
  9448. this.grid.focus = new _FocusManager(this.grid);
  9449. new _Events(this.grid);//overwrite some default events of DataGrid
  9450. this._init(true);
  9451. this.forEach('onPreInit');
  9452. },
  9453. postInit: function(){
  9454. // summary:
  9455. // Load plugins after DataGrid.postCreate() - the default phase when plugins are created
  9456. // See EnhancedGrid.postCreate()
  9457. this._init(false);
  9458. array.forEach(this.grid.views.views, this._initView, this);
  9459. this._connects.push(connect.connect(this.grid.views, 'addView', lang.hitch(this, this._initView)));
  9460. if(this._plugins.length > 0){
  9461. var edit = this.grid.edit;
  9462. if(edit){ edit.styleRow = function(inRow){}; }
  9463. }
  9464. this.forEach('onPostInit');
  9465. },
  9466. forEach: function(func, args){
  9467. array.forEach(this._plugins, function(p){
  9468. if(!p || !p[func]){ return; }
  9469. p[func].apply(p, args ? args : []);
  9470. });
  9471. },
  9472. _parseProps: function(plugins){
  9473. // summary:
  9474. // Parse plugins properties
  9475. // plugins: Object
  9476. // Plugin properties defined by user
  9477. if(!plugins){ return; }
  9478. var p, loading = {}, options = this._options, grid = this.grid;
  9479. var registry = _PluginManager.registry;//global plugin registry
  9480. for(p in plugins){
  9481. if(plugins[p]){//filter out boolean false e.g. {p:false}
  9482. this._normalize(p, plugins, registry, loading);
  9483. }
  9484. }
  9485. //"columnReordering" attribute won't work when either DnD or Indirect Selections plugin is used.
  9486. if(options.dnd || options.indirectSelection){
  9487. options.columnReordering = false;
  9488. }
  9489. //mixin all plugin properties into Grid
  9490. lang.mixin(grid, options);
  9491. },
  9492. _normalize: function(p, plugins, registry, loading){
  9493. // summary:
  9494. // Normalize plugin properties especially the dependency chain
  9495. // p: String
  9496. // Plugin name
  9497. // plugins: Object
  9498. // Plugin properties set by user
  9499. // registry: Object
  9500. // The global plugin registry
  9501. // loading: Object
  9502. // Map for checking process state
  9503. if(!registry[p]){ throw new Error('Plugin ' + p + ' is required.');}
  9504. if(loading[p]){ throw new Error('Recursive cycle dependency is not supported.'); }
  9505. var options = this._options;
  9506. if(options[p]){ return options[p]; }
  9507. loading[p] = true;
  9508. //TBD - more strict conditions?
  9509. options[p] = lang.mixin({}, registry[p], lang.isObject(plugins[p]) ? plugins[p] : {});
  9510. var dependencies = options[p]['dependency'];
  9511. if(dependencies){
  9512. if(!lang.isArray(dependencies)){
  9513. dependencies = options[p]['dependency'] = [dependencies];
  9514. }
  9515. array.forEach(dependencies, function(dependency){
  9516. if(!this._normalize(dependency, plugins, registry, loading)){
  9517. throw new Error('Plugin ' + dependency + ' is required.');
  9518. }
  9519. }, this);
  9520. }
  9521. delete loading[p];
  9522. return options[p];
  9523. },
  9524. _init: function(pre){
  9525. // summary:
  9526. // Find appropriate plugins and load them
  9527. // pre: Boolean
  9528. // True - preInit | False - postInit(by default)
  9529. var p, preInit, options = this._options;
  9530. for(p in options){
  9531. preInit = options[p]['preInit'];
  9532. if((pre ? preInit : !preInit) && options[p]['class'] && !this.pluginExisted(p)){
  9533. this.loadPlugin(p);
  9534. }
  9535. }
  9536. },
  9537. loadPlugin: function(name){
  9538. // summary:
  9539. // Load required plugin("name")
  9540. // name: String
  9541. // Plugin name
  9542. // return: Object
  9543. // The newly loaded plugin
  9544. var option = this._options[name];
  9545. if(!option){ return null; } //return if no plugin option
  9546. var plugin = this.getPlugin(name);
  9547. if(plugin){ return plugin; } //return if plugin("name") already existed
  9548. var dependencies = option['dependency'];
  9549. array.forEach(dependencies, function(dependency){
  9550. if(!this.loadPlugin(dependency)){
  9551. throw new Error('Plugin ' + dependency + ' is required.');
  9552. }
  9553. }, this);
  9554. var cls = option['class'];
  9555. delete option['class'];//remove it for safety
  9556. plugin = new this.getPluginClazz(cls)(this.grid, option);
  9557. this._plugins.push(plugin);
  9558. return plugin;
  9559. },
  9560. _initView: function(view){
  9561. // summary:
  9562. // Overwrite several default behavior for each views(including _RowSelector view)
  9563. if(!view){ return; }
  9564. //add more events handler - _View
  9565. util.funnelEvents(view.contentNode, view, "doContentEvent", ['mouseup', 'mousemove']);
  9566. util.funnelEvents(view.headerNode, view, "doHeaderEvent", ['mouseup']);
  9567. },
  9568. pluginExisted: function(name){
  9569. // summary:
  9570. // Check if plugin("name") existed
  9571. // name: String
  9572. // Plugin name
  9573. // return: Boolean
  9574. // True - existed | False - not existed
  9575. return !!this.getPlugin(name);
  9576. },
  9577. getPlugin: function(name){
  9578. // summary:
  9579. // Get plugin("name")
  9580. // name: String
  9581. // Plugin name
  9582. // return: Object
  9583. // Plugin instance
  9584. var plugins = this._plugins;
  9585. name = name.toLowerCase();
  9586. for(var i = 0, len = plugins.length; i < len; i++){
  9587. if(name == plugins[i]['name'].toLowerCase()){
  9588. return plugins[i];
  9589. }
  9590. }
  9591. return null;
  9592. },
  9593. getPluginClazz: function(clazz){
  9594. // summary:
  9595. // Load target plugin which must be already required (require(..))
  9596. // clazz: class | String
  9597. // Plugin class
  9598. if(lang.isFunction(clazz)){
  9599. return clazz;//return if it's already a clazz
  9600. }
  9601. var errorMsg = 'Please make sure Plugin "' + clazz + '" is existed.';
  9602. try{
  9603. var cls = lang.getObject(clazz);
  9604. if(!cls){ throw new Error(errorMsg); }
  9605. return cls;
  9606. }catch(e){
  9607. throw new Error(errorMsg);
  9608. }
  9609. },
  9610. isFixedCell: function(cell){
  9611. // summary:
  9612. // See if target cell(column) is fixed or not.
  9613. // cell: Object
  9614. // Target cell(column)
  9615. // return: Boolean
  9616. // True - fixed| False - not fixed
  9617. //target cell can use Boolean attributes named "isRowSelector" or "fixedPos" to mark it's a fixed cell(column)
  9618. return cell && (cell.isRowSelector || cell.fixedPos);
  9619. },
  9620. destroy: function(){
  9621. // summary:
  9622. // Destroy all resources
  9623. array.forEach(this._connects, connect.disconnect);
  9624. this.forEach('destroy');
  9625. if(this.grid.unwrap){
  9626. this.grid.unwrap();
  9627. }
  9628. delete this._connects;
  9629. delete this._plugins;
  9630. delete this._options;
  9631. }
  9632. });
  9633. _PluginManager.registerPlugin = function(clazz, props){
  9634. // summary:
  9635. // Register plugins - TODO, a better way rather than global registry?
  9636. // clazz: String
  9637. // Full class name, e.g. "dojox.grid.enhanced.plugins.DnD"
  9638. // props: Object - Optional
  9639. // Plugin properties e.g. {"dependency": ["nestedSorting"], ...}
  9640. if(!clazz){
  9641. console.warn("Failed to register plugin, class missed!");
  9642. return;
  9643. }
  9644. var cls = _PluginManager;
  9645. cls.registry = cls.registry || {};
  9646. cls.registry[clazz.prototype.name]/*plugin name*/ = lang.mixin({"class": clazz}, (props ? props : {}));
  9647. };
  9648. return _PluginManager;
  9649. });
  9650. },
  9651. 'dijit/_OnDijitClickMixin':function(){
  9652. define("dijit/_OnDijitClickMixin", [
  9653. "dojo/on",
  9654. "dojo/_base/array", // array.forEach
  9655. "dojo/keys", // keys.ENTER keys.SPACE
  9656. "dojo/_base/declare", // declare
  9657. "dojo/_base/sniff", // has("ie")
  9658. "dojo/_base/unload", // unload.addOnWindowUnload
  9659. "dojo/_base/window" // win.doc.addEventListener win.doc.attachEvent win.doc.detachEvent
  9660. ], function(on, array, keys, declare, has, unload, win){
  9661. // module:
  9662. // dijit/_OnDijitClickMixin
  9663. // summary:
  9664. // Mixin so you can pass "ondijitclick" to this.connect() method,
  9665. // as a way to handle clicks by mouse, or by keyboard (SPACE/ENTER key)
  9666. // Keep track of where the last keydown event was, to help avoid generating
  9667. // spurious ondijitclick events when:
  9668. // 1. focus is on a <button> or <a>
  9669. // 2. user presses then releases the ENTER key
  9670. // 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler
  9671. // 4. onkeyup event fires, causing the ondijitclick handler to fire
  9672. var lastKeyDownNode = null;
  9673. if(has("ie")){
  9674. (function(){
  9675. var keydownCallback = function(evt){
  9676. lastKeyDownNode = evt.srcElement;
  9677. };
  9678. win.doc.attachEvent('onkeydown', keydownCallback);
  9679. unload.addOnWindowUnload(function(){
  9680. win.doc.detachEvent('onkeydown', keydownCallback);
  9681. });
  9682. })();
  9683. }else{
  9684. win.doc.addEventListener('keydown', function(evt){
  9685. lastKeyDownNode = evt.target;
  9686. }, true);
  9687. }
  9688. // Custom a11yclick (a.k.a. ondijitclick) event
  9689. var a11yclick = function(node, listener){
  9690. if(/input|button/i.test(node.nodeName)){
  9691. // pass through, the browser already generates click event on SPACE/ENTER key
  9692. return on(node, "click", listener);
  9693. }else{
  9694. // Don't fire the click event unless both the keydown and keyup occur on this node.
  9695. // Avoids problems where focus shifted to this node or away from the node on keydown,
  9696. // either causing this node to process a stray keyup event, or causing another node
  9697. // to get a stray keyup event.
  9698. function clickKey(/*Event*/ e){
  9699. return (e.keyCode == keys.ENTER || e.keyCode == keys.SPACE) &&
  9700. !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey;
  9701. }
  9702. var handles = [
  9703. on(node, "keypress", function(e){
  9704. //console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode));
  9705. if(clickKey(e)){
  9706. // needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work
  9707. lastKeyDownNode = e.target;
  9708. // Prevent viewport scrolling on space key in IE<9.
  9709. // (Reproducible on test_Button.html on any of the first dijit.form.Button examples)
  9710. // Do this onkeypress rather than onkeydown because onkeydown.preventDefault() will
  9711. // suppress the onkeypress event, breaking _HasDropDown
  9712. e.preventDefault();
  9713. }
  9714. }),
  9715. on(node, "keyup", function(e){
  9716. //console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode));
  9717. if(clickKey(e) && e.target == lastKeyDownNode){ // === breaks greasemonkey
  9718. //need reset here or have problems in FF when focus returns to trigger element after closing popup/alert
  9719. lastKeyDownNode = null;
  9720. listener.call(this, e);
  9721. }
  9722. }),
  9723. on(node, "click", function(e){
  9724. // and connect for mouse clicks too (or touch-clicks on mobile)
  9725. listener.call(this, e);
  9726. })
  9727. ];
  9728. return {
  9729. remove: function(){
  9730. array.forEach(handles, function(h){ h.remove(); });
  9731. }
  9732. };
  9733. }
  9734. };
  9735. return declare("dijit._OnDijitClickMixin", null, {
  9736. connect: function(
  9737. /*Object|null*/ obj,
  9738. /*String|Function*/ event,
  9739. /*String|Function*/ method){
  9740. // summary:
  9741. // Connects specified obj/event to specified method of this object
  9742. // and registers for disconnect() on widget destroy.
  9743. // description:
  9744. // Provide widget-specific analog to connect.connect, except with the
  9745. // implicit use of this widget as the target object.
  9746. // This version of connect also provides a special "ondijitclick"
  9747. // event which triggers on a click or space or enter keyup.
  9748. // Events connected with `this.connect` are disconnected upon
  9749. // destruction.
  9750. // returns:
  9751. // A handle that can be passed to `disconnect` in order to disconnect before
  9752. // the widget is destroyed.
  9753. // example:
  9754. // | var btn = new dijit.form.Button();
  9755. // | // when foo.bar() is called, call the listener we're going to
  9756. // | // provide in the scope of btn
  9757. // | btn.connect(foo, "bar", function(){
  9758. // | console.debug(this.toString());
  9759. // | });
  9760. // tags:
  9761. // protected
  9762. return this.inherited(arguments, [obj, event == "ondijitclick" ? a11yclick : event, method]);
  9763. }
  9764. });
  9765. });
  9766. },
  9767. 'dojo/dnd/autoscroll':function(){
  9768. define("dojo/dnd/autoscroll", ["../main", "../window"], function(dojo) {
  9769. // module:
  9770. // dojo/dnd/autoscroll
  9771. // summary:
  9772. // TODOC
  9773. dojo.getObject("dnd", true, dojo);
  9774. dojo.dnd.getViewport = dojo.window.getBox;
  9775. dojo.dnd.V_TRIGGER_AUTOSCROLL = 32;
  9776. dojo.dnd.H_TRIGGER_AUTOSCROLL = 32;
  9777. dojo.dnd.V_AUTOSCROLL_VALUE = 16;
  9778. dojo.dnd.H_AUTOSCROLL_VALUE = 16;
  9779. dojo.dnd.autoScroll = function(e){
  9780. // summary:
  9781. // a handler for onmousemove event, which scrolls the window, if
  9782. // necesary
  9783. // e: Event
  9784. // onmousemove event
  9785. // FIXME: needs more docs!
  9786. var v = dojo.window.getBox(), dx = 0, dy = 0;
  9787. if(e.clientX < dojo.dnd.H_TRIGGER_AUTOSCROLL){
  9788. dx = -dojo.dnd.H_AUTOSCROLL_VALUE;
  9789. }else if(e.clientX > v.w - dojo.dnd.H_TRIGGER_AUTOSCROLL){
  9790. dx = dojo.dnd.H_AUTOSCROLL_VALUE;
  9791. }
  9792. if(e.clientY < dojo.dnd.V_TRIGGER_AUTOSCROLL){
  9793. dy = -dojo.dnd.V_AUTOSCROLL_VALUE;
  9794. }else if(e.clientY > v.h - dojo.dnd.V_TRIGGER_AUTOSCROLL){
  9795. dy = dojo.dnd.V_AUTOSCROLL_VALUE;
  9796. }
  9797. window.scrollBy(dx, dy);
  9798. };
  9799. dojo.dnd._validNodes = {"div": 1, "p": 1, "td": 1};
  9800. dojo.dnd._validOverflow = {"auto": 1, "scroll": 1};
  9801. dojo.dnd.autoScrollNodes = function(e){
  9802. // summary:
  9803. // a handler for onmousemove event, which scrolls the first avaialble
  9804. // Dom element, it falls back to dojo.dnd.autoScroll()
  9805. // e: Event
  9806. // onmousemove event
  9807. // FIXME: needs more docs!
  9808. var b, t, w, h, rx, ry, dx = 0, dy = 0, oldLeft, oldTop;
  9809. for(var n = e.target; n;){
  9810. if(n.nodeType == 1 && (n.tagName.toLowerCase() in dojo.dnd._validNodes)){
  9811. var s = dojo.getComputedStyle(n),
  9812. overflow = (s.overflow.toLowerCase() in dojo.dnd._validOverflow),
  9813. overflowX = (s.overflowX.toLowerCase() in dojo.dnd._validOverflow),
  9814. overflowY = (s.overflowY.toLowerCase() in dojo.dnd._validOverflow);
  9815. if(overflow || overflowX || overflowY){
  9816. b = dojo._getContentBox(n, s);
  9817. t = dojo.position(n, true);
  9818. }
  9819. // overflow-x
  9820. if(overflow || overflowX){
  9821. w = Math.min(dojo.dnd.H_TRIGGER_AUTOSCROLL, b.w / 2);
  9822. rx = e.pageX - t.x;
  9823. if(dojo.isWebKit || dojo.isOpera){
  9824. // FIXME: this code should not be here, it should be taken into account
  9825. // either by the event fixing code, or the dojo.position()
  9826. // FIXME: this code doesn't work on Opera 9.5 Beta
  9827. rx += dojo.body().scrollLeft;
  9828. }
  9829. dx = 0;
  9830. if(rx > 0 && rx < b.w){
  9831. if(rx < w){
  9832. dx = -w;
  9833. }else if(rx > b.w - w){
  9834. dx = w;
  9835. }
  9836. oldLeft = n.scrollLeft;
  9837. n.scrollLeft = n.scrollLeft + dx;
  9838. }
  9839. }
  9840. // overflow-y
  9841. if(overflow || overflowY){
  9842. //console.log(b.l, b.t, t.x, t.y, n.scrollLeft, n.scrollTop);
  9843. h = Math.min(dojo.dnd.V_TRIGGER_AUTOSCROLL, b.h / 2);
  9844. ry = e.pageY - t.y;
  9845. if(dojo.isWebKit || dojo.isOpera){
  9846. // FIXME: this code should not be here, it should be taken into account
  9847. // either by the event fixing code, or the dojo.position()
  9848. // FIXME: this code doesn't work on Opera 9.5 Beta
  9849. ry += dojo.body().scrollTop;
  9850. }
  9851. dy = 0;
  9852. if(ry > 0 && ry < b.h){
  9853. if(ry < h){
  9854. dy = -h;
  9855. }else if(ry > b.h - h){
  9856. dy = h;
  9857. }
  9858. oldTop = n.scrollTop;
  9859. n.scrollTop = n.scrollTop + dy;
  9860. }
  9861. }
  9862. if(dx || dy){ return; }
  9863. }
  9864. try{
  9865. n = n.parentNode;
  9866. }catch(x){
  9867. n = null;
  9868. }
  9869. }
  9870. dojo.dnd.autoScroll(e);
  9871. };
  9872. return dojo.dnd;
  9873. });
  9874. },
  9875. 'dojo/data/ObjectStore':function(){
  9876. define("dojo/data/ObjectStore", ["../_base/lang", "../Evented", "../_base/declare", "../_base/Deferred", "../_base/array",
  9877. "../_base/connect", "../regexp"
  9878. ], function(lang, Evented, declare, Deferred, array, connect, regexp) {
  9879. // module:
  9880. // dojo/data/ObjectStore
  9881. // summary:
  9882. // TODOC
  9883. return declare("dojo.data.ObjectStore", [Evented],{
  9884. objectStore: null,
  9885. constructor: function(options){
  9886. // summary:
  9887. // A Dojo Data implementation that wraps Dojo object stores for backwards
  9888. // compatibility.
  9889. // options:
  9890. // The configuration information to pass into the data store.
  9891. // options.objectStore:
  9892. // The object store to use as the source provider for this data store
  9893. lang.mixin(this, options);
  9894. },
  9895. labelProperty: "label",
  9896. getValue: function(/*Object*/ item, /*String*/property, /*value?*/defaultValue){
  9897. // summary:
  9898. // Gets the value of an item's 'property'
  9899. //
  9900. // item:
  9901. // The item to get the value from
  9902. // property:
  9903. // property to look up value for
  9904. // defaultValue:
  9905. // the default value
  9906. return typeof item.get === "function" ? item.get(property) :
  9907. property in item ?
  9908. item[property] : defaultValue;
  9909. },
  9910. getValues: function(item, property){
  9911. // summary:
  9912. // Gets the value of an item's 'property' and returns
  9913. // it. If this value is an array it is just returned,
  9914. // if not, the value is added to an array and that is returned.
  9915. //
  9916. // item: /* object */
  9917. // property: /* string */
  9918. // property to look up value for
  9919. var val = this.getValue(item,property);
  9920. return val instanceof Array ? val : val === undefined ? [] : [val];
  9921. },
  9922. getAttributes: function(item){
  9923. // summary:
  9924. // Gets the available attributes of an item's 'property' and returns
  9925. // it as an array.
  9926. //
  9927. // item: /* object */
  9928. var res = [];
  9929. for(var i in item){
  9930. if(item.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_')){
  9931. res.push(i);
  9932. }
  9933. }
  9934. return res;
  9935. },
  9936. hasAttribute: function(item,attribute){
  9937. // summary:
  9938. // Checks to see if item has attribute
  9939. //
  9940. // item: /* object */
  9941. // attribute: /* string */
  9942. return attribute in item;
  9943. },
  9944. containsValue: function(item, attribute, value){
  9945. // summary:
  9946. // Checks to see if 'item' has 'value' at 'attribute'
  9947. //
  9948. // item: /* object */
  9949. // attribute: /* string */
  9950. // value: /* anything */
  9951. return array.indexOf(this.getValues(item,attribute),value) > -1;
  9952. },
  9953. isItem: function(item){
  9954. // summary:
  9955. // Checks to see if the argument is an item
  9956. //
  9957. // item: /* object */
  9958. // attribute: /* string */
  9959. // we have no way of determining if it belongs, we just have object returned from
  9960. // service queries
  9961. return (typeof item == 'object') && item && !(item instanceof Date);
  9962. },
  9963. isItemLoaded: function(item){
  9964. // summary:
  9965. // Checks to see if the item is loaded.
  9966. //
  9967. // item: /* object */
  9968. return item && typeof item.load !== "function";
  9969. },
  9970. loadItem: function(args){
  9971. // summary:
  9972. // Loads an item and calls the callback handler. Note, that this will call the callback
  9973. // handler even if the item is loaded. Consequently, you can use loadItem to ensure
  9974. // that an item is loaded is situations when the item may or may not be loaded yet.
  9975. // If you access a value directly through property access, you can use this to load
  9976. // a lazy value as well (doesn't need to be an item).
  9977. //
  9978. // example:
  9979. // store.loadItem({
  9980. // item: item, // this item may or may not be loaded
  9981. // onItem: function(item){
  9982. // // do something with the item
  9983. // }
  9984. // });
  9985. var item;
  9986. if(typeof args.item.load === "function"){
  9987. Deferred.when(args.item.load(), function(result){
  9988. item = result; // in synchronous mode this can allow loadItem to return the value
  9989. var func = result instanceof Error ? args.onError : args.onItem;
  9990. if(func){
  9991. func.call(args.scope, result);
  9992. }
  9993. });
  9994. }else if(args.onItem){
  9995. // even if it is already loaded, we will use call the callback, this makes it easier to
  9996. // use when it is not known if the item is loaded (you can always safely call loadItem).
  9997. args.onItem.call(args.scope, args.item);
  9998. }
  9999. return item;
  10000. },
  10001. close: function(request){
  10002. return request && request.abort && request.abort();
  10003. },
  10004. fetch: function(args){
  10005. // summary:
  10006. // See dojo.data.api.Read.fetch
  10007. //
  10008. args = lang.delegate(args, args && args.queryOptions);
  10009. var self = this;
  10010. var scope = args.scope || self;
  10011. var query = args.query;
  10012. if(typeof query == "object"){ // can be null, but that is ignore by for-in
  10013. query = lang.delegate(query); // don't modify the original
  10014. for(var i in query){
  10015. // find any strings and convert them to regular expressions for wildcard support
  10016. var required = query[i];
  10017. if(typeof required == "string"){
  10018. query[i] = RegExp("^" + regexp.escapeString(required, "*?").replace(/\*/g, '.*').replace(/\?/g, '.') + "$", args.ignoreCase ? "mi" : "m");
  10019. query[i].toString = (function(original){
  10020. return function(){
  10021. return original;
  10022. }
  10023. })(required);
  10024. }
  10025. }
  10026. }
  10027. var results = this.objectStore.query(query, args);
  10028. Deferred.when(results.total, function(totalCount){
  10029. Deferred.when(results, function(results){
  10030. if(args.onBegin){
  10031. args.onBegin.call(scope, totalCount || results.length, args);
  10032. }
  10033. if(args.onItem){
  10034. for(var i=0; i<results.length;i++){
  10035. args.onItem.call(scope, results[i], args);
  10036. }
  10037. }
  10038. if(args.onComplete){
  10039. args.onComplete.call(scope, args.onItem ? null : results, args);
  10040. }
  10041. return results;
  10042. }, errorHandler);
  10043. }, errorHandler);
  10044. function errorHandler(error){
  10045. if(args.onError){
  10046. args.onError.call(scope, error, args);
  10047. }
  10048. }
  10049. args.abort = function(){
  10050. // abort the request
  10051. if(results.cancel){
  10052. results.cancel();
  10053. }
  10054. };
  10055. if(results.observe){
  10056. if(this.observing){
  10057. // if we were previously observing, cancel the last time to avoid multiple notifications. Just the best we can do for the impedance mismatch between APIs
  10058. this.observing.cancel();
  10059. }
  10060. this.observing = results.observe(function(object, removedFrom, insertedInto){
  10061. if(array.indexOf(self._dirtyObjects, object) == -1){
  10062. if(removedFrom == -1){
  10063. self.onNew(object);
  10064. }
  10065. else if(insertedInto == -1){
  10066. self.onDelete(object);
  10067. }
  10068. else{
  10069. for(var i in object){
  10070. if(i != self.objectStore.idProperty){
  10071. self.onSet(object, i, null, object[i]);
  10072. }
  10073. }
  10074. }
  10075. }
  10076. }, true);
  10077. }
  10078. this.onFetch(results);
  10079. args.store = this;
  10080. return args;
  10081. },
  10082. getFeatures: function(){
  10083. // summary:
  10084. // return the store feature set
  10085. return {
  10086. "dojo.data.api.Read": !!this.objectStore.get,
  10087. "dojo.data.api.Identity": true,
  10088. "dojo.data.api.Write": !!this.objectStore.put,
  10089. "dojo.data.api.Notification": true
  10090. };
  10091. },
  10092. getLabel: function(/* item */ item){
  10093. // summary:
  10094. // See dojo.data.api.Read.getLabel()
  10095. if(this.isItem(item)){
  10096. return this.getValue(item,this.labelProperty); //String
  10097. }
  10098. return undefined; //undefined
  10099. },
  10100. getLabelAttributes: function(/* item */ item){
  10101. // summary:
  10102. // See dojo.data.api.Read.getLabelAttributes()
  10103. return [this.labelProperty]; //array
  10104. },
  10105. //Identity API Support
  10106. getIdentity: function(item){
  10107. return this.objectStore.getIdentity ? this.objectStore.getIdentity(item) : item[this.objectStore.idProperty || "id"];
  10108. },
  10109. getIdentityAttributes: function(item){
  10110. // summary:
  10111. // returns the attributes which are used to make up the
  10112. // identity of an item. Basically returns this.objectStore.idProperty
  10113. return [this.objectStore.idProperty];
  10114. },
  10115. fetchItemByIdentity: function(args){
  10116. // summary:
  10117. // fetch an item by its identity, by looking in our index of what we have loaded
  10118. var item;
  10119. Deferred.when(this.objectStore.get(args.identity),
  10120. function(result){
  10121. item = result;
  10122. args.onItem.call(args.scope, result);
  10123. },
  10124. function(error){
  10125. args.onError.call(args.scope, error);
  10126. }
  10127. );
  10128. return item;
  10129. },
  10130. newItem: function(data, parentInfo){
  10131. // summary:
  10132. // adds a new item to the store at the specified point.
  10133. // Takes two parameters, data, and options.
  10134. //
  10135. // data: Object
  10136. // The data to be added in as an item.
  10137. // TODOC: parentInfo
  10138. if(parentInfo){
  10139. // get the previous value or any empty array
  10140. var values = this.getValue(parentInfo.parent,parentInfo.attribute,[]);
  10141. // set the new value
  10142. values = values.concat([data]);
  10143. data.__parent = values;
  10144. this.setValue(parentInfo.parent, parentInfo.attribute, values);
  10145. }
  10146. this._dirtyObjects.push({object:data, save: true});
  10147. this.onNew(data);
  10148. return data;
  10149. },
  10150. deleteItem: function(item){
  10151. // summary:
  10152. // deletes item and any references to that item from the store.
  10153. //
  10154. // item:
  10155. // item to delete
  10156. //
  10157. // If the desire is to delete only one reference, unsetAttribute or
  10158. // setValue is the way to go.
  10159. this.changing(item, true);
  10160. this.onDelete(item);
  10161. },
  10162. setValue: function(item, attribute, value){
  10163. // summary:
  10164. // sets 'attribute' on 'item' to 'value'
  10165. var old = item[attribute];
  10166. this.changing(item);
  10167. item[attribute]=value;
  10168. this.onSet(item,attribute,old,value);
  10169. },
  10170. setValues: function(item, attribute, values){
  10171. // summary:
  10172. // sets 'attribute' on 'item' to 'value' value
  10173. // must be an array.
  10174. if(!lang.isArray(values)){
  10175. throw new Error("setValues expects to be passed an Array object as its value");
  10176. }
  10177. this.setValue(item,attribute,values);
  10178. },
  10179. unsetAttribute: function(item, attribute){
  10180. // summary:
  10181. // unsets 'attribute' on 'item'
  10182. this.changing(item);
  10183. var old = item[attribute];
  10184. delete item[attribute];
  10185. this.onSet(item,attribute,old,undefined);
  10186. },
  10187. _dirtyObjects: [],
  10188. changing: function(object,_deleting){
  10189. // summary:
  10190. // adds an object to the list of dirty objects. This object
  10191. // contains a reference to the object itself as well as a
  10192. // cloned and trimmed version of old object for use with
  10193. // revert.
  10194. object.__isDirty = true;
  10195. //if an object is already in the list of dirty objects, don't add it again
  10196. //or it will overwrite the premodification data set.
  10197. for(var i=0; i<this._dirtyObjects.length; i++){
  10198. var dirty = this._dirtyObjects[i];
  10199. if(object==dirty.object){
  10200. if(_deleting){
  10201. // we are deleting, no object is an indicator of deletiong
  10202. dirty.object = false;
  10203. if(!this._saveNotNeeded){
  10204. dirty.save = true;
  10205. }
  10206. }
  10207. return;
  10208. }
  10209. }
  10210. var old = object instanceof Array ? [] : {};
  10211. for(i in object){
  10212. if(object.hasOwnProperty(i)){
  10213. old[i] = object[i];
  10214. }
  10215. }
  10216. this._dirtyObjects.push({object: !_deleting && object, old: old, save: !this._saveNotNeeded});
  10217. },
  10218. save: function(kwArgs){
  10219. // summary:
  10220. // Saves the dirty data using object store provider. See dojo.data.api.Write for API.
  10221. //
  10222. // kwArgs.global:
  10223. // This will cause the save to commit the dirty data for all
  10224. // ObjectStores as a single transaction.
  10225. //
  10226. // kwArgs.revertOnError
  10227. // This will cause the changes to be reverted if there is an
  10228. // error on the save. By default a revert is executed unless
  10229. // a value of false is provide for this parameter.
  10230. // TODOC: kwArgs pseudo
  10231. kwArgs = kwArgs || {};
  10232. var result, actions = [];
  10233. var savingObjects = [];
  10234. var self = this;
  10235. var dirtyObjects = this._dirtyObjects;
  10236. var left = dirtyObjects.length;// this is how many changes are remaining to be received from the server
  10237. try{
  10238. connect.connect(kwArgs,"onError",function(){
  10239. if(kwArgs.revertOnError !== false){
  10240. var postCommitDirtyObjects = dirtyObjects;
  10241. dirtyObjects = savingObjects;
  10242. self.revert(); // revert if there was an error
  10243. self._dirtyObjects = postCommitDirtyObjects;
  10244. }
  10245. else{
  10246. self._dirtyObjects = dirtyObjects.concat(savingObjects);
  10247. }
  10248. });
  10249. if(this.objectStore.transaction){
  10250. var transaction = this.objectStore.transaction();
  10251. }
  10252. for(var i = 0; i < dirtyObjects.length; i++){
  10253. var dirty = dirtyObjects[i];
  10254. var object = dirty.object;
  10255. var old = dirty.old;
  10256. delete object.__isDirty;
  10257. if(object){
  10258. result = this.objectStore.put(object, {overwrite: !!old});
  10259. }
  10260. else if(typeof old != "undefined"){
  10261. result = this.objectStore.remove(this.getIdentity(old));
  10262. }
  10263. savingObjects.push(dirty);
  10264. dirtyObjects.splice(i--,1);
  10265. Deferred.when(result, function(value){
  10266. if(!(--left)){
  10267. if(kwArgs.onComplete){
  10268. kwArgs.onComplete.call(kwArgs.scope, actions);
  10269. }
  10270. }
  10271. },function(value){
  10272. // on an error we want to revert, first we want to separate any changes that were made since the commit
  10273. left = -1; // first make sure that success isn't called
  10274. kwArgs.onError.call(kwArgs.scope, value);
  10275. });
  10276. }
  10277. if(transaction){
  10278. transaction.commit();
  10279. }
  10280. }catch(e){
  10281. kwArgs.onError.call(kwArgs.scope, value);
  10282. }
  10283. },
  10284. revert: function(kwArgs){
  10285. // summary:
  10286. // returns any modified data to its original state prior to a save();
  10287. //
  10288. var dirtyObjects = this._dirtyObjects;
  10289. for(var i = dirtyObjects.length; i > 0;){
  10290. i--;
  10291. var dirty = dirtyObjects[i];
  10292. var object = dirty.object;
  10293. var old = dirty.old;
  10294. if(object && old){
  10295. // changed
  10296. for(var j in old){
  10297. if(old.hasOwnProperty(j) && object[j] !== old[j]){
  10298. this.onSet(object, j, object[j], old[j]);
  10299. object[j] = old[j];
  10300. }
  10301. }
  10302. for(j in object){
  10303. if(!old.hasOwnProperty(j)){
  10304. this.onSet(object, j, object[j]);
  10305. delete object[j];
  10306. }
  10307. }
  10308. }else if(!old){
  10309. // was an addition, remove it
  10310. this.onDelete(object);
  10311. }else{
  10312. // was a deletion, we will add it back
  10313. this.onNew(old);
  10314. }
  10315. delete (object || old).__isDirty;
  10316. dirtyObjects.splice(i, 1);
  10317. }
  10318. },
  10319. isDirty: function(item){
  10320. // summary:
  10321. // returns true if the item is marked as dirty or true if there are any dirty items
  10322. if(!item){
  10323. return !!this._dirtyObjects.length;
  10324. }
  10325. return item.__isDirty;
  10326. },
  10327. //Notifcation Support
  10328. onSet: function(){},
  10329. onNew: function(){},
  10330. onDelete: function(){},
  10331. // an extra to get result sets
  10332. onFetch: function(results){}
  10333. }
  10334. );
  10335. });
  10336. },
  10337. 'dojox/grid/enhanced/_Events':function(){
  10338. define("dojox/grid/enhanced/_Events", [
  10339. "dojo/_base/kernel",
  10340. "dojo/_base/declare",
  10341. "dojo/keys",
  10342. "dojo/_base/html",
  10343. "dojo/_base/event",
  10344. "dojox/grid/_Events"
  10345. ], function(dojo, declare, keys, html, event, _Events){
  10346. return declare("dojox.grid.enhanced._Events", null, {
  10347. // summary:
  10348. // Overwrite some default events of DataGrid
  10349. //
  10350. // description:
  10351. // Methods are copied or replaced for overwriting, this might be refined once
  10352. // an overall plugin architecture is set up for DataGrid.
  10353. //_events: Object
  10354. // Method map cached from dojox.grid._Events().
  10355. _events: null,
  10356. // headerCellActiveClass: String
  10357. // css class to apply to grid header cells when activated(mouse down)
  10358. headerCellActiveClass: 'dojoxGridHeaderActive',
  10359. // cellActiveClass: String
  10360. // css class to apply to grid content cells when activated(mouse down)
  10361. cellActiveClass: 'dojoxGridCellActive',
  10362. // rowActiveClass: String
  10363. // css class to apply to grid rows when activated(mouse down)
  10364. rowActiveClass: 'dojoxGridRowActive',
  10365. constructor: function(inGrid){
  10366. //TODO - extend dojox.grid._Events rather than mixin for 1.8
  10367. this._events = new _Events();
  10368. //mixin "this" to Grid
  10369. inGrid.mixin(inGrid, this);
  10370. },
  10371. dokeyup: function(e){
  10372. // summary:
  10373. // Grid key up event handler.
  10374. // e: Event
  10375. // Un-decorated event object
  10376. this.focus.currentArea().keyup(e);
  10377. },
  10378. onKeyDown: function(e){
  10379. // summary:
  10380. // Overwritten, see dojox.grid._Events.onKeyDown();
  10381. if(e.altKey || e.metaKey){ return; }
  10382. var focus = this.focus;
  10383. var editing = this.edit.isEditing();
  10384. switch(e.keyCode){
  10385. case keys.TAB:
  10386. if(e.ctrlKey){ return; }
  10387. focus.tab(e.shiftKey ? -1:1,e);
  10388. break;
  10389. case keys.UP_ARROW:
  10390. case keys.DOWN_ARROW:
  10391. if(editing){ return; }
  10392. focus.currentArea().move(e.keyCode == keys.UP_ARROW ? -1 : 1, 0, e);
  10393. break;
  10394. case keys.LEFT_ARROW:
  10395. case keys.RIGHT_ARROW:
  10396. if(editing){ return; }
  10397. var offset = (e.keyCode == keys.LEFT_ARROW) ? 1 : -1;
  10398. if(html._isBodyLtr()){ offset *= -1; }
  10399. focus.currentArea().move(0, offset, e);
  10400. break;
  10401. case keys.F10:
  10402. if(this.menus && e.shiftKey){
  10403. this.onRowContextMenu(e);
  10404. }
  10405. break;
  10406. default:
  10407. focus.currentArea().keydown(e);
  10408. break;
  10409. }
  10410. },
  10411. //TODO - make the following events more reasonalble - e.g. more accurate conditions
  10412. //events for row selectors
  10413. domouseup: function(e){
  10414. if(e.cellNode){
  10415. this.onMouseUp(e);
  10416. }else{
  10417. this.onRowSelectorMouseUp(e);
  10418. }
  10419. },
  10420. domousedown: function(e){
  10421. if(!e.cellNode){
  10422. this.onRowSelectorMouseDown(e);
  10423. }
  10424. },
  10425. onMouseUp: function(e){
  10426. // summary:
  10427. // New - Event fired when mouse is up inside grid.
  10428. // e: Event
  10429. // Decorated event object that contains reference to grid, cell, and rowIndex
  10430. this[e.rowIndex == -1 ? "onHeaderCellMouseUp" : "onCellMouseUp"](e);
  10431. },
  10432. onCellMouseDown: function(e){
  10433. // summary:
  10434. // Overwritten, see dojox.grid._Events.onCellMouseDown()
  10435. html.addClass(e.cellNode, this.cellActiveClass);
  10436. html.addClass(e.rowNode, this.rowActiveClass);
  10437. },
  10438. onCellMouseUp: function(e){
  10439. // summary:
  10440. // New - Event fired when mouse is up inside content cell.
  10441. // e: Event
  10442. // Decorated event object that contains reference to grid, cell, and rowIndex
  10443. html.removeClass(e.cellNode, this.cellActiveClass);
  10444. html.removeClass(e.rowNode, this.rowActiveClass);
  10445. },
  10446. onCellClick: function(e){
  10447. // summary:
  10448. // Overwritten, see dojox.grid._Events.onCellClick()
  10449. //invoke dojox.grid._Events.onCellClick()
  10450. this._events.onCellClick.call(this, e);
  10451. //move mouse events to the focus manager.
  10452. this.focus.contentMouseEvent(e);//TODO
  10453. },
  10454. onCellDblClick: function(e){
  10455. // summary:
  10456. // Overwritten, see dojox.grid._Events.onCellDblClick()
  10457. if(this.pluginMgr.isFixedCell(e.cell)){ return; }
  10458. if(this._click.length > 1 && (!this._click[0] || !this._click[1])){
  10459. this._click[0] = this._click[1] = e;
  10460. }
  10461. //invoke dojox.grid._Events.onCellDblClick()
  10462. this._events.onCellDblClick.call(this, e);
  10463. },
  10464. onRowClick: function(e){
  10465. // summary:
  10466. // Overwritten, see dojox.grid._Events.onRowClick()
  10467. this.edit.rowClick(e);
  10468. if(!e.cell || !this.plugin('indirectSelection')){
  10469. this.selection.clickSelectEvent(e);
  10470. }
  10471. },
  10472. onRowContextMenu: function(e){
  10473. // summary:
  10474. // Overwritten, see dojox.grid._Events.onRowContextMenu()
  10475. if(!this.edit.isEditing() && this.menus){
  10476. this.showMenu(e);
  10477. }
  10478. },
  10479. onSelectedRegionContextMenu: function(e){
  10480. // summary:
  10481. // New - Event fired when a selected region context menu is accessed via mouse right click.
  10482. // e: Event
  10483. // Decorated event object which contains reference to grid and info of selected
  10484. // regions(selection type - row|column, selected index - [...])
  10485. if(this.selectedRegionMenu){
  10486. this.selectedRegionMenu._openMyself({
  10487. target: e.target,
  10488. coords: e.keyCode !== keys.F10 && "pageX" in e ? {
  10489. x: e.pageX,
  10490. y: e.pageY
  10491. } : null
  10492. });
  10493. event.stop(e);
  10494. }
  10495. },
  10496. onHeaderCellMouseOut: function(e){
  10497. // summary:
  10498. // Overwritten, see dojox.grid._Events.onHeaderCellMouseOut()
  10499. if(e.cellNode){
  10500. html.removeClass(e.cellNode, this.cellOverClass);
  10501. html.removeClass(e.cellNode, this.headerCellActiveClass);
  10502. }
  10503. },
  10504. onHeaderCellMouseDown: function(e){
  10505. // summary:
  10506. // Overwritten, see dojox.grid._Events.onHeaderCellMouseDown()
  10507. if(e.cellNode){//TBD - apply to selection region for nested sorting?
  10508. html.addClass(e.cellNode, this.headerCellActiveClass);
  10509. }
  10510. },
  10511. onHeaderCellMouseUp: function(e){
  10512. // summary:
  10513. // New event
  10514. if(e.cellNode){
  10515. html.removeClass(e.cellNode, this.headerCellActiveClass);
  10516. }
  10517. },
  10518. onHeaderCellClick: function(e){
  10519. // summary:
  10520. // Overwritten, see dojox.grid._Events.onHeaderCellClick()
  10521. //move focus to header.
  10522. this.focus.currentArea("header");
  10523. //invoke dojox.grid._Events.onHeaderCellClick()
  10524. if(!e.cell.isRowSelector){
  10525. this._events.onHeaderCellClick.call(this, e);
  10526. }
  10527. //move mouse events to the focus manager.
  10528. this.focus.headerMouseEvent(e);
  10529. },
  10530. onRowSelectorMouseDown: function(e){
  10531. this.focus.focusArea("rowHeader", e);
  10532. },
  10533. onRowSelectorMouseUp: function(e){},
  10534. //triggered in _View, see Selector plugin
  10535. onMouseUpRow: function(e){
  10536. if(e.rowIndex != -1){
  10537. this.onRowMouseUp(e);
  10538. }
  10539. },
  10540. onRowMouseUp: function(e){}
  10541. });
  10542. });
  10543. },
  10544. 'dijit/form/_ListMouseMixin':function(){
  10545. define("dijit/form/_ListMouseMixin", [
  10546. "dojo/_base/declare", // declare
  10547. "dojo/_base/event", // event.stop
  10548. "dojo/touch",
  10549. "./_ListBase"
  10550. ], function(declare, event, touch, _ListBase){
  10551. /*=====
  10552. var _ListBase = dijit.form._ListBase;
  10553. =====*/
  10554. // module:
  10555. // dijit/form/_ListMouseMixin
  10556. // summary:
  10557. // a mixin to handle mouse or touch events for a focus-less menu
  10558. return declare( "dijit.form._ListMouseMixin", _ListBase, {
  10559. // summary:
  10560. // a Mixin to handle mouse or touch events for a focus-less menu
  10561. // Abstract methods that must be defined externally:
  10562. // onClick: item was chosen (mousedown somewhere on the menu and mouseup somewhere on the menu)
  10563. // tags:
  10564. // private
  10565. postCreate: function(){
  10566. this.inherited(arguments);
  10567. this.connect(this.domNode, touch.press, "_onMouseDown");
  10568. this.connect(this.domNode, touch.release, "_onMouseUp");
  10569. this.connect(this.domNode, "onmouseover", "_onMouseOver");
  10570. this.connect(this.domNode, "onmouseout", "_onMouseOut");
  10571. },
  10572. _onMouseDown: function(/*Event*/ evt){
  10573. event.stop(evt);
  10574. if(this._hoveredNode){
  10575. this.onUnhover(this._hoveredNode);
  10576. this._hoveredNode = null;
  10577. }
  10578. this._isDragging = true;
  10579. this._setSelectedAttr(this._getTarget(evt));
  10580. },
  10581. _onMouseUp: function(/*Event*/ evt){
  10582. event.stop(evt);
  10583. this._isDragging = false;
  10584. var selectedNode = this._getSelectedAttr();
  10585. var target = this._getTarget(evt);
  10586. var hoveredNode = this._hoveredNode;
  10587. if(selectedNode && target == selectedNode){
  10588. this.onClick(selectedNode);
  10589. }else if(hoveredNode && target == hoveredNode){ // drag to select
  10590. this._setSelectedAttr(hoveredNode);
  10591. this.onClick(hoveredNode);
  10592. }
  10593. },
  10594. _onMouseOut: function(/*Event*/ /*===== evt ====*/){
  10595. if(this._hoveredNode){
  10596. this.onUnhover(this._hoveredNode);
  10597. if(this._getSelectedAttr() == this._hoveredNode){
  10598. this.onSelect(this._hoveredNode);
  10599. }
  10600. this._hoveredNode = null;
  10601. }
  10602. if(this._isDragging){
  10603. this._cancelDrag = (new Date()).getTime() + 1000; // cancel in 1 second if no _onMouseOver fires
  10604. }
  10605. },
  10606. _onMouseOver: function(/*Event*/ evt){
  10607. if(this._cancelDrag){
  10608. var time = (new Date()).getTime();
  10609. if(time > this._cancelDrag){
  10610. this._isDragging = false;
  10611. }
  10612. this._cancelDrag = null;
  10613. }
  10614. var node = this._getTarget(evt);
  10615. if(!node){ return; }
  10616. if(this._hoveredNode != node){
  10617. if(this._hoveredNode){
  10618. this._onMouseOut({ target: this._hoveredNode });
  10619. }
  10620. if(node && node.parentNode == this.containerNode){
  10621. if(this._isDragging){
  10622. this._setSelectedAttr(node);
  10623. }else{
  10624. this._hoveredNode = node;
  10625. this.onHover(node);
  10626. }
  10627. }
  10628. }
  10629. }
  10630. });
  10631. });
  10632. },
  10633. 'dojo/cldr/monetary':function(){
  10634. define("dojo/cldr/monetary", ["../main"], function(dojo) {
  10635. // module:
  10636. // dojo/cldr/monetary
  10637. // summary:
  10638. // TODOC
  10639. dojo.getObject("cldr.monetary", true, dojo);
  10640. dojo.cldr.monetary.getData = function(/*String*/code){
  10641. // summary: A mapping of currency code to currency-specific formatting information. Returns a unique object with properties: places, round.
  10642. // code: an [ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code
  10643. // from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/currencyData/fractions
  10644. var placesData = {
  10645. ADP:0,AFN:0,ALL:0,AMD:0,BHD:3,BIF:0,BYR:0,CLF:0,CLP:0,
  10646. COP:0,CRC:0,DJF:0,ESP:0,GNF:0,GYD:0,HUF:0,IDR:0,IQD:0,
  10647. IRR:3,ISK:0,ITL:0,JOD:3,JPY:0,KMF:0,KPW:0,KRW:0,KWD:3,
  10648. LAK:0,LBP:0,LUF:0,LYD:3,MGA:0,MGF:0,MMK:0,MNT:0,MRO:0,
  10649. MUR:0,OMR:3,PKR:0,PYG:0,RSD:0,RWF:0,SLL:0,SOS:0,STD:0,
  10650. SYP:0,TMM:0,TND:3,TRL:0,TZS:0,UGX:0,UZS:0,VND:0,VUV:0,
  10651. XAF:0,XOF:0,XPF:0,YER:0,ZMK:0,ZWD:0
  10652. };
  10653. var roundingData = {CHF:5};
  10654. var places = placesData[code], round = roundingData[code];
  10655. if(typeof places == "undefined"){ places = 2; }
  10656. if(typeof round == "undefined"){ round = 0; }
  10657. return {places: places, round: round}; // Object
  10658. };
  10659. return dojo.cldr.monetary;
  10660. });
  10661. },
  10662. 'dojo/cookie':function(){
  10663. define("dojo/cookie", ["./_base/kernel", "./regexp"], function(dojo, regexp) {
  10664. // module:
  10665. // dojo/cookie
  10666. // summary:
  10667. // TODOC
  10668. /*=====
  10669. dojo.__cookieProps = function(){
  10670. // expires: Date|String|Number?
  10671. // If a number, the number of days from today at which the cookie
  10672. // will expire. If a date, the date past which the cookie will expire.
  10673. // If expires is in the past, the cookie will be deleted.
  10674. // If expires is omitted or is 0, the cookie will expire when the browser closes.
  10675. // path: String?
  10676. // The path to use for the cookie.
  10677. // domain: String?
  10678. // The domain to use for the cookie.
  10679. // secure: Boolean?
  10680. // Whether to only send the cookie on secure connections
  10681. this.expires = expires;
  10682. this.path = path;
  10683. this.domain = domain;
  10684. this.secure = secure;
  10685. }
  10686. =====*/
  10687. dojo.cookie = function(/*String*/name, /*String?*/value, /*dojo.__cookieProps?*/props){
  10688. // summary:
  10689. // Get or set a cookie.
  10690. // description:
  10691. // If one argument is passed, returns the value of the cookie
  10692. // For two or more arguments, acts as a setter.
  10693. // name:
  10694. // Name of the cookie
  10695. // value:
  10696. // Value for the cookie
  10697. // props:
  10698. // Properties for the cookie
  10699. // example:
  10700. // set a cookie with the JSON-serialized contents of an object which
  10701. // will expire 5 days from now:
  10702. // | dojo.cookie("configObj", dojo.toJson(config), { expires: 5 });
  10703. //
  10704. // example:
  10705. // de-serialize a cookie back into a JavaScript object:
  10706. // | var config = dojo.fromJson(dojo.cookie("configObj"));
  10707. //
  10708. // example:
  10709. // delete a cookie:
  10710. // | dojo.cookie("configObj", null, {expires: -1});
  10711. var c = document.cookie, ret;
  10712. if(arguments.length == 1){
  10713. var matches = c.match(new RegExp("(?:^|; )" + regexp.escapeString(name) + "=([^;]*)"));
  10714. ret = matches ? decodeURIComponent(matches[1]) : undefined;
  10715. }else{
  10716. props = props || {};
  10717. // FIXME: expires=0 seems to disappear right away, not on close? (FF3) Change docs?
  10718. var exp = props.expires;
  10719. if(typeof exp == "number"){
  10720. var d = new Date();
  10721. d.setTime(d.getTime() + exp*24*60*60*1000);
  10722. exp = props.expires = d;
  10723. }
  10724. if(exp && exp.toUTCString){ props.expires = exp.toUTCString(); }
  10725. value = encodeURIComponent(value);
  10726. var updatedCookie = name + "=" + value, propName;
  10727. for(propName in props){
  10728. updatedCookie += "; " + propName;
  10729. var propValue = props[propName];
  10730. if(propValue !== true){ updatedCookie += "=" + propValue; }
  10731. }
  10732. document.cookie = updatedCookie;
  10733. }
  10734. return ret; // String|undefined
  10735. };
  10736. dojo.cookie.isSupported = function(){
  10737. // summary:
  10738. // Use to determine if the current browser supports cookies or not.
  10739. //
  10740. // Returns true if user allows cookies.
  10741. // Returns false if user doesn't allow cookies.
  10742. if(!("cookieEnabled" in navigator)){
  10743. this("__djCookieTest__", "CookiesAllowed");
  10744. navigator.cookieEnabled = this("__djCookieTest__") == "CookiesAllowed";
  10745. if(navigator.cookieEnabled){
  10746. this("__djCookieTest__", "", {expires: -1});
  10747. }
  10748. }
  10749. return navigator.cookieEnabled;
  10750. };
  10751. return dojo.cookie;
  10752. });
  10753. },
  10754. 'dojo/cache':function(){
  10755. define("dojo/cache", ["./_base/kernel", "./text"], function(dojo, text){
  10756. // module:
  10757. // dojo/cache
  10758. // summary:
  10759. // The module defines dojo.cache by loading dojo/text.
  10760. //dojo.cache is defined in dojo/text
  10761. return dojo.cache;
  10762. });
  10763. },
  10764. 'url:dijit/form/templates/DropDownBox.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\"\r\n\tid=\"widget_${id}\"\r\n\trole=\"combobox\"\r\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\r\n\t\tdata-dojo-attach-point=\"_buttonNode, _popupStateNode\" role=\"presentation\"\r\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t\t${_buttonInputDisabled}\r\n\t/></div\r\n\t><div class='dijitReset dijitValidationContainer'\r\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t/></div\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\r\n\t\t\tdata-dojo-attach-point=\"textbox,focusNode\" role=\"textbox\" aria-haspopup=\"true\"\r\n\t/></div\r\n></div>\r\n",
  10765. 'dijit/ProgressBar':function(){
  10766. require({cache:{
  10767. 'url:dijit/templates/ProgressBar.html':"<div class=\"dijitProgressBar dijitProgressBarEmpty\" role=\"progressbar\"\r\n\t><div data-dojo-attach-point=\"internalProgress\" class=\"dijitProgressBarFull\"\r\n\t\t><div class=\"dijitProgressBarTile\" role=\"presentation\"></div\r\n\t\t><span style=\"visibility:hidden\">&#160;</span\r\n\t></div\r\n\t><div data-dojo-attach-point=\"labelNode\" class=\"dijitProgressBarLabel\" id=\"${id}_label\"></div\r\n\t><img data-dojo-attach-point=\"indeterminateHighContrastImage\" class=\"dijitProgressBarIndeterminateHighContrastImage\" alt=\"\"\r\n/></div>\r\n"}});
  10768. define("dijit/ProgressBar", [
  10769. "require", // require.toUrl
  10770. "dojo/_base/declare", // declare
  10771. "dojo/dom-class", // domClass.toggle
  10772. "dojo/_base/lang", // lang.mixin
  10773. "dojo/number", // number.format
  10774. "./_Widget",
  10775. "./_TemplatedMixin",
  10776. "dojo/text!./templates/ProgressBar.html"
  10777. ], function(require, declare, domClass, lang, number, _Widget, _TemplatedMixin, template){
  10778. /*=====
  10779. var _Widget = dijit._Widget;
  10780. var _TemplatedMixin = dijit._TemplatedMixin;
  10781. =====*/
  10782. // module:
  10783. // dijit/ProgressBar
  10784. // summary:
  10785. // A progress indication widget, showing the amount completed
  10786. // (often the percentage completed) of a task.
  10787. return declare("dijit.ProgressBar", [_Widget, _TemplatedMixin], {
  10788. // summary:
  10789. // A progress indication widget, showing the amount completed
  10790. // (often the percentage completed) of a task.
  10791. //
  10792. // example:
  10793. // | <div data-dojo-type="ProgressBar"
  10794. // | places="0"
  10795. // | value="..." maximum="...">
  10796. // | </div>
  10797. // progress: [const] String (Percentage or Number)
  10798. // Number or percentage indicating amount of task completed.
  10799. // Deprecated. Use "value" instead.
  10800. progress: "0",
  10801. // value: String (Percentage or Number)
  10802. // Number or percentage indicating amount of task completed.
  10803. // With "%": percentage value, 0% <= progress <= 100%, or
  10804. // without "%": absolute value, 0 <= progress <= maximum.
  10805. // Infinity means that the progress bar is indeterminate.
  10806. value: "",
  10807. // maximum: [const] Float
  10808. // Max sample number
  10809. maximum: 100,
  10810. // places: [const] Number
  10811. // Number of places to show in values; 0 by default
  10812. places: 0,
  10813. // indeterminate: [const] Boolean
  10814. // If false: show progress value (number or percentage).
  10815. // If true: show that a process is underway but that the amount completed is unknown.
  10816. // Deprecated. Use "value" instead.
  10817. indeterminate: false,
  10818. // label: String?
  10819. // Label on progress bar. Defaults to percentage for determinate progress bar and
  10820. // blank for indeterminate progress bar.
  10821. label:"",
  10822. // name: String
  10823. // this is the field name (for a form) if set. This needs to be set if you want to use
  10824. // this widget in a dijit.form.Form widget (such as dijit.Dialog)
  10825. name: '',
  10826. templateString: template,
  10827. // _indeterminateHighContrastImagePath: [private] URL
  10828. // URL to image to use for indeterminate progress bar when display is in high contrast mode
  10829. _indeterminateHighContrastImagePath:
  10830. require.toUrl("./themes/a11y/indeterminate_progress.gif"),
  10831. postMixInProperties: function(){
  10832. this.inherited(arguments);
  10833. if(!("value" in this.params)){
  10834. this.value = this.indeterminate ? Infinity : this.progress;
  10835. }
  10836. },
  10837. buildRendering: function(){
  10838. this.inherited(arguments);
  10839. this.indeterminateHighContrastImage.setAttribute("src",
  10840. this._indeterminateHighContrastImagePath.toString());
  10841. this.update();
  10842. },
  10843. update: function(/*Object?*/attributes){
  10844. // summary:
  10845. // Internal method to change attributes of ProgressBar, similar to set(hash). Users should call
  10846. // set("value", ...) rather than calling this method directly.
  10847. // attributes:
  10848. // May provide progress and/or maximum properties on this parameter;
  10849. // see attribute specs for details.
  10850. // example:
  10851. // | myProgressBar.update({'indeterminate': true});
  10852. // | myProgressBar.update({'progress': 80});
  10853. // | myProgressBar.update({'indeterminate': true, label:"Loading ..." })
  10854. // tags:
  10855. // private
  10856. // TODO: deprecate this method and use set() instead
  10857. lang.mixin(this, attributes || {});
  10858. var tip = this.internalProgress, ap = this.domNode;
  10859. var percent = 1;
  10860. if(this.indeterminate){
  10861. ap.removeAttribute("aria-valuenow");
  10862. ap.removeAttribute("aria-valuemin");
  10863. ap.removeAttribute("aria-valuemax");
  10864. }else{
  10865. if(String(this.progress).indexOf("%") != -1){
  10866. percent = Math.min(parseFloat(this.progress)/100, 1);
  10867. this.progress = percent * this.maximum;
  10868. }else{
  10869. this.progress = Math.min(this.progress, this.maximum);
  10870. percent = this.maximum ? this.progress / this.maximum : 0;
  10871. }
  10872. ap.setAttribute("aria-describedby", this.labelNode.id);
  10873. ap.setAttribute("aria-valuenow", this.progress);
  10874. ap.setAttribute("aria-valuemin", 0);
  10875. ap.setAttribute("aria-valuemax", this.maximum);
  10876. }
  10877. this.labelNode.innerHTML = this.report(percent);
  10878. domClass.toggle(this.domNode, "dijitProgressBarIndeterminate", this.indeterminate);
  10879. tip.style.width = (percent * 100) + "%";
  10880. this.onChange();
  10881. },
  10882. _setValueAttr: function(v){
  10883. this._set("value", v);
  10884. if(v == Infinity){
  10885. this.update({indeterminate:true});
  10886. }else{
  10887. this.update({indeterminate:false, progress:v});
  10888. }
  10889. },
  10890. _setLabelAttr: function(label){
  10891. this._set("label", label);
  10892. this.update();
  10893. },
  10894. _setIndeterminateAttr: function(indeterminate){
  10895. // Deprecated, use set("value", ...) instead
  10896. this.indeterminate = indeterminate;
  10897. this.update();
  10898. },
  10899. report: function(/*float*/percent){
  10900. // summary:
  10901. // Generates message to show inside progress bar (normally indicating amount of task completed).
  10902. // May be overridden.
  10903. // tags:
  10904. // extension
  10905. return this.label ? this.label :
  10906. (this.indeterminate ? "&#160;" : number.format(percent, { type: "percent", places: this.places, locale: this.lang }));
  10907. },
  10908. onChange: function(){
  10909. // summary:
  10910. // Callback fired when progress updates.
  10911. // tags:
  10912. // extension
  10913. }
  10914. });
  10915. });
  10916. },
  10917. 'dojox/grid/_ViewManager':function(){
  10918. define("dojox/grid/_ViewManager", [
  10919. "dojo/_base/declare",
  10920. "dojo/_base/sniff",
  10921. "dojo/dom-class"
  10922. ], function(declare, has, domClass){
  10923. return declare('dojox.grid._ViewManager', null, {
  10924. // summary:
  10925. // A collection of grid views. Owned by grid and used internally for managing grid views.
  10926. // description:
  10927. // Grid creates views automatically based on grid's layout structure.
  10928. // Users should typically not need to access individual views or the views collection directly.
  10929. constructor: function(inGrid){
  10930. this.grid = inGrid;
  10931. },
  10932. defaultWidth: 200,
  10933. views: [],
  10934. // operations
  10935. resize: function(){
  10936. this.onEach("resize");
  10937. },
  10938. render: function(){
  10939. this.onEach("render");
  10940. },
  10941. // views
  10942. addView: function(inView){
  10943. inView.idx = this.views.length;
  10944. this.views.push(inView);
  10945. },
  10946. destroyViews: function(){
  10947. for(var i=0, v; v=this.views[i]; i++){
  10948. v.destroy();
  10949. }
  10950. this.views = [];
  10951. },
  10952. getContentNodes: function(){
  10953. var nodes = [];
  10954. for(var i=0, v; v=this.views[i]; i++){
  10955. nodes.push(v.contentNode);
  10956. }
  10957. return nodes;
  10958. },
  10959. forEach: function(inCallback){
  10960. for(var i=0, v; v=this.views[i]; i++){
  10961. inCallback(v, i);
  10962. }
  10963. },
  10964. onEach: function(inMethod, inArgs){
  10965. inArgs = inArgs || [];
  10966. for(var i=0, v; v=this.views[i]; i++){
  10967. if(inMethod in v){
  10968. v[inMethod].apply(v, inArgs);
  10969. }
  10970. }
  10971. },
  10972. // layout
  10973. normalizeHeaderNodeHeight: function(){
  10974. var rowNodes = [];
  10975. for(var i=0, v; (v=this.views[i]); i++){
  10976. if(v.headerContentNode.firstChild){
  10977. rowNodes.push(v.headerContentNode);
  10978. }
  10979. }
  10980. this.normalizeRowNodeHeights(rowNodes);
  10981. },
  10982. normalizeRowNodeHeights: function(inRowNodes){
  10983. var h = 0;
  10984. var currHeights = [];
  10985. if(this.grid.rowHeight){
  10986. h = this.grid.rowHeight;
  10987. }else{
  10988. if(inRowNodes.length <= 1){
  10989. // no need to normalize if we are the only one...
  10990. return;
  10991. }
  10992. for(var i=0, n; (n=inRowNodes[i]); i++){
  10993. // We only care about the height - so don't use marginBox. This
  10994. // depends on the container not having any margin (which it shouldn't)
  10995. // Also - we only look up the height if the cell doesn't have the
  10996. // dojoxGridNonNormalizedCell class (like for row selectors)
  10997. if(!domClass.contains(n, "dojoxGridNonNormalizedCell")){
  10998. currHeights[i] = n.firstChild.offsetHeight;
  10999. h = Math.max(h, currHeights[i]);
  11000. }
  11001. }
  11002. h = (h >= 0 ? h : 0);
  11003. //Work around odd FF3 rendering bug: #8864.
  11004. //A one px increase fixes FireFox 3's rounding bug for fractional font sizes.
  11005. if((has("mozilla") || has("ie") > 8 ) && h){h++;}
  11006. }
  11007. for(i=0; (n=inRowNodes[i]); i++){
  11008. if(currHeights[i] != h){
  11009. n.firstChild.style.height = h + "px";
  11010. }
  11011. }
  11012. },
  11013. resetHeaderNodeHeight: function(){
  11014. for(var i=0, v, n; (v=this.views[i]); i++){
  11015. n = v.headerContentNode.firstChild;
  11016. if(n){
  11017. n.style.height = "";
  11018. }
  11019. }
  11020. },
  11021. renormalizeRow: function(inRowIndex){
  11022. var rowNodes = [];
  11023. for(var i=0, v, n; (v=this.views[i])&&(n=v.getRowNode(inRowIndex)); i++){
  11024. n.firstChild.style.height = '';
  11025. rowNodes.push(n);
  11026. }
  11027. this.normalizeRowNodeHeights(rowNodes);
  11028. },
  11029. getViewWidth: function(inIndex){
  11030. return this.views[inIndex].getWidth() || this.defaultWidth;
  11031. },
  11032. // must be called after view widths are properly set or height can be miscalculated
  11033. // if there are flex columns
  11034. measureHeader: function(){
  11035. // need to reset view header heights so they are properly measured.
  11036. this.resetHeaderNodeHeight();
  11037. this.forEach(function(inView){
  11038. inView.headerContentNode.style.height = '';
  11039. });
  11040. var h = 0;
  11041. // calculate maximum view header height
  11042. this.forEach(function(inView){
  11043. h = Math.max(inView.headerNode.offsetHeight, h);
  11044. });
  11045. return h;
  11046. },
  11047. measureContent: function(){
  11048. var h = 0;
  11049. this.forEach(function(inView){
  11050. h = Math.max(inView.domNode.offsetHeight, h);
  11051. });
  11052. return h;
  11053. },
  11054. findClient: function(inAutoWidth){
  11055. // try to use user defined client
  11056. var c = this.grid.elasticView || -1;
  11057. // attempt to find implicit client
  11058. if(c < 0){
  11059. for(var i=1, v; (v=this.views[i]); i++){
  11060. if(v.viewWidth){
  11061. for(i=1; (v=this.views[i]); i++){
  11062. if(!v.viewWidth){
  11063. c = i;
  11064. break;
  11065. }
  11066. }
  11067. break;
  11068. }
  11069. }
  11070. }
  11071. // client is in the middle by default
  11072. if(c < 0){
  11073. c = Math.floor(this.views.length / 2);
  11074. }
  11075. return c;
  11076. },
  11077. arrange: function(l, w){
  11078. var i, v, vw, len = this.views.length, self = this;
  11079. // find the client
  11080. var c = (w <= 0 ? len : this.findClient());
  11081. // layout views
  11082. var setPosition = function(v, l){
  11083. var ds = v.domNode.style;
  11084. var hs = v.headerNode.style;
  11085. if(!self.grid.isLeftToRight()){
  11086. ds.right = l + 'px';
  11087. // fixed rtl, the scrollbar is on the right side in FF < 4
  11088. if (has("ff") < 4){
  11089. hs.right = l + v.getScrollbarWidth() + 'px';
  11090. }else{
  11091. hs.right = l + 'px';
  11092. }
  11093. if(!has("webkit")){
  11094. hs.width = parseInt(hs.width, 10) - v.getScrollbarWidth() + 'px';
  11095. }
  11096. }else{
  11097. ds.left = l + 'px';
  11098. hs.left = l + 'px';
  11099. }
  11100. ds.top = 0 + 'px';
  11101. hs.top = 0;
  11102. };
  11103. // for views left of the client
  11104. //BiDi TODO: The left and right should not appear in BIDI environment. Should be replaced with
  11105. //leading and tailing concept.
  11106. for(i=0; (v=this.views[i])&&(i<c); i++){
  11107. // get width
  11108. vw = this.getViewWidth(i);
  11109. // process boxes
  11110. v.setSize(vw, 0);
  11111. setPosition(v, l);
  11112. if(v.headerContentNode && v.headerContentNode.firstChild){
  11113. vw = v.getColumnsWidth()+v.getScrollbarWidth();
  11114. }else{
  11115. vw = v.domNode.offsetWidth;
  11116. }
  11117. // update position
  11118. l += vw;
  11119. }
  11120. // next view (is the client, i++ == c)
  11121. i++;
  11122. // start from the right edge
  11123. var r = w;
  11124. // for views right of the client (iterated from the right)
  11125. for(var j=len-1; (v=this.views[j])&&(i<=j); j--){
  11126. // get width
  11127. vw = this.getViewWidth(j);
  11128. // set size
  11129. v.setSize(vw, 0);
  11130. // measure in pixels
  11131. vw = v.domNode.offsetWidth;
  11132. // update position
  11133. r -= vw;
  11134. // set position
  11135. setPosition(v, r);
  11136. }
  11137. if(c<len){
  11138. v = this.views[c];
  11139. // position the client box between left and right boxes
  11140. vw = Math.max(1, r-l);
  11141. // set size
  11142. v.setSize(vw + 'px', 0);
  11143. setPosition(v, l);
  11144. }
  11145. return l;
  11146. },
  11147. // rendering
  11148. renderRow: function(inRowIndex, inNodes, skipRenorm){
  11149. var rowNodes = [];
  11150. for(var i=0, v, n, rowNode; (v=this.views[i])&&(n=inNodes[i]); i++){
  11151. rowNode = v.renderRow(inRowIndex);
  11152. n.appendChild(rowNode);
  11153. rowNodes.push(rowNode);
  11154. }
  11155. if(!skipRenorm){
  11156. this.normalizeRowNodeHeights(rowNodes);
  11157. }
  11158. },
  11159. rowRemoved: function(inRowIndex){
  11160. this.onEach("rowRemoved", [ inRowIndex ]);
  11161. },
  11162. // updating
  11163. updateRow: function(inRowIndex, skipRenorm){
  11164. for(var i=0, v; v=this.views[i]; i++){
  11165. v.updateRow(inRowIndex);
  11166. }
  11167. if(!skipRenorm){
  11168. this.renormalizeRow(inRowIndex);
  11169. }
  11170. },
  11171. updateRowStyles: function(inRowIndex){
  11172. this.onEach("updateRowStyles", [ inRowIndex ]);
  11173. },
  11174. // scrolling
  11175. setScrollTop: function(inTop){
  11176. var top = inTop;
  11177. for(var i=0, v; v=this.views[i]; i++){
  11178. top = v.setScrollTop(inTop);
  11179. // Work around IE not firing scroll events that cause header offset
  11180. // issues to occur.
  11181. if(has("ie") && v.headerNode && v.scrollboxNode){
  11182. v.headerNode.scrollLeft = v.scrollboxNode.scrollLeft;
  11183. }
  11184. }
  11185. return top;
  11186. //this.onEach("setScrollTop", [ inTop ]);
  11187. },
  11188. getFirstScrollingView: function(){
  11189. // summary: Returns the first grid view with a scroll bar
  11190. for(var i=0, v; (v=this.views[i]); i++){
  11191. if(v.hasHScrollbar() || v.hasVScrollbar()){
  11192. return v;
  11193. }
  11194. }
  11195. return null;
  11196. }
  11197. });
  11198. });
  11199. },
  11200. 'dijit/form/NumberTextBox':function(){
  11201. define("dijit/form/NumberTextBox", [
  11202. "dojo/_base/declare", // declare
  11203. "dojo/_base/lang", // lang.hitch lang.mixin
  11204. "dojo/number", // number._realNumberRegexp number.format number.parse number.regexp
  11205. "./RangeBoundTextBox"
  11206. ], function(declare, lang, number, RangeBoundTextBox){
  11207. /*=====
  11208. var RangeBoundTextBox = dijit.form.RangeBoundTextBox;
  11209. =====*/
  11210. // module:
  11211. // dijit/form/NumberTextBox
  11212. // summary:
  11213. // A TextBox for entering numbers, with formatting and range checking
  11214. /*=====
  11215. declare(
  11216. "dijit.form.NumberTextBox.__Constraints",
  11217. [dijit.form.RangeBoundTextBox.__Constraints, number.__FormatOptions, number.__ParseOptions], {
  11218. // summary:
  11219. // Specifies both the rules on valid/invalid values (minimum, maximum,
  11220. // number of required decimal places), and also formatting options for
  11221. // displaying the value when the field is not focused.
  11222. // example:
  11223. // Minimum/maximum:
  11224. // To specify a field between 0 and 120:
  11225. // | {min:0,max:120}
  11226. // To specify a field that must be an integer:
  11227. // | {fractional:false}
  11228. // To specify a field where 0 to 3 decimal places are allowed on input:
  11229. // | {places:'0,3'}
  11230. });
  11231. =====*/
  11232. var NumberTextBoxMixin = declare("dijit.form.NumberTextBoxMixin", null, {
  11233. // summary:
  11234. // A mixin for all number textboxes
  11235. // tags:
  11236. // protected
  11237. // Override ValidationTextBox.regExpGen().... we use a reg-ex generating function rather
  11238. // than a straight regexp to deal with locale (plus formatting options too?)
  11239. regExpGen: number.regexp,
  11240. /*=====
  11241. // constraints: dijit.form.NumberTextBox.__Constraints
  11242. // Despite the name, this parameter specifies both constraints on the input
  11243. // (including minimum/maximum allowed values) as well as
  11244. // formatting options like places (the number of digits to display after
  11245. // the decimal point). See `dijit.form.NumberTextBox.__Constraints` for details.
  11246. constraints: {},
  11247. ======*/
  11248. // value: Number
  11249. // The value of this NumberTextBox as a Javascript Number (i.e., not a String).
  11250. // If the displayed value is blank, the value is NaN, and if the user types in
  11251. // an gibberish value (like "hello world"), the value is undefined
  11252. // (i.e. get('value') returns undefined).
  11253. //
  11254. // Symmetrically, set('value', NaN) will clear the displayed value,
  11255. // whereas set('value', undefined) will have no effect.
  11256. value: NaN,
  11257. // editOptions: [protected] Object
  11258. // Properties to mix into constraints when the value is being edited.
  11259. // This is here because we edit the number in the format "12345", which is
  11260. // different than the display value (ex: "12,345")
  11261. editOptions: { pattern: '#.######' },
  11262. /*=====
  11263. _formatter: function(value, options){
  11264. // summary:
  11265. // _formatter() is called by format(). It's the base routine for formatting a number,
  11266. // as a string, for example converting 12345 into "12,345".
  11267. // value: Number
  11268. // The number to be converted into a string.
  11269. // options: dojo.number.__FormatOptions?
  11270. // Formatting options
  11271. // tags:
  11272. // protected extension
  11273. return "12345"; // String
  11274. },
  11275. =====*/
  11276. _formatter: number.format,
  11277. postMixInProperties: function(){
  11278. this.inherited(arguments);
  11279. this._set("type", "text"); // in case type="number" was specified which messes up parse/format
  11280. },
  11281. _setConstraintsAttr: function(/*Object*/ constraints){
  11282. var places = typeof constraints.places == "number"? constraints.places : 0;
  11283. if(places){ places++; } // decimal rounding errors take away another digit of precision
  11284. if(typeof constraints.max != "number"){
  11285. constraints.max = 9 * Math.pow(10, 15-places);
  11286. }
  11287. if(typeof constraints.min != "number"){
  11288. constraints.min = -9 * Math.pow(10, 15-places);
  11289. }
  11290. this.inherited(arguments, [ constraints ]);
  11291. if(this.focusNode && this.focusNode.value && !isNaN(this.value)){
  11292. this.set('value', this.value);
  11293. }
  11294. },
  11295. _onFocus: function(){
  11296. if(this.disabled){ return; }
  11297. var val = this.get('value');
  11298. if(typeof val == "number" && !isNaN(val)){
  11299. var formattedValue = this.format(val, this.constraints);
  11300. if(formattedValue !== undefined){
  11301. this.textbox.value = formattedValue;
  11302. }
  11303. }
  11304. this.inherited(arguments);
  11305. },
  11306. format: function(/*Number*/ value, /*dojo.number.__FormatOptions*/ constraints){
  11307. // summary:
  11308. // Formats the value as a Number, according to constraints.
  11309. // tags:
  11310. // protected
  11311. var formattedValue = String(value);
  11312. if(typeof value != "number"){ return formattedValue; }
  11313. if(isNaN(value)){ return ""; }
  11314. // check for exponential notation that dojo.number.format chokes on
  11315. if(!("rangeCheck" in this && this.rangeCheck(value, constraints)) && constraints.exponent !== false && /\de[-+]?\d/i.test(formattedValue)){
  11316. return formattedValue;
  11317. }
  11318. if(this.editOptions && this.focused){
  11319. constraints = lang.mixin({}, constraints, this.editOptions);
  11320. }
  11321. return this._formatter(value, constraints);
  11322. },
  11323. /*=====
  11324. _parser: function(value, constraints){
  11325. // summary:
  11326. // Parses the string value as a Number, according to constraints.
  11327. // value: String
  11328. // String representing a number
  11329. // constraints: dojo.number.__ParseOptions
  11330. // Formatting options
  11331. // tags:
  11332. // protected
  11333. return 123.45; // Number
  11334. },
  11335. =====*/
  11336. _parser: number.parse,
  11337. parse: function(/*String*/ value, /*number.__FormatOptions*/ constraints){
  11338. // summary:
  11339. // Replaceable function to convert a formatted string to a number value
  11340. // tags:
  11341. // protected extension
  11342. var v = this._parser(value, lang.mixin({}, constraints, (this.editOptions && this.focused) ? this.editOptions : {}));
  11343. if(this.editOptions && this.focused && isNaN(v)){
  11344. v = this._parser(value, constraints); // parse w/o editOptions: not technically needed but is nice for the user
  11345. }
  11346. return v;
  11347. },
  11348. _getDisplayedValueAttr: function(){
  11349. var v = this.inherited(arguments);
  11350. return isNaN(v) ? this.textbox.value : v;
  11351. },
  11352. filter: function(/*Number*/ value){
  11353. // summary:
  11354. // This is called with both the display value (string), and the actual value (a number).
  11355. // When called with the actual value it does corrections so that '' etc. are represented as NaN.
  11356. // Otherwise it dispatches to the superclass's filter() method.
  11357. //
  11358. // See `dijit.form.TextBox.filter` for more details.
  11359. return (value === null || value === '' || value === undefined) ? NaN : this.inherited(arguments); // set('value', null||''||undefined) should fire onChange(NaN)
  11360. },
  11361. serialize: function(/*Number*/ value, /*Object?*/ options){
  11362. // summary:
  11363. // Convert value (a Number) into a canonical string (ie, how the number literal is written in javascript/java/C/etc.)
  11364. // tags:
  11365. // protected
  11366. return (typeof value != "number" || isNaN(value)) ? '' : this.inherited(arguments);
  11367. },
  11368. _setBlurValue: function(){
  11369. var val = lang.hitch(lang.mixin({}, this, { focused: true }), "get")('value'); // parse with editOptions
  11370. this._setValueAttr(val, true);
  11371. },
  11372. _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
  11373. // summary:
  11374. // Hook so set('value', ...) works.
  11375. if(value !== undefined && formattedValue === undefined){
  11376. formattedValue = String(value);
  11377. if(typeof value == "number"){
  11378. if(isNaN(value)){ formattedValue = '' }
  11379. // check for exponential notation that number.format chokes on
  11380. else if(("rangeCheck" in this && this.rangeCheck(value, this.constraints)) || this.constraints.exponent === false || !/\de[-+]?\d/i.test(formattedValue)){
  11381. formattedValue = undefined; // lets format compute a real string value
  11382. }
  11383. }else if(!value){ // 0 processed in if branch above, ''|null|undefined flows through here
  11384. formattedValue = '';
  11385. value = NaN;
  11386. }else{ // non-numeric values
  11387. value = undefined;
  11388. }
  11389. }
  11390. this.inherited(arguments, [value, priorityChange, formattedValue]);
  11391. },
  11392. _getValueAttr: function(){
  11393. // summary:
  11394. // Hook so get('value') works.
  11395. // Returns Number, NaN for '', or undefined for unparseable text
  11396. var v = this.inherited(arguments); // returns Number for all values accepted by parse() or NaN for all other displayed values
  11397. // If the displayed value of the textbox is gibberish (ex: "hello world"), this.inherited() above
  11398. // returns NaN; this if() branch converts the return value to undefined.
  11399. // Returning undefined prevents user text from being overwritten when doing _setValueAttr(_getValueAttr()).
  11400. // A blank displayed value is still returned as NaN.
  11401. if(isNaN(v) && this.textbox.value !== ''){
  11402. 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?)
  11403. var n = Number(this.textbox.value);
  11404. return isNaN(n) ? undefined : n; // return exponential Number or undefined for random text (may not be possible to do with the above RegExp check)
  11405. }else{
  11406. return undefined; // gibberish
  11407. }
  11408. }else{
  11409. return v; // Number or NaN for ''
  11410. }
  11411. },
  11412. isValid: function(/*Boolean*/ isFocused){
  11413. // Overrides dijit.form.RangeBoundTextBox.isValid to check that the editing-mode value is valid since
  11414. // it may not be formatted according to the regExp validation rules
  11415. if(!this.focused || this._isEmpty(this.textbox.value)){
  11416. return this.inherited(arguments);
  11417. }else{
  11418. var v = this.get('value');
  11419. if(!isNaN(v) && this.rangeCheck(v, this.constraints)){
  11420. if(this.constraints.exponent !== false && /\de[-+]?\d/i.test(this.textbox.value)){ // exponential, parse doesn't like it
  11421. return true; // valid exponential number in range
  11422. }else{
  11423. return this.inherited(arguments);
  11424. }
  11425. }else{
  11426. return false;
  11427. }
  11428. }
  11429. }
  11430. });
  11431. /*=====
  11432. NumberTextBoxMixin = dijit.form.NumberTextBoxMixin;
  11433. =====*/
  11434. var NumberTextBox = declare("dijit.form.NumberTextBox", [RangeBoundTextBox,NumberTextBoxMixin], {
  11435. // summary:
  11436. // A TextBox for entering numbers, with formatting and range checking
  11437. // description:
  11438. // NumberTextBox is a textbox for entering and displaying numbers, supporting
  11439. // the following main features:
  11440. //
  11441. // 1. Enforce minimum/maximum allowed values (as well as enforcing that the user types
  11442. // a number rather than a random string)
  11443. // 2. NLS support (altering roles of comma and dot as "thousands-separator" and "decimal-point"
  11444. // depending on locale).
  11445. // 3. Separate modes for editing the value and displaying it, specifically that
  11446. // the thousands separator character (typically comma) disappears when editing
  11447. // but reappears after the field is blurred.
  11448. // 4. Formatting and constraints regarding the number of places (digits after the decimal point)
  11449. // allowed on input, and number of places displayed when blurred (see `constraints` parameter).
  11450. baseClass: "dijitTextBox dijitNumberTextBox"
  11451. });
  11452. NumberTextBox.Mixin = NumberTextBoxMixin; // for monkey patching
  11453. return NumberTextBox;
  11454. });
  11455. },
  11456. 'dijit/form/TimeTextBox':function(){
  11457. define("dijit/form/TimeTextBox", [
  11458. "dojo/_base/declare", // declare
  11459. "dojo/keys", // keys.DOWN_ARROW keys.ENTER keys.ESCAPE keys.TAB keys.UP_ARROW
  11460. "dojo/_base/lang", // lang.hitch
  11461. "../_TimePicker",
  11462. "./_DateTimeTextBox"
  11463. ], function(declare, keys, lang, _TimePicker, _DateTimeTextBox){
  11464. /*=====
  11465. var _TimePicker = dijit._TimePicker;
  11466. var _DateTimeTextBox = dijit.form._DateTimeTextBox;
  11467. =====*/
  11468. // module:
  11469. // dijit/form/TimeTextBox
  11470. // summary:
  11471. // A validating, serializable, range-bound time text box with a drop down time picker
  11472. /*=====
  11473. declare(
  11474. "dijit.form.TimeTextBox.__Constraints",
  11475. [dijit.form._DateTimeTextBox.__Constraints, dijit._TimePicker.__Constraints]
  11476. );
  11477. =====*/
  11478. return declare("dijit.form.TimeTextBox", _DateTimeTextBox, {
  11479. // summary:
  11480. // A validating, serializable, range-bound time text box with a drop down time picker
  11481. baseClass: "dijitTextBox dijitComboBox dijitTimeTextBox",
  11482. popupClass: _TimePicker,
  11483. _selector: "time",
  11484. /*=====
  11485. // constraints: dijit.form.TimeTextBox.__Constraints
  11486. constraints:{},
  11487. =====*/
  11488. // value: Date
  11489. // The value of this widget as a JavaScript Date object. Note that the date portion implies time zone and daylight savings rules.
  11490. //
  11491. // Example:
  11492. // | new dijit.form.TimeTextBox({value: stamp.fromISOString("T12:59:59", new Date())})
  11493. //
  11494. // When passed to the parser in markup, must be specified according to locale-independent
  11495. // `stamp.fromISOString` format.
  11496. //
  11497. // Example:
  11498. // | <input data-dojo-type='dijit.form.TimeTextBox' value='T12:34:00'>
  11499. value: new Date(""), // value.toString()="NaN"
  11500. //FIXME: in markup, you have no control over daylight savings
  11501. _onKey: function(evt){
  11502. if(this.disabled || this.readOnly){ return; }
  11503. this.inherited(arguments);
  11504. // If the user has backspaced or typed some numbers, then filter the result list
  11505. // by what they typed. Maybe there's a better way to detect this, like _handleOnChange()?
  11506. switch(evt.keyCode){
  11507. case keys.ENTER:
  11508. case keys.TAB:
  11509. case keys.ESCAPE:
  11510. case keys.DOWN_ARROW:
  11511. case keys.UP_ARROW:
  11512. // these keys have special meaning
  11513. break;
  11514. default:
  11515. // setTimeout() because the keystroke hasn't yet appeared in the <input>,
  11516. // so the get('displayedValue') call below won't give the result we want.
  11517. setTimeout(lang.hitch(this, function(){
  11518. // set this.filterString to the filter to apply to the drop down list;
  11519. // it will be used in openDropDown()
  11520. var val = this.get('displayedValue');
  11521. this.filterString = (val && !this.parse(val, this.constraints)) ? val.toLowerCase() : "";
  11522. // close the drop down and reopen it, in order to filter the items shown in the list
  11523. // and also since the drop down may need to be repositioned if the number of list items has changed
  11524. // and it's being displayed above the <input>
  11525. if(this._opened){
  11526. this.closeDropDown();
  11527. }
  11528. this.openDropDown();
  11529. }), 0);
  11530. }
  11531. }
  11532. });
  11533. });
  11534. },
  11535. 'url:dijit/form/templates/Button.html':"<span class=\"dijit dijitReset dijitInline\" role=\"presentation\"\r\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\r\n\t\tdata-dojo-attach-event=\"ondijitclick:_onClick\" role=\"presentation\"\r\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\r\n\t\t\tdata-dojo-attach-point=\"titleNode,focusNode\"\r\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\r\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" data-dojo-attach-point=\"iconNode\"></span\r\n\t\t\t><span class=\"dijitReset dijitToggleButtonIconChar\">&#x25CF;</span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\r\n\t\t\t\tid=\"${id}_label\"\r\n\t\t\t\tdata-dojo-attach-point=\"containerNode\"\r\n\t\t\t></span\r\n\t\t></span\r\n\t></span\r\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\r\n\t\ttabIndex=\"-1\" role=\"presentation\" data-dojo-attach-point=\"valueNode\"\r\n/></span>\r\n",
  11536. 'dijit/form/CurrencyTextBox':function(){
  11537. define("dijit/form/CurrencyTextBox", [
  11538. "dojo/currency", // currency._mixInDefaults currency.format currency.parse currency.regexp
  11539. "dojo/_base/declare", // declare
  11540. "dojo/_base/lang", // lang.hitch
  11541. "./NumberTextBox"
  11542. ], function(currency, declare, lang, NumberTextBox){
  11543. /*=====
  11544. var NumberTextBox = dijit.form.NumberTextBox;
  11545. =====*/
  11546. // module:
  11547. // dijit/form/CurrencyTextBox
  11548. // summary:
  11549. // A validating currency textbox
  11550. /*=====
  11551. declare(
  11552. "dijit.form.CurrencyTextBox.__Constraints",
  11553. [dijit.form.NumberTextBox.__Constraints, currency.__FormatOptions, currency.__ParseOptions], {
  11554. // summary:
  11555. // Specifies both the rules on valid/invalid values (minimum, maximum,
  11556. // number of required decimal places), and also formatting options for
  11557. // displaying the value when the field is not focused (currency symbol,
  11558. // etc.)
  11559. // description:
  11560. // Follows the pattern of `dijit.form.NumberTextBox.constraints`.
  11561. // In general developers won't need to set this parameter
  11562. // example:
  11563. // To ensure that the user types in the cents (for example, 1.00 instead of just 1):
  11564. // | {fractional:true}
  11565. });
  11566. =====*/
  11567. return declare("dijit.form.CurrencyTextBox", NumberTextBox, {
  11568. // summary:
  11569. // A validating currency textbox
  11570. // description:
  11571. // CurrencyTextBox is similar to `dijit.form.NumberTextBox` but has a few
  11572. // extra features related to currency:
  11573. //
  11574. // 1. After specifying the currency type (american dollars, euros, etc.) it automatically
  11575. // sets parse/format options such as how many decimal places to show.
  11576. // 2. The currency mark (dollar sign, euro mark, etc.) is displayed when the field is blurred
  11577. // but erased during editing, so that the user can just enter a plain number.
  11578. // currency: [const] String
  11579. // the [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code, a three letter sequence like "USD"
  11580. currency: "",
  11581. /*=====
  11582. // constraints: dijit.form.CurrencyTextBox.__Constraints
  11583. // Despite the name, this parameter specifies both constraints on the input
  11584. // (including minimum/maximum allowed values) as well as
  11585. // formatting options. See `dijit.form.CurrencyTextBox.__Constraints` for details.
  11586. constraints: {},
  11587. ======*/
  11588. baseClass: "dijitTextBox dijitCurrencyTextBox",
  11589. // Override regExpGen ValidationTextBox.regExpGen().... we use a reg-ex generating function rather
  11590. // than a straight regexp to deal with locale (plus formatting options too?)
  11591. regExpGen: function(constraints){
  11592. // if focused, accept either currency data or NumberTextBox format
  11593. return '(' + (this.focused ? this.inherited(arguments, [ lang.mixin({}, constraints, this.editOptions) ]) + '|' : '')
  11594. + currency.regexp(constraints) + ')';
  11595. },
  11596. // Override NumberTextBox._formatter to deal with currencies, ex: converts "123.45" to "$123.45"
  11597. _formatter: currency.format,
  11598. _parser: currency.parse,
  11599. parse: function(/*String*/ value, /*Object*/ constraints){
  11600. // summary:
  11601. // Parses string value as a Currency, according to the constraints object
  11602. // tags:
  11603. // protected extension
  11604. var v = this.inherited(arguments);
  11605. if(isNaN(v) && /\d+/.test(value)){ // currency parse failed, but it could be because they are using NumberTextBox format so try its parse
  11606. v = lang.hitch(lang.mixin({}, this, { _parser: NumberTextBox.prototype._parser }), "inherited")(arguments);
  11607. }
  11608. return v;
  11609. },
  11610. _setConstraintsAttr: function(/*Object*/ constraints){
  11611. if(!constraints.currency && this.currency){
  11612. constraints.currency = this.currency;
  11613. }
  11614. this.inherited(arguments, [ currency._mixInDefaults(lang.mixin(constraints, { exponent: false })) ]); // get places
  11615. }
  11616. });
  11617. });
  11618. },
  11619. 'dojo/_base/url':function(){
  11620. define("dojo/_base/url", ["./kernel"], function(dojo) {
  11621. // module:
  11622. // dojo/url
  11623. // summary:
  11624. // This module contains dojo._Url
  11625. var
  11626. ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$"),
  11627. ire = new RegExp("^((([^\\[:]+):)?([^@]+)@)?(\\[([^\\]]+)\\]|([^\\[:]*))(:([0-9]+))?$"),
  11628. _Url = function(){
  11629. var n = null,
  11630. _a = arguments,
  11631. uri = [_a[0]];
  11632. // resolve uri components relative to each other
  11633. for(var i = 1; i<_a.length; i++){
  11634. if(!_a[i]){ continue; }
  11635. // Safari doesn't support this.constructor so we have to be explicit
  11636. // FIXME: Tracked (and fixed) in Webkit bug 3537.
  11637. // http://bugs.webkit.org/show_bug.cgi?id=3537
  11638. var relobj = new _Url(_a[i]+""),
  11639. uriobj = new _Url(uri[0]+"");
  11640. if(
  11641. relobj.path == "" &&
  11642. !relobj.scheme &&
  11643. !relobj.authority &&
  11644. !relobj.query
  11645. ){
  11646. if(relobj.fragment != n){
  11647. uriobj.fragment = relobj.fragment;
  11648. }
  11649. relobj = uriobj;
  11650. }else if(!relobj.scheme){
  11651. relobj.scheme = uriobj.scheme;
  11652. if(!relobj.authority){
  11653. relobj.authority = uriobj.authority;
  11654. if(relobj.path.charAt(0) != "/"){
  11655. var path = uriobj.path.substring(0,
  11656. uriobj.path.lastIndexOf("/") + 1) + relobj.path;
  11657. var segs = path.split("/");
  11658. for(var j = 0; j < segs.length; j++){
  11659. if(segs[j] == "."){
  11660. // flatten "./" references
  11661. if(j == segs.length - 1){
  11662. segs[j] = "";
  11663. }else{
  11664. segs.splice(j, 1);
  11665. j--;
  11666. }
  11667. }else if(j > 0 && !(j == 1 && segs[0] == "") &&
  11668. segs[j] == ".." && segs[j-1] != ".."){
  11669. // flatten "../" references
  11670. if(j == (segs.length - 1)){
  11671. segs.splice(j, 1);
  11672. segs[j - 1] = "";
  11673. }else{
  11674. segs.splice(j - 1, 2);
  11675. j -= 2;
  11676. }
  11677. }
  11678. }
  11679. relobj.path = segs.join("/");
  11680. }
  11681. }
  11682. }
  11683. uri = [];
  11684. if(relobj.scheme){
  11685. uri.push(relobj.scheme, ":");
  11686. }
  11687. if(relobj.authority){
  11688. uri.push("//", relobj.authority);
  11689. }
  11690. uri.push(relobj.path);
  11691. if(relobj.query){
  11692. uri.push("?", relobj.query);
  11693. }
  11694. if(relobj.fragment){
  11695. uri.push("#", relobj.fragment);
  11696. }
  11697. }
  11698. this.uri = uri.join("");
  11699. // break the uri into its main components
  11700. var r = this.uri.match(ore);
  11701. this.scheme = r[2] || (r[1] ? "" : n);
  11702. this.authority = r[4] || (r[3] ? "" : n);
  11703. this.path = r[5]; // can never be undefined
  11704. this.query = r[7] || (r[6] ? "" : n);
  11705. this.fragment = r[9] || (r[8] ? "" : n);
  11706. if(this.authority != n){
  11707. // server based naming authority
  11708. r = this.authority.match(ire);
  11709. this.user = r[3] || n;
  11710. this.password = r[4] || n;
  11711. this.host = r[6] || r[7]; // ipv6 || ipv4
  11712. this.port = r[9] || n;
  11713. }
  11714. };
  11715. _Url.prototype.toString = function(){ return this.uri; };
  11716. return dojo._Url = _Url;
  11717. });
  11718. },
  11719. 'dojox/main':function(){
  11720. define("dojox/main", ["dojo/_base/kernel"], function(dojo) {
  11721. // module:
  11722. // dojox/main
  11723. // summary:
  11724. // The dojox package main module; dojox package is somewhat unusual in that the main module currently just provides an empty object.
  11725. return dojo.dojox;
  11726. });
  11727. },
  11728. 'dojo/text':function(){
  11729. define("dojo/text", ["./_base/kernel", "require", "./has", "./_base/xhr"], function(dojo, require, has, xhr){
  11730. // module:
  11731. // dojo/text
  11732. // summary:
  11733. // This module implements the !dojo/text plugin and the dojo.cache API.
  11734. // description:
  11735. // We choose to include our own plugin to leverage functionality already contained in dojo
  11736. // and thereby reduce the size of the plugin compared to various foreign loader implementations.
  11737. // Also, this allows foreign AMD loaders to be used without their plugins.
  11738. //
  11739. // CAUTION: this module is designed to optionally function synchronously to support the dojo v1.x synchronous
  11740. // loader. This feature is outside the scope of the CommonJS plugins specification.
  11741. var getText;
  11742. if(1){
  11743. getText= function(url, sync, load){
  11744. xhr("GET", {url:url, sync:!!sync, load:load});
  11745. };
  11746. }else{
  11747. // TODOC: only works for dojo AMD loader
  11748. if(require.getText){
  11749. getText= require.getText;
  11750. }else{
  11751. console.error("dojo/text plugin failed to load because loader does not support getText");
  11752. }
  11753. }
  11754. var
  11755. theCache= {},
  11756. strip= function(text){
  11757. //Strips <?xml ...?> declarations so that external SVG and XML
  11758. //documents can be added to a document without worry. Also, if the string
  11759. //is an HTML document, only the part inside the body tag is returned.
  11760. if(text){
  11761. text= text.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
  11762. var matches= text.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
  11763. if(matches){
  11764. text= matches[1];
  11765. }
  11766. }else{
  11767. text = "";
  11768. }
  11769. return text;
  11770. },
  11771. notFound = {},
  11772. pending = {},
  11773. result= {
  11774. dynamic:
  11775. // the dojo/text caches it's own resources because of dojo.cache
  11776. true,
  11777. normalize:function(id, toAbsMid){
  11778. // id is something like (path may be relative):
  11779. //
  11780. // "path/to/text.html"
  11781. // "path/to/text.html!strip"
  11782. var parts= id.split("!"),
  11783. url= parts[0];
  11784. return (/^\./.test(url) ? toAbsMid(url) : url) + (parts[1] ? "!" + parts[1] : "");
  11785. },
  11786. load:function(id, require, load){
  11787. // id is something like (path is always absolute):
  11788. //
  11789. // "path/to/text.html"
  11790. // "path/to/text.html!strip"
  11791. var
  11792. parts= id.split("!"),
  11793. stripFlag= parts.length>1,
  11794. absMid= parts[0],
  11795. url = require.toUrl(parts[0]),
  11796. text = notFound,
  11797. finish = function(text){
  11798. load(stripFlag ? strip(text) : text);
  11799. };
  11800. if(absMid in theCache){
  11801. text = theCache[absMid];
  11802. }else if(url in require.cache){
  11803. text = require.cache[url];
  11804. }else if(url in theCache){
  11805. text = theCache[url];
  11806. }
  11807. if(text===notFound){
  11808. if(pending[url]){
  11809. pending[url].push(finish);
  11810. }else{
  11811. var pendingList = pending[url] = [finish];
  11812. getText(url, !require.async, function(text){
  11813. theCache[absMid]= theCache[url]= text;
  11814. for(var i = 0; i<pendingList.length;){
  11815. pendingList[i++](text);
  11816. }
  11817. delete pending[url];
  11818. });
  11819. }
  11820. }else{
  11821. finish(text);
  11822. }
  11823. }
  11824. };
  11825. dojo.cache= function(/*String||Object*/module, /*String*/url, /*String||Object?*/value){
  11826. // * (string string [value]) => (module, url, value)
  11827. // * (object [value]) => (module, value), url defaults to ""
  11828. //
  11829. // * if module is an object, then it must be convertable to a string
  11830. // * (module, url) module + (url ? ("/" + url) : "") must be a legal argument to require.toUrl
  11831. // * value may be a string or an object; if an object then may have the properties "value" and/or "sanitize"
  11832. var key;
  11833. if(typeof module=="string"){
  11834. if(/\//.test(module)){
  11835. // module is a version 1.7+ resolved path
  11836. key = module;
  11837. value = url;
  11838. }else{
  11839. // module is a version 1.6- argument to dojo.moduleUrl
  11840. key = require.toUrl(module.replace(/\./g, "/") + (url ? ("/" + url) : ""));
  11841. }
  11842. }else{
  11843. key = module + "";
  11844. value = url;
  11845. }
  11846. var
  11847. val = (value != undefined && typeof value != "string") ? value.value : value,
  11848. sanitize = value && value.sanitize;
  11849. if(typeof val == "string"){
  11850. //We have a string, set cache value
  11851. theCache[key] = val;
  11852. return sanitize ? strip(val) : val;
  11853. }else if(val === null){
  11854. //Remove cached value
  11855. delete theCache[key];
  11856. return null;
  11857. }else{
  11858. //Allow cache values to be empty strings. If key property does
  11859. //not exist, fetch it.
  11860. if(!(key in theCache)){
  11861. getText(key, true, function(text){
  11862. theCache[key]= text;
  11863. });
  11864. }
  11865. return sanitize ? strip(theCache[key]) : theCache[key];
  11866. }
  11867. };
  11868. return result;
  11869. /*=====
  11870. dojo.cache = function(module, url, value){
  11871. // summary:
  11872. // A getter and setter for storing the string content associated with the
  11873. // module and url arguments.
  11874. // description:
  11875. // If module is a string that contains slashes, then it is interpretted as a fully
  11876. // resolved path (typically a result returned by require.toUrl), and url should not be
  11877. // provided. This is the preferred signature. If module is a string that does not
  11878. // contain slashes, then url must also be provided and module and url are used to
  11879. // call `dojo.moduleUrl()` to generate a module URL. This signature is deprecated.
  11880. // If value is specified, the cache value for the moduleUrl will be set to
  11881. // that value. Otherwise, dojo.cache will fetch the moduleUrl and store it
  11882. // in its internal cache and return that cached value for the URL. To clear
  11883. // a cache value pass null for value. Since XMLHttpRequest (XHR) is used to fetch the
  11884. // the URL contents, only modules on the same domain of the page can use this capability.
  11885. // The build system can inline the cache values though, to allow for xdomain hosting.
  11886. // module: String||Object
  11887. // If a String with slashes, a fully resolved path; if a String without slashes, the
  11888. // module name to use for the base part of the URL, similar to module argument
  11889. // to `dojo.moduleUrl`. If an Object, something that has a .toString() method that
  11890. // generates a valid path for the cache item. For example, a dojo._Url object.
  11891. // url: String
  11892. // The rest of the path to append to the path derived from the module argument. If
  11893. // module is an object, then this second argument should be the "value" argument instead.
  11894. // value: String||Object?
  11895. // If a String, the value to use in the cache for the module/url combination.
  11896. // If an Object, it can have two properties: value and sanitize. The value property
  11897. // should be the value to use in the cache, and sanitize can be set to true or false,
  11898. // to indicate if XML declarations should be removed from the value and if the HTML
  11899. // inside a body tag in the value should be extracted as the real value. The value argument
  11900. // or the value property on the value argument are usually only used by the build system
  11901. // as it inlines cache content.
  11902. // example:
  11903. // To ask dojo.cache to fetch content and store it in the cache (the dojo["cache"] style
  11904. // of call is used to avoid an issue with the build system erroneously trying to intern
  11905. // this example. To get the build system to intern your dojo.cache calls, use the
  11906. // "dojo.cache" style of call):
  11907. // | //If template.html contains "<h1>Hello</h1>" that will be
  11908. // | //the value for the text variable.
  11909. // | var text = dojo["cache"]("my.module", "template.html");
  11910. // example:
  11911. // To ask dojo.cache to fetch content and store it in the cache, and sanitize the input
  11912. // (the dojo["cache"] style of call is used to avoid an issue with the build system
  11913. // erroneously trying to intern this example. To get the build system to intern your
  11914. // dojo.cache calls, use the "dojo.cache" style of call):
  11915. // | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the
  11916. // | //text variable will contain just "<h1>Hello</h1>".
  11917. // | var text = dojo["cache"]("my.module", "template.html", {sanitize: true});
  11918. // example:
  11919. // Same example as previous, but demostrates how an object can be passed in as
  11920. // the first argument, then the value argument can then be the second argument.
  11921. // | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the
  11922. // | //text variable will contain just "<h1>Hello</h1>".
  11923. // | var text = dojo["cache"](new dojo._Url("my/module/template.html"), {sanitize: true});
  11924. return val; //String
  11925. };
  11926. =====*/
  11927. });
  11928. },
  11929. 'url:dijit/templates/MenuItem.html':"<tr class=\"dijitReset dijitMenuItem\" data-dojo-attach-point=\"focusNode\" role=\"menuitem\" tabIndex=\"-1\"\r\n\t\tdata-dojo-attach-event=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\r\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\r\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitMenuItemIcon\" data-dojo-attach-point=\"iconNode\"/>\r\n\t</td>\r\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" data-dojo-attach-point=\"containerNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" data-dojo-attach-point=\"accelKeyNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">\r\n\t\t<div data-dojo-attach-point=\"arrowWrapper\" style=\"visibility: hidden\">\r\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuExpand\"/>\r\n\t\t\t<span class=\"dijitMenuExpandA11y\">+</span>\r\n\t\t</div>\r\n\t</td>\r\n</tr>\r\n",
  11930. 'url:dijit/form/templates/CheckBox.html':"<div class=\"dijit dijitReset dijitInline\" role=\"presentation\"\r\n\t><input\r\n\t \t${!nameAttrSetting} type=\"${type}\" ${checkedAttrSetting}\r\n\t\tclass=\"dijitReset dijitCheckBoxInput\"\r\n\t\tdata-dojo-attach-point=\"focusNode\"\r\n\t \tdata-dojo-attach-event=\"onclick:_onClick\"\r\n/></div>\r\n",
  11931. 'dojo/uacss':function(){
  11932. define("dojo/uacss", ["./dom-geometry", "./_base/lang", "./ready", "./_base/sniff", "./_base/window"],
  11933. function(geometry, lang, ready, has, baseWindow){
  11934. // module:
  11935. // dojo/uacss
  11936. // summary:
  11937. // Applies pre-set CSS classes to the top-level HTML node, based on:
  11938. // - browser (ex: dj_ie)
  11939. // - browser version (ex: dj_ie6)
  11940. // - box model (ex: dj_contentBox)
  11941. // - text direction (ex: dijitRtl)
  11942. //
  11943. // In addition, browser, browser version, and box model are
  11944. // combined with an RTL flag when browser text is RTL. ex: dj_ie-rtl.
  11945. var
  11946. html = baseWindow.doc.documentElement,
  11947. ie = has("ie"),
  11948. opera = has("opera"),
  11949. maj = Math.floor,
  11950. ff = has("ff"),
  11951. boxModel = geometry.boxModel.replace(/-/,''),
  11952. classes = {
  11953. "dj_ie": ie,
  11954. "dj_ie6": maj(ie) == 6,
  11955. "dj_ie7": maj(ie) == 7,
  11956. "dj_ie8": maj(ie) == 8,
  11957. "dj_ie9": maj(ie) == 9,
  11958. "dj_quirks": has("quirks"),
  11959. "dj_iequirks": ie && has("quirks"),
  11960. // NOTE: Opera not supported by dijit
  11961. "dj_opera": opera,
  11962. "dj_khtml": has("khtml"),
  11963. "dj_webkit": has("webkit"),
  11964. "dj_safari": has("safari"),
  11965. "dj_chrome": has("chrome"),
  11966. "dj_gecko": has("mozilla"),
  11967. "dj_ff3": maj(ff) == 3
  11968. }; // no dojo unsupported browsers
  11969. classes["dj_" + boxModel] = true;
  11970. // apply browser, browser version, and box model class names
  11971. var classStr = "";
  11972. for(var clz in classes){
  11973. if(classes[clz]){
  11974. classStr += clz + " ";
  11975. }
  11976. }
  11977. html.className = lang.trim(html.className + " " + classStr);
  11978. // If RTL mode, then add dj_rtl flag plus repeat existing classes with -rtl extension.
  11979. // We can't run the code below until the <body> tag has loaded (so we can check for dir=rtl).
  11980. // priority is 90 to run ahead of parser priority of 100
  11981. ready(90, function(){
  11982. if(!geometry.isBodyLtr()){
  11983. var rtlClassStr = "dj_rtl dijitRtl " + classStr.replace(/ /g, "-rtl ");
  11984. html.className = lang.trim(html.className + " " + rtlClassStr + "dj_rtl dijitRtl " + classStr.replace(/ /g, "-rtl "));
  11985. }
  11986. });
  11987. return has;
  11988. });
  11989. },
  11990. 'dijit/Tooltip':function(){
  11991. require({cache:{
  11992. 'url:dijit/templates/Tooltip.html':"<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\"\r\n\t><div class=\"dijitTooltipContainer dijitTooltipContents\" data-dojo-attach-point=\"containerNode\" role='alert'></div\r\n\t><div class=\"dijitTooltipConnector\" data-dojo-attach-point=\"connectorNode\"></div\r\n></div>\r\n"}});
  11993. define("dijit/Tooltip", [
  11994. "dojo/_base/array", // array.forEach array.indexOf array.map
  11995. "dojo/_base/declare", // declare
  11996. "dojo/_base/fx", // fx.fadeIn fx.fadeOut
  11997. "dojo/dom", // dom.byId
  11998. "dojo/dom-class", // domClass.add
  11999. "dojo/dom-geometry", // domGeometry.getMarginBox domGeometry.position
  12000. "dojo/dom-style", // domStyle.set, domStyle.get
  12001. "dojo/_base/lang", // lang.hitch lang.isArrayLike
  12002. "dojo/_base/sniff", // has("ie")
  12003. "dojo/_base/window", // win.body
  12004. "./_base/manager", // manager.defaultDuration
  12005. "./place",
  12006. "./_Widget",
  12007. "./_TemplatedMixin",
  12008. "./BackgroundIframe",
  12009. "dojo/text!./templates/Tooltip.html",
  12010. "." // sets dijit.showTooltip etc. for back-compat
  12011. ], function(array, declare, fx, dom, domClass, domGeometry, domStyle, lang, has, win,
  12012. manager, place, _Widget, _TemplatedMixin, BackgroundIframe, template, dijit){
  12013. /*=====
  12014. var _Widget = dijit._Widget;
  12015. var BackgroundIframe = dijit.BackgroundIframe;
  12016. var _TemplatedMixin = dijit._TemplatedMixin;
  12017. =====*/
  12018. // module:
  12019. // dijit/Tooltip
  12020. // summary:
  12021. // Defines dijit.Tooltip widget (to display a tooltip), showTooltip()/hideTooltip(), and _MasterTooltip
  12022. var MasterTooltip = declare("dijit._MasterTooltip", [_Widget, _TemplatedMixin], {
  12023. // summary:
  12024. // Internal widget that holds the actual tooltip markup,
  12025. // which occurs once per page.
  12026. // Called by Tooltip widgets which are just containers to hold
  12027. // the markup
  12028. // tags:
  12029. // protected
  12030. // duration: Integer
  12031. // Milliseconds to fade in/fade out
  12032. duration: manager.defaultDuration,
  12033. templateString: template,
  12034. postCreate: function(){
  12035. win.body().appendChild(this.domNode);
  12036. this.bgIframe = new BackgroundIframe(this.domNode);
  12037. // Setup fade-in and fade-out functions.
  12038. this.fadeIn = fx.fadeIn({ node: this.domNode, duration: this.duration, onEnd: lang.hitch(this, "_onShow") });
  12039. this.fadeOut = fx.fadeOut({ node: this.domNode, duration: this.duration, onEnd: lang.hitch(this, "_onHide") });
  12040. },
  12041. show: function(innerHTML, aroundNode, position, rtl, textDir){
  12042. // summary:
  12043. // Display tooltip w/specified contents to right of specified node
  12044. // (To left if there's no space on the right, or if rtl == true)
  12045. // innerHTML: String
  12046. // Contents of the tooltip
  12047. // aroundNode: DomNode || dijit.__Rectangle
  12048. // Specifies that tooltip should be next to this node / area
  12049. // position: String[]?
  12050. // List of positions to try to position tooltip (ex: ["right", "above"])
  12051. // rtl: Boolean?
  12052. // Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true
  12053. // means "rtl"; specifies GUI direction, not text direction.
  12054. // textDir: String?
  12055. // Corresponds to `WidgetBase.textdir` attribute; specifies direction of text.
  12056. if(this.aroundNode && this.aroundNode === aroundNode && this.containerNode.innerHTML == innerHTML){
  12057. return;
  12058. }
  12059. // reset width; it may have been set by orient() on a previous tooltip show()
  12060. this.domNode.width = "auto";
  12061. if(this.fadeOut.status() == "playing"){
  12062. // previous tooltip is being hidden; wait until the hide completes then show new one
  12063. this._onDeck=arguments;
  12064. return;
  12065. }
  12066. this.containerNode.innerHTML=innerHTML;
  12067. this.set("textDir", textDir);
  12068. this.containerNode.align = rtl? "right" : "left"; //fix the text alignment
  12069. var pos = place.around(this.domNode, aroundNode,
  12070. position && position.length ? position : Tooltip.defaultPosition, !rtl, lang.hitch(this, "orient"));
  12071. // Position the tooltip connector for middle alignment.
  12072. // This could not have been done in orient() since the tooltip wasn't positioned at that time.
  12073. var aroundNodeCoords = pos.aroundNodePos;
  12074. if(pos.corner.charAt(0) == 'M' && pos.aroundCorner.charAt(0) == 'M'){
  12075. this.connectorNode.style.top = aroundNodeCoords.y + ((aroundNodeCoords.h - this.connectorNode.offsetHeight) >> 1) - pos.y + "px";
  12076. this.connectorNode.style.left = "";
  12077. }else if(pos.corner.charAt(1) == 'M' && pos.aroundCorner.charAt(1) == 'M'){
  12078. this.connectorNode.style.left = aroundNodeCoords.x + ((aroundNodeCoords.w - this.connectorNode.offsetWidth) >> 1) - pos.x + "px";
  12079. }
  12080. // show it
  12081. domStyle.set(this.domNode, "opacity", 0);
  12082. this.fadeIn.play();
  12083. this.isShowingNow = true;
  12084. this.aroundNode = aroundNode;
  12085. },
  12086. orient: function(/*DomNode*/ node, /*String*/ aroundCorner, /*String*/ tooltipCorner, /*Object*/ spaceAvailable, /*Object*/ aroundNodeCoords){
  12087. // summary:
  12088. // Private function to set CSS for tooltip node based on which position it's in.
  12089. // This is called by the dijit popup code. It will also reduce the tooltip's
  12090. // width to whatever width is available
  12091. // tags:
  12092. // protected
  12093. this.connectorNode.style.top = ""; //reset to default
  12094. //Adjust the spaceAvailable width, without changing the spaceAvailable object
  12095. var tooltipSpaceAvaliableWidth = spaceAvailable.w - this.connectorNode.offsetWidth;
  12096. node.className = "dijitTooltip " +
  12097. {
  12098. "MR-ML": "dijitTooltipRight",
  12099. "ML-MR": "dijitTooltipLeft",
  12100. "TM-BM": "dijitTooltipAbove",
  12101. "BM-TM": "dijitTooltipBelow",
  12102. "BL-TL": "dijitTooltipBelow dijitTooltipABLeft",
  12103. "TL-BL": "dijitTooltipAbove dijitTooltipABLeft",
  12104. "BR-TR": "dijitTooltipBelow dijitTooltipABRight",
  12105. "TR-BR": "dijitTooltipAbove dijitTooltipABRight",
  12106. "BR-BL": "dijitTooltipRight",
  12107. "BL-BR": "dijitTooltipLeft"
  12108. }[aroundCorner + "-" + tooltipCorner];
  12109. // reduce tooltip's width to the amount of width available, so that it doesn't overflow screen
  12110. this.domNode.style.width = "auto";
  12111. var size = domGeometry.getContentBox(this.domNode);
  12112. var width = Math.min((Math.max(tooltipSpaceAvaliableWidth,1)), size.w);
  12113. var widthWasReduced = width < size.w;
  12114. this.domNode.style.width = width+"px";
  12115. //Adjust width for tooltips that have a really long word or a nowrap setting
  12116. if(widthWasReduced){
  12117. this.containerNode.style.overflow = "auto"; //temp change to overflow to detect if our tooltip needs to be wider to support the content
  12118. var scrollWidth = this.containerNode.scrollWidth;
  12119. this.containerNode.style.overflow = "visible"; //change it back
  12120. if(scrollWidth > width){
  12121. scrollWidth = scrollWidth + domStyle.get(this.domNode,"paddingLeft") + domStyle.get(this.domNode,"paddingRight");
  12122. this.domNode.style.width = scrollWidth + "px";
  12123. }
  12124. }
  12125. // Reposition the tooltip connector.
  12126. if(tooltipCorner.charAt(0) == 'B' && aroundCorner.charAt(0) == 'B'){
  12127. var mb = domGeometry.getMarginBox(node);
  12128. var tooltipConnectorHeight = this.connectorNode.offsetHeight;
  12129. if(mb.h > spaceAvailable.h){
  12130. // The tooltip starts at the top of the page and will extend past the aroundNode
  12131. var aroundNodePlacement = spaceAvailable.h - ((aroundNodeCoords.h + tooltipConnectorHeight) >> 1);
  12132. this.connectorNode.style.top = aroundNodePlacement + "px";
  12133. this.connectorNode.style.bottom = "";
  12134. }else{
  12135. // Align center of connector with center of aroundNode, except don't let bottom
  12136. // of connector extend below bottom of tooltip content, or top of connector
  12137. // extend past top of tooltip content
  12138. this.connectorNode.style.bottom = Math.min(
  12139. Math.max(aroundNodeCoords.h/2 - tooltipConnectorHeight/2, 0),
  12140. mb.h - tooltipConnectorHeight) + "px";
  12141. this.connectorNode.style.top = "";
  12142. }
  12143. }else{
  12144. // reset the tooltip back to the defaults
  12145. this.connectorNode.style.top = "";
  12146. this.connectorNode.style.bottom = "";
  12147. }
  12148. return Math.max(0, size.w - tooltipSpaceAvaliableWidth);
  12149. },
  12150. _onShow: function(){
  12151. // summary:
  12152. // Called at end of fade-in operation
  12153. // tags:
  12154. // protected
  12155. if(has("ie")){
  12156. // the arrow won't show up on a node w/an opacity filter
  12157. this.domNode.style.filter="";
  12158. }
  12159. },
  12160. hide: function(aroundNode){
  12161. // summary:
  12162. // Hide the tooltip
  12163. if(this._onDeck && this._onDeck[1] == aroundNode){
  12164. // this hide request is for a show() that hasn't even started yet;
  12165. // just cancel the pending show()
  12166. this._onDeck=null;
  12167. }else if(this.aroundNode === aroundNode){
  12168. // this hide request is for the currently displayed tooltip
  12169. this.fadeIn.stop();
  12170. this.isShowingNow = false;
  12171. this.aroundNode = null;
  12172. this.fadeOut.play();
  12173. }else{
  12174. // just ignore the call, it's for a tooltip that has already been erased
  12175. }
  12176. },
  12177. _onHide: function(){
  12178. // summary:
  12179. // Called at end of fade-out operation
  12180. // tags:
  12181. // protected
  12182. this.domNode.style.cssText=""; // to position offscreen again
  12183. this.containerNode.innerHTML="";
  12184. if(this._onDeck){
  12185. // a show request has been queued up; do it now
  12186. this.show.apply(this, this._onDeck);
  12187. this._onDeck=null;
  12188. }
  12189. },
  12190. _setAutoTextDir: function(/*Object*/node){
  12191. // summary:
  12192. // Resolve "auto" text direction for children nodes
  12193. // tags:
  12194. // private
  12195. this.applyTextDir(node, has("ie") ? node.outerText : node.textContent);
  12196. array.forEach(node.children, function(child){this._setAutoTextDir(child); }, this);
  12197. },
  12198. _setTextDirAttr: function(/*String*/ textDir){
  12199. // summary:
  12200. // Setter for textDir.
  12201. // description:
  12202. // Users shouldn't call this function; they should be calling
  12203. // set('textDir', value)
  12204. // tags:
  12205. // private
  12206. this._set("textDir", typeof textDir != 'undefined'? textDir : "");
  12207. if (textDir == "auto"){
  12208. this._setAutoTextDir(this.containerNode);
  12209. }else{
  12210. this.containerNode.dir = this.textDir;
  12211. }
  12212. }
  12213. });
  12214. dijit.showTooltip = function(innerHTML, aroundNode, position, rtl, textDir){
  12215. // summary:
  12216. // Static method to display tooltip w/specified contents in specified position.
  12217. // See description of dijit.Tooltip.defaultPosition for details on position parameter.
  12218. // If position is not specified then dijit.Tooltip.defaultPosition is used.
  12219. // innerHTML: String
  12220. // Contents of the tooltip
  12221. // aroundNode: dijit.__Rectangle
  12222. // Specifies that tooltip should be next to this node / area
  12223. // position: String[]?
  12224. // List of positions to try to position tooltip (ex: ["right", "above"])
  12225. // rtl: Boolean?
  12226. // Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true
  12227. // means "rtl"; specifies GUI direction, not text direction.
  12228. // textDir: String?
  12229. // Corresponds to `WidgetBase.textdir` attribute; specifies direction of text.
  12230. // after/before don't work, but they used to, so for back-compat convert them to after-centered, before-centered
  12231. if(position){
  12232. position = array.map(position, function(val){
  12233. return {after: "after-centered", before: "before-centered"}[val] || val;
  12234. });
  12235. }
  12236. if(!Tooltip._masterTT){ dijit._masterTT = Tooltip._masterTT = new MasterTooltip(); }
  12237. return Tooltip._masterTT.show(innerHTML, aroundNode, position, rtl, textDir);
  12238. };
  12239. dijit.hideTooltip = function(aroundNode){
  12240. // summary:
  12241. // Static method to hide the tooltip displayed via showTooltip()
  12242. return Tooltip._masterTT && Tooltip._masterTT.hide(aroundNode);
  12243. };
  12244. var Tooltip = declare("dijit.Tooltip", _Widget, {
  12245. // summary:
  12246. // Pops up a tooltip (a help message) when you hover over a node.
  12247. // label: String
  12248. // Text to display in the tooltip.
  12249. // Specified as innerHTML when creating the widget from markup.
  12250. label: "",
  12251. // showDelay: Integer
  12252. // Number of milliseconds to wait after hovering over/focusing on the object, before
  12253. // the tooltip is displayed.
  12254. showDelay: 400,
  12255. // connectId: String|String[]
  12256. // Id of domNode(s) to attach the tooltip to.
  12257. // When user hovers over specified dom node, the tooltip will appear.
  12258. connectId: [],
  12259. // position: String[]
  12260. // See description of `dijit.Tooltip.defaultPosition` for details on position parameter.
  12261. position: [],
  12262. _setConnectIdAttr: function(/*String|String[]*/ newId){
  12263. // summary:
  12264. // Connect to specified node(s)
  12265. // Remove connections to old nodes (if there are any)
  12266. array.forEach(this._connections || [], function(nested){
  12267. array.forEach(nested, lang.hitch(this, "disconnect"));
  12268. }, this);
  12269. // Make array of id's to connect to, excluding entries for nodes that don't exist yet, see startup()
  12270. this._connectIds = array.filter(lang.isArrayLike(newId) ? newId : (newId ? [newId] : []),
  12271. function(id){ return dom.byId(id); });
  12272. // Make connections
  12273. this._connections = array.map(this._connectIds, function(id){
  12274. var node = dom.byId(id);
  12275. return [
  12276. this.connect(node, "onmouseenter", "_onHover"),
  12277. this.connect(node, "onmouseleave", "_onUnHover"),
  12278. this.connect(node, "onfocus", "_onHover"),
  12279. this.connect(node, "onblur", "_onUnHover")
  12280. ];
  12281. }, this);
  12282. this._set("connectId", newId);
  12283. },
  12284. addTarget: function(/*DOMNODE || String*/ node){
  12285. // summary:
  12286. // Attach tooltip to specified node if it's not already connected
  12287. // TODO: remove in 2.0 and just use set("connectId", ...) interface
  12288. var id = node.id || node;
  12289. if(array.indexOf(this._connectIds, id) == -1){
  12290. this.set("connectId", this._connectIds.concat(id));
  12291. }
  12292. },
  12293. removeTarget: function(/*DomNode || String*/ node){
  12294. // summary:
  12295. // Detach tooltip from specified node
  12296. // TODO: remove in 2.0 and just use set("connectId", ...) interface
  12297. var id = node.id || node, // map from DOMNode back to plain id string
  12298. idx = array.indexOf(this._connectIds, id);
  12299. if(idx >= 0){
  12300. // remove id (modifies original this._connectIds but that's OK in this case)
  12301. this._connectIds.splice(idx, 1);
  12302. this.set("connectId", this._connectIds);
  12303. }
  12304. },
  12305. buildRendering: function(){
  12306. this.inherited(arguments);
  12307. domClass.add(this.domNode,"dijitTooltipData");
  12308. },
  12309. startup: function(){
  12310. this.inherited(arguments);
  12311. // If this tooltip was created in a template, or for some other reason the specified connectId[s]
  12312. // didn't exist during the widget's initialization, then connect now.
  12313. var ids = this.connectId;
  12314. array.forEach(lang.isArrayLike(ids) ? ids : [ids], this.addTarget, this);
  12315. },
  12316. _onHover: function(/*Event*/ e){
  12317. // summary:
  12318. // Despite the name of this method, it actually handles both hover and focus
  12319. // events on the target node, setting a timer to show the tooltip.
  12320. // tags:
  12321. // private
  12322. if(!this._showTimer){
  12323. var target = e.target;
  12324. this._showTimer = setTimeout(lang.hitch(this, function(){this.open(target)}), this.showDelay);
  12325. }
  12326. },
  12327. _onUnHover: function(/*Event*/ /*===== e =====*/){
  12328. // summary:
  12329. // Despite the name of this method, it actually handles both mouseleave and blur
  12330. // events on the target node, hiding the tooltip.
  12331. // tags:
  12332. // private
  12333. // keep a tooltip open if the associated element still has focus (even though the
  12334. // mouse moved away)
  12335. if(this._focus){ return; }
  12336. if(this._showTimer){
  12337. clearTimeout(this._showTimer);
  12338. delete this._showTimer;
  12339. }
  12340. this.close();
  12341. },
  12342. open: function(/*DomNode*/ target){
  12343. // summary:
  12344. // Display the tooltip; usually not called directly.
  12345. // tags:
  12346. // private
  12347. if(this._showTimer){
  12348. clearTimeout(this._showTimer);
  12349. delete this._showTimer;
  12350. }
  12351. Tooltip.show(this.label || this.domNode.innerHTML, target, this.position, !this.isLeftToRight(), this.textDir);
  12352. this._connectNode = target;
  12353. this.onShow(target, this.position);
  12354. },
  12355. close: function(){
  12356. // summary:
  12357. // Hide the tooltip or cancel timer for show of tooltip
  12358. // tags:
  12359. // private
  12360. if(this._connectNode){
  12361. // if tooltip is currently shown
  12362. Tooltip.hide(this._connectNode);
  12363. delete this._connectNode;
  12364. this.onHide();
  12365. }
  12366. if(this._showTimer){
  12367. // if tooltip is scheduled to be shown (after a brief delay)
  12368. clearTimeout(this._showTimer);
  12369. delete this._showTimer;
  12370. }
  12371. },
  12372. onShow: function(/*===== target, position =====*/){
  12373. // summary:
  12374. // Called when the tooltip is shown
  12375. // tags:
  12376. // callback
  12377. },
  12378. onHide: function(){
  12379. // summary:
  12380. // Called when the tooltip is hidden
  12381. // tags:
  12382. // callback
  12383. },
  12384. uninitialize: function(){
  12385. this.close();
  12386. this.inherited(arguments);
  12387. }
  12388. });
  12389. Tooltip._MasterTooltip = MasterTooltip; // for monkey patching
  12390. Tooltip.show = dijit.showTooltip; // export function through module return value
  12391. Tooltip.hide = dijit.hideTooltip; // export function through module return value
  12392. // dijit.Tooltip.defaultPosition: String[]
  12393. // This variable controls the position of tooltips, if the position is not specified to
  12394. // the Tooltip widget or *TextBox widget itself. It's an array of strings with the values
  12395. // possible for `dijit/place::around()`. The recommended values are:
  12396. //
  12397. // * before-centered: centers tooltip to the left of the anchor node/widget, or to the right
  12398. // in the case of RTL scripts like Hebrew and Arabic
  12399. // * after-centered: centers tooltip to the right of the anchor node/widget, or to the left
  12400. // in the case of RTL scripts like Hebrew and Arabic
  12401. // * above-centered: tooltip is centered above anchor node
  12402. // * below-centered: tooltip is centered above anchor node
  12403. //
  12404. // The list is positions is tried, in order, until a position is found where the tooltip fits
  12405. // within the viewport.
  12406. //
  12407. // Be careful setting this parameter. A value of "above-centered" may work fine until the user scrolls
  12408. // the screen so that there's no room above the target node. Nodes with drop downs, like
  12409. // DropDownButton or FilteringSelect, are especially problematic, in that you need to be sure
  12410. // that the drop down and tooltip don't overlap, even when the viewport is scrolled so that there
  12411. // is only room below (or above) the target node, but not both.
  12412. Tooltip.defaultPosition = ["after-centered", "before-centered"];
  12413. return Tooltip;
  12414. });
  12415. },
  12416. 'dojo/string':function(){
  12417. define("dojo/string", ["./_base/kernel", "./_base/lang"], function(dojo, lang) {
  12418. // module:
  12419. // dojo/string
  12420. // summary:
  12421. // TODOC
  12422. lang.getObject("string", true, dojo);
  12423. /*=====
  12424. dojo.string = {
  12425. // summary: String utilities for Dojo
  12426. };
  12427. =====*/
  12428. dojo.string.rep = function(/*String*/str, /*Integer*/num){
  12429. // summary:
  12430. // Efficiently replicate a string `n` times.
  12431. // str:
  12432. // the string to replicate
  12433. // num:
  12434. // number of times to replicate the string
  12435. if(num <= 0 || !str){ return ""; }
  12436. var buf = [];
  12437. for(;;){
  12438. if(num & 1){
  12439. buf.push(str);
  12440. }
  12441. if(!(num >>= 1)){ break; }
  12442. str += str;
  12443. }
  12444. return buf.join(""); // String
  12445. };
  12446. dojo.string.pad = function(/*String*/text, /*Integer*/size, /*String?*/ch, /*Boolean?*/end){
  12447. // summary:
  12448. // Pad a string to guarantee that it is at least `size` length by
  12449. // filling with the character `ch` at either the start or end of the
  12450. // string. Pads at the start, by default.
  12451. // text:
  12452. // the string to pad
  12453. // size:
  12454. // length to provide padding
  12455. // ch:
  12456. // character to pad, defaults to '0'
  12457. // end:
  12458. // adds padding at the end if true, otherwise pads at start
  12459. // example:
  12460. // | // Fill the string to length 10 with "+" characters on the right. Yields "Dojo++++++".
  12461. // | dojo.string.pad("Dojo", 10, "+", true);
  12462. if(!ch){
  12463. ch = '0';
  12464. }
  12465. var out = String(text),
  12466. pad = dojo.string.rep(ch, Math.ceil((size - out.length) / ch.length));
  12467. return end ? out + pad : pad + out; // String
  12468. };
  12469. dojo.string.substitute = function( /*String*/ template,
  12470. /*Object|Array*/map,
  12471. /*Function?*/ transform,
  12472. /*Object?*/ thisObject){
  12473. // summary:
  12474. // Performs parameterized substitutions on a string. Throws an
  12475. // exception if any parameter is unmatched.
  12476. // template:
  12477. // a string with expressions in the form `${key}` to be replaced or
  12478. // `${key:format}` which specifies a format function. keys are case-sensitive.
  12479. // map:
  12480. // hash to search for substitutions
  12481. // transform:
  12482. // a function to process all parameters before substitution takes
  12483. // place, e.g. mylib.encodeXML
  12484. // thisObject:
  12485. // where to look for optional format function; default to the global
  12486. // namespace
  12487. // example:
  12488. // Substitutes two expressions in a string from an Array or Object
  12489. // | // returns "File 'foo.html' is not found in directory '/temp'."
  12490. // | // by providing substitution data in an Array
  12491. // | dojo.string.substitute(
  12492. // | "File '${0}' is not found in directory '${1}'.",
  12493. // | ["foo.html","/temp"]
  12494. // | );
  12495. // |
  12496. // | // also returns "File 'foo.html' is not found in directory '/temp'."
  12497. // | // but provides substitution data in an Object structure. Dotted
  12498. // | // notation may be used to traverse the structure.
  12499. // | dojo.string.substitute(
  12500. // | "File '${name}' is not found in directory '${info.dir}'.",
  12501. // | { name: "foo.html", info: { dir: "/temp" } }
  12502. // | );
  12503. // example:
  12504. // Use a transform function to modify the values:
  12505. // | // returns "file 'foo.html' is not found in directory '/temp'."
  12506. // | dojo.string.substitute(
  12507. // | "${0} is not found in ${1}.",
  12508. // | ["foo.html","/temp"],
  12509. // | function(str){
  12510. // | // try to figure out the type
  12511. // | var prefix = (str.charAt(0) == "/") ? "directory": "file";
  12512. // | return prefix + " '" + str + "'";
  12513. // | }
  12514. // | );
  12515. // example:
  12516. // Use a formatter
  12517. // | // returns "thinger -- howdy"
  12518. // | dojo.string.substitute(
  12519. // | "${0:postfix}", ["thinger"], null, {
  12520. // | postfix: function(value, key){
  12521. // | return value + " -- howdy";
  12522. // | }
  12523. // | }
  12524. // | );
  12525. thisObject = thisObject || dojo.global;
  12526. transform = transform ?
  12527. lang.hitch(thisObject, transform) : function(v){ return v; };
  12528. return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,
  12529. function(match, key, format){
  12530. var value = lang.getObject(key, false, map);
  12531. if(format){
  12532. value = lang.getObject(format, false, thisObject).call(thisObject, value, key);
  12533. }
  12534. return transform(value, key).toString();
  12535. }); // String
  12536. };
  12537. /*=====
  12538. dojo.string.trim = function(str){
  12539. // summary:
  12540. // Trims whitespace from both sides of the string
  12541. // str: String
  12542. // String to be trimmed
  12543. // returns: String
  12544. // Returns the trimmed string
  12545. // description:
  12546. // This version of trim() was taken from [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript).
  12547. // The short yet performant version of this function is dojo.trim(),
  12548. // which is part of Dojo base. Uses String.prototype.trim instead, if available.
  12549. return ""; // String
  12550. }
  12551. =====*/
  12552. dojo.string.trim = String.prototype.trim ?
  12553. lang.trim : // aliasing to the native function
  12554. function(str){
  12555. str = str.replace(/^\s+/, '');
  12556. for(var i = str.length - 1; i >= 0; i--){
  12557. if(/\S/.test(str.charAt(i))){
  12558. str = str.substring(0, i + 1);
  12559. break;
  12560. }
  12561. }
  12562. return str;
  12563. };
  12564. return dojo.string;
  12565. });
  12566. },
  12567. 'dijit/form/_FormValueMixin':function(){
  12568. define("dijit/form/_FormValueMixin", [
  12569. "dojo/_base/declare", // declare
  12570. "dojo/dom-attr", // domAttr.set
  12571. "dojo/keys", // keys.ESCAPE
  12572. "dojo/_base/sniff", // has("ie"), has("quirks")
  12573. "./_FormWidgetMixin"
  12574. ], function(declare, domAttr, keys, has, _FormWidgetMixin){
  12575. /*=====
  12576. var _FormWidgetMixin = dijit.form._FormWidgetMixin;
  12577. =====*/
  12578. // module:
  12579. // dijit/form/_FormValueMixin
  12580. // summary:
  12581. // Mixin for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values.
  12582. return declare("dijit.form._FormValueMixin", _FormWidgetMixin, {
  12583. // summary:
  12584. // Mixin for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values.
  12585. // description:
  12586. // Each _FormValueMixin represents a single input value, and has a (possibly hidden) <input> element,
  12587. // to which it serializes it's input value, so that form submission (either normal submission or via FormBind?)
  12588. // works as expected.
  12589. // readOnly: Boolean
  12590. // Should this widget respond to user input?
  12591. // In markup, this is specified as "readOnly".
  12592. // Similar to disabled except readOnly form values are submitted.
  12593. readOnly: false,
  12594. _setReadOnlyAttr: function(/*Boolean*/ value){
  12595. domAttr.set(this.focusNode, 'readOnly', value);
  12596. this.focusNode.setAttribute("aria-readonly", value);
  12597. this._set("readOnly", value);
  12598. },
  12599. postCreate: function(){
  12600. this.inherited(arguments);
  12601. if(has("ie")){ // IE won't stop the event with keypress
  12602. this.connect(this.focusNode || this.domNode, "onkeydown", this._onKeyDown);
  12603. }
  12604. // Update our reset value if it hasn't yet been set (because this.set()
  12605. // is only called when there *is* a value)
  12606. if(this._resetValue === undefined){
  12607. this._lastValueReported = this._resetValue = this.value;
  12608. }
  12609. },
  12610. _setValueAttr: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
  12611. // summary:
  12612. // Hook so set('value', value) works.
  12613. // description:
  12614. // Sets the value of the widget.
  12615. // If the value has changed, then fire onChange event, unless priorityChange
  12616. // is specified as null (or false?)
  12617. this._handleOnChange(newValue, priorityChange);
  12618. },
  12619. _handleOnChange: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
  12620. // summary:
  12621. // Called when the value of the widget has changed. Saves the new value in this.value,
  12622. // and calls onChange() if appropriate. See _FormWidget._handleOnChange() for details.
  12623. this._set("value", newValue);
  12624. this.inherited(arguments);
  12625. },
  12626. undo: function(){
  12627. // summary:
  12628. // Restore the value to the last value passed to onChange
  12629. this._setValueAttr(this._lastValueReported, false);
  12630. },
  12631. reset: function(){
  12632. // summary:
  12633. // Reset the widget's value to what it was at initialization time
  12634. this._hasBeenBlurred = false;
  12635. this._setValueAttr(this._resetValue, true);
  12636. },
  12637. _onKeyDown: function(e){
  12638. if(e.keyCode == keys.ESCAPE && !(e.ctrlKey || e.altKey || e.metaKey)){
  12639. var te;
  12640. if(has("ie") < 9 || (has("ie") && has("quirks"))){
  12641. e.preventDefault(); // default behavior needs to be stopped here since keypress is too late
  12642. te = document.createEventObject();
  12643. te.keyCode = keys.ESCAPE;
  12644. te.shiftKey = e.shiftKey;
  12645. e.srcElement.fireEvent('onkeypress', te);
  12646. }
  12647. }
  12648. }
  12649. });
  12650. });
  12651. },
  12652. 'dijit/form/DropDownButton':function(){
  12653. require({cache:{
  12654. 'url:dijit/form/templates/DropDownButton.html':"<span class=\"dijit dijitReset dijitInline\"\r\n\t><span class='dijitReset dijitInline dijitButtonNode'\r\n\t\tdata-dojo-attach-event=\"ondijitclick:_onClick\" data-dojo-attach-point=\"_buttonNode\"\r\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\r\n\t\t\tdata-dojo-attach-point=\"focusNode,titleNode,_arrowWrapperNode\"\r\n\t\t\trole=\"button\" aria-haspopup=\"true\" aria-labelledby=\"${id}_label\"\r\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\"\r\n\t\t\t\tdata-dojo-attach-point=\"iconNode\"\r\n\t\t\t></span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\r\n\t\t\t\tdata-dojo-attach-point=\"containerNode,_popupStateNode\"\r\n\t\t\t\tid=\"${id}_label\"\r\n\t\t\t></span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonInner\"></span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonChar\">&#9660;</span\r\n\t\t></span\r\n\t></span\r\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\" tabIndex=\"-1\"\r\n\t\tdata-dojo-attach-point=\"valueNode\"\r\n/></span>\r\n"}});
  12655. define("dijit/form/DropDownButton", [
  12656. "dojo/_base/declare", // declare
  12657. "dojo/_base/lang", // hitch
  12658. "dojo/query", // query
  12659. "../registry", // registry.byNode
  12660. "../popup", // dijit.popup2.hide
  12661. "./Button",
  12662. "../_Container",
  12663. "../_HasDropDown",
  12664. "dojo/text!./templates/DropDownButton.html"
  12665. ], function(declare, lang, query, registry, popup, Button, _Container, _HasDropDown, template){
  12666. /*=====
  12667. Button = dijit.form.Button;
  12668. _Container = dijit._Container;
  12669. _HasDropDown = dijit._HasDropDown;
  12670. =====*/
  12671. // module:
  12672. // dijit/form/DropDownButton
  12673. // summary:
  12674. // A button with a drop down
  12675. return declare("dijit.form.DropDownButton", [Button, _Container, _HasDropDown], {
  12676. // summary:
  12677. // A button with a drop down
  12678. //
  12679. // example:
  12680. // | <button data-dojo-type="dijit.form.DropDownButton">
  12681. // | Hello world
  12682. // | <div data-dojo-type="dijit.Menu">...</div>
  12683. // | </button>
  12684. //
  12685. // example:
  12686. // | var button1 = new dijit.form.DropDownButton({ label: "hi", dropDown: new dijit.Menu(...) });
  12687. // | win.body().appendChild(button1);
  12688. //
  12689. baseClass : "dijitDropDownButton",
  12690. templateString: template,
  12691. _fillContent: function(){
  12692. // Overrides Button._fillContent().
  12693. //
  12694. // My inner HTML contains both the button contents and a drop down widget, like
  12695. // <DropDownButton> <span>push me</span> <Menu> ... </Menu> </DropDownButton>
  12696. // The first node is assumed to be the button content. The widget is the popup.
  12697. if(this.srcNodeRef){ // programatically created buttons might not define srcNodeRef
  12698. //FIXME: figure out how to filter out the widget and use all remaining nodes as button
  12699. // content, not just nodes[0]
  12700. var nodes = query("*", this.srcNodeRef);
  12701. this.inherited(arguments, [nodes[0]]);
  12702. // save pointer to srcNode so we can grab the drop down widget after it's instantiated
  12703. this.dropDownContainer = this.srcNodeRef;
  12704. }
  12705. },
  12706. startup: function(){
  12707. if(this._started){ return; }
  12708. // the child widget from srcNodeRef is the dropdown widget. Insert it in the page DOM,
  12709. // make it invisible, and store a reference to pass to the popup code.
  12710. if(!this.dropDown && this.dropDownContainer){
  12711. var dropDownNode = query("[widgetId]", this.dropDownContainer)[0];
  12712. this.dropDown = registry.byNode(dropDownNode);
  12713. delete this.dropDownContainer;
  12714. }
  12715. if(this.dropDown){
  12716. popup.hide(this.dropDown);
  12717. }
  12718. this.inherited(arguments);
  12719. },
  12720. isLoaded: function(){
  12721. // Returns whether or not we are loaded - if our dropdown has an href,
  12722. // then we want to check that.
  12723. var dropDown = this.dropDown;
  12724. return (!!dropDown && (!dropDown.href || dropDown.isLoaded));
  12725. },
  12726. loadDropDown: function(/*Function*/ callback){
  12727. // Default implementation assumes that drop down already exists,
  12728. // but hasn't loaded it's data (ex: ContentPane w/href).
  12729. // App must override if the drop down is lazy-created.
  12730. var dropDown = this.dropDown;
  12731. var handler = dropDown.on("load", lang.hitch(this, function(){
  12732. handler.remove();
  12733. callback();
  12734. }));
  12735. dropDown.refresh(); // tell it to load
  12736. },
  12737. isFocusable: function(){
  12738. // Overridden so that focus is handled by the _HasDropDown mixin, not by
  12739. // the _FormWidget mixin.
  12740. return this.inherited(arguments) && !this._mouseDown;
  12741. }
  12742. });
  12743. });
  12744. },
  12745. 'dijit/form/_FormWidgetMixin':function(){
  12746. define("dijit/form/_FormWidgetMixin", [
  12747. "dojo/_base/array", // array.forEach
  12748. "dojo/_base/declare", // declare
  12749. "dojo/dom-attr", // domAttr.set
  12750. "dojo/dom-style", // domStyle.get
  12751. "dojo/_base/lang", // lang.hitch lang.isArray
  12752. "dojo/mouse", // mouse.isLeft
  12753. "dojo/_base/sniff", // has("webkit")
  12754. "dojo/_base/window", // win.body
  12755. "dojo/window", // winUtils.scrollIntoView
  12756. "../a11y" // a11y.hasDefaultTabStop
  12757. ], function(array, declare, domAttr, domStyle, lang, mouse, has, win, winUtils, a11y){
  12758. // module:
  12759. // dijit/form/_FormWidgetMixin
  12760. // summary:
  12761. // Mixin for widgets corresponding to native HTML elements such as <checkbox> or <button>,
  12762. // which can be children of a <form> node or a `dijit.form.Form` widget.
  12763. return declare("dijit.form._FormWidgetMixin", null, {
  12764. // summary:
  12765. // Mixin for widgets corresponding to native HTML elements such as <checkbox> or <button>,
  12766. // which can be children of a <form> node or a `dijit.form.Form` widget.
  12767. //
  12768. // description:
  12769. // Represents a single HTML element.
  12770. // All these widgets should have these attributes just like native HTML input elements.
  12771. // You can set them during widget construction or afterwards, via `dijit._Widget.attr`.
  12772. //
  12773. // They also share some common methods.
  12774. // name: [const] String
  12775. // Name used when submitting form; same as "name" attribute or plain HTML elements
  12776. name: "",
  12777. // alt: String
  12778. // Corresponds to the native HTML <input> element's attribute.
  12779. alt: "",
  12780. // value: String
  12781. // Corresponds to the native HTML <input> element's attribute.
  12782. value: "",
  12783. // type: [const] String
  12784. // Corresponds to the native HTML <input> element's attribute.
  12785. type: "text",
  12786. // tabIndex: Integer
  12787. // Order fields are traversed when user hits the tab key
  12788. tabIndex: "0",
  12789. _setTabIndexAttr: "focusNode", // force copy even when tabIndex default value, needed since Button is <span>
  12790. // disabled: Boolean
  12791. // Should this widget respond to user input?
  12792. // In markup, this is specified as "disabled='disabled'", or just "disabled".
  12793. disabled: false,
  12794. // intermediateChanges: Boolean
  12795. // Fires onChange for each value change or only on demand
  12796. intermediateChanges: false,
  12797. // scrollOnFocus: Boolean
  12798. // On focus, should this widget scroll into view?
  12799. scrollOnFocus: true,
  12800. // Override _WidgetBase mapping id to this.domNode, needs to be on focusNode so <label> etc.
  12801. // works with screen reader
  12802. _setIdAttr: "focusNode",
  12803. _setDisabledAttr: function(/*Boolean*/ value){
  12804. this._set("disabled", value);
  12805. domAttr.set(this.focusNode, 'disabled', value);
  12806. if(this.valueNode){
  12807. domAttr.set(this.valueNode, 'disabled', value);
  12808. }
  12809. this.focusNode.setAttribute("aria-disabled", value ? "true" : "false");
  12810. if(value){
  12811. // reset these, because after the domNode is disabled, we can no longer receive
  12812. // mouse related events, see #4200
  12813. this._set("hovering", false);
  12814. this._set("active", false);
  12815. // clear tab stop(s) on this widget's focusable node(s) (ComboBox has two focusable nodes)
  12816. var attachPointNames = "tabIndex" in this.attributeMap ? this.attributeMap.tabIndex :
  12817. ("_setTabIndexAttr" in this) ? this._setTabIndexAttr : "focusNode";
  12818. array.forEach(lang.isArray(attachPointNames) ? attachPointNames : [attachPointNames], function(attachPointName){
  12819. var node = this[attachPointName];
  12820. // complex code because tabIndex=-1 on a <div> doesn't work on FF
  12821. if(has("webkit") || a11y.hasDefaultTabStop(node)){ // see #11064 about webkit bug
  12822. node.setAttribute('tabIndex', "-1");
  12823. }else{
  12824. node.removeAttribute('tabIndex');
  12825. }
  12826. }, this);
  12827. }else{
  12828. if(this.tabIndex != ""){
  12829. this.set('tabIndex', this.tabIndex);
  12830. }
  12831. }
  12832. },
  12833. _onFocus: function(/*String*/ by){
  12834. // If user clicks on the widget, even if the mouse is released outside of it,
  12835. // this widget's focusNode should get focus (to mimic native browser hehavior).
  12836. // Browsers often need help to make sure the focus via mouse actually gets to the focusNode.
  12837. if(by == "mouse" && this.isFocusable()){
  12838. // IE exhibits strange scrolling behavior when refocusing a node so only do it when !focused.
  12839. var focusConnector = this.connect(this.focusNode, "onfocus", function(){
  12840. this.disconnect(mouseUpConnector);
  12841. this.disconnect(focusConnector);
  12842. });
  12843. // Set a global event to handle mouseup, so it fires properly
  12844. // even if the cursor leaves this.domNode before the mouse up event.
  12845. var mouseUpConnector = this.connect(win.body(), "onmouseup", function(){
  12846. this.disconnect(mouseUpConnector);
  12847. this.disconnect(focusConnector);
  12848. // if here, then the mousedown did not focus the focusNode as the default action
  12849. if(this.focused){
  12850. this.focus();
  12851. }
  12852. });
  12853. }
  12854. if(this.scrollOnFocus){
  12855. this.defer(function(){ winUtils.scrollIntoView(this.domNode); }); // without defer, the input caret position can change on mouse click
  12856. }
  12857. this.inherited(arguments);
  12858. },
  12859. isFocusable: function(){
  12860. // summary:
  12861. // Tells if this widget is focusable or not. Used internally by dijit.
  12862. // tags:
  12863. // protected
  12864. return !this.disabled && this.focusNode && (domStyle.get(this.domNode, "display") != "none");
  12865. },
  12866. focus: function(){
  12867. // summary:
  12868. // Put focus on this widget
  12869. if(!this.disabled && this.focusNode.focus){
  12870. try{ this.focusNode.focus(); }catch(e){}/*squelch errors from hidden nodes*/
  12871. }
  12872. },
  12873. compare: function(/*anything*/ val1, /*anything*/ val2){
  12874. // summary:
  12875. // Compare 2 values (as returned by get('value') for this widget).
  12876. // tags:
  12877. // protected
  12878. if(typeof val1 == "number" && typeof val2 == "number"){
  12879. return (isNaN(val1) && isNaN(val2)) ? 0 : val1 - val2;
  12880. }else if(val1 > val2){
  12881. return 1;
  12882. }else if(val1 < val2){
  12883. return -1;
  12884. }else{
  12885. return 0;
  12886. }
  12887. },
  12888. onChange: function(/*===== newValue =====*/){
  12889. // summary:
  12890. // Callback when this widget's value is changed.
  12891. // tags:
  12892. // callback
  12893. },
  12894. // _onChangeActive: [private] Boolean
  12895. // Indicates that changes to the value should call onChange() callback.
  12896. // This is false during widget initialization, to avoid calling onChange()
  12897. // when the initial value is set.
  12898. _onChangeActive: false,
  12899. _handleOnChange: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
  12900. // summary:
  12901. // Called when the value of the widget is set. Calls onChange() if appropriate
  12902. // newValue:
  12903. // the new value
  12904. // priorityChange:
  12905. // For a slider, for example, dragging the slider is priorityChange==false,
  12906. // but on mouse up, it's priorityChange==true. If intermediateChanges==false,
  12907. // onChange is only called form priorityChange=true events.
  12908. // tags:
  12909. // private
  12910. if(this._lastValueReported == undefined && (priorityChange === null || !this._onChangeActive)){
  12911. // this block executes not for a change, but during initialization,
  12912. // and is used to store away the original value (or for ToggleButton, the original checked state)
  12913. this._resetValue = this._lastValueReported = newValue;
  12914. }
  12915. this._pendingOnChange = this._pendingOnChange
  12916. || (typeof newValue != typeof this._lastValueReported)
  12917. || (this.compare(newValue, this._lastValueReported) != 0);
  12918. if((this.intermediateChanges || priorityChange || priorityChange === undefined) && this._pendingOnChange){
  12919. this._lastValueReported = newValue;
  12920. this._pendingOnChange = false;
  12921. if(this._onChangeActive){
  12922. if(this._onChangeHandle){
  12923. this._onChangeHandle.remove();
  12924. }
  12925. // defer allows hidden value processing to run and
  12926. // also the onChange handler can safely adjust focus, etc
  12927. this._onChangeHandle = this.defer(
  12928. function(){
  12929. this._onChangeHandle = null;
  12930. this.onChange(newValue);
  12931. }); // try to collapse multiple onChange's fired faster than can be processed
  12932. }
  12933. }
  12934. },
  12935. create: function(){
  12936. // Overrides _Widget.create()
  12937. this.inherited(arguments);
  12938. this._onChangeActive = true;
  12939. },
  12940. destroy: function(){
  12941. if(this._onChangeHandle){ // destroy called before last onChange has fired
  12942. this._onChangeHandle.remove();
  12943. this.onChange(this._lastValueReported);
  12944. }
  12945. this.inherited(arguments);
  12946. }
  12947. });
  12948. });
  12949. },
  12950. 'url:dijit/templates/ProgressBar.html':"<div class=\"dijitProgressBar dijitProgressBarEmpty\" role=\"progressbar\"\r\n\t><div data-dojo-attach-point=\"internalProgress\" class=\"dijitProgressBarFull\"\r\n\t\t><div class=\"dijitProgressBarTile\" role=\"presentation\"></div\r\n\t\t><span style=\"visibility:hidden\">&#160;</span\r\n\t></div\r\n\t><div data-dojo-attach-point=\"labelNode\" class=\"dijitProgressBarLabel\" id=\"${id}_label\"></div\r\n\t><img data-dojo-attach-point=\"indeterminateHighContrastImage\" class=\"dijitProgressBarIndeterminateHighContrastImage\" alt=\"\"\r\n/></div>\r\n",
  12951. 'dojox/grid/cells':function(){
  12952. define("dojox/grid/cells", ["../main", "./cells/_base"], function(dojox){
  12953. return dojox.grid.cells;
  12954. });
  12955. },
  12956. 'dojox/grid/enhanced/_FocusManager':function(){
  12957. define("dojox/grid/enhanced/_FocusManager", [
  12958. "dojo/_base/kernel",
  12959. "dojo/_base/lang",
  12960. "dojo/_base/declare",
  12961. "dojo/_base/array",
  12962. "dojo/_base/connect",
  12963. "dojo/_base/event",
  12964. "dojo/_base/sniff",
  12965. "dojo/_base/html",
  12966. "dojo/keys",
  12967. "dijit/a11y",
  12968. "dijit/focus",
  12969. "../_FocusManager"
  12970. ], function(dojo, lang, declare, array, connect, event, has, html, keys, dijitA11y, dijitFocus, _FocusManager){
  12971. var _FocusArea = declare("dojox.grid.enhanced._FocusArea", null, {
  12972. // summary:
  12973. // This is a friend class of _FocusManager
  12974. /*=====
  12975. // name: string
  12976. // Name of this area.
  12977. name: "",
  12978. // onFocus: function(event, step)
  12979. // Called when this area logically gets focus.
  12980. // event: Event object
  12981. // May be unavailable, should check before use.
  12982. // step: Integer
  12983. // The distance in the tab sequence from last focused area to this area.
  12984. // returns:
  12985. // whether this area is successfully focused. If not, the next area will get focus.
  12986. onFocus: function(event, step){return true;},
  12987. // onBlur: function(event, step)
  12988. // Called when this area logically loses focus.
  12989. // event: Event object
  12990. // May be unavailable, should check before use.
  12991. // step: Integer
  12992. // The distance in the tab sequence from this area to the area to focus.
  12993. // returns:
  12994. // If Boolean, means whether this area has successfully blurred. If not, the next area to focus is still this one.
  12995. // If String, means the next area to focus is given by this returned name.
  12996. onBlur: function(event, step){return true;},
  12997. // onMove: function(rowStep, colStep, event)
  12998. // Called when focus is moving around within this area.
  12999. // rowStep: Integer
  13000. // colStep: Integer
  13001. // event: Event object
  13002. // May be unavailable, should check before use.
  13003. onMove: function(rowStep, colStep, event){},
  13004. // onKey: function(event, isBubble)
  13005. // Called when some key is pressed when focus is logically in this area.
  13006. // event: Event object
  13007. // isBubble: Boolean
  13008. // Whether is in bubble stage (true) or catch stage (false).
  13009. // returns:
  13010. // If you do NOT want the event to propagate any further along the area stack, return exactly false.
  13011. // So if you return nothing (undefined), this event is still propagating.
  13012. onKey: function(event, isBubble){return true},
  13013. // getRegions: function()
  13014. // Define the small regions (dom nodes) in this area.
  13015. // returns: Array of dom nodes.
  13016. getRegions: function(){},
  13017. // onRegionFocus: function(event)
  13018. // Connected to the onfocus event of the defined regions (if any)
  13019. onRegionFocus: function(event){},
  13020. // onRegionBlur: function(event)
  13021. // Connected to the onblur event of the defined regions (if any)
  13022. onRegionBlur: function(event){},
  13023. =====*/
  13024. constructor: function(area, focusManager){
  13025. this._fm = focusManager;
  13026. this._evtStack = [area.name];
  13027. var dummy = function(){return true;};
  13028. area.onFocus = area.onFocus || dummy;
  13029. area.onBlur = area.onBlur || dummy;
  13030. area.onMove = area.onMove || dummy;
  13031. area.onKeyUp = area.onKeyUp || dummy;
  13032. area.onKeyDown = area.onKeyDown || dummy;
  13033. lang.mixin(this, area);
  13034. },
  13035. move: function(rowStep, colStep, evt){
  13036. if(this.name){
  13037. var i, len = this._evtStack.length;
  13038. for(i = len - 1; i >= 0; --i){
  13039. if(this._fm._areas[this._evtStack[i]].onMove(rowStep, colStep, evt) === false){
  13040. return false;
  13041. }
  13042. }
  13043. }
  13044. return true;
  13045. },
  13046. _onKeyEvent: function(evt, funcName){
  13047. if(this.name){
  13048. var i, len = this._evtStack.length;
  13049. for(i = len - 1; i >= 0; --i){
  13050. if(this._fm._areas[this._evtStack[i]][funcName](evt, false) === false){
  13051. return false;
  13052. }
  13053. }
  13054. for(i = 0; i < len; ++i){
  13055. if(this._fm._areas[this._evtStack[i]][funcName](evt, true) === false){
  13056. return false;
  13057. }
  13058. }
  13059. }
  13060. return true;
  13061. },
  13062. keydown: function(evt){
  13063. return this._onKeyEvent(evt, "onKeyDown");
  13064. },
  13065. keyup: function(evt){
  13066. return this._onKeyEvent(evt, "onKeyUp");
  13067. },
  13068. contentMouseEventPlanner: function(){
  13069. return 0;
  13070. },
  13071. headerMouseEventPlanner: function(){
  13072. return 0;
  13073. }
  13074. });
  13075. return declare("dojox.grid.enhanced._FocusManager", _FocusManager, {
  13076. _stopEvent: function(evt){
  13077. try{
  13078. if(evt && evt.preventDefault){
  13079. event.stop(evt);
  13080. }
  13081. }catch(e){}
  13082. },
  13083. constructor: function(grid){
  13084. this.grid = grid;
  13085. this._areas = {};
  13086. this._areaQueue = [];
  13087. this._contentMouseEventHandlers = [];
  13088. this._headerMouseEventHandlers = [];
  13089. this._currentAreaIdx = -1;
  13090. this._gridBlured = true;
  13091. this._connects.push(connect.connect(grid, "onBlur", this, "_doBlur"));
  13092. this._connects.push(connect.connect(grid.scroller, "renderPage", this, "_delayedCellFocus"));
  13093. this.addArea({
  13094. name: "header",
  13095. onFocus: lang.hitch(this, this.focusHeader),
  13096. onBlur: lang.hitch(this, this._blurHeader),
  13097. onMove: lang.hitch(this, this._navHeader),
  13098. getRegions: lang.hitch(this, this._findHeaderCells),
  13099. onRegionFocus: lang.hitch(this, this.doColHeaderFocus),
  13100. onRegionBlur: lang.hitch(this, this.doColHeaderBlur),
  13101. onKeyDown: lang.hitch(this, this._onHeaderKeyDown)
  13102. });
  13103. this.addArea({
  13104. name: "content",
  13105. onFocus: lang.hitch(this, this._focusContent),
  13106. onBlur: lang.hitch(this, this._blurContent),
  13107. onMove: lang.hitch(this, this._navContent),
  13108. onKeyDown: lang.hitch(this, this._onContentKeyDown)
  13109. });
  13110. this.addArea({
  13111. name: "editableCell",
  13112. onFocus: lang.hitch(this, this._focusEditableCell),
  13113. onBlur: lang.hitch(this, this._blurEditableCell),
  13114. onKeyDown: lang.hitch(this, this._onEditableCellKeyDown),
  13115. onContentMouseEvent: lang.hitch(this, this._onEditableCellMouseEvent),
  13116. contentMouseEventPlanner: function(evt, areas){ return -1; }
  13117. });
  13118. this.placeArea("header");
  13119. this.placeArea("content");
  13120. this.placeArea("editableCell");
  13121. this.placeArea("editableCell","above","content");
  13122. },
  13123. destroy: function(){
  13124. for(var name in this._areas){
  13125. var area = this._areas[name];
  13126. array.forEach(area._connects, connect.disconnect);
  13127. area._connects = null;
  13128. if(area.uninitialize){
  13129. area.uninitialize();
  13130. }
  13131. }
  13132. this.inherited(arguments);
  13133. },
  13134. addArea: function(area){
  13135. if(area.name && lang.isString(area.name)){
  13136. if(this._areas[area.name]){
  13137. //Just replace the original area, instead of remove it, so the position does not change.
  13138. array.forEach(area._connects, connect.disconnect);
  13139. }
  13140. this._areas[area.name] = new _FocusArea(area, this);
  13141. if(area.onHeaderMouseEvent){
  13142. this._headerMouseEventHandlers.push(area.name);
  13143. }
  13144. if(area.onContentMouseEvent){
  13145. this._contentMouseEventHandlers.push(area.name);
  13146. }
  13147. }
  13148. },
  13149. getArea: function(areaName){
  13150. return this._areas[areaName];
  13151. },
  13152. _bindAreaEvents: function(){
  13153. var area, hdl, areas = this._areas;
  13154. array.forEach(this._areaQueue, function(name){
  13155. area = areas[name];
  13156. if(!area._initialized && lang.isFunction(area.initialize)){
  13157. area.initialize();
  13158. area._initialized = true;
  13159. }
  13160. if(area.getRegions){
  13161. area._regions = area.getRegions() || [];
  13162. array.forEach(area._connects || [], connect.disconnect);
  13163. area._connects = [];
  13164. array.forEach(area._regions, function(r){
  13165. if(area.onRegionFocus){
  13166. hdl = connect.connect(r, "onfocus", area.onRegionFocus);
  13167. area._connects.push(hdl);
  13168. }
  13169. if(area.onRegionBlur){
  13170. hdl = connect.connect(r, "onblur", area.onRegionBlur);
  13171. area._connects.push(hdl);
  13172. }
  13173. });
  13174. }
  13175. });
  13176. },
  13177. removeArea: function(areaName){
  13178. var area = this._areas[areaName];
  13179. if(area){
  13180. this.ignoreArea(areaName);
  13181. var i = array.indexOf(this._contentMouseEventHandlers, areaName);
  13182. if(i >= 0){
  13183. this._contentMouseEventHandlers.splice(i, 1);
  13184. }
  13185. i = array.indexOf(this._headerMouseEventHandlers, areaName);
  13186. if(i >= 0){
  13187. this._headerMouseEventHandlers.splice(i, 1);
  13188. }
  13189. array.forEach(area._connects, connect.disconnect);
  13190. if(area.uninitialize){
  13191. area.uninitialize();
  13192. }
  13193. delete this._areas[areaName];
  13194. }
  13195. },
  13196. currentArea: function(areaName, toBlurOld){
  13197. // summary:
  13198. // Set current area to the one areaName refers.
  13199. // areaName: String
  13200. var idx, cai = this._currentAreaIdx;
  13201. if(lang.isString(areaName) && (idx = array.indexOf(this._areaQueue, areaName)) >= 0){
  13202. if(cai != idx){
  13203. this.tabbingOut = false;
  13204. if(toBlurOld && cai >= 0 && cai < this._areaQueue.length){
  13205. this._areas[this._areaQueue[cai]].onBlur();
  13206. }
  13207. this._currentAreaIdx = idx;
  13208. }
  13209. }else{
  13210. return (cai < 0 || cai >= this._areaQueue.length) ?
  13211. new _FocusArea({}, this) :
  13212. this._areas[this._areaQueue[this._currentAreaIdx]];
  13213. }
  13214. return null;
  13215. },
  13216. placeArea: function(name, pos, otherAreaName){
  13217. // summary:
  13218. // Place the area refered by *name* at some logical position relative to an existing area.
  13219. // example:
  13220. // placeArea("myarea","before"|"after",...)
  13221. // placeArea("myarea","below"|"above",...)
  13222. if(!this._areas[name]){ return; }
  13223. var idx = array.indexOf(this._areaQueue,otherAreaName);
  13224. switch(pos){
  13225. case "after":
  13226. if(idx >= 0){ ++idx; }
  13227. //intentional drop through
  13228. case "before":
  13229. if(idx >= 0){
  13230. this._areaQueue.splice(idx,0,name);
  13231. break;
  13232. }
  13233. //intentional drop through
  13234. default:
  13235. this._areaQueue.push(name);
  13236. break;
  13237. case "above":
  13238. var isAbove = true;
  13239. //intentional drop through
  13240. case "below":
  13241. var otherArea = this._areas[otherAreaName];
  13242. if(otherArea){
  13243. if(isAbove){
  13244. otherArea._evtStack.push(name);
  13245. }else{
  13246. otherArea._evtStack.splice(0,0,name);
  13247. }
  13248. }
  13249. }
  13250. },
  13251. ignoreArea: function(name){
  13252. this._areaQueue = array.filter(this._areaQueue,function(areaName){
  13253. return areaName != name;
  13254. });
  13255. },
  13256. focusArea: function(/* int|string|areaObj */areaId,evt){
  13257. var idx;
  13258. if(typeof areaId == "number"){
  13259. idx = areaId < 0 ? this._areaQueue.length + areaId : areaId;
  13260. }else{
  13261. idx = array.indexOf(this._areaQueue,
  13262. lang.isString(areaId) ? areaId : (areaId && areaId.name));
  13263. }
  13264. if(idx < 0){ idx = 0; }
  13265. var step = idx - this._currentAreaIdx;
  13266. this._gridBlured = false;
  13267. if(step){
  13268. this.tab(step, evt);
  13269. }else{
  13270. this.currentArea().onFocus(evt, step);
  13271. }
  13272. },
  13273. tab: function(step,evt){
  13274. //console.log("===========tab",step,"curArea",this._currentAreaIdx,"areaCnt",this._areaQueue.length);
  13275. this._gridBlured = false;
  13276. this.tabbingOut = false;
  13277. if(step === 0){
  13278. return;
  13279. }
  13280. var cai = this._currentAreaIdx;
  13281. var dir = step > 0 ? 1:-1;
  13282. if(cai < 0 || cai >= this._areaQueue.length){
  13283. cai = (this._currentAreaIdx += step);
  13284. }else{
  13285. var nextArea = this._areas[this._areaQueue[cai]].onBlur(evt,step);
  13286. if(nextArea === true){
  13287. cai = (this._currentAreaIdx += step);
  13288. }else if(lang.isString(nextArea) && this._areas[nextArea]){
  13289. cai = this._currentAreaIdx = array.indexOf(this._areaQueue,nextArea);
  13290. }
  13291. }
  13292. //console.log("target area:",cai);
  13293. for(; cai >= 0 && cai < this._areaQueue.length; cai += dir){
  13294. this._currentAreaIdx = cai;
  13295. if(this._areaQueue[cai] && this._areas[this._areaQueue[cai]].onFocus(evt,step)){
  13296. //console.log("final target area:",this._currentAreaIdx);
  13297. return;
  13298. }
  13299. }
  13300. //console.log("tab out");
  13301. this.tabbingOut = true;
  13302. if(step < 0){
  13303. this._currentAreaIdx = -1;
  13304. dijitFocus.focus(this.grid.domNode);
  13305. }else{
  13306. this._currentAreaIdx = this._areaQueue.length;
  13307. dijitFocus.focus(this.grid.lastFocusNode);
  13308. }
  13309. },
  13310. _onMouseEvent: function(type, evt){
  13311. var lowercase = type.toLowerCase(),
  13312. handlers = this["_" + lowercase + "MouseEventHandlers"],
  13313. res = array.map(handlers, function(areaName){
  13314. return {
  13315. "area": areaName,
  13316. "idx": this._areas[areaName][lowercase + "MouseEventPlanner"](evt, handlers)
  13317. };
  13318. }, this).sort(function(a, b){
  13319. return b.idx - a.idx;
  13320. }),
  13321. resHandlers = array.map(res, function(handler){
  13322. return res.area;
  13323. }),
  13324. i = res.length;
  13325. while(--i >= 0){
  13326. if(this._areas[res[i].area]["on" + type + "MouseEvent"](evt, resHandlers) === false){
  13327. return;
  13328. }
  13329. }
  13330. },
  13331. contentMouseEvent: function(evt){
  13332. this._onMouseEvent("Content", evt);
  13333. },
  13334. headerMouseEvent: function(evt){
  13335. this._onMouseEvent("Header", evt);
  13336. },
  13337. initFocusView: function(){
  13338. // summary:
  13339. // Overwritten
  13340. this.focusView = this.grid.views.getFirstScrollingView() || this.focusView || this.grid.views.views[0];
  13341. this._bindAreaEvents();
  13342. },
  13343. isNavHeader: function(){
  13344. // summary:
  13345. // Overwritten
  13346. // Check whether currently navigating among column headers.
  13347. // return:
  13348. // true - focus is on a certain column header | false otherwise
  13349. return this._areaQueue[this._currentAreaIdx] == "header";
  13350. },
  13351. previousKey: function(e){
  13352. // summary:
  13353. // Overwritten
  13354. this.tab(-1,e);
  13355. },
  13356. nextKey: function(e){
  13357. // summary:
  13358. // Overwritten
  13359. this.tab(1,e);
  13360. },
  13361. setFocusCell: function(/* Object */inCell, /* Integer */inRowIndex){
  13362. // summary:
  13363. // Overwritten - focuses the given grid cell
  13364. if(inCell){
  13365. this.currentArea(this.grid.edit.isEditing() ? "editableCell" : "content", true);
  13366. //This is very slow when selecting cells!
  13367. //this.focusGridView();
  13368. this._focusifyCellNode(false);
  13369. this.cell = inCell;
  13370. this.rowIndex = inRowIndex;
  13371. this._focusifyCellNode(true);
  13372. }
  13373. this.grid.onCellFocus(this.cell, this.rowIndex);
  13374. },
  13375. doFocus: function(e){
  13376. // summary:
  13377. // Overwritten
  13378. // trap focus only for grid dom node
  13379. // do not focus for scrolling if grid is about to blur
  13380. if(e && e.target == e.currentTarget && !this.tabbingOut){
  13381. if(this._gridBlured){
  13382. this._gridBlured = false;
  13383. if(this._currentAreaIdx < 0 || this._currentAreaIdx >= this._areaQueue.length){
  13384. this.focusArea(0, e);
  13385. }else{
  13386. this.focusArea(this._currentAreaIdx, e);
  13387. }
  13388. }
  13389. }else{
  13390. this.tabbingOut = false;
  13391. }
  13392. event.stop(e);
  13393. },
  13394. _doBlur: function(){
  13395. this._gridBlured = true;
  13396. },
  13397. doLastNodeFocus: function(e){
  13398. // summary:
  13399. // Overwritten
  13400. if(this.tabbingOut){
  13401. this.tabbingOut = false;
  13402. }else{
  13403. this.focusArea(-1, e);
  13404. }
  13405. },
  13406. _delayedHeaderFocus: function(){
  13407. // summary:
  13408. // Overwritten
  13409. if(this.isNavHeader() && !has("ie")){
  13410. this.focusHeader();
  13411. }
  13412. },
  13413. _delayedCellFocus: function(){
  13414. // summary:
  13415. // Overwritten
  13416. this.currentArea("header", true);
  13417. this.focusArea(this._currentAreaIdx);
  13418. },
  13419. _changeMenuBindNode: function(oldBindNode, newBindNode){
  13420. var hm = this.grid.headerMenu;
  13421. if(hm && this._contextMenuBindNode == oldBindNode){
  13422. hm.unBindDomNode(oldBindNode);
  13423. hm.bindDomNode(newBindNode);
  13424. this._contextMenuBindNode = newBindNode;
  13425. }
  13426. },
  13427. //---------------Header Area------------------------------------------
  13428. focusHeader: function(evt, step){ //need a further look why these changes to parent's
  13429. // summary:
  13430. // Overwritten
  13431. var didFocus = false;
  13432. this.inherited(arguments);
  13433. if(this._colHeadNode && html.style(this._colHeadNode, 'display') != "none"){
  13434. dijitFocus.focus(this._colHeadNode);
  13435. this._stopEvent(evt);
  13436. didFocus = true;
  13437. }
  13438. return didFocus;
  13439. },
  13440. _blurHeader: function(evt,step){
  13441. // summary:
  13442. // Overwritten
  13443. if(this._colHeadNode){
  13444. html.removeClass(this._colHeadNode, this.focusClass);
  13445. }
  13446. html.removeAttr(this.grid.domNode,"aria-activedescendant");
  13447. // reset contextMenu onto viewsHeaderNode so right mouse on header will invoke (see focusHeader)
  13448. this._changeMenuBindNode(this.grid.domNode,this.grid.viewsHeaderNode);
  13449. //moved here from nextKey
  13450. this._colHeadNode = this._colHeadFocusIdx = null;
  13451. return true;
  13452. },
  13453. _navHeader: function(rowStep, colStep, evt){
  13454. var colDir = colStep < 0 ? -1 : 1,
  13455. savedIdx = array.indexOf(this._findHeaderCells(), this._colHeadNode);
  13456. if(savedIdx >= 0 && (evt.shiftKey && evt.ctrlKey)){
  13457. this.colSizeAdjust(evt, savedIdx, colDir * 5);
  13458. return;
  13459. }
  13460. this.move(rowStep, colStep);
  13461. },
  13462. _onHeaderKeyDown: function(e, isBubble){
  13463. if(isBubble){
  13464. var dk = keys;
  13465. switch(e.keyCode){
  13466. case dk.ENTER:
  13467. case dk.SPACE:
  13468. var colIdx = this.getHeaderIndex();
  13469. if(colIdx >= 0 && !this.grid.pluginMgr.isFixedCell(e.cell)/*TODO*/){
  13470. this.grid.setSortIndex(colIdx, null, e);
  13471. event.stop(e);
  13472. }
  13473. break;
  13474. }
  13475. }
  13476. return true;
  13477. },
  13478. _setActiveColHeader: function(){
  13479. // summary:
  13480. // Overwritten
  13481. this.inherited(arguments);
  13482. //EDG now will decorate event on header key events, if no focus, the cell will be wrong
  13483. dijitFocus.focus(this._colHeadNode);
  13484. },
  13485. //---------------Content Area------------------------------------------
  13486. findAndFocusGridCell: function(){
  13487. // summary:
  13488. // Overwritten
  13489. this._focusContent();
  13490. },
  13491. _focusContent: function(evt,step){
  13492. var didFocus = true;
  13493. var isEmpty = (this.grid.rowCount === 0); // If grid is empty this.grid.rowCount == 0
  13494. if(this.isNoFocusCell() && !isEmpty){
  13495. //skip all the hidden cells
  13496. for(var i = 0, cell = this.grid.getCell(0); cell && cell.hidden; cell = this.grid.getCell(++i)){}
  13497. this.setFocusIndex(0, cell ? i : 0);
  13498. }else if(this.cell && !isEmpty){
  13499. if(this.focusView && !this.focusView.rowNodes[this.rowIndex]){
  13500. // if rowNode for current index is undefined (likely as a result of a sort and because of #7304)
  13501. // scroll to that row
  13502. this.grid.scrollToRow(this.rowIndex);
  13503. this.focusGrid();
  13504. }else{
  13505. this.setFocusIndex(this.rowIndex, this.cell.index);
  13506. }
  13507. }else{
  13508. didFocus = false;
  13509. }
  13510. if(didFocus){ this._stopEvent(evt); }
  13511. return didFocus;
  13512. },
  13513. _blurContent: function(evt,step){
  13514. this._focusifyCellNode(false);
  13515. return true;
  13516. },
  13517. _navContent: function(rowStep, colStep, evt){
  13518. if((this.rowIndex === 0 && rowStep < 0) || (this.rowIndex === this.grid.rowCount - 1 && rowStep > 0)){
  13519. return;
  13520. }
  13521. this._colHeadNode = null;
  13522. this.move(rowStep, colStep, evt);
  13523. if(evt){
  13524. event.stop(evt);
  13525. }
  13526. },
  13527. _onContentKeyDown: function(e, isBubble){
  13528. if(isBubble){
  13529. var dk = keys, s = this.grid.scroller;
  13530. switch(e.keyCode){
  13531. case dk.ENTER:
  13532. case dk.SPACE:
  13533. var g = this.grid;
  13534. if(g.indirectSelection){ break; }
  13535. g.selection.clickSelect(this.rowIndex, connect.isCopyKey(e), e.shiftKey);
  13536. g.onRowClick(e);
  13537. event.stop(e);
  13538. break;
  13539. case dk.PAGE_UP:
  13540. if(this.rowIndex !== 0){
  13541. if(this.rowIndex != s.firstVisibleRow + 1){
  13542. this._navContent(s.firstVisibleRow - this.rowIndex, 0);
  13543. }else{
  13544. this.grid.setScrollTop(s.findScrollTop(this.rowIndex - 1));
  13545. this._navContent(s.firstVisibleRow - s.lastVisibleRow + 1, 0);
  13546. }
  13547. event.stop(e);
  13548. }
  13549. break;
  13550. case dk.PAGE_DOWN:
  13551. if(this.rowIndex + 1 != this.grid.rowCount){
  13552. event.stop(e);
  13553. if(this.rowIndex != s.lastVisibleRow - 1){
  13554. this._navContent(s.lastVisibleRow - this.rowIndex - 1, 0);
  13555. }else{
  13556. this.grid.setScrollTop(s.findScrollTop(this.rowIndex + 1));
  13557. this._navContent(s.lastVisibleRow - s.firstVisibleRow - 1, 0);
  13558. }
  13559. event.stop(e);
  13560. }
  13561. break;
  13562. }
  13563. }
  13564. return true;
  13565. },
  13566. //------------------editable content area-------------------------
  13567. _blurFromEditableCell: false,
  13568. _isNavigating: false,
  13569. _navElems: null,
  13570. _focusEditableCell: function(evt,step){
  13571. var didFocus = false;
  13572. if(this._isNavigating){
  13573. didFocus = true;
  13574. }else if(this.grid.edit.isEditing() && this.cell){
  13575. if(this._blurFromEditableCell || !this._blurEditableCell(evt, step)){
  13576. this.setFocusIndex(this.rowIndex,this.cell.index);
  13577. didFocus = true;
  13578. }
  13579. this._stopEvent(evt);
  13580. }
  13581. return didFocus;
  13582. },
  13583. _applyEditableCell: function(){
  13584. try{
  13585. this.grid.edit.apply();
  13586. }catch(e){
  13587. console.warn("_FocusManager._applyEditableCell() error:", e);
  13588. }
  13589. },
  13590. _blurEditableCell: function(evt,step){
  13591. this._blurFromEditableCell = false;
  13592. if(this._isNavigating){
  13593. var toBlur = true;
  13594. if(evt){
  13595. var elems = this._navElems;
  13596. var firstElem = elems.lowest || elems.first;
  13597. var lastElem = elems.last || elems.highest || firstElem;
  13598. var target = has("ie") ? evt.srcElement : evt.target;
  13599. toBlur = target == (step > 0 ? lastElem : firstElem);
  13600. }
  13601. if(toBlur){
  13602. this._isNavigating = false;
  13603. html.setSelectable(this.cell.getNode(this.rowIndex), false);
  13604. return "content";
  13605. }
  13606. return false;
  13607. }else if(this.grid.edit.isEditing() && this.cell){
  13608. if(!step || typeof step != "number"){ return false; }
  13609. var dir = step > 0 ? 1 : -1;
  13610. var cc = this.grid.layout.cellCount;
  13611. for(var cell, col = this.cell.index + dir; col >= 0 && col < cc; col += dir){
  13612. cell = this.grid.getCell(col);
  13613. if(cell.editable){
  13614. this.cell = cell;
  13615. this._blurFromEditableCell = true;
  13616. return false;
  13617. }
  13618. }
  13619. if((this.rowIndex > 0 || dir == 1) && (this.rowIndex < this.grid.rowCount || dir == -1)){
  13620. this.rowIndex += dir;
  13621. //this.cell = this.grid.getCell(0); //There must be an editable cell, so this is not necessary.
  13622. for(col = dir > 0 ? 0 : cc - 1; col >= 0 && col < cc; col += dir){
  13623. cell = this.grid.getCell(col);
  13624. if(cell.editable){
  13625. this.cell = cell;
  13626. break;
  13627. }
  13628. }
  13629. this._applyEditableCell();
  13630. return "content";
  13631. }
  13632. }
  13633. return true;
  13634. },
  13635. _initNavigatableElems: function(){
  13636. this._navElems = dijitA11y._getTabNavigable(this.cell.getNode(this.rowIndex));
  13637. },
  13638. _onEditableCellKeyDown: function(e, isBubble){
  13639. var dk = keys,
  13640. g = this.grid,
  13641. edit = g.edit,
  13642. editApplied = false,
  13643. toPropagate = true;
  13644. switch(e.keyCode){
  13645. case dk.ENTER:
  13646. if(isBubble && edit.isEditing()){
  13647. this._applyEditableCell();
  13648. editApplied = true;
  13649. event.stop(e);
  13650. }
  13651. //intentional drop through
  13652. case dk.SPACE:
  13653. if(!isBubble && this._isNavigating){
  13654. toPropagate = false;
  13655. break;
  13656. }
  13657. if(isBubble){
  13658. if(!this.cell.editable && this.cell.navigatable){
  13659. this._initNavigatableElems();
  13660. var toFocus = this._navElems.lowest || this._navElems.first;
  13661. if(toFocus){
  13662. this._isNavigating = true;
  13663. html.setSelectable(this.cell.getNode(this.rowIndex), true);
  13664. dijitFocus.focus(toFocus);
  13665. event.stop(e);
  13666. this.currentArea("editableCell", true);
  13667. break;
  13668. }
  13669. }
  13670. if(!editApplied && !edit.isEditing() && !g.pluginMgr.isFixedCell(this.cell)){
  13671. edit.setEditCell(this.cell, this.rowIndex);
  13672. }
  13673. if(editApplied){
  13674. this.currentArea("content", true);
  13675. }else if(this.cell.editable && g.canEdit()){
  13676. this.currentArea("editableCell", true);
  13677. }
  13678. }
  13679. break;
  13680. case dk.PAGE_UP:
  13681. case dk.PAGE_DOWN:
  13682. if(!isBubble && edit.isEditing()){
  13683. //prevent propagating to content area
  13684. toPropagate = false;
  13685. }
  13686. break;
  13687. case dk.ESCAPE:
  13688. if(!isBubble){
  13689. edit.cancel();
  13690. this.currentArea("content", true);
  13691. }
  13692. }
  13693. return toPropagate;
  13694. },
  13695. _onEditableCellMouseEvent: function(evt){
  13696. if(evt.type == "click"){
  13697. var cell = this.cell || evt.cell;
  13698. if(cell && !cell.editable && cell.navigatable){
  13699. this._initNavigatableElems();
  13700. if(this._navElems.lowest || this._navElems.first){
  13701. var target = has("ie") ? evt.srcElement : evt.target;
  13702. if(target != cell.getNode(evt.rowIndex)){
  13703. this._isNavigating = true;
  13704. this.focusArea("editableCell", evt);
  13705. html.setSelectable(cell.getNode(evt.rowIndex), true);
  13706. dijitFocus.focus(target);
  13707. return false;
  13708. }
  13709. }
  13710. }else if(this.grid.singleClickEdit){
  13711. this.currentArea("editableCell");
  13712. return false;
  13713. }
  13714. }
  13715. return true;
  13716. }
  13717. });
  13718. });
  13719. },
  13720. 'dojo/date':function(){
  13721. define("dojo/date", ["./_base/kernel", "./_base/lang"], function(dojo, lang) {
  13722. // module:
  13723. // dojo/date
  13724. // summary:
  13725. // TODOC
  13726. lang.getObject("date", true, dojo);
  13727. /*=====
  13728. dojo.date = {
  13729. // summary: Date manipulation utilities
  13730. }
  13731. =====*/
  13732. dojo.date.getDaysInMonth = function(/*Date*/dateObject){
  13733. // summary:
  13734. // Returns the number of days in the month used by dateObject
  13735. var month = dateObject.getMonth();
  13736. var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  13737. if(month == 1 && dojo.date.isLeapYear(dateObject)){ return 29; } // Number
  13738. return days[month]; // Number
  13739. };
  13740. dojo.date.isLeapYear = function(/*Date*/dateObject){
  13741. // summary:
  13742. // Determines if the year of the dateObject is a leap year
  13743. // description:
  13744. // Leap years are years with an additional day YYYY-02-29, where the
  13745. // year number is a multiple of four with the following exception: If
  13746. // a year is a multiple of 100, then it is only a leap year if it is
  13747. // also a multiple of 400. For example, 1900 was not a leap year, but
  13748. // 2000 is one.
  13749. var year = dateObject.getFullYear();
  13750. return !(year%400) || (!(year%4) && !!(year%100)); // Boolean
  13751. };
  13752. // FIXME: This is not localized
  13753. dojo.date.getTimezoneName = function(/*Date*/dateObject){
  13754. // summary:
  13755. // Get the user's time zone as provided by the browser
  13756. // dateObject:
  13757. // Needed because the timezone may vary with time (daylight savings)
  13758. // description:
  13759. // Try to get time zone info from toString or toLocaleString method of
  13760. // the Date object -- UTC offset is not a time zone. See
  13761. // http://www.twinsun.com/tz/tz-link.htm Note: results may be
  13762. // inconsistent across browsers.
  13763. var str = dateObject.toString(); // Start looking in toString
  13764. var tz = ''; // The result -- return empty string if nothing found
  13765. var match;
  13766. // First look for something in parentheses -- fast lookup, no regex
  13767. var pos = str.indexOf('(');
  13768. if(pos > -1){
  13769. tz = str.substring(++pos, str.indexOf(')'));
  13770. }else{
  13771. // If at first you don't succeed ...
  13772. // If IE knows about the TZ, it appears before the year
  13773. // Capital letters or slash before a 4-digit year
  13774. // at the end of string
  13775. var pat = /([A-Z\/]+) \d{4}$/;
  13776. if((match = str.match(pat))){
  13777. tz = match[1];
  13778. }else{
  13779. // Some browsers (e.g. Safari) glue the TZ on the end
  13780. // of toLocaleString instead of putting it in toString
  13781. str = dateObject.toLocaleString();
  13782. // Capital letters or slash -- end of string,
  13783. // after space
  13784. pat = / ([A-Z\/]+)$/;
  13785. if((match = str.match(pat))){
  13786. tz = match[1];
  13787. }
  13788. }
  13789. }
  13790. // Make sure it doesn't somehow end up return AM or PM
  13791. return (tz == 'AM' || tz == 'PM') ? '' : tz; // String
  13792. };
  13793. // Utility methods to do arithmetic calculations with Dates
  13794. dojo.date.compare = function(/*Date*/date1, /*Date?*/date2, /*String?*/portion){
  13795. // summary:
  13796. // Compare two date objects by date, time, or both.
  13797. // description:
  13798. // Returns 0 if equal, positive if a > b, else negative.
  13799. // date1:
  13800. // Date object
  13801. // date2:
  13802. // Date object. If not specified, the current Date is used.
  13803. // portion:
  13804. // A string indicating the "date" or "time" portion of a Date object.
  13805. // Compares both "date" and "time" by default. One of the following:
  13806. // "date", "time", "datetime"
  13807. // Extra step required in copy for IE - see #3112
  13808. date1 = new Date(+date1);
  13809. date2 = new Date(+(date2 || new Date()));
  13810. if(portion == "date"){
  13811. // Ignore times and compare dates.
  13812. date1.setHours(0, 0, 0, 0);
  13813. date2.setHours(0, 0, 0, 0);
  13814. }else if(portion == "time"){
  13815. // Ignore dates and compare times.
  13816. date1.setFullYear(0, 0, 0);
  13817. date2.setFullYear(0, 0, 0);
  13818. }
  13819. if(date1 > date2){ return 1; } // int
  13820. if(date1 < date2){ return -1; } // int
  13821. return 0; // int
  13822. };
  13823. dojo.date.add = function(/*Date*/date, /*String*/interval, /*int*/amount){
  13824. // summary:
  13825. // Add to a Date in intervals of different size, from milliseconds to years
  13826. // date: Date
  13827. // Date object to start with
  13828. // interval:
  13829. // A string representing the interval. One of the following:
  13830. // "year", "month", "day", "hour", "minute", "second",
  13831. // "millisecond", "quarter", "week", "weekday"
  13832. // amount:
  13833. // How much to add to the date.
  13834. var sum = new Date(+date); // convert to Number before copying to accomodate IE (#3112)
  13835. var fixOvershoot = false;
  13836. var property = "Date";
  13837. switch(interval){
  13838. case "day":
  13839. break;
  13840. case "weekday":
  13841. //i18n FIXME: assumes Saturday/Sunday weekend, but this is not always true. see dojo.cldr.supplemental
  13842. // Divide the increment time span into weekspans plus leftover days
  13843. // e.g., 8 days is one 5-day weekspan / and two leftover days
  13844. // Can't have zero leftover days, so numbers divisible by 5 get
  13845. // a days value of 5, and the remaining days make up the number of weeks
  13846. var days, weeks;
  13847. var mod = amount % 5;
  13848. if(!mod){
  13849. days = (amount > 0) ? 5 : -5;
  13850. weeks = (amount > 0) ? ((amount-5)/5) : ((amount+5)/5);
  13851. }else{
  13852. days = mod;
  13853. weeks = parseInt(amount/5);
  13854. }
  13855. // Get weekday value for orig date param
  13856. var strt = date.getDay();
  13857. // Orig date is Sat / positive incrementer
  13858. // Jump over Sun
  13859. var adj = 0;
  13860. if(strt == 6 && amount > 0){
  13861. adj = 1;
  13862. }else if(strt == 0 && amount < 0){
  13863. // Orig date is Sun / negative incrementer
  13864. // Jump back over Sat
  13865. adj = -1;
  13866. }
  13867. // Get weekday val for the new date
  13868. var trgt = strt + days;
  13869. // New date is on Sat or Sun
  13870. if(trgt == 0 || trgt == 6){
  13871. adj = (amount > 0) ? 2 : -2;
  13872. }
  13873. // Increment by number of weeks plus leftover days plus
  13874. // weekend adjustments
  13875. amount = (7 * weeks) + days + adj;
  13876. break;
  13877. case "year":
  13878. property = "FullYear";
  13879. // Keep increment/decrement from 2/29 out of March
  13880. fixOvershoot = true;
  13881. break;
  13882. case "week":
  13883. amount *= 7;
  13884. break;
  13885. case "quarter":
  13886. // Naive quarter is just three months
  13887. amount *= 3;
  13888. // fallthrough...
  13889. case "month":
  13890. // Reset to last day of month if you overshoot
  13891. fixOvershoot = true;
  13892. property = "Month";
  13893. break;
  13894. // case "hour":
  13895. // case "minute":
  13896. // case "second":
  13897. // case "millisecond":
  13898. default:
  13899. property = "UTC"+interval.charAt(0).toUpperCase() + interval.substring(1) + "s";
  13900. }
  13901. if(property){
  13902. sum["set"+property](sum["get"+property]()+amount);
  13903. }
  13904. if(fixOvershoot && (sum.getDate() < date.getDate())){
  13905. sum.setDate(0);
  13906. }
  13907. return sum; // Date
  13908. };
  13909. dojo.date.difference = function(/*Date*/date1, /*Date?*/date2, /*String?*/interval){
  13910. // summary:
  13911. // Get the difference in a specific unit of time (e.g., number of
  13912. // months, weeks, days, etc.) between two dates, rounded to the
  13913. // nearest integer.
  13914. // date1:
  13915. // Date object
  13916. // date2:
  13917. // Date object. If not specified, the current Date is used.
  13918. // interval:
  13919. // A string representing the interval. One of the following:
  13920. // "year", "month", "day", "hour", "minute", "second",
  13921. // "millisecond", "quarter", "week", "weekday"
  13922. // Defaults to "day".
  13923. date2 = date2 || new Date();
  13924. interval = interval || "day";
  13925. var yearDiff = date2.getFullYear() - date1.getFullYear();
  13926. var delta = 1; // Integer return value
  13927. switch(interval){
  13928. case "quarter":
  13929. var m1 = date1.getMonth();
  13930. var m2 = date2.getMonth();
  13931. // Figure out which quarter the months are in
  13932. var q1 = Math.floor(m1/3) + 1;
  13933. var q2 = Math.floor(m2/3) + 1;
  13934. // Add quarters for any year difference between the dates
  13935. q2 += (yearDiff * 4);
  13936. delta = q2 - q1;
  13937. break;
  13938. case "weekday":
  13939. var days = Math.round(dojo.date.difference(date1, date2, "day"));
  13940. var weeks = parseInt(dojo.date.difference(date1, date2, "week"));
  13941. var mod = days % 7;
  13942. // Even number of weeks
  13943. if(mod == 0){
  13944. days = weeks*5;
  13945. }else{
  13946. // Weeks plus spare change (< 7 days)
  13947. var adj = 0;
  13948. var aDay = date1.getDay();
  13949. var bDay = date2.getDay();
  13950. weeks = parseInt(days/7);
  13951. mod = days % 7;
  13952. // Mark the date advanced by the number of
  13953. // round weeks (may be zero)
  13954. var dtMark = new Date(date1);
  13955. dtMark.setDate(dtMark.getDate()+(weeks*7));
  13956. var dayMark = dtMark.getDay();
  13957. // Spare change days -- 6 or less
  13958. if(days > 0){
  13959. switch(true){
  13960. // Range starts on Sat
  13961. case aDay == 6:
  13962. adj = -1;
  13963. break;
  13964. // Range starts on Sun
  13965. case aDay == 0:
  13966. adj = 0;
  13967. break;
  13968. // Range ends on Sat
  13969. case bDay == 6:
  13970. adj = -1;
  13971. break;
  13972. // Range ends on Sun
  13973. case bDay == 0:
  13974. adj = -2;
  13975. break;
  13976. // Range contains weekend
  13977. case (dayMark + mod) > 5:
  13978. adj = -2;
  13979. }
  13980. }else if(days < 0){
  13981. switch(true){
  13982. // Range starts on Sat
  13983. case aDay == 6:
  13984. adj = 0;
  13985. break;
  13986. // Range starts on Sun
  13987. case aDay == 0:
  13988. adj = 1;
  13989. break;
  13990. // Range ends on Sat
  13991. case bDay == 6:
  13992. adj = 2;
  13993. break;
  13994. // Range ends on Sun
  13995. case bDay == 0:
  13996. adj = 1;
  13997. break;
  13998. // Range contains weekend
  13999. case (dayMark + mod) < 0:
  14000. adj = 2;
  14001. }
  14002. }
  14003. days += adj;
  14004. days -= (weeks*2);
  14005. }
  14006. delta = days;
  14007. break;
  14008. case "year":
  14009. delta = yearDiff;
  14010. break;
  14011. case "month":
  14012. delta = (date2.getMonth() - date1.getMonth()) + (yearDiff * 12);
  14013. break;
  14014. case "week":
  14015. // Truncate instead of rounding
  14016. // Don't use Math.floor -- value may be negative
  14017. delta = parseInt(dojo.date.difference(date1, date2, "day")/7);
  14018. break;
  14019. case "day":
  14020. delta /= 24;
  14021. // fallthrough
  14022. case "hour":
  14023. delta /= 60;
  14024. // fallthrough
  14025. case "minute":
  14026. delta /= 60;
  14027. // fallthrough
  14028. case "second":
  14029. delta /= 1000;
  14030. // fallthrough
  14031. case "millisecond":
  14032. delta *= date2.getTime() - date1.getTime();
  14033. }
  14034. // Round for fractional values and DST leaps
  14035. return Math.round(delta); // Number (integer)
  14036. };
  14037. return dojo.date;
  14038. });
  14039. },
  14040. 'dojox/grid/_Layout':function(){
  14041. define("dojox/grid/_Layout", [
  14042. "dojo/_base/kernel",
  14043. "../main",
  14044. "dojo/_base/declare",
  14045. "dojo/_base/array",
  14046. "dojo/_base/lang",
  14047. "dojo/dom-geometry",
  14048. "./cells",
  14049. "./_RowSelector"
  14050. ], function(dojo, dojox, declare, array, lang, domGeometry){
  14051. return declare("dojox.grid._Layout", null, {
  14052. // summary:
  14053. // Controls grid cell layout. Owned by grid and used internally.
  14054. constructor: function(inGrid){
  14055. this.grid = inGrid;
  14056. },
  14057. // flat array of grid cells
  14058. cells: [],
  14059. // structured array of grid cells
  14060. structure: null,
  14061. // default cell width
  14062. defaultWidth: '6em',
  14063. // methods
  14064. moveColumn: function(sourceViewIndex, destViewIndex, cellIndex, targetIndex, before){
  14065. var source_cells = this.structure[sourceViewIndex].cells[0];
  14066. var dest_cells = this.structure[destViewIndex].cells[0];
  14067. var cell = null;
  14068. var cell_ri = 0;
  14069. var target_ri = 0;
  14070. for(var i=0, c; c=source_cells[i]; i++){
  14071. if(c.index == cellIndex){
  14072. cell_ri = i;
  14073. break;
  14074. }
  14075. }
  14076. cell = source_cells.splice(cell_ri, 1)[0];
  14077. cell.view = this.grid.views.views[destViewIndex];
  14078. for(i=0, c=null; c=dest_cells[i]; i++){
  14079. if(c.index == targetIndex){
  14080. target_ri = i;
  14081. break;
  14082. }
  14083. }
  14084. if(!before){
  14085. target_ri += 1;
  14086. }
  14087. dest_cells.splice(target_ri, 0, cell);
  14088. var sortedCell = this.grid.getCell(this.grid.getSortIndex());
  14089. if(sortedCell){
  14090. sortedCell._currentlySorted = this.grid.getSortAsc();
  14091. }
  14092. this.cells = [];
  14093. cellIndex = 0;
  14094. var v;
  14095. for(i=0; v=this.structure[i]; i++){
  14096. for(var j=0, cs; cs=v.cells[j]; j++){
  14097. for(var k=0; c=cs[k]; k++){
  14098. c.index = cellIndex;
  14099. this.cells.push(c);
  14100. if("_currentlySorted" in c){
  14101. var si = cellIndex + 1;
  14102. si *= c._currentlySorted ? 1 : -1;
  14103. this.grid.sortInfo = si;
  14104. delete c._currentlySorted;
  14105. }
  14106. cellIndex++;
  14107. }
  14108. }
  14109. }
  14110. //Fix #9481 - reset idx in cell markup
  14111. array.forEach(this.cells, function(c){
  14112. var marks = c.markup[2].split(" ");
  14113. var oldIdx = parseInt(marks[1].substring(5));//get old "idx"
  14114. if(oldIdx != c.index){
  14115. marks[1] = "idx=\"" + c.index + "\"";
  14116. c.markup[2] = marks.join(" ");
  14117. }
  14118. });
  14119. this.grid.setupHeaderMenu();
  14120. //this.grid.renderOnIdle();
  14121. },
  14122. setColumnVisibility: function(columnIndex, visible){
  14123. var cell = this.cells[columnIndex];
  14124. if(cell.hidden == visible){
  14125. cell.hidden = !visible;
  14126. var v = cell.view, w = v.viewWidth;
  14127. if(w && w != "auto"){
  14128. v._togglingColumn = domGeometry.getMarginBox(cell.getHeaderNode()).w || 0;
  14129. }
  14130. v.update();
  14131. return true;
  14132. }else{
  14133. return false;
  14134. }
  14135. },
  14136. addCellDef: function(inRowIndex, inCellIndex, inDef){
  14137. var self = this;
  14138. var getCellWidth = function(inDef){
  14139. var w = 0;
  14140. if(inDef.colSpan > 1){
  14141. w = 0;
  14142. }else{
  14143. w = inDef.width || self._defaultCellProps.width || self.defaultWidth;
  14144. if(!isNaN(w)){
  14145. w = w + "em";
  14146. }
  14147. }
  14148. return w;
  14149. };
  14150. var props = {
  14151. grid: this.grid,
  14152. subrow: inRowIndex,
  14153. layoutIndex: inCellIndex,
  14154. index: this.cells.length
  14155. };
  14156. if(inDef && inDef instanceof dojox.grid.cells._Base){
  14157. var new_cell = lang.clone(inDef);
  14158. props.unitWidth = getCellWidth(new_cell._props);
  14159. new_cell = lang.mixin(new_cell, this._defaultCellProps, inDef._props, props);
  14160. return new_cell;
  14161. }
  14162. var cell_type = inDef.type || inDef.cellType || this._defaultCellProps.type || this._defaultCellProps.cellType || dojox.grid.cells.Cell;
  14163. if(lang.isString(cell_type)){
  14164. cell_type = lang.getObject(cell_type);
  14165. }
  14166. props.unitWidth = getCellWidth(inDef);
  14167. return new cell_type(lang.mixin({}, this._defaultCellProps, inDef, props));
  14168. },
  14169. addRowDef: function(inRowIndex, inDef){
  14170. var result = [];
  14171. var relSum = 0, pctSum = 0, doRel = true;
  14172. for(var i=0, def, cell; (def=inDef[i]); i++){
  14173. cell = this.addCellDef(inRowIndex, i, def);
  14174. result.push(cell);
  14175. this.cells.push(cell);
  14176. // Check and calculate the sum of all relative widths
  14177. if(doRel && cell.relWidth){
  14178. relSum += cell.relWidth;
  14179. }else if(cell.width){
  14180. var w = cell.width;
  14181. if(typeof w == "string" && w.slice(-1) == "%"){
  14182. pctSum += window.parseInt(w, 10);
  14183. }else if(w == "auto"){
  14184. // relative widths doesn't play nice with auto - since we
  14185. // don't have a way of knowing how much space the auto is
  14186. // supposed to take up.
  14187. doRel = false;
  14188. }
  14189. }
  14190. }
  14191. if(relSum && doRel){
  14192. // We have some kind of relWidths specified - so change them to %
  14193. array.forEach(result, function(cell){
  14194. if(cell.relWidth){
  14195. cell.width = cell.unitWidth = ((cell.relWidth / relSum) * (100 - pctSum)) + "%";
  14196. }
  14197. });
  14198. }
  14199. return result;
  14200. },
  14201. addRowsDef: function(inDef){
  14202. var result = [];
  14203. if(lang.isArray(inDef)){
  14204. if(lang.isArray(inDef[0])){
  14205. for(var i=0, row; inDef && (row=inDef[i]); i++){
  14206. result.push(this.addRowDef(i, row));
  14207. }
  14208. }else{
  14209. result.push(this.addRowDef(0, inDef));
  14210. }
  14211. }
  14212. return result;
  14213. },
  14214. addViewDef: function(inDef){
  14215. this._defaultCellProps = inDef.defaultCell || {};
  14216. if(inDef.width && inDef.width == "auto"){
  14217. delete inDef.width;
  14218. }
  14219. return lang.mixin({}, inDef, {cells: this.addRowsDef(inDef.rows || inDef.cells)});
  14220. },
  14221. setStructure: function(inStructure){
  14222. this.fieldIndex = 0;
  14223. this.cells = [];
  14224. var s = this.structure = [];
  14225. if(this.grid.rowSelector){
  14226. var sel = { type: dojox._scopeName + ".grid._RowSelector" };
  14227. if(lang.isString(this.grid.rowSelector)){
  14228. var width = this.grid.rowSelector;
  14229. if(width == "false"){
  14230. sel = null;
  14231. }else if(width != "true"){
  14232. sel['width'] = width;
  14233. }
  14234. }else{
  14235. if(!this.grid.rowSelector){
  14236. sel = null;
  14237. }
  14238. }
  14239. if(sel){
  14240. s.push(this.addViewDef(sel));
  14241. }
  14242. }
  14243. var isCell = function(def){
  14244. return ("name" in def || "field" in def || "get" in def);
  14245. };
  14246. var isRowDef = function(def){
  14247. if(lang.isArray(def)){
  14248. if(lang.isArray(def[0]) || isCell(def[0])){
  14249. return true;
  14250. }
  14251. }
  14252. return false;
  14253. };
  14254. var isView = function(def){
  14255. return (def !== null && lang.isObject(def) &&
  14256. ("cells" in def || "rows" in def || ("type" in def && !isCell(def))));
  14257. };
  14258. if(lang.isArray(inStructure)){
  14259. var hasViews = false;
  14260. for(var i=0, st; (st=inStructure[i]); i++){
  14261. if(isView(st)){
  14262. hasViews = true;
  14263. break;
  14264. }
  14265. }
  14266. if(!hasViews){
  14267. s.push(this.addViewDef({ cells: inStructure }));
  14268. }else{
  14269. for(i=0; (st=inStructure[i]); i++){
  14270. if(isRowDef(st)){
  14271. s.push(this.addViewDef({ cells: st }));
  14272. }else if(isView(st)){
  14273. s.push(this.addViewDef(st));
  14274. }
  14275. }
  14276. }
  14277. }else if(isView(inStructure)){
  14278. // it's a view object
  14279. s.push(this.addViewDef(inStructure));
  14280. }
  14281. this.cellCount = this.cells.length;
  14282. this.grid.setupHeaderMenu();
  14283. }
  14284. });
  14285. });
  14286. },
  14287. 'dijit/layout/_ContentPaneResizeMixin':function(){
  14288. define("dijit/layout/_ContentPaneResizeMixin", [
  14289. "dojo/_base/array", // array.filter array.forEach
  14290. "dojo/_base/declare", // declare
  14291. "dojo/dom-attr", // domAttr.has
  14292. "dojo/dom-class", // domClass.contains domClass.toggle
  14293. "dojo/dom-geometry",// domGeometry.contentBox domGeometry.marginBox
  14294. "dojo/_base/lang", // lang.mixin
  14295. "dojo/query", // query
  14296. "dojo/_base/sniff", // has("ie")
  14297. "dojo/_base/window", // win.global
  14298. "../registry", // registry.byId
  14299. "./utils", // marginBox2contextBox
  14300. "../_Contained"
  14301. ], function(array, declare, domAttr, domClass, domGeometry, lang, query, has, win,
  14302. registry, layoutUtils, _Contained){
  14303. /*=====
  14304. var _Contained = dijit._Contained;
  14305. =====*/
  14306. // module:
  14307. // dijit/layout/_ContentPaneResizeMixin
  14308. // summary:
  14309. // Resize() functionality of ContentPane. If there's a single layout widget
  14310. // child then it will call resize() with the same dimensions as the ContentPane.
  14311. // Otherwise just calls resize on each child.
  14312. return declare("dijit.layout._ContentPaneResizeMixin", null, {
  14313. // summary:
  14314. // Resize() functionality of ContentPane. If there's a single layout widget
  14315. // child then it will call resize() with the same dimensions as the ContentPane.
  14316. // Otherwise just calls resize on each child.
  14317. //
  14318. // Also implements basic startup() functionality, where starting the parent
  14319. // will start the children
  14320. // doLayout: Boolean
  14321. // - false - don't adjust size of children
  14322. // - true - if there is a single visible child widget, set it's size to
  14323. // however big the ContentPane is
  14324. doLayout: true,
  14325. // isLayoutContainer: [protected] Boolean
  14326. // Indicates that this widget will call resize() on it's child widgets
  14327. // when they become visible.
  14328. isLayoutContainer: true,
  14329. startup: function(){
  14330. // summary:
  14331. // See `dijit.layout._LayoutWidget.startup` for description.
  14332. // Although ContentPane doesn't extend _LayoutWidget, it does implement
  14333. // the same API.
  14334. if(this._started){ return; }
  14335. var parent = this.getParent();
  14336. this._childOfLayoutWidget = parent && parent.isLayoutContainer;
  14337. // I need to call resize() on my child/children (when I become visible), unless
  14338. // I'm the child of a layout widget in which case my parent will call resize() on me and I'll do it then.
  14339. this._needLayout = !this._childOfLayoutWidget;
  14340. this.inherited(arguments);
  14341. if(this._isShown()){
  14342. this._onShow();
  14343. }
  14344. if(!this._childOfLayoutWidget){
  14345. // If my parent isn't a layout container, since my style *may be* width=height=100%
  14346. // or something similar (either set directly or via a CSS class),
  14347. // monitor when my size changes so that I can re-layout.
  14348. // For browsers where I can't directly monitor when my size changes,
  14349. // monitor when the viewport changes size, which *may* indicate a size change for me.
  14350. this.connect(has("ie") ? this.domNode : win.global, 'onresize', function(){
  14351. // Using function(){} closure to ensure no arguments to resize.
  14352. this._needLayout = !this._childOfLayoutWidget;
  14353. this.resize();
  14354. });
  14355. }
  14356. },
  14357. _checkIfSingleChild: function(){
  14358. // summary:
  14359. // Test if we have exactly one visible widget as a child,
  14360. // and if so assume that we are a container for that widget,
  14361. // and should propagate startup() and resize() calls to it.
  14362. // Skips over things like data stores since they aren't visible.
  14363. var childNodes = query("> *", this.containerNode).filter(function(node){
  14364. return node.tagName !== "SCRIPT"; // or a regexp for hidden elements like script|area|map|etc..
  14365. }),
  14366. childWidgetNodes = childNodes.filter(function(node){
  14367. return domAttr.has(node, "data-dojo-type") || domAttr.has(node, "dojoType") || domAttr.has(node, "widgetId");
  14368. }),
  14369. candidateWidgets = array.filter(childWidgetNodes.map(registry.byNode), function(widget){
  14370. return widget && widget.domNode && widget.resize;
  14371. });
  14372. if(
  14373. // all child nodes are widgets
  14374. childNodes.length == childWidgetNodes.length &&
  14375. // all but one are invisible (like dojo.data)
  14376. candidateWidgets.length == 1
  14377. ){
  14378. this._singleChild = candidateWidgets[0];
  14379. }else{
  14380. delete this._singleChild;
  14381. }
  14382. // So we can set overflow: hidden to avoid a safari bug w/scrollbars showing up (#9449)
  14383. domClass.toggle(this.containerNode, this.baseClass + "SingleChild", !!this._singleChild);
  14384. },
  14385. resize: function(changeSize, resultSize){
  14386. // summary:
  14387. // See `dijit.layout._LayoutWidget.resize` for description.
  14388. // Although ContentPane doesn't extend _LayoutWidget, it does implement
  14389. // the same API.
  14390. // For the TabContainer --> BorderContainer --> ContentPane case, _onShow() is
  14391. // never called, so resize() is our trigger to do the initial href download (see [20099]).
  14392. // However, don't load href for closed TitlePanes.
  14393. if(!this._wasShown && this.open !== false){
  14394. this._onShow();
  14395. }
  14396. this._resizeCalled = true;
  14397. this._scheduleLayout(changeSize, resultSize);
  14398. },
  14399. _scheduleLayout: function(changeSize, resultSize){
  14400. // summary:
  14401. // Resize myself, and call resize() on each of my child layout widgets, either now
  14402. // (if I'm currently visible) or when I become visible
  14403. if(this._isShown()){
  14404. this._layout(changeSize, resultSize);
  14405. }else{
  14406. this._needLayout = true;
  14407. this._changeSize = changeSize;
  14408. this._resultSize = resultSize;
  14409. }
  14410. },
  14411. _layout: function(changeSize, resultSize){
  14412. // summary:
  14413. // Resize myself according to optional changeSize/resultSize parameters, like a layout widget.
  14414. // Also, since I am a Container widget, each of my children expects me to
  14415. // call resize() or layout() on them.
  14416. //
  14417. // Should be called on initialization and also whenever we get new content
  14418. // (from an href, or from set('content', ...))... but deferred until
  14419. // the ContentPane is visible
  14420. // Set margin box size, unless it wasn't specified, in which case use current size.
  14421. if(changeSize){
  14422. domGeometry.setMarginBox(this.domNode, changeSize);
  14423. }
  14424. // Compute content box size of containerNode in case we [later] need to size our single child.
  14425. var cn = this.containerNode;
  14426. if(cn === this.domNode){
  14427. // If changeSize or resultSize was passed to this method and this.containerNode ==
  14428. // this.domNode then we can compute the content-box size without querying the node,
  14429. // which is more reliable (similar to LayoutWidget.resize) (see for example #9449).
  14430. var mb = resultSize || {};
  14431. lang.mixin(mb, changeSize || {}); // changeSize overrides resultSize
  14432. if(!("h" in mb) || !("w" in mb)){
  14433. mb = lang.mixin(domGeometry.getMarginBox(cn), mb); // just use domGeometry.setMarginBox() to fill in missing values
  14434. }
  14435. this._contentBox = layoutUtils.marginBox2contentBox(cn, mb);
  14436. }else{
  14437. this._contentBox = domGeometry.getContentBox(cn);
  14438. }
  14439. this._layoutChildren();
  14440. delete this._needLayout;
  14441. },
  14442. _layoutChildren: function(){
  14443. // Call _checkIfSingleChild() again in case app has manually mucked w/the content
  14444. // of the ContentPane (rather than changing it through the set("content", ...) API.
  14445. if(this.doLayout){
  14446. this._checkIfSingleChild();
  14447. }
  14448. if(this._singleChild && this._singleChild.resize){
  14449. var cb = this._contentBox || domGeometry.getContentBox(this.containerNode);
  14450. // note: if widget has padding this._contentBox will have l and t set,
  14451. // but don't pass them to resize() or it will doubly-offset the child
  14452. this._singleChild.resize({w: cb.w, h: cb.h});
  14453. }else{
  14454. // All my child widgets are independently sized (rather than matching my size),
  14455. // but I still need to call resize() on each child to make it layout.
  14456. array.forEach(this.getChildren(), function(widget){
  14457. if(widget.resize){
  14458. widget.resize();
  14459. }
  14460. });
  14461. }
  14462. },
  14463. _isShown: function(){
  14464. // summary:
  14465. // Returns true if the content is currently shown.
  14466. // description:
  14467. // If I am a child of a layout widget then it actually returns true if I've ever been visible,
  14468. // not whether I'm currently visible, since that's much faster than tracing up the DOM/widget
  14469. // tree every call, and at least solves the performance problem on page load by deferring loading
  14470. // hidden ContentPanes until they are first shown
  14471. if(this._childOfLayoutWidget){
  14472. // If we are TitlePane, etc - we return that only *IF* we've been resized
  14473. if(this._resizeCalled && "open" in this){
  14474. return this.open;
  14475. }
  14476. return this._resizeCalled;
  14477. }else if("open" in this){
  14478. return this.open; // for TitlePane, etc.
  14479. }else{
  14480. var node = this.domNode, parent = this.domNode.parentNode;
  14481. return (node.style.display != 'none') && (node.style.visibility != 'hidden') && !domClass.contains(node, "dijitHidden") &&
  14482. parent && parent.style && (parent.style.display != 'none');
  14483. }
  14484. },
  14485. _onShow: function(){
  14486. // summary:
  14487. // Called when the ContentPane is made visible
  14488. // description:
  14489. // For a plain ContentPane, this is called on initialization, from startup().
  14490. // If the ContentPane is a hidden pane of a TabContainer etc., then it's
  14491. // called whenever the pane is made visible.
  14492. //
  14493. // Does layout/resize of child widget(s)
  14494. if(this._needLayout){
  14495. // If a layout has been scheduled for when we become visible, do it now
  14496. this._layout(this._changeSize, this._resultSize);
  14497. }
  14498. this.inherited(arguments);
  14499. // Need to keep track of whether ContentPane has been shown (which is different than
  14500. // whether or not it's currently visible).
  14501. this._wasShown = true;
  14502. }
  14503. });
  14504. });
  14505. },
  14506. 'dijit/form/RangeBoundTextBox':function(){
  14507. define("dijit/form/RangeBoundTextBox", [
  14508. "dojo/_base/declare", // declare
  14509. "dojo/i18n", // i18n.getLocalization
  14510. "./MappedTextBox"
  14511. ], function(declare, i18n, MappedTextBox){
  14512. /*=====
  14513. var MappedTextBox = dijit.form.MappedTextBox;
  14514. =====*/
  14515. // module:
  14516. // dijit/form/RangeBoundTextBox
  14517. // summary:
  14518. // Base class for textbox form widgets which defines a range of valid values.
  14519. /*=====
  14520. dijit.form.RangeBoundTextBox.__Constraints = function(){
  14521. // min: Number
  14522. // Minimum signed value. Default is -Infinity
  14523. // max: Number
  14524. // Maximum signed value. Default is +Infinity
  14525. this.min = min;
  14526. this.max = max;
  14527. }
  14528. =====*/
  14529. return declare("dijit.form.RangeBoundTextBox", MappedTextBox, {
  14530. // summary:
  14531. // Base class for textbox form widgets which defines a range of valid values.
  14532. // rangeMessage: String
  14533. // The message to display if value is out-of-range
  14534. rangeMessage: "",
  14535. /*=====
  14536. // constraints: dijit.form.RangeBoundTextBox.__Constraints
  14537. constraints: {},
  14538. ======*/
  14539. rangeCheck: function(/*Number*/ primitive, /*dijit.form.RangeBoundTextBox.__Constraints*/ constraints){
  14540. // summary:
  14541. // Overridable function used to validate the range of the numeric input value.
  14542. // tags:
  14543. // protected
  14544. return ("min" in constraints? (this.compare(primitive,constraints.min) >= 0) : true) &&
  14545. ("max" in constraints? (this.compare(primitive,constraints.max) <= 0) : true); // Boolean
  14546. },
  14547. isInRange: function(/*Boolean*/ /*===== isFocused =====*/){
  14548. // summary:
  14549. // Tests if the value is in the min/max range specified in constraints
  14550. // tags:
  14551. // protected
  14552. return this.rangeCheck(this.get('value'), this.constraints);
  14553. },
  14554. _isDefinitelyOutOfRange: function(){
  14555. // summary:
  14556. // Returns true if the value is out of range and will remain
  14557. // out of range even if the user types more characters
  14558. var val = this.get('value');
  14559. var isTooLittle = false;
  14560. var isTooMuch = false;
  14561. if("min" in this.constraints){
  14562. var min = this.constraints.min;
  14563. min = this.compare(val, ((typeof min == "number") && min >= 0 && val !=0) ? 0 : min);
  14564. isTooLittle = (typeof min == "number") && min < 0;
  14565. }
  14566. if("max" in this.constraints){
  14567. var max = this.constraints.max;
  14568. max = this.compare(val, ((typeof max != "number") || max > 0) ? max : 0);
  14569. isTooMuch = (typeof max == "number") && max > 0;
  14570. }
  14571. return isTooLittle || isTooMuch;
  14572. },
  14573. _isValidSubset: function(){
  14574. // summary:
  14575. // Overrides `dijit.form.ValidationTextBox._isValidSubset`.
  14576. // Returns true if the input is syntactically valid, and either within
  14577. // range or could be made in range by more typing.
  14578. return this.inherited(arguments) && !this._isDefinitelyOutOfRange();
  14579. },
  14580. isValid: function(/*Boolean*/ isFocused){
  14581. // Overrides dijit.form.ValidationTextBox.isValid to check that the value is also in range.
  14582. return this.inherited(arguments) &&
  14583. ((this._isEmpty(this.textbox.value) && !this.required) || this.isInRange(isFocused)); // Boolean
  14584. },
  14585. getErrorMessage: function(/*Boolean*/ isFocused){
  14586. // Overrides dijit.form.ValidationTextBox.getErrorMessage to print "out of range" message if appropriate
  14587. var v = this.get('value');
  14588. if(v !== null && v !== '' && v !== undefined && (typeof v != "number" || !isNaN(v)) && !this.isInRange(isFocused)){ // don't check isInRange w/o a real value
  14589. return this.rangeMessage; // String
  14590. }
  14591. return this.inherited(arguments);
  14592. },
  14593. postMixInProperties: function(){
  14594. this.inherited(arguments);
  14595. if(!this.rangeMessage){
  14596. this.messages = i18n.getLocalization("dijit.form", "validate", this.lang);
  14597. this.rangeMessage = this.messages.rangeMessage;
  14598. }
  14599. },
  14600. _setConstraintsAttr: function(/*Object*/ constraints){
  14601. this.inherited(arguments);
  14602. if(this.focusNode){ // not set when called from postMixInProperties
  14603. if(this.constraints.min !== undefined){
  14604. this.focusNode.setAttribute("aria-valuemin", this.constraints.min);
  14605. }else{
  14606. this.focusNode.removeAttribute("aria-valuemin");
  14607. }
  14608. if(this.constraints.max !== undefined){
  14609. this.focusNode.setAttribute("aria-valuemax", this.constraints.max);
  14610. }else{
  14611. this.focusNode.removeAttribute("aria-valuemax");
  14612. }
  14613. }
  14614. },
  14615. _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange){
  14616. // summary:
  14617. // Hook so set('value', ...) works.
  14618. this.focusNode.setAttribute("aria-valuenow", value);
  14619. this.inherited(arguments);
  14620. },
  14621. applyTextDir: function(/*===== element, text =====*/){
  14622. // summary:
  14623. // The function overridden in the _BidiSupport module,
  14624. // originally used for setting element.dir according to this.textDir.
  14625. // In this case does nothing.
  14626. // element: Object
  14627. // text: String
  14628. // tags:
  14629. // protected.
  14630. }
  14631. });
  14632. });
  14633. },
  14634. 'dijit/_editor/RichText':function(){
  14635. define("dijit/_editor/RichText", [
  14636. "dojo/_base/array", // array.forEach array.indexOf array.some
  14637. "dojo/_base/config", // config
  14638. "dojo/_base/declare", // declare
  14639. "dojo/_base/Deferred", // Deferred
  14640. "dojo/dom", // dom.byId
  14641. "dojo/dom-attr", // domAttr.set or get
  14642. "dojo/dom-class", // domClass.add domClass.remove
  14643. "dojo/dom-construct", // domConstruct.create domConstruct.destroy domConstruct.place
  14644. "dojo/dom-geometry", // domGeometry.getMarginBox domGeometry.position
  14645. "dojo/dom-style", // domStyle.getComputedStyle domStyle.set
  14646. "dojo/_base/event", // event.stop
  14647. "dojo/_base/kernel", // kernel.deprecated
  14648. "dojo/keys", // keys.BACKSPACE keys.TAB
  14649. "dojo/_base/lang", // lang.clone lang.hitch lang.isArray lang.isFunction lang.isString lang.trim
  14650. "dojo/on", // on()
  14651. "dojo/query", // query
  14652. "dojo/ready", // ready
  14653. "dojo/_base/sniff", // has("ie") has("mozilla") has("opera") has("safari") has("webkit")
  14654. "dojo/topic", // topic.publish() (publish)
  14655. "dojo/_base/unload", // unload
  14656. "dojo/_base/url", // url
  14657. "dojo/_base/window", // win.body win.doc.body.focus win.doc.createElement win.global.location win.withGlobal
  14658. "../_Widget",
  14659. "../_CssStateMixin",
  14660. "./selection",
  14661. "./range",
  14662. "./html",
  14663. "../focus",
  14664. ".." // dijit._scopeName
  14665. ], function(array, config, declare, Deferred, dom, domAttr, domClass, domConstruct, domGeometry, domStyle,
  14666. event, kernel, keys, lang, on, query, ready, has, topic, unload, _Url, win,
  14667. _Widget, _CssStateMixin, selectionapi, rangeapi, htmlapi, focus, dijit){
  14668. /*=====
  14669. var _Widget = dijit._Widget;
  14670. var _CssStateMixin = dijit._CssStateMixin;
  14671. =====*/
  14672. // module:
  14673. // dijit/_editor/RichText
  14674. // summary:
  14675. // dijit._editor.RichText is the core of dijit.Editor, which provides basic
  14676. // WYSIWYG editing features.
  14677. // if you want to allow for rich text saving with back/forward actions, you must add a text area to your page with
  14678. // the id==dijit._scopeName + "._editor.RichText.value" (typically "dijit._editor.RichText.value). For example,
  14679. // something like this will work:
  14680. //
  14681. // <textarea id="dijit._editor.RichText.value" style="display:none;position:absolute;top:-100px;left:-100px;height:3px;width:3px;overflow:hidden;"></textarea>
  14682. //
  14683. var RichText = declare("dijit._editor.RichText", [_Widget, _CssStateMixin], {
  14684. // summary:
  14685. // dijit._editor.RichText is the core of dijit.Editor, which provides basic
  14686. // WYSIWYG editing features.
  14687. //
  14688. // description:
  14689. // dijit._editor.RichText is the core of dijit.Editor, which provides basic
  14690. // WYSIWYG editing features. It also encapsulates the differences
  14691. // of different js engines for various browsers. Do not use this widget
  14692. // with an HTML &lt;TEXTAREA&gt; tag, since the browser unescapes XML escape characters,
  14693. // like &lt;. This can have unexpected behavior and lead to security issues
  14694. // such as scripting attacks.
  14695. //
  14696. // tags:
  14697. // private
  14698. constructor: function(params){
  14699. // contentPreFilters: Function(String)[]
  14700. // Pre content filter function register array.
  14701. // these filters will be executed before the actual
  14702. // editing area gets the html content.
  14703. this.contentPreFilters = [];
  14704. // contentPostFilters: Function(String)[]
  14705. // post content filter function register array.
  14706. // These will be used on the resulting html
  14707. // from contentDomPostFilters. The resulting
  14708. // content is the final html (returned by getValue()).
  14709. this.contentPostFilters = [];
  14710. // contentDomPreFilters: Function(DomNode)[]
  14711. // Pre content dom filter function register array.
  14712. // These filters are applied after the result from
  14713. // contentPreFilters are set to the editing area.
  14714. this.contentDomPreFilters = [];
  14715. // contentDomPostFilters: Function(DomNode)[]
  14716. // Post content dom filter function register array.
  14717. // These filters are executed on the editing area dom.
  14718. // The result from these will be passed to contentPostFilters.
  14719. this.contentDomPostFilters = [];
  14720. // editingAreaStyleSheets: dojo._URL[]
  14721. // array to store all the stylesheets applied to the editing area
  14722. this.editingAreaStyleSheets = [];
  14723. // Make a copy of this.events before we start writing into it, otherwise we
  14724. // will modify the prototype which leads to bad things on pages w/multiple editors
  14725. this.events = [].concat(this.events);
  14726. this._keyHandlers = {};
  14727. if(params && lang.isString(params.value)){
  14728. this.value = params.value;
  14729. }
  14730. this.onLoadDeferred = new Deferred();
  14731. },
  14732. baseClass: "dijitEditor",
  14733. // inheritWidth: Boolean
  14734. // whether to inherit the parent's width or simply use 100%
  14735. inheritWidth: false,
  14736. // focusOnLoad: [deprecated] Boolean
  14737. // Focus into this widget when the page is loaded
  14738. focusOnLoad: false,
  14739. // name: String?
  14740. // Specifies the name of a (hidden) <textarea> node on the page that's used to save
  14741. // the editor content on page leave. Used to restore editor contents after navigating
  14742. // to a new page and then hitting the back button.
  14743. name: "",
  14744. // styleSheets: [const] String
  14745. // semicolon (";") separated list of css files for the editing area
  14746. styleSheets: "",
  14747. // height: String
  14748. // Set height to fix the editor at a specific height, with scrolling.
  14749. // By default, this is 300px. If you want to have the editor always
  14750. // resizes to accommodate the content, use AlwaysShowToolbar plugin
  14751. // and set height="". If this editor is used within a layout widget,
  14752. // set height="100%".
  14753. height: "300px",
  14754. // minHeight: String
  14755. // The minimum height that the editor should have.
  14756. minHeight: "1em",
  14757. // isClosed: [private] Boolean
  14758. isClosed: true,
  14759. // isLoaded: [private] Boolean
  14760. isLoaded: false,
  14761. // _SEPARATOR: [private] String
  14762. // Used to concat contents from multiple editors into a single string,
  14763. // so they can be saved into a single <textarea> node. See "name" attribute.
  14764. _SEPARATOR: "@@**%%__RICHTEXTBOUNDRY__%%**@@",
  14765. // _NAME_CONTENT_SEP: [private] String
  14766. // USed to separate name from content. Just a colon isn't safe.
  14767. _NAME_CONTENT_SEP: "@@**%%:%%**@@",
  14768. // onLoadDeferred: [readonly] dojo.Deferred
  14769. // Deferred which is fired when the editor finishes loading.
  14770. // Call myEditor.onLoadDeferred.then(callback) it to be informed
  14771. // when the rich-text area initialization is finalized.
  14772. onLoadDeferred: null,
  14773. // isTabIndent: Boolean
  14774. // Make tab key and shift-tab indent and outdent rather than navigating.
  14775. // Caution: sing this makes web pages inaccessible to users unable to use a mouse.
  14776. isTabIndent: false,
  14777. // disableSpellCheck: [const] Boolean
  14778. // When true, disables the browser's native spell checking, if supported.
  14779. // Works only in Firefox.
  14780. disableSpellCheck: false,
  14781. postCreate: function(){
  14782. if("textarea" === this.domNode.tagName.toLowerCase()){
  14783. console.warn("RichText should not be used with the TEXTAREA tag. See dijit._editor.RichText docs.");
  14784. }
  14785. // Push in the builtin filters now, making them the first executed, but not over-riding anything
  14786. // users passed in. See: #6062
  14787. this.contentPreFilters = [lang.hitch(this, "_preFixUrlAttributes")].concat(this.contentPreFilters);
  14788. if(has("mozilla")){
  14789. this.contentPreFilters = [this._normalizeFontStyle].concat(this.contentPreFilters);
  14790. this.contentPostFilters = [this._removeMozBogus].concat(this.contentPostFilters);
  14791. }
  14792. if(has("webkit")){
  14793. // Try to clean up WebKit bogus artifacts. The inserted classes
  14794. // made by WebKit sometimes messes things up.
  14795. this.contentPreFilters = [this._removeWebkitBogus].concat(this.contentPreFilters);
  14796. this.contentPostFilters = [this._removeWebkitBogus].concat(this.contentPostFilters);
  14797. }
  14798. if(has("ie")){
  14799. // IE generates <strong> and <em> but we want to normalize to <b> and <i>
  14800. this.contentPostFilters = [this._normalizeFontStyle].concat(this.contentPostFilters);
  14801. this.contentDomPostFilters = [lang.hitch(this, this._stripBreakerNodes)].concat(this.contentDomPostFilters);
  14802. }
  14803. this.inherited(arguments);
  14804. topic.publish(dijit._scopeName + "._editor.RichText::init", this);
  14805. this.open();
  14806. this.setupDefaultShortcuts();
  14807. },
  14808. setupDefaultShortcuts: function(){
  14809. // summary:
  14810. // Add some default key handlers
  14811. // description:
  14812. // Overwrite this to setup your own handlers. The default
  14813. // implementation does not use Editor commands, but directly
  14814. // executes the builtin commands within the underlying browser
  14815. // support.
  14816. // tags:
  14817. // protected
  14818. var exec = lang.hitch(this, function(cmd, arg){
  14819. return function(){
  14820. return !this.execCommand(cmd,arg);
  14821. };
  14822. });
  14823. var ctrlKeyHandlers = {
  14824. b: exec("bold"),
  14825. i: exec("italic"),
  14826. u: exec("underline"),
  14827. a: exec("selectall"),
  14828. s: function(){ this.save(true); },
  14829. m: function(){ this.isTabIndent = !this.isTabIndent; },
  14830. "1": exec("formatblock", "h1"),
  14831. "2": exec("formatblock", "h2"),
  14832. "3": exec("formatblock", "h3"),
  14833. "4": exec("formatblock", "h4"),
  14834. "\\": exec("insertunorderedlist")
  14835. };
  14836. if(!has("ie")){
  14837. ctrlKeyHandlers.Z = exec("redo"); //FIXME: undo?
  14838. }
  14839. var key;
  14840. for(key in ctrlKeyHandlers){
  14841. this.addKeyHandler(key, true, false, ctrlKeyHandlers[key]);
  14842. }
  14843. },
  14844. // events: [private] String[]
  14845. // events which should be connected to the underlying editing area
  14846. events: ["onKeyPress", "onKeyDown", "onKeyUp"], // onClick handled specially
  14847. // captureEvents: [deprecated] String[]
  14848. // Events which should be connected to the underlying editing
  14849. // area, events in this array will be addListener with
  14850. // capture=true.
  14851. // TODO: looking at the code I don't see any distinction between events and captureEvents,
  14852. // so get rid of this for 2.0 if not sooner
  14853. captureEvents: [],
  14854. _editorCommandsLocalized: false,
  14855. _localizeEditorCommands: function(){
  14856. // summary:
  14857. // When IE is running in a non-English locale, the API actually changes,
  14858. // so that we have to say (for example) danraku instead of p (for paragraph).
  14859. // Handle that here.
  14860. // tags:
  14861. // private
  14862. if(RichText._editorCommandsLocalized){
  14863. // Use the already generate cache of mappings.
  14864. this._local2NativeFormatNames = RichText._local2NativeFormatNames;
  14865. this._native2LocalFormatNames = RichText._native2LocalFormatNames;
  14866. return;
  14867. }
  14868. RichText._editorCommandsLocalized = true;
  14869. RichText._local2NativeFormatNames = {};
  14870. RichText._native2LocalFormatNames = {};
  14871. this._local2NativeFormatNames = RichText._local2NativeFormatNames;
  14872. this._native2LocalFormatNames = RichText._native2LocalFormatNames;
  14873. //in IE, names for blockformat is locale dependent, so we cache the values here
  14874. //put p after div, so if IE returns Normal, we show it as paragraph
  14875. //We can distinguish p and div if IE returns Normal, however, in order to detect that,
  14876. //we have to call this.document.selection.createRange().parentElement() or such, which
  14877. //could slow things down. Leave it as it is for now
  14878. var formats = ['div', 'p', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'ul', 'address'];
  14879. var localhtml = "", format, i=0;
  14880. while((format=formats[i++])){
  14881. //append a <br> after each element to separate the elements more reliably
  14882. if(format.charAt(1) !== 'l'){
  14883. localhtml += "<"+format+"><span>content</span></"+format+"><br/>";
  14884. }else{
  14885. localhtml += "<"+format+"><li>content</li></"+format+"><br/>";
  14886. }
  14887. }
  14888. // queryCommandValue returns empty if we hide editNode, so move it out of screen temporary
  14889. // Also, IE9 does weird stuff unless we do it inside the editor iframe.
  14890. var style = { position: "absolute", top: "0px", zIndex: 10, opacity: 0.01 };
  14891. var div = domConstruct.create('div', {style: style, innerHTML: localhtml});
  14892. win.body().appendChild(div);
  14893. // IE9 has a timing issue with doing this right after setting
  14894. // the inner HTML, so put a delay in.
  14895. var inject = lang.hitch(this, function(){
  14896. var node = div.firstChild;
  14897. while(node){
  14898. try{
  14899. selectionapi.selectElement(node.firstChild);
  14900. var nativename = node.tagName.toLowerCase();
  14901. this._local2NativeFormatNames[nativename] = document.queryCommandValue("formatblock");
  14902. this._native2LocalFormatNames[this._local2NativeFormatNames[nativename]] = nativename;
  14903. node = node.nextSibling.nextSibling;
  14904. //console.log("Mapped: ", nativename, " to: ", this._local2NativeFormatNames[nativename]);
  14905. }catch(e){ /*Sqelch the occasional IE9 error */ }
  14906. }
  14907. div.parentNode.removeChild(div);
  14908. div.innerHTML = "";
  14909. });
  14910. setTimeout(inject, 0);
  14911. },
  14912. open: function(/*DomNode?*/ element){
  14913. // summary:
  14914. // Transforms the node referenced in this.domNode into a rich text editing
  14915. // node.
  14916. // description:
  14917. // Sets up the editing area asynchronously. This will result in
  14918. // the creation and replacement with an iframe.
  14919. // tags:
  14920. // private
  14921. if(!this.onLoadDeferred || this.onLoadDeferred.fired >= 0){
  14922. this.onLoadDeferred = new Deferred();
  14923. }
  14924. if(!this.isClosed){ this.close(); }
  14925. topic.publish(dijit._scopeName + "._editor.RichText::open", this);
  14926. if(arguments.length === 1 && element.nodeName){ // else unchanged
  14927. this.domNode = element;
  14928. }
  14929. var dn = this.domNode;
  14930. // "html" will hold the innerHTML of the srcNodeRef and will be used to
  14931. // initialize the editor.
  14932. var html;
  14933. if(lang.isString(this.value)){
  14934. // Allow setting the editor content programmatically instead of
  14935. // relying on the initial content being contained within the target
  14936. // domNode.
  14937. html = this.value;
  14938. delete this.value;
  14939. dn.innerHTML = "";
  14940. }else if(dn.nodeName && dn.nodeName.toLowerCase() == "textarea"){
  14941. // if we were created from a textarea, then we need to create a
  14942. // new editing harness node.
  14943. var ta = (this.textarea = dn);
  14944. this.name = ta.name;
  14945. html = ta.value;
  14946. dn = this.domNode = win.doc.createElement("div");
  14947. dn.setAttribute('widgetId', this.id);
  14948. ta.removeAttribute('widgetId');
  14949. dn.cssText = ta.cssText;
  14950. dn.className += " " + ta.className;
  14951. domConstruct.place(dn, ta, "before");
  14952. var tmpFunc = lang.hitch(this, function(){
  14953. //some browsers refuse to submit display=none textarea, so
  14954. //move the textarea off screen instead
  14955. domStyle.set(ta, {
  14956. display: "block",
  14957. position: "absolute",
  14958. top: "-1000px"
  14959. });
  14960. if(has("ie")){ //nasty IE bug: abnormal formatting if overflow is not hidden
  14961. var s = ta.style;
  14962. this.__overflow = s.overflow;
  14963. s.overflow = "hidden";
  14964. }
  14965. });
  14966. if(has("ie")){
  14967. setTimeout(tmpFunc, 10);
  14968. }else{
  14969. tmpFunc();
  14970. }
  14971. if(ta.form){
  14972. var resetValue = ta.value;
  14973. this.reset = function(){
  14974. var current = this.getValue();
  14975. if(current !== resetValue){
  14976. this.replaceValue(resetValue);
  14977. }
  14978. };
  14979. on(ta.form, "submit", lang.hitch(this, function(){
  14980. // Copy value to the <textarea> so it gets submitted along with form.
  14981. // FIXME: should we be calling close() here instead?
  14982. domAttr.set(ta, 'disabled', this.disabled); // don't submit the value if disabled
  14983. ta.value = this.getValue();
  14984. }));
  14985. }
  14986. }else{
  14987. html = htmlapi.getChildrenHtml(dn);
  14988. dn.innerHTML = "";
  14989. }
  14990. this.value = html;
  14991. // If we're a list item we have to put in a blank line to force the
  14992. // bullet to nicely align at the top of text
  14993. if(dn.nodeName && dn.nodeName === "LI"){
  14994. dn.innerHTML = " <br>";
  14995. }
  14996. // Construct the editor div structure.
  14997. this.header = dn.ownerDocument.createElement("div");
  14998. dn.appendChild(this.header);
  14999. this.editingArea = dn.ownerDocument.createElement("div");
  15000. dn.appendChild(this.editingArea);
  15001. this.footer = dn.ownerDocument.createElement("div");
  15002. dn.appendChild(this.footer);
  15003. if(!this.name){
  15004. this.name = this.id + "_AUTOGEN";
  15005. }
  15006. // User has pressed back/forward button so we lost the text in the editor, but it's saved
  15007. // in a hidden <textarea> (which contains the data for all the editors on this page),
  15008. // so get editor value from there
  15009. if(this.name !== "" && (!config["useXDomain"] || config["allowXdRichTextSave"])){
  15010. var saveTextarea = dom.byId(dijit._scopeName + "._editor.RichText.value");
  15011. if(saveTextarea && saveTextarea.value !== ""){
  15012. var datas = saveTextarea.value.split(this._SEPARATOR), i=0, dat;
  15013. while((dat=datas[i++])){
  15014. var data = dat.split(this._NAME_CONTENT_SEP);
  15015. if(data[0] === this.name){
  15016. html = data[1];
  15017. datas = datas.splice(i, 1);
  15018. saveTextarea.value = datas.join(this._SEPARATOR);
  15019. break;
  15020. }
  15021. }
  15022. }
  15023. if(!RichText._globalSaveHandler){
  15024. RichText._globalSaveHandler = {};
  15025. unload.addOnUnload(function(){
  15026. var id;
  15027. for(id in RichText._globalSaveHandler){
  15028. var f = RichText._globalSaveHandler[id];
  15029. if(lang.isFunction(f)){
  15030. f();
  15031. }
  15032. }
  15033. });
  15034. }
  15035. RichText._globalSaveHandler[this.id] = lang.hitch(this, "_saveContent");
  15036. }
  15037. this.isClosed = false;
  15038. var ifr = (this.editorObject = this.iframe = win.doc.createElement('iframe'));
  15039. ifr.id = this.id+"_iframe";
  15040. this._iframeSrc = this._getIframeDocTxt();
  15041. ifr.style.border = "none";
  15042. ifr.style.width = "100%";
  15043. if(this._layoutMode){
  15044. // iframe should be 100% height, thus getting it's height from surrounding
  15045. // <div> (which has the correct height set by Editor)
  15046. ifr.style.height = "100%";
  15047. }else{
  15048. if(has("ie") >= 7){
  15049. if(this.height){
  15050. ifr.style.height = this.height;
  15051. }
  15052. if(this.minHeight){
  15053. ifr.style.minHeight = this.minHeight;
  15054. }
  15055. }else{
  15056. ifr.style.height = this.height ? this.height : this.minHeight;
  15057. }
  15058. }
  15059. ifr.frameBorder = 0;
  15060. ifr._loadFunc = lang.hitch( this, function(w){
  15061. this.window = w;
  15062. this.document = this.window.document;
  15063. if(has("ie")){
  15064. this._localizeEditorCommands();
  15065. }
  15066. // Do final setup and set initial contents of editor
  15067. this.onLoad(html);
  15068. });
  15069. // Set the iframe's initial (blank) content.
  15070. var iframeSrcRef = 'parent.' + dijit._scopeName + '.byId("'+this.id+'")._iframeSrc';
  15071. var s = 'javascript:(function(){try{return ' + iframeSrcRef + '}catch(e){document.open();document.domain="' +
  15072. document.domain + '";document.write(' + iframeSrcRef + ');document.close();}})()';
  15073. ifr.setAttribute('src', s);
  15074. this.editingArea.appendChild(ifr);
  15075. if(has("safari") <= 4){
  15076. var src = ifr.getAttribute("src");
  15077. if(!src || src.indexOf("javascript") === -1){
  15078. // Safari 4 and earlier sometimes act oddly
  15079. // So we have to set it again.
  15080. setTimeout(function(){ifr.setAttribute('src', s);},0);
  15081. }
  15082. }
  15083. // TODO: this is a guess at the default line-height, kinda works
  15084. if(dn.nodeName === "LI"){
  15085. dn.lastChild.style.marginTop = "-1.2em";
  15086. }
  15087. domClass.add(this.domNode, this.baseClass);
  15088. },
  15089. //static cache variables shared among all instance of this class
  15090. _local2NativeFormatNames: {},
  15091. _native2LocalFormatNames: {},
  15092. _getIframeDocTxt: function(){
  15093. // summary:
  15094. // Generates the boilerplate text of the document inside the iframe (ie, <html><head>...</head><body/></html>).
  15095. // Editor content (if not blank) should be added afterwards.
  15096. // tags:
  15097. // private
  15098. var _cs = domStyle.getComputedStyle(this.domNode);
  15099. // The contents inside of <body>. The real contents are set later via a call to setValue().
  15100. var html = "";
  15101. var setBodyId = true;
  15102. if(has("ie") || has("webkit") || (!this.height && !has("mozilla"))){
  15103. // In auto-expand mode, need a wrapper div for AlwaysShowToolbar plugin to correctly
  15104. // expand/contract the editor as the content changes.
  15105. html = "<div id='dijitEditorBody'></div>";
  15106. setBodyId = false;
  15107. }else if(has("mozilla")){
  15108. // workaround bug where can't select then delete text (until user types something
  15109. // into the editor)... and/or issue where typing doesn't erase selected text
  15110. this._cursorToStart = true;
  15111. html = "&#160;"; // &nbsp;
  15112. }
  15113. var font = [ _cs.fontWeight, _cs.fontSize, _cs.fontFamily ].join(" ");
  15114. // line height is tricky - applying a units value will mess things up.
  15115. // if we can't get a non-units value, bail out.
  15116. var lineHeight = _cs.lineHeight;
  15117. if(lineHeight.indexOf("px") >= 0){
  15118. lineHeight = parseFloat(lineHeight)/parseFloat(_cs.fontSize);
  15119. // console.debug(lineHeight);
  15120. }else if(lineHeight.indexOf("em")>=0){
  15121. lineHeight = parseFloat(lineHeight);
  15122. }else{
  15123. // If we can't get a non-units value, just default
  15124. // it to the CSS spec default of 'normal'. Seems to
  15125. // work better, esp on IE, than '1.0'
  15126. lineHeight = "normal";
  15127. }
  15128. var userStyle = "";
  15129. var self = this;
  15130. this.style.replace(/(^|;)\s*(line-|font-?)[^;]+/ig, function(match){
  15131. match = match.replace(/^;/ig,"") + ';';
  15132. var s = match.split(":")[0];
  15133. if(s){
  15134. s = lang.trim(s);
  15135. s = s.toLowerCase();
  15136. var i;
  15137. var sC = "";
  15138. for(i = 0; i < s.length; i++){
  15139. var c = s.charAt(i);
  15140. switch(c){
  15141. case "-":
  15142. i++;
  15143. c = s.charAt(i).toUpperCase();
  15144. default:
  15145. sC += c;
  15146. }
  15147. }
  15148. domStyle.set(self.domNode, sC, "");
  15149. }
  15150. userStyle += match + ';';
  15151. });
  15152. // need to find any associated label element and update iframe document title
  15153. var label=query('label[for="'+this.id+'"]');
  15154. return [
  15155. this.isLeftToRight() ? "<html>\n<head>\n" : "<html dir='rtl'>\n<head>\n",
  15156. (has("mozilla") && label.length ? "<title>" + label[0].innerHTML + "</title>\n" : ""),
  15157. "<meta http-equiv='Content-Type' content='text/html'>\n",
  15158. "<style>\n",
  15159. "\tbody,html {\n",
  15160. "\t\tbackground:transparent;\n",
  15161. "\t\tpadding: 1px 0 0 0;\n",
  15162. "\t\tmargin: -1px 0 0 0;\n", // remove extraneous vertical scrollbar on safari and firefox
  15163. // Set the html/body sizing. Webkit always needs this, other browsers
  15164. // only set it when height is defined (not auto-expanding), otherwise
  15165. // scrollers do not appear.
  15166. ((has("webkit"))?"\t\twidth: 100%;\n":""),
  15167. ((has("webkit"))?"\t\theight: 100%;\n":""),
  15168. "\t}\n",
  15169. // TODO: left positioning will cause contents to disappear out of view
  15170. // if it gets too wide for the visible area
  15171. "\tbody{\n",
  15172. "\t\ttop:0px;\n",
  15173. "\t\tleft:0px;\n",
  15174. "\t\tright:0px;\n",
  15175. "\t\tfont:", font, ";\n",
  15176. ((this.height||has("opera")) ? "" : "\t\tposition: fixed;\n"),
  15177. // FIXME: IE 6 won't understand min-height?
  15178. "\t\tmin-height:", this.minHeight, ";\n",
  15179. "\t\tline-height:", lineHeight,";\n",
  15180. "\t}\n",
  15181. "\tp{ margin: 1em 0; }\n",
  15182. // Determine how scrollers should be applied. In autoexpand mode (height = "") no scrollers on y at all.
  15183. // But in fixed height mode we want both x/y scrollers. Also, if it's using wrapping div and in auto-expand
  15184. // (Mainly IE) we need to kill the y scroller on body and html.
  15185. (!setBodyId && !this.height ? "\tbody,html {overflow-y: hidden;}\n" : ""),
  15186. "\t#dijitEditorBody{overflow-x: auto; overflow-y:" + (this.height ? "auto;" : "hidden;") + " outline: 0px;}\n",
  15187. "\tli > ul:-moz-first-node, li > ol:-moz-first-node{ padding-top: 1.2em; }\n",
  15188. // Can't set min-height in IE9, it puts layout on li, which puts move/resize handles.
  15189. (!has("ie") ? "\tli{ min-height:1.2em; }\n" : ""),
  15190. "</style>\n",
  15191. this._applyEditingAreaStyleSheets(),"\n",
  15192. "</head>\n<body ",
  15193. (setBodyId?"id='dijitEditorBody' ":""),
  15194. "onload='frameElement._loadFunc(window,document)' style='"+userStyle+"'>", html, "</body>\n</html>"
  15195. ].join(""); // String
  15196. },
  15197. _applyEditingAreaStyleSheets: function(){
  15198. // summary:
  15199. // apply the specified css files in styleSheets
  15200. // tags:
  15201. // private
  15202. var files = [];
  15203. if(this.styleSheets){
  15204. files = this.styleSheets.split(';');
  15205. this.styleSheets = '';
  15206. }
  15207. //empty this.editingAreaStyleSheets here, as it will be filled in addStyleSheet
  15208. files = files.concat(this.editingAreaStyleSheets);
  15209. this.editingAreaStyleSheets = [];
  15210. var text='', i=0, url;
  15211. while((url=files[i++])){
  15212. var abstring = (new _Url(win.global.location, url)).toString();
  15213. this.editingAreaStyleSheets.push(abstring);
  15214. text += '<link rel="stylesheet" type="text/css" href="'+abstring+'"/>';
  15215. }
  15216. return text;
  15217. },
  15218. addStyleSheet: function(/*dojo._Url*/ uri){
  15219. // summary:
  15220. // add an external stylesheet for the editing area
  15221. // uri:
  15222. // A dojo.uri.Uri pointing to the url of the external css file
  15223. var url=uri.toString();
  15224. //if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe
  15225. if(url.charAt(0) === '.' || (url.charAt(0) !== '/' && !uri.host)){
  15226. url = (new _Url(win.global.location, url)).toString();
  15227. }
  15228. if(array.indexOf(this.editingAreaStyleSheets, url) > -1){
  15229. // console.debug("dijit._editor.RichText.addStyleSheet: Style sheet "+url+" is already applied");
  15230. return;
  15231. }
  15232. this.editingAreaStyleSheets.push(url);
  15233. this.onLoadDeferred.addCallback(lang.hitch(this, function(){
  15234. if(this.document.createStyleSheet){ //IE
  15235. this.document.createStyleSheet(url);
  15236. }else{ //other browser
  15237. var head = this.document.getElementsByTagName("head")[0];
  15238. var stylesheet = this.document.createElement("link");
  15239. stylesheet.rel="stylesheet";
  15240. stylesheet.type="text/css";
  15241. stylesheet.href=url;
  15242. head.appendChild(stylesheet);
  15243. }
  15244. }));
  15245. },
  15246. removeStyleSheet: function(/*dojo._Url*/ uri){
  15247. // summary:
  15248. // remove an external stylesheet for the editing area
  15249. var url=uri.toString();
  15250. //if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe
  15251. if(url.charAt(0) === '.' || (url.charAt(0) !== '/' && !uri.host)){
  15252. url = (new _Url(win.global.location, url)).toString();
  15253. }
  15254. var index = array.indexOf(this.editingAreaStyleSheets, url);
  15255. if(index === -1){
  15256. // console.debug("dijit._editor.RichText.removeStyleSheet: Style sheet "+url+" has not been applied");
  15257. return;
  15258. }
  15259. delete this.editingAreaStyleSheets[index];
  15260. win.withGlobal(this.window,'query', dojo, ['link:[href="'+url+'"]']).orphan();
  15261. },
  15262. // disabled: Boolean
  15263. // The editor is disabled; the text cannot be changed.
  15264. disabled: false,
  15265. _mozSettingProps: {'styleWithCSS':false},
  15266. _setDisabledAttr: function(/*Boolean*/ value){
  15267. value = !!value;
  15268. this._set("disabled", value);
  15269. if(!this.isLoaded){ return; } // this method requires init to be complete
  15270. if(has("ie") || has("webkit") || has("opera")){
  15271. var preventIEfocus = has("ie") && (this.isLoaded || !this.focusOnLoad);
  15272. if(preventIEfocus){ this.editNode.unselectable = "on"; }
  15273. this.editNode.contentEditable = !value;
  15274. if(preventIEfocus){
  15275. var _this = this;
  15276. setTimeout(function(){
  15277. if(_this.editNode){ // guard in case widget destroyed before timeout
  15278. _this.editNode.unselectable = "off";
  15279. }
  15280. }, 0);
  15281. }
  15282. }else{ //moz
  15283. try{
  15284. this.document.designMode=(value?'off':'on');
  15285. }catch(e){ return; } // ! _disabledOK
  15286. if(!value && this._mozSettingProps){
  15287. var ps = this._mozSettingProps;
  15288. var n;
  15289. for(n in ps){
  15290. if(ps.hasOwnProperty(n)){
  15291. try{
  15292. this.document.execCommand(n,false,ps[n]);
  15293. }catch(e2){}
  15294. }
  15295. }
  15296. }
  15297. // this.document.execCommand('contentReadOnly', false, value);
  15298. // if(value){
  15299. // this.blur(); //to remove the blinking caret
  15300. // }
  15301. }
  15302. this._disabledOK = true;
  15303. },
  15304. /* Event handlers
  15305. *****************/
  15306. onLoad: function(/*String*/ html){
  15307. // summary:
  15308. // Handler after the iframe finishes loading.
  15309. // html: String
  15310. // Editor contents should be set to this value
  15311. // tags:
  15312. // protected
  15313. // TODO: rename this to _onLoad, make empty public onLoad() method, deprecate/make protected onLoadDeferred handler?
  15314. if(!this.window.__registeredWindow){
  15315. this.window.__registeredWindow = true;
  15316. this._iframeRegHandle = focus.registerIframe(this.iframe);
  15317. }
  15318. if(!has("ie") && !has("webkit") && (this.height || has("mozilla"))){
  15319. this.editNode=this.document.body;
  15320. }else{
  15321. // there's a wrapper div around the content, see _getIframeDocTxt().
  15322. this.editNode=this.document.body.firstChild;
  15323. var _this = this;
  15324. if(has("ie")){ // #4996 IE wants to focus the BODY tag
  15325. this.tabStop = domConstruct.create('div', { tabIndex: -1 }, this.editingArea);
  15326. this.iframe.onfocus = function(){ _this.editNode.setActive(); };
  15327. }
  15328. }
  15329. this.focusNode = this.editNode; // for InlineEditBox
  15330. var events = this.events.concat(this.captureEvents);
  15331. var ap = this.iframe ? this.document : this.editNode;
  15332. array.forEach(events, function(item){
  15333. this.connect(ap, item.toLowerCase(), item);
  15334. }, this);
  15335. this.connect(ap, "onmouseup", "onClick"); // mouseup in the margin does not generate an onclick event
  15336. if(has("ie")){ // IE contentEditable
  15337. this.connect(this.document, "onmousedown", "_onIEMouseDown"); // #4996 fix focus
  15338. // give the node Layout on IE
  15339. // TODO: this may no longer be needed, since we've reverted IE to using an iframe,
  15340. // not contentEditable. Removing it would also probably remove the need for creating
  15341. // the extra <div> in _getIframeDocTxt()
  15342. this.editNode.style.zoom = 1.0;
  15343. }else{
  15344. this.connect(this.document, "onmousedown", function(){
  15345. // Clear the moveToStart focus, as mouse
  15346. // down will set cursor point. Required to properly
  15347. // work with selection/position driven plugins and clicks in
  15348. // the window. refs: #10678
  15349. delete this._cursorToStart;
  15350. });
  15351. }
  15352. if(has("webkit")){
  15353. //WebKit sometimes doesn't fire right on selections, so the toolbar
  15354. //doesn't update right. Therefore, help it out a bit with an additional
  15355. //listener. A mouse up will typically indicate a display change, so fire this
  15356. //and get the toolbar to adapt. Reference: #9532
  15357. this._webkitListener = this.connect(this.document, "onmouseup", "onDisplayChanged");
  15358. this.connect(this.document, "onmousedown", function(e){
  15359. var t = e.target;
  15360. if(t && (t === this.document.body || t === this.document)){
  15361. // Since WebKit uses the inner DIV, we need to check and set position.
  15362. // See: #12024 as to why the change was made.
  15363. setTimeout(lang.hitch(this, "placeCursorAtEnd"), 0);
  15364. }
  15365. });
  15366. }
  15367. if(has("ie")){
  15368. // Try to make sure 'hidden' elements aren't visible in edit mode (like browsers other than IE
  15369. // do). See #9103
  15370. try{
  15371. this.document.execCommand('RespectVisibilityInDesign', true, null);
  15372. }catch(e){/* squelch */}
  15373. }
  15374. this.isLoaded = true;
  15375. this.set('disabled', this.disabled); // initialize content to editable (or not)
  15376. // Note that setValue() call will only work after isLoaded is set to true (above)
  15377. // Set up a function to allow delaying the setValue until a callback is fired
  15378. // This ensures extensions like dijit.Editor have a way to hold the value set
  15379. // until plugins load (and do things like register filters).
  15380. var setContent = lang.hitch(this, function(){
  15381. this.setValue(html);
  15382. if(this.onLoadDeferred){
  15383. this.onLoadDeferred.callback(true);
  15384. }
  15385. this.onDisplayChanged();
  15386. if(this.focusOnLoad){
  15387. // after the document loads, then set focus after updateInterval expires so that
  15388. // onNormalizedDisplayChanged has run to avoid input caret issues
  15389. ready(lang.hitch(this, function(){ setTimeout(lang.hitch(this, "focus"), this.updateInterval); }));
  15390. }
  15391. // Save off the initial content now
  15392. this.value = this.getValue(true);
  15393. });
  15394. if(this.setValueDeferred){
  15395. this.setValueDeferred.addCallback(setContent);
  15396. }else{
  15397. setContent();
  15398. }
  15399. },
  15400. onKeyDown: function(/* Event */ e){
  15401. // summary:
  15402. // Handler for onkeydown event
  15403. // tags:
  15404. // protected
  15405. // we need this event at the moment to get the events from control keys
  15406. // such as the backspace. It might be possible to add this to Dojo, so that
  15407. // keyPress events can be emulated by the keyDown and keyUp detection.
  15408. if(e.keyCode === keys.TAB && this.isTabIndent ){
  15409. event.stop(e); //prevent tab from moving focus out of editor
  15410. // FIXME: this is a poor-man's indent/outdent. It would be
  15411. // better if it added 4 "&nbsp;" chars in an undoable way.
  15412. // Unfortunately pasteHTML does not prove to be undoable
  15413. if(this.queryCommandEnabled((e.shiftKey ? "outdent" : "indent"))){
  15414. this.execCommand((e.shiftKey ? "outdent" : "indent"));
  15415. }
  15416. }
  15417. if(has("ie")){
  15418. if(e.keyCode == keys.TAB && !this.isTabIndent){
  15419. if(e.shiftKey && !e.ctrlKey && !e.altKey){
  15420. // focus the BODY so the browser will tab away from it instead
  15421. this.iframe.focus();
  15422. }else if(!e.shiftKey && !e.ctrlKey && !e.altKey){
  15423. // focus the BODY so the browser will tab away from it instead
  15424. this.tabStop.focus();
  15425. }
  15426. }else if(e.keyCode === keys.BACKSPACE && this.document.selection.type === "Control"){
  15427. // IE has a bug where if a non-text object is selected in the editor,
  15428. // hitting backspace would act as if the browser's back button was
  15429. // clicked instead of deleting the object. see #1069
  15430. event.stop(e);
  15431. this.execCommand("delete");
  15432. }else if((65 <= e.keyCode && e.keyCode <= 90) ||
  15433. (e.keyCode>=37 && e.keyCode<=40) // FIXME: get this from connect() instead!
  15434. ){ //arrow keys
  15435. e.charCode = e.keyCode;
  15436. this.onKeyPress(e);
  15437. }
  15438. }
  15439. if(has("ff")){
  15440. if(e.keyCode === keys.PAGE_UP || e.keyCode === keys.PAGE_DOWN ){
  15441. if(this.editNode.clientHeight >= this.editNode.scrollHeight){
  15442. // Stop the event to prevent firefox from trapping the cursor when there is no scroll bar.
  15443. e.preventDefault();
  15444. }
  15445. }
  15446. }
  15447. return true;
  15448. },
  15449. onKeyUp: function(/*===== e =====*/){
  15450. // summary:
  15451. // Handler for onkeyup event
  15452. // tags:
  15453. // callback
  15454. },
  15455. setDisabled: function(/*Boolean*/ disabled){
  15456. // summary:
  15457. // Deprecated, use set('disabled', ...) instead.
  15458. // tags:
  15459. // deprecated
  15460. kernel.deprecated('dijit.Editor::setDisabled is deprecated','use dijit.Editor::attr("disabled",boolean) instead', 2.0);
  15461. this.set('disabled',disabled);
  15462. },
  15463. _setValueAttr: function(/*String*/ value){
  15464. // summary:
  15465. // Registers that attr("value", foo) should call setValue(foo)
  15466. this.setValue(value);
  15467. },
  15468. _setDisableSpellCheckAttr: function(/*Boolean*/ disabled){
  15469. if(this.document){
  15470. domAttr.set(this.document.body, "spellcheck", !disabled);
  15471. }else{
  15472. // try again after the editor is finished loading
  15473. this.onLoadDeferred.addCallback(lang.hitch(this, function(){
  15474. domAttr.set(this.document.body, "spellcheck", !disabled);
  15475. }));
  15476. }
  15477. this._set("disableSpellCheck", disabled);
  15478. },
  15479. onKeyPress: function(e){
  15480. // summary:
  15481. // Handle the various key events
  15482. // tags:
  15483. // protected
  15484. var c = (e.keyChar && e.keyChar.toLowerCase()) || e.keyCode,
  15485. handlers = this._keyHandlers[c],
  15486. args = arguments;
  15487. if(handlers && !e.altKey){
  15488. array.some(handlers, function(h){
  15489. // treat meta- same as ctrl-, for benefit of mac users
  15490. if(!(h.shift ^ e.shiftKey) && !(h.ctrl ^ (e.ctrlKey||e.metaKey))){
  15491. if(!h.handler.apply(this, args)){
  15492. e.preventDefault();
  15493. }
  15494. return true;
  15495. }
  15496. }, this);
  15497. }
  15498. // function call after the character has been inserted
  15499. if(!this._onKeyHitch){
  15500. this._onKeyHitch = lang.hitch(this, "onKeyPressed");
  15501. }
  15502. setTimeout(this._onKeyHitch, 1);
  15503. return true;
  15504. },
  15505. addKeyHandler: function(/*String*/ key, /*Boolean*/ ctrl, /*Boolean*/ shift, /*Function*/ handler){
  15506. // summary:
  15507. // Add a handler for a keyboard shortcut
  15508. // description:
  15509. // The key argument should be in lowercase if it is a letter character
  15510. // tags:
  15511. // protected
  15512. if(!lang.isArray(this._keyHandlers[key])){
  15513. this._keyHandlers[key] = [];
  15514. }
  15515. //TODO: would be nice to make this a hash instead of an array for quick lookups
  15516. this._keyHandlers[key].push({
  15517. shift: shift || false,
  15518. ctrl: ctrl || false,
  15519. handler: handler
  15520. });
  15521. },
  15522. onKeyPressed: function(){
  15523. // summary:
  15524. // Handler for after the user has pressed a key, and the display has been updated.
  15525. // (Runs on a timer so that it runs after the display is updated)
  15526. // tags:
  15527. // private
  15528. this.onDisplayChanged(/*e*/); // can't pass in e
  15529. },
  15530. onClick: function(/*Event*/ e){
  15531. // summary:
  15532. // Handler for when the user clicks.
  15533. // tags:
  15534. // private
  15535. // console.info('onClick',this._tryDesignModeOn);
  15536. this.onDisplayChanged(e);
  15537. },
  15538. _onIEMouseDown: function(){
  15539. // summary:
  15540. // IE only to prevent 2 clicks to focus
  15541. // tags:
  15542. // protected
  15543. if(!this.focused && !this.disabled){
  15544. this.focus();
  15545. }
  15546. },
  15547. _onBlur: function(e){
  15548. // summary:
  15549. // Called from focus manager when focus has moved away from this editor
  15550. // tags:
  15551. // protected
  15552. // console.info('_onBlur')
  15553. this.inherited(arguments);
  15554. var newValue = this.getValue(true);
  15555. if(newValue !== this.value){
  15556. this.onChange(newValue);
  15557. }
  15558. this._set("value", newValue);
  15559. },
  15560. _onFocus: function(/*Event*/ e){
  15561. // summary:
  15562. // Called from focus manager when focus has moved into this editor
  15563. // tags:
  15564. // protected
  15565. // console.info('_onFocus')
  15566. if(!this.disabled){
  15567. if(!this._disabledOK){
  15568. this.set('disabled', false);
  15569. }
  15570. this.inherited(arguments);
  15571. }
  15572. },
  15573. // TODO: remove in 2.0
  15574. blur: function(){
  15575. // summary:
  15576. // Remove focus from this instance.
  15577. // tags:
  15578. // deprecated
  15579. if(!has("ie") && this.window.document.documentElement && this.window.document.documentElement.focus){
  15580. this.window.document.documentElement.focus();
  15581. }else if(win.doc.body.focus){
  15582. win.doc.body.focus();
  15583. }
  15584. },
  15585. focus: function(){
  15586. // summary:
  15587. // Move focus to this editor
  15588. if(!this.isLoaded){
  15589. this.focusOnLoad = true;
  15590. return;
  15591. }
  15592. if(this._cursorToStart){
  15593. delete this._cursorToStart;
  15594. if(this.editNode.childNodes){
  15595. this.placeCursorAtStart(); // this calls focus() so return
  15596. return;
  15597. }
  15598. }
  15599. if(!has("ie")){
  15600. focus.focus(this.iframe);
  15601. }else if(this.editNode && this.editNode.focus){
  15602. // editNode may be hidden in display:none div, lets just punt in this case
  15603. //this.editNode.focus(); -> causes IE to scroll always (strict and quirks mode) to the top the Iframe
  15604. // if we fire the event manually and let the browser handle the focusing, the latest
  15605. // cursor position is focused like in FF
  15606. this.iframe.fireEvent('onfocus', document.createEventObject()); // createEventObject only in IE
  15607. // }else{
  15608. // TODO: should we throw here?
  15609. // console.debug("Have no idea how to focus into the editor!");
  15610. }
  15611. },
  15612. // _lastUpdate: 0,
  15613. updateInterval: 200,
  15614. _updateTimer: null,
  15615. onDisplayChanged: function(/*Event*/ /*===== e =====*/){
  15616. // summary:
  15617. // This event will be fired every time the display context
  15618. // changes and the result needs to be reflected in the UI.
  15619. // description:
  15620. // If you don't want to have update too often,
  15621. // onNormalizedDisplayChanged should be used instead
  15622. // tags:
  15623. // private
  15624. // var _t=new Date();
  15625. if(this._updateTimer){
  15626. clearTimeout(this._updateTimer);
  15627. }
  15628. if(!this._updateHandler){
  15629. this._updateHandler = lang.hitch(this,"onNormalizedDisplayChanged");
  15630. }
  15631. this._updateTimer = setTimeout(this._updateHandler, this.updateInterval);
  15632. // Technically this should trigger a call to watch("value", ...) registered handlers,
  15633. // but getValue() is too slow to call on every keystroke so we don't.
  15634. },
  15635. onNormalizedDisplayChanged: function(){
  15636. // summary:
  15637. // This event is fired every updateInterval ms or more
  15638. // description:
  15639. // If something needs to happen immediately after a
  15640. // user change, please use onDisplayChanged instead.
  15641. // tags:
  15642. // private
  15643. delete this._updateTimer;
  15644. },
  15645. onChange: function(/*===== newContent =====*/){
  15646. // summary:
  15647. // This is fired if and only if the editor loses focus and
  15648. // the content is changed.
  15649. },
  15650. _normalizeCommand: function(/*String*/ cmd, /*Anything?*/argument){
  15651. // summary:
  15652. // Used as the advice function to map our
  15653. // normalized set of commands to those supported by the target
  15654. // browser.
  15655. // tags:
  15656. // private
  15657. var command = cmd.toLowerCase();
  15658. if(command === "formatblock"){
  15659. if(has("safari") && argument === undefined){ command = "heading"; }
  15660. }else if(command === "hilitecolor" && !has("mozilla")){
  15661. command = "backcolor";
  15662. }
  15663. return command;
  15664. },
  15665. _qcaCache: {},
  15666. queryCommandAvailable: function(/*String*/ command){
  15667. // summary:
  15668. // Tests whether a command is supported by the host. Clients
  15669. // SHOULD check whether a command is supported before attempting
  15670. // to use it, behaviour for unsupported commands is undefined.
  15671. // command:
  15672. // The command to test for
  15673. // tags:
  15674. // private
  15675. // memoizing version. See _queryCommandAvailable for computing version
  15676. var ca = this._qcaCache[command];
  15677. if(ca !== undefined){ return ca; }
  15678. return (this._qcaCache[command] = this._queryCommandAvailable(command));
  15679. },
  15680. _queryCommandAvailable: function(/*String*/ command){
  15681. // summary:
  15682. // See queryCommandAvailable().
  15683. // tags:
  15684. // private
  15685. var ie = 1;
  15686. var mozilla = 1 << 1;
  15687. var webkit = 1 << 2;
  15688. var opera = 1 << 3;
  15689. function isSupportedBy(browsers){
  15690. return {
  15691. ie: Boolean(browsers & ie),
  15692. mozilla: Boolean(browsers & mozilla),
  15693. webkit: Boolean(browsers & webkit),
  15694. opera: Boolean(browsers & opera)
  15695. };
  15696. }
  15697. var supportedBy = null;
  15698. switch(command.toLowerCase()){
  15699. case "bold": case "italic": case "underline":
  15700. case "subscript": case "superscript":
  15701. case "fontname": case "fontsize":
  15702. case "forecolor": case "hilitecolor":
  15703. case "justifycenter": case "justifyfull": case "justifyleft":
  15704. case "justifyright": case "delete": case "selectall": case "toggledir":
  15705. supportedBy = isSupportedBy(mozilla | ie | webkit | opera);
  15706. break;
  15707. case "createlink": case "unlink": case "removeformat":
  15708. case "inserthorizontalrule": case "insertimage":
  15709. case "insertorderedlist": case "insertunorderedlist":
  15710. case "indent": case "outdent": case "formatblock":
  15711. case "inserthtml": case "undo": case "redo": case "strikethrough": case "tabindent":
  15712. supportedBy = isSupportedBy(mozilla | ie | opera | webkit);
  15713. break;
  15714. case "blockdirltr": case "blockdirrtl":
  15715. case "dirltr": case "dirrtl":
  15716. case "inlinedirltr": case "inlinedirrtl":
  15717. supportedBy = isSupportedBy(ie);
  15718. break;
  15719. case "cut": case "copy": case "paste":
  15720. supportedBy = isSupportedBy( ie | mozilla | webkit);
  15721. break;
  15722. case "inserttable":
  15723. supportedBy = isSupportedBy(mozilla | ie);
  15724. break;
  15725. case "insertcell": case "insertcol": case "insertrow":
  15726. case "deletecells": case "deletecols": case "deleterows":
  15727. case "mergecells": case "splitcell":
  15728. supportedBy = isSupportedBy(ie | mozilla);
  15729. break;
  15730. default: return false;
  15731. }
  15732. return (has("ie") && supportedBy.ie) ||
  15733. (has("mozilla") && supportedBy.mozilla) ||
  15734. (has("webkit") && supportedBy.webkit) ||
  15735. (has("opera") && supportedBy.opera); // Boolean return true if the command is supported, false otherwise
  15736. },
  15737. execCommand: function(/*String*/ command, argument){
  15738. // summary:
  15739. // Executes a command in the Rich Text area
  15740. // command:
  15741. // The command to execute
  15742. // argument:
  15743. // An optional argument to the command
  15744. // tags:
  15745. // protected
  15746. var returnValue;
  15747. //focus() is required for IE to work
  15748. //In addition, focus() makes sure after the execution of
  15749. //the command, the editor receives the focus as expected
  15750. this.focus();
  15751. command = this._normalizeCommand(command, argument);
  15752. if(argument !== undefined){
  15753. if(command === "heading"){
  15754. throw new Error("unimplemented");
  15755. }else if((command === "formatblock") && has("ie")){
  15756. argument = '<'+argument+'>';
  15757. }
  15758. }
  15759. //Check to see if we have any over-rides for commands, they will be functions on this
  15760. //widget of the form _commandImpl. If we don't, fall through to the basic native
  15761. //exec command of the browser.
  15762. var implFunc = "_" + command + "Impl";
  15763. if(this[implFunc]){
  15764. returnValue = this[implFunc](argument);
  15765. }else{
  15766. argument = arguments.length > 1 ? argument : null;
  15767. if(argument || command !== "createlink"){
  15768. returnValue = this.document.execCommand(command, false, argument);
  15769. }
  15770. }
  15771. this.onDisplayChanged();
  15772. return returnValue;
  15773. },
  15774. queryCommandEnabled: function(/*String*/ command){
  15775. // summary:
  15776. // Check whether a command is enabled or not.
  15777. // command:
  15778. // The command to execute
  15779. // tags:
  15780. // protected
  15781. if(this.disabled || !this._disabledOK){ return false; }
  15782. command = this._normalizeCommand(command);
  15783. //Check to see if we have any over-rides for commands, they will be functions on this
  15784. //widget of the form _commandEnabledImpl. If we don't, fall through to the basic native
  15785. //command of the browser.
  15786. var implFunc = "_" + command + "EnabledImpl";
  15787. if(this[implFunc]){
  15788. return this[implFunc](command);
  15789. }else{
  15790. return this._browserQueryCommandEnabled(command);
  15791. }
  15792. },
  15793. queryCommandState: function(command){
  15794. // summary:
  15795. // Check the state of a given command and returns true or false.
  15796. // tags:
  15797. // protected
  15798. if(this.disabled || !this._disabledOK){ return false; }
  15799. command = this._normalizeCommand(command);
  15800. try{
  15801. return this.document.queryCommandState(command);
  15802. }catch(e){
  15803. //Squelch, occurs if editor is hidden on FF 3 (and maybe others.)
  15804. return false;
  15805. }
  15806. },
  15807. queryCommandValue: function(command){
  15808. // summary:
  15809. // Check the value of a given command. This matters most for
  15810. // custom selections and complex values like font value setting.
  15811. // tags:
  15812. // protected
  15813. if(this.disabled || !this._disabledOK){ return false; }
  15814. var r;
  15815. command = this._normalizeCommand(command);
  15816. if(has("ie") && command === "formatblock"){
  15817. r = this._native2LocalFormatNames[this.document.queryCommandValue(command)];
  15818. }else if(has("mozilla") && command === "hilitecolor"){
  15819. var oldValue;
  15820. try{
  15821. oldValue = this.document.queryCommandValue("styleWithCSS");
  15822. }catch(e){
  15823. oldValue = false;
  15824. }
  15825. this.document.execCommand("styleWithCSS", false, true);
  15826. r = this.document.queryCommandValue(command);
  15827. this.document.execCommand("styleWithCSS", false, oldValue);
  15828. }else{
  15829. r = this.document.queryCommandValue(command);
  15830. }
  15831. return r;
  15832. },
  15833. // Misc.
  15834. _sCall: function(name, args){
  15835. // summary:
  15836. // Run the named method of dijit._editor.selection over the
  15837. // current editor instance's window, with the passed args.
  15838. // tags:
  15839. // private
  15840. return win.withGlobal(this.window, name, selectionapi, args);
  15841. },
  15842. // FIXME: this is a TON of code duplication. Why?
  15843. placeCursorAtStart: function(){
  15844. // summary:
  15845. // Place the cursor at the start of the editing area.
  15846. // tags:
  15847. // private
  15848. this.focus();
  15849. //see comments in placeCursorAtEnd
  15850. var isvalid=false;
  15851. if(has("mozilla")){
  15852. // TODO: Is this branch even necessary?
  15853. var first=this.editNode.firstChild;
  15854. while(first){
  15855. if(first.nodeType === 3){
  15856. if(first.nodeValue.replace(/^\s+|\s+$/g, "").length>0){
  15857. isvalid=true;
  15858. this._sCall("selectElement", [ first ]);
  15859. break;
  15860. }
  15861. }else if(first.nodeType === 1){
  15862. isvalid=true;
  15863. var tg = first.tagName ? first.tagName.toLowerCase() : "";
  15864. // Collapse before childless tags.
  15865. if(/br|input|img|base|meta|area|basefont|hr|link/.test(tg)){
  15866. this._sCall("selectElement", [ first ]);
  15867. }else{
  15868. // Collapse inside tags with children.
  15869. this._sCall("selectElementChildren", [ first ]);
  15870. }
  15871. break;
  15872. }
  15873. first = first.nextSibling;
  15874. }
  15875. }else{
  15876. isvalid=true;
  15877. this._sCall("selectElementChildren", [ this.editNode ]);
  15878. }
  15879. if(isvalid){
  15880. this._sCall("collapse", [ true ]);
  15881. }
  15882. },
  15883. placeCursorAtEnd: function(){
  15884. // summary:
  15885. // Place the cursor at the end of the editing area.
  15886. // tags:
  15887. // private
  15888. this.focus();
  15889. //In mozilla, if last child is not a text node, we have to use
  15890. // selectElementChildren on this.editNode.lastChild otherwise the
  15891. // cursor would be placed at the end of the closing tag of
  15892. //this.editNode.lastChild
  15893. var isvalid=false;
  15894. if(has("mozilla")){
  15895. var last=this.editNode.lastChild;
  15896. while(last){
  15897. if(last.nodeType === 3){
  15898. if(last.nodeValue.replace(/^\s+|\s+$/g, "").length>0){
  15899. isvalid=true;
  15900. this._sCall("selectElement", [ last ]);
  15901. break;
  15902. }
  15903. }else if(last.nodeType === 1){
  15904. isvalid=true;
  15905. if(last.lastChild){
  15906. this._sCall("selectElement", [ last.lastChild ]);
  15907. }else{
  15908. this._sCall("selectElement", [ last ]);
  15909. }
  15910. break;
  15911. }
  15912. last = last.previousSibling;
  15913. }
  15914. }else{
  15915. isvalid=true;
  15916. this._sCall("selectElementChildren", [ this.editNode ]);
  15917. }
  15918. if(isvalid){
  15919. this._sCall("collapse", [ false ]);
  15920. }
  15921. },
  15922. getValue: function(/*Boolean?*/ nonDestructive){
  15923. // summary:
  15924. // Return the current content of the editing area (post filters
  15925. // are applied). Users should call get('value') instead.
  15926. // nonDestructive:
  15927. // defaults to false. Should the post-filtering be run over a copy
  15928. // of the live DOM? Most users should pass "true" here unless they
  15929. // *really* know that none of the installed filters are going to
  15930. // mess up the editing session.
  15931. // tags:
  15932. // private
  15933. if(this.textarea){
  15934. if(this.isClosed || !this.isLoaded){
  15935. return this.textarea.value;
  15936. }
  15937. }
  15938. return this._postFilterContent(null, nonDestructive);
  15939. },
  15940. _getValueAttr: function(){
  15941. // summary:
  15942. // Hook to make attr("value") work
  15943. return this.getValue(true);
  15944. },
  15945. setValue: function(/*String*/ html){
  15946. // summary:
  15947. // This function sets the content. No undo history is preserved.
  15948. // Users should use set('value', ...) instead.
  15949. // tags:
  15950. // deprecated
  15951. // TODO: remove this and getValue() for 2.0, and move code to _setValueAttr()
  15952. if(!this.isLoaded){
  15953. // try again after the editor is finished loading
  15954. this.onLoadDeferred.addCallback(lang.hitch(this, function(){
  15955. this.setValue(html);
  15956. }));
  15957. return;
  15958. }
  15959. this._cursorToStart = true;
  15960. if(this.textarea && (this.isClosed || !this.isLoaded)){
  15961. this.textarea.value=html;
  15962. }else{
  15963. html = this._preFilterContent(html);
  15964. var node = this.isClosed ? this.domNode : this.editNode;
  15965. if(html && has("mozilla") && html.toLowerCase() === "<p></p>"){
  15966. html = "<p>&#160;</p>"; // &nbsp;
  15967. }
  15968. // Use &nbsp; to avoid webkit problems where editor is disabled until the user clicks it
  15969. if(!html && has("webkit")){
  15970. html = "&#160;"; // &nbsp;
  15971. }
  15972. node.innerHTML = html;
  15973. this._preDomFilterContent(node);
  15974. }
  15975. this.onDisplayChanged();
  15976. this._set("value", this.getValue(true));
  15977. },
  15978. replaceValue: function(/*String*/ html){
  15979. // summary:
  15980. // This function set the content while trying to maintain the undo stack
  15981. // (now only works fine with Moz, this is identical to setValue in all
  15982. // other browsers)
  15983. // tags:
  15984. // protected
  15985. if(this.isClosed){
  15986. this.setValue(html);
  15987. }else if(this.window && this.window.getSelection && !has("mozilla")){ // Safari
  15988. // look ma! it's a totally f'd browser!
  15989. this.setValue(html);
  15990. }else if(this.window && this.window.getSelection){ // Moz
  15991. html = this._preFilterContent(html);
  15992. this.execCommand("selectall");
  15993. if(!html){
  15994. this._cursorToStart = true;
  15995. html = "&#160;"; // &nbsp;
  15996. }
  15997. this.execCommand("inserthtml", html);
  15998. this._preDomFilterContent(this.editNode);
  15999. }else if(this.document && this.document.selection){//IE
  16000. //In IE, when the first element is not a text node, say
  16001. //an <a> tag, when replacing the content of the editing
  16002. //area, the <a> tag will be around all the content
  16003. //so for now, use setValue for IE too
  16004. this.setValue(html);
  16005. }
  16006. this._set("value", this.getValue(true));
  16007. },
  16008. _preFilterContent: function(/*String*/ html){
  16009. // summary:
  16010. // Filter the input before setting the content of the editing
  16011. // area. DOM pre-filtering may happen after this
  16012. // string-based filtering takes place but as of 1.2, this is not
  16013. // guaranteed for operations such as the inserthtml command.
  16014. // tags:
  16015. // private
  16016. var ec = html;
  16017. array.forEach(this.contentPreFilters, function(ef){ if(ef){ ec = ef(ec); } });
  16018. return ec;
  16019. },
  16020. _preDomFilterContent: function(/*DomNode*/ dom){
  16021. // summary:
  16022. // filter the input's live DOM. All filter operations should be
  16023. // considered to be "live" and operating on the DOM that the user
  16024. // will be interacting with in their editing session.
  16025. // tags:
  16026. // private
  16027. dom = dom || this.editNode;
  16028. array.forEach(this.contentDomPreFilters, function(ef){
  16029. if(ef && lang.isFunction(ef)){
  16030. ef(dom);
  16031. }
  16032. }, this);
  16033. },
  16034. _postFilterContent: function(
  16035. /*DomNode|DomNode[]|String?*/ dom,
  16036. /*Boolean?*/ nonDestructive){
  16037. // summary:
  16038. // filter the output after getting the content of the editing area
  16039. //
  16040. // description:
  16041. // post-filtering allows plug-ins and users to specify any number
  16042. // of transforms over the editor's content, enabling many common
  16043. // use-cases such as transforming absolute to relative URLs (and
  16044. // vice-versa), ensuring conformance with a particular DTD, etc.
  16045. // The filters are registered in the contentDomPostFilters and
  16046. // contentPostFilters arrays. Each item in the
  16047. // contentDomPostFilters array is a function which takes a DOM
  16048. // Node or array of nodes as its only argument and returns the
  16049. // same. It is then passed down the chain for further filtering.
  16050. // The contentPostFilters array behaves the same way, except each
  16051. // member operates on strings. Together, the DOM and string-based
  16052. // filtering allow the full range of post-processing that should
  16053. // be necessaray to enable even the most agressive of post-editing
  16054. // conversions to take place.
  16055. //
  16056. // If nonDestructive is set to "true", the nodes are cloned before
  16057. // filtering proceeds to avoid potentially destructive transforms
  16058. // to the content which may still needed to be edited further.
  16059. // Once DOM filtering has taken place, the serialized version of
  16060. // the DOM which is passed is run through each of the
  16061. // contentPostFilters functions.
  16062. //
  16063. // dom:
  16064. // a node, set of nodes, which to filter using each of the current
  16065. // members of the contentDomPostFilters and contentPostFilters arrays.
  16066. //
  16067. // nonDestructive:
  16068. // defaults to "false". If true, ensures that filtering happens on
  16069. // a clone of the passed-in content and not the actual node
  16070. // itself.
  16071. //
  16072. // tags:
  16073. // private
  16074. var ec;
  16075. if(!lang.isString(dom)){
  16076. dom = dom || this.editNode;
  16077. if(this.contentDomPostFilters.length){
  16078. if(nonDestructive){
  16079. dom = lang.clone(dom);
  16080. }
  16081. array.forEach(this.contentDomPostFilters, function(ef){
  16082. dom = ef(dom);
  16083. });
  16084. }
  16085. ec = htmlapi.getChildrenHtml(dom);
  16086. }else{
  16087. ec = dom;
  16088. }
  16089. if(!lang.trim(ec.replace(/^\xA0\xA0*/, '').replace(/\xA0\xA0*$/, '')).length){
  16090. ec = "";
  16091. }
  16092. // if(has("ie")){
  16093. // //removing appended <P>&nbsp;</P> for IE
  16094. // ec = ec.replace(/(?:<p>&nbsp;</p>[\n\r]*)+$/i,"");
  16095. // }
  16096. array.forEach(this.contentPostFilters, function(ef){
  16097. ec = ef(ec);
  16098. });
  16099. return ec;
  16100. },
  16101. _saveContent: function(){
  16102. // summary:
  16103. // Saves the content in an onunload event if the editor has not been closed
  16104. // tags:
  16105. // private
  16106. var saveTextarea = dom.byId(dijit._scopeName + "._editor.RichText.value");
  16107. if(saveTextarea){
  16108. if(saveTextarea.value){
  16109. saveTextarea.value += this._SEPARATOR;
  16110. }
  16111. saveTextarea.value += this.name + this._NAME_CONTENT_SEP + this.getValue(true);
  16112. }
  16113. },
  16114. escapeXml: function(/*String*/ str, /*Boolean*/ noSingleQuotes){
  16115. // summary:
  16116. // Adds escape sequences for special characters in XML.
  16117. // Optionally skips escapes for single quotes
  16118. // tags:
  16119. // private
  16120. str = str.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;");
  16121. if(!noSingleQuotes){
  16122. str = str.replace(/'/gm, "&#39;");
  16123. }
  16124. return str; // string
  16125. },
  16126. getNodeHtml: function(/* DomNode */ node){
  16127. // summary:
  16128. // Deprecated. Use dijit/_editor/html::_getNodeHtml() instead.
  16129. // tags:
  16130. // deprecated
  16131. kernel.deprecated('dijit.Editor::getNodeHtml is deprecated','use dijit/_editor/html::getNodeHtml instead', 2);
  16132. return htmlapi.getNodeHtml(node); // String
  16133. },
  16134. getNodeChildrenHtml: function(/* DomNode */ dom){
  16135. // summary:
  16136. // Deprecated. Use dijit/_editor/html::getChildrenHtml() instead.
  16137. // tags:
  16138. // deprecated
  16139. kernel.deprecated('dijit.Editor::getNodeChildrenHtml is deprecated','use dijit/_editor/html::getChildrenHtml instead', 2);
  16140. return htmlapi.getChildrenHtml(dom);
  16141. },
  16142. close: function(/*Boolean?*/ save){
  16143. // summary:
  16144. // Kills the editor and optionally writes back the modified contents to the
  16145. // element from which it originated.
  16146. // save:
  16147. // Whether or not to save the changes. If false, the changes are discarded.
  16148. // tags:
  16149. // private
  16150. if(this.isClosed){ return; }
  16151. if(!arguments.length){ save = true; }
  16152. if(save){
  16153. this._set("value", this.getValue(true));
  16154. }
  16155. // line height is squashed for iframes
  16156. // FIXME: why was this here? if(this.iframe){ this.domNode.style.lineHeight = null; }
  16157. if(this.interval){ clearInterval(this.interval); }
  16158. if(this._webkitListener){
  16159. //Cleaup of WebKit fix: #9532
  16160. this.disconnect(this._webkitListener);
  16161. delete this._webkitListener;
  16162. }
  16163. // Guard against memory leaks on IE (see #9268)
  16164. if(has("ie")){
  16165. this.iframe.onfocus = null;
  16166. }
  16167. this.iframe._loadFunc = null;
  16168. if(this._iframeRegHandle){
  16169. this._iframeRegHandle.remove();
  16170. delete this._iframeRegHandle;
  16171. }
  16172. if(this.textarea){
  16173. var s = this.textarea.style;
  16174. s.position = "";
  16175. s.left = s.top = "";
  16176. if(has("ie")){
  16177. s.overflow = this.__overflow;
  16178. this.__overflow = null;
  16179. }
  16180. this.textarea.value = this.value;
  16181. domConstruct.destroy(this.domNode);
  16182. this.domNode = this.textarea;
  16183. }else{
  16184. // Note that this destroys the iframe
  16185. this.domNode.innerHTML = this.value;
  16186. }
  16187. delete this.iframe;
  16188. domClass.remove(this.domNode, this.baseClass);
  16189. this.isClosed = true;
  16190. this.isLoaded = false;
  16191. delete this.editNode;
  16192. delete this.focusNode;
  16193. if(this.window && this.window._frameElement){
  16194. this.window._frameElement = null;
  16195. }
  16196. this.window = null;
  16197. this.document = null;
  16198. this.editingArea = null;
  16199. this.editorObject = null;
  16200. },
  16201. destroy: function(){
  16202. if(!this.isClosed){ this.close(false); }
  16203. if(this._updateTimer){
  16204. clearTimeout(this._updateTimer);
  16205. }
  16206. this.inherited(arguments);
  16207. if(RichText._globalSaveHandler){
  16208. delete RichText._globalSaveHandler[this.id];
  16209. }
  16210. },
  16211. _removeMozBogus: function(/* String */ html){
  16212. // summary:
  16213. // Post filter to remove unwanted HTML attributes generated by mozilla
  16214. // tags:
  16215. // private
  16216. return html.replace(/\stype="_moz"/gi, '').replace(/\s_moz_dirty=""/gi, '').replace(/_moz_resizing="(true|false)"/gi,''); // String
  16217. },
  16218. _removeWebkitBogus: function(/* String */ html){
  16219. // summary:
  16220. // Post filter to remove unwanted HTML attributes generated by webkit
  16221. // tags:
  16222. // private
  16223. html = html.replace(/\sclass="webkit-block-placeholder"/gi, '');
  16224. html = html.replace(/\sclass="apple-style-span"/gi, '');
  16225. // For some reason copy/paste sometime adds extra meta tags for charset on
  16226. // webkit (chrome) on mac.They need to be removed. See: #12007"
  16227. html = html.replace(/<meta charset=\"utf-8\" \/>/gi, '');
  16228. return html; // String
  16229. },
  16230. _normalizeFontStyle: function(/* String */ html){
  16231. // summary:
  16232. // Convert 'strong' and 'em' to 'b' and 'i'.
  16233. // description:
  16234. // Moz can not handle strong/em tags correctly, so to help
  16235. // mozilla and also to normalize output, convert them to 'b' and 'i'.
  16236. //
  16237. // Note the IE generates 'strong' and 'em' rather than 'b' and 'i'
  16238. // tags:
  16239. // private
  16240. return html.replace(/<(\/)?strong([ \>])/gi, '<$1b$2')
  16241. .replace(/<(\/)?em([ \>])/gi, '<$1i$2' ); // String
  16242. },
  16243. _preFixUrlAttributes: function(/* String */ html){
  16244. // summary:
  16245. // Pre-filter to do fixing to href attributes on <a> and <img> tags
  16246. // tags:
  16247. // private
  16248. return html.replace(/(?:(<a(?=\s).*?\shref=)("|')(.*?)\2)|(?:(<a\s.*?href=)([^"'][^ >]+))/gi,
  16249. '$1$4$2$3$5$2 _djrealurl=$2$3$5$2')
  16250. .replace(/(?:(<img(?=\s).*?\ssrc=)("|')(.*?)\2)|(?:(<img\s.*?src=)([^"'][^ >]+))/gi,
  16251. '$1$4$2$3$5$2 _djrealurl=$2$3$5$2'); // String
  16252. },
  16253. /*****************************************************************************
  16254. The following functions implement HTML manipulation commands for various
  16255. browser/contentEditable implementations. The goal of them is to enforce
  16256. standard behaviors of them.
  16257. ******************************************************************************/
  16258. /*** queryCommandEnabled implementations ***/
  16259. _browserQueryCommandEnabled: function(command){
  16260. // summary:
  16261. // Implementation to call to the native queryCommandEnabled of the browser.
  16262. // command:
  16263. // The command to check.
  16264. // tags:
  16265. // protected
  16266. if(!command) { return false; }
  16267. var elem = has("ie") ? this.document.selection.createRange() : this.document;
  16268. try{
  16269. return elem.queryCommandEnabled(command);
  16270. }catch(e){
  16271. return false;
  16272. }
  16273. },
  16274. _createlinkEnabledImpl: function(/*===== argument =====*/){
  16275. // summary:
  16276. // This function implements the test for if the create link
  16277. // command should be enabled or not.
  16278. // argument:
  16279. // arguments to the exec command, if any.
  16280. // tags:
  16281. // protected
  16282. var enabled = true;
  16283. if(has("opera")){
  16284. var sel = this.window.getSelection();
  16285. if(sel.isCollapsed){
  16286. enabled = true;
  16287. }else{
  16288. enabled = this.document.queryCommandEnabled("createlink");
  16289. }
  16290. }else{
  16291. enabled = this._browserQueryCommandEnabled("createlink");
  16292. }
  16293. return enabled;
  16294. },
  16295. _unlinkEnabledImpl: function(/*===== argument =====*/){
  16296. // summary:
  16297. // This function implements the test for if the unlink
  16298. // command should be enabled or not.
  16299. // argument:
  16300. // arguments to the exec command, if any.
  16301. // tags:
  16302. // protected
  16303. var enabled = true;
  16304. if(has("mozilla") || has("webkit")){
  16305. enabled = this._sCall("hasAncestorElement", ["a"]);
  16306. }else{
  16307. enabled = this._browserQueryCommandEnabled("unlink");
  16308. }
  16309. return enabled;
  16310. },
  16311. _inserttableEnabledImpl: function(/*===== argument =====*/){
  16312. // summary:
  16313. // This function implements the test for if the inserttable
  16314. // command should be enabled or not.
  16315. // argument:
  16316. // arguments to the exec command, if any.
  16317. // tags:
  16318. // protected
  16319. var enabled = true;
  16320. if(has("mozilla") || has("webkit")){
  16321. enabled = true;
  16322. }else{
  16323. enabled = this._browserQueryCommandEnabled("inserttable");
  16324. }
  16325. return enabled;
  16326. },
  16327. _cutEnabledImpl: function(/*===== argument =====*/){
  16328. // summary:
  16329. // This function implements the test for if the cut
  16330. // command should be enabled or not.
  16331. // argument:
  16332. // arguments to the exec command, if any.
  16333. // tags:
  16334. // protected
  16335. var enabled = true;
  16336. if(has("webkit")){
  16337. // WebKit deems clipboard activity as a security threat and natively would return false
  16338. var sel = this.window.getSelection();
  16339. if(sel){ sel = sel.toString(); }
  16340. enabled = !!sel;
  16341. }else{
  16342. enabled = this._browserQueryCommandEnabled("cut");
  16343. }
  16344. return enabled;
  16345. },
  16346. _copyEnabledImpl: function(/*===== argument =====*/){
  16347. // summary:
  16348. // This function implements the test for if the copy
  16349. // command should be enabled or not.
  16350. // argument:
  16351. // arguments to the exec command, if any.
  16352. // tags:
  16353. // protected
  16354. var enabled = true;
  16355. if(has("webkit")){
  16356. // WebKit deems clipboard activity as a security threat and natively would return false
  16357. var sel = this.window.getSelection();
  16358. if(sel){ sel = sel.toString(); }
  16359. enabled = !!sel;
  16360. }else{
  16361. enabled = this._browserQueryCommandEnabled("copy");
  16362. }
  16363. return enabled;
  16364. },
  16365. _pasteEnabledImpl: function(/*===== argument =====*/){
  16366. // summary:c
  16367. // This function implements the test for if the paste
  16368. // command should be enabled or not.
  16369. // argument:
  16370. // arguments to the exec command, if any.
  16371. // tags:
  16372. // protected
  16373. var enabled = true;
  16374. if(has("webkit")){
  16375. return true;
  16376. }else{
  16377. enabled = this._browserQueryCommandEnabled("paste");
  16378. }
  16379. return enabled;
  16380. },
  16381. /*** execCommand implementations ***/
  16382. _inserthorizontalruleImpl: function(argument){
  16383. // summary:
  16384. // This function implements the insertion of HTML 'HR' tags.
  16385. // into a point on the page. IE doesn't to it right, so
  16386. // we have to use an alternate form
  16387. // argument:
  16388. // arguments to the exec command, if any.
  16389. // tags:
  16390. // protected
  16391. if(has("ie")){
  16392. return this._inserthtmlImpl("<hr>");
  16393. }
  16394. return this.document.execCommand("inserthorizontalrule", false, argument);
  16395. },
  16396. _unlinkImpl: function(argument){
  16397. // summary:
  16398. // This function implements the unlink of an 'a' tag.
  16399. // argument:
  16400. // arguments to the exec command, if any.
  16401. // tags:
  16402. // protected
  16403. if((this.queryCommandEnabled("unlink")) && (has("mozilla") || has("webkit"))){
  16404. var a = this._sCall("getAncestorElement", [ "a" ]);
  16405. this._sCall("selectElement", [ a ]);
  16406. return this.document.execCommand("unlink", false, null);
  16407. }
  16408. return this.document.execCommand("unlink", false, argument);
  16409. },
  16410. _hilitecolorImpl: function(argument){
  16411. // summary:
  16412. // This function implements the hilitecolor command
  16413. // argument:
  16414. // arguments to the exec command, if any.
  16415. // tags:
  16416. // protected
  16417. var returnValue;
  16418. var isApplied = this._handleTextColorOrProperties("hilitecolor", argument);
  16419. if(!isApplied){
  16420. if(has("mozilla")){
  16421. // mozilla doesn't support hilitecolor properly when useCSS is
  16422. // set to false (bugzilla #279330)
  16423. this.document.execCommand("styleWithCSS", false, true);
  16424. console.log("Executing color command.");
  16425. returnValue = this.document.execCommand("hilitecolor", false, argument);
  16426. this.document.execCommand("styleWithCSS", false, false);
  16427. }else{
  16428. returnValue = this.document.execCommand("hilitecolor", false, argument);
  16429. }
  16430. }
  16431. return returnValue;
  16432. },
  16433. _backcolorImpl: function(argument){
  16434. // summary:
  16435. // This function implements the backcolor command
  16436. // argument:
  16437. // arguments to the exec command, if any.
  16438. // tags:
  16439. // protected
  16440. if(has("ie")){
  16441. // Tested under IE 6 XP2, no problem here, comment out
  16442. // IE weirdly collapses ranges when we exec these commands, so prevent it
  16443. // var tr = this.document.selection.createRange();
  16444. argument = argument ? argument : null;
  16445. }
  16446. var isApplied = this._handleTextColorOrProperties("backcolor", argument);
  16447. if(!isApplied){
  16448. isApplied = this.document.execCommand("backcolor", false, argument);
  16449. }
  16450. return isApplied;
  16451. },
  16452. _forecolorImpl: function(argument){
  16453. // summary:
  16454. // This function implements the forecolor command
  16455. // argument:
  16456. // arguments to the exec command, if any.
  16457. // tags:
  16458. // protected
  16459. if(has("ie")){
  16460. // Tested under IE 6 XP2, no problem here, comment out
  16461. // IE weirdly collapses ranges when we exec these commands, so prevent it
  16462. // var tr = this.document.selection.createRange();
  16463. argument = argument? argument : null;
  16464. }
  16465. var isApplied = false;
  16466. isApplied = this._handleTextColorOrProperties("forecolor", argument);
  16467. if(!isApplied){
  16468. isApplied = this.document.execCommand("forecolor", false, argument);
  16469. }
  16470. return isApplied;
  16471. },
  16472. _inserthtmlImpl: function(argument){
  16473. // summary:
  16474. // This function implements the insertion of HTML content into
  16475. // a point on the page.
  16476. // argument:
  16477. // The content to insert, if any.
  16478. // tags:
  16479. // protected
  16480. argument = this._preFilterContent(argument);
  16481. var rv = true;
  16482. if(has("ie")){
  16483. var insertRange = this.document.selection.createRange();
  16484. if(this.document.selection.type.toUpperCase() === 'CONTROL'){
  16485. var n=insertRange.item(0);
  16486. while(insertRange.length){
  16487. insertRange.remove(insertRange.item(0));
  16488. }
  16489. n.outerHTML=argument;
  16490. }else{
  16491. insertRange.pasteHTML(argument);
  16492. }
  16493. insertRange.select();
  16494. //insertRange.collapse(true);
  16495. }else if(has("mozilla") && !argument.length){
  16496. //mozilla can not inserthtml an empty html to delete current selection
  16497. //so we delete the selection instead in this case
  16498. this._sCall("remove"); // FIXME
  16499. }else{
  16500. rv = this.document.execCommand("inserthtml", false, argument);
  16501. }
  16502. return rv;
  16503. },
  16504. _boldImpl: function(argument){
  16505. // summary:
  16506. // This function implements an over-ride of the bold command.
  16507. // argument:
  16508. // Not used, operates by selection.
  16509. // tags:
  16510. // protected
  16511. var applied = false;
  16512. if(has("ie")){
  16513. this._adaptIESelection();
  16514. applied = this._adaptIEFormatAreaAndExec("bold");
  16515. }
  16516. if(!applied){
  16517. applied = this.document.execCommand("bold", false, argument);
  16518. }
  16519. return applied;
  16520. },
  16521. _italicImpl: function(argument){
  16522. // summary:
  16523. // This function implements an over-ride of the italic command.
  16524. // argument:
  16525. // Not used, operates by selection.
  16526. // tags:
  16527. // protected
  16528. var applied = false;
  16529. if(has("ie")){
  16530. this._adaptIESelection();
  16531. applied = this._adaptIEFormatAreaAndExec("italic");
  16532. }
  16533. if(!applied){
  16534. applied = this.document.execCommand("italic", false, argument);
  16535. }
  16536. return applied;
  16537. },
  16538. _underlineImpl: function(argument){
  16539. // summary:
  16540. // This function implements an over-ride of the underline command.
  16541. // argument:
  16542. // Not used, operates by selection.
  16543. // tags:
  16544. // protected
  16545. var applied = false;
  16546. if(has("ie")){
  16547. this._adaptIESelection();
  16548. applied = this._adaptIEFormatAreaAndExec("underline");
  16549. }
  16550. if(!applied){
  16551. applied = this.document.execCommand("underline", false, argument);
  16552. }
  16553. return applied;
  16554. },
  16555. _strikethroughImpl: function(argument){
  16556. // summary:
  16557. // This function implements an over-ride of the strikethrough command.
  16558. // argument:
  16559. // Not used, operates by selection.
  16560. // tags:
  16561. // protected
  16562. var applied = false;
  16563. if(has("ie")){
  16564. this._adaptIESelection();
  16565. applied = this._adaptIEFormatAreaAndExec("strikethrough");
  16566. }
  16567. if(!applied){
  16568. applied = this.document.execCommand("strikethrough", false, argument);
  16569. }
  16570. return applied;
  16571. },
  16572. _superscriptImpl: function(argument){
  16573. // summary:
  16574. // This function implements an over-ride of the superscript command.
  16575. // argument:
  16576. // Not used, operates by selection.
  16577. // tags:
  16578. // protected
  16579. var applied = false;
  16580. if(has("ie")){
  16581. this._adaptIESelection();
  16582. applied = this._adaptIEFormatAreaAndExec("superscript");
  16583. }
  16584. if(!applied){
  16585. applied = this.document.execCommand("superscript", false, argument);
  16586. }
  16587. return applied;
  16588. },
  16589. _subscriptImpl: function(argument){
  16590. // summary:
  16591. // This function implements an over-ride of the superscript command.
  16592. // argument:
  16593. // Not used, operates by selection.
  16594. // tags:
  16595. // protected
  16596. var applied = false;
  16597. if(has("ie")){
  16598. this._adaptIESelection();
  16599. applied = this._adaptIEFormatAreaAndExec("subscript");
  16600. }
  16601. if(!applied){
  16602. applied = this.document.execCommand("subscript", false, argument);
  16603. }
  16604. return applied;
  16605. },
  16606. _fontnameImpl: function(argument){
  16607. // summary:
  16608. // This function implements the fontname command
  16609. // argument:
  16610. // arguments to the exec command, if any.
  16611. // tags:
  16612. // protected
  16613. var isApplied;
  16614. if(has("ie")){
  16615. isApplied = this._handleTextColorOrProperties("fontname", argument);
  16616. }
  16617. if(!isApplied){
  16618. isApplied = this.document.execCommand("fontname", false, argument);
  16619. }
  16620. return isApplied;
  16621. },
  16622. _fontsizeImpl: function(argument){
  16623. // summary:
  16624. // This function implements the fontsize command
  16625. // argument:
  16626. // arguments to the exec command, if any.
  16627. // tags:
  16628. // protected
  16629. var isApplied;
  16630. if(has("ie")){
  16631. isApplied = this._handleTextColorOrProperties("fontsize", argument);
  16632. }
  16633. if(!isApplied){
  16634. isApplied = this.document.execCommand("fontsize", false, argument);
  16635. }
  16636. return isApplied;
  16637. },
  16638. _insertorderedlistImpl: function(argument){
  16639. // summary:
  16640. // This function implements the insertorderedlist command
  16641. // argument:
  16642. // arguments to the exec command, if any.
  16643. // tags:
  16644. // protected
  16645. var applied = false;
  16646. if(has("ie")){
  16647. applied = this._adaptIEList("insertorderedlist", argument);
  16648. }
  16649. if(!applied){
  16650. applied = this.document.execCommand("insertorderedlist", false, argument);
  16651. }
  16652. return applied;
  16653. },
  16654. _insertunorderedlistImpl: function(argument){
  16655. // summary:
  16656. // This function implements the insertunorderedlist command
  16657. // argument:
  16658. // arguments to the exec command, if any.
  16659. // tags:
  16660. // protected
  16661. var applied = false;
  16662. if(has("ie")){
  16663. applied = this._adaptIEList("insertunorderedlist", argument);
  16664. }
  16665. if(!applied){
  16666. applied = this.document.execCommand("insertunorderedlist", false, argument);
  16667. }
  16668. return applied;
  16669. },
  16670. getHeaderHeight: function(){
  16671. // summary:
  16672. // A function for obtaining the height of the header node
  16673. return this._getNodeChildrenHeight(this.header); // Number
  16674. },
  16675. getFooterHeight: function(){
  16676. // summary:
  16677. // A function for obtaining the height of the footer node
  16678. return this._getNodeChildrenHeight(this.footer); // Number
  16679. },
  16680. _getNodeChildrenHeight: function(node){
  16681. // summary:
  16682. // An internal function for computing the cumulative height of all child nodes of 'node'
  16683. // node:
  16684. // The node to process the children of;
  16685. var h = 0;
  16686. if(node && node.childNodes){
  16687. // IE didn't compute it right when position was obtained on the node directly is some cases,
  16688. // so we have to walk over all the children manually.
  16689. var i;
  16690. for(i = 0; i < node.childNodes.length; i++){
  16691. var size = domGeometry.position(node.childNodes[i]);
  16692. h += size.h;
  16693. }
  16694. }
  16695. return h; // Number
  16696. },
  16697. _isNodeEmpty: function(node, startOffset){
  16698. // summary:
  16699. // Function to test if a node is devoid of real content.
  16700. // node:
  16701. // The node to check.
  16702. // tags:
  16703. // private.
  16704. if(node.nodeType === 1/*element*/){
  16705. if(node.childNodes.length > 0){
  16706. return this._isNodeEmpty(node.childNodes[0], startOffset);
  16707. }
  16708. return true;
  16709. }else if(node.nodeType === 3/*text*/){
  16710. return (node.nodeValue.substring(startOffset) === "");
  16711. }
  16712. return false;
  16713. },
  16714. _removeStartingRangeFromRange: function(node, range){
  16715. // summary:
  16716. // Function to adjust selection range by removing the current
  16717. // start node.
  16718. // node:
  16719. // The node to remove from the starting range.
  16720. // range:
  16721. // The range to adapt.
  16722. // tags:
  16723. // private
  16724. if(node.nextSibling){
  16725. range.setStart(node.nextSibling,0);
  16726. }else{
  16727. var parent = node.parentNode;
  16728. while(parent && parent.nextSibling == null){
  16729. //move up the tree until we find a parent that has another node, that node will be the next node
  16730. parent = parent.parentNode;
  16731. }
  16732. if(parent){
  16733. range.setStart(parent.nextSibling,0);
  16734. }
  16735. }
  16736. return range;
  16737. },
  16738. _adaptIESelection: function(){
  16739. // summary:
  16740. // Function to adapt the IE range by removing leading 'newlines'
  16741. // Needed to fix issue with bold/italics/underline not working if
  16742. // range included leading 'newlines'.
  16743. // In IE, if a user starts a selection at the very end of a line,
  16744. // then the native browser commands will fail to execute correctly.
  16745. // To work around the issue, we can remove all empty nodes from
  16746. // the start of the range selection.
  16747. var selection = rangeapi.getSelection(this.window);
  16748. if(selection && selection.rangeCount && !selection.isCollapsed){
  16749. var range = selection.getRangeAt(0);
  16750. var firstNode = range.startContainer;
  16751. var startOffset = range.startOffset;
  16752. while(firstNode.nodeType === 3/*text*/ && startOffset >= firstNode.length && firstNode.nextSibling){
  16753. //traverse the text nodes until we get to the one that is actually highlighted
  16754. startOffset = startOffset - firstNode.length;
  16755. firstNode = firstNode.nextSibling;
  16756. }
  16757. //Remove the starting ranges until the range does not start with an empty node.
  16758. var lastNode=null;
  16759. while(this._isNodeEmpty(firstNode, startOffset) && firstNode !== lastNode){
  16760. lastNode =firstNode; //this will break the loop in case we can't find the next sibling
  16761. range = this._removeStartingRangeFromRange(firstNode, range); //move the start container to the next node in the range
  16762. firstNode = range.startContainer;
  16763. startOffset = 0; //start at the beginning of the new starting range
  16764. }
  16765. selection.removeAllRanges();// this will work as long as users cannot select multiple ranges. I have not been able to do that in the editor.
  16766. selection.addRange(range);
  16767. }
  16768. },
  16769. _adaptIEFormatAreaAndExec: function(command){
  16770. // summary:
  16771. // Function to handle IE's quirkiness regarding how it handles
  16772. // format commands on a word. This involves a lit of node splitting
  16773. // and format cloning.
  16774. // command:
  16775. // The format command, needed to check if the desired
  16776. // command is true or not.
  16777. var selection = rangeapi.getSelection(this.window);
  16778. var doc = this.document;
  16779. var rs, ret, range, txt, startNode, endNode, breaker, sNode;
  16780. if(command && selection && selection.isCollapsed){
  16781. var isApplied = this.queryCommandValue(command);
  16782. if(isApplied){
  16783. // We have to split backwards until we hit the format
  16784. var nNames = this._tagNamesForCommand(command);
  16785. range = selection.getRangeAt(0);
  16786. var fs = range.startContainer;
  16787. if(fs.nodeType === 3){
  16788. var offset = range.endOffset;
  16789. if(fs.length < offset){
  16790. //We are not looking from the right node, try to locate the correct one
  16791. ret = this._adjustNodeAndOffset(rs, offset);
  16792. fs = ret.node;
  16793. offset = ret.offset;
  16794. }
  16795. }
  16796. var topNode;
  16797. while(fs && fs !== this.editNode){
  16798. // We have to walk back and see if this is still a format or not.
  16799. // Hm, how do I do this?
  16800. var tName = fs.tagName? fs.tagName.toLowerCase() : "";
  16801. if(array.indexOf(nNames, tName) > -1){
  16802. topNode = fs;
  16803. break;
  16804. }
  16805. fs = fs.parentNode;
  16806. }
  16807. // Okay, we have a stopping place, time to split things apart.
  16808. if(topNode){
  16809. // Okay, we know how far we have to split backwards, so we have to split now.
  16810. rs = range.startContainer;
  16811. var newblock = doc.createElement(topNode.tagName);
  16812. domConstruct.place(newblock, topNode, "after");
  16813. if(rs && rs.nodeType === 3){
  16814. // Text node, we have to split it.
  16815. var nodeToMove, tNode;
  16816. var endOffset = range.endOffset;
  16817. if(rs.length < endOffset){
  16818. //We are not splitting the right node, try to locate the correct one
  16819. ret = this._adjustNodeAndOffset(rs, endOffset);
  16820. rs = ret.node;
  16821. endOffset = ret.offset;
  16822. }
  16823. txt = rs.nodeValue;
  16824. startNode = doc.createTextNode(txt.substring(0, endOffset));
  16825. var endText = txt.substring(endOffset, txt.length);
  16826. if(endText){
  16827. endNode = doc.createTextNode(endText);
  16828. }
  16829. // Place the split, then remove original nodes.
  16830. domConstruct.place(startNode, rs, "before");
  16831. if(endNode){
  16832. breaker = doc.createElement("span");
  16833. breaker.className = "ieFormatBreakerSpan";
  16834. domConstruct.place(breaker, rs, "after");
  16835. domConstruct.place(endNode, breaker, "after");
  16836. endNode = breaker;
  16837. }
  16838. domConstruct.destroy(rs);
  16839. // Okay, we split the text. Now we need to see if we're
  16840. // parented to the block element we're splitting and if
  16841. // not, we have to split all the way up. Ugh.
  16842. var parentC = startNode.parentNode;
  16843. var tagList = [];
  16844. var tagData;
  16845. while(parentC !== topNode){
  16846. var tg = parentC.tagName;
  16847. tagData = {tagName: tg};
  16848. tagList.push(tagData);
  16849. var newTg = doc.createElement(tg);
  16850. // Clone over any 'style' data.
  16851. if(parentC.style){
  16852. if(newTg.style){
  16853. if(parentC.style.cssText){
  16854. newTg.style.cssText = parentC.style.cssText;
  16855. tagData.cssText = parentC.style.cssText;
  16856. }
  16857. }
  16858. }
  16859. // If font also need to clone over any font data.
  16860. if(parentC.tagName === "FONT"){
  16861. if(parentC.color){
  16862. newTg.color = parentC.color;
  16863. tagData.color = parentC.color;
  16864. }
  16865. if(parentC.face){
  16866. newTg.face = parentC.face;
  16867. tagData.face = parentC.face;
  16868. }
  16869. if(parentC.size){ // this check was necessary on IE
  16870. newTg.size = parentC.size;
  16871. tagData.size = parentC.size;
  16872. }
  16873. }
  16874. if(parentC.className){
  16875. newTg.className = parentC.className;
  16876. tagData.className = parentC.className;
  16877. }
  16878. // Now move end node and every sibling
  16879. // after it over into the new tag.
  16880. if(endNode){
  16881. nodeToMove = endNode;
  16882. while(nodeToMove){
  16883. tNode = nodeToMove.nextSibling;
  16884. newTg.appendChild(nodeToMove);
  16885. nodeToMove = tNode;
  16886. }
  16887. }
  16888. if(newTg.tagName == parentC.tagName){
  16889. breaker = doc.createElement("span");
  16890. breaker.className = "ieFormatBreakerSpan";
  16891. domConstruct.place(breaker, parentC, "after");
  16892. domConstruct.place(newTg, breaker, "after");
  16893. }else{
  16894. domConstruct.place(newTg, parentC, "after");
  16895. }
  16896. startNode = parentC;
  16897. endNode = newTg;
  16898. parentC = parentC.parentNode;
  16899. }
  16900. // Lastly, move the split out all the split tags
  16901. // to the new block as they should now be split properly.
  16902. if(endNode){
  16903. nodeToMove = endNode;
  16904. if(nodeToMove.nodeType === 1 || (nodeToMove.nodeType === 3 && nodeToMove.nodeValue)){
  16905. // Non-blank text and non-text nodes need to clear out that blank space
  16906. // before moving the contents.
  16907. newblock.innerHTML = "";
  16908. }
  16909. while(nodeToMove){
  16910. tNode = nodeToMove.nextSibling;
  16911. newblock.appendChild(nodeToMove);
  16912. nodeToMove = tNode;
  16913. }
  16914. }
  16915. // We had intermediate tags, we have to now recreate them inbetween the split
  16916. // and restore what styles, classnames, etc, we can.
  16917. if(tagList.length){
  16918. tagData = tagList.pop();
  16919. var newContTag = doc.createElement(tagData.tagName);
  16920. if(tagData.cssText && newContTag.style){
  16921. newContTag.style.cssText = tagData.cssText;
  16922. }
  16923. if(tagData.className){
  16924. newContTag.className = tagData.className;
  16925. }
  16926. if(tagData.tagName === "FONT"){
  16927. if(tagData.color){
  16928. newContTag.color = tagData.color;
  16929. }
  16930. if(tagData.face){
  16931. newContTag.face = tagData.face;
  16932. }
  16933. if(tagData.size){
  16934. newContTag.size = tagData.size;
  16935. }
  16936. }
  16937. domConstruct.place(newContTag, newblock, "before");
  16938. while(tagList.length){
  16939. tagData = tagList.pop();
  16940. var newTgNode = doc.createElement(tagData.tagName);
  16941. if(tagData.cssText && newTgNode.style){
  16942. newTgNode.style.cssText = tagData.cssText;
  16943. }
  16944. if(tagData.className){
  16945. newTgNode.className = tagData.className;
  16946. }
  16947. if(tagData.tagName === "FONT"){
  16948. if(tagData.color){
  16949. newTgNode.color = tagData.color;
  16950. }
  16951. if(tagData.face){
  16952. newTgNode.face = tagData.face;
  16953. }
  16954. if(tagData.size){
  16955. newTgNode.size = tagData.size;
  16956. }
  16957. }
  16958. newContTag.appendChild(newTgNode);
  16959. newContTag = newTgNode;
  16960. }
  16961. // Okay, everything is theoretically split apart and removed from the content
  16962. // so insert the dummy text to select, select it, then
  16963. // clear to position cursor.
  16964. sNode = doc.createTextNode(".");
  16965. breaker.appendChild(sNode);
  16966. newContTag.appendChild(sNode);
  16967. win.withGlobal(this.window, lang.hitch(this, function(){
  16968. var newrange = rangeapi.create();
  16969. newrange.setStart(sNode, 0);
  16970. newrange.setEnd(sNode, sNode.length);
  16971. selection.removeAllRanges();
  16972. selection.addRange(newrange);
  16973. selectionapi.collapse(false);
  16974. sNode.parentNode.innerHTML = "";
  16975. }));
  16976. }else{
  16977. // No extra tags, so we have to insert a breaker point and rely
  16978. // on filters to remove it later.
  16979. breaker = doc.createElement("span");
  16980. breaker.className="ieFormatBreakerSpan";
  16981. sNode = doc.createTextNode(".");
  16982. breaker.appendChild(sNode);
  16983. domConstruct.place(breaker, newblock, "before");
  16984. win.withGlobal(this.window, lang.hitch(this, function(){
  16985. var newrange = rangeapi.create();
  16986. newrange.setStart(sNode, 0);
  16987. newrange.setEnd(sNode, sNode.length);
  16988. selection.removeAllRanges();
  16989. selection.addRange(newrange);
  16990. selectionapi.collapse(false);
  16991. sNode.parentNode.innerHTML = "";
  16992. }));
  16993. }
  16994. if(!newblock.firstChild){
  16995. // Empty, we don't need it. Split was at end or similar
  16996. // So, remove it.
  16997. domConstruct.destroy(newblock);
  16998. }
  16999. return true;
  17000. }
  17001. }
  17002. return false;
  17003. }else{
  17004. range = selection.getRangeAt(0);
  17005. rs = range.startContainer;
  17006. if(rs && rs.nodeType === 3){
  17007. // Text node, we have to split it.
  17008. win.withGlobal(this.window, lang.hitch(this, function(){
  17009. var offset = range.startOffset;
  17010. if(rs.length < offset){
  17011. //We are not splitting the right node, try to locate the correct one
  17012. ret = this._adjustNodeAndOffset(rs, offset);
  17013. rs = ret.node;
  17014. offset = ret.offset;
  17015. }
  17016. txt = rs.nodeValue;
  17017. startNode = doc.createTextNode(txt.substring(0, offset));
  17018. var endText = txt.substring(offset);
  17019. if(endText !== ""){
  17020. endNode = doc.createTextNode(txt.substring(offset));
  17021. }
  17022. // Create a space, we'll select and bold it, so
  17023. // the whole word doesn't get bolded
  17024. breaker = doc.createElement("span");
  17025. sNode = doc.createTextNode(".");
  17026. breaker.appendChild(sNode);
  17027. if(startNode.length){
  17028. domConstruct.place(startNode, rs, "after");
  17029. }else{
  17030. startNode = rs;
  17031. }
  17032. domConstruct.place(breaker, startNode, "after");
  17033. if(endNode){
  17034. domConstruct.place(endNode, breaker, "after");
  17035. }
  17036. domConstruct.destroy(rs);
  17037. var newrange = rangeapi.create();
  17038. newrange.setStart(sNode, 0);
  17039. newrange.setEnd(sNode, sNode.length);
  17040. selection.removeAllRanges();
  17041. selection.addRange(newrange);
  17042. doc.execCommand(command);
  17043. domConstruct.place(breaker.firstChild, breaker, "before");
  17044. domConstruct.destroy(breaker);
  17045. newrange.setStart(sNode, 0);
  17046. newrange.setEnd(sNode, sNode.length);
  17047. selection.removeAllRanges();
  17048. selection.addRange(newrange);
  17049. selectionapi.collapse(false);
  17050. sNode.parentNode.innerHTML = "";
  17051. }));
  17052. return true;
  17053. }
  17054. }
  17055. }else{
  17056. return false;
  17057. }
  17058. },
  17059. _adaptIEList: function(command /*===== , argument =====*/){
  17060. // summary:
  17061. // This function handles normalizing the IE list behavior as
  17062. // much as possible.
  17063. // command:
  17064. // The list command to execute.
  17065. // argument:
  17066. // Any additional argument.
  17067. // tags:
  17068. // private
  17069. var selection = rangeapi.getSelection(this.window);
  17070. if(selection.isCollapsed){
  17071. // In the case of no selection, lets commonize the behavior and
  17072. // make sure that it indents if needed.
  17073. if(selection.rangeCount && !this.queryCommandValue(command)){
  17074. var range = selection.getRangeAt(0);
  17075. var sc = range.startContainer;
  17076. if(sc && sc.nodeType == 3){
  17077. // text node. Lets see if there is a node before it that isn't
  17078. // some sort of breaker.
  17079. if(!range.startOffset){
  17080. // We're at the beginning of a text area. It may have been br split
  17081. // Who knows? In any event, we must create the list manually
  17082. // or IE may shove too much into the list element. It seems to
  17083. // grab content before the text node too if it's br split.
  17084. // Why can't IE work like everyone else?
  17085. win.withGlobal(this.window, lang.hitch(this, function(){
  17086. // Create a space, we'll select and bold it, so
  17087. // the whole word doesn't get bolded
  17088. var lType = "ul";
  17089. if(command === "insertorderedlist"){
  17090. lType = "ol";
  17091. }
  17092. var list = domConstruct.create(lType);
  17093. var li = domConstruct.create("li", null, list);
  17094. domConstruct.place(list, sc, "before");
  17095. // Move in the text node as part of the li.
  17096. li.appendChild(sc);
  17097. // We need a br after it or the enter key handler
  17098. // sometimes throws errors.
  17099. domConstruct.create("br", null, list, "after");
  17100. // Okay, now lets move our cursor to the beginning.
  17101. var newrange = rangeapi.create();
  17102. newrange.setStart(sc, 0);
  17103. newrange.setEnd(sc, sc.length);
  17104. selection.removeAllRanges();
  17105. selection.addRange(newrange);
  17106. selectionapi.collapse(true);
  17107. }));
  17108. return true;
  17109. }
  17110. }
  17111. }
  17112. }
  17113. return false;
  17114. },
  17115. _handleTextColorOrProperties: function(command, argument){
  17116. // summary:
  17117. // This function handles appplying text color as best it is
  17118. // able to do so when the selection is collapsed, making the
  17119. // behavior cross-browser consistent. It also handles the name
  17120. // and size for IE.
  17121. // command:
  17122. // The command.
  17123. // argument:
  17124. // Any additional arguments.
  17125. // tags:
  17126. // private
  17127. var selection = rangeapi.getSelection(this.window);
  17128. var doc = this.document;
  17129. var rs, ret, range, txt, startNode, endNode, breaker, sNode;
  17130. argument = argument || null;
  17131. if(command && selection && selection.isCollapsed){
  17132. if(selection.rangeCount){
  17133. range = selection.getRangeAt(0);
  17134. rs = range.startContainer;
  17135. if(rs && rs.nodeType === 3){
  17136. // Text node, we have to split it.
  17137. win.withGlobal(this.window, lang.hitch(this, function(){
  17138. var offset = range.startOffset;
  17139. if(rs.length < offset){
  17140. //We are not splitting the right node, try to locate the correct one
  17141. ret = this._adjustNodeAndOffset(rs, offset);
  17142. rs = ret.node;
  17143. offset = ret.offset;
  17144. }
  17145. txt = rs.nodeValue;
  17146. startNode = doc.createTextNode(txt.substring(0, offset));
  17147. var endText = txt.substring(offset);
  17148. if(endText !== ""){
  17149. endNode = doc.createTextNode(txt.substring(offset));
  17150. }
  17151. // Create a space, we'll select and bold it, so
  17152. // the whole word doesn't get bolded
  17153. breaker = domConstruct.create("span");
  17154. sNode = doc.createTextNode(".");
  17155. breaker.appendChild(sNode);
  17156. // Create a junk node to avoid it trying to stlye the breaker.
  17157. // This will get destroyed later.
  17158. var extraSpan = domConstruct.create("span");
  17159. breaker.appendChild(extraSpan);
  17160. if(startNode.length){
  17161. domConstruct.place(startNode, rs, "after");
  17162. }else{
  17163. startNode = rs;
  17164. }
  17165. domConstruct.place(breaker, startNode, "after");
  17166. if(endNode){
  17167. domConstruct.place(endNode, breaker, "after");
  17168. }
  17169. domConstruct.destroy(rs);
  17170. var newrange = rangeapi.create();
  17171. newrange.setStart(sNode, 0);
  17172. newrange.setEnd(sNode, sNode.length);
  17173. selection.removeAllRanges();
  17174. selection.addRange(newrange);
  17175. if(has("webkit")){
  17176. // WebKit is frustrating with positioning the cursor.
  17177. // It stinks to have a selected space, but there really
  17178. // isn't much choice here.
  17179. var style = "color";
  17180. if(command === "hilitecolor" || command === "backcolor"){
  17181. style = "backgroundColor";
  17182. }
  17183. domStyle.set(breaker, style, argument);
  17184. selectionapi.remove();
  17185. domConstruct.destroy(extraSpan);
  17186. breaker.innerHTML = "&#160;"; // &nbsp;
  17187. selectionapi.selectElement(breaker);
  17188. this.focus();
  17189. }else{
  17190. this.execCommand(command, argument);
  17191. domConstruct.place(breaker.firstChild, breaker, "before");
  17192. domConstruct.destroy(breaker);
  17193. newrange.setStart(sNode, 0);
  17194. newrange.setEnd(sNode, sNode.length);
  17195. selection.removeAllRanges();
  17196. selection.addRange(newrange);
  17197. selectionapi.collapse(false);
  17198. sNode.parentNode.removeChild(sNode);
  17199. }
  17200. }));
  17201. return true;
  17202. }
  17203. }
  17204. }
  17205. return false;
  17206. },
  17207. _adjustNodeAndOffset: function(/*DomNode*/node, /*Int*/offset){
  17208. // summary:
  17209. // In the case there are multiple text nodes in a row the offset may not be within the node.
  17210. // If the offset is larger than the node length, it will attempt to find
  17211. // the next text sibling until it locates the text node in which the offset refers to
  17212. // node:
  17213. // The node to check.
  17214. // offset:
  17215. // The position to find within the text node
  17216. // tags:
  17217. // private.
  17218. while(node.length < offset && node.nextSibling && node.nextSibling.nodeType === 3){
  17219. //Adjust the offset and node in the case of multiple text nodes in a row
  17220. offset = offset - node.length;
  17221. node = node.nextSibling;
  17222. }
  17223. return {"node": node, "offset": offset};
  17224. },
  17225. _tagNamesForCommand: function(command){
  17226. // summary:
  17227. // Function to return the tab names that are associated
  17228. // with a particular style.
  17229. // command: String
  17230. // The command to return tags for.
  17231. // tags:
  17232. // private
  17233. if(command === "bold"){
  17234. return ["b", "strong"];
  17235. }else if(command === "italic"){
  17236. return ["i","em"];
  17237. }else if(command === "strikethrough"){
  17238. return ["s", "strike"];
  17239. }else if(command === "superscript"){
  17240. return ["sup"];
  17241. }else if(command === "subscript"){
  17242. return ["sub"];
  17243. }else if(command === "underline"){
  17244. return ["u"];
  17245. }
  17246. return [];
  17247. },
  17248. _stripBreakerNodes: function(node){
  17249. // summary:
  17250. // Function for stripping out the breaker spans inserted by the formatting command.
  17251. // Registered as a filter for IE, handles the breaker spans needed to fix up
  17252. // How bold/italic/etc, work when selection is collapsed (single cursor).
  17253. win.withGlobal(this.window, lang.hitch(this, function(){
  17254. var breakers = query(".ieFormatBreakerSpan", node);
  17255. var i;
  17256. for(i = 0; i < breakers.length; i++){
  17257. var b = breakers[i];
  17258. while(b.firstChild){
  17259. domConstruct.place(b.firstChild, b, "before");
  17260. }
  17261. domConstruct.destroy(b);
  17262. }
  17263. }));
  17264. return node;
  17265. }
  17266. });
  17267. return RichText;
  17268. });
  17269. },
  17270. 'dojo/dnd/Moveable':function(){
  17271. define("dojo/dnd/Moveable", ["../main", "../Evented", "../touch", "./Mover"], function(dojo, Evented, touch) {
  17272. // module:
  17273. // dojo/dnd/Moveable
  17274. // summary:
  17275. // TODOC
  17276. /*=====
  17277. dojo.declare("dojo.dnd.__MoveableArgs", [], {
  17278. // handle: Node||String
  17279. // A node (or node's id), which is used as a mouse handle.
  17280. // If omitted, the node itself is used as a handle.
  17281. handle: null,
  17282. // delay: Number
  17283. // delay move by this number of pixels
  17284. delay: 0,
  17285. // skip: Boolean
  17286. // skip move of form elements
  17287. skip: false,
  17288. // mover: Object
  17289. // a constructor of custom Mover
  17290. mover: dojo.dnd.Mover
  17291. });
  17292. =====*/
  17293. dojo.declare("dojo.dnd.Moveable", [Evented], {
  17294. // object attributes (for markup)
  17295. handle: "",
  17296. delay: 0,
  17297. skip: false,
  17298. constructor: function(node, params){
  17299. // summary:
  17300. // an object, which makes a node moveable
  17301. // node: Node
  17302. // a node (or node's id) to be moved
  17303. // params: dojo.dnd.__MoveableArgs?
  17304. // optional parameters
  17305. this.node = dojo.byId(node);
  17306. if(!params){ params = {}; }
  17307. this.handle = params.handle ? dojo.byId(params.handle) : null;
  17308. if(!this.handle){ this.handle = this.node; }
  17309. this.delay = params.delay > 0 ? params.delay : 0;
  17310. this.skip = params.skip;
  17311. this.mover = params.mover ? params.mover : dojo.dnd.Mover;
  17312. this.events = [
  17313. dojo.connect(this.handle, touch.press, this, "onMouseDown"),
  17314. // cancel text selection and text dragging
  17315. dojo.connect(this.handle, "ondragstart", this, "onSelectStart"),
  17316. dojo.connect(this.handle, "onselectstart", this, "onSelectStart")
  17317. ];
  17318. },
  17319. // markup methods
  17320. markupFactory: function(params, node, ctor){
  17321. return new ctor(node, params);
  17322. },
  17323. // methods
  17324. destroy: function(){
  17325. // summary:
  17326. // stops watching for possible move, deletes all references, so the object can be garbage-collected
  17327. dojo.forEach(this.events, dojo.disconnect);
  17328. this.events = this.node = this.handle = null;
  17329. },
  17330. // mouse event processors
  17331. onMouseDown: function(e){
  17332. // summary:
  17333. // event processor for onmousedown/ontouchstart, creates a Mover for the node
  17334. // e: Event
  17335. // mouse/touch event
  17336. if(this.skip && dojo.dnd.isFormElement(e)){ return; }
  17337. if(this.delay){
  17338. this.events.push(
  17339. dojo.connect(this.handle, touch.move, this, "onMouseMove"),
  17340. dojo.connect(this.handle, touch.release, this, "onMouseUp")
  17341. );
  17342. this._lastX = e.pageX;
  17343. this._lastY = e.pageY;
  17344. }else{
  17345. this.onDragDetected(e);
  17346. }
  17347. dojo.stopEvent(e);
  17348. },
  17349. onMouseMove: function(e){
  17350. // summary:
  17351. // event processor for onmousemove/ontouchmove, used only for delayed drags
  17352. // e: Event
  17353. // mouse/touch event
  17354. if(Math.abs(e.pageX - this._lastX) > this.delay || Math.abs(e.pageY - this._lastY) > this.delay){
  17355. this.onMouseUp(e);
  17356. this.onDragDetected(e);
  17357. }
  17358. dojo.stopEvent(e);
  17359. },
  17360. onMouseUp: function(e){
  17361. // summary:
  17362. // event processor for onmouseup, used only for delayed drags
  17363. // e: Event
  17364. // mouse event
  17365. for(var i = 0; i < 2; ++i){
  17366. dojo.disconnect(this.events.pop());
  17367. }
  17368. dojo.stopEvent(e);
  17369. },
  17370. onSelectStart: function(e){
  17371. // summary:
  17372. // event processor for onselectevent and ondragevent
  17373. // e: Event
  17374. // mouse event
  17375. if(!this.skip || !dojo.dnd.isFormElement(e)){
  17376. dojo.stopEvent(e);
  17377. }
  17378. },
  17379. // local events
  17380. onDragDetected: function(/* Event */ e){
  17381. // summary:
  17382. // called when the drag is detected;
  17383. // responsible for creation of the mover
  17384. new this.mover(this.node, e, this);
  17385. },
  17386. onMoveStart: function(/* dojo.dnd.Mover */ mover){
  17387. // summary:
  17388. // called before every move operation
  17389. dojo.publish("/dnd/move/start", [mover]);
  17390. dojo.addClass(dojo.body(), "dojoMove");
  17391. dojo.addClass(this.node, "dojoMoveItem");
  17392. },
  17393. onMoveStop: function(/* dojo.dnd.Mover */ mover){
  17394. // summary:
  17395. // called after every move operation
  17396. dojo.publish("/dnd/move/stop", [mover]);
  17397. dojo.removeClass(dojo.body(), "dojoMove");
  17398. dojo.removeClass(this.node, "dojoMoveItem");
  17399. },
  17400. onFirstMove: function(/* dojo.dnd.Mover */ mover, /* Event */ e){
  17401. // summary:
  17402. // called during the very first move notification;
  17403. // can be used to initialize coordinates, can be overwritten.
  17404. // default implementation does nothing
  17405. },
  17406. onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop, /* Event */ e){
  17407. // summary:
  17408. // called during every move notification;
  17409. // should actually move the node; can be overwritten.
  17410. this.onMoving(mover, leftTop);
  17411. var s = mover.node.style;
  17412. s.left = leftTop.l + "px";
  17413. s.top = leftTop.t + "px";
  17414. this.onMoved(mover, leftTop);
  17415. },
  17416. onMoving: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
  17417. // summary:
  17418. // called before every incremental move; can be overwritten.
  17419. // default implementation does nothing
  17420. },
  17421. onMoved: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
  17422. // summary:
  17423. // called after every incremental move; can be overwritten.
  17424. // default implementation does nothing
  17425. }
  17426. });
  17427. return dojo.dnd.Moveable;
  17428. });
  17429. },
  17430. 'dojo/store/util/SimpleQueryEngine':function(){
  17431. define("dojo/store/util/SimpleQueryEngine", ["../../_base/array"], function(arrayUtil) {
  17432. // module:
  17433. // dojo/store/util/SimpleQueryEngine
  17434. // summary:
  17435. // The module defines a simple filtering query engine for object stores.
  17436. return function(query, options){
  17437. // summary:
  17438. // Simple query engine that matches using filter functions, named filter
  17439. // functions or objects by name-value on a query object hash
  17440. //
  17441. // description:
  17442. // The SimpleQueryEngine provides a way of getting a QueryResults through
  17443. // the use of a simple object hash as a filter. The hash will be used to
  17444. // match properties on data objects with the corresponding value given. In
  17445. // other words, only exact matches will be returned.
  17446. //
  17447. // This function can be used as a template for more complex query engines;
  17448. // for example, an engine can be created that accepts an object hash that
  17449. // contains filtering functions, or a string that gets evaluated, etc.
  17450. //
  17451. // When creating a new dojo.store, simply set the store's queryEngine
  17452. // field as a reference to this function.
  17453. //
  17454. // query: Object
  17455. // An object hash with fields that may match fields of items in the store.
  17456. // Values in the hash will be compared by normal == operator, but regular expressions
  17457. // or any object that provides a test() method are also supported and can be
  17458. // used to match strings by more complex expressions
  17459. // (and then the regex's or object's test() method will be used to match values).
  17460. //
  17461. // options: dojo.store.util.SimpleQueryEngine.__queryOptions?
  17462. // An object that contains optional information such as sort, start, and count.
  17463. //
  17464. // returns: Function
  17465. // A function that caches the passed query under the field "matches". See any
  17466. // of the "query" methods on dojo.stores.
  17467. //
  17468. // example:
  17469. // Define a store with a reference to this engine, and set up a query method.
  17470. //
  17471. // | var myStore = function(options){
  17472. // | // ...more properties here
  17473. // | this.queryEngine = dojo.store.util.SimpleQueryEngine;
  17474. // | // define our query method
  17475. // | this.query = function(query, options){
  17476. // | return dojo.store.util.QueryResults(this.queryEngine(query, options)(this.data));
  17477. // | };
  17478. // | };
  17479. // create our matching query function
  17480. switch(typeof query){
  17481. default:
  17482. throw new Error("Can not query with a " + typeof query);
  17483. case "object": case "undefined":
  17484. var queryObject = query;
  17485. query = function(object){
  17486. for(var key in queryObject){
  17487. var required = queryObject[key];
  17488. if(required && required.test){
  17489. if(!required.test(object[key])){
  17490. return false;
  17491. }
  17492. }else if(required != object[key]){
  17493. return false;
  17494. }
  17495. }
  17496. return true;
  17497. };
  17498. break;
  17499. case "string":
  17500. // named query
  17501. if(!this[query]){
  17502. throw new Error("No filter function " + query + " was found in store");
  17503. }
  17504. query = this[query];
  17505. // fall through
  17506. case "function":
  17507. // fall through
  17508. }
  17509. function execute(array){
  17510. // execute the whole query, first we filter
  17511. var results = arrayUtil.filter(array, query);
  17512. // next we sort
  17513. if(options && options.sort){
  17514. results.sort(function(a, b){
  17515. for(var sort, i=0; sort = options.sort[i]; i++){
  17516. var aValue = a[sort.attribute];
  17517. var bValue = b[sort.attribute];
  17518. if (aValue != bValue) {
  17519. return !!sort.descending == aValue > bValue ? -1 : 1;
  17520. }
  17521. }
  17522. return 0;
  17523. });
  17524. }
  17525. // now we paginate
  17526. if(options && (options.start || options.count)){
  17527. var total = results.length;
  17528. results = results.slice(options.start || 0, (options.start || 0) + (options.count || Infinity));
  17529. results.total = total;
  17530. }
  17531. return results;
  17532. }
  17533. execute.matches = query;
  17534. return execute;
  17535. };
  17536. });
  17537. },
  17538. 'dojox/grid/_View':function(){
  17539. require({cache:{
  17540. 'url:dojox/grid/resources/View.html':"<div class=\"dojoxGridView\" role=\"presentation\">\r\n\t<div class=\"dojoxGridHeader\" dojoAttachPoint=\"headerNode\" role=\"presentation\">\r\n\t\t<div dojoAttachPoint=\"headerNodeContainer\" style=\"width:9000em\" role=\"presentation\">\r\n\t\t\t<div dojoAttachPoint=\"headerContentNode\" role=\"row\"></div>\r\n\t\t</div>\r\n\t</div>\r\n\t<input type=\"checkbox\" class=\"dojoxGridHiddenFocus\" dojoAttachPoint=\"hiddenFocusNode\" role=\"presentation\" />\r\n\t<input type=\"checkbox\" class=\"dojoxGridHiddenFocus\" role=\"presentation\" />\r\n\t<div class=\"dojoxGridScrollbox\" dojoAttachPoint=\"scrollboxNode\" role=\"presentation\">\r\n\t\t<div class=\"dojoxGridContent\" dojoAttachPoint=\"contentNode\" hidefocus=\"hidefocus\" role=\"presentation\"></div>\r\n\t</div>\r\n</div>\r\n"}});
  17541. define("dojox/grid/_View", [
  17542. "dojo",
  17543. "dijit/registry",
  17544. "../main",
  17545. "dojo/_base/declare",
  17546. "dojo/_base/array",
  17547. "dojo/_base/lang",
  17548. "dojo/_base/connect",
  17549. "dojo/_base/sniff",
  17550. "dojo/query",
  17551. "dojo/_base/window",
  17552. "dojo/text!./resources/View.html",
  17553. "dojo/dnd/Source",
  17554. "dijit/_Widget",
  17555. "dijit/_TemplatedMixin",
  17556. "dojox/html/metrics",
  17557. "./util",
  17558. "dojo/_base/html",
  17559. "./_Builder",
  17560. "dojo/dnd/Avatar",
  17561. "dojo/dnd/Manager"
  17562. ], function(dojo, dijit, dojox, declare, array, lang, connect, has, query,
  17563. win, template, Source, _Widget, _TemplatedMixin, metrics, util, html, _Builder, Avatar){
  17564. // a private function
  17565. var getStyleText = function(inNode, inStyleText){
  17566. return inNode.style.cssText == undefined ? inNode.getAttribute("style") : inNode.style.cssText;
  17567. };
  17568. // some public functions
  17569. var _View = declare('dojox.grid._View', [_Widget, _TemplatedMixin], {
  17570. // summary:
  17571. // A collection of grid columns. A grid is comprised of a set of views that stack horizontally.
  17572. // Grid creates views automatically based on grid's layout structure.
  17573. // Users should typically not need to access individual views directly.
  17574. //
  17575. // defaultWidth: String
  17576. // Default width of the view
  17577. defaultWidth: "18em",
  17578. // viewWidth: String
  17579. // Width for the view, in valid css unit
  17580. viewWidth: "",
  17581. templateString: template,
  17582. themeable: false,
  17583. classTag: 'dojoxGrid',
  17584. marginBottom: 0,
  17585. rowPad: 2,
  17586. // _togglingColumn: int
  17587. // Width of the column being toggled (-1 for none)
  17588. _togglingColumn: -1,
  17589. // _headerBuilderClass: Object
  17590. // The class to use for our header builder
  17591. _headerBuilderClass: _Builder._HeaderBuilder,
  17592. // _contentBuilderClass: Object
  17593. // The class to use for our content builder
  17594. _contentBuilderClass: _Builder._ContentBuilder,
  17595. postMixInProperties: function(){
  17596. this.rowNodes = {};
  17597. },
  17598. postCreate: function(){
  17599. this.connect(this.scrollboxNode,"onscroll","doscroll");
  17600. util.funnelEvents(this.contentNode, this, "doContentEvent", [ 'mouseover', 'mouseout', 'click', 'dblclick', 'contextmenu', 'mousedown' ]);
  17601. util.funnelEvents(this.headerNode, this, "doHeaderEvent", [ 'dblclick', 'mouseover', 'mouseout', 'mousemove', 'mousedown', 'click', 'contextmenu' ]);
  17602. this.content = new this._contentBuilderClass(this);
  17603. this.header = new this._headerBuilderClass(this);
  17604. //BiDi: in RTL case, style width='9000em' causes scrolling problem in head node
  17605. if(!this.grid.isLeftToRight()){
  17606. this.headerNodeContainer.style.width = "";
  17607. }
  17608. },
  17609. destroy: function(){
  17610. html.destroy(this.headerNode);
  17611. delete this.headerNode;
  17612. for(var i in this.rowNodes){
  17613. this._cleanupRowWidgets(this.rowNodes[i]);
  17614. html.destroy(this.rowNodes[i]);
  17615. }
  17616. this.rowNodes = {};
  17617. if(this.source){
  17618. this.source.destroy();
  17619. }
  17620. this.inherited(arguments);
  17621. },
  17622. // focus
  17623. focus: function(){
  17624. if(has("ie") || has("webkit") || has("opera")){
  17625. this.hiddenFocusNode.focus();
  17626. }else{
  17627. this.scrollboxNode.focus();
  17628. }
  17629. },
  17630. setStructure: function(inStructure){
  17631. var vs = (this.structure = inStructure);
  17632. // FIXME: similar logic is duplicated in layout
  17633. if(vs.width && !isNaN(vs.width)){
  17634. this.viewWidth = vs.width + 'em';
  17635. }else{
  17636. this.viewWidth = vs.width || (vs.noscroll ? 'auto' : this.viewWidth); //|| this.defaultWidth;
  17637. }
  17638. this._onBeforeRow = vs.onBeforeRow||function(){};
  17639. this._onAfterRow = vs.onAfterRow||function(){};
  17640. this.noscroll = vs.noscroll;
  17641. if(this.noscroll){
  17642. this.scrollboxNode.style.overflow = "hidden";
  17643. }
  17644. this.simpleStructure = Boolean(vs.cells.length == 1);
  17645. // bookkeeping
  17646. this.testFlexCells();
  17647. // accomodate new structure
  17648. this.updateStructure();
  17649. },
  17650. _cleanupRowWidgets: function(inRowNode){
  17651. // Summary:
  17652. // Cleans up the widgets for the given row node so that
  17653. // we can reattach them if needed
  17654. if(inRowNode){
  17655. array.forEach(query("[widgetId]", inRowNode).map(dijit.byNode), function(w){
  17656. if(w._destroyOnRemove){
  17657. w.destroy();
  17658. delete w;
  17659. }else if(w.domNode && w.domNode.parentNode){
  17660. w.domNode.parentNode.removeChild(w.domNode);
  17661. }
  17662. });
  17663. }
  17664. },
  17665. onBeforeRow: function(inRowIndex, cells){
  17666. this._onBeforeRow(inRowIndex, cells);
  17667. if(inRowIndex >= 0){
  17668. this._cleanupRowWidgets(this.getRowNode(inRowIndex));
  17669. }
  17670. },
  17671. onAfterRow: function(inRowIndex, cells, inRowNode){
  17672. this._onAfterRow(inRowIndex, cells, inRowNode);
  17673. var g = this.grid;
  17674. array.forEach(query(".dojoxGridStubNode", inRowNode), function(n){
  17675. if(n && n.parentNode){
  17676. var lw = n.getAttribute("linkWidget");
  17677. var cellIdx = window.parseInt(html.attr(n, "cellIdx"), 10);
  17678. var cellDef = g.getCell(cellIdx);
  17679. var w = dijit.byId(lw);
  17680. if(w){
  17681. n.parentNode.replaceChild(w.domNode, n);
  17682. if(!w._started){
  17683. w.startup();
  17684. }
  17685. dojo.destroy(n);
  17686. }else{
  17687. n.innerHTML = "";
  17688. }
  17689. }
  17690. }, this);
  17691. },
  17692. testFlexCells: function(){
  17693. // FIXME: cheater, this function does double duty as initializer and tester
  17694. this.flexCells = false;
  17695. for(var j=0, row; (row=this.structure.cells[j]); j++){
  17696. for(var i=0, cell; (cell=row[i]); i++){
  17697. cell.view = this;
  17698. this.flexCells = this.flexCells || cell.isFlex();
  17699. }
  17700. }
  17701. return this.flexCells;
  17702. },
  17703. updateStructure: function(){
  17704. // header builder needs to update table map
  17705. this.header.update();
  17706. // content builder needs to update markup cache
  17707. this.content.update();
  17708. },
  17709. getScrollbarWidth: function(){
  17710. var hasScrollSpace = this.hasVScrollbar();
  17711. var overflow = html.style(this.scrollboxNode, "overflow");
  17712. if(this.noscroll || !overflow || overflow == "hidden"){
  17713. hasScrollSpace = false;
  17714. }else if(overflow == "scroll"){
  17715. hasScrollSpace = true;
  17716. }
  17717. return (hasScrollSpace ? metrics.getScrollbar().w : 0); // Integer
  17718. },
  17719. getColumnsWidth: function(){
  17720. var h = this.headerContentNode;
  17721. return h && h.firstChild ? h.firstChild.offsetWidth : 0; // Integer
  17722. },
  17723. setColumnsWidth: function(width){
  17724. this.headerContentNode.firstChild.style.width = width + 'px';
  17725. if(this.viewWidth){
  17726. this.viewWidth = width + 'px';
  17727. }
  17728. },
  17729. getWidth: function(){
  17730. return this.viewWidth || (this.getColumnsWidth()+this.getScrollbarWidth()) +'px'; // String
  17731. },
  17732. getContentWidth: function(){
  17733. return Math.max(0, html._getContentBox(this.domNode).w - this.getScrollbarWidth()) + 'px'; // String
  17734. },
  17735. render: function(){
  17736. this.scrollboxNode.style.height = '';
  17737. this.renderHeader();
  17738. if(this._togglingColumn >= 0){
  17739. this.setColumnsWidth(this.getColumnsWidth() - this._togglingColumn);
  17740. this._togglingColumn = -1;
  17741. }
  17742. var cells = this.grid.layout.cells;
  17743. var getSibling = lang.hitch(this, function(node, before){
  17744. !this.grid.isLeftToRight() && (before = !before);
  17745. var inc = before?-1:1;
  17746. var idx = this.header.getCellNodeIndex(node) + inc;
  17747. var cell = cells[idx];
  17748. while(cell && cell.getHeaderNode() && cell.getHeaderNode().style.display == "none"){
  17749. idx += inc;
  17750. cell = cells[idx];
  17751. }
  17752. if(cell){
  17753. return cell.getHeaderNode();
  17754. }
  17755. return null;
  17756. });
  17757. if(this.grid.columnReordering && this.simpleStructure){
  17758. if(this.source){
  17759. this.source.destroy();
  17760. }
  17761. // Create the top and bottom markers
  17762. var bottomMarkerId = "dojoxGrid_bottomMarker";
  17763. var topMarkerId = "dojoxGrid_topMarker";
  17764. if(this.bottomMarker){
  17765. html.destroy(this.bottomMarker);
  17766. }
  17767. this.bottomMarker = html.byId(bottomMarkerId);
  17768. if(this.topMarker){
  17769. html.destroy(this.topMarker);
  17770. }
  17771. this.topMarker = html.byId(topMarkerId);
  17772. if (!this.bottomMarker) {
  17773. this.bottomMarker = html.create("div", {
  17774. "id": bottomMarkerId,
  17775. "class": "dojoxGridColPlaceBottom"
  17776. }, win.body());
  17777. this._hide(this.bottomMarker);
  17778. this.topMarker = html.create("div", {
  17779. "id": topMarkerId,
  17780. "class": "dojoxGridColPlaceTop"
  17781. }, win.body());
  17782. this._hide(this.topMarker);
  17783. }
  17784. this.arrowDim = html.contentBox(this.bottomMarker);
  17785. var headerHeight = html.contentBox(this.headerContentNode.firstChild.rows[0]).h;
  17786. this.source = new Source(this.headerContentNode.firstChild.rows[0], {
  17787. horizontal: true,
  17788. accept: [ "gridColumn_" + this.grid.id ],
  17789. viewIndex: this.index,
  17790. generateText: false,
  17791. onMouseDown: lang.hitch(this, function(e){
  17792. this.header.decorateEvent(e);
  17793. if((this.header.overRightResizeArea(e) || this.header.overLeftResizeArea(e)) &&
  17794. this.header.canResize(e) && !this.header.moveable){
  17795. this.header.beginColumnResize(e);
  17796. }else{
  17797. if(this.grid.headerMenu){
  17798. this.grid.headerMenu.onCancel(true);
  17799. }
  17800. // IE reports a left click as 1, where everything else reports 0
  17801. if(e.button === (has("ie") < 9 ? 1 : 0)){
  17802. Source.prototype.onMouseDown.call(this.source, e);
  17803. }
  17804. }
  17805. }),
  17806. onMouseOver: lang.hitch(this, function(e){
  17807. var src = this.source;
  17808. if(src._getChildByEvent(e)){
  17809. Source.prototype.onMouseOver.apply(src, arguments);
  17810. }
  17811. }),
  17812. _markTargetAnchor: lang.hitch(this, function(before){
  17813. var src = this.source;
  17814. if(src.current == src.targetAnchor && src.before == before){ return; }
  17815. if(src.targetAnchor && getSibling(src.targetAnchor, src.before)){
  17816. src._removeItemClass(getSibling(src.targetAnchor, src.before), src.before ? "After" : "Before");
  17817. }
  17818. Source.prototype._markTargetAnchor.call(src, before);
  17819. var target = before ? src.targetAnchor : getSibling(src.targetAnchor, src.before);
  17820. var endAdd = 0;
  17821. if (!target) {
  17822. target = src.targetAnchor;
  17823. endAdd = html.contentBox(target).w + this.arrowDim.w/2 + 2;
  17824. }
  17825. var pos = html.position(target, true);
  17826. var left = Math.floor(pos.x - this.arrowDim.w/2 + endAdd);
  17827. html.style(this.bottomMarker, "visibility", "visible");
  17828. html.style(this.topMarker, "visibility", "visible");
  17829. html.style(this.bottomMarker, {
  17830. "left": left + "px",
  17831. "top" : (headerHeight + pos.y) + "px"
  17832. });
  17833. html.style(this.topMarker, {
  17834. "left": left + "px",
  17835. "top" : (pos.y - this.arrowDim.h) + "px"
  17836. });
  17837. if(src.targetAnchor && getSibling(src.targetAnchor, src.before)){
  17838. src._addItemClass(getSibling(src.targetAnchor, src.before), src.before ? "After" : "Before");
  17839. }
  17840. }),
  17841. _unmarkTargetAnchor: lang.hitch(this, function(){
  17842. var src = this.source;
  17843. if(!src.targetAnchor){ return; }
  17844. if(src.targetAnchor && getSibling(src.targetAnchor, src.before)){
  17845. src._removeItemClass(getSibling(src.targetAnchor, src.before), src.before ? "After" : "Before");
  17846. }
  17847. this._hide(this.bottomMarker);
  17848. this._hide(this.topMarker);
  17849. Source.prototype._unmarkTargetAnchor.call(src);
  17850. }),
  17851. destroy: lang.hitch(this, function(){
  17852. connect.disconnect(this._source_conn);
  17853. connect.unsubscribe(this._source_sub);
  17854. Source.prototype.destroy.call(this.source);
  17855. if(this.bottomMarker){
  17856. html.destroy(this.bottomMarker);
  17857. delete this.bottomMarker;
  17858. }
  17859. if(this.topMarker){
  17860. html.destroy(this.topMarker);
  17861. delete this.topMarker;
  17862. }
  17863. }),
  17864. onDndCancel: lang.hitch(this, function(){
  17865. Source.prototype.onDndCancel.call(this.source);
  17866. this._hide(this.bottomMarker);
  17867. this._hide(this.topMarker);
  17868. })
  17869. });
  17870. this._source_conn = connect.connect(this.source, "onDndDrop", this, "_onDndDrop");
  17871. this._source_sub = connect.subscribe("/dnd/drop/before", this, "_onDndDropBefore");
  17872. this.source.startup();
  17873. }
  17874. },
  17875. _hide: function(node){
  17876. html.style(node, {
  17877. top: "-10000px",
  17878. "visibility": "hidden"
  17879. });
  17880. },
  17881. _onDndDropBefore: function(source, nodes, copy){
  17882. if(dojo.dnd.manager().target !== this.source){
  17883. return;
  17884. }
  17885. this.source._targetNode = this.source.targetAnchor;
  17886. this.source._beforeTarget = this.source.before;
  17887. var views = this.grid.views.views;
  17888. var srcView = views[source.viewIndex];
  17889. var tgtView = views[this.index];
  17890. if(tgtView != srcView){
  17891. srcView.convertColPctToFixed();
  17892. tgtView.convertColPctToFixed();
  17893. }
  17894. },
  17895. _onDndDrop: function(source, nodes, copy){
  17896. if(dojo.dnd.manager().target !== this.source){
  17897. if(dojo.dnd.manager().source === this.source){
  17898. this._removingColumn = true;
  17899. }
  17900. return;
  17901. }
  17902. this._hide(this.bottomMarker);
  17903. this._hide(this.topMarker);
  17904. var getIdx = function(n){
  17905. return n ? html.attr(n, "idx") : null;
  17906. };
  17907. var w = html.marginBox(nodes[0]).w;
  17908. if(source.viewIndex !== this.index){
  17909. var views = this.grid.views.views;
  17910. var srcView = views[source.viewIndex];
  17911. var tgtView = views[this.index];
  17912. if(srcView.viewWidth && srcView.viewWidth != "auto"){
  17913. srcView.setColumnsWidth(srcView.getColumnsWidth() - w);
  17914. }
  17915. if(tgtView.viewWidth && tgtView.viewWidth != "auto"){
  17916. tgtView.setColumnsWidth(tgtView.getColumnsWidth());
  17917. }
  17918. }
  17919. var stn = this.source._targetNode;
  17920. var stb = this.source._beforeTarget;
  17921. !this.grid.isLeftToRight() && (stb = !stb);
  17922. var layout = this.grid.layout;
  17923. var idx = this.index;
  17924. delete this.source._targetNode;
  17925. delete this.source._beforeTarget;
  17926. layout.moveColumn(
  17927. source.viewIndex,
  17928. idx,
  17929. getIdx(nodes[0]),
  17930. getIdx(stn),
  17931. stb);
  17932. },
  17933. renderHeader: function(){
  17934. this.headerContentNode.innerHTML = this.header.generateHtml(this._getHeaderContent);
  17935. if(this.flexCells){
  17936. this.contentWidth = this.getContentWidth();
  17937. this.headerContentNode.firstChild.style.width = this.contentWidth;
  17938. }
  17939. util.fire(this, "onAfterRow", [-1, this.structure.cells, this.headerContentNode]);
  17940. },
  17941. // note: not called in 'view' context
  17942. _getHeaderContent: function(inCell){
  17943. var n = inCell.name || inCell.grid.getCellName(inCell);
  17944. if(/^\s+$/.test(n)){
  17945. n = '&nbsp;'//otherwise arrow styles will be messed up
  17946. }
  17947. var ret = [ '<div class="dojoxGridSortNode' ];
  17948. if(inCell.index != inCell.grid.getSortIndex()){
  17949. ret.push('">');
  17950. }else{
  17951. ret = ret.concat([ ' ',
  17952. inCell.grid.sortInfo > 0 ? 'dojoxGridSortUp' : 'dojoxGridSortDown',
  17953. '"><div class="dojoxGridArrowButtonChar">',
  17954. inCell.grid.sortInfo > 0 ? '&#9650;' : '&#9660;',
  17955. '</div><div class="dojoxGridArrowButtonNode" role="presentation"></div>',
  17956. '<div class="dojoxGridColCaption">']);
  17957. }
  17958. ret = ret.concat([n, '</div></div>']);
  17959. return ret.join('');
  17960. },
  17961. resize: function(){
  17962. this.adaptHeight();
  17963. this.adaptWidth();
  17964. },
  17965. hasHScrollbar: function(reset){
  17966. var hadScroll = this._hasHScroll||false;
  17967. if(this._hasHScroll == undefined || reset){
  17968. if(this.noscroll){
  17969. this._hasHScroll = false;
  17970. }else{
  17971. var style = html.style(this.scrollboxNode, "overflow");
  17972. if(style == "hidden"){
  17973. this._hasHScroll = false;
  17974. }else if(style == "scroll"){
  17975. this._hasHScroll = true;
  17976. }else{
  17977. this._hasHScroll = (this.scrollboxNode.offsetWidth - this.getScrollbarWidth() < this.contentNode.offsetWidth );
  17978. }
  17979. }
  17980. }
  17981. if(hadScroll !== this._hasHScroll){
  17982. this.grid.update();
  17983. }
  17984. return this._hasHScroll; // Boolean
  17985. },
  17986. hasVScrollbar: function(reset){
  17987. var hadScroll = this._hasVScroll||false;
  17988. if(this._hasVScroll == undefined || reset){
  17989. if(this.noscroll){
  17990. this._hasVScroll = false;
  17991. }else{
  17992. var style = html.style(this.scrollboxNode, "overflow");
  17993. if(style == "hidden"){
  17994. this._hasVScroll = false;
  17995. }else if(style == "scroll"){
  17996. this._hasVScroll = true;
  17997. }else{
  17998. this._hasVScroll = (this.scrollboxNode.scrollHeight > this.scrollboxNode.clientHeight);
  17999. }
  18000. }
  18001. }
  18002. if(hadScroll !== this._hasVScroll){
  18003. this.grid.update();
  18004. }
  18005. return this._hasVScroll; // Boolean
  18006. },
  18007. convertColPctToFixed: function(){
  18008. // Fix any percentage widths to be pixel values
  18009. var hasPct = false;
  18010. this.grid.initialWidth = "";
  18011. var cellNodes = query("th", this.headerContentNode);
  18012. var fixedWidths = array.map(cellNodes, function(c, vIdx){
  18013. var w = c.style.width;
  18014. html.attr(c, "vIdx", vIdx);
  18015. if(w && w.slice(-1) == "%"){
  18016. hasPct = true;
  18017. }else if(w && w.slice(-2) == "px"){
  18018. return window.parseInt(w, 10);
  18019. }
  18020. return html.contentBox(c).w;
  18021. });
  18022. if(hasPct){
  18023. array.forEach(this.grid.layout.cells, function(cell, idx){
  18024. if(cell.view == this){
  18025. var cellNode = cell.view.getHeaderCellNode(cell.index);
  18026. if(cellNode && html.hasAttr(cellNode, "vIdx")){
  18027. var vIdx = window.parseInt(html.attr(cellNode, "vIdx"));
  18028. this.setColWidth(idx, fixedWidths[vIdx]);
  18029. html.removeAttr(cellNode, "vIdx");
  18030. }
  18031. }
  18032. }, this);
  18033. return true;
  18034. }
  18035. return false;
  18036. },
  18037. adaptHeight: function(minusScroll){
  18038. if(!this.grid._autoHeight){
  18039. var h = (this.domNode.style.height && parseInt(this.domNode.style.height.replace(/px/,''), 10)) || this.domNode.clientHeight;
  18040. var self = this;
  18041. var checkOtherViewScrollers = function(){
  18042. var v;
  18043. for(var i in self.grid.views.views){
  18044. v = self.grid.views.views[i];
  18045. if(v !== self && v.hasHScrollbar()){
  18046. return true;
  18047. }
  18048. }
  18049. return false;
  18050. };
  18051. if(minusScroll || (this.noscroll && checkOtherViewScrollers())){
  18052. h -= metrics.getScrollbar().h;
  18053. }
  18054. util.setStyleHeightPx(this.scrollboxNode, h);
  18055. }
  18056. this.hasVScrollbar(true);
  18057. },
  18058. adaptWidth: function(){
  18059. if(this.flexCells){
  18060. // the view content width
  18061. this.contentWidth = this.getContentWidth();
  18062. this.headerContentNode.firstChild.style.width = this.contentWidth;
  18063. }
  18064. // FIXME: it should be easier to get w from this.scrollboxNode.clientWidth,
  18065. // but clientWidth seemingly does not include scrollbar width in some cases
  18066. var w = this.scrollboxNode.offsetWidth - this.getScrollbarWidth();
  18067. if(!this._removingColumn){
  18068. w = Math.max(w, this.getColumnsWidth()) + 'px';
  18069. }else{
  18070. w = Math.min(w, this.getColumnsWidth()) + 'px';
  18071. this._removingColumn = false;
  18072. }
  18073. var cn = this.contentNode;
  18074. cn.style.width = w;
  18075. this.hasHScrollbar(true);
  18076. },
  18077. setSize: function(w, h){
  18078. var ds = this.domNode.style;
  18079. var hs = this.headerNode.style;
  18080. if(w){
  18081. ds.width = w;
  18082. hs.width = w;
  18083. }
  18084. ds.height = (h >= 0 ? h + 'px' : '');
  18085. },
  18086. renderRow: function(inRowIndex){
  18087. var rowNode = this.createRowNode(inRowIndex);
  18088. this.buildRow(inRowIndex, rowNode);
  18089. //this.grid.edit.restore(this, inRowIndex);
  18090. return rowNode;
  18091. },
  18092. createRowNode: function(inRowIndex){
  18093. var node = document.createElement("div");
  18094. node.className = this.classTag + 'Row';
  18095. if (this instanceof dojox.grid._RowSelector){
  18096. html.attr(node,"role","presentation");
  18097. }else{
  18098. html.attr(node,"role","row");
  18099. if (this.grid.selectionMode != "none") {
  18100. node.setAttribute("aria-selected", "false"); //rows can be selected so add aria-selected prop
  18101. }
  18102. }
  18103. node[util.gridViewTag] = this.id;
  18104. node[util.rowIndexTag] = inRowIndex;
  18105. this.rowNodes[inRowIndex] = node;
  18106. return node;
  18107. },
  18108. buildRow: function(inRowIndex, inRowNode){
  18109. this.buildRowContent(inRowIndex, inRowNode);
  18110. this.styleRow(inRowIndex, inRowNode);
  18111. },
  18112. buildRowContent: function(inRowIndex, inRowNode){
  18113. inRowNode.innerHTML = this.content.generateHtml(inRowIndex, inRowIndex);
  18114. if(this.flexCells && this.contentWidth){
  18115. // FIXME: accessing firstChild here breaks encapsulation
  18116. inRowNode.firstChild.style.width = this.contentWidth;
  18117. }
  18118. util.fire(this, "onAfterRow", [inRowIndex, this.structure.cells, inRowNode]);
  18119. },
  18120. rowRemoved:function(inRowIndex){
  18121. if(inRowIndex >= 0){
  18122. this._cleanupRowWidgets(this.getRowNode(inRowIndex));
  18123. }
  18124. this.grid.edit.save(this, inRowIndex);
  18125. delete this.rowNodes[inRowIndex];
  18126. },
  18127. getRowNode: function(inRowIndex){
  18128. return this.rowNodes[inRowIndex];
  18129. },
  18130. getCellNode: function(inRowIndex, inCellIndex){
  18131. var row = this.getRowNode(inRowIndex);
  18132. if(row){
  18133. return this.content.getCellNode(row, inCellIndex);
  18134. }
  18135. },
  18136. getHeaderCellNode: function(inCellIndex){
  18137. if(this.headerContentNode){
  18138. return this.header.getCellNode(this.headerContentNode, inCellIndex);
  18139. }
  18140. },
  18141. // styling
  18142. styleRow: function(inRowIndex, inRowNode){
  18143. inRowNode._style = getStyleText(inRowNode);
  18144. this.styleRowNode(inRowIndex, inRowNode);
  18145. },
  18146. styleRowNode: function(inRowIndex, inRowNode){
  18147. if(inRowNode){
  18148. this.doStyleRowNode(inRowIndex, inRowNode);
  18149. }
  18150. },
  18151. doStyleRowNode: function(inRowIndex, inRowNode){
  18152. this.grid.styleRowNode(inRowIndex, inRowNode);
  18153. },
  18154. // updating
  18155. updateRow: function(inRowIndex){
  18156. var rowNode = this.getRowNode(inRowIndex);
  18157. if(rowNode){
  18158. rowNode.style.height = '';
  18159. this.buildRow(inRowIndex, rowNode);
  18160. }
  18161. return rowNode;
  18162. },
  18163. updateRowStyles: function(inRowIndex){
  18164. this.styleRowNode(inRowIndex, this.getRowNode(inRowIndex));
  18165. },
  18166. // scrolling
  18167. lastTop: 0,
  18168. firstScroll:0,
  18169. _nativeScroll: false,
  18170. doscroll: function(inEvent){
  18171. if(has("ff") >= 13){
  18172. this._nativeScroll = true;
  18173. }
  18174. //var s = dojo.marginBox(this.headerContentNode.firstChild);
  18175. var isLtr = this.grid.isLeftToRight();
  18176. if(this.firstScroll < 2){
  18177. if((!isLtr && this.firstScroll == 1) || (isLtr && this.firstScroll === 0)){
  18178. var s = html.marginBox(this.headerNodeContainer);
  18179. if(has("ie")){
  18180. this.headerNodeContainer.style.width = s.w + this.getScrollbarWidth() + 'px';
  18181. }else if(has("mozilla")){
  18182. //TODO currently only for FF, not sure for safari and opera
  18183. this.headerNodeContainer.style.width = s.w - this.getScrollbarWidth() + 'px';
  18184. //this.headerNodeContainer.style.width = s.w + 'px';
  18185. //set scroll to right in FF
  18186. this.scrollboxNode.scrollLeft = isLtr ?
  18187. this.scrollboxNode.clientWidth - this.scrollboxNode.scrollWidth :
  18188. this.scrollboxNode.scrollWidth - this.scrollboxNode.clientWidth;
  18189. }
  18190. }
  18191. this.firstScroll++;
  18192. }
  18193. this.headerNode.scrollLeft = this.scrollboxNode.scrollLeft;
  18194. // 'lastTop' is a semaphore to prevent feedback-loop with setScrollTop below
  18195. var top = this.scrollboxNode.scrollTop;
  18196. if(top !== this.lastTop){
  18197. this.grid.scrollTo(top);
  18198. }
  18199. this._nativeScroll = false;
  18200. },
  18201. setScrollTop: function(inTop){
  18202. // 'lastTop' is a semaphore to prevent feedback-loop with doScroll above
  18203. this.lastTop = inTop;
  18204. if(!this._nativeScroll){
  18205. //fix #15487
  18206. this.scrollboxNode.scrollTop = inTop;
  18207. }
  18208. return this.scrollboxNode.scrollTop;
  18209. },
  18210. // event handlers (direct from DOM)
  18211. doContentEvent: function(e){
  18212. if(this.content.decorateEvent(e)){
  18213. this.grid.onContentEvent(e);
  18214. }
  18215. },
  18216. doHeaderEvent: function(e){
  18217. if(this.header.decorateEvent(e)){
  18218. this.grid.onHeaderEvent(e);
  18219. }
  18220. },
  18221. // event dispatch(from Grid)
  18222. dispatchContentEvent: function(e){
  18223. return this.content.dispatchEvent(e);
  18224. },
  18225. dispatchHeaderEvent: function(e){
  18226. return this.header.dispatchEvent(e);
  18227. },
  18228. // column resizing
  18229. setColWidth: function(inIndex, inWidth){
  18230. this.grid.setCellWidth(inIndex, inWidth + 'px');
  18231. },
  18232. update: function(){
  18233. if(!this.domNode){
  18234. return;
  18235. }
  18236. this.content.update();
  18237. this.grid.update();
  18238. //get scroll after update or scroll left setting goes wrong on IE.
  18239. //See trac: #8040
  18240. var left = this.scrollboxNode.scrollLeft;
  18241. this.scrollboxNode.scrollLeft = left;
  18242. this.headerNode.scrollLeft = left;
  18243. }
  18244. });
  18245. var _GridAvatar = declare("dojox.grid._GridAvatar", Avatar, {
  18246. construct: function(){
  18247. var dd = win.doc;
  18248. var a = dd.createElement("table");
  18249. a.cellPadding = a.cellSpacing = "0";
  18250. a.className = "dojoxGridDndAvatar";
  18251. a.style.position = "absolute";
  18252. a.style.zIndex = 1999;
  18253. a.style.margin = "0px"; // to avoid dojo.marginBox() problems with table's margins
  18254. var b = dd.createElement("tbody");
  18255. var tr = dd.createElement("tr");
  18256. var td = dd.createElement("td");
  18257. var img = dd.createElement("td");
  18258. tr.className = "dojoxGridDndAvatarItem";
  18259. img.className = "dojoxGridDndAvatarItemImage";
  18260. img.style.width = "16px";
  18261. var source = this.manager.source, node;
  18262. if(source.creator){
  18263. // create an avatar representation of the node
  18264. node = source._normalizedCreator(source.getItem(this.manager.nodes[0].id).data, "avatar").node;
  18265. }else{
  18266. // or just clone the node and hope it works
  18267. node = this.manager.nodes[0].cloneNode(true);
  18268. var table, tbody;
  18269. if(node.tagName.toLowerCase() == "tr"){
  18270. // insert extra table nodes
  18271. table = dd.createElement("table");
  18272. tbody = dd.createElement("tbody");
  18273. tbody.appendChild(node);
  18274. table.appendChild(tbody);
  18275. node = table;
  18276. }else if(node.tagName.toLowerCase() == "th"){
  18277. // insert extra table nodes
  18278. table = dd.createElement("table");
  18279. tbody = dd.createElement("tbody");
  18280. var r = dd.createElement("tr");
  18281. table.cellPadding = table.cellSpacing = "0";
  18282. r.appendChild(node);
  18283. tbody.appendChild(r);
  18284. table.appendChild(tbody);
  18285. node = table;
  18286. }
  18287. }
  18288. node.id = "";
  18289. td.appendChild(node);
  18290. tr.appendChild(img);
  18291. tr.appendChild(td);
  18292. html.style(tr, "opacity", 0.9);
  18293. b.appendChild(tr);
  18294. a.appendChild(b);
  18295. this.node = a;
  18296. var m = dojo.dnd.manager();
  18297. this.oldOffsetY = m.OFFSET_Y;
  18298. m.OFFSET_Y = 1;
  18299. },
  18300. destroy: function(){
  18301. dojo.dnd.manager().OFFSET_Y = this.oldOffsetY;
  18302. this.inherited(arguments);
  18303. }
  18304. });
  18305. var oldMakeAvatar = dojo.dnd.manager().makeAvatar;
  18306. dojo.dnd.manager().makeAvatar = function(){
  18307. var src = this.source;
  18308. if(src.viewIndex !== undefined && !html.hasClass(win.body(),"dijit_a11y")){
  18309. return new _GridAvatar(this);
  18310. }
  18311. return oldMakeAvatar.call(dojo.dnd.manager());
  18312. };
  18313. return _View;
  18314. });
  18315. },
  18316. 'dijit/typematic':function(){
  18317. define("dijit/typematic", [
  18318. "dojo/_base/array", // array.forEach
  18319. "dojo/_base/connect", // connect.connect
  18320. "dojo/_base/event", // event.stop
  18321. "dojo/_base/kernel", // kernel.deprecated
  18322. "dojo/_base/lang", // lang.mixin, lang.hitch
  18323. "dojo/on",
  18324. "dojo/_base/sniff", // has("ie")
  18325. "." // setting dijit.typematic global
  18326. ], function(array, connect, event, kernel, lang, on, has, dijit){
  18327. // module:
  18328. // dijit/typematic
  18329. // summary:
  18330. // These functions are used to repetitively call a user specified callback
  18331. // method when a specific key or mouse click over a specific DOM node is
  18332. // held down for a specific amount of time.
  18333. // Only 1 such event is allowed to occur on the browser page at 1 time.
  18334. var typematic = (dijit.typematic = {
  18335. // summary:
  18336. // These functions are used to repetitively call a user specified callback
  18337. // method when a specific key or mouse click over a specific DOM node is
  18338. // held down for a specific amount of time.
  18339. // Only 1 such event is allowed to occur on the browser page at 1 time.
  18340. _fireEventAndReload: function(){
  18341. this._timer = null;
  18342. this._callback(++this._count, this._node, this._evt);
  18343. // Schedule next event, timer is at most minDelay (default 10ms) to avoid
  18344. // browser overload (particularly avoiding starving DOH robot so it never gets to send a mouseup)
  18345. this._currentTimeout = Math.max(
  18346. this._currentTimeout < 0 ? this._initialDelay :
  18347. (this._subsequentDelay > 1 ? this._subsequentDelay : Math.round(this._currentTimeout * this._subsequentDelay)),
  18348. this._minDelay);
  18349. this._timer = setTimeout(lang.hitch(this, "_fireEventAndReload"), this._currentTimeout);
  18350. },
  18351. trigger: function(/*Event*/ evt, /*Object*/ _this, /*DOMNode*/ node, /*Function*/ callback, /*Object*/ obj, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
  18352. // summary:
  18353. // Start a timed, repeating callback sequence.
  18354. // If already started, the function call is ignored.
  18355. // This method is not normally called by the user but can be
  18356. // when the normal listener code is insufficient.
  18357. // evt:
  18358. // key or mouse event object to pass to the user callback
  18359. // _this:
  18360. // pointer to the user's widget space.
  18361. // node:
  18362. // the DOM node object to pass the the callback function
  18363. // callback:
  18364. // function to call until the sequence is stopped called with 3 parameters:
  18365. // count:
  18366. // integer representing number of repeated calls (0..n) with -1 indicating the iteration has stopped
  18367. // node:
  18368. // the DOM node object passed in
  18369. // evt:
  18370. // key or mouse event object
  18371. // obj:
  18372. // user space object used to uniquely identify each typematic sequence
  18373. // subsequentDelay (optional):
  18374. // if > 1, the number of milliseconds until the 3->n events occur
  18375. // or else the fractional time multiplier for the next event's delay, default=0.9
  18376. // initialDelay (optional):
  18377. // the number of milliseconds until the 2nd event occurs, default=500ms
  18378. // minDelay (optional):
  18379. // the maximum delay in milliseconds for event to fire, default=10ms
  18380. if(obj != this._obj){
  18381. this.stop();
  18382. this._initialDelay = initialDelay || 500;
  18383. this._subsequentDelay = subsequentDelay || 0.90;
  18384. this._minDelay = minDelay || 10;
  18385. this._obj = obj;
  18386. this._evt = evt;
  18387. this._node = node;
  18388. this._currentTimeout = -1;
  18389. this._count = -1;
  18390. this._callback = lang.hitch(_this, callback);
  18391. this._fireEventAndReload();
  18392. this._evt = lang.mixin({faux: true}, evt);
  18393. }
  18394. },
  18395. stop: function(){
  18396. // summary:
  18397. // Stop an ongoing timed, repeating callback sequence.
  18398. if(this._timer){
  18399. clearTimeout(this._timer);
  18400. this._timer = null;
  18401. }
  18402. if(this._obj){
  18403. this._callback(-1, this._node, this._evt);
  18404. this._obj = null;
  18405. }
  18406. },
  18407. addKeyListener: function(/*DOMNode*/ node, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
  18408. // summary:
  18409. // Start listening for a specific typematic key.
  18410. // See also the trigger method for other parameters.
  18411. // keyObject:
  18412. // an object defining the key to listen for:
  18413. // charOrCode:
  18414. // the printable character (string) or keyCode (number) to listen for.
  18415. // keyCode:
  18416. // (deprecated - use charOrCode) the keyCode (number) to listen for (implies charCode = 0).
  18417. // charCode:
  18418. // (deprecated - use charOrCode) the charCode (number) to listen for.
  18419. // ctrlKey:
  18420. // desired ctrl key state to initiate the callback sequence:
  18421. // - pressed (true)
  18422. // - released (false)
  18423. // - either (unspecified)
  18424. // altKey:
  18425. // same as ctrlKey but for the alt key
  18426. // shiftKey:
  18427. // same as ctrlKey but for the shift key
  18428. // returns:
  18429. // a connection handle
  18430. if(keyObject.keyCode){
  18431. keyObject.charOrCode = keyObject.keyCode;
  18432. kernel.deprecated("keyCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
  18433. }else if(keyObject.charCode){
  18434. keyObject.charOrCode = String.fromCharCode(keyObject.charCode);
  18435. kernel.deprecated("charCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
  18436. }
  18437. var handles = [
  18438. on(node, connect._keypress, lang.hitch(this, function(evt){
  18439. if(evt.charOrCode == keyObject.charOrCode &&
  18440. (keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey) &&
  18441. (keyObject.altKey === undefined || keyObject.altKey == evt.altKey) &&
  18442. (keyObject.metaKey === undefined || keyObject.metaKey == (evt.metaKey || false)) && // IE doesn't even set metaKey
  18443. (keyObject.shiftKey === undefined || keyObject.shiftKey == evt.shiftKey)){
  18444. event.stop(evt);
  18445. typematic.trigger(evt, _this, node, callback, keyObject, subsequentDelay, initialDelay, minDelay);
  18446. }else if(typematic._obj == keyObject){
  18447. typematic.stop();
  18448. }
  18449. })),
  18450. on(node, "keyup", lang.hitch(this, function(){
  18451. if(typematic._obj == keyObject){
  18452. typematic.stop();
  18453. }
  18454. }))
  18455. ];
  18456. return { remove: function(){ array.forEach(handles, function(h){ h.remove(); }); } };
  18457. },
  18458. addMouseListener: function(/*DOMNode*/ node, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
  18459. // summary:
  18460. // Start listening for a typematic mouse click.
  18461. // See the trigger method for other parameters.
  18462. // returns:
  18463. // a connection handle
  18464. var handles = [
  18465. on(node, "mousedown", lang.hitch(this, function(evt){
  18466. event.stop(evt);
  18467. typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay);
  18468. })),
  18469. on(node, "mouseup", lang.hitch(this, function(evt){
  18470. if(this._obj){
  18471. event.stop(evt);
  18472. }
  18473. typematic.stop();
  18474. })),
  18475. on(node, "mouseout", lang.hitch(this, function(evt){
  18476. event.stop(evt);
  18477. typematic.stop();
  18478. })),
  18479. on(node, "mousemove", lang.hitch(this, function(evt){
  18480. evt.preventDefault();
  18481. })),
  18482. on(node, "dblclick", lang.hitch(this, function(evt){
  18483. event.stop(evt);
  18484. if(has("ie")){
  18485. typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay);
  18486. setTimeout(lang.hitch(this, typematic.stop), 50);
  18487. }
  18488. }))
  18489. ];
  18490. return { remove: function(){ array.forEach(handles, function(h){ h.remove(); }); } };
  18491. },
  18492. addListener: function(/*Node*/ mouseNode, /*Node*/ keyNode, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
  18493. // summary:
  18494. // Start listening for a specific typematic key and mouseclick.
  18495. // This is a thin wrapper to addKeyListener and addMouseListener.
  18496. // See the addMouseListener and addKeyListener methods for other parameters.
  18497. // mouseNode:
  18498. // the DOM node object to listen on for mouse events.
  18499. // keyNode:
  18500. // the DOM node object to listen on for key events.
  18501. // returns:
  18502. // a connection handle
  18503. var handles = [
  18504. this.addKeyListener(keyNode, keyObject, _this, callback, subsequentDelay, initialDelay, minDelay),
  18505. this.addMouseListener(mouseNode, _this, callback, subsequentDelay, initialDelay, minDelay)
  18506. ];
  18507. return { remove: function(){ array.forEach(handles, function(h){ h.remove(); }); } };
  18508. }
  18509. });
  18510. return typematic;
  18511. });
  18512. },
  18513. 'dijit/MenuItem':function(){
  18514. require({cache:{
  18515. 'url:dijit/templates/MenuItem.html':"<tr class=\"dijitReset dijitMenuItem\" data-dojo-attach-point=\"focusNode\" role=\"menuitem\" tabIndex=\"-1\"\r\n\t\tdata-dojo-attach-event=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\r\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\r\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitMenuItemIcon\" data-dojo-attach-point=\"iconNode\"/>\r\n\t</td>\r\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" data-dojo-attach-point=\"containerNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" data-dojo-attach-point=\"accelKeyNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">\r\n\t\t<div data-dojo-attach-point=\"arrowWrapper\" style=\"visibility: hidden\">\r\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuExpand\"/>\r\n\t\t\t<span class=\"dijitMenuExpandA11y\">+</span>\r\n\t\t</div>\r\n\t</td>\r\n</tr>\r\n"}});
  18516. define("dijit/MenuItem", [
  18517. "dojo/_base/declare", // declare
  18518. "dojo/dom", // dom.setSelectable
  18519. "dojo/dom-attr", // domAttr.set
  18520. "dojo/dom-class", // domClass.toggle
  18521. "dojo/_base/event", // event.stop
  18522. "dojo/_base/kernel", // kernel.deprecated
  18523. "dojo/_base/sniff", // has("ie")
  18524. "./_Widget",
  18525. "./_TemplatedMixin",
  18526. "./_Contained",
  18527. "./_CssStateMixin",
  18528. "dojo/text!./templates/MenuItem.html"
  18529. ], function(declare, dom, domAttr, domClass, event, kernel, has,
  18530. _Widget, _TemplatedMixin, _Contained, _CssStateMixin, template){
  18531. /*=====
  18532. var _Widget = dijit._Widget;
  18533. var _TemplatedMixin = dijit._TemplatedMixin;
  18534. var _Contained = dijit._Contained;
  18535. var _CssStateMixin = dijit._CssStateMixin;
  18536. =====*/
  18537. // module:
  18538. // dijit/MenuItem
  18539. // summary:
  18540. // A line item in a Menu Widget
  18541. return declare("dijit.MenuItem",
  18542. [_Widget, _TemplatedMixin, _Contained, _CssStateMixin],
  18543. {
  18544. // summary:
  18545. // A line item in a Menu Widget
  18546. // Make 3 columns
  18547. // icon, label, and expand arrow (BiDi-dependent) indicating sub-menu
  18548. templateString: template,
  18549. baseClass: "dijitMenuItem",
  18550. // label: String
  18551. // Menu text
  18552. label: '',
  18553. _setLabelAttr: { node: "containerNode", type: "innerHTML" },
  18554. // iconClass: String
  18555. // Class to apply to DOMNode to make it display an icon.
  18556. iconClass: "dijitNoIcon",
  18557. _setIconClassAttr: { node: "iconNode", type: "class" },
  18558. // accelKey: String
  18559. // Text for the accelerator (shortcut) key combination.
  18560. // Note that although Menu can display accelerator keys there
  18561. // is no infrastructure to actually catch and execute these
  18562. // accelerators.
  18563. accelKey: "",
  18564. // disabled: Boolean
  18565. // If true, the menu item is disabled.
  18566. // If false, the menu item is enabled.
  18567. disabled: false,
  18568. _fillContent: function(/*DomNode*/ source){
  18569. // If button label is specified as srcNodeRef.innerHTML rather than
  18570. // this.params.label, handle it here.
  18571. if(source && !("label" in this.params)){
  18572. this.set('label', source.innerHTML);
  18573. }
  18574. },
  18575. buildRendering: function(){
  18576. this.inherited(arguments);
  18577. var label = this.id+"_text";
  18578. domAttr.set(this.containerNode, "id", label);
  18579. if(this.accelKeyNode){
  18580. domAttr.set(this.accelKeyNode, "id", this.id + "_accel");
  18581. label += " " + this.id + "_accel";
  18582. }
  18583. this.domNode.setAttribute("aria-labelledby", label);
  18584. dom.setSelectable(this.domNode, false);
  18585. },
  18586. _onHover: function(){
  18587. // summary:
  18588. // Handler when mouse is moved onto menu item
  18589. // tags:
  18590. // protected
  18591. this.getParent().onItemHover(this);
  18592. },
  18593. _onUnhover: function(){
  18594. // summary:
  18595. // Handler when mouse is moved off of menu item,
  18596. // possibly to a child menu, or maybe to a sibling
  18597. // menuitem or somewhere else entirely.
  18598. // tags:
  18599. // protected
  18600. // if we are unhovering the currently selected item
  18601. // then unselect it
  18602. this.getParent().onItemUnhover(this);
  18603. // When menu is hidden (collapsed) due to clicking a MenuItem and having it execute,
  18604. // FF and IE don't generate an onmouseout event for the MenuItem.
  18605. // So, help out _CssStateMixin in this case.
  18606. this._set("hovering", false);
  18607. },
  18608. _onClick: function(evt){
  18609. // summary:
  18610. // Internal handler for click events on MenuItem.
  18611. // tags:
  18612. // private
  18613. this.getParent().onItemClick(this, evt);
  18614. event.stop(evt);
  18615. },
  18616. onClick: function(/*Event*/){
  18617. // summary:
  18618. // User defined function to handle clicks
  18619. // tags:
  18620. // callback
  18621. },
  18622. focus: function(){
  18623. // summary:
  18624. // Focus on this MenuItem
  18625. try{
  18626. if(has("ie") == 8){
  18627. // needed for IE8 which won't scroll TR tags into view on focus yet calling scrollIntoView creates flicker (#10275)
  18628. this.containerNode.focus();
  18629. }
  18630. this.focusNode.focus();
  18631. }catch(e){
  18632. // this throws on IE (at least) in some scenarios
  18633. }
  18634. },
  18635. _onFocus: function(){
  18636. // summary:
  18637. // This is called by the focus manager when focus
  18638. // goes to this MenuItem or a child menu.
  18639. // tags:
  18640. // protected
  18641. this._setSelected(true);
  18642. this.getParent()._onItemFocus(this);
  18643. this.inherited(arguments);
  18644. },
  18645. _setSelected: function(selected){
  18646. // summary:
  18647. // Indicate that this node is the currently selected one
  18648. // tags:
  18649. // private
  18650. /***
  18651. * TODO: remove this method and calls to it, when _onBlur() is working for MenuItem.
  18652. * Currently _onBlur() gets called when focus is moved from the MenuItem to a child menu.
  18653. * That's not supposed to happen, but the problem is:
  18654. * In order to allow dijit.popup's getTopPopup() to work,a sub menu's popupParent
  18655. * points to the parent Menu, bypassing the parent MenuItem... thus the
  18656. * MenuItem is not in the chain of active widgets and gets a premature call to
  18657. * _onBlur()
  18658. */
  18659. domClass.toggle(this.domNode, "dijitMenuItemSelected", selected);
  18660. },
  18661. setLabel: function(/*String*/ content){
  18662. // summary:
  18663. // Deprecated. Use set('label', ...) instead.
  18664. // tags:
  18665. // deprecated
  18666. kernel.deprecated("dijit.MenuItem.setLabel() is deprecated. Use set('label', ...) instead.", "", "2.0");
  18667. this.set("label", content);
  18668. },
  18669. setDisabled: function(/*Boolean*/ disabled){
  18670. // summary:
  18671. // Deprecated. Use set('disabled', bool) instead.
  18672. // tags:
  18673. // deprecated
  18674. kernel.deprecated("dijit.Menu.setDisabled() is deprecated. Use set('disabled', bool) instead.", "", "2.0");
  18675. this.set('disabled', disabled);
  18676. },
  18677. _setDisabledAttr: function(/*Boolean*/ value){
  18678. // summary:
  18679. // Hook for attr('disabled', ...) to work.
  18680. // Enable or disable this menu item.
  18681. this.focusNode.setAttribute('aria-disabled', value ? 'true' : 'false');
  18682. this._set("disabled", value);
  18683. },
  18684. _setAccelKeyAttr: function(/*String*/ value){
  18685. // summary:
  18686. // Hook for attr('accelKey', ...) to work.
  18687. // Set accelKey on this menu item.
  18688. this.accelKeyNode.style.display=value?"":"none";
  18689. this.accelKeyNode.innerHTML=value;
  18690. //have to use colSpan to make it work in IE
  18691. domAttr.set(this.containerNode,'colSpan',value?"1":"2");
  18692. this._set("accelKey", value);
  18693. }
  18694. });
  18695. });
  18696. },
  18697. 'dojo/cldr/supplemental':function(){
  18698. define("dojo/cldr/supplemental", ["../_base/kernel", "../_base/lang", "../i18n"], function(dojo, lang) {
  18699. // module:
  18700. // dojo/cldr/supplemental
  18701. // summary:
  18702. // TODOC
  18703. lang.getObject("cldr.supplemental", true, dojo);
  18704. dojo.cldr.supplemental.getFirstDayOfWeek = function(/*String?*/locale){
  18705. // summary: Returns a zero-based index for first day of the week
  18706. // description:
  18707. // Returns a zero-based index for first day of the week, as used by the local (Gregorian) calendar.
  18708. // e.g. Sunday (returns 0), or Monday (returns 1)
  18709. // from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/firstDay
  18710. var firstDay = {/*default is 1=Monday*/
  18711. mv:5,
  18712. 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,
  18713. ly:6,ma:6,om:6,qa:6,sa:6,sd:6,so:6,sy:6,tn:6,ye:6,
  18714. ar:0,as:0,az:0,bw:0,ca:0,cn:0,fo:0,ge:0,gl:0,gu:0,hk:0,
  18715. il:0,'in':0,jm:0,jp:0,kg:0,kr:0,la:0,mh:0,mn:0,mo:0,mp:0,
  18716. mt:0,nz:0,ph:0,pk:0,sg:0,th:0,tt:0,tw:0,um:0,us:0,uz:0,
  18717. vi:0,zw:0
  18718. // variant. do not use? gb:0,
  18719. };
  18720. var country = dojo.cldr.supplemental._region(locale);
  18721. var dow = firstDay[country];
  18722. return (dow === undefined) ? 1 : dow; /*Number*/
  18723. };
  18724. dojo.cldr.supplemental._region = function(/*String?*/locale){
  18725. locale = dojo.i18n.normalizeLocale(locale);
  18726. var tags = locale.split('-');
  18727. var region = tags[1];
  18728. if(!region){
  18729. // IE often gives language only (#2269)
  18730. // Arbitrary mappings of language-only locales to a country:
  18731. region = {de:"de", en:"us", es:"es", fi:"fi", fr:"fr", he:"il", hu:"hu", it:"it",
  18732. ja:"jp", ko:"kr", nl:"nl", pt:"br", sv:"se", zh:"cn"}[tags[0]];
  18733. }else if(region.length == 4){
  18734. // The ISO 3166 country code is usually in the second position, unless a
  18735. // 4-letter script is given. See http://www.ietf.org/rfc/rfc4646.txt
  18736. region = tags[2];
  18737. }
  18738. return region;
  18739. };
  18740. dojo.cldr.supplemental.getWeekend = function(/*String?*/locale){
  18741. // summary: Returns a hash containing the start and end days of the weekend
  18742. // description:
  18743. // Returns a hash containing the start and end days of the weekend according to local custom using locale,
  18744. // or by default in the user's locale.
  18745. // e.g. {start:6, end:0}
  18746. // from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/weekend{Start,End}
  18747. var weekendStart = {/*default is 6=Saturday*/
  18748. 'in':0,
  18749. af:4,dz:4,ir:4,om:4,sa:4,ye:4,
  18750. 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
  18751. };
  18752. var weekendEnd = {/*default is 0=Sunday*/
  18753. af:5,dz:5,ir:5,om:5,sa:5,ye:5,
  18754. 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
  18755. };
  18756. var country = dojo.cldr.supplemental._region(locale);
  18757. var start = weekendStart[country];
  18758. var end = weekendEnd[country];
  18759. if(start === undefined){start=6;}
  18760. if(end === undefined){end=0;}
  18761. return {start:start, end:end}; /*Object {start,end}*/
  18762. };
  18763. return dojo.cldr.supplemental;
  18764. });
  18765. },
  18766. 'dijit/ToolbarSeparator':function(){
  18767. define("dijit/ToolbarSeparator", [
  18768. "dojo/_base/declare", // declare
  18769. "dojo/dom", // dom.setSelectable
  18770. "./_Widget",
  18771. "./_TemplatedMixin"
  18772. ], function(declare, dom, _Widget, _TemplatedMixin){
  18773. /*=====
  18774. var _Widget = dijit._Widget;
  18775. var _TemplatedMixin = dijit._TemplatedMixin;
  18776. =====*/
  18777. // module:
  18778. // dijit/ToolbarSeparator
  18779. // summary:
  18780. // A spacer between two `dijit.Toolbar` items
  18781. return declare("dijit.ToolbarSeparator", [_Widget, _TemplatedMixin], {
  18782. // summary:
  18783. // A spacer between two `dijit.Toolbar` items
  18784. templateString: '<div class="dijitToolbarSeparator dijitInline" role="presentation"></div>',
  18785. buildRendering: function(){
  18786. this.inherited(arguments);
  18787. dom.setSelectable(this.domNode, false);
  18788. },
  18789. isFocusable: function(){
  18790. // summary:
  18791. // This widget isn't focusable, so pass along that fact.
  18792. // tags:
  18793. // protected
  18794. return false;
  18795. }
  18796. });
  18797. });
  18798. },
  18799. 'dijit/layout/_LayoutWidget':function(){
  18800. define("dijit/layout/_LayoutWidget", [
  18801. "dojo/_base/lang", // lang.mixin
  18802. "../_Widget",
  18803. "../_Container",
  18804. "../_Contained",
  18805. "dojo/_base/declare", // declare
  18806. "dojo/dom-class", // domClass.add domClass.remove
  18807. "dojo/dom-geometry", // domGeometry.marginBox
  18808. "dojo/dom-style", // domStyle.getComputedStyle
  18809. "dojo/_base/sniff", // has("ie")
  18810. "dojo/_base/window" // win.global
  18811. ], function(lang, _Widget, _Container, _Contained,
  18812. declare, domClass, domGeometry, domStyle, has, win){
  18813. /*=====
  18814. var _Widget = dijit._Widget;
  18815. var _Container = dijit._Container;
  18816. var _Contained = dijit._Contained;
  18817. =====*/
  18818. // module:
  18819. // dijit/layout/_LayoutWidget
  18820. // summary:
  18821. // _LayoutWidget Base class for a _Container widget which is responsible for laying out its children.
  18822. // Widgets which mixin this code must define layout() to manage placement and sizing of the children.
  18823. return declare("dijit.layout._LayoutWidget", [_Widget, _Container, _Contained], {
  18824. // summary:
  18825. // Base class for a _Container widget which is responsible for laying out its children.
  18826. // Widgets which mixin this code must define layout() to manage placement and sizing of the children.
  18827. // baseClass: [protected extension] String
  18828. // This class name is applied to the widget's domNode
  18829. // and also may be used to generate names for sub nodes,
  18830. // for example dijitTabContainer-content.
  18831. baseClass: "dijitLayoutContainer",
  18832. // isLayoutContainer: [protected] Boolean
  18833. // Indicates that this widget is going to call resize() on its
  18834. // children widgets, setting their size, when they become visible.
  18835. isLayoutContainer: true,
  18836. buildRendering: function(){
  18837. this.inherited(arguments);
  18838. domClass.add(this.domNode, "dijitContainer");
  18839. },
  18840. startup: function(){
  18841. // summary:
  18842. // Called after all the widgets have been instantiated and their
  18843. // dom nodes have been inserted somewhere under win.doc.body.
  18844. //
  18845. // Widgets should override this method to do any initialization
  18846. // dependent on other widgets existing, and then call
  18847. // this superclass method to finish things off.
  18848. //
  18849. // startup() in subclasses shouldn't do anything
  18850. // size related because the size of the widget hasn't been set yet.
  18851. if(this._started){ return; }
  18852. // Need to call inherited first - so that child widgets get started
  18853. // up correctly
  18854. this.inherited(arguments);
  18855. // If I am a not being controlled by a parent layout widget...
  18856. var parent = this.getParent && this.getParent();
  18857. if(!(parent && parent.isLayoutContainer)){
  18858. // Do recursive sizing and layout of all my descendants
  18859. // (passing in no argument to resize means that it has to glean the size itself)
  18860. this.resize();
  18861. // Since my parent isn't a layout container, and my style *may be* width=height=100%
  18862. // or something similar (either set directly or via a CSS class),
  18863. // monitor when viewport size changes so that I can re-layout.
  18864. this.connect(win.global, 'onresize', function(){
  18865. // Using function(){} closure to ensure no arguments passed to resize().
  18866. this.resize();
  18867. });
  18868. }
  18869. },
  18870. resize: function(changeSize, resultSize){
  18871. // summary:
  18872. // Call this to resize a widget, or after its size has changed.
  18873. // description:
  18874. // Change size mode:
  18875. // When changeSize is specified, changes the marginBox of this widget
  18876. // and forces it to relayout its contents accordingly.
  18877. // changeSize may specify height, width, or both.
  18878. //
  18879. // If resultSize is specified it indicates the size the widget will
  18880. // become after changeSize has been applied.
  18881. //
  18882. // Notification mode:
  18883. // When changeSize is null, indicates that the caller has already changed
  18884. // the size of the widget, or perhaps it changed because the browser
  18885. // window was resized. Tells widget to relayout its contents accordingly.
  18886. //
  18887. // If resultSize is also specified it indicates the size the widget has
  18888. // become.
  18889. //
  18890. // In either mode, this method also:
  18891. // 1. Sets this._borderBox and this._contentBox to the new size of
  18892. // the widget. Queries the current domNode size if necessary.
  18893. // 2. Calls layout() to resize contents (and maybe adjust child widgets).
  18894. //
  18895. // changeSize: Object?
  18896. // Sets the widget to this margin-box size and position.
  18897. // May include any/all of the following properties:
  18898. // | {w: int, h: int, l: int, t: int}
  18899. //
  18900. // resultSize: Object?
  18901. // The margin-box size of this widget after applying changeSize (if
  18902. // changeSize is specified). If caller knows this size and
  18903. // passes it in, we don't need to query the browser to get the size.
  18904. // | {w: int, h: int}
  18905. var node = this.domNode;
  18906. // set margin box size, unless it wasn't specified, in which case use current size
  18907. if(changeSize){
  18908. domGeometry.setMarginBox(node, changeSize);
  18909. }
  18910. // If either height or width wasn't specified by the user, then query node for it.
  18911. // But note that setting the margin box and then immediately querying dimensions may return
  18912. // inaccurate results, so try not to depend on it.
  18913. var mb = resultSize || {};
  18914. lang.mixin(mb, changeSize || {}); // changeSize overrides resultSize
  18915. if( !("h" in mb) || !("w" in mb) ){
  18916. mb = lang.mixin(domGeometry.getMarginBox(node), mb); // just use domGeometry.marginBox() to fill in missing values
  18917. }
  18918. // Compute and save the size of my border box and content box
  18919. // (w/out calling domGeometry.getContentBox() since that may fail if size was recently set)
  18920. var cs = domStyle.getComputedStyle(node);
  18921. var me = domGeometry.getMarginExtents(node, cs);
  18922. var be = domGeometry.getBorderExtents(node, cs);
  18923. var bb = (this._borderBox = {
  18924. w: mb.w - (me.w + be.w),
  18925. h: mb.h - (me.h + be.h)
  18926. });
  18927. var pe = domGeometry.getPadExtents(node, cs);
  18928. this._contentBox = {
  18929. l: domStyle.toPixelValue(node, cs.paddingLeft),
  18930. t: domStyle.toPixelValue(node, cs.paddingTop),
  18931. w: bb.w - pe.w,
  18932. h: bb.h - pe.h
  18933. };
  18934. // Callback for widget to adjust size of its children
  18935. this.layout();
  18936. },
  18937. layout: function(){
  18938. // summary:
  18939. // Widgets override this method to size and position their contents/children.
  18940. // When this is called this._contentBox is guaranteed to be set (see resize()).
  18941. //
  18942. // This is called after startup(), and also when the widget's size has been
  18943. // changed.
  18944. // tags:
  18945. // protected extension
  18946. },
  18947. _setupChild: function(/*dijit._Widget*/child){
  18948. // summary:
  18949. // Common setup for initial children and children which are added after startup
  18950. // tags:
  18951. // protected extension
  18952. var cls = this.baseClass + "-child "
  18953. + (child.baseClass ? this.baseClass + "-" + child.baseClass : "");
  18954. domClass.add(child.domNode, cls);
  18955. },
  18956. addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
  18957. // Overrides _Container.addChild() to call _setupChild()
  18958. this.inherited(arguments);
  18959. if(this._started){
  18960. this._setupChild(child);
  18961. }
  18962. },
  18963. removeChild: function(/*dijit._Widget*/ child){
  18964. // Overrides _Container.removeChild() to remove class added by _setupChild()
  18965. var cls = this.baseClass + "-child"
  18966. + (child.baseClass ?
  18967. " " + this.baseClass + "-" + child.baseClass : "");
  18968. domClass.remove(child.domNode, cls);
  18969. this.inherited(arguments);
  18970. }
  18971. });
  18972. });
  18973. },
  18974. 'dojox/uuid/_base':function(){
  18975. define("dojox/uuid/_base", ['dojo/_base/kernel', 'dojo/_base/lang'], function(dojo){
  18976. dojo.getObject("uuid", true, dojox);
  18977. // Public constants:
  18978. dojox.uuid.NIL_UUID = "00000000-0000-0000-0000-000000000000";
  18979. dojox.uuid.version = {
  18980. // Enumeration for the different UUID versions.
  18981. UNKNOWN: 0,
  18982. TIME_BASED: 1,
  18983. DCE_SECURITY: 2,
  18984. NAME_BASED_MD5: 3,
  18985. RANDOM: 4,
  18986. NAME_BASED_SHA1: 5 };
  18987. dojox.uuid.variant = {
  18988. // Enumeration for the different UUID variants.
  18989. NCS: "0",
  18990. DCE: "10",
  18991. MICROSOFT: "110",
  18992. UNKNOWN: "111" };
  18993. dojox.uuid.assert = function(/*Boolean*/ booleanValue, /*String?*/ message){
  18994. // summary:
  18995. // Throws an exception if the assertion fails.
  18996. // description:
  18997. // If the asserted condition is true, this method does nothing. If the
  18998. // condition is false, we throw an error with a error message.
  18999. // booleanValue: Must be true for the assertion to succeed.
  19000. // message: A string describing the assertion.
  19001. // throws: Throws an Error if 'booleanValue' is false.
  19002. if(!booleanValue){
  19003. if(!message){
  19004. message = "An assert statement failed.\n" +
  19005. "The method dojox.uuid.assert() was called with a 'false' value.\n";
  19006. }
  19007. throw new Error(message);
  19008. }
  19009. };
  19010. dojox.uuid.generateNilUuid = function(){
  19011. // summary:
  19012. // This function returns the Nil UUID: "00000000-0000-0000-0000-000000000000".
  19013. // description:
  19014. // The Nil UUID is described in section 4.1.7 of
  19015. // RFC 4122: http://tools.ietf.org/html/rfc4122#section-4.1.7
  19016. // examples:
  19017. // var string = dojox.uuid.generateNilUuid();
  19018. return dojox.uuid.NIL_UUID; // String
  19019. };
  19020. dojox.uuid.isValid = function(/*String*/ uuidString){
  19021. // summary:
  19022. // Returns true if the UUID was initialized with a valid value.
  19023. uuidString = uuidString.toString();
  19024. var valid = (dojo.isString(uuidString) &&
  19025. (uuidString.length == 36) &&
  19026. (uuidString == uuidString.toLowerCase()));
  19027. if(valid){
  19028. var arrayOfParts = uuidString.split("-");
  19029. valid = ((arrayOfParts.length == 5) &&
  19030. (arrayOfParts[0].length == 8) &&
  19031. (arrayOfParts[1].length == 4) &&
  19032. (arrayOfParts[2].length == 4) &&
  19033. (arrayOfParts[3].length == 4) &&
  19034. (arrayOfParts[4].length == 12));
  19035. var HEX_RADIX = 16;
  19036. for (var i in arrayOfParts) {
  19037. var part = arrayOfParts[i];
  19038. var integer = parseInt(part, HEX_RADIX);
  19039. valid = valid && isFinite(integer);
  19040. }
  19041. }
  19042. return valid; // boolean
  19043. };
  19044. dojox.uuid.getVariant = function(/*String*/ uuidString){
  19045. // summary:
  19046. // Returns a variant code that indicates what type of UUID this is.
  19047. // Returns one of the enumerated dojox.uuid.variant values.
  19048. // example:
  19049. // var variant = dojox.uuid.getVariant("3b12f1df-5232-4804-897e-917bf397618a");
  19050. // dojox.uuid.assert(variant == dojox.uuid.variant.DCE);
  19051. // example:
  19052. // "3b12f1df-5232-4804-897e-917bf397618a"
  19053. // ^
  19054. // |
  19055. // (variant "10__" == DCE)
  19056. if(!dojox.uuid._ourVariantLookupTable){
  19057. var variant = dojox.uuid.variant;
  19058. var lookupTable = [];
  19059. lookupTable[0x0] = variant.NCS; // 0000
  19060. lookupTable[0x1] = variant.NCS; // 0001
  19061. lookupTable[0x2] = variant.NCS; // 0010
  19062. lookupTable[0x3] = variant.NCS; // 0011
  19063. lookupTable[0x4] = variant.NCS; // 0100
  19064. lookupTable[0x5] = variant.NCS; // 0101
  19065. lookupTable[0x6] = variant.NCS; // 0110
  19066. lookupTable[0x7] = variant.NCS; // 0111
  19067. lookupTable[0x8] = variant.DCE; // 1000
  19068. lookupTable[0x9] = variant.DCE; // 1001
  19069. lookupTable[0xA] = variant.DCE; // 1010
  19070. lookupTable[0xB] = variant.DCE; // 1011
  19071. lookupTable[0xC] = variant.MICROSOFT; // 1100
  19072. lookupTable[0xD] = variant.MICROSOFT; // 1101
  19073. lookupTable[0xE] = variant.UNKNOWN; // 1110
  19074. lookupTable[0xF] = variant.UNKNOWN; // 1111
  19075. dojox.uuid._ourVariantLookupTable = lookupTable;
  19076. }
  19077. uuidString = uuidString.toString();
  19078. var variantCharacter = uuidString.charAt(19);
  19079. var HEX_RADIX = 16;
  19080. var variantNumber = parseInt(variantCharacter, HEX_RADIX);
  19081. dojox.uuid.assert((variantNumber >= 0) && (variantNumber <= 16));
  19082. return dojox.uuid._ourVariantLookupTable[variantNumber]; // dojox.uuid.variant
  19083. };
  19084. dojox.uuid.getVersion = function(/*String*/ uuidString){
  19085. // summary:
  19086. // Returns a version number that indicates what type of UUID this is.
  19087. // Returns one of the enumerated dojox.uuid.version values.
  19088. // example:
  19089. // var version = dojox.uuid.getVersion("b4308fb0-86cd-11da-a72b-0800200c9a66");
  19090. // dojox.uuid.assert(version == dojox.uuid.version.TIME_BASED);
  19091. // exceptions:
  19092. // Throws an Error if this is not a DCE Variant UUID.
  19093. var errorMessage = "dojox.uuid.getVersion() was not passed a DCE Variant UUID.";
  19094. dojox.uuid.assert(dojox.uuid.getVariant(uuidString) == dojox.uuid.variant.DCE, errorMessage);
  19095. uuidString = uuidString.toString();
  19096. // "b4308fb0-86cd-11da-a72b-0800200c9a66"
  19097. // ^
  19098. // |
  19099. // (version 1 == TIME_BASED)
  19100. var versionCharacter = uuidString.charAt(14);
  19101. var HEX_RADIX = 16;
  19102. var versionNumber = parseInt(versionCharacter, HEX_RADIX);
  19103. return versionNumber; // dojox.uuid.version
  19104. };
  19105. dojox.uuid.getNode = function(/*String*/ uuidString){
  19106. // summary:
  19107. // If this is a version 1 UUID (a time-based UUID), getNode() returns a
  19108. // 12-character string with the "node" or "pseudonode" portion of the UUID,
  19109. // which is the rightmost 12 characters.
  19110. // exceptions:
  19111. // Throws an Error if this is not a version 1 UUID.
  19112. var errorMessage = "dojox.uuid.getNode() was not passed a TIME_BASED UUID.";
  19113. dojox.uuid.assert(dojox.uuid.getVersion(uuidString) == dojox.uuid.version.TIME_BASED, errorMessage);
  19114. uuidString = uuidString.toString();
  19115. var arrayOfStrings = uuidString.split('-');
  19116. var nodeString = arrayOfStrings[4];
  19117. return nodeString; // String (a 12-character string, which will look something like "917bf397618a")
  19118. };
  19119. dojox.uuid.getTimestamp = function(/*String*/ uuidString, /*String?*/ returnType){
  19120. // summary:
  19121. // If this is a version 1 UUID (a time-based UUID), this method returns
  19122. // the timestamp value encoded in the UUID. The caller can ask for the
  19123. // timestamp to be returned either as a JavaScript Date object or as a
  19124. // 15-character string of hex digits.
  19125. // returnType: Any of these five values: "string", String, "hex", "date", Date
  19126. // returns:
  19127. // Returns the timestamp value as a JavaScript Date object or a 15-character string of hex digits.
  19128. // examples:
  19129. // var uuidString = "b4308fb0-86cd-11da-a72b-0800200c9a66";
  19130. // var date, string, hexString;
  19131. // date = dojox.uuid.getTimestamp(uuidString); // returns a JavaScript Date
  19132. // date = dojox.uuid.getTimestamp(uuidString, Date); //
  19133. // string = dojox.uuid.getTimestamp(uuidString, String); // "Mon, 16 Jan 2006 20:21:41 GMT"
  19134. // hexString = dojox.uuid.getTimestamp(uuidString, "hex"); // "1da86cdb4308fb0"
  19135. // exceptions:
  19136. // Throws an Error if this is not a version 1 UUID.
  19137. var errorMessage = "dojox.uuid.getTimestamp() was not passed a TIME_BASED UUID.";
  19138. dojox.uuid.assert(dojox.uuid.getVersion(uuidString) == dojox.uuid.version.TIME_BASED, errorMessage);
  19139. uuidString = uuidString.toString();
  19140. if(!returnType){returnType = null};
  19141. switch(returnType){
  19142. case "string":
  19143. case String:
  19144. return dojox.uuid.getTimestamp(uuidString, Date).toUTCString(); // String (e.g. "Mon, 16 Jan 2006 20:21:41 GMT")
  19145. break;
  19146. case "hex":
  19147. // Return a 15-character string of hex digits containing the
  19148. // timestamp for this UUID, with the high-order bits first.
  19149. var arrayOfStrings = uuidString.split('-');
  19150. var hexTimeLow = arrayOfStrings[0];
  19151. var hexTimeMid = arrayOfStrings[1];
  19152. var hexTimeHigh = arrayOfStrings[2];
  19153. // Chop off the leading "1" character, which is the UUID
  19154. // version number for time-based UUIDs.
  19155. hexTimeHigh = hexTimeHigh.slice(1);
  19156. var timestampAsHexString = hexTimeHigh + hexTimeMid + hexTimeLow;
  19157. dojox.uuid.assert(timestampAsHexString.length == 15);
  19158. return timestampAsHexString; // String (e.g. "1da86cdb4308fb0")
  19159. break;
  19160. case null: // no returnType was specified, so default to Date
  19161. case "date":
  19162. case Date:
  19163. // Return a JavaScript Date object.
  19164. var GREGORIAN_CHANGE_OFFSET_IN_HOURS = 3394248;
  19165. var HEX_RADIX = 16;
  19166. var arrayOfParts = uuidString.split('-');
  19167. var timeLow = parseInt(arrayOfParts[0], HEX_RADIX);
  19168. var timeMid = parseInt(arrayOfParts[1], HEX_RADIX);
  19169. var timeHigh = parseInt(arrayOfParts[2], HEX_RADIX);
  19170. var hundredNanosecondIntervalsSince1582 = timeHigh & 0x0FFF;
  19171. hundredNanosecondIntervalsSince1582 <<= 16;
  19172. hundredNanosecondIntervalsSince1582 += timeMid;
  19173. // What we really want to do next is shift left 32 bits, but the
  19174. // result will be too big to fit in an int, so we'll multiply by 2^32,
  19175. // and the result will be a floating point approximation.
  19176. hundredNanosecondIntervalsSince1582 *= 0x100000000;
  19177. hundredNanosecondIntervalsSince1582 += timeLow;
  19178. var millisecondsSince1582 = hundredNanosecondIntervalsSince1582 / 10000;
  19179. // Again, this will be a floating point approximation.
  19180. // We can make things exact later if we need to.
  19181. var secondsPerHour = 60 * 60;
  19182. var hoursBetween1582and1970 = GREGORIAN_CHANGE_OFFSET_IN_HOURS;
  19183. var secondsBetween1582and1970 = hoursBetween1582and1970 * secondsPerHour;
  19184. var millisecondsBetween1582and1970 = secondsBetween1582and1970 * 1000;
  19185. var millisecondsSince1970 = millisecondsSince1582 - millisecondsBetween1582and1970;
  19186. var timestampAsDate = new Date(millisecondsSince1970);
  19187. return timestampAsDate; // Date
  19188. break;
  19189. default:
  19190. // we got passed something other than a valid returnType
  19191. dojox.uuid.assert(false, "dojox.uuid.getTimestamp was not passed a valid returnType: " + returnType);
  19192. break;
  19193. }
  19194. };
  19195. return dojox.uuid;
  19196. });
  19197. },
  19198. 'dijit/popup':function(){
  19199. define("dijit/popup", [
  19200. "dojo/_base/array", // array.forEach array.some
  19201. "dojo/aspect",
  19202. "dojo/_base/connect", // connect._keypress
  19203. "dojo/_base/declare", // declare
  19204. "dojo/dom", // dom.isDescendant
  19205. "dojo/dom-attr", // domAttr.set
  19206. "dojo/dom-construct", // domConstruct.create domConstruct.destroy
  19207. "dojo/dom-geometry", // domGeometry.isBodyLtr
  19208. "dojo/dom-style", // domStyle.set
  19209. "dojo/_base/event", // event.stop
  19210. "dojo/keys",
  19211. "dojo/_base/lang", // lang.hitch
  19212. "dojo/on",
  19213. "dojo/_base/sniff", // has("ie") has("mozilla")
  19214. "dojo/_base/window", // win.body
  19215. "./place",
  19216. "./BackgroundIframe",
  19217. "." // dijit (defining dijit.popup to match API doc)
  19218. ], function(array, aspect, connect, declare, dom, domAttr, domConstruct, domGeometry, domStyle, event, keys, lang, on, has, win,
  19219. place, BackgroundIframe, dijit){
  19220. // module:
  19221. // dijit/popup
  19222. // summary:
  19223. // Used to show drop downs (ex: the select list of a ComboBox)
  19224. // or popups (ex: right-click context menus)
  19225. /*=====
  19226. dijit.popup.__OpenArgs = function(){
  19227. // popup: Widget
  19228. // widget to display
  19229. // parent: Widget
  19230. // the button etc. that is displaying this popup
  19231. // around: DomNode
  19232. // DOM node (typically a button); place popup relative to this node. (Specify this *or* "x" and "y" parameters.)
  19233. // x: Integer
  19234. // Absolute horizontal position (in pixels) to place node at. (Specify this *or* "around" parameter.)
  19235. // y: Integer
  19236. // Absolute vertical position (in pixels) to place node at. (Specify this *or* "around" parameter.)
  19237. // orient: Object|String
  19238. // When the around parameter is specified, orient should be a list of positions to try, ex:
  19239. // | [ "below", "above" ]
  19240. // For backwards compatibility it can also be an (ordered) hash of tuples of the form
  19241. // (around-node-corner, popup-node-corner), ex:
  19242. // | { "BL": "TL", "TL": "BL" }
  19243. // where BL means "bottom left" and "TL" means "top left", etc.
  19244. //
  19245. // dijit.popup.open() tries to position the popup according to each specified position, in order,
  19246. // until the popup appears fully within the viewport.
  19247. //
  19248. // The default value is ["below", "above"]
  19249. //
  19250. // When an (x,y) position is specified rather than an around node, orient is either
  19251. // "R" or "L". R (for right) means that it tries to put the popup to the right of the mouse,
  19252. // specifically positioning the popup's top-right corner at the mouse position, and if that doesn't
  19253. // fit in the viewport, then it tries, in order, the bottom-right corner, the top left corner,
  19254. // and the top-right corner.
  19255. // onCancel: Function
  19256. // callback when user has canceled the popup by
  19257. // 1. hitting ESC or
  19258. // 2. by using the popup widget's proprietary cancel mechanism (like a cancel button in a dialog);
  19259. // i.e. whenever popupWidget.onCancel() is called, args.onCancel is called
  19260. // onClose: Function
  19261. // callback whenever this popup is closed
  19262. // onExecute: Function
  19263. // callback when user "executed" on the popup/sub-popup by selecting a menu choice, etc. (top menu only)
  19264. // padding: dijit.__Position
  19265. // adding a buffer around the opening position. This is only useful when around is not set.
  19266. this.popup = popup;
  19267. this.parent = parent;
  19268. this.around = around;
  19269. this.x = x;
  19270. this.y = y;
  19271. this.orient = orient;
  19272. this.onCancel = onCancel;
  19273. this.onClose = onClose;
  19274. this.onExecute = onExecute;
  19275. this.padding = padding;
  19276. }
  19277. =====*/
  19278. /*=====
  19279. dijit.popup = {
  19280. // summary:
  19281. // Used to show drop downs (ex: the select list of a ComboBox)
  19282. // or popups (ex: right-click context menus).
  19283. //
  19284. // Access via require(["dijit/popup"], function(popup){ ... }).
  19285. moveOffScreen: function(widget){
  19286. // summary:
  19287. // Moves the popup widget off-screen.
  19288. // Do not use this method to hide popups when not in use, because
  19289. // that will create an accessibility issue: the offscreen popup is
  19290. // still in the tabbing order.
  19291. // widget: dijit._WidgetBase
  19292. // The widget
  19293. },
  19294. hide: function(widget){
  19295. // summary:
  19296. // Hide this popup widget (until it is ready to be shown).
  19297. // Initialization for widgets that will be used as popups
  19298. //
  19299. // Also puts widget inside a wrapper DIV (if not already in one)
  19300. //
  19301. // If popup widget needs to layout it should
  19302. // do so when it is made visible, and popup._onShow() is called.
  19303. // widget: dijit._WidgetBase
  19304. // The widget
  19305. },
  19306. open: function(args){
  19307. // summary:
  19308. // Popup the widget at the specified position
  19309. // example:
  19310. // opening at the mouse position
  19311. // | popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY});
  19312. // example:
  19313. // opening the widget as a dropdown
  19314. // | popup.open({parent: this, popup: menuWidget, around: this.domNode, onClose: function(){...}});
  19315. //
  19316. // Note that whatever widget called dijit.popup.open() should also listen to its own _onBlur callback
  19317. // (fired from _base/focus.js) to know that focus has moved somewhere else and thus the popup should be closed.
  19318. // args: dijit.popup.__OpenArgs
  19319. // Parameters
  19320. return {}; // Object specifying which position was chosen
  19321. },
  19322. close: function(popup){
  19323. // summary:
  19324. // Close specified popup and any popups that it parented.
  19325. // If no popup is specified, closes all popups.
  19326. // widget: dijit._WidgetBase?
  19327. // The widget, optional
  19328. }
  19329. };
  19330. =====*/
  19331. function destroyWrapper(){
  19332. // summary:
  19333. // Function to destroy wrapper when popup widget is destroyed.
  19334. // Left in this scope to avoid memory leak on IE8 on refresh page, see #15206.
  19335. if(this._popupWrapper){
  19336. domConstruct.destroy(this._popupWrapper);
  19337. delete this._popupWrapper;
  19338. }
  19339. }
  19340. var PopupManager = declare(null, {
  19341. // _stack: dijit._Widget[]
  19342. // Stack of currently popped up widgets.
  19343. // (someone opened _stack[0], and then it opened _stack[1], etc.)
  19344. _stack: [],
  19345. // _beginZIndex: Number
  19346. // Z-index of the first popup. (If first popup opens other
  19347. // popups they get a higher z-index.)
  19348. _beginZIndex: 1000,
  19349. _idGen: 1,
  19350. _createWrapper: function(/*Widget*/ widget){
  19351. // summary:
  19352. // Initialization for widgets that will be used as popups.
  19353. // Puts widget inside a wrapper DIV (if not already in one),
  19354. // and returns pointer to that wrapper DIV.
  19355. var wrapper = widget._popupWrapper,
  19356. node = widget.domNode;
  19357. if(!wrapper){
  19358. // Create wrapper <div> for when this widget [in the future] will be used as a popup.
  19359. // This is done early because of IE bugs where creating/moving DOM nodes causes focus
  19360. // to go wonky, see tests/robot/Toolbar.html to reproduce
  19361. wrapper = domConstruct.create("div", {
  19362. "class":"dijitPopup",
  19363. style:{ display: "none"},
  19364. role: "presentation"
  19365. }, win.body());
  19366. wrapper.appendChild(node);
  19367. var s = node.style;
  19368. s.display = "";
  19369. s.visibility = "";
  19370. s.position = "";
  19371. s.top = "0px";
  19372. widget._popupWrapper = wrapper;
  19373. aspect.after(widget, "destroy", destroyWrapper, true);
  19374. }
  19375. return wrapper;
  19376. },
  19377. moveOffScreen: function(/*Widget*/ widget){
  19378. // summary:
  19379. // Moves the popup widget off-screen.
  19380. // Do not use this method to hide popups when not in use, because
  19381. // that will create an accessibility issue: the offscreen popup is
  19382. // still in the tabbing order.
  19383. // Create wrapper if not already there
  19384. var wrapper = this._createWrapper(widget);
  19385. domStyle.set(wrapper, {
  19386. visibility: "hidden",
  19387. top: "-9999px", // prevent transient scrollbar causing misalign (#5776), and initial flash in upper left (#10111)
  19388. display: ""
  19389. });
  19390. },
  19391. hide: function(/*Widget*/ widget){
  19392. // summary:
  19393. // Hide this popup widget (until it is ready to be shown).
  19394. // Initialization for widgets that will be used as popups
  19395. //
  19396. // Also puts widget inside a wrapper DIV (if not already in one)
  19397. //
  19398. // If popup widget needs to layout it should
  19399. // do so when it is made visible, and popup._onShow() is called.
  19400. // Create wrapper if not already there
  19401. var wrapper = this._createWrapper(widget);
  19402. domStyle.set(wrapper, "display", "none");
  19403. },
  19404. getTopPopup: function(){
  19405. // summary:
  19406. // Compute the closest ancestor popup that's *not* a child of another popup.
  19407. // Ex: For a TooltipDialog with a button that spawns a tree of menus, find the popup of the button.
  19408. var stack = this._stack;
  19409. for(var pi=stack.length-1; pi > 0 && stack[pi].parent === stack[pi-1].widget; pi--){
  19410. /* do nothing, just trying to get right value for pi */
  19411. }
  19412. return stack[pi];
  19413. },
  19414. open: function(/*dijit.popup.__OpenArgs*/ args){
  19415. // summary:
  19416. // Popup the widget at the specified position
  19417. //
  19418. // example:
  19419. // opening at the mouse position
  19420. // | popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY});
  19421. //
  19422. // example:
  19423. // opening the widget as a dropdown
  19424. // | popup.open({parent: this, popup: menuWidget, around: this.domNode, onClose: function(){...}});
  19425. //
  19426. // Note that whatever widget called dijit.popup.open() should also listen to its own _onBlur callback
  19427. // (fired from _base/focus.js) to know that focus has moved somewhere else and thus the popup should be closed.
  19428. var stack = this._stack,
  19429. widget = args.popup,
  19430. orient = args.orient || ["below", "below-alt", "above", "above-alt"],
  19431. ltr = args.parent ? args.parent.isLeftToRight() : domGeometry.isBodyLtr(),
  19432. around = args.around,
  19433. id = (args.around && args.around.id) ? (args.around.id+"_dropdown") : ("popup_"+this._idGen++);
  19434. // If we are opening a new popup that isn't a child of a currently opened popup, then
  19435. // close currently opened popup(s). This should happen automatically when the old popups
  19436. // gets the _onBlur() event, except that the _onBlur() event isn't reliable on IE, see [22198].
  19437. while(stack.length && (!args.parent || !dom.isDescendant(args.parent.domNode, stack[stack.length-1].widget.domNode))){
  19438. this.close(stack[stack.length-1].widget);
  19439. }
  19440. // Get pointer to popup wrapper, and create wrapper if it doesn't exist
  19441. var wrapper = this._createWrapper(widget);
  19442. domAttr.set(wrapper, {
  19443. id: id,
  19444. style: {
  19445. zIndex: this._beginZIndex + stack.length
  19446. },
  19447. "class": "dijitPopup " + (widget.baseClass || widget["class"] || "").split(" ")[0] +"Popup",
  19448. dijitPopupParent: args.parent ? args.parent.id : ""
  19449. });
  19450. if(has("ie") || has("mozilla")){
  19451. if(!widget.bgIframe){
  19452. // setting widget.bgIframe triggers cleanup in _Widget.destroy()
  19453. widget.bgIframe = new BackgroundIframe(wrapper);
  19454. }
  19455. }
  19456. // position the wrapper node and make it visible
  19457. var best = around ?
  19458. place.around(wrapper, around, orient, ltr, widget.orient ? lang.hitch(widget, "orient") : null) :
  19459. place.at(wrapper, args, orient == 'R' ? ['TR','BR','TL','BL'] : ['TL','BL','TR','BR'], args.padding);
  19460. wrapper.style.display = "";
  19461. wrapper.style.visibility = "visible";
  19462. widget.domNode.style.visibility = "visible"; // counteract effects from _HasDropDown
  19463. var handlers = [];
  19464. // provide default escape and tab key handling
  19465. // (this will work for any widget, not just menu)
  19466. handlers.push(on(wrapper, connect._keypress, lang.hitch(this, function(evt){
  19467. if(evt.charOrCode == keys.ESCAPE && args.onCancel){
  19468. event.stop(evt);
  19469. args.onCancel();
  19470. }else if(evt.charOrCode === keys.TAB){
  19471. event.stop(evt);
  19472. var topPopup = this.getTopPopup();
  19473. if(topPopup && topPopup.onCancel){
  19474. topPopup.onCancel();
  19475. }
  19476. }
  19477. })));
  19478. // watch for cancel/execute events on the popup and notify the caller
  19479. // (for a menu, "execute" means clicking an item)
  19480. if(widget.onCancel && args.onCancel){
  19481. handlers.push(widget.on("cancel", args.onCancel));
  19482. }
  19483. handlers.push(widget.on(widget.onExecute ? "execute" : "change", lang.hitch(this, function(){
  19484. var topPopup = this.getTopPopup();
  19485. if(topPopup && topPopup.onExecute){
  19486. topPopup.onExecute();
  19487. }
  19488. })));
  19489. stack.push({
  19490. widget: widget,
  19491. parent: args.parent,
  19492. onExecute: args.onExecute,
  19493. onCancel: args.onCancel,
  19494. onClose: args.onClose,
  19495. handlers: handlers
  19496. });
  19497. if(widget.onOpen){
  19498. // TODO: in 2.0 standardize onShow() (used by StackContainer) and onOpen() (used here)
  19499. widget.onOpen(best);
  19500. }
  19501. return best;
  19502. },
  19503. close: function(/*Widget?*/ popup){
  19504. // summary:
  19505. // Close specified popup and any popups that it parented.
  19506. // If no popup is specified, closes all popups.
  19507. var stack = this._stack;
  19508. // Basically work backwards from the top of the stack closing popups
  19509. // until we hit the specified popup, but IIRC there was some issue where closing
  19510. // a popup would cause others to close too. Thus if we are trying to close B in [A,B,C]
  19511. // closing C might close B indirectly and then the while() condition will run where stack==[A]...
  19512. // so the while condition is constructed defensively.
  19513. while((popup && array.some(stack, function(elem){return elem.widget == popup;})) ||
  19514. (!popup && stack.length)){
  19515. var top = stack.pop(),
  19516. widget = top.widget,
  19517. onClose = top.onClose;
  19518. if(widget.onClose){
  19519. // TODO: in 2.0 standardize onHide() (used by StackContainer) and onClose() (used here)
  19520. widget.onClose();
  19521. }
  19522. var h;
  19523. while(h = top.handlers.pop()){ h.remove(); }
  19524. // Hide the widget and it's wrapper unless it has already been destroyed in above onClose() etc.
  19525. if(widget && widget.domNode){
  19526. this.hide(widget);
  19527. }
  19528. if(onClose){
  19529. onClose();
  19530. }
  19531. }
  19532. }
  19533. });
  19534. return (dijit.popup = new PopupManager());
  19535. });
  19536. },
  19537. 'dijit/_base/manager':function(){
  19538. define("dijit/_base/manager", [
  19539. "dojo/_base/array",
  19540. "dojo/_base/config", // defaultDuration
  19541. "../registry",
  19542. ".." // for setting exports to dijit namespace
  19543. ], function(array, config, registry, dijit){
  19544. // module:
  19545. // dijit/_base/manager
  19546. // summary:
  19547. // Shim to methods on registry, plus a few other declarations.
  19548. // New code should access dijit/registry directly when possible.
  19549. /*=====
  19550. dijit.byId = function(id){
  19551. // summary:
  19552. // Returns a widget by it's id, or if passed a widget, no-op (like dom.byId())
  19553. // id: String|dijit._Widget
  19554. return registry.byId(id); // dijit._Widget
  19555. };
  19556. dijit.getUniqueId = function(widgetType){
  19557. // summary:
  19558. // Generates a unique id for a given widgetType
  19559. // widgetType: String
  19560. return registry.getUniqueId(widgetType); // String
  19561. };
  19562. dijit.findWidgets = function(root){
  19563. // summary:
  19564. // Search subtree under root returning widgets found.
  19565. // Doesn't search for nested widgets (ie, widgets inside other widgets).
  19566. // root: DOMNode
  19567. return registry.findWidgets(root);
  19568. };
  19569. dijit._destroyAll = function(){
  19570. // summary:
  19571. // Code to destroy all widgets and do other cleanup on page unload
  19572. return registry._destroyAll();
  19573. };
  19574. dijit.byNode = function(node){
  19575. // summary:
  19576. // Returns the widget corresponding to the given DOMNode
  19577. // node: DOMNode
  19578. return registry.byNode(node); // dijit._Widget
  19579. };
  19580. dijit.getEnclosingWidget = function(node){
  19581. // summary:
  19582. // Returns the widget whose DOM tree contains the specified DOMNode, or null if
  19583. // the node is not contained within the DOM tree of any widget
  19584. // node: DOMNode
  19585. return registry.getEnclosingWidget(node);
  19586. };
  19587. =====*/
  19588. array.forEach(["byId", "getUniqueId", "findWidgets", "_destroyAll", "byNode", "getEnclosingWidget"], function(name){
  19589. dijit[name] = registry[name];
  19590. });
  19591. /*=====
  19592. dojo.mixin(dijit, {
  19593. // defaultDuration: Integer
  19594. // The default fx.animation speed (in ms) to use for all Dijit
  19595. // transitional fx.animations, unless otherwise specified
  19596. // on a per-instance basis. Defaults to 200, overrided by
  19597. // `djConfig.defaultDuration`
  19598. defaultDuration: 200
  19599. });
  19600. =====*/
  19601. dijit.defaultDuration = config["defaultDuration"] || 200;
  19602. return dijit;
  19603. });
  19604. },
  19605. 'dojox/grid/enhanced/plugins/_SelectionPreserver':function(){
  19606. define("dojox/grid/enhanced/plugins/_SelectionPreserver", [
  19607. "dojo/_base/declare",
  19608. "dojo/_base/lang",
  19609. "dojo/_base/connect",
  19610. '../../_SelectionPreserver'
  19611. ], function(declare, lang, connect, _SelectionPreserver){
  19612. return declare("dojox.grid.enhanced.plugins._SelectionPreserver", _SelectionPreserver, {
  19613. // summary:
  19614. // Preserve selections across various user actions.
  19615. //
  19616. // description:
  19617. // Extends dojox.grid._SelectionPreserver adding a bit more support to make selection persistence working well
  19618. // with various EnhancedGrid features, e.g. filtering, nested sorting, pagination, select all etc.
  19619. //
  19620. // Precondition - Identifier(id) is required for store, as id is used for differentiating row items.
  19621. // Known issue - The preserved selections might be inaccurate if some unloaded rows are previously selected by range(e.g.SHIFT + click)
  19622. //
  19623. // example:
  19624. // | //To turn on this - set 'keepSelection' attribute to true
  19625. // | <div dojoType="dojox.grid.EnhancedGrid" keepSelection = true .../>
  19626. constructor: function(selection){
  19627. var grid = this.grid;
  19628. grid.onSelectedById = this.onSelectedById;
  19629. this._oldClearData = grid._clearData;
  19630. var self = this;
  19631. grid._clearData = function(){
  19632. self._updateMapping(!grid._noInternalMapping);
  19633. self._trustSelection = [];
  19634. self._oldClearData.apply(grid, arguments);
  19635. };
  19636. this._connects.push(
  19637. connect.connect(selection, 'selectRange', lang.hitch(this, '_updateMapping', true, true, false)),
  19638. connect.connect(selection, 'deselectRange', lang.hitch(this, '_updateMapping', true, false, false)),
  19639. connect.connect(selection, 'deselectAll', lang.hitch(this, '_updateMapping', true, false, true))
  19640. );
  19641. },
  19642. destroy: function(){
  19643. this.inherited(arguments);
  19644. this.grid._clearData = this._oldClearData;
  19645. },
  19646. reset: function(){
  19647. this.inherited(arguments);
  19648. this._idMap = [];
  19649. this._trustSelection = [];
  19650. this._defaultSelected = false;
  19651. },
  19652. _reSelectById: function(item, index){
  19653. // summary:
  19654. // Overwritten
  19655. var s = this.selection, g = this.grid;
  19656. if(item && g._hasIdentity){
  19657. var id = g.store.getIdentity(item);
  19658. if(this._selectedById[id] === undefined){
  19659. if(!this._trustSelection[index]){
  19660. s.selected[index] = this._defaultSelected;
  19661. }
  19662. }else{
  19663. s.selected[index] = this._selectedById[id];
  19664. }
  19665. this._idMap.push(id);
  19666. g.onSelectedById(id, index, s.selected[index]);
  19667. }
  19668. },
  19669. _selectById: function(toSelect, inItemOrIndex){
  19670. // summary:
  19671. // Overwritten
  19672. if(!this.inherited(arguments)){
  19673. this._trustSelection[inItemOrIndex] = true;
  19674. }
  19675. },
  19676. onSelectedById: function(id, rowIndex, value){},
  19677. _updateMapping: function(trustSelection, isSelect, isForAll, from, to){
  19678. // summary:
  19679. // This function try to keep the selection info updated when range selection is performed.
  19680. // 1. Calculate how many unloaded rows are there;
  19681. // 2. update _selectedById data if grid.selection._selected can be trusted, so loaded but unselected rows can
  19682. // be properly recorded.
  19683. var s = this.selection, g = this.grid, flag = 0, unloaded = 0, i, id;
  19684. for(i = g.rowCount - 1; i >= 0; --i){
  19685. if(!g._by_idx[i]){
  19686. ++unloaded;
  19687. flag += s.selected[i] ? 1 : -1;
  19688. }else{
  19689. id = g._by_idx[i].idty;
  19690. if(id && (trustSelection || this._selectedById[id] === undefined)){
  19691. this._selectedById[id] = !!s.selected[i];
  19692. }
  19693. }
  19694. }
  19695. if(unloaded){
  19696. this._defaultSelected = flag > 0;
  19697. }
  19698. if(!isForAll && from !== undefined && to !== undefined){
  19699. isForAll = !g.usingPagination && Math.abs(to - from + 1) === g.rowCount;
  19700. }
  19701. // When deselectAll, make sure every thing is deselected, even if it was selected but not loaded now.
  19702. // This occurs only when pagination's "All" is used.
  19703. if(isForAll && (!g.usingPagination || g.selectionMode === 'single')){
  19704. for(i = this._idMap.length - 1; i >= 0; --i){
  19705. this._selectedById[this._idMap[i]] = isSelect;
  19706. }
  19707. }
  19708. }
  19709. });
  19710. });
  19711. },
  19712. 'dojox/grid/_RowManager':function(){
  19713. define("dojox/grid/_RowManager", [
  19714. "dojo/_base/declare",
  19715. "dojo/_base/lang",
  19716. "dojo/dom-class"
  19717. ], function(declare, lang, domClass){
  19718. var setStyleText = function(inNode, inStyleText){
  19719. if(inNode.style.cssText == undefined){
  19720. inNode.setAttribute("style", inStyleText);
  19721. }else{
  19722. inNode.style.cssText = inStyleText;
  19723. }
  19724. };
  19725. return declare("dojox.grid._RowManager", null, {
  19726. // Stores information about grid rows. Owned by grid and used internally.
  19727. constructor: function(inGrid){
  19728. this.grid = inGrid;
  19729. },
  19730. linesToEms: 2,
  19731. overRow: -2,
  19732. // styles
  19733. prepareStylingRow: function(inRowIndex, inRowNode){
  19734. return {
  19735. index: inRowIndex,
  19736. node: inRowNode,
  19737. odd: Boolean(inRowIndex&1),
  19738. selected: !!this.grid.selection.isSelected(inRowIndex),
  19739. over: this.isOver(inRowIndex),
  19740. customStyles: "",
  19741. customClasses: "dojoxGridRow"
  19742. };
  19743. },
  19744. styleRowNode: function(inRowIndex, inRowNode){
  19745. var row = this.prepareStylingRow(inRowIndex, inRowNode);
  19746. this.grid.onStyleRow(row);
  19747. this.applyStyles(row);
  19748. },
  19749. applyStyles: function(inRow){
  19750. var i = inRow;
  19751. i.node.className = i.customClasses;
  19752. var h = i.node.style.height;
  19753. setStyleText(i.node, i.customStyles + ';' + (i.node._style||''));
  19754. i.node.style.height = h;
  19755. },
  19756. updateStyles: function(inRowIndex){
  19757. this.grid.updateRowStyles(inRowIndex);
  19758. },
  19759. // states and events
  19760. setOverRow: function(inRowIndex){
  19761. var last = this.overRow;
  19762. this.overRow = inRowIndex;
  19763. if((last!=this.overRow)&&(lang.isString(last) || last >= 0)){
  19764. this.updateStyles(last);
  19765. }
  19766. this.updateStyles(this.overRow);
  19767. },
  19768. isOver: function(inRowIndex){
  19769. return (this.overRow == inRowIndex && !domClass.contains(this.grid.domNode, "dojoxGridColumnResizing"));
  19770. }
  19771. });
  19772. });
  19773. },
  19774. 'dojo/dnd/Mover':function(){
  19775. define("dojo/dnd/Mover", ["../main", "../Evented", "../touch", "./common", "./autoscroll"], function(dojo, Evented, touch) {
  19776. // module:
  19777. // dojo/dnd/Mover
  19778. // summary:
  19779. // TODOC
  19780. dojo.declare("dojo.dnd.Mover", [Evented], {
  19781. constructor: function(node, e, host){
  19782. // summary:
  19783. // an object which makes a node follow the mouse, or touch-drag on touch devices.
  19784. // Used as a default mover, and as a base class for custom movers.
  19785. // node: Node
  19786. // a node (or node's id) to be moved
  19787. // e: Event
  19788. // a mouse event, which started the move;
  19789. // only pageX and pageY properties are used
  19790. // host: Object?
  19791. // object which implements the functionality of the move,
  19792. // and defines proper events (onMoveStart and onMoveStop)
  19793. this.node = dojo.byId(node);
  19794. this.marginBox = {l: e.pageX, t: e.pageY};
  19795. this.mouseButton = e.button;
  19796. var h = (this.host = host), d = node.ownerDocument;
  19797. this.events = [
  19798. // At the start of a drag, onFirstMove is called, and then the following two
  19799. // connects are disconnected
  19800. dojo.connect(d, touch.move, this, "onFirstMove"),
  19801. // These are called continually during the drag
  19802. dojo.connect(d, touch.move, this, "onMouseMove"),
  19803. // And these are called at the end of the drag
  19804. dojo.connect(d, touch.release, this, "onMouseUp"),
  19805. // cancel text selection and text dragging
  19806. dojo.connect(d, "ondragstart", dojo.stopEvent),
  19807. dojo.connect(d.body, "onselectstart", dojo.stopEvent)
  19808. ];
  19809. // notify that the move has started
  19810. if(h && h.onMoveStart){
  19811. h.onMoveStart(this);
  19812. }
  19813. },
  19814. // mouse event processors
  19815. onMouseMove: function(e){
  19816. // summary:
  19817. // event processor for onmousemove/ontouchmove
  19818. // e: Event
  19819. // mouse/touch event
  19820. dojo.dnd.autoScroll(e);
  19821. var m = this.marginBox;
  19822. this.host.onMove(this, {l: m.l + e.pageX, t: m.t + e.pageY}, e);
  19823. dojo.stopEvent(e);
  19824. },
  19825. onMouseUp: function(e){
  19826. if(dojo.isWebKit && dojo.isMac && this.mouseButton == 2 ?
  19827. e.button == 0 : this.mouseButton == e.button){ // TODO Should condition be met for touch devices, too?
  19828. this.destroy();
  19829. }
  19830. dojo.stopEvent(e);
  19831. },
  19832. // utilities
  19833. onFirstMove: function(e){
  19834. // summary:
  19835. // makes the node absolute; it is meant to be called only once.
  19836. // relative and absolutely positioned nodes are assumed to use pixel units
  19837. var s = this.node.style, l, t, h = this.host;
  19838. switch(s.position){
  19839. case "relative":
  19840. case "absolute":
  19841. // assume that left and top values are in pixels already
  19842. l = Math.round(parseFloat(s.left)) || 0;
  19843. t = Math.round(parseFloat(s.top)) || 0;
  19844. break;
  19845. default:
  19846. s.position = "absolute"; // enforcing the absolute mode
  19847. var m = dojo.marginBox(this.node);
  19848. // event.pageX/pageY (which we used to generate the initial
  19849. // margin box) includes padding and margin set on the body.
  19850. // However, setting the node's position to absolute and then
  19851. // doing dojo.marginBox on it *doesn't* take that additional
  19852. // space into account - so we need to subtract the combined
  19853. // padding and margin. We use getComputedStyle and
  19854. // _getMarginBox/_getContentBox to avoid the extra lookup of
  19855. // the computed style.
  19856. var b = dojo.doc.body;
  19857. var bs = dojo.getComputedStyle(b);
  19858. var bm = dojo._getMarginBox(b, bs);
  19859. var bc = dojo._getContentBox(b, bs);
  19860. l = m.l - (bc.l - bm.l);
  19861. t = m.t - (bc.t - bm.t);
  19862. break;
  19863. }
  19864. this.marginBox.l = l - this.marginBox.l;
  19865. this.marginBox.t = t - this.marginBox.t;
  19866. if(h && h.onFirstMove){
  19867. h.onFirstMove(this, e);
  19868. }
  19869. // Disconnect onmousemove and ontouchmove events that call this function
  19870. dojo.disconnect(this.events.shift());
  19871. },
  19872. destroy: function(){
  19873. // summary:
  19874. // stops the move, deletes all references, so the object can be garbage-collected
  19875. dojo.forEach(this.events, dojo.disconnect);
  19876. // undo global settings
  19877. var h = this.host;
  19878. if(h && h.onMoveStop){
  19879. h.onMoveStop(this);
  19880. }
  19881. // destroy objects
  19882. this.events = this.node = this.host = null;
  19883. }
  19884. });
  19885. return dojo.dnd.Mover;
  19886. });
  19887. },
  19888. 'dijit/BackgroundIframe':function(){
  19889. define("dijit/BackgroundIframe", [
  19890. "require", // require.toUrl
  19891. ".", // to export dijit.BackgroundIframe
  19892. "dojo/_base/config",
  19893. "dojo/dom-construct", // domConstruct.create
  19894. "dojo/dom-style", // domStyle.set
  19895. "dojo/_base/lang", // lang.extend lang.hitch
  19896. "dojo/on",
  19897. "dojo/_base/sniff", // has("ie"), has("mozilla"), has("quirks")
  19898. "dojo/_base/window" // win.doc.createElement
  19899. ], function(require, dijit, config, domConstruct, domStyle, lang, on, has, win){
  19900. // module:
  19901. // dijit/BackgroundIFrame
  19902. // summary:
  19903. // new dijit.BackgroundIframe(node)
  19904. // Makes a background iframe as a child of node, that fills
  19905. // area (and position) of node
  19906. // TODO: remove _frames, it isn't being used much, since popups never release their
  19907. // iframes (see [22236])
  19908. var _frames = new function(){
  19909. // summary:
  19910. // cache of iframes
  19911. var queue = [];
  19912. this.pop = function(){
  19913. var iframe;
  19914. if(queue.length){
  19915. iframe = queue.pop();
  19916. iframe.style.display="";
  19917. }else{
  19918. if(has("ie") < 9){
  19919. var burl = config["dojoBlankHtmlUrl"] || require.toUrl("dojo/resources/blank.html") || "javascript:\"\"";
  19920. var html="<iframe src='" + burl + "' role='presentation'"
  19921. + " style='position: absolute; left: 0px; top: 0px;"
  19922. + "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
  19923. iframe = win.doc.createElement(html);
  19924. }else{
  19925. iframe = domConstruct.create("iframe");
  19926. iframe.src = 'javascript:""';
  19927. iframe.className = "dijitBackgroundIframe";
  19928. iframe.setAttribute("role", "presentation");
  19929. domStyle.set(iframe, "opacity", 0.1);
  19930. }
  19931. iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didn't work.
  19932. }
  19933. return iframe;
  19934. };
  19935. this.push = function(iframe){
  19936. iframe.style.display="none";
  19937. queue.push(iframe);
  19938. }
  19939. }();
  19940. dijit.BackgroundIframe = function(/*DomNode*/ node){
  19941. // summary:
  19942. // For IE/FF z-index schenanigans. id attribute is required.
  19943. //
  19944. // description:
  19945. // new dijit.BackgroundIframe(node)
  19946. // Makes a background iframe as a child of node, that fills
  19947. // area (and position) of node
  19948. if(!node.id){ throw new Error("no id"); }
  19949. if(has("ie") || has("mozilla")){
  19950. var iframe = (this.iframe = _frames.pop());
  19951. node.appendChild(iframe);
  19952. if(has("ie")<7 || has("quirks")){
  19953. this.resize(node);
  19954. this._conn = on(node, 'resize', lang.hitch(this, function(){
  19955. this.resize(node);
  19956. }));
  19957. }else{
  19958. domStyle.set(iframe, {
  19959. width: '100%',
  19960. height: '100%'
  19961. });
  19962. }
  19963. }
  19964. };
  19965. lang.extend(dijit.BackgroundIframe, {
  19966. resize: function(node){
  19967. // summary:
  19968. // Resize the iframe so it's the same size as node.
  19969. // Needed on IE6 and IE/quirks because height:100% doesn't work right.
  19970. if(this.iframe){
  19971. domStyle.set(this.iframe, {
  19972. width: node.offsetWidth + 'px',
  19973. height: node.offsetHeight + 'px'
  19974. });
  19975. }
  19976. },
  19977. destroy: function(){
  19978. // summary:
  19979. // destroy the iframe
  19980. if(this._conn){
  19981. this._conn.remove();
  19982. this._conn = null;
  19983. }
  19984. if(this.iframe){
  19985. _frames.push(this.iframe);
  19986. delete this.iframe;
  19987. }
  19988. }
  19989. });
  19990. return dijit.BackgroundIframe;
  19991. });
  19992. },
  19993. 'dojo/dnd/Avatar':function(){
  19994. define("dojo/dnd/Avatar", ["../main", "./common"], function(dojo) {
  19995. // module:
  19996. // dojo/dnd/Avatar
  19997. // summary:
  19998. // TODOC
  19999. dojo.declare("dojo.dnd.Avatar", null, {
  20000. // summary:
  20001. // Object that represents transferred DnD items visually
  20002. // manager: Object
  20003. // a DnD manager object
  20004. constructor: function(manager){
  20005. this.manager = manager;
  20006. this.construct();
  20007. },
  20008. // methods
  20009. construct: function(){
  20010. // summary:
  20011. // constructor function;
  20012. // it is separate so it can be (dynamically) overwritten in case of need
  20013. this.isA11y = dojo.hasClass(dojo.body(),"dijit_a11y");
  20014. var a = dojo.create("table", {
  20015. "class": "dojoDndAvatar",
  20016. style: {
  20017. position: "absolute",
  20018. zIndex: "1999",
  20019. margin: "0px"
  20020. }
  20021. }),
  20022. source = this.manager.source, node,
  20023. b = dojo.create("tbody", null, a),
  20024. tr = dojo.create("tr", null, b),
  20025. td = dojo.create("td", null, tr),
  20026. icon = this.isA11y ? dojo.create("span", {
  20027. id : "a11yIcon",
  20028. innerHTML : this.manager.copy ? '+' : "<"
  20029. }, td) : null,
  20030. span = dojo.create("span", {
  20031. innerHTML: source.generateText ? this._generateText() : ""
  20032. }, td),
  20033. k = Math.min(5, this.manager.nodes.length), i = 0;
  20034. // we have to set the opacity on IE only after the node is live
  20035. dojo.attr(tr, {
  20036. "class": "dojoDndAvatarHeader",
  20037. style: {opacity: 0.9}
  20038. });
  20039. for(; i < k; ++i){
  20040. if(source.creator){
  20041. // create an avatar representation of the node
  20042. node = source._normalizedCreator(source.getItem(this.manager.nodes[i].id).data, "avatar").node;
  20043. }else{
  20044. // or just clone the node and hope it works
  20045. node = this.manager.nodes[i].cloneNode(true);
  20046. if(node.tagName.toLowerCase() == "tr"){
  20047. // insert extra table nodes
  20048. var table = dojo.create("table"),
  20049. tbody = dojo.create("tbody", null, table);
  20050. tbody.appendChild(node);
  20051. node = table;
  20052. }
  20053. }
  20054. node.id = "";
  20055. tr = dojo.create("tr", null, b);
  20056. td = dojo.create("td", null, tr);
  20057. td.appendChild(node);
  20058. dojo.attr(tr, {
  20059. "class": "dojoDndAvatarItem",
  20060. style: {opacity: (9 - i) / 10}
  20061. });
  20062. }
  20063. this.node = a;
  20064. },
  20065. destroy: function(){
  20066. // summary:
  20067. // destructor for the avatar; called to remove all references so it can be garbage-collected
  20068. dojo.destroy(this.node);
  20069. this.node = false;
  20070. },
  20071. update: function(){
  20072. // summary:
  20073. // updates the avatar to reflect the current DnD state
  20074. dojo[(this.manager.canDropFlag ? "add" : "remove") + "Class"](this.node, "dojoDndAvatarCanDrop");
  20075. if (this.isA11y){
  20076. var icon = dojo.byId("a11yIcon");
  20077. var text = '+'; // assume canDrop && copy
  20078. if (this.manager.canDropFlag && !this.manager.copy) {
  20079. text = '< '; // canDrop && move
  20080. }else if (!this.manager.canDropFlag && !this.manager.copy) {
  20081. text = "o"; //!canDrop && move
  20082. }else if(!this.manager.canDropFlag){
  20083. text = 'x'; // !canDrop && copy
  20084. }
  20085. icon.innerHTML=text;
  20086. }
  20087. // replace text
  20088. dojo.query(("tr.dojoDndAvatarHeader td span" +(this.isA11y ? " span" : "")), this.node).forEach(
  20089. function(node){
  20090. node.innerHTML = this._generateText();
  20091. }, this);
  20092. },
  20093. _generateText: function(){
  20094. // summary: generates a proper text to reflect copying or moving of items
  20095. return this.manager.nodes.length.toString();
  20096. }
  20097. });
  20098. return dojo.dnd.Avatar;
  20099. });
  20100. },
  20101. 'dijit/form/_Spinner':function(){
  20102. require({cache:{
  20103. 'url:dijit/form/templates/Spinner.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\"\r\n\tid=\"widget_${id}\" role=\"presentation\"\r\n\t><div class=\"dijitReset dijitButtonNode dijitSpinnerButtonContainer\"\r\n\t\t><input class=\"dijitReset dijitInputField dijitSpinnerButtonInner\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t/><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitUpArrowButton\"\r\n\t\t\tdata-dojo-attach-point=\"upArrowNode\"\r\n\t\t\t><div class=\"dijitArrowButtonInner\"\r\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9650;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t\t\t\t${_buttonInputDisabled}\r\n\t\t\t/></div\r\n\t\t></div\r\n\t\t><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitDownArrowButton\"\r\n\t\t\tdata-dojo-attach-point=\"downArrowNode\"\r\n\t\t\t><div class=\"dijitArrowButtonInner\"\r\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9660;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t\t\t\t${_buttonInputDisabled}\r\n\t\t\t/></div\r\n\t\t></div\r\n\t></div\r\n\t><div class='dijitReset dijitValidationContainer'\r\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t/></div\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class='dijitReset dijitInputInner' data-dojo-attach-point=\"textbox,focusNode\" type=\"${type}\" data-dojo-attach-event=\"onkeypress:_onKeyPress\"\r\n\t\t\trole=\"spinbutton\" autocomplete=\"off\" ${!nameAttrSetting}\r\n\t/></div\r\n></div>\r\n"}});
  20104. define("dijit/form/_Spinner", [
  20105. "dojo/_base/declare", // declare
  20106. "dojo/_base/event", // event.stop
  20107. "dojo/keys", // keys keys.DOWN_ARROW keys.PAGE_DOWN keys.PAGE_UP keys.UP_ARROW
  20108. "dojo/_base/lang", // lang.hitch
  20109. "dojo/_base/sniff", // has("mozilla")
  20110. "dijit/typematic",
  20111. "./RangeBoundTextBox",
  20112. "dojo/text!./templates/Spinner.html",
  20113. "./_TextBoxMixin" // selectInputText
  20114. ], function(declare, event, keys, lang, has, typematic, RangeBoundTextBox, template, _TextBoxMixin){
  20115. /*=====
  20116. var RangeBoundTextBox = dijit.form.RangeBoundTextBox;
  20117. =====*/
  20118. // module:
  20119. // dijit/form/_Spinner
  20120. // summary:
  20121. // Mixin for validation widgets with a spinner.
  20122. return declare("dijit.form._Spinner", RangeBoundTextBox, {
  20123. // summary:
  20124. // Mixin for validation widgets with a spinner.
  20125. // description:
  20126. // This class basically (conceptually) extends `dijit.form.ValidationTextBox`.
  20127. // It modifies the template to have up/down arrows, and provides related handling code.
  20128. // defaultTimeout: Number
  20129. // Number of milliseconds before a held arrow key or up/down button becomes typematic
  20130. defaultTimeout: 500,
  20131. // minimumTimeout: Number
  20132. // minimum number of milliseconds that typematic event fires when held key or button is held
  20133. minimumTimeout: 10,
  20134. // timeoutChangeRate: Number
  20135. // Fraction of time used to change the typematic timer between events.
  20136. // 1.0 means that each typematic event fires at defaultTimeout intervals.
  20137. // < 1.0 means that each typematic event fires at an increasing faster rate.
  20138. timeoutChangeRate: 0.90,
  20139. // smallDelta: Number
  20140. // Adjust the value by this much when spinning using the arrow keys/buttons
  20141. smallDelta: 1,
  20142. // largeDelta: Number
  20143. // Adjust the value by this much when spinning using the PgUp/Dn keys
  20144. largeDelta: 10,
  20145. templateString: template,
  20146. baseClass: "dijitTextBox dijitSpinner",
  20147. // Set classes like dijitUpArrowButtonHover or dijitDownArrowButtonActive depending on
  20148. // mouse action over specified node
  20149. cssStateNodes: {
  20150. "upArrowNode": "dijitUpArrowButton",
  20151. "downArrowNode": "dijitDownArrowButton"
  20152. },
  20153. adjust: function(val /*=====, delta =====*/){
  20154. // summary:
  20155. // Overridable function used to adjust a primitive value(Number/Date/...) by the delta amount specified.
  20156. // The val is adjusted in a way that makes sense to the object type.
  20157. // val: Object
  20158. // delta: Number
  20159. // tags:
  20160. // protected extension
  20161. return val;
  20162. },
  20163. _arrowPressed: function(/*Node*/ nodePressed, /*Number*/ direction, /*Number*/ increment){
  20164. // summary:
  20165. // Handler for arrow button or arrow key being pressed
  20166. if(this.disabled || this.readOnly){ return; }
  20167. this._setValueAttr(this.adjust(this.get('value'), direction*increment), false);
  20168. _TextBoxMixin.selectInputText(this.textbox, this.textbox.value.length);
  20169. },
  20170. _arrowReleased: function(/*Node*/ /*===== node =====*/){
  20171. // summary:
  20172. // Handler for arrow button or arrow key being released
  20173. this._wheelTimer = null;
  20174. },
  20175. _typematicCallback: function(/*Number*/ count, /*DOMNode*/ node, /*Event*/ evt){
  20176. var inc=this.smallDelta;
  20177. if(node == this.textbox){
  20178. var key = evt.charOrCode;
  20179. inc = (key == keys.PAGE_UP || key == keys.PAGE_DOWN) ? this.largeDelta : this.smallDelta;
  20180. node = (key == keys.UP_ARROW || key == keys.PAGE_UP) ? this.upArrowNode : this.downArrowNode;
  20181. }
  20182. if(count == -1){ this._arrowReleased(node); }
  20183. else{ this._arrowPressed(node, (node == this.upArrowNode) ? 1 : -1, inc); }
  20184. },
  20185. _wheelTimer: null,
  20186. _mouseWheeled: function(/*Event*/ evt){
  20187. // summary:
  20188. // Mouse wheel listener where supported
  20189. event.stop(evt);
  20190. // FIXME: Safari bubbles
  20191. // be nice to DOH and scroll as much as the event says to
  20192. var wheelDelta = evt.wheelDelta / 120;
  20193. if(Math.floor(wheelDelta) != wheelDelta){
  20194. // If not an int multiple of 120, then its touchpad scrolling.
  20195. // This can change very fast so just assume 1 wheel click to make it more manageable.
  20196. wheelDelta = evt.wheelDelta > 0 ? 1 : -1;
  20197. }
  20198. var scrollAmount = evt.detail ? (evt.detail * -1) : wheelDelta;
  20199. if(scrollAmount !== 0){
  20200. var node = this[(scrollAmount > 0 ? "upArrowNode" : "downArrowNode" )];
  20201. this._arrowPressed(node, scrollAmount, this.smallDelta);
  20202. if(!this._wheelTimer){
  20203. clearTimeout(this._wheelTimer);
  20204. }
  20205. this._wheelTimer = setTimeout(lang.hitch(this,"_arrowReleased",node), 50);
  20206. }
  20207. },
  20208. postCreate: function(){
  20209. this.inherited(arguments);
  20210. // extra listeners
  20211. this.connect(this.domNode, !has("mozilla") ? "onmousewheel" : 'DOMMouseScroll', "_mouseWheeled");
  20212. 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));
  20213. 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));
  20214. 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));
  20215. 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));
  20216. }
  20217. });
  20218. });
  20219. },
  20220. 'dijit/form/Button':function(){
  20221. require({cache:{
  20222. 'url:dijit/form/templates/Button.html':"<span class=\"dijit dijitReset dijitInline\" role=\"presentation\"\r\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\r\n\t\tdata-dojo-attach-event=\"ondijitclick:_onClick\" role=\"presentation\"\r\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\r\n\t\t\tdata-dojo-attach-point=\"titleNode,focusNode\"\r\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\r\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" data-dojo-attach-point=\"iconNode\"></span\r\n\t\t\t><span class=\"dijitReset dijitToggleButtonIconChar\">&#x25CF;</span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\r\n\t\t\t\tid=\"${id}_label\"\r\n\t\t\t\tdata-dojo-attach-point=\"containerNode\"\r\n\t\t\t></span\r\n\t\t></span\r\n\t></span\r\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\r\n\t\ttabIndex=\"-1\" role=\"presentation\" data-dojo-attach-point=\"valueNode\"\r\n/></span>\r\n"}});
  20223. define("dijit/form/Button", [
  20224. "require",
  20225. "dojo/_base/declare", // declare
  20226. "dojo/dom-class", // domClass.toggle
  20227. "dojo/_base/kernel", // kernel.deprecated
  20228. "dojo/_base/lang", // lang.trim
  20229. "dojo/ready",
  20230. "./_FormWidget",
  20231. "./_ButtonMixin",
  20232. "dojo/text!./templates/Button.html"
  20233. ], function(require, declare, domClass, kernel, lang, ready, _FormWidget, _ButtonMixin, template){
  20234. /*=====
  20235. var _FormWidget = dijit.form._FormWidget;
  20236. var _ButtonMixin = dijit.form._ButtonMixin;
  20237. =====*/
  20238. // module:
  20239. // dijit/form/Button
  20240. // summary:
  20241. // Button widget
  20242. // Back compat w/1.6, remove for 2.0
  20243. if(!kernel.isAsync){
  20244. ready(0, function(){
  20245. var requires = ["dijit/form/DropDownButton", "dijit/form/ComboButton", "dijit/form/ToggleButton"];
  20246. require(requires); // use indirection so modules not rolled into a build
  20247. });
  20248. }
  20249. return declare("dijit.form.Button", [_FormWidget, _ButtonMixin], {
  20250. // summary:
  20251. // Basically the same thing as a normal HTML button, but with special styling.
  20252. // description:
  20253. // Buttons can display a label, an icon, or both.
  20254. // A label should always be specified (through innerHTML) or the label
  20255. // attribute. It can be hidden via showLabel=false.
  20256. // example:
  20257. // | <button data-dojo-type="dijit.form.Button" onClick="...">Hello world</button>
  20258. //
  20259. // example:
  20260. // | var button1 = new dijit.form.Button({label: "hello world", onClick: foo});
  20261. // | dojo.body().appendChild(button1.domNode);
  20262. // showLabel: Boolean
  20263. // Set this to true to hide the label text and display only the icon.
  20264. // (If showLabel=false then iconClass must be specified.)
  20265. // Especially useful for toolbars.
  20266. // If showLabel=true, the label will become the title (a.k.a. tooltip/hint) of the icon.
  20267. //
  20268. // The exception case is for computers in high-contrast mode, where the label
  20269. // will still be displayed, since the icon doesn't appear.
  20270. showLabel: true,
  20271. // iconClass: String
  20272. // Class to apply to DOMNode in button to make it display an icon
  20273. iconClass: "dijitNoIcon",
  20274. _setIconClassAttr: { node: "iconNode", type: "class" },
  20275. baseClass: "dijitButton",
  20276. templateString: template,
  20277. // Map widget attributes to DOMNode attributes.
  20278. _setValueAttr: "valueNode",
  20279. _onClick: function(/*Event*/ e){
  20280. // summary:
  20281. // Internal function to handle click actions
  20282. var ok = this.inherited(arguments);
  20283. if(ok){
  20284. if(this.valueNode){
  20285. this.valueNode.click();
  20286. e.preventDefault(); // cancel BUTTON click and continue with hidden INPUT click
  20287. // leave ok = true so that subclasses can do what they need to do
  20288. }
  20289. }
  20290. return ok;
  20291. },
  20292. _fillContent: function(/*DomNode*/ source){
  20293. // Overrides _Templated._fillContent().
  20294. // If button label is specified as srcNodeRef.innerHTML rather than
  20295. // this.params.label, handle it here.
  20296. // TODO: remove the method in 2.0, parser will do it all for me
  20297. if(source && (!this.params || !("label" in this.params))){
  20298. var sourceLabel = lang.trim(source.innerHTML);
  20299. if(sourceLabel){
  20300. this.label = sourceLabel; // _applyAttributes will be called after buildRendering completes to update the DOM
  20301. }
  20302. }
  20303. },
  20304. _setShowLabelAttr: function(val){
  20305. if(this.containerNode){
  20306. domClass.toggle(this.containerNode, "dijitDisplayNone", !val);
  20307. }
  20308. this._set("showLabel", val);
  20309. },
  20310. setLabel: function(/*String*/ content){
  20311. // summary:
  20312. // Deprecated. Use set('label', ...) instead.
  20313. kernel.deprecated("dijit.form.Button.setLabel() is deprecated. Use set('label', ...) instead.", "", "2.0");
  20314. this.set("label", content);
  20315. },
  20316. _setLabelAttr: function(/*String*/ content){
  20317. // summary:
  20318. // Hook for set('label', ...) to work.
  20319. // description:
  20320. // Set the label (text) of the button; takes an HTML string.
  20321. // If the label is hidden (showLabel=false) then and no title has
  20322. // been specified, then label is also set as title attribute of icon.
  20323. this.inherited(arguments);
  20324. if(!this.showLabel && !("title" in this.params)){
  20325. this.titleNode.title = lang.trim(this.containerNode.innerText || this.containerNode.textContent || '');
  20326. }
  20327. }
  20328. });
  20329. });
  20330. },
  20331. 'dojo/dnd/move':function(){
  20332. define("dojo/dnd/move", ["../main", "./Mover", "./Moveable"], function(dojo) {
  20333. // module:
  20334. // dojo/dnd/move
  20335. // summary:
  20336. // TODOC
  20337. /*=====
  20338. dojo.declare("dojo.dnd.move.__constrainedMoveableArgs", [dojo.dnd.__MoveableArgs], {
  20339. // constraints: Function
  20340. // Calculates a constraint box.
  20341. // It is called in a context of the moveable object.
  20342. constraints: function(){},
  20343. // within: Boolean
  20344. // restrict move within boundaries.
  20345. within: false
  20346. });
  20347. =====*/
  20348. dojo.declare("dojo.dnd.move.constrainedMoveable", dojo.dnd.Moveable, {
  20349. // object attributes (for markup)
  20350. constraints: function(){},
  20351. within: false,
  20352. constructor: function(node, params){
  20353. // summary:
  20354. // an object that makes a node moveable
  20355. // node: Node
  20356. // a node (or node's id) to be moved
  20357. // params: dojo.dnd.move.__constrainedMoveableArgs?
  20358. // an optional object with additional parameters;
  20359. // the rest is passed to the base class
  20360. if(!params){ params = {}; }
  20361. this.constraints = params.constraints;
  20362. this.within = params.within;
  20363. },
  20364. onFirstMove: function(/* dojo.dnd.Mover */ mover){
  20365. // summary:
  20366. // called during the very first move notification;
  20367. // can be used to initialize coordinates, can be overwritten.
  20368. var c = this.constraintBox = this.constraints.call(this, mover);
  20369. c.r = c.l + c.w;
  20370. c.b = c.t + c.h;
  20371. if(this.within){
  20372. var mb = dojo._getMarginSize(mover.node);
  20373. c.r -= mb.w;
  20374. c.b -= mb.h;
  20375. }
  20376. },
  20377. onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
  20378. // summary:
  20379. // called during every move notification;
  20380. // should actually move the node; can be overwritten.
  20381. var c = this.constraintBox, s = mover.node.style;
  20382. this.onMoving(mover, leftTop);
  20383. leftTop.l = leftTop.l < c.l ? c.l : c.r < leftTop.l ? c.r : leftTop.l;
  20384. leftTop.t = leftTop.t < c.t ? c.t : c.b < leftTop.t ? c.b : leftTop.t;
  20385. s.left = leftTop.l + "px";
  20386. s.top = leftTop.t + "px";
  20387. this.onMoved(mover, leftTop);
  20388. }
  20389. });
  20390. /*=====
  20391. dojo.declare("dojo.dnd.move.__boxConstrainedMoveableArgs", [dojo.dnd.move.__constrainedMoveableArgs], {
  20392. // box: Object
  20393. // a constraint box
  20394. box: {}
  20395. });
  20396. =====*/
  20397. dojo.declare("dojo.dnd.move.boxConstrainedMoveable", dojo.dnd.move.constrainedMoveable, {
  20398. // box:
  20399. // object attributes (for markup)
  20400. box: {},
  20401. constructor: function(node, params){
  20402. // summary:
  20403. // an object, which makes a node moveable
  20404. // node: Node
  20405. // a node (or node's id) to be moved
  20406. // params: dojo.dnd.move.__boxConstrainedMoveableArgs?
  20407. // an optional object with parameters
  20408. var box = params && params.box;
  20409. this.constraints = function(){ return box; };
  20410. }
  20411. });
  20412. /*=====
  20413. dojo.declare("dojo.dnd.move.__parentConstrainedMoveableArgs", [dojo.dnd.move.__constrainedMoveableArgs], {
  20414. // area: String
  20415. // A parent's area to restrict the move.
  20416. // Can be "margin", "border", "padding", or "content".
  20417. area: ""
  20418. });
  20419. =====*/
  20420. dojo.declare("dojo.dnd.move.parentConstrainedMoveable", dojo.dnd.move.constrainedMoveable, {
  20421. // area:
  20422. // object attributes (for markup)
  20423. area: "content",
  20424. constructor: function(node, params){
  20425. // summary:
  20426. // an object, which makes a node moveable
  20427. // node: Node
  20428. // a node (or node's id) to be moved
  20429. // params: dojo.dnd.move.__parentConstrainedMoveableArgs?
  20430. // an optional object with parameters
  20431. var area = params && params.area;
  20432. this.constraints = function(){
  20433. var n = this.node.parentNode,
  20434. s = dojo.getComputedStyle(n),
  20435. mb = dojo._getMarginBox(n, s);
  20436. if(area == "margin"){
  20437. return mb; // Object
  20438. }
  20439. var t = dojo._getMarginExtents(n, s);
  20440. mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
  20441. if(area == "border"){
  20442. return mb; // Object
  20443. }
  20444. t = dojo._getBorderExtents(n, s);
  20445. mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
  20446. if(area == "padding"){
  20447. return mb; // Object
  20448. }
  20449. t = dojo._getPadExtents(n, s);
  20450. mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
  20451. return mb; // Object
  20452. };
  20453. }
  20454. });
  20455. // patching functions one level up for compatibility
  20456. dojo.dnd.constrainedMover = dojo.dnd.move.constrainedMover;
  20457. dojo.dnd.boxConstrainedMover = dojo.dnd.move.boxConstrainedMover;
  20458. dojo.dnd.parentConstrainedMover = dojo.dnd.move.parentConstrainedMover;
  20459. return dojo.dnd.move;
  20460. });
  20461. },
  20462. 'dijit/_WidgetBase':function(){
  20463. define("dijit/_WidgetBase", [
  20464. "require", // require.toUrl
  20465. "dojo/_base/array", // array.forEach array.map
  20466. "dojo/aspect",
  20467. "dojo/_base/config", // config.blankGif
  20468. "dojo/_base/connect", // connect.connect
  20469. "dojo/_base/declare", // declare
  20470. "dojo/dom", // dom.byId
  20471. "dojo/dom-attr", // domAttr.set domAttr.remove
  20472. "dojo/dom-class", // domClass.add domClass.replace
  20473. "dojo/dom-construct", // domConstruct.create domConstruct.destroy domConstruct.place
  20474. "dojo/dom-geometry", // isBodyLtr
  20475. "dojo/dom-style", // domStyle.set, domStyle.get
  20476. "dojo/_base/kernel",
  20477. "dojo/_base/lang", // mixin(), isArray(), etc.
  20478. "dojo/on",
  20479. "dojo/ready",
  20480. "dojo/Stateful", // Stateful
  20481. "dojo/topic",
  20482. "dojo/_base/window", // win.doc.createTextNode
  20483. "./registry" // registry.getUniqueId(), registry.findWidgets()
  20484. ], function(require, array, aspect, config, connect, declare,
  20485. dom, domAttr, domClass, domConstruct, domGeometry, domStyle, kernel,
  20486. lang, on, ready, Stateful, topic, win, registry){
  20487. /*=====
  20488. var Stateful = dojo.Stateful;
  20489. =====*/
  20490. // module:
  20491. // dijit/_WidgetBase
  20492. // summary:
  20493. // Future base class for all Dijit widgets.
  20494. // For back-compat, remove in 2.0.
  20495. if(!kernel.isAsync){
  20496. ready(0, function(){
  20497. var requires = ["dijit/_base/manager"];
  20498. require(requires); // use indirection so modules not rolled into a build
  20499. });
  20500. }
  20501. // Nested hash listing attributes for each tag, all strings in lowercase.
  20502. // ex: {"div": {"style": true, "tabindex" true}, "form": { ...
  20503. var tagAttrs = {};
  20504. function getAttrs(obj){
  20505. var ret = {};
  20506. for(var attr in obj){
  20507. ret[attr.toLowerCase()] = true;
  20508. }
  20509. return ret;
  20510. }
  20511. function nonEmptyAttrToDom(attr){
  20512. // summary:
  20513. // Returns a setter function that copies the attribute to this.domNode,
  20514. // or removes the attribute from this.domNode, depending on whether the
  20515. // value is defined or not.
  20516. return function(val){
  20517. domAttr[val ? "set" : "remove"](this.domNode, attr, val);
  20518. this._set(attr, val);
  20519. };
  20520. }
  20521. return declare("dijit._WidgetBase", Stateful, {
  20522. // summary:
  20523. // Future base class for all Dijit widgets.
  20524. // description:
  20525. // Future base class for all Dijit widgets.
  20526. // _Widget extends this class adding support for various features needed by desktop.
  20527. //
  20528. // Provides stubs for widget lifecycle methods for subclasses to extend, like postMixInProperties(), buildRendering(),
  20529. // postCreate(), startup(), and destroy(), and also public API methods like set(), get(), and watch().
  20530. //
  20531. // Widgets can provide custom setters/getters for widget attributes, which are called automatically by set(name, value).
  20532. // For an attribute XXX, define methods _setXXXAttr() and/or _getXXXAttr().
  20533. //
  20534. // _setXXXAttr can also be a string/hash/array mapping from a widget attribute XXX to the widget's DOMNodes:
  20535. //
  20536. // - DOM node attribute
  20537. // | _setFocusAttr: {node: "focusNode", type: "attribute"}
  20538. // | _setFocusAttr: "focusNode" (shorthand)
  20539. // | _setFocusAttr: "" (shorthand, maps to this.domNode)
  20540. // Maps this.focus to this.focusNode.focus, or (last example) this.domNode.focus
  20541. //
  20542. // - DOM node innerHTML
  20543. // | _setTitleAttr: { node: "titleNode", type: "innerHTML" }
  20544. // Maps this.title to this.titleNode.innerHTML
  20545. //
  20546. // - DOM node innerText
  20547. // | _setTitleAttr: { node: "titleNode", type: "innerText" }
  20548. // Maps this.title to this.titleNode.innerText
  20549. //
  20550. // - DOM node CSS class
  20551. // | _setMyClassAttr: { node: "domNode", type: "class" }
  20552. // Maps this.myClass to this.domNode.className
  20553. //
  20554. // If the value of _setXXXAttr is an array, then each element in the array matches one of the
  20555. // formats of the above list.
  20556. //
  20557. // If the custom setter is null, no action is performed other than saving the new value
  20558. // in the widget (in this).
  20559. //
  20560. // If no custom setter is defined for an attribute, then it will be copied
  20561. // to this.focusNode (if the widget defines a focusNode), or this.domNode otherwise.
  20562. // That's only done though for attributes that match DOMNode attributes (title,
  20563. // alt, aria-labelledby, etc.)
  20564. // id: [const] String
  20565. // A unique, opaque ID string that can be assigned by users or by the
  20566. // system. If the developer passes an ID which is known not to be
  20567. // unique, the specified ID is ignored and the system-generated ID is
  20568. // used instead.
  20569. id: "",
  20570. _setIdAttr: "domNode", // to copy to this.domNode even for auto-generated id's
  20571. // lang: [const] String
  20572. // Rarely used. Overrides the default Dojo locale used to render this widget,
  20573. // as defined by the [HTML LANG](http://www.w3.org/TR/html401/struct/dirlang.html#adef-lang) attribute.
  20574. // Value must be among the list of locales specified during by the Dojo bootstrap,
  20575. // formatted according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt) (like en-us).
  20576. lang: "",
  20577. // set on domNode even when there's a focus node. but don't set lang="", since that's invalid.
  20578. _setLangAttr: nonEmptyAttrToDom("lang"),
  20579. // dir: [const] String
  20580. // Bi-directional support, as defined by the [HTML DIR](http://www.w3.org/TR/html401/struct/dirlang.html#adef-dir)
  20581. // attribute. Either left-to-right "ltr" or right-to-left "rtl". If undefined, widgets renders in page's
  20582. // default direction.
  20583. dir: "",
  20584. // set on domNode even when there's a focus node. but don't set dir="", since that's invalid.
  20585. _setDirAttr: nonEmptyAttrToDom("dir"), // to set on domNode even when there's a focus node
  20586. // textDir: String
  20587. // Bi-directional support, the main variable which is responsible for the direction of the text.
  20588. // The text direction can be different than the GUI direction by using this parameter in creation
  20589. // of a widget.
  20590. // Allowed values:
  20591. // 1. "ltr"
  20592. // 2. "rtl"
  20593. // 3. "auto" - contextual the direction of a text defined by first strong letter.
  20594. // By default is as the page direction.
  20595. textDir: "",
  20596. // class: String
  20597. // HTML class attribute
  20598. "class": "",
  20599. _setClassAttr: { node: "domNode", type: "class" },
  20600. // style: String||Object
  20601. // HTML style attributes as cssText string or name/value hash
  20602. style: "",
  20603. // title: String
  20604. // HTML title attribute.
  20605. //
  20606. // For form widgets this specifies a tooltip to display when hovering over
  20607. // the widget (just like the native HTML title attribute).
  20608. //
  20609. // For TitlePane or for when this widget is a child of a TabContainer, AccordionContainer,
  20610. // etc., it's used to specify the tab label, accordion pane title, etc.
  20611. title: "",
  20612. // tooltip: String
  20613. // When this widget's title attribute is used to for a tab label, accordion pane title, etc.,
  20614. // this specifies the tooltip to appear when the mouse is hovered over that text.
  20615. tooltip: "",
  20616. // baseClass: [protected] String
  20617. // Root CSS class of the widget (ex: dijitTextBox), used to construct CSS classes to indicate
  20618. // widget state.
  20619. baseClass: "",
  20620. // srcNodeRef: [readonly] DomNode
  20621. // pointer to original DOM node
  20622. srcNodeRef: null,
  20623. // domNode: [readonly] DomNode
  20624. // This is our visible representation of the widget! Other DOM
  20625. // Nodes may by assigned to other properties, usually through the
  20626. // template system's data-dojo-attach-point syntax, but the domNode
  20627. // property is the canonical "top level" node in widget UI.
  20628. domNode: null,
  20629. // containerNode: [readonly] DomNode
  20630. // Designates where children of the source DOM node will be placed.
  20631. // "Children" in this case refers to both DOM nodes and widgets.
  20632. // For example, for myWidget:
  20633. //
  20634. // | <div data-dojo-type=myWidget>
  20635. // | <b> here's a plain DOM node
  20636. // | <span data-dojo-type=subWidget>and a widget</span>
  20637. // | <i> and another plain DOM node </i>
  20638. // | </div>
  20639. //
  20640. // containerNode would point to:
  20641. //
  20642. // | <b> here's a plain DOM node
  20643. // | <span data-dojo-type=subWidget>and a widget</span>
  20644. // | <i> and another plain DOM node </i>
  20645. //
  20646. // In templated widgets, "containerNode" is set via a
  20647. // data-dojo-attach-point assignment.
  20648. //
  20649. // containerNode must be defined for any widget that accepts innerHTML
  20650. // (like ContentPane or BorderContainer or even Button), and conversely
  20651. // is null for widgets that don't, like TextBox.
  20652. containerNode: null,
  20653. /*=====
  20654. // _started: Boolean
  20655. // startup() has completed.
  20656. _started: false,
  20657. =====*/
  20658. // attributeMap: [protected] Object
  20659. // Deprecated. Instead of attributeMap, widget should have a _setXXXAttr attribute
  20660. // for each XXX attribute to be mapped to the DOM.
  20661. //
  20662. // attributeMap sets up a "binding" between attributes (aka properties)
  20663. // of the widget and the widget's DOM.
  20664. // Changes to widget attributes listed in attributeMap will be
  20665. // reflected into the DOM.
  20666. //
  20667. // For example, calling set('title', 'hello')
  20668. // on a TitlePane will automatically cause the TitlePane's DOM to update
  20669. // with the new title.
  20670. //
  20671. // attributeMap is a hash where the key is an attribute of the widget,
  20672. // and the value reflects a binding to a:
  20673. //
  20674. // - DOM node attribute
  20675. // | focus: {node: "focusNode", type: "attribute"}
  20676. // Maps this.focus to this.focusNode.focus
  20677. //
  20678. // - DOM node innerHTML
  20679. // | title: { node: "titleNode", type: "innerHTML" }
  20680. // Maps this.title to this.titleNode.innerHTML
  20681. //
  20682. // - DOM node innerText
  20683. // | title: { node: "titleNode", type: "innerText" }
  20684. // Maps this.title to this.titleNode.innerText
  20685. //
  20686. // - DOM node CSS class
  20687. // | myClass: { node: "domNode", type: "class" }
  20688. // Maps this.myClass to this.domNode.className
  20689. //
  20690. // If the value is an array, then each element in the array matches one of the
  20691. // formats of the above list.
  20692. //
  20693. // There are also some shorthands for backwards compatibility:
  20694. // - string --> { node: string, type: "attribute" }, for example:
  20695. // | "focusNode" ---> { node: "focusNode", type: "attribute" }
  20696. // - "" --> { node: "domNode", type: "attribute" }
  20697. attributeMap: {},
  20698. // _blankGif: [protected] String
  20699. // Path to a blank 1x1 image.
  20700. // Used by <img> nodes in templates that really get their image via CSS background-image.
  20701. _blankGif: config.blankGif || require.toUrl("dojo/resources/blank.gif"),
  20702. //////////// INITIALIZATION METHODS ///////////////////////////////////////
  20703. postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){
  20704. // summary:
  20705. // Kicks off widget instantiation. See create() for details.
  20706. // tags:
  20707. // private
  20708. this.create(params, srcNodeRef);
  20709. },
  20710. create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){
  20711. // summary:
  20712. // Kick off the life-cycle of a widget
  20713. // params:
  20714. // Hash of initialization parameters for widget, including
  20715. // scalar values (like title, duration etc.) and functions,
  20716. // typically callbacks like onClick.
  20717. // srcNodeRef:
  20718. // If a srcNodeRef (DOM node) is specified:
  20719. // - use srcNodeRef.innerHTML as my contents
  20720. // - if this is a behavioral widget then apply behavior
  20721. // to that srcNodeRef
  20722. // - otherwise, replace srcNodeRef with my generated DOM
  20723. // tree
  20724. // description:
  20725. // Create calls a number of widget methods (postMixInProperties, buildRendering, postCreate,
  20726. // etc.), some of which of you'll want to override. See http://dojotoolkit.org/reference-guide/dijit/_WidgetBase.html
  20727. // for a discussion of the widget creation lifecycle.
  20728. //
  20729. // Of course, adventurous developers could override create entirely, but this should
  20730. // only be done as a last resort.
  20731. // tags:
  20732. // private
  20733. // store pointer to original DOM tree
  20734. this.srcNodeRef = dom.byId(srcNodeRef);
  20735. // For garbage collection. An array of listener handles returned by this.connect() / this.subscribe()
  20736. this._connects = [];
  20737. // For widgets internal to this widget, invisible to calling code
  20738. this._supportingWidgets = [];
  20739. // this is here for back-compat, remove in 2.0 (but check NodeList-instantiate.html test)
  20740. if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; }
  20741. // mix in our passed parameters
  20742. if(params){
  20743. this.params = params;
  20744. lang.mixin(this, params);
  20745. }
  20746. this.postMixInProperties();
  20747. // generate an id for the widget if one wasn't specified
  20748. // (be sure to do this before buildRendering() because that function might
  20749. // expect the id to be there.)
  20750. if(!this.id){
  20751. this.id = registry.getUniqueId(this.declaredClass.replace(/\./g,"_"));
  20752. }
  20753. registry.add(this);
  20754. this.buildRendering();
  20755. if(this.domNode){
  20756. // Copy attributes listed in attributeMap into the [newly created] DOM for the widget.
  20757. // Also calls custom setters for all attributes with custom setters.
  20758. this._applyAttributes();
  20759. // If srcNodeRef was specified, then swap out original srcNode for this widget's DOM tree.
  20760. // For 2.0, move this after postCreate(). postCreate() shouldn't depend on the
  20761. // widget being attached to the DOM since it isn't when a widget is created programmatically like
  20762. // new MyWidget({}). See #11635.
  20763. var source = this.srcNodeRef;
  20764. if(source && source.parentNode && this.domNode !== source){
  20765. source.parentNode.replaceChild(this.domNode, source);
  20766. }
  20767. }
  20768. if(this.domNode){
  20769. // Note: for 2.0 may want to rename widgetId to dojo._scopeName + "_widgetId",
  20770. // assuming that dojo._scopeName even exists in 2.0
  20771. this.domNode.setAttribute("widgetId", this.id);
  20772. }
  20773. this.postCreate();
  20774. // If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC.
  20775. if(this.srcNodeRef && !this.srcNodeRef.parentNode){
  20776. delete this.srcNodeRef;
  20777. }
  20778. this._created = true;
  20779. },
  20780. _applyAttributes: function(){
  20781. // summary:
  20782. // Step during widget creation to copy widget attributes to the
  20783. // DOM according to attributeMap and _setXXXAttr objects, and also to call
  20784. // custom _setXXXAttr() methods.
  20785. //
  20786. // Skips over blank/false attribute values, unless they were explicitly specified
  20787. // as parameters to the widget, since those are the default anyway,
  20788. // and setting tabIndex="" is different than not setting tabIndex at all.
  20789. //
  20790. // For backwards-compatibility reasons attributeMap overrides _setXXXAttr when
  20791. // _setXXXAttr is a hash/string/array, but _setXXXAttr as a functions override attributeMap.
  20792. // tags:
  20793. // private
  20794. // Get list of attributes where this.set(name, value) will do something beyond
  20795. // setting this[name] = value. Specifically, attributes that have:
  20796. // - associated _setXXXAttr() method/hash/string/array
  20797. // - entries in attributeMap.
  20798. var ctor = this.constructor,
  20799. list = ctor._setterAttrs;
  20800. if(!list){
  20801. list = (ctor._setterAttrs = []);
  20802. for(var attr in this.attributeMap){
  20803. list.push(attr);
  20804. }
  20805. var proto = ctor.prototype;
  20806. for(var fxName in proto){
  20807. if(fxName in this.attributeMap){ continue; }
  20808. var setterName = "_set" + fxName.replace(/^[a-z]|-[a-zA-Z]/g, function(c){ return c.charAt(c.length-1).toUpperCase(); }) + "Attr";
  20809. if(setterName in proto){
  20810. list.push(fxName);
  20811. }
  20812. }
  20813. }
  20814. // Call this.set() for each attribute that was either specified as parameter to constructor,
  20815. // or was found above and has a default non-null value. For correlated attributes like value and displayedValue, the one
  20816. // specified as a parameter should take precedence, so apply attributes in this.params last.
  20817. // Particularly important for new DateTextBox({displayedValue: ...}) since DateTextBox's default value is
  20818. // NaN and thus is not ignored like a default value of "".
  20819. array.forEach(list, function(attr){
  20820. if(this.params && attr in this.params){
  20821. // skip this one, do it below
  20822. }else if(this[attr]){
  20823. this.set(attr, this[attr]);
  20824. }
  20825. }, this);
  20826. for(var param in this.params){
  20827. this.set(param, this[param]);
  20828. }
  20829. },
  20830. postMixInProperties: function(){
  20831. // summary:
  20832. // Called after the parameters to the widget have been read-in,
  20833. // but before the widget template is instantiated. Especially
  20834. // useful to set properties that are referenced in the widget
  20835. // template.
  20836. // tags:
  20837. // protected
  20838. },
  20839. buildRendering: function(){
  20840. // summary:
  20841. // Construct the UI for this widget, setting this.domNode.
  20842. // Most widgets will mixin `dijit._TemplatedMixin`, which implements this method.
  20843. // tags:
  20844. // protected
  20845. if(!this.domNode){
  20846. // Create root node if it wasn't created by _Templated
  20847. this.domNode = this.srcNodeRef || domConstruct.create('div');
  20848. }
  20849. // baseClass is a single class name or occasionally a space-separated list of names.
  20850. // Add those classes to the DOMNode. If RTL mode then also add with Rtl suffix.
  20851. // TODO: make baseClass custom setter
  20852. if(this.baseClass){
  20853. var classes = this.baseClass.split(" ");
  20854. if(!this.isLeftToRight()){
  20855. classes = classes.concat( array.map(classes, function(name){ return name+"Rtl"; }));
  20856. }
  20857. domClass.add(this.domNode, classes);
  20858. }
  20859. },
  20860. postCreate: function(){
  20861. // summary:
  20862. // Processing after the DOM fragment is created
  20863. // description:
  20864. // Called after the DOM fragment has been created, but not necessarily
  20865. // added to the document. Do not include any operations which rely on
  20866. // node dimensions or placement.
  20867. // tags:
  20868. // protected
  20869. },
  20870. startup: function(){
  20871. // summary:
  20872. // Processing after the DOM fragment is added to the document
  20873. // description:
  20874. // Called after a widget and its children have been created and added to the page,
  20875. // and all related widgets have finished their create() cycle, up through postCreate().
  20876. // This is useful for composite widgets that need to control or layout sub-widgets.
  20877. // Many layout widgets can use this as a wiring phase.
  20878. if(this._started){ return; }
  20879. this._started = true;
  20880. array.forEach(this.getChildren(), function(obj){
  20881. if(!obj._started && !obj._destroyed && lang.isFunction(obj.startup)){
  20882. obj.startup();
  20883. obj._started = true;
  20884. }
  20885. });
  20886. },
  20887. //////////// DESTROY FUNCTIONS ////////////////////////////////
  20888. destroyRecursive: function(/*Boolean?*/ preserveDom){
  20889. // summary:
  20890. // Destroy this widget and its descendants
  20891. // description:
  20892. // This is the generic "destructor" function that all widget users
  20893. // should call to cleanly discard with a widget. Once a widget is
  20894. // destroyed, it is removed from the manager object.
  20895. // preserveDom:
  20896. // If true, this method will leave the original DOM structure
  20897. // alone of descendant Widgets. Note: This will NOT work with
  20898. // dijit._Templated widgets.
  20899. this._beingDestroyed = true;
  20900. this.destroyDescendants(preserveDom);
  20901. this.destroy(preserveDom);
  20902. },
  20903. destroy: function(/*Boolean*/ preserveDom){
  20904. // summary:
  20905. // Destroy this widget, but not its descendants.
  20906. // This method will, however, destroy internal widgets such as those used within a template.
  20907. // preserveDom: Boolean
  20908. // If true, this method will leave the original DOM structure alone.
  20909. // Note: This will not yet work with _Templated widgets
  20910. this._beingDestroyed = true;
  20911. this.uninitialize();
  20912. // remove this.connect() and this.subscribe() listeners
  20913. var c;
  20914. while((c = this._connects.pop())){
  20915. c.remove();
  20916. }
  20917. // destroy widgets created as part of template, etc.
  20918. var w;
  20919. while((w = this._supportingWidgets.pop())){
  20920. if(w.destroyRecursive){
  20921. w.destroyRecursive();
  20922. }else if(w.destroy){
  20923. w.destroy();
  20924. }
  20925. }
  20926. this.destroyRendering(preserveDom);
  20927. registry.remove(this.id);
  20928. this._destroyed = true;
  20929. },
  20930. destroyRendering: function(/*Boolean?*/ preserveDom){
  20931. // summary:
  20932. // Destroys the DOM nodes associated with this widget
  20933. // preserveDom:
  20934. // If true, this method will leave the original DOM structure alone
  20935. // during tear-down. Note: this will not work with _Templated
  20936. // widgets yet.
  20937. // tags:
  20938. // protected
  20939. if(this.bgIframe){
  20940. this.bgIframe.destroy(preserveDom);
  20941. delete this.bgIframe;
  20942. }
  20943. if(this.domNode){
  20944. if(preserveDom){
  20945. domAttr.remove(this.domNode, "widgetId");
  20946. }else{
  20947. domConstruct.destroy(this.domNode);
  20948. }
  20949. delete this.domNode;
  20950. }
  20951. if(this.srcNodeRef){
  20952. if(!preserveDom){
  20953. domConstruct.destroy(this.srcNodeRef);
  20954. }
  20955. delete this.srcNodeRef;
  20956. }
  20957. },
  20958. destroyDescendants: function(/*Boolean?*/ preserveDom){
  20959. // summary:
  20960. // Recursively destroy the children of this widget and their
  20961. // descendants.
  20962. // preserveDom:
  20963. // If true, the preserveDom attribute is passed to all descendant
  20964. // widget's .destroy() method. Not for use with _Templated
  20965. // widgets.
  20966. // get all direct descendants and destroy them recursively
  20967. array.forEach(this.getChildren(), function(widget){
  20968. if(widget.destroyRecursive){
  20969. widget.destroyRecursive(preserveDom);
  20970. }
  20971. });
  20972. },
  20973. uninitialize: function(){
  20974. // summary:
  20975. // Stub function. Override to implement custom widget tear-down
  20976. // behavior.
  20977. // tags:
  20978. // protected
  20979. return false;
  20980. },
  20981. ////////////////// GET/SET, CUSTOM SETTERS, ETC. ///////////////////
  20982. _setStyleAttr: function(/*String||Object*/ value){
  20983. // summary:
  20984. // Sets the style attribute of the widget according to value,
  20985. // which is either a hash like {height: "5px", width: "3px"}
  20986. // or a plain string
  20987. // description:
  20988. // Determines which node to set the style on based on style setting
  20989. // in attributeMap.
  20990. // tags:
  20991. // protected
  20992. var mapNode = this.domNode;
  20993. // Note: technically we should revert any style setting made in a previous call
  20994. // to his method, but that's difficult to keep track of.
  20995. if(lang.isObject(value)){
  20996. domStyle.set(mapNode, value);
  20997. }else{
  20998. if(mapNode.style.cssText){
  20999. mapNode.style.cssText += "; " + value;
  21000. }else{
  21001. mapNode.style.cssText = value;
  21002. }
  21003. }
  21004. this._set("style", value);
  21005. },
  21006. _attrToDom: function(/*String*/ attr, /*String*/ value, /*Object?*/ commands){
  21007. // summary:
  21008. // Reflect a widget attribute (title, tabIndex, duration etc.) to
  21009. // the widget DOM, as specified by commands parameter.
  21010. // If commands isn't specified then it's looked up from attributeMap.
  21011. // Note some attributes like "type"
  21012. // cannot be processed this way as they are not mutable.
  21013. //
  21014. // tags:
  21015. // private
  21016. commands = arguments.length >= 3 ? commands : this.attributeMap[attr];
  21017. array.forEach(lang.isArray(commands) ? commands : [commands], function(command){
  21018. // Get target node and what we are doing to that node
  21019. var mapNode = this[command.node || command || "domNode"]; // DOM node
  21020. var type = command.type || "attribute"; // class, innerHTML, innerText, or attribute
  21021. switch(type){
  21022. case "attribute":
  21023. if(lang.isFunction(value)){ // functions execute in the context of the widget
  21024. value = lang.hitch(this, value);
  21025. }
  21026. // Get the name of the DOM node attribute; usually it's the same
  21027. // as the name of the attribute in the widget (attr), but can be overridden.
  21028. // Also maps handler names to lowercase, like onSubmit --> onsubmit
  21029. var attrName = command.attribute ? command.attribute :
  21030. (/^on[A-Z][a-zA-Z]*$/.test(attr) ? attr.toLowerCase() : attr);
  21031. domAttr.set(mapNode, attrName, value);
  21032. break;
  21033. case "innerText":
  21034. mapNode.innerHTML = "";
  21035. mapNode.appendChild(win.doc.createTextNode(value));
  21036. break;
  21037. case "innerHTML":
  21038. mapNode.innerHTML = value;
  21039. break;
  21040. case "class":
  21041. domClass.replace(mapNode, value, this[attr]);
  21042. break;
  21043. }
  21044. }, this);
  21045. },
  21046. get: function(name){
  21047. // summary:
  21048. // Get a property from a widget.
  21049. // name:
  21050. // The property to get.
  21051. // description:
  21052. // Get a named property from a widget. The property may
  21053. // potentially be retrieved via a getter method. If no getter is defined, this
  21054. // just retrieves the object's property.
  21055. //
  21056. // For example, if the widget has properties `foo` and `bar`
  21057. // and a method named `_getFooAttr()`, calling:
  21058. // `myWidget.get("foo")` would be equivalent to calling
  21059. // `widget._getFooAttr()` and `myWidget.get("bar")`
  21060. // would be equivalent to the expression
  21061. // `widget.bar2`
  21062. var names = this._getAttrNames(name);
  21063. return this[names.g] ? this[names.g]() : this[name];
  21064. },
  21065. set: function(name, value){
  21066. // summary:
  21067. // Set a property on a widget
  21068. // name:
  21069. // The property to set.
  21070. // value:
  21071. // The value to set in the property.
  21072. // description:
  21073. // Sets named properties on a widget which may potentially be handled by a
  21074. // setter in the widget.
  21075. //
  21076. // For example, if the widget has properties `foo` and `bar`
  21077. // and a method named `_setFooAttr()`, calling
  21078. // `myWidget.set("foo", "Howdy!")` would be equivalent to calling
  21079. // `widget._setFooAttr("Howdy!")` and `myWidget.set("bar", 3)`
  21080. // would be equivalent to the statement `widget.bar = 3;`
  21081. //
  21082. // set() may also be called with a hash of name/value pairs, ex:
  21083. //
  21084. // | myWidget.set({
  21085. // | foo: "Howdy",
  21086. // | bar: 3
  21087. // | });
  21088. //
  21089. // This is equivalent to calling `set(foo, "Howdy")` and `set(bar, 3)`
  21090. if(typeof name === "object"){
  21091. for(var x in name){
  21092. this.set(x, name[x]);
  21093. }
  21094. return this;
  21095. }
  21096. var names = this._getAttrNames(name),
  21097. setter = this[names.s];
  21098. if(lang.isFunction(setter)){
  21099. // use the explicit setter
  21100. var result = setter.apply(this, Array.prototype.slice.call(arguments, 1));
  21101. }else{
  21102. // Mapping from widget attribute to DOMNode attribute/value/etc.
  21103. // Map according to:
  21104. // 1. attributeMap setting, if one exists (TODO: attributeMap deprecated, remove in 2.0)
  21105. // 2. _setFooAttr: {...} type attribute in the widget (if one exists)
  21106. // 3. apply to focusNode or domNode if standard attribute name, excluding funcs like onClick.
  21107. // Checks if an attribute is a "standard attribute" by whether the DOMNode JS object has a similar
  21108. // attribute name (ex: accept-charset attribute matches jsObject.acceptCharset).
  21109. // Note also that Tree.focusNode() is a function not a DOMNode, so test for that.
  21110. var defaultNode = this.focusNode && !lang.isFunction(this.focusNode) ? "focusNode" : "domNode",
  21111. tag = this[defaultNode].tagName,
  21112. attrsForTag = tagAttrs[tag] || (tagAttrs[tag] = getAttrs(this[defaultNode])),
  21113. map = name in this.attributeMap ? this.attributeMap[name] :
  21114. names.s in this ? this[names.s] :
  21115. ((names.l in attrsForTag && typeof value != "function") ||
  21116. /^aria-|^data-|^role$/.test(name)) ? defaultNode : null;
  21117. if(map != null){
  21118. this._attrToDom(name, value, map);
  21119. }
  21120. this._set(name, value);
  21121. }
  21122. return result || this;
  21123. },
  21124. _attrPairNames: {}, // shared between all widgets
  21125. _getAttrNames: function(name){
  21126. // summary:
  21127. // Helper function for get() and set().
  21128. // Caches attribute name values so we don't do the string ops every time.
  21129. // tags:
  21130. // private
  21131. var apn = this._attrPairNames;
  21132. if(apn[name]){ return apn[name]; }
  21133. var uc = name.replace(/^[a-z]|-[a-zA-Z]/g, function(c){ return c.charAt(c.length-1).toUpperCase(); });
  21134. return (apn[name] = {
  21135. n: name+"Node",
  21136. s: "_set"+uc+"Attr", // converts dashes to camel case, ex: accept-charset --> _setAcceptCharsetAttr
  21137. g: "_get"+uc+"Attr",
  21138. l: uc.toLowerCase() // lowercase name w/out dashes, ex: acceptcharset
  21139. });
  21140. },
  21141. _set: function(/*String*/ name, /*anything*/ value){
  21142. // summary:
  21143. // Helper function to set new value for specified attribute, and call handlers
  21144. // registered with watch() if the value has changed.
  21145. var oldValue = this[name];
  21146. this[name] = value;
  21147. if(this._watchCallbacks && this._created && value !== oldValue){
  21148. this._watchCallbacks(name, oldValue, value);
  21149. }
  21150. },
  21151. on: function(/*String*/ type, /*Function*/ func){
  21152. // summary:
  21153. // Call specified function when event occurs, ex: myWidget.on("click", function(){ ... }).
  21154. // description:
  21155. // Call specified function when event `type` occurs, ex: `myWidget.on("click", function(){ ... })`.
  21156. // Note that the function is not run in any particular scope, so if (for example) you want it to run in the
  21157. // widget's scope you must do `myWidget.on("click", lang.hitch(myWidget, func))`.
  21158. return aspect.after(this, this._onMap(type), func, true);
  21159. },
  21160. _onMap: function(/*String*/ type){
  21161. // summary:
  21162. // Maps on() type parameter (ex: "mousemove") to method name (ex: "onMouseMove")
  21163. var ctor = this.constructor, map = ctor._onMap;
  21164. if(!map){
  21165. map = (ctor._onMap = {});
  21166. for(var attr in ctor.prototype){
  21167. if(/^on/.test(attr)){
  21168. map[attr.replace(/^on/, "").toLowerCase()] = attr;
  21169. }
  21170. }
  21171. }
  21172. return map[type.toLowerCase()]; // String
  21173. },
  21174. toString: function(){
  21175. // summary:
  21176. // Returns a string that represents the widget
  21177. // description:
  21178. // When a widget is cast to a string, this method will be used to generate the
  21179. // output. Currently, it does not implement any sort of reversible
  21180. // serialization.
  21181. return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String
  21182. },
  21183. getChildren: function(){
  21184. // summary:
  21185. // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode.
  21186. // Does not return nested widgets, nor widgets that are part of this widget's template.
  21187. return this.containerNode ? registry.findWidgets(this.containerNode) : []; // dijit._Widget[]
  21188. },
  21189. getParent: function(){
  21190. // summary:
  21191. // Returns the parent widget of this widget
  21192. return registry.getEnclosingWidget(this.domNode.parentNode);
  21193. },
  21194. connect: function(
  21195. /*Object|null*/ obj,
  21196. /*String|Function*/ event,
  21197. /*String|Function*/ method){
  21198. // summary:
  21199. // Connects specified obj/event to specified method of this object
  21200. // and registers for disconnect() on widget destroy.
  21201. // description:
  21202. // Provide widget-specific analog to dojo.connect, except with the
  21203. // implicit use of this widget as the target object.
  21204. // Events connected with `this.connect` are disconnected upon
  21205. // destruction.
  21206. // returns:
  21207. // A handle that can be passed to `disconnect` in order to disconnect before
  21208. // the widget is destroyed.
  21209. // example:
  21210. // | var btn = new dijit.form.Button();
  21211. // | // when foo.bar() is called, call the listener we're going to
  21212. // | // provide in the scope of btn
  21213. // | btn.connect(foo, "bar", function(){
  21214. // | console.debug(this.toString());
  21215. // | });
  21216. // tags:
  21217. // protected
  21218. var handle = connect.connect(obj, event, this, method);
  21219. this._connects.push(handle);
  21220. return handle; // _Widget.Handle
  21221. },
  21222. disconnect: function(handle){
  21223. // summary:
  21224. // Disconnects handle created by `connect`.
  21225. // Also removes handle from this widget's list of connects.
  21226. // tags:
  21227. // protected
  21228. var i = array.indexOf(this._connects, handle);
  21229. if(i != -1){
  21230. handle.remove();
  21231. this._connects.splice(i, 1);
  21232. }
  21233. },
  21234. subscribe: function(t, method){
  21235. // summary:
  21236. // Subscribes to the specified topic and calls the specified method
  21237. // of this object and registers for unsubscribe() on widget destroy.
  21238. // description:
  21239. // Provide widget-specific analog to dojo.subscribe, except with the
  21240. // implicit use of this widget as the target object.
  21241. // t: String
  21242. // The topic
  21243. // method: Function
  21244. // The callback
  21245. // example:
  21246. // | var btn = new dijit.form.Button();
  21247. // | // when /my/topic is published, this button changes its label to
  21248. // | // be the parameter of the topic.
  21249. // | btn.subscribe("/my/topic", function(v){
  21250. // | this.set("label", v);
  21251. // | });
  21252. // tags:
  21253. // protected
  21254. var handle = topic.subscribe(t, lang.hitch(this, method));
  21255. this._connects.push(handle);
  21256. return handle; // _Widget.Handle
  21257. },
  21258. unsubscribe: function(/*Object*/ handle){
  21259. // summary:
  21260. // Unsubscribes handle created by this.subscribe.
  21261. // Also removes handle from this widget's list of subscriptions
  21262. // tags:
  21263. // protected
  21264. this.disconnect(handle);
  21265. },
  21266. isLeftToRight: function(){
  21267. // summary:
  21268. // Return this widget's explicit or implicit orientation (true for LTR, false for RTL)
  21269. // tags:
  21270. // protected
  21271. return this.dir ? (this.dir == "ltr") : domGeometry.isBodyLtr(); //Boolean
  21272. },
  21273. isFocusable: function(){
  21274. // summary:
  21275. // Return true if this widget can currently be focused
  21276. // and false if not
  21277. return this.focus && (domStyle.get(this.domNode, "display") != "none");
  21278. },
  21279. placeAt: function(/* String|DomNode|_Widget */reference, /* String?|Int? */position){
  21280. // summary:
  21281. // Place this widget's domNode reference somewhere in the DOM based
  21282. // on standard domConstruct.place conventions, or passing a Widget reference that
  21283. // contains and addChild member.
  21284. //
  21285. // description:
  21286. // A convenience function provided in all _Widgets, providing a simple
  21287. // shorthand mechanism to put an existing (or newly created) Widget
  21288. // somewhere in the dom, and allow chaining.
  21289. //
  21290. // reference:
  21291. // The String id of a domNode, a domNode reference, or a reference to a Widget possessing
  21292. // an addChild method.
  21293. //
  21294. // position:
  21295. // If passed a string or domNode reference, the position argument
  21296. // accepts a string just as domConstruct.place does, one of: "first", "last",
  21297. // "before", or "after".
  21298. //
  21299. // If passed a _Widget reference, and that widget reference has an ".addChild" method,
  21300. // it will be called passing this widget instance into that method, supplying the optional
  21301. // position index passed.
  21302. //
  21303. // returns:
  21304. // dijit._Widget
  21305. // Provides a useful return of the newly created dijit._Widget instance so you
  21306. // can "chain" this function by instantiating, placing, then saving the return value
  21307. // to a variable.
  21308. //
  21309. // example:
  21310. // | // create a Button with no srcNodeRef, and place it in the body:
  21311. // | var button = new dijit.form.Button({ label:"click" }).placeAt(win.body());
  21312. // | // now, 'button' is still the widget reference to the newly created button
  21313. // | button.on("click", function(e){ console.log('click'); }));
  21314. //
  21315. // example:
  21316. // | // create a button out of a node with id="src" and append it to id="wrapper":
  21317. // | var button = new dijit.form.Button({},"src").placeAt("wrapper");
  21318. //
  21319. // example:
  21320. // | // place a new button as the first element of some div
  21321. // | var button = new dijit.form.Button({ label:"click" }).placeAt("wrapper","first");
  21322. //
  21323. // example:
  21324. // | // create a contentpane and add it to a TabContainer
  21325. // | var tc = dijit.byId("myTabs");
  21326. // | new dijit.layout.ContentPane({ href:"foo.html", title:"Wow!" }).placeAt(tc)
  21327. if(reference.declaredClass && reference.addChild){
  21328. reference.addChild(this, position);
  21329. }else{
  21330. domConstruct.place(this.domNode, reference, position);
  21331. }
  21332. return this;
  21333. },
  21334. getTextDir: function(/*String*/ text,/*String*/ originalDir){
  21335. // summary:
  21336. // Return direction of the text.
  21337. // The function overridden in the _BidiSupport module,
  21338. // its main purpose is to calculate the direction of the
  21339. // text, if was defined by the programmer through textDir.
  21340. // tags:
  21341. // protected.
  21342. return originalDir;
  21343. },
  21344. applyTextDir: function(/*===== element, text =====*/){
  21345. // summary:
  21346. // The function overridden in the _BidiSupport module,
  21347. // originally used for setting element.dir according to this.textDir.
  21348. // In this case does nothing.
  21349. // element: DOMNode
  21350. // text: String
  21351. // tags:
  21352. // protected.
  21353. },
  21354. defer: function(fcn, delay){
  21355. // summary:
  21356. // Wrapper to setTimeout to avoid deferred functions executing
  21357. // after the originating widget has been destroyed.
  21358. // Returns an object handle with a remove method (that returns null) (replaces clearTimeout).
  21359. // fcn: function reference
  21360. // delay: Optional number (defaults to 0)
  21361. // tags:
  21362. // protected.
  21363. var timer = setTimeout(lang.hitch(this,
  21364. function(){
  21365. timer = null;
  21366. if(!this._destroyed){
  21367. lang.hitch(this, fcn)();
  21368. }
  21369. }),
  21370. delay || 0
  21371. );
  21372. return {
  21373. remove: function(){
  21374. if(timer){
  21375. clearTimeout(timer);
  21376. timer = null;
  21377. }
  21378. return null; // so this works well: handle = handle.remove();
  21379. }
  21380. };
  21381. }
  21382. });
  21383. });
  21384. },
  21385. 'dojo/store/Memory':function(){
  21386. define("dojo/store/Memory", ["../_base/declare", "./util/QueryResults", "./util/SimpleQueryEngine"], function(declare, QueryResults, SimpleQueryEngine) {
  21387. // module:
  21388. // dojo/store/Memory
  21389. // summary:
  21390. // The module defines an in-memory object store.
  21391. return declare("dojo.store.Memory", null, {
  21392. // summary:
  21393. // This is a basic in-memory object store. It implements dojo.store.api.Store.
  21394. constructor: function(/*dojo.store.Memory*/ options){
  21395. // summary:
  21396. // Creates a memory object store.
  21397. // options:
  21398. // This provides any configuration information that will be mixed into the store.
  21399. // This should generally include the data property to provide the starting set of data.
  21400. for(var i in options){
  21401. this[i] = options[i];
  21402. }
  21403. this.setData(this.data || []);
  21404. },
  21405. // data: Array
  21406. // The array of all the objects in the memory store
  21407. data:null,
  21408. // idProperty: String
  21409. // Indicates the property to use as the identity property. The values of this
  21410. // property should be unique.
  21411. idProperty: "id",
  21412. // index: Object
  21413. // An index of data indices into the data array by id
  21414. index:null,
  21415. // queryEngine: Function
  21416. // Defines the query engine to use for querying the data store
  21417. queryEngine: SimpleQueryEngine,
  21418. get: function(id){
  21419. // summary:
  21420. // Retrieves an object by its identity
  21421. // id: Number
  21422. // The identity to use to lookup the object
  21423. // returns: Object
  21424. // The object in the store that matches the given id.
  21425. return this.data[this.index[id]];
  21426. },
  21427. getIdentity: function(object){
  21428. // summary:
  21429. // Returns an object's identity
  21430. // object: Object
  21431. // The object to get the identity from
  21432. // returns: Number
  21433. return object[this.idProperty];
  21434. },
  21435. put: function(object, options){
  21436. // summary:
  21437. // Stores an object
  21438. // object: Object
  21439. // The object to store.
  21440. // options: dojo.store.api.Store.PutDirectives??
  21441. // Additional metadata for storing the data. Includes an "id"
  21442. // property if a specific id is to be used.
  21443. // returns: Number
  21444. var data = this.data,
  21445. index = this.index,
  21446. idProperty = this.idProperty;
  21447. var id = (options && "id" in options) ? options.id : idProperty in object ? object[idProperty] : Math.random();
  21448. if(id in index){
  21449. // object exists
  21450. if(options && options.overwrite === false){
  21451. throw new Error("Object already exists");
  21452. }
  21453. // replace the entry in data
  21454. data[index[id]] = object;
  21455. }else{
  21456. // add the new object
  21457. index[id] = data.push(object) - 1;
  21458. }
  21459. return id;
  21460. },
  21461. add: function(object, options){
  21462. // summary:
  21463. // Creates an object, throws an error if the object already exists
  21464. // object: Object
  21465. // The object to store.
  21466. // options: dojo.store.api.Store.PutDirectives??
  21467. // Additional metadata for storing the data. Includes an "id"
  21468. // property if a specific id is to be used.
  21469. // returns: Number
  21470. (options = options || {}).overwrite = false;
  21471. // call put with overwrite being false
  21472. return this.put(object, options);
  21473. },
  21474. remove: function(id){
  21475. // summary:
  21476. // Deletes an object by its identity
  21477. // id: Number
  21478. // The identity to use to delete the object
  21479. // returns: Boolean
  21480. // Returns true if an object was removed, falsy (undefined) if no object matched the id
  21481. var index = this.index;
  21482. var data = this.data;
  21483. if(id in index){
  21484. data.splice(index[id], 1);
  21485. // now we have to reindex
  21486. this.setData(data);
  21487. return true;
  21488. }
  21489. },
  21490. query: function(query, options){
  21491. // summary:
  21492. // Queries the store for objects.
  21493. // query: Object
  21494. // The query to use for retrieving objects from the store.
  21495. // options: dojo.store.api.Store.QueryOptions?
  21496. // The optional arguments to apply to the resultset.
  21497. // returns: dojo.store.api.Store.QueryResults
  21498. // The results of the query, extended with iterative methods.
  21499. //
  21500. // example:
  21501. // Given the following store:
  21502. //
  21503. // | var store = new dojo.store.Memory({
  21504. // | data: [
  21505. // | {id: 1, name: "one", prime: false },
  21506. // | {id: 2, name: "two", even: true, prime: true},
  21507. // | {id: 3, name: "three", prime: true},
  21508. // | {id: 4, name: "four", even: true, prime: false},
  21509. // | {id: 5, name: "five", prime: true}
  21510. // | ]
  21511. // | });
  21512. //
  21513. // ...find all items where "prime" is true:
  21514. //
  21515. // | var results = store.query({ prime: true });
  21516. //
  21517. // ...or find all items where "even" is true:
  21518. //
  21519. // | var results = store.query({ even: true });
  21520. return QueryResults(this.queryEngine(query, options)(this.data));
  21521. },
  21522. setData: function(data){
  21523. // summary:
  21524. // Sets the given data as the source for this store, and indexes it
  21525. // data: Object[]
  21526. // An array of objects to use as the source of data.
  21527. if(data.items){
  21528. // just for convenience with the data format IFRS expects
  21529. this.idProperty = data.identifier;
  21530. data = this.data = data.items;
  21531. }else{
  21532. this.data = data;
  21533. }
  21534. this.index = {};
  21535. for(var i = 0, l = data.length; i < l; i++){
  21536. this.index[data[i][this.idProperty]] = i;
  21537. }
  21538. }
  21539. });
  21540. });
  21541. },
  21542. 'url:dijit/templates/Tooltip.html':"<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\"\r\n\t><div class=\"dijitTooltipContainer dijitTooltipContents\" data-dojo-attach-point=\"containerNode\" role='alert'></div\r\n\t><div class=\"dijitTooltipConnector\" data-dojo-attach-point=\"connectorNode\"></div\r\n></div>\r\n",
  21543. 'dojox/grid/_Grid':function(){
  21544. require({cache:{
  21545. 'url:dojox/grid/resources/_Grid.html':"<div hidefocus=\"hidefocus\" role=\"grid\" dojoAttachEvent=\"onmouseout:_mouseOut\">\r\n\t<div class=\"dojoxGridMasterHeader\" dojoAttachPoint=\"viewsHeaderNode\" role=\"presentation\"></div>\r\n\t<div class=\"dojoxGridMasterView\" dojoAttachPoint=\"viewsNode\" role=\"presentation\"></div>\r\n\t<div class=\"dojoxGridMasterMessages\" style=\"display: none;\" dojoAttachPoint=\"messagesNode\"></div>\r\n\t<span dojoAttachPoint=\"lastFocusNode\" tabindex=\"0\"></span>\r\n</div>\r\n"}});
  21546. define("dojox/grid/_Grid", [
  21547. "dojo/_base/kernel",
  21548. "../main",
  21549. "dojo/_base/declare",
  21550. "./_Events",
  21551. "./_Scroller",
  21552. "./_Layout",
  21553. "./_View",
  21554. "./_ViewManager",
  21555. "./_RowManager",
  21556. "./_FocusManager",
  21557. "./_EditManager",
  21558. "./Selection",
  21559. "./_RowSelector",
  21560. "./util",
  21561. "dijit/_Widget",
  21562. "dijit/_TemplatedMixin",
  21563. "dijit/CheckedMenuItem",
  21564. "dojo/text!./resources/_Grid.html",
  21565. "dojo/string",
  21566. "dojo/_base/array",
  21567. "dojo/_base/lang",
  21568. "dojo/_base/sniff",
  21569. "dojox/html/metrics",
  21570. "dojo/_base/html",
  21571. "dojo/query",
  21572. "dojo/dnd/common",
  21573. "dojo/i18n!dijit/nls/loading"
  21574. ], function(dojo, dojox, declare, _Events, _Scroller, _Layout, _View, _ViewManager,
  21575. _RowManager, _FocusManager, _EditManager, Selection, _RowSelector, util, _Widget,
  21576. _TemplatedMixin, CheckedMenuItem, template, string, array, lang, has, metrics, html, query){
  21577. // NOTE: this is for backwards compatibility with Dojo 1.3
  21578. if(!dojo.isCopyKey){
  21579. dojo.isCopyKey = dojo.dnd.getCopyKeyState;
  21580. }
  21581. /*=====
  21582. dojox.grid.__CellDef = function(){
  21583. // name: String?
  21584. // The text to use in the header of the grid for this cell.
  21585. // get: Function?
  21586. // function(rowIndex){} rowIndex is of type Integer. This
  21587. // function will be called when a cell requests data. Returns the
  21588. // unformatted data for the cell.
  21589. // value: String?
  21590. // If "get" is not specified, this is used as the data for the cell.
  21591. // defaultValue: String?
  21592. // If "get" and "value" aren't specified or if "get" returns an undefined
  21593. // value, this is used as the data for the cell. "formatter" is not run
  21594. // on this if "get" returns an undefined value.
  21595. // formatter: Function?
  21596. // function(data, rowIndex){} data is of type anything, rowIndex
  21597. // is of type Integer. This function will be called after the cell
  21598. // has its data but before it passes it back to the grid to render.
  21599. // Returns the formatted version of the cell's data.
  21600. // type: dojox.grid.cells._Base|Function?
  21601. // TODO
  21602. // editable: Boolean?
  21603. // Whether this cell should be editable or not.
  21604. // hidden: Boolean?
  21605. // If true, the cell will not be displayed.
  21606. // noresize: Boolean?
  21607. // If true, the cell will not be able to be resized.
  21608. // width: Integer|String?
  21609. // A CSS size. If it's an Integer, the width will be in em's.
  21610. // colSpan: Integer?
  21611. // How many columns to span this cell. Will not work in the first
  21612. // sub-row of cells.
  21613. // rowSpan: Integer?
  21614. // How many sub-rows to span this cell.
  21615. // styles: String?
  21616. // A string of styles to apply to both the header cell and main
  21617. // grid cells. Must end in a ';'.
  21618. // headerStyles: String?
  21619. // A string of styles to apply to just the header cell. Must end
  21620. // in a ';'
  21621. // cellStyles: String?
  21622. // A string of styles to apply to just the main grid cells. Must
  21623. // end in a ';'
  21624. // classes: String?
  21625. // A space separated list of classes to apply to both the header
  21626. // cell and the main grid cells.
  21627. // headerClasses: String?
  21628. // A space separated list of classes to apply to just the header
  21629. // cell.
  21630. // cellClasses: String?
  21631. // A space separated list of classes to apply to just the main
  21632. // grid cells.
  21633. // attrs: String?
  21634. // A space separated string of attribute='value' pairs to add to
  21635. // the header cell element and main grid cell elements.
  21636. this.name = name;
  21637. this.value = value;
  21638. this.get = get;
  21639. this.formatter = formatter;
  21640. this.type = type;
  21641. this.editable = editable;
  21642. this.hidden = hidden;
  21643. this.width = width;
  21644. this.colSpan = colSpan;
  21645. this.rowSpan = rowSpan;
  21646. this.styles = styles;
  21647. this.headerStyles = headerStyles;
  21648. this.cellStyles = cellStyles;
  21649. this.classes = classes;
  21650. this.headerClasses = headerClasses;
  21651. this.cellClasses = cellClasses;
  21652. this.attrs = attrs;
  21653. }
  21654. =====*/
  21655. /*=====
  21656. dojox.grid.__ViewDef = function(){
  21657. // noscroll: Boolean?
  21658. // If true, no scrollbars will be rendered without scrollbars.
  21659. // width: Integer|String?
  21660. // A CSS size. If it's an Integer, the width will be in em's. If
  21661. // "noscroll" is true, this value is ignored.
  21662. // cells: dojox.grid.__CellDef[]|Array[dojox.grid.__CellDef[]]?
  21663. // The structure of the cells within this grid.
  21664. // type: String?
  21665. // A string containing the constructor of a subclass of
  21666. // dojox.grid._View. If this is not specified, dojox.grid._View
  21667. // is used.
  21668. // defaultCell: dojox.grid.__CellDef?
  21669. // A cell definition with default values for all cells in this view. If
  21670. // a property is defined in a cell definition in the "cells" array and
  21671. // this property, the cell definition's property will override this
  21672. // property's property.
  21673. // onBeforeRow: Function?
  21674. // function(rowIndex, cells){} rowIndex is of type Integer, cells
  21675. // is of type Array[dojox.grid.__CellDef[]]. This function is called
  21676. // before each row of data is rendered. Before the header is
  21677. // rendered, rowIndex will be -1. "cells" is a reference to the
  21678. // internal structure of this view's cells so any changes you make to
  21679. // it will persist between calls.
  21680. // onAfterRow: Function?
  21681. // function(rowIndex, cells, rowNode){} rowIndex is of type Integer, cells
  21682. // is of type Array[dojox.grid.__CellDef[]], rowNode is of type DOMNode.
  21683. // This function is called after each row of data is rendered. After the
  21684. // header is rendered, rowIndex will be -1. "cells" is a reference to the
  21685. // internal structure of this view's cells so any changes you make to
  21686. // it will persist between calls.
  21687. this.noscroll = noscroll;
  21688. this.width = width;
  21689. this.cells = cells;
  21690. this.type = type;
  21691. this.defaultCell = defaultCell;
  21692. this.onBeforeRow = onBeforeRow;
  21693. this.onAfterRow = onAfterRow;
  21694. }
  21695. =====*/
  21696. var _Grid = declare('dojox.grid._Grid',
  21697. [ _Widget, _TemplatedMixin, _Events ],
  21698. {
  21699. // summary:
  21700. // A grid widget with virtual scrolling, cell editing, complex rows,
  21701. // sorting, fixed columns, sizeable columns, etc.
  21702. //
  21703. // description:
  21704. // _Grid provides the full set of grid features without any
  21705. // direct connection to a data store.
  21706. //
  21707. // The grid exposes a get function for the grid, or optionally
  21708. // individual columns, to populate cell contents.
  21709. //
  21710. // The grid is rendered based on its structure, an object describing
  21711. // column and cell layout.
  21712. //
  21713. // example:
  21714. // A quick sample:
  21715. //
  21716. // define a get function
  21717. // | function get(inRowIndex){ // called in cell context
  21718. // | return [this.index, inRowIndex].join(', ');
  21719. // | }
  21720. //
  21721. // define the grid structure:
  21722. // | var structure = [ // array of view objects
  21723. // | { cells: [// array of rows, a row is an array of cells
  21724. // | [
  21725. // | { name: "Alpha", width: 6 },
  21726. // | { name: "Beta" },
  21727. // | { name: "Gamma", get: get }]
  21728. // | ]}
  21729. // | ];
  21730. //
  21731. // | <div id="grid"
  21732. // | rowCount="100" get="get"
  21733. // | structure="structure"
  21734. // | dojoType="dojox.grid._Grid"></div>
  21735. templateString: template,
  21736. // classTag: String
  21737. // CSS class applied to the grid's domNode
  21738. classTag: 'dojoxGrid',
  21739. // settings
  21740. // rowCount: Integer
  21741. // Number of rows to display.
  21742. rowCount: 5,
  21743. // keepRows: Integer
  21744. // Number of rows to keep in the rendering cache.
  21745. keepRows: 75,
  21746. // rowsPerPage: Integer
  21747. // Number of rows to render at a time.
  21748. rowsPerPage: 25,
  21749. // autoWidth: Boolean
  21750. // If autoWidth is true, grid width is automatically set to fit the data.
  21751. autoWidth: false,
  21752. // initialWidth: String
  21753. // A css string to use to set our initial width (only used if autoWidth
  21754. // is true). The first rendering of the grid will be this width, any
  21755. // resizing of columns, etc will result in the grid switching to
  21756. // autoWidth mode. Note, this width will override any styling in a
  21757. // stylesheet or directly on the node.
  21758. initialWidth: "",
  21759. // autoHeight: Boolean|Integer
  21760. // If autoHeight is true, grid height is automatically set to fit the data.
  21761. // If it is an integer, the height will be automatically set to fit the data
  21762. // if there are fewer than that many rows - and the height will be set to show
  21763. // that many rows if there are more
  21764. autoHeight: '',
  21765. // rowHeight: Integer
  21766. // If rowHeight is set to a positive number, it will define the height of the rows
  21767. // in pixels. This can provide a significant performance advantage, since it
  21768. // eliminates the need to measure row sizes during rendering, which is one
  21769. // the primary bottlenecks in the DataGrid's performance.
  21770. rowHeight: 0,
  21771. // autoRender: Boolean
  21772. // If autoRender is true, grid will render itself after initialization.
  21773. autoRender: true,
  21774. // defaultHeight: String
  21775. // default height of the grid, measured in any valid css unit.
  21776. defaultHeight: '15em',
  21777. // height: String
  21778. // explicit height of the grid, measured in any valid css unit. This will be populated (and overridden)
  21779. // if the height: css attribute exists on the source node.
  21780. height: '',
  21781. // structure: dojox.grid.__ViewDef|dojox.grid.__ViewDef[]|dojox.grid.__CellDef[]|Array[dojox.grid.__CellDef[]]
  21782. // View layout defintion.
  21783. structure: null,
  21784. // elasticView: Integer
  21785. // Override defaults and make the indexed grid view elastic, thus filling available horizontal space.
  21786. elasticView: -1,
  21787. // singleClickEdit: boolean
  21788. // Single-click starts editing. Default is double-click
  21789. singleClickEdit: false,
  21790. // selectionMode: String
  21791. // Set the selection mode of grid's Selection. Value must be 'single', 'multiple',
  21792. // or 'extended'. Default is 'extended'.
  21793. selectionMode: 'extended',
  21794. // rowSelector: Boolean|String
  21795. // If set to true, will add a row selector view to this grid. If set to a CSS width, will add
  21796. // a row selector of that width to this grid.
  21797. rowSelector: '',
  21798. // columnReordering: Boolean
  21799. // If set to true, will add drag and drop reordering to views with one row of columns.
  21800. columnReordering: false,
  21801. // headerMenu: dijit.Menu
  21802. // If set to a dijit.Menu, will use this as a context menu for the grid headers.
  21803. headerMenu: null,
  21804. // placeholderLabel: String
  21805. // Label of placeholders to search for in the header menu to replace with column toggling
  21806. // menu items.
  21807. placeholderLabel: "GridColumns",
  21808. // selectable: Boolean
  21809. // Set to true if you want to be able to select the text within the grid.
  21810. selectable: false,
  21811. // Used to store the last two clicks, to ensure double-clicking occurs based on the intended row
  21812. _click: null,
  21813. // loadingMessage: String
  21814. // Message that shows while the grid is loading
  21815. loadingMessage: "<span class='dojoxGridLoading'>${loadingState}</span>",
  21816. // errorMessage: String
  21817. // Message that shows when the grid encounters an error loading
  21818. errorMessage: "<span class='dojoxGridError'>${errorState}</span>",
  21819. // noDataMessage: String
  21820. // Message that shows if the grid has no data - wrap it in a
  21821. // span with class 'dojoxGridNoData' if you want it to be
  21822. // styled similar to the loading and error messages
  21823. noDataMessage: "",
  21824. // escapeHTMLInData: Boolean
  21825. // This will escape HTML brackets from the data to prevent HTML from
  21826. // user-inputted data being rendered with may contain JavaScript and result in
  21827. // XSS attacks. This is true by default, and it is recommended that it remain
  21828. // true. Setting this to false will allow data to be displayed in the grid without
  21829. // filtering, and should be only used if it is known that the data won't contain
  21830. // malicious scripts. If HTML is needed in grid cells, it is recommended that
  21831. // you use the formatter function to generate the HTML (the output of
  21832. // formatter functions is not filtered, even with escapeHTMLInData set to true).
  21833. escapeHTMLInData: true,
  21834. // formatterScope: Object
  21835. // An object to execute format functions within. If not set, the
  21836. // format functions will execute within the scope of the cell that
  21837. // has a format function.
  21838. formatterScope: null,
  21839. // editable: boolean
  21840. // indicates if the grid contains editable cells, default is false
  21841. // set to true if editable cell encountered during rendering
  21842. editable: false,
  21843. // private
  21844. sortInfo: 0,
  21845. themeable: true,
  21846. _placeholders: null,
  21847. // _layoutClass: Object
  21848. // The class to use for our layout - can be overridden by grid subclasses
  21849. _layoutClass: _Layout,
  21850. // initialization
  21851. buildRendering: function(){
  21852. this.inherited(arguments);
  21853. if(!this.domNode.getAttribute('tabIndex')){
  21854. this.domNode.tabIndex = "0";
  21855. }
  21856. this.createScroller();
  21857. this.createLayout();
  21858. this.createViews();
  21859. this.createManagers();
  21860. this.createSelection();
  21861. this.connect(this.selection, "onSelected", "onSelected");
  21862. this.connect(this.selection, "onDeselected", "onDeselected");
  21863. this.connect(this.selection, "onChanged", "onSelectionChanged");
  21864. metrics.initOnFontResize();
  21865. this.connect(metrics, "onFontResize", "textSizeChanged");
  21866. util.funnelEvents(this.domNode, this, 'doKeyEvent', util.keyEvents);
  21867. if (this.selectionMode != "none") {
  21868. this.domNode.setAttribute("aria-multiselectable", this.selectionMode == "single" ? "false" : "true");
  21869. }
  21870. html.addClass(this.domNode, this.classTag);
  21871. if(!this.isLeftToRight()){
  21872. html.addClass(this.domNode, this.classTag+"Rtl");
  21873. }
  21874. },
  21875. postMixInProperties: function(){
  21876. this.inherited(arguments);
  21877. var messages = dojo.i18n.getLocalization("dijit", "loading", this.lang);
  21878. this.loadingMessage = string.substitute(this.loadingMessage, messages);
  21879. this.errorMessage = string.substitute(this.errorMessage, messages);
  21880. if(this.srcNodeRef && this.srcNodeRef.style.height){
  21881. this.height = this.srcNodeRef.style.height;
  21882. }
  21883. // Call this to update our autoheight to start out
  21884. this._setAutoHeightAttr(this.autoHeight, true);
  21885. this.lastScrollTop = this.scrollTop = 0;
  21886. },
  21887. postCreate: function(){
  21888. this._placeholders = [];
  21889. this._setHeaderMenuAttr(this.headerMenu);
  21890. this._setStructureAttr(this.structure);
  21891. this._click = [];
  21892. this.inherited(arguments);
  21893. if(this.domNode && this.autoWidth && this.initialWidth){
  21894. this.domNode.style.width = this.initialWidth;
  21895. }
  21896. if (this.domNode && !this.editable){
  21897. // default value for aria-readonly is false, set to true if grid is not editable
  21898. html.attr(this.domNode,"aria-readonly", "true");
  21899. }
  21900. },
  21901. destroy: function(){
  21902. this.domNode.onReveal = null;
  21903. this.domNode.onSizeChange = null;
  21904. // Fixes IE domNode leak
  21905. delete this._click;
  21906. if(this.scroller){
  21907. this.scroller.destroy();
  21908. delete this.scroller;
  21909. }
  21910. this.edit.destroy();
  21911. delete this.edit;
  21912. this.views.destroyViews();
  21913. if(this.focus){
  21914. this.focus.destroy();
  21915. delete this.focus;
  21916. }
  21917. if(this.headerMenu&&this._placeholders.length){
  21918. array.forEach(this._placeholders, function(p){ p.unReplace(true); });
  21919. this.headerMenu.unBindDomNode(this.viewsHeaderNode);
  21920. }
  21921. this.inherited(arguments);
  21922. },
  21923. _setAutoHeightAttr: function(ah, skipRender){
  21924. // Calculate our autoheight - turn it into a boolean or an integer
  21925. if(typeof ah == "string"){
  21926. if(!ah || ah == "false"){
  21927. ah = false;
  21928. }else if (ah == "true"){
  21929. ah = true;
  21930. }else{
  21931. ah = window.parseInt(ah, 10);
  21932. }
  21933. }
  21934. if(typeof ah == "number"){
  21935. if(isNaN(ah)){
  21936. ah = false;
  21937. }
  21938. // Autoheight must be at least 1, if it's a number. If it's
  21939. // less than 0, we'll take that to mean "all" rows (same as
  21940. // autoHeight=true - if it is equal to zero, we'll take that
  21941. // to mean autoHeight=false
  21942. if(ah < 0){
  21943. ah = true;
  21944. }else if (ah === 0){
  21945. ah = false;
  21946. }
  21947. }
  21948. this.autoHeight = ah;
  21949. if(typeof ah == "boolean"){
  21950. this._autoHeight = ah;
  21951. }else if(typeof ah == "number"){
  21952. this._autoHeight = (ah >= this.get('rowCount'));
  21953. }else{
  21954. this._autoHeight = false;
  21955. }
  21956. if(this._started && !skipRender){
  21957. this.render();
  21958. }
  21959. },
  21960. _getRowCountAttr: function(){
  21961. return this.updating && this.invalidated && this.invalidated.rowCount != undefined ?
  21962. this.invalidated.rowCount : this.rowCount;
  21963. },
  21964. textSizeChanged: function(){
  21965. this.render();
  21966. },
  21967. sizeChange: function(){
  21968. this.update();
  21969. },
  21970. createManagers: function(){
  21971. // summary:
  21972. // create grid managers for various tasks including rows, focus, selection, editing
  21973. // row manager
  21974. this.rows = new _RowManager(this);
  21975. // focus manager
  21976. this.focus = new _FocusManager(this);
  21977. // edit manager
  21978. this.edit = new _EditManager(this);
  21979. },
  21980. createSelection: function(){
  21981. // summary: Creates a new Grid selection manager.
  21982. // selection manager
  21983. this.selection = new Selection(this);
  21984. },
  21985. createScroller: function(){
  21986. // summary: Creates a new virtual scroller
  21987. this.scroller = new _Scroller();
  21988. this.scroller.grid = this;
  21989. this.scroller.renderRow = lang.hitch(this, "renderRow");
  21990. this.scroller.removeRow = lang.hitch(this, "rowRemoved");
  21991. },
  21992. createLayout: function(){
  21993. // summary: Creates a new Grid layout
  21994. this.layout = new this._layoutClass(this);
  21995. this.connect(this.layout, "moveColumn", "onMoveColumn");
  21996. },
  21997. onMoveColumn: function(){
  21998. this.update();
  21999. },
  22000. onResizeColumn: function(/*int*/ cellIdx){
  22001. // Called when a column is resized.
  22002. },
  22003. // views
  22004. createViews: function(){
  22005. this.views = new _ViewManager(this);
  22006. this.views.createView = lang.hitch(this, "createView");
  22007. },
  22008. createView: function(inClass, idx){
  22009. var c = lang.getObject(inClass);
  22010. var view = new c({ grid: this, index: idx });
  22011. this.viewsNode.appendChild(view.domNode);
  22012. this.viewsHeaderNode.appendChild(view.headerNode);
  22013. this.views.addView(view);
  22014. html.attr(this.domNode, "align", this.isLeftToRight() ? 'left' : 'right');
  22015. return view;
  22016. },
  22017. buildViews: function(){
  22018. for(var i=0, vs; (vs=this.layout.structure[i]); i++){
  22019. this.createView(vs.type || dojox._scopeName + ".grid._View", i).setStructure(vs);
  22020. }
  22021. this.scroller.setContentNodes(this.views.getContentNodes());
  22022. },
  22023. _setStructureAttr: function(structure){
  22024. var s = structure;
  22025. if(s && lang.isString(s)){
  22026. dojo.deprecated("dojox.grid._Grid.set('structure', 'objVar')", "use dojox.grid._Grid.set('structure', objVar) instead", "2.0");
  22027. s=lang.getObject(s);
  22028. }
  22029. this.structure = s;
  22030. if(!s){
  22031. if(this.layout.structure){
  22032. s = this.layout.structure;
  22033. }else{
  22034. return;
  22035. }
  22036. }
  22037. this.views.destroyViews();
  22038. this.focus.focusView = null;
  22039. if(s !== this.layout.structure){
  22040. this.layout.setStructure(s);
  22041. }
  22042. this._structureChanged();
  22043. },
  22044. setStructure: function(/* dojox.grid.__ViewDef|dojox.grid.__ViewDef[]|dojox.grid.__CellDef[]|Array[dojox.grid.__CellDef[]] */ inStructure){
  22045. // summary:
  22046. // Install a new structure and rebuild the grid.
  22047. dojo.deprecated("dojox.grid._Grid.setStructure(obj)", "use dojox.grid._Grid.set('structure', obj) instead.", "2.0");
  22048. this._setStructureAttr(inStructure);
  22049. },
  22050. getColumnTogglingItems: function(){
  22051. // Summary: returns an array of dijit.CheckedMenuItem widgets that can be
  22052. // added to a menu for toggling columns on and off.
  22053. var items, checkedItems = [];
  22054. items = array.map(this.layout.cells, function(cell){
  22055. if(!cell.menuItems){ cell.menuItems = []; }
  22056. var self = this;
  22057. var item = new CheckedMenuItem({
  22058. label: cell.name,
  22059. checked: !cell.hidden,
  22060. _gridCell: cell,
  22061. onChange: function(checked){
  22062. if(self.layout.setColumnVisibility(this._gridCell.index, checked)){
  22063. var items = this._gridCell.menuItems;
  22064. if(items.length > 1){
  22065. array.forEach(items, function(item){
  22066. if(item !== this){
  22067. item.setAttribute("checked", checked);
  22068. }
  22069. }, this);
  22070. }
  22071. checked = array.filter(self.layout.cells, function(c){
  22072. if(c.menuItems.length > 1){
  22073. array.forEach(c.menuItems, "item.set('disabled', false);");
  22074. }else{
  22075. c.menuItems[0].set('disabled', false);
  22076. }
  22077. return !c.hidden;
  22078. });
  22079. if(checked.length == 1){
  22080. array.forEach(checked[0].menuItems, "item.set('disabled', true);");
  22081. }
  22082. }
  22083. },
  22084. destroy: function(){
  22085. var index = array.indexOf(this._gridCell.menuItems, this);
  22086. this._gridCell.menuItems.splice(index, 1);
  22087. delete this._gridCell;
  22088. CheckedMenuItem.prototype.destroy.apply(this, arguments);
  22089. }
  22090. });
  22091. cell.menuItems.push(item);
  22092. if(!cell.hidden) {
  22093. checkedItems.push(item);
  22094. }
  22095. return item;
  22096. }, this); // dijit.CheckedMenuItem[]
  22097. if(checkedItems.length == 1) {
  22098. checkedItems[0].set('disabled', true);
  22099. }
  22100. return items;
  22101. },
  22102. _setHeaderMenuAttr: function(menu){
  22103. if(this._placeholders && this._placeholders.length){
  22104. array.forEach(this._placeholders, function(p){
  22105. p.unReplace(true);
  22106. });
  22107. this._placeholders = [];
  22108. }
  22109. if(this.headerMenu){
  22110. this.headerMenu.unBindDomNode(this.viewsHeaderNode);
  22111. }
  22112. this.headerMenu = menu;
  22113. if(!menu){ return; }
  22114. this.headerMenu.bindDomNode(this.viewsHeaderNode);
  22115. if(this.headerMenu.getPlaceholders){
  22116. this._placeholders = this.headerMenu.getPlaceholders(this.placeholderLabel);
  22117. }
  22118. },
  22119. setHeaderMenu: function(/* dijit.Menu */ menu){
  22120. dojo.deprecated("dojox.grid._Grid.setHeaderMenu(obj)", "use dojox.grid._Grid.set('headerMenu', obj) instead.", "2.0");
  22121. this._setHeaderMenuAttr(menu);
  22122. },
  22123. setupHeaderMenu: function(){
  22124. if(this._placeholders && this._placeholders.length){
  22125. array.forEach(this._placeholders, function(p){
  22126. if(p._replaced){
  22127. p.unReplace(true);
  22128. }
  22129. p.replace(this.getColumnTogglingItems());
  22130. }, this);
  22131. }
  22132. },
  22133. _fetch: function(start){
  22134. this.setScrollTop(0);
  22135. },
  22136. getItem: function(inRowIndex){
  22137. return null;
  22138. },
  22139. showMessage: function(message){
  22140. if(message){
  22141. this.messagesNode.innerHTML = message;
  22142. this.messagesNode.style.display = "";
  22143. }else{
  22144. this.messagesNode.innerHTML = "";
  22145. this.messagesNode.style.display = "none";
  22146. }
  22147. },
  22148. _structureChanged: function() {
  22149. this.buildViews();
  22150. if(this.autoRender && this._started){
  22151. this.render();
  22152. }
  22153. },
  22154. hasLayout: function() {
  22155. return this.layout.cells.length;
  22156. },
  22157. // sizing
  22158. resize: function(changeSize, resultSize){
  22159. // summary:
  22160. // Update the grid's rendering dimensions and resize it
  22161. // Calling sizeChange calls update() which calls _resize...so let's
  22162. // save our input values, if any, and use them there when it gets
  22163. // called. This saves us an extra call to _resize(), which can
  22164. // get kind of heavy.
  22165. // fixes #11101, should ignore resize when in autoheight mode(IE) to avoid a deadlock
  22166. // e.g when an autoheight editable grid put in dijit.form.Form or other similar containers,
  22167. // grid switch to editing mode --> grid height change --> From height change
  22168. // ---> Form call grid.resize() ---> grid height change --> deaklock
  22169. if(dojo.isIE && !changeSize && !resultSize && this._autoHeight){
  22170. return;
  22171. }
  22172. this._pendingChangeSize = changeSize;
  22173. this._pendingResultSize = resultSize;
  22174. this.sizeChange();
  22175. },
  22176. _getPadBorder: function() {
  22177. this._padBorder = this._padBorder || html._getPadBorderExtents(this.domNode);
  22178. return this._padBorder;
  22179. },
  22180. _getHeaderHeight: function(){
  22181. var vns = this.viewsHeaderNode.style, t = vns.display == "none" ? 0 : this.views.measureHeader();
  22182. vns.height = t + 'px';
  22183. // header heights are reset during measuring so must be normalized after measuring.
  22184. this.views.normalizeHeaderNodeHeight();
  22185. return t;
  22186. },
  22187. _resize: function(changeSize, resultSize){
  22188. // Restore our pending values, if any
  22189. changeSize = changeSize || this._pendingChangeSize;
  22190. resultSize = resultSize || this._pendingResultSize;
  22191. delete this._pendingChangeSize;
  22192. delete this._pendingResultSize;
  22193. // if we have set up everything except the DOM, we cannot resize
  22194. if(!this.domNode){ return; }
  22195. var pn = this.domNode.parentNode;
  22196. if(!pn || pn.nodeType != 1 || !this.hasLayout() || pn.style.visibility == "hidden" || pn.style.display == "none"){
  22197. return;
  22198. }
  22199. // useful measurement
  22200. var padBorder = this._getPadBorder();
  22201. var hh = undefined;
  22202. var h;
  22203. // grid height
  22204. if(this._autoHeight){
  22205. this.domNode.style.height = 'auto';
  22206. }else if(typeof this.autoHeight == "number"){
  22207. h = hh = this._getHeaderHeight();
  22208. h += (this.scroller.averageRowHeight * this.autoHeight);
  22209. this.domNode.style.height = h + "px";
  22210. }else if(this.domNode.clientHeight <= padBorder.h){
  22211. if(pn == document.body){
  22212. this.domNode.style.height = this.defaultHeight;
  22213. }else if(this.height){
  22214. this.domNode.style.height = this.height;
  22215. }else{
  22216. this.fitTo = "parent";
  22217. }
  22218. }
  22219. // if we are given dimensions, size the grid's domNode to those dimensions
  22220. if(resultSize){
  22221. changeSize = resultSize;
  22222. }
  22223. if(!this._autoHeight && changeSize){
  22224. html.marginBox(this.domNode, changeSize);
  22225. this.height = this.domNode.style.height;
  22226. delete this.fitTo;
  22227. }else if(this.fitTo == "parent"){
  22228. h = this._parentContentBoxHeight = this._parentContentBoxHeight || html._getContentBox(pn).h;
  22229. this.domNode.style.height = Math.max(0, h) + "px";
  22230. }
  22231. var hasFlex = array.some(this.views.views, function(v){ return v.flexCells; });
  22232. if(!this._autoHeight && (h || html._getContentBox(this.domNode).h) === 0){
  22233. // We need to hide the header, since the Grid is essentially hidden.
  22234. this.viewsHeaderNode.style.display = "none";
  22235. }else{
  22236. // Otherwise, show the header and give it an appropriate height.
  22237. this.viewsHeaderNode.style.display = "block";
  22238. if(!hasFlex && hh === undefined){
  22239. hh = this._getHeaderHeight();
  22240. }
  22241. }
  22242. if(hasFlex){
  22243. hh = undefined;
  22244. }
  22245. // NOTE: it is essential that width be applied before height
  22246. // Header height can only be calculated properly after view widths have been set.
  22247. // This is because flex column width is naturally 0 in Firefox.
  22248. // Therefore prior to width sizing flex columns with spaces are maximally wrapped
  22249. // and calculated to be too tall.
  22250. this.adaptWidth();
  22251. this.adaptHeight(hh);
  22252. this.postresize();
  22253. },
  22254. adaptWidth: function() {
  22255. // private: sets width and position for views and update grid width if necessary
  22256. var doAutoWidth = (!this.initialWidth && this.autoWidth);
  22257. var w = doAutoWidth ? 0 : this.domNode.clientWidth || (this.domNode.offsetWidth - this._getPadBorder().w),
  22258. vw = this.views.arrange(1, w);
  22259. this.views.onEach("adaptWidth");
  22260. if(doAutoWidth){
  22261. this.domNode.style.width = vw + "px";
  22262. }
  22263. },
  22264. adaptHeight: function(inHeaderHeight){
  22265. // private: measures and normalizes header height, then sets view heights, and then updates scroller
  22266. // content extent
  22267. var t = inHeaderHeight === undefined ? this._getHeaderHeight() : inHeaderHeight;
  22268. var h = (this._autoHeight ? -1 : Math.max(this.domNode.clientHeight - t, 0) || 0);
  22269. this.views.onEach('setSize', [0, h]);
  22270. this.views.onEach('adaptHeight');
  22271. if(!this._autoHeight){
  22272. var numScroll = 0, numNoScroll = 0;
  22273. var noScrolls = array.filter(this.views.views, function(v){
  22274. var has = v.hasHScrollbar();
  22275. if(has){ numScroll++; }else{ numNoScroll++; }
  22276. return (!has);
  22277. });
  22278. if(numScroll > 0 && numNoScroll > 0){
  22279. array.forEach(noScrolls, function(v){
  22280. v.adaptHeight(true);
  22281. });
  22282. }
  22283. }
  22284. if(this.autoHeight === true || h != -1 || (typeof this.autoHeight == "number" && this.autoHeight >= this.get('rowCount'))){
  22285. this.scroller.windowHeight = h;
  22286. }else{
  22287. this.scroller.windowHeight = Math.max(this.domNode.clientHeight - t, 0);
  22288. }
  22289. },
  22290. // startup
  22291. startup: function(){
  22292. if(this._started){return;}
  22293. this.inherited(arguments);
  22294. if(this.autoRender){
  22295. this.render();
  22296. }
  22297. },
  22298. // render
  22299. render: function(){
  22300. // summary:
  22301. // Render the grid, headers, and views. Edit and scrolling states are reset. To retain edit and
  22302. // scrolling states, see Update.
  22303. if(!this.domNode){return;}
  22304. if(!this._started){return;}
  22305. if(!this.hasLayout()) {
  22306. this.scroller.init(0, this.keepRows, this.rowsPerPage);
  22307. return;
  22308. }
  22309. //
  22310. this.update = this.defaultUpdate;
  22311. this._render();
  22312. },
  22313. _render: function(){
  22314. this.scroller.init(this.get('rowCount'), this.keepRows, this.rowsPerPage);
  22315. this.prerender();
  22316. this.setScrollTop(0);
  22317. this.postrender();
  22318. },
  22319. prerender: function(){
  22320. // if autoHeight, make sure scroller knows not to virtualize; everything must be rendered.
  22321. this.keepRows = this._autoHeight ? 0 : this.keepRows;
  22322. this.scroller.setKeepInfo(this.keepRows);
  22323. this.views.render();
  22324. this._resize();
  22325. },
  22326. postrender: function(){
  22327. this.postresize();
  22328. this.focus.initFocusView();
  22329. // make rows unselectable
  22330. html.setSelectable(this.domNode, this.selectable);
  22331. },
  22332. postresize: function(){
  22333. // views are position absolute, so they do not inflate the parent
  22334. if(this._autoHeight){
  22335. var size = Math.max(this.views.measureContent()) + 'px';
  22336. this.viewsNode.style.height = size;
  22337. }
  22338. },
  22339. renderRow: function(inRowIndex, inNodes){
  22340. // summary: private, used internally to render rows
  22341. this.views.renderRow(inRowIndex, inNodes, this._skipRowRenormalize);
  22342. },
  22343. rowRemoved: function(inRowIndex){
  22344. // summary: private, used internally to remove rows
  22345. this.views.rowRemoved(inRowIndex);
  22346. },
  22347. invalidated: null,
  22348. updating: false,
  22349. beginUpdate: function(){
  22350. // summary:
  22351. // Use to make multiple changes to rows while queueing row updating.
  22352. // NOTE: not currently supporting nested begin/endUpdate calls
  22353. this.invalidated = [];
  22354. this.updating = true;
  22355. },
  22356. endUpdate: function(){
  22357. // summary:
  22358. // Use after calling beginUpdate to render any changes made to rows.
  22359. this.updating = false;
  22360. var i = this.invalidated, r;
  22361. if(i.all){
  22362. this.update();
  22363. }else if(i.rowCount != undefined){
  22364. this.updateRowCount(i.rowCount);
  22365. }else{
  22366. for(r in i){
  22367. this.updateRow(Number(r));
  22368. }
  22369. }
  22370. this.invalidated = [];
  22371. },
  22372. // update
  22373. defaultUpdate: function(){
  22374. // note: initial update calls render and subsequently this function.
  22375. if(!this.domNode){return;}
  22376. if(this.updating){
  22377. this.invalidated.all = true;
  22378. return;
  22379. }
  22380. //this.edit.saveState(inRowIndex);
  22381. this.lastScrollTop = this.scrollTop;
  22382. this.prerender();
  22383. this.scroller.invalidateNodes();
  22384. this.setScrollTop(this.lastScrollTop);
  22385. this.postrender();
  22386. //this.edit.restoreState(inRowIndex);
  22387. },
  22388. update: function(){
  22389. // summary:
  22390. // Update the grid, retaining edit and scrolling states.
  22391. this.render();
  22392. },
  22393. updateRow: function(inRowIndex){
  22394. // summary:
  22395. // Render a single row.
  22396. // inRowIndex: Integer
  22397. // Index of the row to render
  22398. inRowIndex = Number(inRowIndex);
  22399. if(this.updating){
  22400. this.invalidated[inRowIndex]=true;
  22401. }else{
  22402. this.views.updateRow(inRowIndex);
  22403. this.scroller.rowHeightChanged(inRowIndex);
  22404. }
  22405. },
  22406. updateRows: function(startIndex, howMany){
  22407. // summary:
  22408. // Render consecutive rows at once.
  22409. // startIndex: Integer
  22410. // Index of the starting row to render
  22411. // howMany: Integer
  22412. // How many rows to update.
  22413. startIndex = Number(startIndex);
  22414. howMany = Number(howMany);
  22415. var i;
  22416. if(this.updating){
  22417. for(i=0; i<howMany; i++){
  22418. this.invalidated[i+startIndex]=true;
  22419. }
  22420. }else{
  22421. for(i=0; i<howMany; i++){
  22422. this.views.updateRow(i+startIndex, this._skipRowRenormalize);
  22423. }
  22424. this.scroller.rowHeightChanged(startIndex);
  22425. }
  22426. },
  22427. updateRowCount: function(inRowCount){
  22428. //summary:
  22429. // Change the number of rows.
  22430. // inRowCount: int
  22431. // Number of rows in the grid.
  22432. if(this.updating){
  22433. this.invalidated.rowCount = inRowCount;
  22434. }else{
  22435. this.rowCount = inRowCount;
  22436. this._setAutoHeightAttr(this.autoHeight, true);
  22437. if(this.layout.cells.length){
  22438. this.scroller.updateRowCount(inRowCount);
  22439. }
  22440. this._resize();
  22441. if(this.layout.cells.length){
  22442. this.setScrollTop(this.scrollTop);
  22443. }
  22444. }
  22445. },
  22446. updateRowStyles: function(inRowIndex){
  22447. // summary:
  22448. // Update the styles for a row after it's state has changed.
  22449. this.views.updateRowStyles(inRowIndex);
  22450. },
  22451. getRowNode: function(inRowIndex){
  22452. // summary:
  22453. // find the rowNode that is not a rowSelector
  22454. if (this.focus.focusView && !(this.focus.focusView instanceof _RowSelector)){
  22455. return this.focus.focusView.rowNodes[inRowIndex];
  22456. }else{ // search through views
  22457. for (var i = 0, cView; (cView = this.views.views[i]); i++) {
  22458. if (!(cView instanceof _RowSelector)) {
  22459. return cView.rowNodes[inRowIndex];
  22460. }
  22461. }
  22462. }
  22463. return null;
  22464. },
  22465. rowHeightChanged: function(inRowIndex){
  22466. // summary:
  22467. // Update grid when the height of a row has changed. Row height is handled automatically as rows
  22468. // are rendered. Use this function only to update a row's height outside the normal rendering process.
  22469. // inRowIndex: Integer
  22470. // index of the row that has changed height
  22471. this.views.renormalizeRow(inRowIndex);
  22472. this.scroller.rowHeightChanged(inRowIndex);
  22473. },
  22474. // fastScroll: Boolean
  22475. // flag modifies vertical scrolling behavior. Defaults to true but set to false for slower
  22476. // scroll performance but more immediate scrolling feedback
  22477. fastScroll: true,
  22478. delayScroll: false,
  22479. // scrollRedrawThreshold: int
  22480. // pixel distance a user must scroll vertically to trigger grid scrolling.
  22481. scrollRedrawThreshold: (has("ie") ? 100 : 50),
  22482. // scroll methods
  22483. scrollTo: function(inTop){
  22484. // summary:
  22485. // Vertically scroll the grid to a given pixel position
  22486. // inTop: Integer
  22487. // vertical position of the grid in pixels
  22488. if(!this.fastScroll){
  22489. this.setScrollTop(inTop);
  22490. return;
  22491. }
  22492. var delta = Math.abs(this.lastScrollTop - inTop);
  22493. this.lastScrollTop = inTop;
  22494. if(delta > this.scrollRedrawThreshold || this.delayScroll){
  22495. this.delayScroll = true;
  22496. this.scrollTop = inTop;
  22497. this.views.setScrollTop(inTop);
  22498. if(this._pendingScroll){
  22499. window.clearTimeout(this._pendingScroll);
  22500. }
  22501. var _this = this;
  22502. this._pendingScroll = window.setTimeout(function(){
  22503. delete _this._pendingScroll;
  22504. _this.finishScrollJob();
  22505. }, 200);
  22506. }else{
  22507. this.setScrollTop(inTop);
  22508. }
  22509. },
  22510. finishScrollJob: function(){
  22511. this.delayScroll = false;
  22512. this.setScrollTop(this.scrollTop);
  22513. },
  22514. setScrollTop: function(inTop){
  22515. this.scroller.scroll(this.views.setScrollTop(inTop));
  22516. },
  22517. scrollToRow: function(inRowIndex){
  22518. // summary:
  22519. // Scroll the grid to a specific row.
  22520. // inRowIndex: Integer
  22521. // grid row index
  22522. this.setScrollTop(this.scroller.findScrollTop(inRowIndex) + 1);
  22523. },
  22524. // styling (private, used internally to style individual parts of a row)
  22525. styleRowNode: function(inRowIndex, inRowNode){
  22526. if(inRowNode){
  22527. this.rows.styleRowNode(inRowIndex, inRowNode);
  22528. }
  22529. },
  22530. // called when the mouse leaves the grid so we can deselect all hover rows
  22531. _mouseOut: function(e){
  22532. this.rows.setOverRow(-2);
  22533. },
  22534. // cells
  22535. getCell: function(inIndex){
  22536. // summary:
  22537. // Retrieves the cell object for a given grid column.
  22538. // inIndex: Integer
  22539. // Grid column index of cell to retrieve
  22540. // returns:
  22541. // a grid cell
  22542. return this.layout.cells[inIndex];
  22543. },
  22544. setCellWidth: function(inIndex, inUnitWidth){
  22545. this.getCell(inIndex).unitWidth = inUnitWidth;
  22546. },
  22547. getCellName: function(inCell){
  22548. // summary: Returns the cell name of a passed cell
  22549. return "Cell " + inCell.index; // String
  22550. },
  22551. // sorting
  22552. canSort: function(inSortInfo){
  22553. // summary:
  22554. // Determines if the grid can be sorted
  22555. // inSortInfo: Integer
  22556. // Sort information, 1-based index of column on which to sort, positive for an ascending sort
  22557. // and negative for a descending sort
  22558. // returns: Boolean
  22559. // True if grid can be sorted on the given column in the given direction
  22560. },
  22561. sort: function(){
  22562. },
  22563. getSortAsc: function(inSortInfo){
  22564. // summary:
  22565. // Returns true if grid is sorted in an ascending direction.
  22566. inSortInfo = inSortInfo == undefined ? this.sortInfo : inSortInfo;
  22567. return Boolean(inSortInfo > 0); // Boolean
  22568. },
  22569. getSortIndex: function(inSortInfo){
  22570. // summary:
  22571. // Returns the index of the column on which the grid is sorted
  22572. inSortInfo = inSortInfo == undefined ? this.sortInfo : inSortInfo;
  22573. return Math.abs(inSortInfo) - 1; // Integer
  22574. },
  22575. setSortIndex: function(inIndex, inAsc){
  22576. // summary:
  22577. // Sort the grid on a column in a specified direction
  22578. // inIndex: Integer
  22579. // Column index on which to sort.
  22580. // inAsc: Boolean
  22581. // If true, sort the grid in ascending order, otherwise in descending order
  22582. var si = inIndex +1;
  22583. if(inAsc != undefined){
  22584. si *= (inAsc ? 1 : -1);
  22585. } else if(this.getSortIndex() == inIndex){
  22586. si = -this.sortInfo;
  22587. }
  22588. this.setSortInfo(si);
  22589. },
  22590. setSortInfo: function(inSortInfo){
  22591. if(this.canSort(inSortInfo)){
  22592. this.sortInfo = inSortInfo;
  22593. this.sort();
  22594. this.update();
  22595. }
  22596. },
  22597. // DOM event handler
  22598. doKeyEvent: function(e){
  22599. e.dispatch = 'do' + e.type;
  22600. this.onKeyEvent(e);
  22601. },
  22602. // event dispatch
  22603. //: protected
  22604. _dispatch: function(m, e){
  22605. if(m in this){
  22606. return this[m](e);
  22607. }
  22608. return false;
  22609. },
  22610. dispatchKeyEvent: function(e){
  22611. this._dispatch(e.dispatch, e);
  22612. },
  22613. dispatchContentEvent: function(e){
  22614. this.edit.dispatchEvent(e) || e.sourceView.dispatchContentEvent(e) || this._dispatch(e.dispatch, e);
  22615. },
  22616. dispatchHeaderEvent: function(e){
  22617. e.sourceView.dispatchHeaderEvent(e) || this._dispatch('doheader' + e.type, e);
  22618. },
  22619. dokeydown: function(e){
  22620. this.onKeyDown(e);
  22621. },
  22622. doclick: function(e){
  22623. if(e.cellNode){
  22624. this.onCellClick(e);
  22625. }else{
  22626. this.onRowClick(e);
  22627. }
  22628. },
  22629. dodblclick: function(e){
  22630. if(e.cellNode){
  22631. this.onCellDblClick(e);
  22632. }else{
  22633. this.onRowDblClick(e);
  22634. }
  22635. },
  22636. docontextmenu: function(e){
  22637. if(e.cellNode){
  22638. this.onCellContextMenu(e);
  22639. }else{
  22640. this.onRowContextMenu(e);
  22641. }
  22642. },
  22643. doheaderclick: function(e){
  22644. if(e.cellNode){
  22645. this.onHeaderCellClick(e);
  22646. }else{
  22647. this.onHeaderClick(e);
  22648. }
  22649. },
  22650. doheaderdblclick: function(e){
  22651. if(e.cellNode){
  22652. this.onHeaderCellDblClick(e);
  22653. }else{
  22654. this.onHeaderDblClick(e);
  22655. }
  22656. },
  22657. doheadercontextmenu: function(e){
  22658. if(e.cellNode){
  22659. this.onHeaderCellContextMenu(e);
  22660. }else{
  22661. this.onHeaderContextMenu(e);
  22662. }
  22663. },
  22664. // override to modify editing process
  22665. doStartEdit: function(inCell, inRowIndex){
  22666. this.onStartEdit(inCell, inRowIndex);
  22667. },
  22668. doApplyCellEdit: function(inValue, inRowIndex, inFieldIndex){
  22669. this.onApplyCellEdit(inValue, inRowIndex, inFieldIndex);
  22670. },
  22671. doCancelEdit: function(inRowIndex){
  22672. this.onCancelEdit(inRowIndex);
  22673. },
  22674. doApplyEdit: function(inRowIndex){
  22675. this.onApplyEdit(inRowIndex);
  22676. },
  22677. // row editing
  22678. addRow: function(){
  22679. // summary:
  22680. // Add a row to the grid.
  22681. this.updateRowCount(this.get('rowCount')+1);
  22682. },
  22683. removeSelectedRows: function(){
  22684. // summary:
  22685. // Remove the selected rows from the grid.
  22686. if(this.allItemsSelected){
  22687. this.updateRowCount(0);
  22688. }else{
  22689. this.updateRowCount(Math.max(0, this.get('rowCount') - this.selection.getSelected().length));
  22690. }
  22691. this.selection.clear();
  22692. }
  22693. });
  22694. _Grid.markupFactory = function(props, node, ctor, cellFunc){
  22695. var widthFromAttr = function(n){
  22696. var w = html.attr(n, "width")||"auto";
  22697. if((w != "auto")&&(w.slice(-2) != "em")&&(w.slice(-1) != "%")){
  22698. w = parseInt(w, 10)+"px";
  22699. }
  22700. return w;
  22701. };
  22702. // if(!props.store){ console.debug("no store!"); }
  22703. // if a structure isn't referenced, do we have enough
  22704. // data to try to build one automatically?
  22705. if( !props.structure &&
  22706. node.nodeName.toLowerCase() == "table"){
  22707. // try to discover a structure
  22708. props.structure = query("> colgroup", node).map(function(cg){
  22709. var sv = html.attr(cg, "span");
  22710. var v = {
  22711. noscroll: (html.attr(cg, "noscroll") == "true") ? true : false,
  22712. __span: (!!sv ? parseInt(sv, 10) : 1),
  22713. cells: []
  22714. };
  22715. if(html.hasAttr(cg, "width")){
  22716. v.width = widthFromAttr(cg);
  22717. }
  22718. return v; // for vendetta
  22719. });
  22720. if(!props.structure.length){
  22721. props.structure.push({
  22722. __span: Infinity,
  22723. cells: [] // catch-all view
  22724. });
  22725. }
  22726. // check to see if we're gonna have more than one view
  22727. // for each tr in our th, create a row of cells
  22728. query("thead > tr", node).forEach(function(tr, tr_idx){
  22729. var cellCount = 0;
  22730. var viewIdx = 0;
  22731. var lastViewIdx;
  22732. var cView = null;
  22733. query("> th", tr).map(function(th){
  22734. // what view will this cell go into?
  22735. // NOTE:
  22736. // to prevent extraneous iteration, we start counters over
  22737. // for each row, incrementing over the surface area of the
  22738. // structure that colgroup processing generates and
  22739. // creating cell objects for each <th> to place into those
  22740. // cell groups. There's a lot of state-keepking logic
  22741. // here, but it is what it has to be.
  22742. if(!cView){ // current view book keeping
  22743. lastViewIdx = 0;
  22744. cView = props.structure[0];
  22745. }else if(cellCount >= (lastViewIdx+cView.__span)){
  22746. viewIdx++;
  22747. // move to allocating things into the next view
  22748. lastViewIdx += cView.__span;
  22749. var lastView = cView;
  22750. cView = props.structure[viewIdx];
  22751. }
  22752. // actually define the cell from what markup hands us
  22753. var cell = {
  22754. name: lang.trim(html.attr(th, "name")||th.innerHTML),
  22755. colSpan: parseInt(html.attr(th, "colspan")||1, 10),
  22756. type: lang.trim(html.attr(th, "cellType")||""),
  22757. id: lang.trim(html.attr(th,"id")||"")
  22758. };
  22759. cellCount += cell.colSpan;
  22760. var rowSpan = html.attr(th, "rowspan");
  22761. if(rowSpan){
  22762. cell.rowSpan = rowSpan;
  22763. }
  22764. if(html.hasAttr(th, "width")){
  22765. cell.width = widthFromAttr(th);
  22766. }
  22767. if(html.hasAttr(th, "relWidth")){
  22768. cell.relWidth = window.parseInt(html.attr(th, "relWidth"), 10);
  22769. }
  22770. if(html.hasAttr(th, "hidden")){
  22771. cell.hidden = (html.attr(th, "hidden") == "true" || html.attr(th, "hidden") === true/*always boolean true in Chrome*/);
  22772. }
  22773. if(cellFunc){
  22774. cellFunc(th, cell);
  22775. }
  22776. cell.type = cell.type ? lang.getObject(cell.type) : dojox.grid.cells.Cell;
  22777. if(cell.type && cell.type.markupFactory){
  22778. cell.type.markupFactory(th, cell);
  22779. }
  22780. if(!cView.cells[tr_idx]){
  22781. cView.cells[tr_idx] = [];
  22782. }
  22783. cView.cells[tr_idx].push(cell);
  22784. });
  22785. });
  22786. }
  22787. return new ctor(props, node);
  22788. };
  22789. return _Grid;
  22790. });
  22791. },
  22792. 'dojox/grid/enhanced/plugins/IndirectSelection':function(){
  22793. define("dojox/grid/enhanced/plugins/IndirectSelection", [
  22794. "dojo/_base/declare",
  22795. "dojo/_base/array",
  22796. "dojo/_base/event",
  22797. "dojo/_base/lang",
  22798. "dojo/_base/html",
  22799. "dojo/_base/window",
  22800. "dojo/_base/connect",
  22801. "dojo/_base/sniff",
  22802. "dojo/query",
  22803. "dojo/keys",
  22804. "dojo/string",
  22805. "../_Plugin",
  22806. "../../EnhancedGrid",
  22807. "../../cells/dijit"
  22808. ], function(declare, array, evt, lang, html, win, connect, has, query, keys, string, _Plugin, EnhancedGrid){
  22809. var gridCells = lang.getObject("dojox.grid.cells");
  22810. var RowSelector = declare("dojox.grid.cells.RowSelector", gridCells._Widget, {
  22811. // summary:
  22812. // Common attributes & functions for row selectors(Radio|CheckBox)
  22813. //inputType: String
  22814. // Input type - Radio|CheckBox
  22815. inputType: "",
  22816. //map: Object
  22817. // Cache div refs of radio|checkbox to avoid querying each time
  22818. map: null,
  22819. //disabledMap: Object
  22820. // Cache index of disabled rows
  22821. disabledMap: null,
  22822. //isRowSelector: Boolean
  22823. // Marker of indirectSelection cell(column)
  22824. isRowSelector: true,
  22825. //_connects: Array
  22826. // List of all connections.
  22827. _connects: null,
  22828. //_subscribes: Array
  22829. // List of all subscribes.
  22830. _subscribes: null,
  22831. //checkedText: String
  22832. // Checked character for high contrast mode
  22833. checkedText: '&#10003;',
  22834. //unCheckedText: String
  22835. // Unchecked character for high contrast mode
  22836. unCheckedText: 'O',
  22837. constructor: function(){
  22838. this.map = {}; this.disabledMap = {}, this.disabledCount= 0;
  22839. this._connects = []; this._subscribes = [];
  22840. this.inA11YMode = html.hasClass(win.body(), "dijit_a11y");
  22841. this.baseClass = "dojoxGridRowSelector dijitReset dijitInline dijit" + this.inputType;
  22842. this.checkedClass = " dijit" + this.inputType + "Checked";
  22843. this.disabledClass = " dijit" + this.inputType + "Disabled";
  22844. this.checkedDisabledClass = " dijit" + this.inputType + "CheckedDisabled";
  22845. this.statusTextClass = " dojoxGridRowSelectorStatusText";//a11y use
  22846. this._connects.push(connect.connect(this.grid, 'dokeyup', this, '_dokeyup'));
  22847. this._connects.push(connect.connect(this.grid.selection, 'onSelected', this, '_onSelected'));
  22848. this._connects.push(connect.connect(this.grid.selection, 'onDeselected', this, '_onDeselected'));
  22849. this._connects.push(connect.connect(this.grid.scroller, 'invalidatePageNode', this, '_pageDestroyed'));
  22850. this._connects.push(connect.connect(this.grid, 'onCellClick', this, '_onClick'));
  22851. this._connects.push(connect.connect(this.grid, 'updateRow', this, '_onUpdateRow'));
  22852. },
  22853. formatter: function(data, rowIndex, scope){
  22854. // summary:
  22855. // Overwritten, see dojox.grid.cells._Widget
  22856. var _this = scope;
  22857. var clazz = _this.baseClass;
  22858. var checked = _this.getValue(rowIndex);
  22859. var disabled = !!_this.disabledMap[rowIndex];//normalize 'undefined'
  22860. if(checked){
  22861. clazz += _this.checkedClass;
  22862. if(disabled){ clazz += _this.checkedDisabledClass; }
  22863. }else if(disabled){
  22864. clazz += _this.disabledClass;
  22865. }
  22866. return ["<div tabindex = -1 ",
  22867. "id = '" + _this.grid.id + "_rowSelector_" + rowIndex + "' ",
  22868. "name = '" + _this.grid.id + "_rowSelector' class = '" + clazz + "' ",
  22869. "role = 'presentation' aria-pressed = '" + checked + "' aria-disabled = '" + disabled +
  22870. "' aria-label = '" + string.substitute(_this.grid._nls["indirectSelection" + _this.inputType], [rowIndex + 1]) + "'>",
  22871. "<span class = '" + _this.statusTextClass + "'>" + (checked ? _this.checkedText : _this.unCheckedText) + "</span>",
  22872. "</div>"].join("");
  22873. },
  22874. setValue: function(rowIndex, inValue){
  22875. // summary:
  22876. // Overwritten, see dojox.grid.cells._Widget
  22877. // Simply return, no action
  22878. },
  22879. getValue: function(rowIndex){
  22880. // summary:
  22881. // Overwritten, see dojox.grid.cells._Widget
  22882. return this.grid.selection.isSelected(rowIndex);
  22883. },
  22884. toggleRow: function(index, value){
  22885. // summary:
  22886. // toggle checked | unchecked state for given row
  22887. // index: Integer
  22888. // Row index
  22889. // value: Boolean
  22890. // True - checked | False - unchecked
  22891. this._nativeSelect(index, value);
  22892. },
  22893. setDisabled: function(index, disabled){
  22894. // summary:
  22895. // toggle disabled | enabled state for given row
  22896. // idx: Integer
  22897. // Row index
  22898. // disabled: Boolean
  22899. // True - disabled | False - enabled
  22900. if(index < 0){ return; }
  22901. this._toggleDisabledStyle(index, disabled);
  22902. },
  22903. disabled: function(index){
  22904. // summary:
  22905. // Check if one row is disabled
  22906. return !!this.disabledMap[index];
  22907. },
  22908. _onClick: function(e){
  22909. // summary:
  22910. // When mouse click on the selector cell, select/deselect the row.
  22911. if(e.cell === this){
  22912. this._selectRow(e);
  22913. }
  22914. },
  22915. _dokeyup: function(e){
  22916. // summary:
  22917. // Event handler for key up event
  22918. // - from dojox.grid.enhanced._Events.dokeyup()
  22919. // e: Event
  22920. // Key up event
  22921. if(e.cellIndex == this.index && e.rowIndex >= 0 && e.keyCode == keys.SPACE){
  22922. this._selectRow(e);
  22923. }
  22924. },
  22925. focus: function(rowIndex){
  22926. // summary:
  22927. // Set focus to given row
  22928. // rowIndex: Integer
  22929. // Target row
  22930. var selector = this.map[rowIndex];
  22931. if(selector){ selector.focus(); }
  22932. },
  22933. _focusEndingCell: function(rowIndex, cellIndex){
  22934. // summary:
  22935. // Set focus to the ending grid cell(rowIndex,cellIndex) when swipe selection finished
  22936. // rowIndex: Integer
  22937. // Row index
  22938. // cellIndex: Integer
  22939. // Column index
  22940. var cell = this.grid.getCell(cellIndex);
  22941. this.grid.focus.setFocusCell(cell, rowIndex);
  22942. },
  22943. _nativeSelect: function(index, value){
  22944. // summary:
  22945. // Use grid's native selection
  22946. this.grid.selection[value ? 'select' : 'deselect'](index);
  22947. },
  22948. _onSelected: function(index){
  22949. // summary:
  22950. // Triggered when a row is selected
  22951. this._toggleCheckedStyle(index, true);
  22952. },
  22953. _onDeselected: function(index){
  22954. // summary:
  22955. // Triggered when a row is deselected
  22956. this._toggleCheckedStyle(index, false);
  22957. },
  22958. _onUpdateRow: function(index){
  22959. // summary:
  22960. // Clear cache when row is re-built.
  22961. delete this.map[index];
  22962. },
  22963. _toggleCheckedStyle: function(index, value){
  22964. // summary:
  22965. // Change css styles for checked | unchecked
  22966. var selector = this._getSelector(index);
  22967. if(selector){
  22968. html.toggleClass(selector, this.checkedClass, value);
  22969. if(this.disabledMap[index]){
  22970. html.toggleClass(selector, this.checkedDisabledClass, value);
  22971. }
  22972. selector.setAttribute("aria-pressed", value);
  22973. if(this.inA11YMode){
  22974. selector.firstChild.innerHTML = (value ? this.checkedText : this.unCheckedText);
  22975. }
  22976. }
  22977. },
  22978. _toggleDisabledStyle: function(index, disabled){
  22979. // summary:
  22980. // Change css styles for disabled | enabled
  22981. var selector = this._getSelector(index);
  22982. if(selector){
  22983. html.toggleClass(selector, this.disabledClass, disabled);
  22984. if(this.getValue(index)){
  22985. html.toggleClass(selector, this.checkedDisabledClass, disabled);
  22986. }
  22987. selector.setAttribute("aria-disabled", disabled);
  22988. }
  22989. this.disabledMap[index] = disabled;
  22990. if(index >= 0){
  22991. this.disabledCount += disabled ? 1 : -1;
  22992. }
  22993. },
  22994. _getSelector: function(index){
  22995. // summary:
  22996. // Find selector for given row caching it if 1st time found
  22997. var selector = this.map[index];
  22998. if(!selector){//use accurate query for better performance
  22999. var rowNode = this.view.rowNodes[index];
  23000. if(rowNode){
  23001. selector = query('.dojoxGridRowSelector', rowNode)[0];
  23002. if(selector){ this.map[index] = selector; }
  23003. }
  23004. }
  23005. return selector;
  23006. },
  23007. _pageDestroyed: function(pageIndex){
  23008. // summary:
  23009. // Explicitly empty map cache when a page destroyed
  23010. // See dojox.grid._Scroller.invalidatePageNode()
  23011. // pageIndex: Integer
  23012. // Index of destroyed page
  23013. var rowsPerPage = this.grid.scroller.rowsPerPage;
  23014. var start = pageIndex * rowsPerPage, end = start + rowsPerPage - 1;
  23015. for(var i = start; i <= end; i++){
  23016. if(!this.map[i]){continue;}
  23017. html.destroy(this.map[i]);
  23018. delete this.map[i];
  23019. }
  23020. //console.log("Page ",pageIndex, " destroyed, Map=",this.map);
  23021. },
  23022. destroy: function(){
  23023. for(var i in this.map){
  23024. html.destroy(this.map[i]);
  23025. delete this.map[i];
  23026. }
  23027. for(i in this.disabledMap){ delete this.disabledMap[i]; }
  23028. array.forEach(this._connects, connect.disconnect);
  23029. array.forEach(this._subscribes, connect.unsubscribe);
  23030. delete this._connects;
  23031. delete this._subscribes;
  23032. //console.log('Single(Multiple)RowSelector.destroy() executed!');
  23033. }
  23034. });
  23035. var SingleRowSelector = declare("dojox.grid.cells.SingleRowSelector", RowSelector, {
  23036. // summary:
  23037. // IndirectSelection cell(column) for single selection mode, using styles of dijit.form.RadioButton
  23038. inputType: "Radio",
  23039. _selectRow: function(e){
  23040. // summary:
  23041. // Select the target row
  23042. // e: Event
  23043. // Event fired on the target row
  23044. var index = e.rowIndex;
  23045. if(this.disabledMap[index]){ return; }
  23046. this._focusEndingCell(index, 0);
  23047. this._nativeSelect(index, !this.grid.selection.selected[index]);
  23048. }
  23049. });
  23050. var MultipleRowSelector = declare("dojox.grid.cells.MultipleRowSelector", RowSelector, {
  23051. // summary:
  23052. // Indirect selection cell for multiple or extended mode, using dijit.form.CheckBox
  23053. inputType: "CheckBox",
  23054. //swipeStartRowIndex: Integer
  23055. // Start row index for swipe selection
  23056. swipeStartRowIndex: -1,
  23057. //swipeMinRowIndex: Integer
  23058. // Min row index for swipe selection
  23059. swipeMinRowIndex: -1,
  23060. //swipeMinRowIndex: Integer
  23061. // Max row index for swipe selection
  23062. swipeMaxRowIndex: -1,
  23063. //toSelect: Boolean
  23064. // new state for selection
  23065. toSelect: false,
  23066. //lastClickRowIdx: Integer
  23067. // Row index for last click, used for range selection via Shift + click
  23068. lastClickRowIdx: -1,
  23069. //toggleAllTrigerred: Boolean
  23070. // Whether toggle all has been triggered or not
  23071. toggleAllTrigerred: false,
  23072. unCheckedText: '&#9633;',
  23073. constructor: function(){
  23074. this._connects.push(connect.connect(win.doc, 'onmouseup', this, '_domouseup'));
  23075. this._connects.push(connect.connect(this.grid, 'onRowMouseOver', this, '_onRowMouseOver'));
  23076. this._connects.push(connect.connect(this.grid.focus, 'move', this, '_swipeByKey'));
  23077. this._connects.push(connect.connect(this.grid, 'onCellMouseDown', this, '_onMouseDown'));
  23078. if(this.headerSelector){//option set by user to add a select-all checkbox in column header
  23079. this._connects.push(connect.connect(this.grid.views, 'render', this, '_addHeaderSelector'));
  23080. this._connects.push(connect.connect(this.grid, '_onFetchComplete', this, '_addHeaderSelector'));
  23081. this._connects.push(connect.connect(this.grid, 'onSelectionChanged', this, '_onSelectionChanged'));
  23082. this._connects.push(connect.connect(this.grid, 'onKeyDown', this, function(e){
  23083. if(e.rowIndex == -1 && e.cellIndex == this.index && e.keyCode == keys.SPACE){
  23084. this._toggletHeader();//TBD - a better way
  23085. }
  23086. }));
  23087. }
  23088. },
  23089. toggleAllSelection:function(checked){
  23090. // summary:
  23091. // Toggle select all|deselect all
  23092. // checked: Boolean
  23093. // True - select all, False - deselect all
  23094. var grid = this.grid, selection = grid.selection;
  23095. if(checked){
  23096. selection.selectRange(0, grid.rowCount-1);
  23097. }else{
  23098. selection.deselectAll();
  23099. }
  23100. this.toggleAllTrigerred = true;
  23101. },
  23102. _onMouseDown: function(e){
  23103. if(e.cell == this){
  23104. this._startSelection(e.rowIndex);
  23105. evt.stop(e);
  23106. }
  23107. },
  23108. _onRowMouseOver: function(e){
  23109. // summary:
  23110. // Event fired when mouse moves over a data row(outside of this column).
  23111. // - from dojox.grid.enhanced._Events.onRowMouseOver()
  23112. // e: Event
  23113. // Decorated event object which contains reference to grid, cell, and rowIndex
  23114. this._updateSelection(e, 0);
  23115. },
  23116. _domouseup: function(e){
  23117. // summary:
  23118. // Event handler for mouse up event - from dojo.doc.domouseup()
  23119. // e: Event
  23120. // Mouse up event
  23121. if(has("ie")){
  23122. this.view.content.decorateEvent(e);//TODO - why only e in IE hasn't been decorated?
  23123. }
  23124. var inSwipeSelection = e.cellIndex >= 0 && this.inSwipeSelection() && !this.grid.edit.isEditRow(e.rowIndex);
  23125. if(inSwipeSelection){
  23126. this._focusEndingCell(e.rowIndex, e.cellIndex);
  23127. }
  23128. this._finishSelect();
  23129. },
  23130. _dokeyup: function(e){
  23131. // summary:
  23132. // Event handler for key up event
  23133. // - from dojox.grid.enhanced._Events.dokeyup()
  23134. // e: Event
  23135. // Key up event
  23136. this.inherited(arguments);
  23137. if(!e.shiftKey){
  23138. this._finishSelect();
  23139. }
  23140. },
  23141. _startSelection: function(rowIndex){
  23142. // summary:
  23143. // Initialize parameters to start a new swipe selection
  23144. // rowIndex: Integer
  23145. // Index of the start row
  23146. this.swipeStartRowIndex = this.swipeMinRowIndex = this.swipeMaxRowIndex = rowIndex;
  23147. this.toSelect = !this.getValue(rowIndex);
  23148. },
  23149. _updateSelection: function(e, delta){
  23150. // summary:
  23151. // Update row selections, fired during a swipe selection
  23152. // e: Event
  23153. // Event of the current row,
  23154. // delta: Integer
  23155. // Row index delta, used for swipe selection via Shift + Arrow key
  23156. // 0: not via key, -1 : Shift + Up, 1 : Shift + Down
  23157. if(!this.inSwipeSelection()){ return; }
  23158. var byKey = delta !== 0;//whether via Shift + Arrow Key
  23159. var currRow = e.rowIndex, deltaRow = currRow - this.swipeStartRowIndex + delta;
  23160. if(deltaRow > 0 && this.swipeMaxRowIndex < currRow + delta){
  23161. this.swipeMaxRowIndex = currRow + delta;
  23162. }
  23163. if(deltaRow < 0 && this.swipeMinRowIndex > currRow + delta){
  23164. this.swipeMinRowIndex = currRow + delta;
  23165. }
  23166. var min = deltaRow > 0 ? this.swipeStartRowIndex : currRow + delta;
  23167. var max = deltaRow > 0 ? currRow + delta : this.swipeStartRowIndex;
  23168. for(var i = this.swipeMinRowIndex; i <= this.swipeMaxRowIndex; i++){
  23169. if(this.disabledMap[i] || i < 0){ continue; }
  23170. if(i >= min && i <= max){//deltaRow != 0 || this.toSelect
  23171. this._nativeSelect(i, this.toSelect);
  23172. }else if(!byKey){
  23173. this._nativeSelect(i, !this.toSelect);
  23174. }
  23175. }
  23176. },
  23177. _swipeByKey: function(rowOffset, colOffset, e){
  23178. // summary:
  23179. // Update row selections, fired when Shift + Cursor is used for swipe selection
  23180. // See dojox.grid.enhanced._Events.onKeyDown
  23181. // e: Event
  23182. // Event of the current row,
  23183. // rowOffset: Integer
  23184. // Row offset, used for swipe selection via Shift + Cursor
  23185. // -1 : Shift + Up, 1 : Shift + Down
  23186. if(!e || rowOffset === 0 || !e.shiftKey || e.cellIndex != this.index ||
  23187. this.grid.focus.rowIndex < 0){ //TBD - e.rowIndex == 0 && delta == -1
  23188. return;
  23189. }
  23190. var rowIndex = e.rowIndex;
  23191. if(this.swipeStartRowIndex < 0){
  23192. //A new swipe selection starts via Shift + Arrow key
  23193. this.swipeStartRowIndex = rowIndex;
  23194. if(rowOffset > 0){//Shift + Down
  23195. this.swipeMaxRowIndex = rowIndex + rowOffset;
  23196. this.swipeMinRowIndex = rowIndex;
  23197. }else{//Shift + UP
  23198. this.swipeMinRowIndex = rowIndex + rowOffset;
  23199. this.swipeMaxRowIndex = rowIndex;
  23200. }
  23201. this.toSelect = this.getValue(rowIndex);
  23202. }
  23203. this._updateSelection(e, rowOffset);
  23204. },
  23205. _finishSelect: function(){
  23206. // summary:
  23207. // Reset parameters to end a swipe selection
  23208. this.swipeStartRowIndex = -1;
  23209. this.swipeMinRowIndex = -1;
  23210. this.swipeMaxRowIndex = -1;
  23211. this.toSelect = false;
  23212. },
  23213. inSwipeSelection: function(){
  23214. // summary:
  23215. // Check if during a swipe selection
  23216. // return: Boolean
  23217. // Whether in swipe selection
  23218. return this.swipeStartRowIndex >= 0;
  23219. },
  23220. _nativeSelect: function(index, value){
  23221. // summary:
  23222. // Overwritten
  23223. this.grid.selection[value ? 'addToSelection' : 'deselect'](index);
  23224. },
  23225. _selectRow: function(e){
  23226. // summary:
  23227. // Select the target row or range or rows
  23228. // e: Event
  23229. // Event fired on the target row
  23230. var rowIndex = e.rowIndex;
  23231. if(this.disabledMap[rowIndex]){ return; }
  23232. evt.stop(e);
  23233. this._focusEndingCell(rowIndex, 0);
  23234. var delta = rowIndex - this.lastClickRowIdx;
  23235. var newValue = !this.grid.selection.selected[rowIndex];
  23236. if(this.lastClickRowIdx >= 0 && !e.ctrlKey && !e.altKey && e.shiftKey){
  23237. var min = delta > 0 ? this.lastClickRowIdx : rowIndex;
  23238. var max = delta > 0 ? rowIndex : this.lastClickRowIdx;
  23239. for(var i = min; i >= 0 && i <= max; i++){
  23240. this._nativeSelect(i, newValue);
  23241. }
  23242. }else{
  23243. this._nativeSelect(rowIndex, newValue);
  23244. }
  23245. this.lastClickRowIdx = rowIndex;
  23246. },
  23247. getValue: function(rowIndex){
  23248. // summary:
  23249. // Overwritten
  23250. if(rowIndex == -1){//header selector
  23251. var g = this.grid;
  23252. return g.rowCount > 0 && g.rowCount <= g.selection.getSelectedCount();
  23253. }
  23254. return this.inherited(arguments);
  23255. },
  23256. _addHeaderSelector: function(){
  23257. // summary:
  23258. // Add selector in column header for selecting|deselecting all
  23259. var headerCellNode = this.view.getHeaderCellNode(this.index);
  23260. if(!headerCellNode){ return; }
  23261. html.empty(headerCellNode);
  23262. var g = this.grid;
  23263. var selector = headerCellNode.appendChild(html.create("div", {
  23264. 'aria-label': g._nls["selectAll"],
  23265. "tabindex": -1, "id": g.id + "_rowSelector_-1", "class": this.baseClass, "role": "presentation",
  23266. "innerHTML": "<span class = '" + this.statusTextClass +
  23267. "'></span><span style='height: 0; width: 0; overflow: hidden; display: block;'>" +
  23268. g._nls["selectAll"] + "</span>"
  23269. }));
  23270. this.map[-1] = selector;
  23271. var idx = this._headerSelectorConnectIdx;
  23272. if(idx !== undefined){
  23273. connect.disconnect(this._connects[idx]);
  23274. this._connects.splice(idx, 1);
  23275. }
  23276. this._headerSelectorConnectIdx = this._connects.length;
  23277. this._connects.push(connect.connect(selector, 'onclick', this, '_toggletHeader'));
  23278. this._onSelectionChanged();
  23279. },
  23280. _toggletHeader: function(){
  23281. // summary:
  23282. // Toggle state for head selector
  23283. if(!!this.disabledMap[-1]){ return; }
  23284. this.grid._selectingRange = true;
  23285. this.toggleAllSelection(!this.getValue(-1));
  23286. this._onSelectionChanged();
  23287. this.grid._selectingRange = false;
  23288. },
  23289. _onSelectionChanged: function(){
  23290. // summary:
  23291. // Update header selector anytime selection changed
  23292. var g = this.grid;
  23293. if(!this.map[-1] || g._selectingRange){ return; }
  23294. g.allItemsSelected = this.getValue(-1);
  23295. this._toggleCheckedStyle(-1, g.allItemsSelected);
  23296. },
  23297. _toggleDisabledStyle: function(index, disabled){
  23298. // summary:
  23299. // Overwritten
  23300. this.inherited(arguments);
  23301. if(this.headerSelector){
  23302. var allDisabled = (this.grid.rowCount == this.disabledCount);
  23303. if(allDisabled != !!this.disabledMap[-1]){//only if needed
  23304. arguments[0] = -1;
  23305. arguments[1] = allDisabled;
  23306. this.inherited(arguments);
  23307. }
  23308. }
  23309. }
  23310. });
  23311. var IndirectSelection = declare("dojox.grid.enhanced.plugins.IndirectSelection", _Plugin, {
  23312. // summary:
  23313. // A handy way for adding check boxe/radio button for rows, and selecting rows by swiping(or keyboard)
  23314. // description:
  23315. // For better rendering performance, div(images) are used to simulate radio button|check boxes
  23316. //
  23317. // example:
  23318. // <div dojoType="dojox.grid.EnhancedGrid" plugins="{indirectSelection: true}" ...></div>
  23319. // or <div dojoType="dojox.grid.EnhancedGrid" plugins="{indirectSelection: {name: 'xxx', width:'30px', styles:'text-align: center;'}}" ...></div>
  23320. //name: String
  23321. // Plugin name
  23322. name: "indirectSelection",
  23323. constructor: function(){
  23324. //Hook layout.setStructure(), so that indirectSelection is always included
  23325. var layout = this.grid.layout;
  23326. this.connect(layout, 'setStructure', lang.hitch(layout, this.addRowSelectCell, this.option));
  23327. },
  23328. addRowSelectCell: function(option){
  23329. // summary:
  23330. // Add indirectSelection cell(mapped to a column of radio button|check boxes)
  23331. if(!this.grid.indirectSelection || this.grid.selectionMode == 'none'){
  23332. return;
  23333. }
  23334. var rowSelectCellAdded = false, inValidFields = ['get', 'formatter', 'field', 'fields'],
  23335. defaultCellDef = {type: MultipleRowSelector, name: '', width:'30px', styles:'text-align: center;'};
  23336. if(option.headerSelector){ option.name = ''; }//mutual conflicting attrs
  23337. if(this.grid.rowSelectCell){//remove the existed one
  23338. this.grid.rowSelectCell.destroy();
  23339. }
  23340. array.forEach(this.structure, function(view){
  23341. var cells = view.cells;
  23342. if(cells && cells.length > 0 && !rowSelectCellAdded){
  23343. var firstRow = cells[0];
  23344. if(firstRow[0] && firstRow[0].isRowSelector){
  23345. console.debug('addRowSelectCell() - row selector cells already added, return.');
  23346. rowSelectCellAdded = true;
  23347. return;
  23348. }
  23349. var selectDef, cellType = this.grid.selectionMode == 'single' ? SingleRowSelector : MultipleRowSelector;
  23350. selectDef = lang.mixin(defaultCellDef, option, {type: cellType, editable: false, notselectable: true, filterable: false, navigatable: true, nosort: true});
  23351. array.forEach(inValidFields, function(field){//remove invalid fields
  23352. if(field in selectDef){ delete selectDef[field]; }
  23353. });
  23354. if(cells.length > 1){ selectDef.rowSpan = cells.length; }//for complicate layout
  23355. array.forEach(this.cells, function(cell, i){
  23356. if(cell.index >= 0){
  23357. cell.index += 1;
  23358. //console.debug('cell '+ (cell.index - 1) + ' is updated to index ' + cell.index);
  23359. }else{
  23360. console.warn('Error:IndirectSelection.addRowSelectCell()- cell ' + i + ' has no index!');
  23361. }
  23362. });
  23363. var rowSelectCell = this.addCellDef(0, 0, selectDef);
  23364. rowSelectCell.index = 0;
  23365. firstRow.unshift(rowSelectCell);
  23366. this.cells.unshift(rowSelectCell);
  23367. this.grid.rowSelectCell = rowSelectCell;
  23368. rowSelectCellAdded = true;
  23369. }
  23370. }, this);
  23371. this.cellCount = this.cells.length;
  23372. },
  23373. destroy: function(){
  23374. this.grid.rowSelectCell.destroy();
  23375. delete this.grid.rowSelectCell;
  23376. this.inherited(arguments);
  23377. }
  23378. });
  23379. EnhancedGrid.registerPlugin(IndirectSelection/*name:'indirectSelection'*/, {"preInit": true});
  23380. return IndirectSelection;
  23381. });
  23382. },
  23383. 'dijit/Editor':function(){
  23384. define("dijit/Editor", [
  23385. "dojo/_base/array", // array.forEach
  23386. "dojo/_base/declare", // declare
  23387. "dojo/_base/Deferred", // Deferred
  23388. "dojo/i18n", // i18n.getLocalization
  23389. "dojo/dom-attr", // domAttr.set
  23390. "dojo/dom-class", // domClass.add
  23391. "dojo/dom-geometry",
  23392. "dojo/dom-style", // domStyle.set, get
  23393. "dojo/_base/event", // event.stop
  23394. "dojo/keys", // keys.F1 keys.F15 keys.TAB
  23395. "dojo/_base/lang", // lang.getObject lang.hitch
  23396. "dojo/_base/sniff", // has("ie") has("mac") has("webkit")
  23397. "dojo/string", // string.substitute
  23398. "dojo/topic", // topic.publish()
  23399. "dojo/_base/window", // win.withGlobal
  23400. "./_base/focus", // dijit.getBookmark()
  23401. "./_Container",
  23402. "./Toolbar",
  23403. "./ToolbarSeparator",
  23404. "./layout/_LayoutWidget",
  23405. "./form/ToggleButton",
  23406. "./_editor/_Plugin",
  23407. "./_editor/plugins/EnterKeyHandling",
  23408. "./_editor/html",
  23409. "./_editor/range",
  23410. "./_editor/RichText",
  23411. ".", // dijit._scopeName
  23412. "dojo/i18n!./_editor/nls/commands"
  23413. ], function(array, declare, Deferred, i18n, domAttr, domClass, domGeometry, domStyle,
  23414. event, keys, lang, has, string, topic, win,
  23415. focusBase, _Container, Toolbar, ToolbarSeparator, _LayoutWidget, ToggleButton,
  23416. _Plugin, EnterKeyHandling, html, rangeapi, RichText, dijit){
  23417. // module:
  23418. // dijit/Editor
  23419. // summary:
  23420. // A rich text Editing widget
  23421. var Editor = declare("dijit.Editor", RichText, {
  23422. // summary:
  23423. // A rich text Editing widget
  23424. //
  23425. // description:
  23426. // This widget provides basic WYSIWYG editing features, based on the browser's
  23427. // underlying rich text editing capability, accompanied by a toolbar (`dijit.Toolbar`).
  23428. // A plugin model is available to extend the editor's capabilities as well as the
  23429. // the options available in the toolbar. Content generation may vary across
  23430. // browsers, and clipboard operations may have different results, to name
  23431. // a few limitations. Note: this widget should not be used with the HTML
  23432. // &lt;TEXTAREA&gt; tag -- see dijit._editor.RichText for details.
  23433. // plugins: [const] Object[]
  23434. // A list of plugin names (as strings) or instances (as objects)
  23435. // for this widget.
  23436. //
  23437. // When declared in markup, it might look like:
  23438. // | plugins="['bold',{name:'dijit._editor.plugins.FontChoice', command:'fontName', generic:true}]"
  23439. plugins: null,
  23440. // extraPlugins: [const] Object[]
  23441. // A list of extra plugin names which will be appended to plugins array
  23442. extraPlugins: null,
  23443. constructor: function(){
  23444. // summary:
  23445. // Runs on widget initialization to setup arrays etc.
  23446. // tags:
  23447. // private
  23448. if(!lang.isArray(this.plugins)){
  23449. this.plugins=["undo","redo","|","cut","copy","paste","|","bold","italic","underline","strikethrough","|",
  23450. "insertOrderedList","insertUnorderedList","indent","outdent","|","justifyLeft","justifyRight","justifyCenter","justifyFull",
  23451. EnterKeyHandling /*, "createLink"*/];
  23452. }
  23453. this._plugins=[];
  23454. this._editInterval = this.editActionInterval * 1000;
  23455. //IE will always lose focus when other element gets focus, while for FF and safari,
  23456. //when no iframe is used, focus will be lost whenever another element gets focus.
  23457. //For IE, we can connect to onBeforeDeactivate, which will be called right before
  23458. //the focus is lost, so we can obtain the selected range. For other browsers,
  23459. //no equivalent of onBeforeDeactivate, so we need to do two things to make sure
  23460. //selection is properly saved before focus is lost: 1) when user clicks another
  23461. //element in the page, in which case we listen to mousedown on the entire page and
  23462. //see whether user clicks out of a focus editor, if so, save selection (focus will
  23463. //only lost after onmousedown event is fired, so we can obtain correct caret pos.)
  23464. //2) when user tabs away from the editor, which is handled in onKeyDown below.
  23465. if(has("ie")){
  23466. this.events.push("onBeforeDeactivate");
  23467. this.events.push("onBeforeActivate");
  23468. }
  23469. },
  23470. postMixInProperties: function(){
  23471. // summary:
  23472. // Extension to make sure a deferred is in place before certain functions
  23473. // execute, like making sure all the plugins are properly inserted.
  23474. // Set up a deferred so that the value isn't applied to the editor
  23475. // until all the plugins load, needed to avoid timing condition
  23476. // reported in #10537.
  23477. this.setValueDeferred = new Deferred();
  23478. this.inherited(arguments);
  23479. },
  23480. postCreate: function(){
  23481. //for custom undo/redo, if enabled.
  23482. this._steps=this._steps.slice(0);
  23483. this._undoedSteps=this._undoedSteps.slice(0);
  23484. if(lang.isArray(this.extraPlugins)){
  23485. this.plugins=this.plugins.concat(this.extraPlugins);
  23486. }
  23487. this.inherited(arguments);
  23488. this.commands = i18n.getLocalization("dijit._editor", "commands", this.lang);
  23489. if(!this.toolbar){
  23490. // if we haven't been assigned a toolbar, create one
  23491. this.toolbar = new Toolbar({
  23492. dir: this.dir,
  23493. lang: this.lang
  23494. });
  23495. this.header.appendChild(this.toolbar.domNode);
  23496. }
  23497. array.forEach(this.plugins, this.addPlugin, this);
  23498. // Okay, denote the value can now be set.
  23499. this.setValueDeferred.callback(true);
  23500. domClass.add(this.iframe.parentNode, "dijitEditorIFrameContainer");
  23501. domClass.add(this.iframe, "dijitEditorIFrame");
  23502. domAttr.set(this.iframe, "allowTransparency", true);
  23503. if(has("webkit")){
  23504. // Disable selecting the entire editor by inadvertent double-clicks.
  23505. // on buttons, title bar, etc. Otherwise clicking too fast on
  23506. // a button such as undo/redo selects the entire editor.
  23507. domStyle.set(this.domNode, "KhtmlUserSelect", "none");
  23508. }
  23509. this.toolbar.startup();
  23510. this.onNormalizedDisplayChanged(); //update toolbar button status
  23511. },
  23512. destroy: function(){
  23513. array.forEach(this._plugins, function(p){
  23514. if(p && p.destroy){
  23515. p.destroy();
  23516. }
  23517. });
  23518. this._plugins=[];
  23519. this.toolbar.destroyRecursive();
  23520. delete this.toolbar;
  23521. this.inherited(arguments);
  23522. },
  23523. addPlugin: function(/*String||Object||Function*/plugin, /*Integer?*/index){
  23524. // summary:
  23525. // takes a plugin name as a string or a plugin instance and
  23526. // adds it to the toolbar and associates it with this editor
  23527. // instance. The resulting plugin is added to the Editor's
  23528. // plugins array. If index is passed, it's placed in the plugins
  23529. // array at that index. No big magic, but a nice helper for
  23530. // passing in plugin names via markup.
  23531. //
  23532. // plugin: String, args object, plugin instance, or plugin constructor
  23533. //
  23534. // args:
  23535. // This object will be passed to the plugin constructor
  23536. //
  23537. // index: Integer
  23538. // Used when creating an instance from
  23539. // something already in this.plugins. Ensures that the new
  23540. // instance is assigned to this.plugins at that index.
  23541. var args=lang.isString(plugin)?{name:plugin}:lang.isFunction(plugin)?{ctor:plugin}:plugin;
  23542. if(!args.setEditor){
  23543. var o={"args":args,"plugin":null,"editor":this};
  23544. if(args.name){
  23545. // search registry for a plugin factory matching args.name, if it's not there then
  23546. // fallback to 1.0 API:
  23547. // ask all loaded plugin modules to fill in o.plugin if they can (ie, if they implement args.name)
  23548. // remove fallback for 2.0.
  23549. if(_Plugin.registry[args.name]){
  23550. o.plugin = _Plugin.registry[args.name](args);
  23551. }else{
  23552. topic.publish(dijit._scopeName + ".Editor.getPlugin", o); // publish
  23553. }
  23554. }
  23555. if(!o.plugin){
  23556. var pc = args.ctor || lang.getObject(args.name);
  23557. if(pc){
  23558. o.plugin=new pc(args);
  23559. }
  23560. }
  23561. if(!o.plugin){
  23562. console.warn('Cannot find plugin',plugin);
  23563. return;
  23564. }
  23565. plugin=o.plugin;
  23566. }
  23567. if(arguments.length > 1){
  23568. this._plugins[index] = plugin;
  23569. }else{
  23570. this._plugins.push(plugin);
  23571. }
  23572. plugin.setEditor(this);
  23573. if(lang.isFunction(plugin.setToolbar)){
  23574. plugin.setToolbar(this.toolbar);
  23575. }
  23576. },
  23577. //the following 2 functions are required to make the editor play nice under a layout widget, see #4070
  23578. resize: function(size){
  23579. // summary:
  23580. // Resize the editor to the specified size, see `dijit.layout._LayoutWidget.resize`
  23581. if(size){
  23582. // we've been given a height/width for the entire editor (toolbar + contents), calls layout()
  23583. // to split the allocated size between the toolbar and the contents
  23584. _LayoutWidget.prototype.resize.apply(this, arguments);
  23585. }
  23586. /*
  23587. else{
  23588. // do nothing, the editor is already laid out correctly. The user has probably specified
  23589. // the height parameter, which was used to set a size on the iframe
  23590. }
  23591. */
  23592. },
  23593. layout: function(){
  23594. // summary:
  23595. // Called from `dijit.layout._LayoutWidget.resize`. This shouldn't be called directly
  23596. // tags:
  23597. // protected
  23598. // Converts the iframe (or rather the <div> surrounding it) to take all the available space
  23599. // except what's needed for the header (toolbars) and footer (breadcrumbs, etc).
  23600. // A class was added to the iframe container and some themes style it, so we have to
  23601. // calc off the added margins and padding too. See tracker: #10662
  23602. var areaHeight = (this._contentBox.h -
  23603. (this.getHeaderHeight() + this.getFooterHeight() +
  23604. domGeometry.getPadBorderExtents(this.iframe.parentNode).h +
  23605. domGeometry.getMarginExtents(this.iframe.parentNode).h));
  23606. this.editingArea.style.height = areaHeight + "px";
  23607. if(this.iframe){
  23608. this.iframe.style.height="100%";
  23609. }
  23610. this._layoutMode = true;
  23611. },
  23612. _onIEMouseDown: function(/*Event*/ e){
  23613. // summary:
  23614. // IE only to prevent 2 clicks to focus
  23615. // tags:
  23616. // private
  23617. var outsideClientArea;
  23618. // IE 8's componentFromPoint is broken, which is a shame since it
  23619. // was smaller code, but oh well. We have to do this brute force
  23620. // to detect if the click was scroller or not.
  23621. var b = this.document.body;
  23622. var clientWidth = b.clientWidth;
  23623. var clientHeight = b.clientHeight;
  23624. var clientLeft = b.clientLeft;
  23625. var offsetWidth = b.offsetWidth;
  23626. var offsetHeight = b.offsetHeight;
  23627. var offsetLeft = b.offsetLeft;
  23628. //Check for vertical scroller click.
  23629. if(/^rtl$/i.test(b.dir || "")){
  23630. if(clientWidth < offsetWidth && e.x > clientWidth && e.x < offsetWidth){
  23631. // Check the click was between width and offset width, if so, scroller
  23632. outsideClientArea = true;
  23633. }
  23634. }else{
  23635. // RTL mode, we have to go by the left offsets.
  23636. if(e.x < clientLeft && e.x > offsetLeft){
  23637. // Check the click was between width and offset width, if so, scroller
  23638. outsideClientArea = true;
  23639. }
  23640. }
  23641. if(!outsideClientArea){
  23642. // Okay, might be horiz scroller, check that.
  23643. if(clientHeight < offsetHeight && e.y > clientHeight && e.y < offsetHeight){
  23644. // Horizontal scroller.
  23645. outsideClientArea = true;
  23646. }
  23647. }
  23648. if(!outsideClientArea){
  23649. delete this._cursorToStart; // Remove the force to cursor to start position.
  23650. delete this._savedSelection; // new mouse position overrides old selection
  23651. if(e.target.tagName == "BODY"){
  23652. setTimeout(lang.hitch(this, "placeCursorAtEnd"), 0);
  23653. }
  23654. this.inherited(arguments);
  23655. }
  23656. },
  23657. onBeforeActivate: function(){
  23658. this._restoreSelection();
  23659. },
  23660. onBeforeDeactivate: function(e){
  23661. // summary:
  23662. // Called on IE right before focus is lost. Saves the selected range.
  23663. // tags:
  23664. // private
  23665. if(this.customUndo){
  23666. this.endEditing(true);
  23667. }
  23668. //in IE, the selection will be lost when other elements get focus,
  23669. //let's save focus before the editor is deactivated
  23670. if(e.target.tagName != "BODY"){
  23671. this._saveSelection();
  23672. }
  23673. //console.log('onBeforeDeactivate',this);
  23674. },
  23675. /* beginning of custom undo/redo support */
  23676. // customUndo: Boolean
  23677. // Whether we shall use custom undo/redo support instead of the native
  23678. // browser support. By default, we now use custom undo. It works better
  23679. // than native browser support and provides a consistent behavior across
  23680. // browsers with a minimal performance hit. We already had the hit on
  23681. // the slowest browser, IE, anyway.
  23682. customUndo: true,
  23683. // editActionInterval: Integer
  23684. // When using customUndo, not every keystroke will be saved as a step.
  23685. // Instead typing (including delete) will be grouped together: after
  23686. // a user stops typing for editActionInterval seconds, a step will be
  23687. // saved; if a user resume typing within editActionInterval seconds,
  23688. // the timeout will be restarted. By default, editActionInterval is 3
  23689. // seconds.
  23690. editActionInterval: 3,
  23691. beginEditing: function(cmd){
  23692. // summary:
  23693. // Called to note that the user has started typing alphanumeric characters, if it's not already noted.
  23694. // Deals with saving undo; see editActionInterval parameter.
  23695. // tags:
  23696. // private
  23697. if(!this._inEditing){
  23698. this._inEditing=true;
  23699. this._beginEditing(cmd);
  23700. }
  23701. if(this.editActionInterval>0){
  23702. if(this._editTimer){
  23703. clearTimeout(this._editTimer);
  23704. }
  23705. this._editTimer = setTimeout(lang.hitch(this, this.endEditing), this._editInterval);
  23706. }
  23707. },
  23708. // TODO: declaring these in the prototype is meaningless, just create in the constructor/postCreate
  23709. _steps:[],
  23710. _undoedSteps:[],
  23711. execCommand: function(cmd){
  23712. // summary:
  23713. // Main handler for executing any commands to the editor, like paste, bold, etc.
  23714. // Called by plugins, but not meant to be called by end users.
  23715. // tags:
  23716. // protected
  23717. if(this.customUndo && (cmd == 'undo' || cmd == 'redo')){
  23718. return this[cmd]();
  23719. }else{
  23720. if(this.customUndo){
  23721. this.endEditing();
  23722. this._beginEditing();
  23723. }
  23724. var r = this.inherited(arguments);
  23725. if(this.customUndo){
  23726. this._endEditing();
  23727. }
  23728. return r;
  23729. }
  23730. },
  23731. _pasteImpl: function(){
  23732. // summary:
  23733. // Over-ride of paste command control to make execCommand cleaner
  23734. // tags:
  23735. // Protected
  23736. return this._clipboardCommand("paste");
  23737. },
  23738. _cutImpl: function(){
  23739. // summary:
  23740. // Over-ride of cut command control to make execCommand cleaner
  23741. // tags:
  23742. // Protected
  23743. return this._clipboardCommand("cut");
  23744. },
  23745. _copyImpl: function(){
  23746. // summary:
  23747. // Over-ride of copy command control to make execCommand cleaner
  23748. // tags:
  23749. // Protected
  23750. return this._clipboardCommand("copy");
  23751. },
  23752. _clipboardCommand: function(cmd){
  23753. // summary:
  23754. // Function to handle processing clipboard commands (or at least try to).
  23755. // tags:
  23756. // Private
  23757. var r;
  23758. try{
  23759. // Try to exec the superclass exec-command and see if it works.
  23760. r = this.document.execCommand(cmd, false, null);
  23761. if(has("webkit") && !r){ //see #4598: webkit does not guarantee clipboard support from js
  23762. throw { code: 1011 }; // throw an object like Mozilla's error
  23763. }
  23764. }catch(e){
  23765. //TODO: when else might we get an exception? Do we need the Mozilla test below?
  23766. if(e.code == 1011 /* Mozilla: service denied */){
  23767. // Warn user of platform limitation. Cannot programmatically access clipboard. See ticket #4136
  23768. var sub = string.substitute,
  23769. accel = {cut:'X', copy:'C', paste:'V'};
  23770. alert(sub(this.commands.systemShortcut,
  23771. [this.commands[cmd], sub(this.commands[has("mac") ? 'appleKey' : 'ctrlKey'], [accel[cmd]])]));
  23772. }
  23773. r = false;
  23774. }
  23775. return r;
  23776. },
  23777. queryCommandEnabled: function(cmd){
  23778. // summary:
  23779. // Returns true if specified editor command is enabled.
  23780. // Used by the plugins to know when to highlight/not highlight buttons.
  23781. // tags:
  23782. // protected
  23783. if(this.customUndo && (cmd == 'undo' || cmd == 'redo')){
  23784. return cmd == 'undo' ? (this._steps.length > 1) : (this._undoedSteps.length > 0);
  23785. }else{
  23786. return this.inherited(arguments);
  23787. }
  23788. },
  23789. _moveToBookmark: function(b){
  23790. // summary:
  23791. // Selects the text specified in bookmark b
  23792. // tags:
  23793. // private
  23794. var bookmark = b.mark;
  23795. var mark = b.mark;
  23796. var col = b.isCollapsed;
  23797. var r, sNode, eNode, sel;
  23798. if(mark){
  23799. if(has("ie") < 9){
  23800. if(lang.isArray(mark)){
  23801. //IE CONTROL, have to use the native bookmark.
  23802. bookmark = [];
  23803. array.forEach(mark,function(n){
  23804. bookmark.push(rangeapi.getNode(n,this.editNode));
  23805. },this);
  23806. win.withGlobal(this.window,'moveToBookmark',dijit,[{mark: bookmark, isCollapsed: col}]);
  23807. }else{
  23808. if(mark.startContainer && mark.endContainer){
  23809. // Use the pseudo WC3 range API. This works better for positions
  23810. // than the IE native bookmark code.
  23811. sel = rangeapi.getSelection(this.window);
  23812. if(sel && sel.removeAllRanges){
  23813. sel.removeAllRanges();
  23814. r = rangeapi.create(this.window);
  23815. sNode = rangeapi.getNode(mark.startContainer,this.editNode);
  23816. eNode = rangeapi.getNode(mark.endContainer,this.editNode);
  23817. if(sNode && eNode){
  23818. // Okay, we believe we found the position, so add it into the selection
  23819. // There are cases where it may not be found, particularly in undo/redo, when
  23820. // IE changes the underlying DOM on us (wraps text in a <p> tag or similar.
  23821. // So, in those cases, don't bother restoring selection.
  23822. r.setStart(sNode,mark.startOffset);
  23823. r.setEnd(eNode,mark.endOffset);
  23824. sel.addRange(r);
  23825. }
  23826. }
  23827. }
  23828. }
  23829. }else{//w3c range
  23830. sel = rangeapi.getSelection(this.window);
  23831. if(sel && sel.removeAllRanges){
  23832. sel.removeAllRanges();
  23833. r = rangeapi.create(this.window);
  23834. sNode = rangeapi.getNode(mark.startContainer,this.editNode);
  23835. eNode = rangeapi.getNode(mark.endContainer,this.editNode);
  23836. if(sNode && eNode){
  23837. // Okay, we believe we found the position, so add it into the selection
  23838. // There are cases where it may not be found, particularly in undo/redo, when
  23839. // formatting as been done and so on, so don't restore selection then.
  23840. r.setStart(sNode,mark.startOffset);
  23841. r.setEnd(eNode,mark.endOffset);
  23842. sel.addRange(r);
  23843. }
  23844. }
  23845. }
  23846. }
  23847. },
  23848. _changeToStep: function(from, to){
  23849. // summary:
  23850. // Reverts editor to "to" setting, from the undo stack.
  23851. // tags:
  23852. // private
  23853. this.setValue(to.text);
  23854. var b=to.bookmark;
  23855. if(!b){ return; }
  23856. this._moveToBookmark(b);
  23857. },
  23858. undo: function(){
  23859. // summary:
  23860. // Handler for editor undo (ex: ctrl-z) operation
  23861. // tags:
  23862. // private
  23863. //console.log('undo');
  23864. var ret = false;
  23865. if(!this._undoRedoActive){
  23866. this._undoRedoActive = true;
  23867. this.endEditing(true);
  23868. var s=this._steps.pop();
  23869. if(s && this._steps.length>0){
  23870. this.focus();
  23871. this._changeToStep(s,this._steps[this._steps.length-1]);
  23872. this._undoedSteps.push(s);
  23873. this.onDisplayChanged();
  23874. delete this._undoRedoActive;
  23875. ret = true;
  23876. }
  23877. delete this._undoRedoActive;
  23878. }
  23879. return ret;
  23880. },
  23881. redo: function(){
  23882. // summary:
  23883. // Handler for editor redo (ex: ctrl-y) operation
  23884. // tags:
  23885. // private
  23886. //console.log('redo');
  23887. var ret = false;
  23888. if(!this._undoRedoActive){
  23889. this._undoRedoActive = true;
  23890. this.endEditing(true);
  23891. var s=this._undoedSteps.pop();
  23892. if(s && this._steps.length>0){
  23893. this.focus();
  23894. this._changeToStep(this._steps[this._steps.length-1],s);
  23895. this._steps.push(s);
  23896. this.onDisplayChanged();
  23897. ret = true;
  23898. }
  23899. delete this._undoRedoActive;
  23900. }
  23901. return ret;
  23902. },
  23903. endEditing: function(ignore_caret){
  23904. // summary:
  23905. // Called to note that the user has stopped typing alphanumeric characters, if it's not already noted.
  23906. // Deals with saving undo; see editActionInterval parameter.
  23907. // tags:
  23908. // private
  23909. if(this._editTimer){
  23910. clearTimeout(this._editTimer);
  23911. }
  23912. if(this._inEditing){
  23913. this._endEditing(ignore_caret);
  23914. this._inEditing=false;
  23915. }
  23916. },
  23917. _getBookmark: function(){
  23918. // summary:
  23919. // Get the currently selected text
  23920. // tags:
  23921. // protected
  23922. var b=win.withGlobal(this.window,focusBase.getBookmark);
  23923. var tmp=[];
  23924. if(b && b.mark){
  23925. var mark = b.mark;
  23926. if(has("ie") < 9){
  23927. // Try to use the pseudo range API on IE for better accuracy.
  23928. var sel = rangeapi.getSelection(this.window);
  23929. if(!lang.isArray(mark)){
  23930. if(sel){
  23931. var range;
  23932. if(sel.rangeCount){
  23933. range = sel.getRangeAt(0);
  23934. }
  23935. if(range){
  23936. b.mark = range.cloneRange();
  23937. }else{
  23938. b.mark = win.withGlobal(this.window,focusBase.getBookmark);
  23939. }
  23940. }
  23941. }else{
  23942. // Control ranges (img, table, etc), handle differently.
  23943. array.forEach(b.mark,function(n){
  23944. tmp.push(rangeapi.getIndex(n,this.editNode).o);
  23945. },this);
  23946. b.mark = tmp;
  23947. }
  23948. }
  23949. try{
  23950. if(b.mark && b.mark.startContainer){
  23951. tmp=rangeapi.getIndex(b.mark.startContainer,this.editNode).o;
  23952. b.mark={startContainer:tmp,
  23953. startOffset:b.mark.startOffset,
  23954. endContainer:b.mark.endContainer===b.mark.startContainer?tmp:rangeapi.getIndex(b.mark.endContainer,this.editNode).o,
  23955. endOffset:b.mark.endOffset};
  23956. }
  23957. }catch(e){
  23958. b.mark = null;
  23959. }
  23960. }
  23961. return b;
  23962. },
  23963. _beginEditing: function(){
  23964. // summary:
  23965. // Called when the user starts typing alphanumeric characters.
  23966. // Deals with saving undo; see editActionInterval parameter.
  23967. // tags:
  23968. // private
  23969. if(this._steps.length === 0){
  23970. // You want to use the editor content without post filtering
  23971. // to make sure selection restores right for the 'initial' state.
  23972. // and undo is called. So not using this.value, as it was 'processed'
  23973. // and the line-up for selections may have been altered.
  23974. this._steps.push({'text':html.getChildrenHtml(this.editNode),'bookmark':this._getBookmark()});
  23975. }
  23976. },
  23977. _endEditing: function(){
  23978. // summary:
  23979. // Called when the user stops typing alphanumeric characters.
  23980. // Deals with saving undo; see editActionInterval parameter.
  23981. // tags:
  23982. // private
  23983. // Avoid filtering to make sure selections restore.
  23984. var v = html.getChildrenHtml(this.editNode);
  23985. this._undoedSteps=[];//clear undoed steps
  23986. this._steps.push({text: v, bookmark: this._getBookmark()});
  23987. },
  23988. onKeyDown: function(e){
  23989. // summary:
  23990. // Handler for onkeydown event.
  23991. // tags:
  23992. // private
  23993. //We need to save selection if the user TAB away from this editor
  23994. //no need to call _saveSelection for IE, as that will be taken care of in onBeforeDeactivate
  23995. if(!has("ie") && !this.iframe && e.keyCode == keys.TAB && !this.tabIndent){
  23996. this._saveSelection();
  23997. }
  23998. if(!this.customUndo){
  23999. this.inherited(arguments);
  24000. return;
  24001. }
  24002. var k = e.keyCode;
  24003. if(e.ctrlKey && !e.altKey){//undo and redo only if the special right Alt + z/y are not pressed #5892
  24004. if(k == 90 || k == 122){ //z
  24005. event.stop(e);
  24006. this.undo();
  24007. return;
  24008. }else if(k == 89 || k == 121){ //y
  24009. event.stop(e);
  24010. this.redo();
  24011. return;
  24012. }
  24013. }
  24014. this.inherited(arguments);
  24015. switch(k){
  24016. case keys.ENTER:
  24017. case keys.BACKSPACE:
  24018. case keys.DELETE:
  24019. this.beginEditing();
  24020. break;
  24021. case 88: //x
  24022. case 86: //v
  24023. if(e.ctrlKey && !e.altKey && !e.metaKey){
  24024. this.endEditing();//end current typing step if any
  24025. if(e.keyCode == 88){
  24026. this.beginEditing('cut');
  24027. //use timeout to trigger after the cut is complete
  24028. setTimeout(lang.hitch(this, this.endEditing), 1);
  24029. }else{
  24030. this.beginEditing('paste');
  24031. //use timeout to trigger after the paste is complete
  24032. setTimeout(lang.hitch(this, this.endEditing), 1);
  24033. }
  24034. break;
  24035. }
  24036. //pass through
  24037. default:
  24038. if(!e.ctrlKey && !e.altKey && !e.metaKey && (e.keyCode<keys.F1 || e.keyCode>keys.F15)){
  24039. this.beginEditing();
  24040. break;
  24041. }
  24042. //pass through
  24043. case keys.ALT:
  24044. this.endEditing();
  24045. break;
  24046. case keys.UP_ARROW:
  24047. case keys.DOWN_ARROW:
  24048. case keys.LEFT_ARROW:
  24049. case keys.RIGHT_ARROW:
  24050. case keys.HOME:
  24051. case keys.END:
  24052. case keys.PAGE_UP:
  24053. case keys.PAGE_DOWN:
  24054. this.endEditing(true);
  24055. break;
  24056. //maybe ctrl+backspace/delete, so don't endEditing when ctrl is pressed
  24057. case keys.CTRL:
  24058. case keys.SHIFT:
  24059. case keys.TAB:
  24060. break;
  24061. }
  24062. },
  24063. _onBlur: function(){
  24064. // summary:
  24065. // Called from focus manager when focus has moved away from this editor
  24066. // tags:
  24067. // protected
  24068. //this._saveSelection();
  24069. this.inherited(arguments);
  24070. this.endEditing(true);
  24071. },
  24072. _saveSelection: function(){
  24073. // summary:
  24074. // Save the currently selected text in _savedSelection attribute
  24075. // tags:
  24076. // private
  24077. try{
  24078. this._savedSelection=this._getBookmark();
  24079. }catch(e){ /* Squelch any errors that occur if selection save occurs due to being hidden simultaneously. */}
  24080. },
  24081. _restoreSelection: function(){
  24082. // summary:
  24083. // Re-select the text specified in _savedSelection attribute;
  24084. // see _saveSelection().
  24085. // tags:
  24086. // private
  24087. if(this._savedSelection){
  24088. // Clear off cursor to start, we're deliberately going to a selection.
  24089. delete this._cursorToStart;
  24090. // only restore the selection if the current range is collapsed
  24091. // if not collapsed, then it means the editor does not lose
  24092. // selection and there is no need to restore it
  24093. if(win.withGlobal(this.window,'isCollapsed',dijit)){
  24094. this._moveToBookmark(this._savedSelection);
  24095. }
  24096. delete this._savedSelection;
  24097. }
  24098. },
  24099. onClick: function(){
  24100. // summary:
  24101. // Handler for when editor is clicked
  24102. // tags:
  24103. // protected
  24104. this.endEditing(true);
  24105. this.inherited(arguments);
  24106. },
  24107. replaceValue: function(/*String*/ html){
  24108. // summary:
  24109. // over-ride of replaceValue to support custom undo and stack maintenance.
  24110. // tags:
  24111. // protected
  24112. if(!this.customUndo){
  24113. this.inherited(arguments);
  24114. }else{
  24115. if(this.isClosed){
  24116. this.setValue(html);
  24117. }else{
  24118. this.beginEditing();
  24119. if(!html){
  24120. html = "&#160;"; // &nbsp;
  24121. }
  24122. this.setValue(html);
  24123. this.endEditing();
  24124. }
  24125. }
  24126. },
  24127. _setDisabledAttr: function(/*Boolean*/ value){
  24128. var disableFunc = lang.hitch(this, function(){
  24129. if((!this.disabled && value) || (!this._buttonEnabledPlugins && value)){
  24130. // Disable editor: disable all enabled buttons and remember that list
  24131. array.forEach(this._plugins, function(p){
  24132. p.set("disabled", true);
  24133. });
  24134. }else if(this.disabled && !value){
  24135. // Restore plugins to being active.
  24136. array.forEach(this._plugins, function(p){
  24137. p.set("disabled", false);
  24138. });
  24139. }
  24140. });
  24141. this.setValueDeferred.addCallback(disableFunc);
  24142. this.inherited(arguments);
  24143. },
  24144. _setStateClass: function(){
  24145. try{
  24146. this.inherited(arguments);
  24147. // Let theme set the editor's text color based on editor enabled/disabled state.
  24148. // We need to jump through hoops because the main document (where the theme CSS is)
  24149. // is separate from the iframe's document.
  24150. if(this.document && this.document.body){
  24151. domStyle.set(this.document.body, "color", domStyle.get(this.iframe, "color"));
  24152. }
  24153. }catch(e){ /* Squelch any errors caused by focus change if hidden during a state change */}
  24154. }
  24155. });
  24156. // Register the "default plugins", ie, the built-in editor commands
  24157. function simplePluginFactory(args){
  24158. return new _Plugin({ command: args.name });
  24159. }
  24160. function togglePluginFactory(args){
  24161. return new _Plugin({ buttonClass: ToggleButton, command: args.name });
  24162. }
  24163. lang.mixin(_Plugin.registry, {
  24164. "undo": simplePluginFactory,
  24165. "redo": simplePluginFactory,
  24166. "cut": simplePluginFactory,
  24167. "copy": simplePluginFactory,
  24168. "paste": simplePluginFactory,
  24169. "insertOrderedList": simplePluginFactory,
  24170. "insertUnorderedList": simplePluginFactory,
  24171. "indent": simplePluginFactory,
  24172. "outdent": simplePluginFactory,
  24173. "justifyCenter": simplePluginFactory,
  24174. "justifyFull": simplePluginFactory,
  24175. "justifyLeft": simplePluginFactory,
  24176. "justifyRight": simplePluginFactory,
  24177. "delete": simplePluginFactory,
  24178. "selectAll": simplePluginFactory,
  24179. "removeFormat": simplePluginFactory,
  24180. "unlink": simplePluginFactory,
  24181. "insertHorizontalRule": simplePluginFactory,
  24182. "bold": togglePluginFactory,
  24183. "italic": togglePluginFactory,
  24184. "underline": togglePluginFactory,
  24185. "strikethrough": togglePluginFactory,
  24186. "subscript": togglePluginFactory,
  24187. "superscript": togglePluginFactory,
  24188. "|": function(){
  24189. return new _Plugin({ button: new ToolbarSeparator(), setEditor: function(editor){this.editor = editor;}});
  24190. }
  24191. });
  24192. return Editor;
  24193. });
  24194. },
  24195. 'dojox/grid/cells/dijit':function(){
  24196. define("dojox/grid/cells/dijit", [
  24197. "dojo/_base/kernel",
  24198. "../../main",
  24199. "dojo/_base/declare",
  24200. "dojo/_base/array",
  24201. "dojo/_base/lang",
  24202. "dojo/_base/json",
  24203. "dojo/_base/connect",
  24204. "dojo/_base/sniff",
  24205. "dojo/dom",
  24206. "dojo/dom-attr",
  24207. "dojo/dom-construct",
  24208. "dojo/dom-geometry",
  24209. "dojo/data/ItemFileReadStore",
  24210. "dijit/form/DateTextBox",
  24211. "dijit/form/TimeTextBox",
  24212. "dijit/form/ComboBox",
  24213. "dijit/form/CheckBox",
  24214. "dijit/form/TextBox",
  24215. "dijit/form/NumberSpinner",
  24216. "dijit/form/NumberTextBox",
  24217. "dijit/form/CurrencyTextBox",
  24218. "dijit/form/HorizontalSlider",
  24219. "dijit/Editor",
  24220. "../util",
  24221. "./_base"
  24222. ], function(dojo, dojox, declare, array, lang, json, connect, has, dom, domAttr, domConstruct,
  24223. domGeometry, ItemFileReadStore, DateTextBox, TimeTextBox, ComboBox, CheckBox, TextBox,
  24224. NumberSpinner, NumberTextBox, CurrencyTextBox, HorizontalSlider, Editor, util, BaseCell){
  24225. // TODO: shouldn't it be the test file's job to require these modules,
  24226. // if it is using them? Most of these modules aren't referenced by this file.
  24227. var _Widget = declare("dojox.grid.cells._Widget", BaseCell, {
  24228. widgetClass: TextBox,
  24229. constructor: function(inCell){
  24230. this.widget = null;
  24231. if(typeof this.widgetClass == "string"){
  24232. dojo.deprecated("Passing a string to widgetClass is deprecated", "pass the widget class object instead", "2.0");
  24233. this.widgetClass = lang.getObject(this.widgetClass);
  24234. }
  24235. },
  24236. formatEditing: function(inDatum, inRowIndex){
  24237. this.needFormatNode(inDatum, inRowIndex);
  24238. return "<div></div>";
  24239. },
  24240. getValue: function(inRowIndex){
  24241. return this.widget.get('value');
  24242. },
  24243. _unescapeHTML: function(value){
  24244. return (value && value.replace && this.grid.escapeHTMLInData) ?
  24245. value.replace(/&lt;/g, '<').replace(/&amp;/g, '&') : value;
  24246. },
  24247. setValue: function(inRowIndex, inValue){
  24248. if(this.widget&&this.widget.set){
  24249. inValue = this._unescapeHTML(inValue);
  24250. //Look for lazy-loading editor and handle it via its deferred.
  24251. if(this.widget.onLoadDeferred){
  24252. var self = this;
  24253. this.widget.onLoadDeferred.addCallback(function(){
  24254. self.widget.set("value",inValue===null?"":inValue);
  24255. });
  24256. }else{
  24257. this.widget.set("value", inValue);
  24258. }
  24259. }else{
  24260. this.inherited(arguments);
  24261. }
  24262. },
  24263. getWidgetProps: function(inDatum){
  24264. return lang.mixin(
  24265. {
  24266. dir: this.dir,
  24267. lang: this.lang
  24268. },
  24269. this.widgetProps||{},
  24270. {
  24271. constraints: lang.mixin({}, this.constraint) || {}, //TODO: really just for ValidationTextBoxes
  24272. value: this._unescapeHTML(inDatum)
  24273. }
  24274. );
  24275. },
  24276. createWidget: function(inNode, inDatum, inRowIndex){
  24277. return new this.widgetClass(this.getWidgetProps(inDatum), inNode);
  24278. },
  24279. attachWidget: function(inNode, inDatum, inRowIndex){
  24280. inNode.appendChild(this.widget.domNode);
  24281. this.setValue(inRowIndex, inDatum);
  24282. },
  24283. formatNode: function(inNode, inDatum, inRowIndex){
  24284. if(!this.widgetClass){
  24285. return inDatum;
  24286. }
  24287. if(!this.widget){
  24288. this.widget = this.createWidget.apply(this, arguments);
  24289. }else{
  24290. this.attachWidget.apply(this, arguments);
  24291. }
  24292. this.sizeWidget.apply(this, arguments);
  24293. this.grid.views.renormalizeRow(inRowIndex);
  24294. this.grid.scroller.rowHeightChanged(inRowIndex, true/*fix #11101*/);
  24295. this.focus();
  24296. return undefined;
  24297. },
  24298. sizeWidget: function(inNode, inDatum, inRowIndex){
  24299. var
  24300. p = this.getNode(inRowIndex),
  24301. box = dojo.contentBox(p);
  24302. dojo.marginBox(this.widget.domNode, {w: box.w});
  24303. },
  24304. focus: function(inRowIndex, inNode){
  24305. if(this.widget){
  24306. setTimeout(lang.hitch(this.widget, function(){
  24307. util.fire(this, "focus");
  24308. }), 0);
  24309. }
  24310. },
  24311. _finish: function(inRowIndex){
  24312. this.inherited(arguments);
  24313. util.removeNode(this.widget.domNode);
  24314. if(has("ie")){
  24315. dom.setSelectable(this.widget.domNode, true);
  24316. }
  24317. }
  24318. });
  24319. _Widget.markupFactory = function(node, cell){
  24320. BaseCell.markupFactory(node, cell);
  24321. var widgetProps = lang.trim(domAttr.get(node, "widgetProps")||"");
  24322. var constraint = lang.trim(domAttr.get(node, "constraint")||"");
  24323. var widgetClass = lang.trim(domAttr.get(node, "widgetClass")||"");
  24324. if(widgetProps){
  24325. cell.widgetProps = json.fromJson(widgetProps);
  24326. }
  24327. if(constraint){
  24328. cell.constraint = json.fromJson(constraint);
  24329. }
  24330. if(widgetClass){
  24331. cell.widgetClass = lang.getObject(widgetClass);
  24332. }
  24333. };
  24334. var ComboBox = declare("dojox.grid.cells.ComboBox", _Widget, {
  24335. widgetClass: ComboBox,
  24336. getWidgetProps: function(inDatum){
  24337. var items=[];
  24338. array.forEach(this.options, function(o){
  24339. items.push({name: o, value: o});
  24340. });
  24341. var store = new ItemFileReadStore({data: {identifier:"name", items: items}});
  24342. return lang.mixin({}, this.widgetProps||{}, {
  24343. value: inDatum,
  24344. store: store
  24345. });
  24346. },
  24347. getValue: function(){
  24348. var e = this.widget;
  24349. // make sure to apply the displayed value
  24350. e.set('displayedValue', e.get('displayedValue'));
  24351. return e.get('value');
  24352. }
  24353. });
  24354. ComboBox.markupFactory = function(node, cell){
  24355. _Widget.markupFactory(node, cell);
  24356. var options = lang.trim(domAttr.get(node, "options")||"");
  24357. if(options){
  24358. var o = options.split(',');
  24359. if(o[0] != options){
  24360. cell.options = o;
  24361. }
  24362. }
  24363. };
  24364. var DateTextBox = declare("dojox.grid.cells.DateTextBox", _Widget, {
  24365. widgetClass: DateTextBox,
  24366. setValue: function(inRowIndex, inValue){
  24367. if(this.widget){
  24368. this.widget.set('value', new Date(inValue));
  24369. }else{
  24370. this.inherited(arguments);
  24371. }
  24372. },
  24373. getWidgetProps: function(inDatum){
  24374. return lang.mixin(this.inherited(arguments), {
  24375. value: new Date(inDatum)
  24376. });
  24377. }
  24378. });
  24379. DateTextBox.markupFactory = function(node, cell){
  24380. _Widget.markupFactory(node, cell);
  24381. };
  24382. var CheckBox = declare("dojox.grid.cells.CheckBox", _Widget, {
  24383. widgetClass: CheckBox,
  24384. getValue: function(){
  24385. return this.widget.checked;
  24386. },
  24387. setValue: function(inRowIndex, inValue){
  24388. if(this.widget&&this.widget.attributeMap.checked){
  24389. this.widget.set("checked", inValue);
  24390. }else{
  24391. this.inherited(arguments);
  24392. }
  24393. },
  24394. sizeWidget: function(inNode, inDatum, inRowIndex){
  24395. return;
  24396. }
  24397. });
  24398. CheckBox.markupFactory = function(node, cell){
  24399. _Widget.markupFactory(node, cell);
  24400. };
  24401. var Editor = declare("dojox.grid.cells.Editor", _Widget, {
  24402. widgetClass: Editor,
  24403. getWidgetProps: function(inDatum){
  24404. return lang.mixin({}, this.widgetProps||{}, {
  24405. height: this.widgetHeight || "100px"
  24406. });
  24407. },
  24408. createWidget: function(inNode, inDatum, inRowIndex){
  24409. // widget needs its value set after creation
  24410. var widget = new this.widgetClass(this.getWidgetProps(inDatum), inNode);
  24411. // use onLoadDeferred because onLoad may have already fired
  24412. widget.onLoadDeferred.then(lang.hitch(this, 'populateEditor'));
  24413. return widget;
  24414. },
  24415. formatNode: function(inNode, inDatum, inRowIndex){
  24416. this.content = inDatum;
  24417. this.inherited(arguments);
  24418. if(has("mozilla")){
  24419. // FIXME: seem to need to reopen the editor and display the toolbar
  24420. var e = this.widget;
  24421. e.open();
  24422. if(this.widgetToolbar){
  24423. domConstruct.place(e.toolbar.domNode, e.editingArea, "before");
  24424. }
  24425. }
  24426. },
  24427. populateEditor: function(){
  24428. this.widget.set('value', this.content);
  24429. this.widget.placeCursorAtEnd();
  24430. }
  24431. });
  24432. Editor.markupFactory = function(node, cell){
  24433. _Widget.markupFactory(node, cell);
  24434. var h = lang.trim(domAttr.get(node, "widgetHeight")||"");
  24435. if(h){
  24436. if((h != "auto")&&(h.substr(-2) != "em")){
  24437. h = parseInt(h, 10)+"px";
  24438. }
  24439. cell.widgetHeight = h;
  24440. }
  24441. };
  24442. return dojox.grid.cells.dijit;
  24443. });
  24444. },
  24445. 'dojox/form/uploader/plugins/HTML5':function(){
  24446. define("dojox/form/uploader/plugins/HTML5", [
  24447. "dojo/_base/declare",
  24448. "dojo/_base/lang",
  24449. "dojo/_base/array",
  24450. "dojo"
  24451. ],function(declare, lang, array, dojo){
  24452. var pluginsHTML5 = declare("dojox.form.uploader.plugins.HTML5", [], {
  24453. //
  24454. // Version: 1.6
  24455. //
  24456. // summary:
  24457. // A plugin for dojox.form.Uploader that adds HTML5 multiple-file upload capabilities and
  24458. // progress events.
  24459. //
  24460. // description:
  24461. // Add this plugin to have HTML5 capabilities in the Uploader. Note that it does not add
  24462. // these capabilities to browsers that don't support them. For IE or older browsers, add
  24463. // additional plugins: IFrame or Flash.
  24464. //
  24465. errMsg:"Error uploading files. Try checking permissions",
  24466. // Overwrites "form" and could possibly be overwritten again by iframe or flash plugin.
  24467. uploadType:"html5",
  24468. postCreate: function(){
  24469. this.connectForm();
  24470. this.inherited(arguments);
  24471. if(this.uploadOnSelect){
  24472. this.connect(this, "onChange", function(data){
  24473. this.upload(data[0]);
  24474. });
  24475. }
  24476. },
  24477. _drop: function(e){
  24478. dojo.stopEvent(e);
  24479. var dt = e.dataTransfer;
  24480. this._files = dt.files;
  24481. this.onChange(this.getFileList());
  24482. },
  24483. /*************************
  24484. * Public Methods *
  24485. *************************/
  24486. upload: function(/*Object ? */formData){
  24487. // summary:
  24488. // See: dojox.form.Uploader.upload
  24489. //
  24490. this.onBegin(this.getFileList());
  24491. if(this.supports("FormData")){
  24492. this.uploadWithFormData(formData);
  24493. }else if(this.supports("sendAsBinary")){
  24494. this.sendAsBinary(formData);
  24495. }
  24496. },
  24497. addDropTarget: function(node, /*Boolean?*/onlyConnectDrop){
  24498. // summary:
  24499. // Add a dom node which will act as the drop target area so user
  24500. // can drop files to this node.
  24501. // description:
  24502. // If onlyConnectDrop is true, dragenter/dragover/dragleave events
  24503. // won't be connected to dojo.stopEvent, and they need to be
  24504. // canceled by user code to allow DnD files to happen.
  24505. // This API is only available in HTML5 plugin (only HTML5 allows
  24506. // DnD files).
  24507. if(!onlyConnectDrop){
  24508. this.connect(node, 'dragenter', dojo.stopEvent);
  24509. this.connect(node, 'dragover', dojo.stopEvent);
  24510. this.connect(node, 'dragleave', dojo.stopEvent);
  24511. }
  24512. this.connect(node, 'drop', '_drop');
  24513. },
  24514. sendAsBinary: function(/* Object */data){
  24515. // summary:
  24516. // Used primarily in FF < 4.0. Sends files and form object as binary data, written to
  24517. // still enable use of $_FILES in PHP (or equivalent).
  24518. // tags:
  24519. // private
  24520. //
  24521. if(!this.getUrl()){
  24522. console.error("No upload url found.", this); return;
  24523. }
  24524. // The date/number doesn't matter but amount of dashes do. The actual boundary
  24525. // will have two more dashes than this one which is used in the header.
  24526. var boundary = "---------------------------" + (new Date).getTime();
  24527. var xhr = this.createXhr();
  24528. xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
  24529. // finally send the request as binary data
  24530. // still accessed as $_FILES
  24531. var msg = this._buildRequestBody(data, boundary);
  24532. if(!msg){
  24533. this.onError(this.errMsg);
  24534. }else{
  24535. console.log("msg:", msg)
  24536. console.log("xhr:", xhr)
  24537. xhr.sendAsBinary(msg);
  24538. }
  24539. },
  24540. uploadWithFormData: function(/* Object */data){
  24541. // summary
  24542. // Used with WebKit and Firefox 4+
  24543. // Upload files using the much friendlier FormData browser object.
  24544. // tags:
  24545. // private
  24546. //
  24547. if(!this.getUrl()){
  24548. console.error("No upload url found.", this); return;
  24549. }
  24550. var fd = new FormData();
  24551. array.forEach(this._files, function(f, i){
  24552. fd.append(this.name+"s[]", f);
  24553. }, this);
  24554. if(data){
  24555. for(var nm in data){
  24556. fd.append(nm, data[nm]);
  24557. }
  24558. }
  24559. var xhr = this.createXhr();
  24560. xhr.send(fd);
  24561. },
  24562. _xhrProgress: function(evt){
  24563. if(evt.lengthComputable){
  24564. var o = {
  24565. bytesLoaded:evt.loaded,
  24566. bytesTotal:evt.total,
  24567. type:evt.type,
  24568. timeStamp:evt.timeStamp
  24569. };
  24570. if(evt.type == "load"){
  24571. // 100%
  24572. o.percent = "100%",
  24573. o.decimal = 1;
  24574. }else{
  24575. o.decimal = evt.loaded / evt.total;
  24576. o.percent = Math.ceil((evt.loaded / evt.total)*100)+"%";
  24577. }
  24578. this.onProgress(o);
  24579. }
  24580. },
  24581. createXhr: function(){
  24582. var xhr = new XMLHttpRequest();
  24583. var timer;
  24584. xhr.upload.addEventListener("progress", lang.hitch(this, "_xhrProgress"), false);
  24585. xhr.addEventListener("load", lang.hitch(this, "_xhrProgress"), false);
  24586. xhr.addEventListener("error", lang.hitch(this, function(evt){
  24587. this.onError(evt);
  24588. clearInterval(timer);
  24589. }), false);
  24590. xhr.addEventListener("abort", lang.hitch(this, function(evt){
  24591. this.onAbort(evt);
  24592. clearInterval(timer);
  24593. }), false);
  24594. xhr.onreadystatechange = lang.hitch(this, function(){
  24595. if(xhr.readyState === 4){
  24596. // console.info("COMPLETE")
  24597. clearInterval(timer);
  24598. this.onComplete(JSON.parse(xhr.responseText.replace(/^\{\}&&/,'')));
  24599. }
  24600. });
  24601. xhr.open("POST", this.getUrl());
  24602. timer = setInterval(lang.hitch(this, function(){
  24603. try{
  24604. if(typeof(xhr.statusText)){} // accessing this error throws an error. Awesomeness.
  24605. }catch(e){
  24606. //this.onError("Error uploading file."); // not always an error.
  24607. clearInterval(timer);
  24608. }
  24609. }),250);
  24610. return xhr;
  24611. },
  24612. _buildRequestBody : function(data, boundary){
  24613. var EOL = "\r\n";
  24614. var part = "";
  24615. boundary = "--" + boundary;
  24616. var filesInError = [], files = this._files;
  24617. array.forEach(files, function(f, i){
  24618. var fieldName = this.name+"s[]";//+i;
  24619. var fileName = f.fileName;
  24620. var binary;
  24621. try{
  24622. binary = f.getAsBinary() + EOL;
  24623. part += boundary + EOL;
  24624. part += 'Content-Disposition: form-data; ';
  24625. part += 'name="' + fieldName + '"; ';
  24626. part += 'filename="'+ fileName + '"' + EOL;
  24627. part += "Content-Type: " + this.getMimeType() + EOL + EOL;
  24628. part += binary;
  24629. }catch(e){
  24630. filesInError.push({index:i, name:fileName});
  24631. }
  24632. }, this);
  24633. if(filesInError.length){
  24634. if(filesInError.length >= files.length){
  24635. // all files were bad. Nothing to upload.
  24636. this.onError({
  24637. message:this.errMsg,
  24638. filesInError:filesInError
  24639. });
  24640. part = false;
  24641. }
  24642. }
  24643. if(!part) return false;
  24644. if(data){
  24645. for(var nm in data){
  24646. part += boundary + EOL;
  24647. part += 'Content-Disposition: form-data; ';
  24648. part += 'name="' + nm + '"' + EOL + EOL;
  24649. part += data[nm] + EOL;
  24650. }
  24651. }
  24652. part += boundary + "--" + EOL;
  24653. return part;
  24654. }
  24655. });
  24656. dojox.form.addUploaderPlugin(pluginsHTML5);
  24657. return pluginsHTML5;
  24658. });
  24659. },
  24660. 'dojox/uuid/generateRandomUuid':function(){
  24661. define("dojox/uuid/generateRandomUuid", ['./_base'], function(){
  24662. dojox.uuid.generateRandomUuid = function(){
  24663. // summary:
  24664. // This function generates random UUIDs, meaning "version 4" UUIDs.
  24665. // description:
  24666. // A typical generated value would be something like this:
  24667. // "3b12f1df-5232-4804-897e-917bf397618a"
  24668. //
  24669. // For more information about random UUIDs, see sections 4.4 and
  24670. // 4.5 of RFC 4122: http://tools.ietf.org/html/rfc4122#section-4.4
  24671. //
  24672. // This generator function is designed to be small and fast,
  24673. // but not necessarily good.
  24674. //
  24675. // Small: This generator has a small footprint. Once comments are
  24676. // stripped, it's only about 25 lines of code, and it doesn't
  24677. // dojo.require() any other modules.
  24678. //
  24679. // Fast: This generator can generate lots of new UUIDs fairly quickly
  24680. // (at least, more quickly than the other dojo UUID generators).
  24681. //
  24682. // Not necessarily good: We use Math.random() as our source
  24683. // of randomness, which may or may not provide much randomness.
  24684. // examples:
  24685. // var string = dojox.uuid.generateRandomUuid();
  24686. var HEX_RADIX = 16;
  24687. function _generateRandomEightCharacterHexString(){
  24688. // Make random32bitNumber be a randomly generated floating point number
  24689. // between 0 and (4,294,967,296 - 1), inclusive.
  24690. var random32bitNumber = Math.floor( (Math.random() % 1) * Math.pow(2, 32) );
  24691. var eightCharacterHexString = random32bitNumber.toString(HEX_RADIX);
  24692. while(eightCharacterHexString.length < 8){
  24693. eightCharacterHexString = "0" + eightCharacterHexString;
  24694. }
  24695. return eightCharacterHexString; // for example: "3B12F1DF"
  24696. }
  24697. var hyphen = "-";
  24698. var versionCodeForRandomlyGeneratedUuids = "4"; // 8 == binary2hex("0100")
  24699. var variantCodeForDCEUuids = "8"; // 8 == binary2hex("1000")
  24700. var a = _generateRandomEightCharacterHexString();
  24701. var b = _generateRandomEightCharacterHexString();
  24702. b = b.substring(0, 4) + hyphen + versionCodeForRandomlyGeneratedUuids + b.substring(5, 8);
  24703. var c = _generateRandomEightCharacterHexString();
  24704. c = variantCodeForDCEUuids + c.substring(1, 4) + hyphen + c.substring(4, 8);
  24705. var d = _generateRandomEightCharacterHexString();
  24706. var returnValue = a + hyphen + b + hyphen + c + d;
  24707. returnValue = returnValue.toLowerCase();
  24708. return returnValue; // String
  24709. };
  24710. return dojox.uuid.generateRandomUuid;
  24711. });
  24712. },
  24713. 'dijit/Toolbar':function(){
  24714. define("dijit/Toolbar", [
  24715. "require",
  24716. "dojo/_base/declare", // declare
  24717. "dojo/_base/kernel",
  24718. "dojo/keys", // keys.LEFT_ARROW keys.RIGHT_ARROW
  24719. "dojo/ready",
  24720. "./_Widget",
  24721. "./_KeyNavContainer",
  24722. "./_TemplatedMixin"
  24723. ], function(require, declare, kernel, keys, ready, _Widget, _KeyNavContainer, _TemplatedMixin){
  24724. /*=====
  24725. var _Widget = dijit._Widget;
  24726. var _KeyNavContainer = dijit._KeyNavContainer;
  24727. var _TemplatedMixin = dijit._TemplatedMixin;
  24728. =====*/
  24729. // module:
  24730. // dijit/Toolbar
  24731. // summary:
  24732. // A Toolbar widget, used to hold things like `dijit.Editor` buttons
  24733. // Back compat w/1.6, remove for 2.0
  24734. if(!kernel.isAsync){
  24735. ready(0, function(){
  24736. var requires = ["dijit/ToolbarSeparator"];
  24737. require(requires); // use indirection so modules not rolled into a build
  24738. });
  24739. }
  24740. return declare("dijit.Toolbar", [_Widget, _TemplatedMixin, _KeyNavContainer], {
  24741. // summary:
  24742. // A Toolbar widget, used to hold things like `dijit.Editor` buttons
  24743. templateString:
  24744. '<div class="dijit" role="toolbar" tabIndex="${tabIndex}" data-dojo-attach-point="containerNode">' +
  24745. '</div>',
  24746. baseClass: "dijitToolbar",
  24747. postCreate: function(){
  24748. this.inherited(arguments);
  24749. this.connectKeyNavHandlers(
  24750. this.isLeftToRight() ? [keys.LEFT_ARROW] : [keys.RIGHT_ARROW],
  24751. this.isLeftToRight() ? [keys.RIGHT_ARROW] : [keys.LEFT_ARROW]
  24752. );
  24753. }
  24754. });
  24755. });
  24756. },
  24757. 'url:dojox/grid/resources/_Grid.html':"<div hidefocus=\"hidefocus\" role=\"grid\" dojoAttachEvent=\"onmouseout:_mouseOut\">\r\n\t<div class=\"dojoxGridMasterHeader\" dojoAttachPoint=\"viewsHeaderNode\" role=\"presentation\"></div>\r\n\t<div class=\"dojoxGridMasterView\" dojoAttachPoint=\"viewsNode\" role=\"presentation\"></div>\r\n\t<div class=\"dojoxGridMasterMessages\" style=\"display: none;\" dojoAttachPoint=\"messagesNode\"></div>\r\n\t<span dojoAttachPoint=\"lastFocusNode\" tabindex=\"0\"></span>\r\n</div>\r\n",
  24758. 'dojo/regexp':function(){
  24759. define("dojo/regexp", ["./_base/kernel", "./_base/lang"], function(dojo, lang) {
  24760. // module:
  24761. // dojo/regexp
  24762. // summary:
  24763. // TODOC
  24764. lang.getObject("regexp", true, dojo);
  24765. /*=====
  24766. dojo.regexp = {
  24767. // summary: Regular expressions and Builder resources
  24768. };
  24769. =====*/
  24770. dojo.regexp.escapeString = function(/*String*/str, /*String?*/except){
  24771. // summary:
  24772. // Adds escape sequences for special characters in regular expressions
  24773. // except:
  24774. // a String with special characters to be left unescaped
  24775. return str.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, function(ch){
  24776. if(except && except.indexOf(ch) != -1){
  24777. return ch;
  24778. }
  24779. return "\\" + ch;
  24780. }); // String
  24781. };
  24782. dojo.regexp.buildGroupRE = function(/*Object|Array*/arr, /*Function*/re, /*Boolean?*/nonCapture){
  24783. // summary:
  24784. // Builds a regular expression that groups subexpressions
  24785. // description:
  24786. // A utility function used by some of the RE generators. The
  24787. // subexpressions are constructed by the function, re, in the second
  24788. // parameter. re builds one subexpression for each elem in the array
  24789. // a, in the first parameter. Returns a string for a regular
  24790. // expression that groups all the subexpressions.
  24791. // arr:
  24792. // A single value or an array of values.
  24793. // re:
  24794. // A function. Takes one parameter and converts it to a regular
  24795. // expression.
  24796. // nonCapture:
  24797. // If true, uses non-capturing match, otherwise matches are retained
  24798. // by regular expression. Defaults to false
  24799. // case 1: a is a single value.
  24800. if(!(arr instanceof Array)){
  24801. return re(arr); // String
  24802. }
  24803. // case 2: a is an array
  24804. var b = [];
  24805. for(var i = 0; i < arr.length; i++){
  24806. // convert each elem to a RE
  24807. b.push(re(arr[i]));
  24808. }
  24809. // join the REs as alternatives in a RE group.
  24810. return dojo.regexp.group(b.join("|"), nonCapture); // String
  24811. };
  24812. dojo.regexp.group = function(/*String*/expression, /*Boolean?*/nonCapture){
  24813. // summary:
  24814. // adds group match to expression
  24815. // nonCapture:
  24816. // If true, uses non-capturing match, otherwise matches are retained
  24817. // by regular expression.
  24818. return "(" + (nonCapture ? "?:":"") + expression + ")"; // String
  24819. };
  24820. return dojo.regexp;
  24821. });
  24822. },
  24823. 'dijit/form/ComboBox':function(){
  24824. define("dijit/form/ComboBox", [
  24825. "dojo/_base/declare", // declare
  24826. "./ValidationTextBox",
  24827. "./ComboBoxMixin"
  24828. ], function(declare, ValidationTextBox, ComboBoxMixin){
  24829. /*=====
  24830. var ValidationTextBox = dijit.form.ValidationTextBox;
  24831. var ComboBoxMixin = dijit.form.ComboBoxMixin;
  24832. =====*/
  24833. // module:
  24834. // dijit/form/ComboBox
  24835. // summary:
  24836. // Auto-completing text box
  24837. return declare("dijit.form.ComboBox", [ValidationTextBox, ComboBoxMixin], {
  24838. // summary:
  24839. // Auto-completing text box
  24840. //
  24841. // description:
  24842. // The drop down box's values are populated from an class called
  24843. // a data provider, which returns a list of values based on the characters
  24844. // that the user has typed into the input box.
  24845. // If OPTION tags are used as the data provider via markup,
  24846. // then the OPTION tag's child text node is used as the widget value
  24847. // when selected. The OPTION tag's value attribute is ignored.
  24848. // To set the default value when using OPTION tags, specify the selected
  24849. // attribute on 1 of the child OPTION tags.
  24850. //
  24851. // Some of the options to the ComboBox are actually arguments to the data
  24852. // provider.
  24853. });
  24854. });
  24855. },
  24856. 'dojo/data/util/simpleFetch':function(){
  24857. define("dojo/data/util/simpleFetch", ["dojo/_base/lang", "dojo/_base/window", "./sorter"],
  24858. function(lang, winUtil, sorter) {
  24859. // module:
  24860. // dojo/data/util/simpleFetch
  24861. // summary:
  24862. // TODOC
  24863. var simpleFetch = lang.getObject("dojo.data.util.simpleFetch", true);
  24864. simpleFetch.fetch = function(/* Object? */ request){
  24865. // summary:
  24866. // The simpleFetch mixin is designed to serve as a set of function(s) that can
  24867. // be mixed into other datastore implementations to accelerate their development.
  24868. // The simpleFetch mixin should work well for any datastore that can respond to a _fetchItems()
  24869. // call by returning an array of all the found items that matched the query. The simpleFetch mixin
  24870. // is not designed to work for datastores that respond to a fetch() call by incrementally
  24871. // loading items, or sequentially loading partial batches of the result
  24872. // set. For datastores that mixin simpleFetch, simpleFetch
  24873. // implements a fetch method that automatically handles eight of the fetch()
  24874. // arguments -- onBegin, onItem, onComplete, onError, start, count, sort and scope
  24875. // The class mixing in simpleFetch should not implement fetch(),
  24876. // but should instead implement a _fetchItems() method. The _fetchItems()
  24877. // method takes three arguments, the keywordArgs object that was passed
  24878. // to fetch(), a callback function to be called when the result array is
  24879. // available, and an error callback to be called if something goes wrong.
  24880. // The _fetchItems() method should ignore any keywordArgs parameters for
  24881. // start, count, onBegin, onItem, onComplete, onError, sort, and scope.
  24882. // The _fetchItems() method needs to correctly handle any other keywordArgs
  24883. // parameters, including the query parameter and any optional parameters
  24884. // (such as includeChildren). The _fetchItems() method should create an array of
  24885. // result items and pass it to the fetchHandler along with the original request object
  24886. // -- or, the _fetchItems() method may, if it wants to, create an new request object
  24887. // with other specifics about the request that are specific to the datastore and pass
  24888. // that as the request object to the handler.
  24889. //
  24890. // For more information on this specific function, see dojo.data.api.Read.fetch()
  24891. request = request || {};
  24892. if(!request.store){
  24893. request.store = this;
  24894. }
  24895. var self = this;
  24896. var _errorHandler = function(errorData, requestObject){
  24897. if(requestObject.onError){
  24898. var scope = requestObject.scope || winUtil.global;
  24899. requestObject.onError.call(scope, errorData, requestObject);
  24900. }
  24901. };
  24902. var _fetchHandler = function(items, requestObject){
  24903. var oldAbortFunction = requestObject.abort || null;
  24904. var aborted = false;
  24905. var startIndex = requestObject.start?requestObject.start:0;
  24906. var endIndex = (requestObject.count && (requestObject.count !== Infinity))?(startIndex + requestObject.count):items.length;
  24907. requestObject.abort = function(){
  24908. aborted = true;
  24909. if(oldAbortFunction){
  24910. oldAbortFunction.call(requestObject);
  24911. }
  24912. };
  24913. var scope = requestObject.scope || winUtil.global;
  24914. if(!requestObject.store){
  24915. requestObject.store = self;
  24916. }
  24917. if(requestObject.onBegin){
  24918. requestObject.onBegin.call(scope, items.length, requestObject);
  24919. }
  24920. if(requestObject.sort){
  24921. items.sort(sorter.createSortFunction(requestObject.sort, self));
  24922. }
  24923. if(requestObject.onItem){
  24924. for(var i = startIndex; (i < items.length) && (i < endIndex); ++i){
  24925. var item = items[i];
  24926. if(!aborted){
  24927. requestObject.onItem.call(scope, item, requestObject);
  24928. }
  24929. }
  24930. }
  24931. if(requestObject.onComplete && !aborted){
  24932. var subset = null;
  24933. if(!requestObject.onItem){
  24934. subset = items.slice(startIndex, endIndex);
  24935. }
  24936. requestObject.onComplete.call(scope, subset, requestObject);
  24937. }
  24938. };
  24939. this._fetchItems(request, _fetchHandler, _errorHandler);
  24940. return request; // Object
  24941. };
  24942. return simpleFetch;
  24943. });
  24944. },
  24945. 'dijit/form/_CheckBoxMixin':function(){
  24946. define("dijit/form/_CheckBoxMixin", [
  24947. "dojo/_base/declare", // declare
  24948. "dojo/dom-attr", // domAttr.set
  24949. "dojo/_base/event" // event.stop
  24950. ], function(declare, domAttr, event){
  24951. // module:
  24952. // dijit/form/_CheckBoxMixin
  24953. // summary:
  24954. // Mixin to provide widget functionality corresponding to an HTML checkbox
  24955. return declare("dijit.form._CheckBoxMixin", null, {
  24956. // summary:
  24957. // Mixin to provide widget functionality corresponding to an HTML checkbox
  24958. //
  24959. // description:
  24960. // User interacts with real html inputs.
  24961. // On onclick (which occurs by mouse click, space-bar, or
  24962. // using the arrow keys to switch the selected radio button),
  24963. // we update the state of the checkbox/radio.
  24964. //
  24965. // type: [private] String
  24966. // type attribute on <input> node.
  24967. // Overrides `dijit.form.Button.type`. Users should not change this value.
  24968. type: "checkbox",
  24969. // value: String
  24970. // As an initialization parameter, equivalent to value field on normal checkbox
  24971. // (if checked, the value is passed as the value when form is submitted).
  24972. value: "on",
  24973. // readOnly: Boolean
  24974. // Should this widget respond to user input?
  24975. // In markup, this is specified as "readOnly".
  24976. // Similar to disabled except readOnly form values are submitted.
  24977. readOnly: false,
  24978. // aria-pressed for toggle buttons, and aria-checked for checkboxes
  24979. _aria_attr: "aria-checked",
  24980. _setReadOnlyAttr: function(/*Boolean*/ value){
  24981. this._set("readOnly", value);
  24982. domAttr.set(this.focusNode, 'readOnly', value);
  24983. this.focusNode.setAttribute("aria-readonly", value);
  24984. },
  24985. // Override dijit.form.Button._setLabelAttr() since we don't even have a containerNode.
  24986. // Normally users won't try to set label, except when CheckBox or RadioButton is the child of a dojox.layout.TabContainer
  24987. _setLabelAttr: undefined,
  24988. postMixInProperties: function(){
  24989. if(this.value == ""){
  24990. this.value = "on";
  24991. }
  24992. this.inherited(arguments);
  24993. },
  24994. reset: function(){
  24995. this.inherited(arguments);
  24996. // Handle unlikely event that the <input type=checkbox> value attribute has changed
  24997. this._set("value", this.params.value || "on");
  24998. domAttr.set(this.focusNode, 'value', this.value);
  24999. },
  25000. _onClick: function(/*Event*/ e){
  25001. // summary:
  25002. // Internal function to handle click actions - need to check
  25003. // readOnly, since button no longer does that check.
  25004. if(this.readOnly){
  25005. event.stop(e);
  25006. return false;
  25007. }
  25008. return this.inherited(arguments);
  25009. }
  25010. });
  25011. });
  25012. },
  25013. 'dijit/layout/ContentPane':function(){
  25014. define("dijit/layout/ContentPane", [
  25015. "dojo/_base/kernel", // kernel.deprecated
  25016. "dojo/_base/lang", // lang.mixin lang.delegate lang.hitch lang.isFunction lang.isObject
  25017. "../_Widget",
  25018. "./_ContentPaneResizeMixin",
  25019. "dojo/string", // string.substitute
  25020. "dojo/html", // html._ContentSetter html._emptyNode
  25021. "dojo/i18n!../nls/loading",
  25022. "dojo/_base/array", // array.forEach
  25023. "dojo/_base/declare", // declare
  25024. "dojo/_base/Deferred", // Deferred
  25025. "dojo/dom", // dom.byId
  25026. "dojo/dom-attr", // domAttr.attr
  25027. "dojo/_base/window", // win.body win.doc.createDocumentFragment
  25028. "dojo/_base/xhr", // xhr.get
  25029. "dojo/i18n" // i18n.getLocalization
  25030. ], function(kernel, lang, _Widget, _ContentPaneResizeMixin, string, html, nlsLoading,
  25031. array, declare, Deferred, dom, domAttr, win, xhr, i18n){
  25032. /*=====
  25033. var _Widget = dijit._Widget;
  25034. var _ContentPaneResizeMixin = dijit.layout._ContentPaneResizeMixin;
  25035. =====*/
  25036. // module:
  25037. // dijit/layout/ContentPane
  25038. // summary:
  25039. // A widget containing an HTML fragment, specified inline
  25040. // or by uri. Fragment may include widgets.
  25041. return declare("dijit.layout.ContentPane", [_Widget, _ContentPaneResizeMixin], {
  25042. // summary:
  25043. // A widget containing an HTML fragment, specified inline
  25044. // or by uri. Fragment may include widgets.
  25045. //
  25046. // description:
  25047. // This widget embeds a document fragment in the page, specified
  25048. // either by uri, javascript generated markup or DOM reference.
  25049. // Any widgets within this content are instantiated and managed,
  25050. // but laid out according to the HTML structure. Unlike IFRAME,
  25051. // ContentPane embeds a document fragment as would be found
  25052. // inside the BODY tag of a full HTML document. It should not
  25053. // contain the HTML, HEAD, or BODY tags.
  25054. // For more advanced functionality with scripts and
  25055. // stylesheets, see dojox.layout.ContentPane. This widget may be
  25056. // used stand alone or as a base class for other widgets.
  25057. // ContentPane is useful as a child of other layout containers
  25058. // such as BorderContainer or TabContainer, but note that those
  25059. // widgets can contain any widget as a child.
  25060. //
  25061. // example:
  25062. // Some quick samples:
  25063. // To change the innerHTML: cp.set('content', '<b>new content</b>')
  25064. //
  25065. // Or you can send it a NodeList: cp.set('content', dojo.query('div [class=selected]', userSelection))
  25066. //
  25067. // To do an ajax update: cp.set('href', url)
  25068. // href: String
  25069. // The href of the content that displays now.
  25070. // Set this at construction if you want to load data externally when the
  25071. // pane is shown. (Set preload=true to load it immediately.)
  25072. // Changing href after creation doesn't have any effect; Use set('href', ...);
  25073. href: "",
  25074. // content: String || DomNode || NodeList || dijit._Widget
  25075. // The innerHTML of the ContentPane.
  25076. // Note that the initialization parameter / argument to set("content", ...)
  25077. // can be a String, DomNode, Nodelist, or _Widget.
  25078. content: "",
  25079. // extractContent: Boolean
  25080. // Extract visible content from inside of <body> .... </body>.
  25081. // I.e., strip <html> and <head> (and it's contents) from the href
  25082. extractContent: false,
  25083. // parseOnLoad: Boolean
  25084. // Parse content and create the widgets, if any.
  25085. parseOnLoad: true,
  25086. // parserScope: String
  25087. // Flag passed to parser. Root for attribute names to search for. If scopeName is dojo,
  25088. // will search for data-dojo-type (or dojoType). For backwards compatibility
  25089. // reasons defaults to dojo._scopeName (which is "dojo" except when
  25090. // multi-version support is used, when it will be something like dojo16, dojo20, etc.)
  25091. parserScope: kernel._scopeName,
  25092. // preventCache: Boolean
  25093. // Prevent caching of data from href's by appending a timestamp to the href.
  25094. preventCache: false,
  25095. // preload: Boolean
  25096. // Force load of data on initialization even if pane is hidden.
  25097. preload: false,
  25098. // refreshOnShow: Boolean
  25099. // Refresh (re-download) content when pane goes from hidden to shown
  25100. refreshOnShow: false,
  25101. // loadingMessage: String
  25102. // Message that shows while downloading
  25103. loadingMessage: "<span class='dijitContentPaneLoading'><span class='dijitInline dijitIconLoading'></span>${loadingState}</span>",
  25104. // errorMessage: String
  25105. // Message that shows if an error occurs
  25106. errorMessage: "<span class='dijitContentPaneError'><span class='dijitInline dijitIconError'></span>${errorState}</span>",
  25107. // isLoaded: [readonly] Boolean
  25108. // True if the ContentPane has data in it, either specified
  25109. // during initialization (via href or inline content), or set
  25110. // via set('content', ...) / set('href', ...)
  25111. //
  25112. // False if it doesn't have any content, or if ContentPane is
  25113. // still in the process of downloading href.
  25114. isLoaded: false,
  25115. baseClass: "dijitContentPane",
  25116. /*======
  25117. // ioMethod: dojo.xhrGet|dojo.xhrPost
  25118. // Function that should grab the content specified via href.
  25119. ioMethod: dojo.xhrGet,
  25120. ======*/
  25121. // ioArgs: Object
  25122. // Parameters to pass to xhrGet() request, for example:
  25123. // | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="href: './bar', ioArgs: {timeout: 500}">
  25124. ioArgs: {},
  25125. // onLoadDeferred: [readonly] dojo.Deferred
  25126. // This is the `dojo.Deferred` returned by set('href', ...) and refresh().
  25127. // Calling onLoadDeferred.addCallback() or addErrback() registers your
  25128. // callback to be called only once, when the prior set('href', ...) call or
  25129. // the initial href parameter to the constructor finishes loading.
  25130. //
  25131. // This is different than an onLoad() handler which gets called any time any href
  25132. // or content is loaded.
  25133. onLoadDeferred: null,
  25134. // Cancel _WidgetBase's _setTitleAttr because we don't want the title attribute (used to specify
  25135. // tab labels) to be copied to ContentPane.domNode... otherwise a tooltip shows up over the
  25136. // entire pane.
  25137. _setTitleAttr: null,
  25138. // Flag to parser that I'll parse my contents, so it shouldn't.
  25139. stopParser: true,
  25140. // template: [private] Boolean
  25141. // Flag from the parser that this ContentPane is inside a template
  25142. // so the contents are pre-parsed.
  25143. // (TODO: this declaration can be commented out in 2.0)
  25144. template: false,
  25145. create: function(params, srcNodeRef){
  25146. // Convert a srcNodeRef argument into a content parameter, so that the original contents are
  25147. // processed in the same way as contents set via set("content", ...), calling the parser etc.
  25148. // Avoid modifying original params object since that breaks NodeList instantiation, see #11906.
  25149. if((!params || !params.template) && srcNodeRef && !("href" in params) && !("content" in params)){
  25150. var df = win.doc.createDocumentFragment();
  25151. srcNodeRef = dom.byId(srcNodeRef);
  25152. while(srcNodeRef.firstChild){
  25153. df.appendChild(srcNodeRef.firstChild);
  25154. }
  25155. params = lang.delegate(params, {content: df});
  25156. }
  25157. this.inherited(arguments, [params, srcNodeRef]);
  25158. },
  25159. postMixInProperties: function(){
  25160. this.inherited(arguments);
  25161. var messages = i18n.getLocalization("dijit", "loading", this.lang);
  25162. this.loadingMessage = string.substitute(this.loadingMessage, messages);
  25163. this.errorMessage = string.substitute(this.errorMessage, messages);
  25164. },
  25165. buildRendering: function(){
  25166. this.inherited(arguments);
  25167. // Since we have no template we need to set this.containerNode ourselves, to make getChildren() work.
  25168. // For subclasses of ContentPane that do have a template, does nothing.
  25169. if(!this.containerNode){
  25170. this.containerNode = this.domNode;
  25171. }
  25172. // remove the title attribute so it doesn't show up when hovering
  25173. // over a node (TODO: remove in 2.0, no longer needed after #11490)
  25174. this.domNode.title = "";
  25175. if(!domAttr.get(this.domNode,"role")){
  25176. this.domNode.setAttribute("role", "group");
  25177. }
  25178. },
  25179. startup: function(){
  25180. // summary:
  25181. // Call startup() on all children including non _Widget ones like dojo.dnd.Source objects
  25182. // This starts all the widgets
  25183. this.inherited(arguments);
  25184. // And this catches stuff like dojo.dnd.Source
  25185. if(this._contentSetter){
  25186. array.forEach(this._contentSetter.parseResults, function(obj){
  25187. if(!obj._started && !obj._destroyed && lang.isFunction(obj.startup)){
  25188. obj.startup();
  25189. obj._started = true;
  25190. }
  25191. }, this);
  25192. }
  25193. },
  25194. setHref: function(/*String|Uri*/ href){
  25195. // summary:
  25196. // Deprecated. Use set('href', ...) instead.
  25197. kernel.deprecated("dijit.layout.ContentPane.setHref() is deprecated. Use set('href', ...) instead.", "", "2.0");
  25198. return this.set("href", href);
  25199. },
  25200. _setHrefAttr: function(/*String|Uri*/ href){
  25201. // summary:
  25202. // Hook so set("href", ...) works.
  25203. // description:
  25204. // Reset the (external defined) content of this pane and replace with new url
  25205. // Note: It delays the download until widget is shown if preload is false.
  25206. // href:
  25207. // url to the page you want to get, must be within the same domain as your mainpage
  25208. // Cancel any in-flight requests (a set('href', ...) will cancel any in-flight set('href', ...))
  25209. this.cancel();
  25210. this.onLoadDeferred = new Deferred(lang.hitch(this, "cancel"));
  25211. this.onLoadDeferred.addCallback(lang.hitch(this, "onLoad"));
  25212. this._set("href", href);
  25213. // _setHrefAttr() is called during creation and by the user, after creation.
  25214. // Assuming preload == false, only in the second case do we actually load the URL;
  25215. // otherwise it's done in startup(), and only if this widget is shown.
  25216. if(this.preload || (this._created && this._isShown())){
  25217. this._load();
  25218. }else{
  25219. // Set flag to indicate that href needs to be loaded the next time the
  25220. // ContentPane is made visible
  25221. this._hrefChanged = true;
  25222. }
  25223. return this.onLoadDeferred; // Deferred
  25224. },
  25225. setContent: function(/*String|DomNode|Nodelist*/data){
  25226. // summary:
  25227. // Deprecated. Use set('content', ...) instead.
  25228. kernel.deprecated("dijit.layout.ContentPane.setContent() is deprecated. Use set('content', ...) instead.", "", "2.0");
  25229. this.set("content", data);
  25230. },
  25231. _setContentAttr: function(/*String|DomNode|Nodelist*/data){
  25232. // summary:
  25233. // Hook to make set("content", ...) work.
  25234. // Replaces old content with data content, include style classes from old content
  25235. // data:
  25236. // the new Content may be String, DomNode or NodeList
  25237. //
  25238. // if data is a NodeList (or an array of nodes) nodes are copied
  25239. // so you can import nodes from another document implicitly
  25240. // clear href so we can't run refresh and clear content
  25241. // refresh should only work if we downloaded the content
  25242. this._set("href", "");
  25243. // Cancel any in-flight requests (a set('content', ...) will cancel any in-flight set('href', ...))
  25244. this.cancel();
  25245. // Even though user is just setting content directly, still need to define an onLoadDeferred
  25246. // because the _onLoadHandler() handler is still getting called from setContent()
  25247. this.onLoadDeferred = new Deferred(lang.hitch(this, "cancel"));
  25248. if(this._created){
  25249. // For back-compat reasons, call onLoad() for set('content', ...)
  25250. // calls but not for content specified in srcNodeRef (ie: <div data-dojo-type=ContentPane>...</div>)
  25251. // or as initialization parameter (ie: new ContentPane({content: ...})
  25252. this.onLoadDeferred.addCallback(lang.hitch(this, "onLoad"));
  25253. }
  25254. this._setContent(data || "");
  25255. this._isDownloaded = false; // mark that content is from a set('content') not a set('href')
  25256. return this.onLoadDeferred; // Deferred
  25257. },
  25258. _getContentAttr: function(){
  25259. // summary:
  25260. // Hook to make get("content") work
  25261. return this.containerNode.innerHTML;
  25262. },
  25263. cancel: function(){
  25264. // summary:
  25265. // Cancels an in-flight download of content
  25266. if(this._xhrDfd && (this._xhrDfd.fired == -1)){
  25267. this._xhrDfd.cancel();
  25268. }
  25269. delete this._xhrDfd; // garbage collect
  25270. this.onLoadDeferred = null;
  25271. },
  25272. uninitialize: function(){
  25273. if(this._beingDestroyed){
  25274. this.cancel();
  25275. }
  25276. this.inherited(arguments);
  25277. },
  25278. destroyRecursive: function(/*Boolean*/ preserveDom){
  25279. // summary:
  25280. // Destroy the ContentPane and its contents
  25281. // if we have multiple controllers destroying us, bail after the first
  25282. if(this._beingDestroyed){
  25283. return;
  25284. }
  25285. this.inherited(arguments);
  25286. },
  25287. _onShow: function(){
  25288. // summary:
  25289. // Called when the ContentPane is made visible
  25290. // description:
  25291. // For a plain ContentPane, this is called on initialization, from startup().
  25292. // If the ContentPane is a hidden pane of a TabContainer etc., then it's
  25293. // called whenever the pane is made visible.
  25294. //
  25295. // Does necessary processing, including href download and layout/resize of
  25296. // child widget(s)
  25297. this.inherited(arguments);
  25298. if(this.href){
  25299. if(!this._xhrDfd && // if there's an href that isn't already being loaded
  25300. (!this.isLoaded || this._hrefChanged || this.refreshOnShow)
  25301. ){
  25302. return this.refresh(); // If child has an href, promise that fires when the load is complete
  25303. }
  25304. }
  25305. },
  25306. refresh: function(){
  25307. // summary:
  25308. // [Re]download contents of href and display
  25309. // description:
  25310. // 1. cancels any currently in-flight requests
  25311. // 2. posts "loading..." message
  25312. // 3. sends XHR to download new data
  25313. // Cancel possible prior in-flight request
  25314. this.cancel();
  25315. this.onLoadDeferred = new Deferred(lang.hitch(this, "cancel"));
  25316. this.onLoadDeferred.addCallback(lang.hitch(this, "onLoad"));
  25317. this._load();
  25318. return this.onLoadDeferred; // If child has an href, promise that fires when refresh is complete
  25319. },
  25320. _load: function(){
  25321. // summary:
  25322. // Load/reload the href specified in this.href
  25323. // display loading message
  25324. this._setContent(this.onDownloadStart(), true);
  25325. var self = this;
  25326. var getArgs = {
  25327. preventCache: (this.preventCache || this.refreshOnShow),
  25328. url: this.href,
  25329. handleAs: "text"
  25330. };
  25331. if(lang.isObject(this.ioArgs)){
  25332. lang.mixin(getArgs, this.ioArgs);
  25333. }
  25334. var hand = (this._xhrDfd = (this.ioMethod || xhr.get)(getArgs));
  25335. hand.addCallback(function(html){
  25336. try{
  25337. self._isDownloaded = true;
  25338. self._setContent(html, false);
  25339. self.onDownloadEnd();
  25340. }catch(err){
  25341. self._onError('Content', err); // onContentError
  25342. }
  25343. delete self._xhrDfd;
  25344. return html;
  25345. });
  25346. hand.addErrback(function(err){
  25347. if(!hand.canceled){
  25348. // show error message in the pane
  25349. self._onError('Download', err); // onDownloadError
  25350. }
  25351. delete self._xhrDfd;
  25352. return err;
  25353. });
  25354. // Remove flag saying that a load is needed
  25355. delete this._hrefChanged;
  25356. },
  25357. _onLoadHandler: function(data){
  25358. // summary:
  25359. // This is called whenever new content is being loaded
  25360. this._set("isLoaded", true);
  25361. try{
  25362. this.onLoadDeferred.callback(data);
  25363. }catch(e){
  25364. console.error('Error '+this.widgetId+' running custom onLoad code: ' + e.message);
  25365. }
  25366. },
  25367. _onUnloadHandler: function(){
  25368. // summary:
  25369. // This is called whenever the content is being unloaded
  25370. this._set("isLoaded", false);
  25371. try{
  25372. this.onUnload();
  25373. }catch(e){
  25374. console.error('Error '+this.widgetId+' running custom onUnload code: ' + e.message);
  25375. }
  25376. },
  25377. destroyDescendants: function(/*Boolean*/ preserveDom){
  25378. // summary:
  25379. // Destroy all the widgets inside the ContentPane and empty containerNode
  25380. // Make sure we call onUnload (but only when the ContentPane has real content)
  25381. if(this.isLoaded){
  25382. this._onUnloadHandler();
  25383. }
  25384. // Even if this.isLoaded == false there might still be a "Loading..." message
  25385. // to erase, so continue...
  25386. // For historical reasons we need to delete all widgets under this.containerNode,
  25387. // even ones that the user has created manually.
  25388. var setter = this._contentSetter;
  25389. array.forEach(this.getChildren(), function(widget){
  25390. if(widget.destroyRecursive){
  25391. widget.destroyRecursive(preserveDom);
  25392. }
  25393. });
  25394. if(setter){
  25395. // Most of the widgets in setter.parseResults have already been destroyed, but
  25396. // things like Menu that have been moved to <body> haven't yet
  25397. array.forEach(setter.parseResults, function(widget){
  25398. if(widget.destroyRecursive && widget.domNode && widget.domNode.parentNode == win.body()){
  25399. widget.destroyRecursive(preserveDom);
  25400. }
  25401. });
  25402. delete setter.parseResults;
  25403. }
  25404. // And then clear away all the DOM nodes
  25405. if(!preserveDom){
  25406. html._emptyNode(this.containerNode);
  25407. }
  25408. // Delete any state information we have about current contents
  25409. delete this._singleChild;
  25410. },
  25411. _setContent: function(/*String|DocumentFragment*/ cont, /*Boolean*/ isFakeContent){
  25412. // summary:
  25413. // Insert the content into the container node
  25414. // first get rid of child widgets
  25415. this.destroyDescendants();
  25416. // html.set will take care of the rest of the details
  25417. // we provide an override for the error handling to ensure the widget gets the errors
  25418. // configure the setter instance with only the relevant widget instance properties
  25419. // NOTE: unless we hook into attr, or provide property setters for each property,
  25420. // we need to re-configure the ContentSetter with each use
  25421. var setter = this._contentSetter;
  25422. if(! (setter && setter instanceof html._ContentSetter)){
  25423. setter = this._contentSetter = new html._ContentSetter({
  25424. node: this.containerNode,
  25425. _onError: lang.hitch(this, this._onError),
  25426. onContentError: lang.hitch(this, function(e){
  25427. // fires if a domfault occurs when we are appending this.errorMessage
  25428. // like for instance if domNode is a UL and we try append a DIV
  25429. var errMess = this.onContentError(e);
  25430. try{
  25431. this.containerNode.innerHTML = errMess;
  25432. }catch(e){
  25433. console.error('Fatal '+this.id+' could not change content due to '+e.message, e);
  25434. }
  25435. })/*,
  25436. _onError */
  25437. });
  25438. }
  25439. var setterParams = lang.mixin({
  25440. cleanContent: this.cleanContent,
  25441. extractContent: this.extractContent,
  25442. parseContent: !cont.domNode && this.parseOnLoad,
  25443. parserScope: this.parserScope,
  25444. startup: false,
  25445. dir: this.dir,
  25446. lang: this.lang,
  25447. textDir: this.textDir
  25448. }, this._contentSetterParams || {});
  25449. setter.set( (lang.isObject(cont) && cont.domNode) ? cont.domNode : cont, setterParams );
  25450. // setter params must be pulled afresh from the ContentPane each time
  25451. delete this._contentSetterParams;
  25452. if(this.doLayout){
  25453. this._checkIfSingleChild();
  25454. }
  25455. if(!isFakeContent){
  25456. if(this._started){
  25457. // Startup each top level child widget (and they will start their children, recursively)
  25458. delete this._started;
  25459. this.startup();
  25460. // Call resize() on each of my child layout widgets,
  25461. // or resize() on my single child layout widget...
  25462. // either now (if I'm currently visible) or when I become visible
  25463. this._scheduleLayout();
  25464. }
  25465. this._onLoadHandler(cont);
  25466. }
  25467. },
  25468. _onError: function(type, err, consoleText){
  25469. this.onLoadDeferred.errback(err);
  25470. // shows user the string that is returned by on[type]Error
  25471. // override on[type]Error and return your own string to customize
  25472. var errText = this['on' + type + 'Error'].call(this, err);
  25473. if(consoleText){
  25474. console.error(consoleText, err);
  25475. }else if(errText){// a empty string won't change current content
  25476. this._setContent(errText, true);
  25477. }
  25478. },
  25479. // EVENT's, should be overide-able
  25480. onLoad: function(/*===== data =====*/){
  25481. // summary:
  25482. // Event hook, is called after everything is loaded and widgetified
  25483. // tags:
  25484. // callback
  25485. },
  25486. onUnload: function(){
  25487. // summary:
  25488. // Event hook, is called before old content is cleared
  25489. // tags:
  25490. // callback
  25491. },
  25492. onDownloadStart: function(){
  25493. // summary:
  25494. // Called before download starts.
  25495. // description:
  25496. // The string returned by this function will be the html
  25497. // that tells the user we are loading something.
  25498. // Override with your own function if you want to change text.
  25499. // tags:
  25500. // extension
  25501. return this.loadingMessage;
  25502. },
  25503. onContentError: function(/*Error*/ /*===== error =====*/){
  25504. // summary:
  25505. // Called on DOM faults, require faults etc. in content.
  25506. //
  25507. // In order to display an error message in the pane, return
  25508. // the error message from this method, as an HTML string.
  25509. //
  25510. // By default (if this method is not overriden), it returns
  25511. // nothing, so the error message is just printed to the console.
  25512. // tags:
  25513. // extension
  25514. },
  25515. onDownloadError: function(/*Error*/ /*===== error =====*/){
  25516. // summary:
  25517. // Called when download error occurs.
  25518. //
  25519. // In order to display an error message in the pane, return
  25520. // the error message from this method, as an HTML string.
  25521. //
  25522. // Default behavior (if this method is not overriden) is to display
  25523. // the error message inside the pane.
  25524. // tags:
  25525. // extension
  25526. return this.errorMessage;
  25527. },
  25528. onDownloadEnd: function(){
  25529. // summary:
  25530. // Called when download is finished.
  25531. // tags:
  25532. // callback
  25533. }
  25534. });
  25535. });
  25536. },
  25537. 'url:dijit/form/templates/ValidationTextBox.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\"\r\n\tid=\"widget_${id}\" role=\"presentation\"\r\n\t><div class='dijitReset dijitValidationContainer'\r\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t/></div\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class=\"dijitReset dijitInputInner\" data-dojo-attach-point='textbox,focusNode' autocomplete=\"off\"\r\n\t\t\t${!nameAttrSetting} type='${type}'\r\n\t/></div\r\n></div>\r\n",
  25538. 'url:dijit/form/templates/TextBox.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\" id=\"widget_${id}\" role=\"presentation\"\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class=\"dijitReset dijitInputInner\" data-dojo-attach-point='textbox,focusNode' autocomplete=\"off\"\r\n\t\t\t${!nameAttrSetting} type='${type}'\r\n\t/></div\r\n></div>\r\n",
  25539. 'dijit/layout/utils':function(){
  25540. define("dijit/layout/utils", [
  25541. "dojo/_base/array", // array.filter array.forEach
  25542. "dojo/dom-class", // domClass.add domClass.remove
  25543. "dojo/dom-geometry", // domGeometry.marginBox
  25544. "dojo/dom-style", // domStyle.getComputedStyle
  25545. "dojo/_base/lang", // lang.mixin
  25546. ".." // for exporting symbols to dijit, remove in 2.0
  25547. ], function(array, domClass, domGeometry, domStyle, lang, dijit){
  25548. // module:
  25549. // dijit/layout/utils
  25550. // summary:
  25551. // marginBox2contentBox() and layoutChildren()
  25552. var layout = lang.getObject("layout", true, dijit);
  25553. /*===== layout = dijit.layout =====*/
  25554. layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
  25555. // summary:
  25556. // Given the margin-box size of a node, return its content box size.
  25557. // Functions like domGeometry.contentBox() but is more reliable since it doesn't have
  25558. // to wait for the browser to compute sizes.
  25559. var cs = domStyle.getComputedStyle(node);
  25560. var me = domGeometry.getMarginExtents(node, cs);
  25561. var pb = domGeometry.getPadBorderExtents(node, cs);
  25562. return {
  25563. l: domStyle.toPixelValue(node, cs.paddingLeft),
  25564. t: domStyle.toPixelValue(node, cs.paddingTop),
  25565. w: mb.w - (me.w + pb.w),
  25566. h: mb.h - (me.h + pb.h)
  25567. };
  25568. };
  25569. function capitalize(word){
  25570. return word.substring(0,1).toUpperCase() + word.substring(1);
  25571. }
  25572. function size(widget, dim){
  25573. // size the child
  25574. var newSize = widget.resize ? widget.resize(dim) : domGeometry.setMarginBox(widget.domNode, dim);
  25575. // record child's size
  25576. if(newSize){
  25577. // if the child returned it's new size then use that
  25578. lang.mixin(widget, newSize);
  25579. }else{
  25580. // otherwise, call getMarginBox(), but favor our own numbers when we have them.
  25581. // the browser lies sometimes
  25582. lang.mixin(widget, domGeometry.getMarginBox(widget.domNode));
  25583. lang.mixin(widget, dim);
  25584. }
  25585. }
  25586. layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Widget[]*/ children,
  25587. /*String?*/ changedRegionId, /*Number?*/ changedRegionSize){
  25588. // summary:
  25589. // Layout a bunch of child dom nodes within a parent dom node
  25590. // container:
  25591. // parent node
  25592. // dim:
  25593. // {l, t, w, h} object specifying dimensions of container into which to place children
  25594. // children:
  25595. // an array of Widgets or at least objects containing:
  25596. // * domNode: pointer to DOM node to position
  25597. // * region or layoutAlign: position to place DOM node
  25598. // * resize(): (optional) method to set size of node
  25599. // * id: (optional) Id of widgets, referenced from resize object, below.
  25600. // changedRegionId:
  25601. // If specified, the slider for the region with the specified id has been dragged, and thus
  25602. // the region's height or width should be adjusted according to changedRegionSize
  25603. // changedRegionSize:
  25604. // See changedRegionId.
  25605. // copy dim because we are going to modify it
  25606. dim = lang.mixin({}, dim);
  25607. domClass.add(container, "dijitLayoutContainer");
  25608. // Move "client" elements to the end of the array for layout. a11y dictates that the author
  25609. // needs to be able to put them in the document in tab-order, but this algorithm requires that
  25610. // client be last. TODO: move these lines to LayoutContainer? Unneeded other places I think.
  25611. children = array.filter(children, function(item){ return item.region != "center" && item.layoutAlign != "client"; })
  25612. .concat(array.filter(children, function(item){ return item.region == "center" || item.layoutAlign == "client"; }));
  25613. // set positions/sizes
  25614. array.forEach(children, function(child){
  25615. var elm = child.domNode,
  25616. pos = (child.region || child.layoutAlign);
  25617. if(!pos){
  25618. throw new Error("No region setting for " + child.id)
  25619. }
  25620. // set elem to upper left corner of unused space; may move it later
  25621. var elmStyle = elm.style;
  25622. elmStyle.left = dim.l+"px";
  25623. elmStyle.top = dim.t+"px";
  25624. elmStyle.position = "absolute";
  25625. domClass.add(elm, "dijitAlign" + capitalize(pos));
  25626. // Size adjustments to make to this child widget
  25627. var sizeSetting = {};
  25628. // Check for optional size adjustment due to splitter drag (height adjustment for top/bottom align
  25629. // panes and width adjustment for left/right align panes.
  25630. if(changedRegionId && changedRegionId == child.id){
  25631. sizeSetting[child.region == "top" || child.region == "bottom" ? "h" : "w"] = changedRegionSize;
  25632. }
  25633. // set size && adjust record of remaining space.
  25634. // note that setting the width of a <div> may affect its height.
  25635. if(pos == "top" || pos == "bottom"){
  25636. sizeSetting.w = dim.w;
  25637. size(child, sizeSetting);
  25638. dim.h -= child.h;
  25639. if(pos == "top"){
  25640. dim.t += child.h;
  25641. }else{
  25642. elmStyle.top = dim.t + dim.h + "px";
  25643. }
  25644. }else if(pos == "left" || pos == "right"){
  25645. sizeSetting.h = dim.h;
  25646. size(child, sizeSetting);
  25647. dim.w -= child.w;
  25648. if(pos == "left"){
  25649. dim.l += child.w;
  25650. }else{
  25651. elmStyle.left = dim.l + dim.w + "px";
  25652. }
  25653. }else if(pos == "client" || pos == "center"){
  25654. size(child, dim);
  25655. }
  25656. });
  25657. };
  25658. return {
  25659. marginBox2contentBox: layout.marginBox2contentBox,
  25660. layoutChildren: layout.layoutChildren
  25661. };
  25662. });
  25663. },
  25664. 'dijit/_Contained':function(){
  25665. define("dijit/_Contained", [
  25666. "dojo/_base/declare", // declare
  25667. "./registry" // registry.getEnclosingWidget(), registry.byNode()
  25668. ], function(declare, registry){
  25669. // module:
  25670. // dijit/_Contained
  25671. // summary:
  25672. // Mixin for widgets that are children of a container widget
  25673. return declare("dijit._Contained", null, {
  25674. // summary:
  25675. // Mixin for widgets that are children of a container widget
  25676. //
  25677. // example:
  25678. // | // make a basic custom widget that knows about it's parents
  25679. // | declare("my.customClass",[dijit._Widget,dijit._Contained],{});
  25680. _getSibling: function(/*String*/ which){
  25681. // summary:
  25682. // Returns next or previous sibling
  25683. // which:
  25684. // Either "next" or "previous"
  25685. // tags:
  25686. // private
  25687. var node = this.domNode;
  25688. do{
  25689. node = node[which+"Sibling"];
  25690. }while(node && node.nodeType != 1);
  25691. return node && registry.byNode(node); // dijit._Widget
  25692. },
  25693. getPreviousSibling: function(){
  25694. // summary:
  25695. // Returns null if this is the first child of the parent,
  25696. // otherwise returns the next element sibling to the "left".
  25697. return this._getSibling("previous"); // dijit._Widget
  25698. },
  25699. getNextSibling: function(){
  25700. // summary:
  25701. // Returns null if this is the last child of the parent,
  25702. // otherwise returns the next element sibling to the "right".
  25703. return this._getSibling("next"); // dijit._Widget
  25704. },
  25705. getIndexInParent: function(){
  25706. // summary:
  25707. // Returns the index of this widget within its container parent.
  25708. // It returns -1 if the parent does not exist, or if the parent
  25709. // is not a dijit._Container
  25710. var p = this.getParent();
  25711. if(!p || !p.getIndexOfChild){
  25712. return -1; // int
  25713. }
  25714. return p.getIndexOfChild(this); // int
  25715. }
  25716. });
  25717. });
  25718. },
  25719. 'dijit/_KeyNavContainer':function(){
  25720. define("dijit/_KeyNavContainer", [
  25721. "dojo/_base/kernel", // kernel.deprecated
  25722. "./_Container",
  25723. "./_FocusMixin",
  25724. "dojo/_base/array", // array.forEach
  25725. "dojo/keys", // keys.END keys.HOME
  25726. "dojo/_base/declare", // declare
  25727. "dojo/_base/event", // event.stop
  25728. "dojo/dom-attr", // domAttr.set
  25729. "dojo/_base/lang" // lang.hitch
  25730. ], function(kernel, _Container, _FocusMixin, array, keys, declare, event, domAttr, lang){
  25731. /*=====
  25732. var _FocusMixin = dijit._FocusMixin;
  25733. var _Container = dijit._Container;
  25734. =====*/
  25735. // module:
  25736. // dijit/_KeyNavContainer
  25737. // summary:
  25738. // A _Container with keyboard navigation of its children.
  25739. return declare("dijit._KeyNavContainer", [_FocusMixin, _Container], {
  25740. // summary:
  25741. // A _Container with keyboard navigation of its children.
  25742. // description:
  25743. // To use this mixin, call connectKeyNavHandlers() in
  25744. // postCreate().
  25745. // It provides normalized keyboard and focusing code for Container
  25746. // widgets.
  25747. /*=====
  25748. // focusedChild: [protected] Widget
  25749. // The currently focused child widget, or null if there isn't one
  25750. focusedChild: null,
  25751. =====*/
  25752. // tabIndex: Integer
  25753. // Tab index of the container; same as HTML tabIndex attribute.
  25754. // Note then when user tabs into the container, focus is immediately
  25755. // moved to the first item in the container.
  25756. tabIndex: "0",
  25757. connectKeyNavHandlers: function(/*keys[]*/ prevKeyCodes, /*keys[]*/ nextKeyCodes){
  25758. // summary:
  25759. // Call in postCreate() to attach the keyboard handlers
  25760. // to the container.
  25761. // preKeyCodes: keys[]
  25762. // Key codes for navigating to the previous child.
  25763. // nextKeyCodes: keys[]
  25764. // Key codes for navigating to the next child.
  25765. // tags:
  25766. // protected
  25767. // TODO: call this automatically from my own postCreate()
  25768. var keyCodes = (this._keyNavCodes = {});
  25769. var prev = lang.hitch(this, "focusPrev");
  25770. var next = lang.hitch(this, "focusNext");
  25771. array.forEach(prevKeyCodes, function(code){ keyCodes[code] = prev; });
  25772. array.forEach(nextKeyCodes, function(code){ keyCodes[code] = next; });
  25773. keyCodes[keys.HOME] = lang.hitch(this, "focusFirstChild");
  25774. keyCodes[keys.END] = lang.hitch(this, "focusLastChild");
  25775. this.connect(this.domNode, "onkeypress", "_onContainerKeypress");
  25776. this.connect(this.domNode, "onfocus", "_onContainerFocus");
  25777. },
  25778. startupKeyNavChildren: function(){
  25779. kernel.deprecated("startupKeyNavChildren() call no longer needed", "", "2.0");
  25780. },
  25781. startup: function(){
  25782. this.inherited(arguments);
  25783. array.forEach(this.getChildren(), lang.hitch(this, "_startupChild"));
  25784. },
  25785. addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){
  25786. this.inherited(arguments);
  25787. this._startupChild(widget);
  25788. },
  25789. focus: function(){
  25790. // summary:
  25791. // Default focus() implementation: focus the first child.
  25792. this.focusFirstChild();
  25793. },
  25794. focusFirstChild: function(){
  25795. // summary:
  25796. // Focus the first focusable child in the container.
  25797. // tags:
  25798. // protected
  25799. this.focusChild(this._getFirstFocusableChild());
  25800. },
  25801. focusLastChild: function(){
  25802. // summary:
  25803. // Focus the last focusable child in the container.
  25804. // tags:
  25805. // protected
  25806. this.focusChild(this._getLastFocusableChild());
  25807. },
  25808. focusNext: function(){
  25809. // summary:
  25810. // Focus the next widget
  25811. // tags:
  25812. // protected
  25813. this.focusChild(this._getNextFocusableChild(this.focusedChild, 1));
  25814. },
  25815. focusPrev: function(){
  25816. // summary:
  25817. // Focus the last focusable node in the previous widget
  25818. // (ex: go to the ComboButton icon section rather than button section)
  25819. // tags:
  25820. // protected
  25821. this.focusChild(this._getNextFocusableChild(this.focusedChild, -1), true);
  25822. },
  25823. focusChild: function(/*dijit._Widget*/ widget, /*Boolean*/ last){
  25824. // summary:
  25825. // Focus specified child widget.
  25826. // widget:
  25827. // Reference to container's child widget
  25828. // last:
  25829. // If true and if widget has multiple focusable nodes, focus the
  25830. // last one instead of the first one
  25831. // tags:
  25832. // protected
  25833. if(!widget){ return; }
  25834. if(this.focusedChild && widget !== this.focusedChild){
  25835. this._onChildBlur(this.focusedChild); // used by _MenuBase
  25836. }
  25837. widget.set("tabIndex", this.tabIndex); // for IE focus outline to appear, must set tabIndex before focs
  25838. widget.focus(last ? "end" : "start");
  25839. this._set("focusedChild", widget);
  25840. },
  25841. _startupChild: function(/*dijit._Widget*/ widget){
  25842. // summary:
  25843. // Setup for each child widget
  25844. // description:
  25845. // Sets tabIndex=-1 on each child, so that the tab key will
  25846. // leave the container rather than visiting each child.
  25847. // tags:
  25848. // private
  25849. widget.set("tabIndex", "-1");
  25850. this.connect(widget, "_onFocus", function(){
  25851. // Set valid tabIndex so tabbing away from widget goes to right place, see #10272
  25852. widget.set("tabIndex", this.tabIndex);
  25853. });
  25854. this.connect(widget, "_onBlur", function(){
  25855. widget.set("tabIndex", "-1");
  25856. });
  25857. },
  25858. _onContainerFocus: function(evt){
  25859. // summary:
  25860. // Handler for when the container gets focus
  25861. // description:
  25862. // Initially the container itself has a tabIndex, but when it gets
  25863. // focus, switch focus to first child...
  25864. // tags:
  25865. // private
  25866. // Note that we can't use _onFocus() because switching focus from the
  25867. // _onFocus() handler confuses the focus.js code
  25868. // (because it causes _onFocusNode() to be called recursively)
  25869. // Also, _onFocus() would fire when focus went directly to a child widget due to mouse click.
  25870. // Ignore spurious focus events:
  25871. // 1. focus on a child widget bubbles on FF
  25872. // 2. on IE, clicking the scrollbar of a select dropdown moves focus from the focused child item to me
  25873. if(evt.target !== this.domNode || this.focusedChild){ return; }
  25874. this.focusFirstChild();
  25875. // and then set the container's tabIndex to -1,
  25876. // (don't remove as that breaks Safari 4)
  25877. // so that tab or shift-tab will go to the fields after/before
  25878. // the container, rather than the container itself
  25879. domAttr.set(this.domNode, "tabIndex", "-1");
  25880. },
  25881. _onBlur: function(evt){
  25882. // When focus is moved away the container, and its descendant (popup) widgets,
  25883. // then restore the container's tabIndex so that user can tab to it again.
  25884. // Note that using _onBlur() so that this doesn't happen when focus is shifted
  25885. // to one of my child widgets (typically a popup)
  25886. if(this.tabIndex){
  25887. domAttr.set(this.domNode, "tabIndex", this.tabIndex);
  25888. }
  25889. this.focusedChild = null;
  25890. this.inherited(arguments);
  25891. },
  25892. _onContainerKeypress: function(evt){
  25893. // summary:
  25894. // When a key is pressed, if it's an arrow key etc. then
  25895. // it's handled here.
  25896. // tags:
  25897. // private
  25898. if(evt.ctrlKey || evt.altKey){ return; }
  25899. var func = this._keyNavCodes[evt.charOrCode];
  25900. if(func){
  25901. func();
  25902. event.stop(evt);
  25903. }
  25904. },
  25905. _onChildBlur: function(/*dijit._Widget*/ /*===== widget =====*/){
  25906. // summary:
  25907. // Called when focus leaves a child widget to go
  25908. // to a sibling widget.
  25909. // Used by MenuBase.js (TODO: move code there)
  25910. // tags:
  25911. // protected
  25912. },
  25913. _getFirstFocusableChild: function(){
  25914. // summary:
  25915. // Returns first child that can be focused
  25916. return this._getNextFocusableChild(null, 1); // dijit._Widget
  25917. },
  25918. _getLastFocusableChild: function(){
  25919. // summary:
  25920. // Returns last child that can be focused
  25921. return this._getNextFocusableChild(null, -1); // dijit._Widget
  25922. },
  25923. _getNextFocusableChild: function(child, dir){
  25924. // summary:
  25925. // Returns the next or previous focusable child, compared
  25926. // to "child"
  25927. // child: Widget
  25928. // The current widget
  25929. // dir: Integer
  25930. // * 1 = after
  25931. // * -1 = before
  25932. if(child){
  25933. child = this._getSiblingOfChild(child, dir);
  25934. }
  25935. var children = this.getChildren();
  25936. for(var i=0; i < children.length; i++){
  25937. if(!child){
  25938. child = children[(dir>0) ? 0 : (children.length-1)];
  25939. }
  25940. if(child.isFocusable()){
  25941. return child; // dijit._Widget
  25942. }
  25943. child = this._getSiblingOfChild(child, dir);
  25944. }
  25945. // no focusable child found
  25946. return null; // dijit._Widget
  25947. }
  25948. });
  25949. });
  25950. },
  25951. 'dijit/form/DataList':function(){
  25952. define("dijit/form/DataList", [
  25953. "dojo/_base/declare", // declare
  25954. "dojo/dom", // dom.byId
  25955. "dojo/_base/lang", // lang.trim
  25956. "dojo/query", // query
  25957. "dojo/store/Memory", // dojo.store.Memory
  25958. "../registry" // registry.add registry.remove
  25959. ], function(declare, dom, lang, query, MemoryStore, registry){
  25960. // module:
  25961. // dijit/form/DataList
  25962. // summary:
  25963. // Inefficient but small data store specialized for inlined data via OPTION tags
  25964. function toItem(/*DOMNode*/ option){
  25965. // summary:
  25966. // Convert <option> node to hash
  25967. return {
  25968. id: option.value,
  25969. value: option.value,
  25970. name: lang.trim(option.innerText || option.textContent || '')
  25971. };
  25972. }
  25973. return declare("dijit.form.DataList", MemoryStore, {
  25974. // summary:
  25975. // Inefficient but small data store specialized for inlined data via OPTION tags
  25976. //
  25977. // description:
  25978. // Provides a store for inlined data like:
  25979. //
  25980. // | <datalist>
  25981. // | <option value="AL">Alabama</option>
  25982. // | ...
  25983. constructor: function(/*Object?*/ params, /*DomNode|String*/ srcNodeRef){
  25984. // store pointer to original DOM tree
  25985. this.domNode = dom.byId(srcNodeRef);
  25986. lang.mixin(this, params);
  25987. if(this.id){
  25988. registry.add(this); // add to registry so it can be easily found by id
  25989. }
  25990. this.domNode.style.display = "none";
  25991. this.inherited(arguments, [{
  25992. data: query("option", this.domNode).map(toItem)
  25993. }]);
  25994. },
  25995. destroy: function(){
  25996. registry.remove(this.id);
  25997. },
  25998. fetchSelectedItem: function(){
  25999. // summary:
  26000. // Get the option marked as selected, like `<option selected>`.
  26001. // Not part of dojo.data API.
  26002. var option = query("> option[selected]", this.domNode)[0] || query("> option", this.domNode)[0];
  26003. return option && toItem(option);
  26004. }
  26005. });
  26006. });
  26007. },
  26008. 'dojox/timing/_base':function(){
  26009. define("dojox/timing/_base", ["dojo/_base/kernel", "dojo/_base/lang"], function(dojo){
  26010. dojo.experimental("dojox.timing");
  26011. dojo.getObject("timing", true, dojox);
  26012. dojox.timing.Timer = function(/*int*/ interval){
  26013. // summary: Timer object executes an "onTick()" method repeatedly at a specified interval.
  26014. // repeatedly at a given interval.
  26015. // interval: Interval between function calls, in milliseconds.
  26016. this.timer = null;
  26017. this.isRunning = false;
  26018. this.interval = interval;
  26019. this.onStart = null;
  26020. this.onStop = null;
  26021. };
  26022. dojo.extend(dojox.timing.Timer, {
  26023. onTick: function(){
  26024. // summary: Method called every time the interval passes. Override to do something useful.
  26025. },
  26026. setInterval: function(interval){
  26027. // summary: Reset the interval of a timer, whether running or not.
  26028. // interval: New interval, in milliseconds.
  26029. if (this.isRunning){
  26030. window.clearInterval(this.timer);
  26031. }
  26032. this.interval = interval;
  26033. if (this.isRunning){
  26034. this.timer = window.setInterval(dojo.hitch(this, "onTick"), this.interval);
  26035. }
  26036. },
  26037. start: function(){
  26038. // summary: Start the timer ticking.
  26039. // description: Calls the "onStart()" handler, if defined.
  26040. // Note that the onTick() function is not called right away,
  26041. // only after first interval passes.
  26042. if (typeof this.onStart == "function"){
  26043. this.onStart();
  26044. }
  26045. this.isRunning = true;
  26046. this.timer = window.setInterval(dojo.hitch(this, "onTick"), this.interval);
  26047. },
  26048. stop: function(){
  26049. // summary: Stop the timer.
  26050. // description: Calls the "onStop()" handler, if defined.
  26051. if (typeof this.onStop == "function"){
  26052. this.onStop();
  26053. }
  26054. this.isRunning = false;
  26055. window.clearInterval(this.timer);
  26056. }
  26057. });
  26058. return dojox.timing;
  26059. });
  26060. },
  26061. 'dijit/form/CheckBox':function(){
  26062. require({cache:{
  26063. 'url:dijit/form/templates/CheckBox.html':"<div class=\"dijit dijitReset dijitInline\" role=\"presentation\"\r\n\t><input\r\n\t \t${!nameAttrSetting} type=\"${type}\" ${checkedAttrSetting}\r\n\t\tclass=\"dijitReset dijitCheckBoxInput\"\r\n\t\tdata-dojo-attach-point=\"focusNode\"\r\n\t \tdata-dojo-attach-event=\"onclick:_onClick\"\r\n/></div>\r\n"}});
  26064. define("dijit/form/CheckBox", [
  26065. "require",
  26066. "dojo/_base/declare", // declare
  26067. "dojo/dom-attr", // domAttr.set
  26068. "dojo/_base/kernel",
  26069. "dojo/query", // query
  26070. "dojo/ready",
  26071. "./ToggleButton",
  26072. "./_CheckBoxMixin",
  26073. "dojo/text!./templates/CheckBox.html",
  26074. "dojo/NodeList-dom" // NodeList.addClass/removeClass
  26075. ], function(require, declare, domAttr, kernel, query, ready, ToggleButton, _CheckBoxMixin, template){
  26076. /*=====
  26077. var ToggleButton = dijit.form.ToggleButton;
  26078. var _CheckBoxMixin = dijit.form._CheckBoxMixin;
  26079. =====*/
  26080. // module:
  26081. // dijit/form/CheckBox
  26082. // summary:
  26083. // Checkbox widget
  26084. // Back compat w/1.6, remove for 2.0
  26085. if(!kernel.isAsync){
  26086. ready(0, function(){
  26087. var requires = ["dijit/form/RadioButton"];
  26088. require(requires); // use indirection so modules not rolled into a build
  26089. });
  26090. }
  26091. return declare("dijit.form.CheckBox", [ToggleButton, _CheckBoxMixin], {
  26092. // summary:
  26093. // Same as an HTML checkbox, but with fancy styling.
  26094. //
  26095. // description:
  26096. // User interacts with real html inputs.
  26097. // On onclick (which occurs by mouse click, space-bar, or
  26098. // using the arrow keys to switch the selected radio button),
  26099. // we update the state of the checkbox/radio.
  26100. //
  26101. // There are two modes:
  26102. // 1. High contrast mode
  26103. // 2. Normal mode
  26104. //
  26105. // In case 1, the regular html inputs are shown and used by the user.
  26106. // In case 2, the regular html inputs are invisible but still used by
  26107. // the user. They are turned quasi-invisible and overlay the background-image.
  26108. templateString: template,
  26109. baseClass: "dijitCheckBox",
  26110. _setValueAttr: function(/*String|Boolean*/ newValue, /*Boolean*/ priorityChange){
  26111. // summary:
  26112. // Handler for value= attribute to constructor, and also calls to
  26113. // set('value', val).
  26114. // description:
  26115. // During initialization, just saves as attribute to the <input type=checkbox>.
  26116. //
  26117. // After initialization,
  26118. // when passed a boolean, controls whether or not the CheckBox is checked.
  26119. // If passed a string, changes the value attribute of the CheckBox (the one
  26120. // specified as "value" when the CheckBox was constructed (ex: <input
  26121. // data-dojo-type="dijit.CheckBox" value="chicken">)
  26122. // widget.set('value', string) will check the checkbox and change the value to the
  26123. // specified string
  26124. // widget.set('value', boolean) will change the checked state.
  26125. if(typeof newValue == "string"){
  26126. this._set("value", newValue);
  26127. domAttr.set(this.focusNode, 'value', newValue);
  26128. newValue = true;
  26129. }
  26130. if(this._created){
  26131. this.set('checked', newValue, priorityChange);
  26132. }
  26133. },
  26134. _getValueAttr: function(){
  26135. // summary:
  26136. // Hook so get('value') works.
  26137. // description:
  26138. // If the CheckBox is checked, returns the value attribute.
  26139. // Otherwise returns false.
  26140. return (this.checked ? this.value : false);
  26141. },
  26142. // Override behavior from Button, since we don't have an iconNode
  26143. _setIconClassAttr: null,
  26144. postMixInProperties: function(){
  26145. this.inherited(arguments);
  26146. // Need to set initial checked state as part of template, so that form submit works.
  26147. // domAttr.set(node, "checked", bool) doesn't work on IE until node has been attached
  26148. // to <body>, see #8666
  26149. this.checkedAttrSetting = this.checked ? "checked" : "";
  26150. },
  26151. _fillContent: function(){
  26152. // Override Button::_fillContent() since it doesn't make sense for CheckBox,
  26153. // since CheckBox doesn't even have a container
  26154. },
  26155. _onFocus: function(){
  26156. if(this.id){
  26157. query("label[for='"+this.id+"']").addClass("dijitFocusedLabel");
  26158. }
  26159. this.inherited(arguments);
  26160. },
  26161. _onBlur: function(){
  26162. if(this.id){
  26163. query("label[for='"+this.id+"']").removeClass("dijitFocusedLabel");
  26164. }
  26165. this.inherited(arguments);
  26166. }
  26167. });
  26168. });
  26169. },
  26170. 'dijit/_editor/_Plugin':function(){
  26171. define("dijit/_editor/_Plugin", [
  26172. "dojo/_base/connect", // connect.connect
  26173. "dojo/_base/declare", // declare
  26174. "dojo/_base/lang", // lang.mixin, lang.hitch
  26175. "../form/Button"
  26176. ], function(connect, declare, lang, Button){
  26177. // module:
  26178. // dijit/_editor/_Plugin
  26179. // summary:
  26180. // Base class for a "plugin" to the editor, which is usually
  26181. // a single button on the Toolbar and some associated code
  26182. var _Plugin = declare("dijit._editor._Plugin", null, {
  26183. // summary:
  26184. // Base class for a "plugin" to the editor, which is usually
  26185. // a single button on the Toolbar and some associated code
  26186. constructor: function(/*Object?*/args){
  26187. this.params = args || {};
  26188. lang.mixin(this, this.params);
  26189. this._connects=[];
  26190. this._attrPairNames = {};
  26191. },
  26192. // editor: [const] dijit.Editor
  26193. // Points to the parent editor
  26194. editor: null,
  26195. // iconClassPrefix: [const] String
  26196. // The CSS class name for the button node is formed from `iconClassPrefix` and `command`
  26197. iconClassPrefix: "dijitEditorIcon",
  26198. // button: dijit._Widget?
  26199. // Pointer to `dijit.form.Button` or other widget (ex: `dijit.form.FilteringSelect`)
  26200. // that is added to the toolbar to control this plugin.
  26201. // If not specified, will be created on initialization according to `buttonClass`
  26202. button: null,
  26203. // command: String
  26204. // String like "insertUnorderedList", "outdent", "justifyCenter", etc. that represents an editor command.
  26205. // Passed to editor.execCommand() if `useDefaultCommand` is true.
  26206. command: "",
  26207. // useDefaultCommand: Boolean
  26208. // If true, this plugin executes by calling Editor.execCommand() with the argument specified in `command`.
  26209. useDefaultCommand: true,
  26210. // buttonClass: Widget Class
  26211. // Class of widget (ex: dijit.form.Button or dijit.form.FilteringSelect)
  26212. // that is added to the toolbar to control this plugin.
  26213. // This is used to instantiate the button, unless `button` itself is specified directly.
  26214. buttonClass: Button,
  26215. // disabled: Boolean
  26216. // Flag to indicate if this plugin has been disabled and should do nothing
  26217. // helps control button state, among other things. Set via the setter api.
  26218. disabled: false,
  26219. getLabel: function(/*String*/key){
  26220. // summary:
  26221. // Returns the label to use for the button
  26222. // tags:
  26223. // private
  26224. return this.editor.commands[key]; // String
  26225. },
  26226. _initButton: function(){
  26227. // summary:
  26228. // Initialize the button or other widget that will control this plugin.
  26229. // This code only works for plugins controlling built-in commands in the editor.
  26230. // tags:
  26231. // protected extension
  26232. if(this.command.length){
  26233. var label = this.getLabel(this.command),
  26234. editor = this.editor,
  26235. className = this.iconClassPrefix+" "+this.iconClassPrefix + this.command.charAt(0).toUpperCase() + this.command.substr(1);
  26236. if(!this.button){
  26237. var props = lang.mixin({
  26238. label: label,
  26239. dir: editor.dir,
  26240. lang: editor.lang,
  26241. showLabel: false,
  26242. iconClass: className,
  26243. dropDown: this.dropDown,
  26244. tabIndex: "-1"
  26245. }, this.params || {});
  26246. this.button = new this.buttonClass(props);
  26247. }
  26248. }
  26249. if(this.get("disabled") && this.button){
  26250. this.button.set("disabled", this.get("disabled"));
  26251. }
  26252. },
  26253. destroy: function(){
  26254. // summary:
  26255. // Destroy this plugin
  26256. var h;
  26257. while(h = this._connects.pop()){ h.remove(); }
  26258. if(this.dropDown){
  26259. this.dropDown.destroyRecursive();
  26260. }
  26261. },
  26262. connect: function(o, f, tf){
  26263. // summary:
  26264. // Make a connect.connect() that is automatically disconnected when this plugin is destroyed.
  26265. // Similar to `dijit._Widget.connect`.
  26266. // tags:
  26267. // protected
  26268. this._connects.push(connect.connect(o, f, this, tf));
  26269. },
  26270. updateState: function(){
  26271. // summary:
  26272. // Change state of the plugin to respond to events in the editor.
  26273. // description:
  26274. // This is called on meaningful events in the editor, such as change of selection
  26275. // or caret position (but not simple typing of alphanumeric keys). It gives the
  26276. // plugin a chance to update the CSS of its button.
  26277. //
  26278. // For example, the "bold" plugin will highlight/unhighlight the bold button depending on whether the
  26279. // characters next to the caret are bold or not.
  26280. //
  26281. // Only makes sense when `useDefaultCommand` is true, as it calls Editor.queryCommandEnabled(`command`).
  26282. var e = this.editor,
  26283. c = this.command,
  26284. checked, enabled;
  26285. if(!e || !e.isLoaded || !c.length){ return; }
  26286. var disabled = this.get("disabled");
  26287. if(this.button){
  26288. try{
  26289. enabled = !disabled && e.queryCommandEnabled(c);
  26290. if(this.enabled !== enabled){
  26291. this.enabled = enabled;
  26292. this.button.set('disabled', !enabled);
  26293. }
  26294. if(typeof this.button.checked == 'boolean'){
  26295. checked = e.queryCommandState(c);
  26296. if(this.checked !== checked){
  26297. this.checked = checked;
  26298. this.button.set('checked', e.queryCommandState(c));
  26299. }
  26300. }
  26301. }catch(e){
  26302. console.log(e); // FIXME: we shouldn't have debug statements in our code. Log as an error?
  26303. }
  26304. }
  26305. },
  26306. setEditor: function(/*dijit.Editor*/ editor){
  26307. // summary:
  26308. // Tell the plugin which Editor it is associated with.
  26309. // TODO: refactor code to just pass editor to constructor.
  26310. // FIXME: detach from previous editor!!
  26311. this.editor = editor;
  26312. // FIXME: prevent creating this if we don't need to (i.e., editor can't handle our command)
  26313. this._initButton();
  26314. // Processing for buttons that execute by calling editor.execCommand()
  26315. if(this.button && this.useDefaultCommand){
  26316. if(this.editor.queryCommandAvailable(this.command)){
  26317. this.connect(this.button, "onClick",
  26318. lang.hitch(this.editor, "execCommand", this.command, this.commandArg)
  26319. );
  26320. }else{
  26321. // hide button because editor doesn't support command (due to browser limitations)
  26322. this.button.domNode.style.display = "none";
  26323. }
  26324. }
  26325. this.connect(this.editor, "onNormalizedDisplayChanged", "updateState");
  26326. },
  26327. setToolbar: function(/*dijit.Toolbar*/ toolbar){
  26328. // summary:
  26329. // Tell the plugin to add it's controller widget (often a button)
  26330. // to the toolbar. Does nothing if there is no controller widget.
  26331. // TODO: refactor code to just pass toolbar to constructor.
  26332. if(this.button){
  26333. toolbar.addChild(this.button);
  26334. }
  26335. // console.debug("adding", this.button, "to:", toolbar);
  26336. },
  26337. set: function(/* attribute */ name, /* anything */ value){
  26338. // summary:
  26339. // Set a property on a plugin
  26340. // name:
  26341. // The property to set.
  26342. // value:
  26343. // The value to set in the property.
  26344. // description:
  26345. // Sets named properties on a plugin which may potentially be handled by a
  26346. // setter in the plugin.
  26347. // For example, if the plugin has a properties "foo"
  26348. // and "bar" and a method named "_setFooAttr", calling:
  26349. // | plugin.set("foo", "Howdy!");
  26350. // would be equivalent to writing:
  26351. // | plugin._setFooAttr("Howdy!");
  26352. // and:
  26353. // | plugin.set("bar", 3);
  26354. // would be equivalent to writing:
  26355. // | plugin.bar = 3;
  26356. //
  26357. // set() may also be called with a hash of name/value pairs, ex:
  26358. // | plugin.set({
  26359. // | foo: "Howdy",
  26360. // | bar: 3
  26361. // | })
  26362. // This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
  26363. if(typeof name === "object"){
  26364. for(var x in name){
  26365. this.set(x, name[x]);
  26366. }
  26367. return this;
  26368. }
  26369. var names = this._getAttrNames(name);
  26370. if(this[names.s]){
  26371. // use the explicit setter
  26372. var result = this[names.s].apply(this, Array.prototype.slice.call(arguments, 1));
  26373. }else{
  26374. this._set(name, value);
  26375. }
  26376. return result || this;
  26377. },
  26378. get: function(name){
  26379. // summary:
  26380. // Get a property from a plugin.
  26381. // name:
  26382. // The property to get.
  26383. // description:
  26384. // Get a named property from a plugin. The property may
  26385. // potentially be retrieved via a getter method. If no getter is defined, this
  26386. // just retrieves the object's property.
  26387. // For example, if the plugin has a properties "foo"
  26388. // and "bar" and a method named "_getFooAttr", calling:
  26389. // | plugin.get("foo");
  26390. // would be equivalent to writing:
  26391. // | plugin._getFooAttr();
  26392. // and:
  26393. // | plugin.get("bar");
  26394. // would be equivalent to writing:
  26395. // | plugin.bar;
  26396. var names = this._getAttrNames(name);
  26397. return this[names.g] ? this[names.g]() : this[name];
  26398. },
  26399. _setDisabledAttr: function(disabled){
  26400. // summary:
  26401. // Function to set the plugin state and call updateState to make sure the
  26402. // button is updated appropriately.
  26403. this.disabled = disabled;
  26404. this.updateState();
  26405. },
  26406. _getAttrNames: function(name){
  26407. // summary:
  26408. // Helper function for get() and set().
  26409. // Caches attribute name values so we don't do the string ops every time.
  26410. // tags:
  26411. // private
  26412. var apn = this._attrPairNames;
  26413. if(apn[name]){ return apn[name]; }
  26414. var uc = name.charAt(0).toUpperCase() + name.substr(1);
  26415. return (apn[name] = {
  26416. s: "_set"+uc+"Attr",
  26417. g: "_get"+uc+"Attr"
  26418. });
  26419. },
  26420. _set: function(/*String*/ name, /*anything*/ value){
  26421. // summary:
  26422. // Helper function to set new value for specified attribute
  26423. this[name] = value;
  26424. }
  26425. });
  26426. // Hash mapping plugin name to factory, used for registering plugins
  26427. _Plugin.registry = {};
  26428. return _Plugin;
  26429. });
  26430. },
  26431. 'dijit/_Container':function(){
  26432. define("dijit/_Container", [
  26433. "dojo/_base/array", // array.forEach array.indexOf
  26434. "dojo/_base/declare", // declare
  26435. "dojo/dom-construct", // domConstruct.place
  26436. "./registry" // registry.byNode()
  26437. ], function(array, declare, domConstruct, registry){
  26438. // module:
  26439. // dijit/_Container
  26440. // summary:
  26441. // Mixin for widgets that contain a set of widget children.
  26442. return declare("dijit._Container", null, {
  26443. // summary:
  26444. // Mixin for widgets that contain a set of widget children.
  26445. // description:
  26446. // Use this mixin for widgets that needs to know about and
  26447. // keep track of their widget children. Suitable for widgets like BorderContainer
  26448. // and TabContainer which contain (only) a set of child widgets.
  26449. //
  26450. // It's not suitable for widgets like ContentPane
  26451. // which contains mixed HTML (plain DOM nodes in addition to widgets),
  26452. // and where contained widgets are not necessarily directly below
  26453. // this.containerNode. In that case calls like addChild(node, position)
  26454. // wouldn't make sense.
  26455. buildRendering: function(){
  26456. this.inherited(arguments);
  26457. if(!this.containerNode){
  26458. // all widgets with descendants must set containerNode
  26459. this.containerNode = this.domNode;
  26460. }
  26461. },
  26462. addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){
  26463. // summary:
  26464. // Makes the given widget a child of this widget.
  26465. // description:
  26466. // Inserts specified child widget's dom node as a child of this widget's
  26467. // container node, and possibly does other processing (such as layout).
  26468. var refNode = this.containerNode;
  26469. if(insertIndex && typeof insertIndex == "number"){
  26470. var children = this.getChildren();
  26471. if(children && children.length >= insertIndex){
  26472. refNode = children[insertIndex-1].domNode;
  26473. insertIndex = "after";
  26474. }
  26475. }
  26476. domConstruct.place(widget.domNode, refNode, insertIndex);
  26477. // If I've been started but the child widget hasn't been started,
  26478. // start it now. Make sure to do this after widget has been
  26479. // inserted into the DOM tree, so it can see that it's being controlled by me,
  26480. // so it doesn't try to size itself.
  26481. if(this._started && !widget._started){
  26482. widget.startup();
  26483. }
  26484. },
  26485. removeChild: function(/*Widget|int*/ widget){
  26486. // summary:
  26487. // Removes the passed widget instance from this widget but does
  26488. // not destroy it. You can also pass in an integer indicating
  26489. // the index within the container to remove
  26490. if(typeof widget == "number"){
  26491. widget = this.getChildren()[widget];
  26492. }
  26493. if(widget){
  26494. var node = widget.domNode;
  26495. if(node && node.parentNode){
  26496. node.parentNode.removeChild(node); // detach but don't destroy
  26497. }
  26498. }
  26499. },
  26500. hasChildren: function(){
  26501. // summary:
  26502. // Returns true if widget has children, i.e. if this.containerNode contains something.
  26503. return this.getChildren().length > 0; // Boolean
  26504. },
  26505. _getSiblingOfChild: function(/*dijit._Widget*/ child, /*int*/ dir){
  26506. // summary:
  26507. // Get the next or previous widget sibling of child
  26508. // dir:
  26509. // if 1, get the next sibling
  26510. // if -1, get the previous sibling
  26511. // tags:
  26512. // private
  26513. var node = child.domNode,
  26514. which = (dir>0 ? "nextSibling" : "previousSibling");
  26515. do{
  26516. node = node[which];
  26517. }while(node && (node.nodeType != 1 || !registry.byNode(node)));
  26518. return node && registry.byNode(node); // dijit._Widget
  26519. },
  26520. getIndexOfChild: function(/*dijit._Widget*/ child){
  26521. // summary:
  26522. // Gets the index of the child in this container or -1 if not found
  26523. return array.indexOf(this.getChildren(), child); // int
  26524. }
  26525. });
  26526. });
  26527. },
  26528. 'dojo/dnd/Source':function(){
  26529. define("dojo/dnd/Source", ["../main", "./Selector", "./Manager"], function(dojo, Selector, Manager) {
  26530. // module:
  26531. // dojo/dnd/Source
  26532. // summary:
  26533. // TODOC
  26534. /*=====
  26535. Selector = dojo.dnd.Selector;
  26536. =====*/
  26537. /*
  26538. Container property:
  26539. "Horizontal"- if this is the horizontal container
  26540. Source states:
  26541. "" - normal state
  26542. "Moved" - this source is being moved
  26543. "Copied" - this source is being copied
  26544. Target states:
  26545. "" - normal state
  26546. "Disabled" - the target cannot accept an avatar
  26547. Target anchor state:
  26548. "" - item is not selected
  26549. "Before" - insert point is before the anchor
  26550. "After" - insert point is after the anchor
  26551. */
  26552. /*=====
  26553. dojo.dnd.__SourceArgs = function(){
  26554. // summary:
  26555. // a dict of parameters for DnD Source configuration. Note that any
  26556. // property on Source elements may be configured, but this is the
  26557. // short-list
  26558. // isSource: Boolean?
  26559. // can be used as a DnD source. Defaults to true.
  26560. // accept: Array?
  26561. // list of accepted types (text strings) for a target; defaults to
  26562. // ["text"]
  26563. // autoSync: Boolean
  26564. // if true refreshes the node list on every operation; false by default
  26565. // copyOnly: Boolean?
  26566. // copy items, if true, use a state of Ctrl key otherwise,
  26567. // see selfCopy and selfAccept for more details
  26568. // delay: Number
  26569. // the move delay in pixels before detecting a drag; 0 by default
  26570. // horizontal: Boolean?
  26571. // a horizontal container, if true, vertical otherwise or when omitted
  26572. // selfCopy: Boolean?
  26573. // copy items by default when dropping on itself,
  26574. // false by default, works only if copyOnly is true
  26575. // selfAccept: Boolean?
  26576. // accept its own items when copyOnly is true,
  26577. // true by default, works only if copyOnly is true
  26578. // withHandles: Boolean?
  26579. // allows dragging only by handles, false by default
  26580. // generateText: Boolean?
  26581. // generate text node for drag and drop, true by default
  26582. this.isSource = isSource;
  26583. this.accept = accept;
  26584. this.autoSync = autoSync;
  26585. this.copyOnly = copyOnly;
  26586. this.delay = delay;
  26587. this.horizontal = horizontal;
  26588. this.selfCopy = selfCopy;
  26589. this.selfAccept = selfAccept;
  26590. this.withHandles = withHandles;
  26591. this.generateText = true;
  26592. }
  26593. =====*/
  26594. // For back-compat, remove in 2.0.
  26595. if(!dojo.isAsync){
  26596. dojo.ready(0, function(){
  26597. var requires = ["dojo/dnd/AutoSource", "dojo/dnd/Target"];
  26598. require(requires); // use indirection so modules not rolled into a build
  26599. })
  26600. }
  26601. return dojo.declare("dojo.dnd.Source", Selector, {
  26602. // summary:
  26603. // a Source object, which can be used as a DnD source, or a DnD target
  26604. // object attributes (for markup)
  26605. isSource: true,
  26606. horizontal: false,
  26607. copyOnly: false,
  26608. selfCopy: false,
  26609. selfAccept: true,
  26610. skipForm: false,
  26611. withHandles: false,
  26612. autoSync: false,
  26613. delay: 0, // pixels
  26614. accept: ["text"],
  26615. generateText: true,
  26616. constructor: function(/*DOMNode|String*/node, /*dojo.dnd.__SourceArgs?*/params){
  26617. // summary:
  26618. // a constructor of the Source
  26619. // node:
  26620. // node or node's id to build the source on
  26621. // params:
  26622. // any property of this class may be configured via the params
  26623. // object which is mixed-in to the `dojo.dnd.Source` instance
  26624. dojo.mixin(this, dojo.mixin({}, params));
  26625. var type = this.accept;
  26626. if(type.length){
  26627. this.accept = {};
  26628. for(var i = 0; i < type.length; ++i){
  26629. this.accept[type[i]] = 1;
  26630. }
  26631. }
  26632. // class-specific variables
  26633. this.isDragging = false;
  26634. this.mouseDown = false;
  26635. this.targetAnchor = null;
  26636. this.targetBox = null;
  26637. this.before = true;
  26638. this._lastX = 0;
  26639. this._lastY = 0;
  26640. // states
  26641. this.sourceState = "";
  26642. if(this.isSource){
  26643. dojo.addClass(this.node, "dojoDndSource");
  26644. }
  26645. this.targetState = "";
  26646. if(this.accept){
  26647. dojo.addClass(this.node, "dojoDndTarget");
  26648. }
  26649. if(this.horizontal){
  26650. dojo.addClass(this.node, "dojoDndHorizontal");
  26651. }
  26652. // set up events
  26653. this.topics = [
  26654. dojo.subscribe("/dnd/source/over", this, "onDndSourceOver"),
  26655. dojo.subscribe("/dnd/start", this, "onDndStart"),
  26656. dojo.subscribe("/dnd/drop", this, "onDndDrop"),
  26657. dojo.subscribe("/dnd/cancel", this, "onDndCancel")
  26658. ];
  26659. },
  26660. // methods
  26661. checkAcceptance: function(source, nodes){
  26662. // summary:
  26663. // checks if the target can accept nodes from this source
  26664. // source: Object
  26665. // the source which provides items
  26666. // nodes: Array
  26667. // the list of transferred items
  26668. if(this == source){
  26669. return !this.copyOnly || this.selfAccept;
  26670. }
  26671. for(var i = 0; i < nodes.length; ++i){
  26672. var type = source.getItem(nodes[i].id).type;
  26673. // type instanceof Array
  26674. var flag = false;
  26675. for(var j = 0; j < type.length; ++j){
  26676. if(type[j] in this.accept){
  26677. flag = true;
  26678. break;
  26679. }
  26680. }
  26681. if(!flag){
  26682. return false; // Boolean
  26683. }
  26684. }
  26685. return true; // Boolean
  26686. },
  26687. copyState: function(keyPressed, self){
  26688. // summary:
  26689. // Returns true if we need to copy items, false to move.
  26690. // It is separated to be overwritten dynamically, if needed.
  26691. // keyPressed: Boolean
  26692. // the "copy" key was pressed
  26693. // self: Boolean?
  26694. // optional flag that means that we are about to drop on itself
  26695. if(keyPressed){ return true; }
  26696. if(arguments.length < 2){
  26697. self = this == Manager.manager().target;
  26698. }
  26699. if(self){
  26700. if(this.copyOnly){
  26701. return this.selfCopy;
  26702. }
  26703. }else{
  26704. return this.copyOnly;
  26705. }
  26706. return false; // Boolean
  26707. },
  26708. destroy: function(){
  26709. // summary:
  26710. // prepares the object to be garbage-collected
  26711. dojo.dnd.Source.superclass.destroy.call(this);
  26712. dojo.forEach(this.topics, dojo.unsubscribe);
  26713. this.targetAnchor = null;
  26714. },
  26715. // mouse event processors
  26716. onMouseMove: function(e){
  26717. // summary:
  26718. // event processor for onmousemove
  26719. // e: Event
  26720. // mouse event
  26721. if(this.isDragging && this.targetState == "Disabled"){ return; }
  26722. dojo.dnd.Source.superclass.onMouseMove.call(this, e);
  26723. var m = Manager.manager();
  26724. if(!this.isDragging){
  26725. if(this.mouseDown && this.isSource &&
  26726. (Math.abs(e.pageX - this._lastX) > this.delay || Math.abs(e.pageY - this._lastY) > this.delay)){
  26727. var nodes = this.getSelectedNodes();
  26728. if(nodes.length){
  26729. m.startDrag(this, nodes, this.copyState(dojo.isCopyKey(e), true));
  26730. }
  26731. }
  26732. }
  26733. if(this.isDragging){
  26734. // calculate before/after
  26735. var before = false;
  26736. if(this.current){
  26737. if(!this.targetBox || this.targetAnchor != this.current){
  26738. this.targetBox = dojo.position(this.current, true);
  26739. }
  26740. if(this.horizontal){
  26741. before = (e.pageX - this.targetBox.x) < (this.targetBox.w / 2);
  26742. }else{
  26743. before = (e.pageY - this.targetBox.y) < (this.targetBox.h / 2);
  26744. }
  26745. }
  26746. if(this.current != this.targetAnchor || before != this.before){
  26747. this._markTargetAnchor(before);
  26748. m.canDrop(!this.current || m.source != this || !(this.current.id in this.selection));
  26749. }
  26750. }
  26751. },
  26752. onMouseDown: function(e){
  26753. // summary:
  26754. // event processor for onmousedown
  26755. // e: Event
  26756. // mouse event
  26757. if(!this.mouseDown && this._legalMouseDown(e) && (!this.skipForm || !dojo.dnd.isFormElement(e))){
  26758. this.mouseDown = true;
  26759. this._lastX = e.pageX;
  26760. this._lastY = e.pageY;
  26761. dojo.dnd.Source.superclass.onMouseDown.call(this, e);
  26762. }
  26763. },
  26764. onMouseUp: function(e){
  26765. // summary:
  26766. // event processor for onmouseup
  26767. // e: Event
  26768. // mouse event
  26769. if(this.mouseDown){
  26770. this.mouseDown = false;
  26771. dojo.dnd.Source.superclass.onMouseUp.call(this, e);
  26772. }
  26773. },
  26774. // topic event processors
  26775. onDndSourceOver: function(source){
  26776. // summary:
  26777. // topic event processor for /dnd/source/over, called when detected a current source
  26778. // source: Object
  26779. // the source which has the mouse over it
  26780. if(this != source){
  26781. this.mouseDown = false;
  26782. if(this.targetAnchor){
  26783. this._unmarkTargetAnchor();
  26784. }
  26785. }else if(this.isDragging){
  26786. var m = Manager.manager();
  26787. m.canDrop(this.targetState != "Disabled" && (!this.current || m.source != this || !(this.current.id in this.selection)));
  26788. }
  26789. },
  26790. onDndStart: function(source, nodes, copy){
  26791. // summary:
  26792. // topic event processor for /dnd/start, called to initiate the DnD operation
  26793. // source: Object
  26794. // the source which provides items
  26795. // nodes: Array
  26796. // the list of transferred items
  26797. // copy: Boolean
  26798. // copy items, if true, move items otherwise
  26799. if(this.autoSync){ this.sync(); }
  26800. if(this.isSource){
  26801. this._changeState("Source", this == source ? (copy ? "Copied" : "Moved") : "");
  26802. }
  26803. var accepted = this.accept && this.checkAcceptance(source, nodes);
  26804. this._changeState("Target", accepted ? "" : "Disabled");
  26805. if(this == source){
  26806. Manager.manager().overSource(this);
  26807. }
  26808. this.isDragging = true;
  26809. },
  26810. onDndDrop: function(source, nodes, copy, target){
  26811. // summary:
  26812. // topic event processor for /dnd/drop, called to finish the DnD operation
  26813. // source: Object
  26814. // the source which provides items
  26815. // nodes: Array
  26816. // the list of transferred items
  26817. // copy: Boolean
  26818. // copy items, if true, move items otherwise
  26819. // target: Object
  26820. // the target which accepts items
  26821. if(this == target){
  26822. // this one is for us => move nodes!
  26823. this.onDrop(source, nodes, copy);
  26824. }
  26825. this.onDndCancel();
  26826. },
  26827. onDndCancel: function(){
  26828. // summary:
  26829. // topic event processor for /dnd/cancel, called to cancel the DnD operation
  26830. if(this.targetAnchor){
  26831. this._unmarkTargetAnchor();
  26832. this.targetAnchor = null;
  26833. }
  26834. this.before = true;
  26835. this.isDragging = false;
  26836. this.mouseDown = false;
  26837. this._changeState("Source", "");
  26838. this._changeState("Target", "");
  26839. },
  26840. // local events
  26841. onDrop: function(source, nodes, copy){
  26842. // summary:
  26843. // called only on the current target, when drop is performed
  26844. // source: Object
  26845. // the source which provides items
  26846. // nodes: Array
  26847. // the list of transferred items
  26848. // copy: Boolean
  26849. // copy items, if true, move items otherwise
  26850. if(this != source){
  26851. this.onDropExternal(source, nodes, copy);
  26852. }else{
  26853. this.onDropInternal(nodes, copy);
  26854. }
  26855. },
  26856. onDropExternal: function(source, nodes, copy){
  26857. // summary:
  26858. // called only on the current target, when drop is performed
  26859. // from an external source
  26860. // source: Object
  26861. // the source which provides items
  26862. // nodes: Array
  26863. // the list of transferred items
  26864. // copy: Boolean
  26865. // copy items, if true, move items otherwise
  26866. var oldCreator = this._normalizedCreator;
  26867. // transferring nodes from the source to the target
  26868. if(this.creator){
  26869. // use defined creator
  26870. this._normalizedCreator = function(node, hint){
  26871. return oldCreator.call(this, source.getItem(node.id).data, hint);
  26872. };
  26873. }else{
  26874. // we have no creator defined => move/clone nodes
  26875. if(copy){
  26876. // clone nodes
  26877. this._normalizedCreator = function(node, hint){
  26878. var t = source.getItem(node.id);
  26879. var n = node.cloneNode(true);
  26880. n.id = dojo.dnd.getUniqueId();
  26881. return {node: n, data: t.data, type: t.type};
  26882. };
  26883. }else{
  26884. // move nodes
  26885. this._normalizedCreator = function(node, hint){
  26886. var t = source.getItem(node.id);
  26887. source.delItem(node.id);
  26888. return {node: node, data: t.data, type: t.type};
  26889. };
  26890. }
  26891. }
  26892. this.selectNone();
  26893. if(!copy && !this.creator){
  26894. source.selectNone();
  26895. }
  26896. this.insertNodes(true, nodes, this.before, this.current);
  26897. if(!copy && this.creator){
  26898. source.deleteSelectedNodes();
  26899. }
  26900. this._normalizedCreator = oldCreator;
  26901. },
  26902. onDropInternal: function(nodes, copy){
  26903. // summary:
  26904. // called only on the current target, when drop is performed
  26905. // from the same target/source
  26906. // nodes: Array
  26907. // the list of transferred items
  26908. // copy: Boolean
  26909. // copy items, if true, move items otherwise
  26910. var oldCreator = this._normalizedCreator;
  26911. // transferring nodes within the single source
  26912. if(this.current && this.current.id in this.selection){
  26913. // do nothing
  26914. return;
  26915. }
  26916. if(copy){
  26917. if(this.creator){
  26918. // create new copies of data items
  26919. this._normalizedCreator = function(node, hint){
  26920. return oldCreator.call(this, this.getItem(node.id).data, hint);
  26921. };
  26922. }else{
  26923. // clone nodes
  26924. this._normalizedCreator = function(node, hint){
  26925. var t = this.getItem(node.id);
  26926. var n = node.cloneNode(true);
  26927. n.id = dojo.dnd.getUniqueId();
  26928. return {node: n, data: t.data, type: t.type};
  26929. };
  26930. }
  26931. }else{
  26932. // move nodes
  26933. if(!this.current){
  26934. // do nothing
  26935. return;
  26936. }
  26937. this._normalizedCreator = function(node, hint){
  26938. var t = this.getItem(node.id);
  26939. return {node: node, data: t.data, type: t.type};
  26940. };
  26941. }
  26942. this._removeSelection();
  26943. this.insertNodes(true, nodes, this.before, this.current);
  26944. this._normalizedCreator = oldCreator;
  26945. },
  26946. onDraggingOver: function(){
  26947. // summary:
  26948. // called during the active DnD operation, when items
  26949. // are dragged over this target, and it is not disabled
  26950. },
  26951. onDraggingOut: function(){
  26952. // summary:
  26953. // called during the active DnD operation, when items
  26954. // are dragged away from this target, and it is not disabled
  26955. },
  26956. // utilities
  26957. onOverEvent: function(){
  26958. // summary:
  26959. // this function is called once, when mouse is over our container
  26960. dojo.dnd.Source.superclass.onOverEvent.call(this);
  26961. Manager.manager().overSource(this);
  26962. if(this.isDragging && this.targetState != "Disabled"){
  26963. this.onDraggingOver();
  26964. }
  26965. },
  26966. onOutEvent: function(){
  26967. // summary:
  26968. // this function is called once, when mouse is out of our container
  26969. dojo.dnd.Source.superclass.onOutEvent.call(this);
  26970. Manager.manager().outSource(this);
  26971. if(this.isDragging && this.targetState != "Disabled"){
  26972. this.onDraggingOut();
  26973. }
  26974. },
  26975. _markTargetAnchor: function(before){
  26976. // summary:
  26977. // assigns a class to the current target anchor based on "before" status
  26978. // before: Boolean
  26979. // insert before, if true, after otherwise
  26980. if(this.current == this.targetAnchor && this.before == before){ return; }
  26981. if(this.targetAnchor){
  26982. this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After");
  26983. }
  26984. this.targetAnchor = this.current;
  26985. this.targetBox = null;
  26986. this.before = before;
  26987. if(this.targetAnchor){
  26988. this._addItemClass(this.targetAnchor, this.before ? "Before" : "After");
  26989. }
  26990. },
  26991. _unmarkTargetAnchor: function(){
  26992. // summary:
  26993. // removes a class of the current target anchor based on "before" status
  26994. if(!this.targetAnchor){ return; }
  26995. this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After");
  26996. this.targetAnchor = null;
  26997. this.targetBox = null;
  26998. this.before = true;
  26999. },
  27000. _markDndStatus: function(copy){
  27001. // summary:
  27002. // changes source's state based on "copy" status
  27003. this._changeState("Source", copy ? "Copied" : "Moved");
  27004. },
  27005. _legalMouseDown: function(e){
  27006. // summary:
  27007. // checks if user clicked on "approved" items
  27008. // e: Event
  27009. // mouse event
  27010. // accept only the left mouse button
  27011. if(!dojo.mouseButtons.isLeft(e)){ return false; }
  27012. if(!this.withHandles){ return true; }
  27013. // check for handles
  27014. for(var node = e.target; node && node !== this.node; node = node.parentNode){
  27015. if(dojo.hasClass(node, "dojoDndHandle")){ return true; }
  27016. if(dojo.hasClass(node, "dojoDndItem") || dojo.hasClass(node, "dojoDndIgnore")){ break; }
  27017. }
  27018. return false; // Boolean
  27019. }
  27020. });
  27021. });
  27022. },
  27023. 'dojo/data/ItemFileReadStore':function(){
  27024. define("dojo/data/ItemFileReadStore", ["../_base/kernel", "../_base/lang", "../_base/declare", "../_base/array", "../_base/xhr",
  27025. "../Evented", "../_base/window", "./util/filter", "./util/simpleFetch", "../date/stamp"
  27026. ], function(kernel, lang, declare, array, xhr, Evented, window, filterUtil, simpleFetch, dateStamp) {
  27027. // module:
  27028. // dojo/data/ItemFileReadStore
  27029. // summary:
  27030. // TODOC
  27031. var ItemFileReadStore = declare("dojo.data.ItemFileReadStore", [Evented],{
  27032. // summary:
  27033. // The ItemFileReadStore implements the dojo.data.api.Read API and reads
  27034. // data from JSON files that have contents in this format --
  27035. // { items: [
  27036. // { name:'Kermit', color:'green', age:12, friends:['Gonzo', {_reference:{name:'Fozzie Bear'}}]},
  27037. // { name:'Fozzie Bear', wears:['hat', 'tie']},
  27038. // { name:'Miss Piggy', pets:'Foo-Foo'}
  27039. // ]}
  27040. // Note that it can also contain an 'identifer' property that specified which attribute on the items
  27041. // in the array of items that acts as the unique identifier for that item.
  27042. //
  27043. constructor: function(/* Object */ keywordParameters){
  27044. // summary: constructor
  27045. // keywordParameters: {url: String}
  27046. // keywordParameters: {data: jsonObject}
  27047. // keywordParameters: {typeMap: object)
  27048. // The structure of the typeMap object is as follows:
  27049. // {
  27050. // type0: function || object,
  27051. // type1: function || object,
  27052. // ...
  27053. // typeN: function || object
  27054. // }
  27055. // Where if it is a function, it is assumed to be an object constructor that takes the
  27056. // value of _value as the initialization parameters. If it is an object, then it is assumed
  27057. // to be an object of general form:
  27058. // {
  27059. // type: function, //constructor.
  27060. // deserialize: function(value) //The function that parses the value and constructs the object defined by type appropriately.
  27061. // }
  27062. this._arrayOfAllItems = [];
  27063. this._arrayOfTopLevelItems = [];
  27064. this._loadFinished = false;
  27065. this._jsonFileUrl = keywordParameters.url;
  27066. this._ccUrl = keywordParameters.url;
  27067. this.url = keywordParameters.url;
  27068. this._jsonData = keywordParameters.data;
  27069. this.data = null;
  27070. this._datatypeMap = keywordParameters.typeMap || {};
  27071. if(!this._datatypeMap['Date']){
  27072. //If no default mapping for dates, then set this as default.
  27073. //We use the dojo.date.stamp here because the ISO format is the 'dojo way'
  27074. //of generically representing dates.
  27075. this._datatypeMap['Date'] = {
  27076. type: Date,
  27077. deserialize: function(value){
  27078. return dateStamp.fromISOString(value);
  27079. }
  27080. };
  27081. }
  27082. this._features = {'dojo.data.api.Read':true, 'dojo.data.api.Identity':true};
  27083. this._itemsByIdentity = null;
  27084. this._storeRefPropName = "_S"; // Default name for the store reference to attach to every item.
  27085. this._itemNumPropName = "_0"; // Default Item Id for isItem to attach to every item.
  27086. this._rootItemPropName = "_RI"; // Default Item Id for isItem to attach to every item.
  27087. this._reverseRefMap = "_RRM"; // Default attribute for constructing a reverse reference map for use with reference integrity
  27088. this._loadInProgress = false; //Got to track the initial load to prevent duelling loads of the dataset.
  27089. this._queuedFetches = [];
  27090. if(keywordParameters.urlPreventCache !== undefined){
  27091. this.urlPreventCache = keywordParameters.urlPreventCache?true:false;
  27092. }
  27093. if(keywordParameters.hierarchical !== undefined){
  27094. this.hierarchical = keywordParameters.hierarchical?true:false;
  27095. }
  27096. if(keywordParameters.clearOnClose){
  27097. this.clearOnClose = true;
  27098. }
  27099. if("failOk" in keywordParameters){
  27100. this.failOk = keywordParameters.failOk?true:false;
  27101. }
  27102. },
  27103. url: "", // use "" rather than undefined for the benefit of the parser (#3539)
  27104. //Internal var, crossCheckUrl. Used so that setting either url or _jsonFileUrl, can still trigger a reload
  27105. //when clearOnClose and close is used.
  27106. _ccUrl: "",
  27107. data: null, // define this so that the parser can populate it
  27108. typeMap: null, //Define so parser can populate.
  27109. //Parameter to allow users to specify if a close call should force a reload or not.
  27110. //By default, it retains the old behavior of not clearing if close is called. But
  27111. //if set true, the store will be reset to default state. Note that by doing this,
  27112. //all item handles will become invalid and a new fetch must be issued.
  27113. clearOnClose: false,
  27114. //Parameter to allow specifying if preventCache should be passed to the xhrGet call or not when loading data from a url.
  27115. //Note this does not mean the store calls the server on each fetch, only that the data load has preventCache set as an option.
  27116. //Added for tracker: #6072
  27117. urlPreventCache: false,
  27118. //Parameter for specifying that it is OK for the xhrGet call to fail silently.
  27119. failOk: false,
  27120. //Parameter to indicate to process data from the url as hierarchical
  27121. //(data items can contain other data items in js form). Default is true
  27122. //for backwards compatibility. False means only root items are processed
  27123. //as items, all child objects outside of type-mapped objects and those in
  27124. //specific reference format, are left straight JS data objects.
  27125. hierarchical: true,
  27126. _assertIsItem: function(/* item */ item){
  27127. // summary:
  27128. // This function tests whether the item passed in is indeed an item in the store.
  27129. // item:
  27130. // The item to test for being contained by the store.
  27131. if(!this.isItem(item)){
  27132. throw new Error("dojo.data.ItemFileReadStore: Invalid item argument.");
  27133. }
  27134. },
  27135. _assertIsAttribute: function(/* attribute-name-string */ attribute){
  27136. // summary:
  27137. // This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
  27138. // attribute:
  27139. // The attribute to test for being contained by the store.
  27140. if(typeof attribute !== "string"){
  27141. throw new Error("dojo.data.ItemFileReadStore: Invalid attribute argument.");
  27142. }
  27143. },
  27144. getValue: function( /* item */ item,
  27145. /* attribute-name-string */ attribute,
  27146. /* value? */ defaultValue){
  27147. // summary:
  27148. // See dojo.data.api.Read.getValue()
  27149. var values = this.getValues(item, attribute);
  27150. return (values.length > 0)?values[0]:defaultValue; // mixed
  27151. },
  27152. getValues: function(/* item */ item,
  27153. /* attribute-name-string */ attribute){
  27154. // summary:
  27155. // See dojo.data.api.Read.getValues()
  27156. this._assertIsItem(item);
  27157. this._assertIsAttribute(attribute);
  27158. // Clone it before returning. refs: #10474
  27159. return (item[attribute] || []).slice(0); // Array
  27160. },
  27161. getAttributes: function(/* item */ item){
  27162. // summary:
  27163. // See dojo.data.api.Read.getAttributes()
  27164. this._assertIsItem(item);
  27165. var attributes = [];
  27166. for(var key in item){
  27167. // Save off only the real item attributes, not the special id marks for O(1) isItem.
  27168. if((key !== this._storeRefPropName) && (key !== this._itemNumPropName) && (key !== this._rootItemPropName) && (key !== this._reverseRefMap)){
  27169. attributes.push(key);
  27170. }
  27171. }
  27172. return attributes; // Array
  27173. },
  27174. hasAttribute: function( /* item */ item,
  27175. /* attribute-name-string */ attribute){
  27176. // summary:
  27177. // See dojo.data.api.Read.hasAttribute()
  27178. this._assertIsItem(item);
  27179. this._assertIsAttribute(attribute);
  27180. return (attribute in item);
  27181. },
  27182. containsValue: function(/* item */ item,
  27183. /* attribute-name-string */ attribute,
  27184. /* anything */ value){
  27185. // summary:
  27186. // See dojo.data.api.Read.containsValue()
  27187. var regexp = undefined;
  27188. if(typeof value === "string"){
  27189. regexp = filterUtil.patternToRegExp(value, false);
  27190. }
  27191. return this._containsValue(item, attribute, value, regexp); //boolean.
  27192. },
  27193. _containsValue: function( /* item */ item,
  27194. /* attribute-name-string */ attribute,
  27195. /* anything */ value,
  27196. /* RegExp?*/ regexp){
  27197. // summary:
  27198. // Internal function for looking at the values contained by the item.
  27199. // description:
  27200. // Internal function for looking at the values contained by the item. This
  27201. // function allows for denoting if the comparison should be case sensitive for
  27202. // strings or not (for handling filtering cases where string case should not matter)
  27203. //
  27204. // item:
  27205. // The data item to examine for attribute values.
  27206. // attribute:
  27207. // The attribute to inspect.
  27208. // value:
  27209. // The value to match.
  27210. // regexp:
  27211. // Optional regular expression generated off value if value was of string type to handle wildcarding.
  27212. // If present and attribute values are string, then it can be used for comparison instead of 'value'
  27213. return array.some(this.getValues(item, attribute), function(possibleValue){
  27214. if(possibleValue !== null && !lang.isObject(possibleValue) && regexp){
  27215. if(possibleValue.toString().match(regexp)){
  27216. return true; // Boolean
  27217. }
  27218. }else if(value === possibleValue){
  27219. return true; // Boolean
  27220. }
  27221. });
  27222. },
  27223. isItem: function(/* anything */ something){
  27224. // summary:
  27225. // See dojo.data.api.Read.isItem()
  27226. if(something && something[this._storeRefPropName] === this){
  27227. if(this._arrayOfAllItems[something[this._itemNumPropName]] === something){
  27228. return true;
  27229. }
  27230. }
  27231. return false; // Boolean
  27232. },
  27233. isItemLoaded: function(/* anything */ something){
  27234. // summary:
  27235. // See dojo.data.api.Read.isItemLoaded()
  27236. return this.isItem(something); //boolean
  27237. },
  27238. loadItem: function(/* object */ keywordArgs){
  27239. // summary:
  27240. // See dojo.data.api.Read.loadItem()
  27241. this._assertIsItem(keywordArgs.item);
  27242. },
  27243. getFeatures: function(){
  27244. // summary:
  27245. // See dojo.data.api.Read.getFeatures()
  27246. return this._features; //Object
  27247. },
  27248. getLabel: function(/* item */ item){
  27249. // summary:
  27250. // See dojo.data.api.Read.getLabel()
  27251. if(this._labelAttr && this.isItem(item)){
  27252. return this.getValue(item,this._labelAttr); //String
  27253. }
  27254. return undefined; //undefined
  27255. },
  27256. getLabelAttributes: function(/* item */ item){
  27257. // summary:
  27258. // See dojo.data.api.Read.getLabelAttributes()
  27259. if(this._labelAttr){
  27260. return [this._labelAttr]; //array
  27261. }
  27262. return null; //null
  27263. },
  27264. _fetchItems: function( /* Object */ keywordArgs,
  27265. /* Function */ findCallback,
  27266. /* Function */ errorCallback){
  27267. // summary:
  27268. // See dojo.data.util.simpleFetch.fetch()
  27269. var self = this,
  27270. filter = function(requestArgs, arrayOfItems){
  27271. var items = [],
  27272. i, key;
  27273. if(requestArgs.query){
  27274. var value,
  27275. ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false;
  27276. //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
  27277. //same value for each item examined. Much more efficient.
  27278. var regexpList = {};
  27279. for(key in requestArgs.query){
  27280. value = requestArgs.query[key];
  27281. if(typeof value === "string"){
  27282. regexpList[key] = filterUtil.patternToRegExp(value, ignoreCase);
  27283. }else if(value instanceof RegExp){
  27284. regexpList[key] = value;
  27285. }
  27286. }
  27287. for(i = 0; i < arrayOfItems.length; ++i){
  27288. var match = true;
  27289. var candidateItem = arrayOfItems[i];
  27290. if(candidateItem === null){
  27291. match = false;
  27292. }else{
  27293. for(key in requestArgs.query){
  27294. value = requestArgs.query[key];
  27295. if(!self._containsValue(candidateItem, key, value, regexpList[key])){
  27296. match = false;
  27297. }
  27298. }
  27299. }
  27300. if(match){
  27301. items.push(candidateItem);
  27302. }
  27303. }
  27304. findCallback(items, requestArgs);
  27305. }else{
  27306. // We want a copy to pass back in case the parent wishes to sort the array.
  27307. // We shouldn't allow resort of the internal list, so that multiple callers
  27308. // can get lists and sort without affecting each other. We also need to
  27309. // filter out any null values that have been left as a result of deleteItem()
  27310. // calls in ItemFileWriteStore.
  27311. for(i = 0; i < arrayOfItems.length; ++i){
  27312. var item = arrayOfItems[i];
  27313. if(item !== null){
  27314. items.push(item);
  27315. }
  27316. }
  27317. findCallback(items, requestArgs);
  27318. }
  27319. };
  27320. if(this._loadFinished){
  27321. filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
  27322. }else{
  27323. //Do a check on the JsonFileUrl and crosscheck it.
  27324. //If it doesn't match the cross-check, it needs to be updated
  27325. //This allows for either url or _jsonFileUrl to he changed to
  27326. //reset the store load location. Done this way for backwards
  27327. //compatibility. People use _jsonFileUrl (even though officially
  27328. //private.
  27329. if(this._jsonFileUrl !== this._ccUrl){
  27330. kernel.deprecated("dojo.data.ItemFileReadStore: ",
  27331. "To change the url, set the url property of the store," +
  27332. " not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");
  27333. this._ccUrl = this._jsonFileUrl;
  27334. this.url = this._jsonFileUrl;
  27335. }else if(this.url !== this._ccUrl){
  27336. this._jsonFileUrl = this.url;
  27337. this._ccUrl = this.url;
  27338. }
  27339. //See if there was any forced reset of data.
  27340. if(this.data != null){
  27341. this._jsonData = this.data;
  27342. this.data = null;
  27343. }
  27344. if(this._jsonFileUrl){
  27345. //If fetches come in before the loading has finished, but while
  27346. //a load is in progress, we have to defer the fetching to be
  27347. //invoked in the callback.
  27348. if(this._loadInProgress){
  27349. this._queuedFetches.push({args: keywordArgs, filter: filter});
  27350. }else{
  27351. this._loadInProgress = true;
  27352. var getArgs = {
  27353. url: self._jsonFileUrl,
  27354. handleAs: "json-comment-optional",
  27355. preventCache: this.urlPreventCache,
  27356. failOk: this.failOk
  27357. };
  27358. var getHandler = xhr.get(getArgs);
  27359. getHandler.addCallback(function(data){
  27360. try{
  27361. self._getItemsFromLoadedData(data);
  27362. self._loadFinished = true;
  27363. self._loadInProgress = false;
  27364. filter(keywordArgs, self._getItemsArray(keywordArgs.queryOptions));
  27365. self._handleQueuedFetches();
  27366. }catch(e){
  27367. self._loadFinished = true;
  27368. self._loadInProgress = false;
  27369. errorCallback(e, keywordArgs);
  27370. }
  27371. });
  27372. getHandler.addErrback(function(error){
  27373. self._loadInProgress = false;
  27374. errorCallback(error, keywordArgs);
  27375. });
  27376. //Wire up the cancel to abort of the request
  27377. //This call cancel on the deferred if it hasn't been called
  27378. //yet and then will chain to the simple abort of the
  27379. //simpleFetch keywordArgs
  27380. var oldAbort = null;
  27381. if(keywordArgs.abort){
  27382. oldAbort = keywordArgs.abort;
  27383. }
  27384. keywordArgs.abort = function(){
  27385. var df = getHandler;
  27386. if(df && df.fired === -1){
  27387. df.cancel();
  27388. df = null;
  27389. }
  27390. if(oldAbort){
  27391. oldAbort.call(keywordArgs);
  27392. }
  27393. };
  27394. }
  27395. }else if(this._jsonData){
  27396. try{
  27397. this._loadFinished = true;
  27398. this._getItemsFromLoadedData(this._jsonData);
  27399. this._jsonData = null;
  27400. filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
  27401. }catch(e){
  27402. errorCallback(e, keywordArgs);
  27403. }
  27404. }else{
  27405. errorCallback(new Error("dojo.data.ItemFileReadStore: No JSON source data was provided as either URL or a nested Javascript object."), keywordArgs);
  27406. }
  27407. }
  27408. },
  27409. _handleQueuedFetches: function(){
  27410. // summary:
  27411. // Internal function to execute delayed request in the store.
  27412. //Execute any deferred fetches now.
  27413. if(this._queuedFetches.length > 0){
  27414. for(var i = 0; i < this._queuedFetches.length; i++){
  27415. var fData = this._queuedFetches[i],
  27416. delayedQuery = fData.args,
  27417. delayedFilter = fData.filter;
  27418. if(delayedFilter){
  27419. delayedFilter(delayedQuery, this._getItemsArray(delayedQuery.queryOptions));
  27420. }else{
  27421. this.fetchItemByIdentity(delayedQuery);
  27422. }
  27423. }
  27424. this._queuedFetches = [];
  27425. }
  27426. },
  27427. _getItemsArray: function(/*object?*/queryOptions){
  27428. // summary:
  27429. // Internal function to determine which list of items to search over.
  27430. // queryOptions: The query options parameter, if any.
  27431. if(queryOptions && queryOptions.deep){
  27432. return this._arrayOfAllItems;
  27433. }
  27434. return this._arrayOfTopLevelItems;
  27435. },
  27436. close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
  27437. // summary:
  27438. // See dojo.data.api.Read.close()
  27439. if(this.clearOnClose &&
  27440. this._loadFinished &&
  27441. !this._loadInProgress){
  27442. //Reset all internalsback to default state. This will force a reload
  27443. //on next fetch. This also checks that the data or url param was set
  27444. //so that the store knows it can get data. Without one of those being set,
  27445. //the next fetch will trigger an error.
  27446. if(((this._jsonFileUrl == "" || this._jsonFileUrl == null) &&
  27447. (this.url == "" || this.url == null)
  27448. ) && this.data == null){
  27449. console.debug("dojo.data.ItemFileReadStore: WARNING! Data reload " +
  27450. " information has not been provided." +
  27451. " Please set 'url' or 'data' to the appropriate value before" +
  27452. " the next fetch");
  27453. }
  27454. this._arrayOfAllItems = [];
  27455. this._arrayOfTopLevelItems = [];
  27456. this._loadFinished = false;
  27457. this._itemsByIdentity = null;
  27458. this._loadInProgress = false;
  27459. this._queuedFetches = [];
  27460. }
  27461. },
  27462. _getItemsFromLoadedData: function(/* Object */ dataObject){
  27463. // summary:
  27464. // Function to parse the loaded data into item format and build the internal items array.
  27465. // description:
  27466. // Function to parse the loaded data into item format and build the internal items array.
  27467. //
  27468. // dataObject:
  27469. // The JS data object containing the raw data to convery into item format.
  27470. //
  27471. // returns: array
  27472. // Array of items in store item format.
  27473. // First, we define a couple little utility functions...
  27474. var addingArrays = false,
  27475. self = this;
  27476. function valueIsAnItem(/* anything */ aValue){
  27477. // summary:
  27478. // Given any sort of value that could be in the raw json data,
  27479. // return true if we should interpret the value as being an
  27480. // item itself, rather than a literal value or a reference.
  27481. // example:
  27482. // | false == valueIsAnItem("Kermit");
  27483. // | false == valueIsAnItem(42);
  27484. // | false == valueIsAnItem(new Date());
  27485. // | false == valueIsAnItem({_type:'Date', _value:'1802-05-14'});
  27486. // | false == valueIsAnItem({_reference:'Kermit'});
  27487. // | true == valueIsAnItem({name:'Kermit', color:'green'});
  27488. // | true == valueIsAnItem({iggy:'pop'});
  27489. // | true == valueIsAnItem({foo:42});
  27490. return (aValue !== null) &&
  27491. (typeof aValue === "object") &&
  27492. (!lang.isArray(aValue) || addingArrays) &&
  27493. (!lang.isFunction(aValue)) &&
  27494. (aValue.constructor == Object || lang.isArray(aValue)) &&
  27495. (typeof aValue._reference === "undefined") &&
  27496. (typeof aValue._type === "undefined") &&
  27497. (typeof aValue._value === "undefined") &&
  27498. self.hierarchical;
  27499. }
  27500. function addItemAndSubItemsToArrayOfAllItems(/* Item */ anItem){
  27501. self._arrayOfAllItems.push(anItem);
  27502. for(var attribute in anItem){
  27503. var valueForAttribute = anItem[attribute];
  27504. if(valueForAttribute){
  27505. if(lang.isArray(valueForAttribute)){
  27506. var valueArray = valueForAttribute;
  27507. for(var k = 0; k < valueArray.length; ++k){
  27508. var singleValue = valueArray[k];
  27509. if(valueIsAnItem(singleValue)){
  27510. addItemAndSubItemsToArrayOfAllItems(singleValue);
  27511. }
  27512. }
  27513. }else{
  27514. if(valueIsAnItem(valueForAttribute)){
  27515. addItemAndSubItemsToArrayOfAllItems(valueForAttribute);
  27516. }
  27517. }
  27518. }
  27519. }
  27520. }
  27521. this._labelAttr = dataObject.label;
  27522. // We need to do some transformations to convert the data structure
  27523. // that we read from the file into a format that will be convenient
  27524. // to work with in memory.
  27525. // Step 1: Walk through the object hierarchy and build a list of all items
  27526. var i,
  27527. item;
  27528. this._arrayOfAllItems = [];
  27529. this._arrayOfTopLevelItems = dataObject.items;
  27530. for(i = 0; i < this._arrayOfTopLevelItems.length; ++i){
  27531. item = this._arrayOfTopLevelItems[i];
  27532. if(lang.isArray(item)){
  27533. addingArrays = true;
  27534. }
  27535. addItemAndSubItemsToArrayOfAllItems(item);
  27536. item[this._rootItemPropName]=true;
  27537. }
  27538. // Step 2: Walk through all the attribute values of all the items,
  27539. // and replace single values with arrays. For example, we change this:
  27540. // { name:'Miss Piggy', pets:'Foo-Foo'}
  27541. // into this:
  27542. // { name:['Miss Piggy'], pets:['Foo-Foo']}
  27543. //
  27544. // We also store the attribute names so we can validate our store
  27545. // reference and item id special properties for the O(1) isItem
  27546. var allAttributeNames = {},
  27547. key;
  27548. for(i = 0; i < this._arrayOfAllItems.length; ++i){
  27549. item = this._arrayOfAllItems[i];
  27550. for(key in item){
  27551. if(key !== this._rootItemPropName){
  27552. var value = item[key];
  27553. if(value !== null){
  27554. if(!lang.isArray(value)){
  27555. item[key] = [value];
  27556. }
  27557. }else{
  27558. item[key] = [null];
  27559. }
  27560. }
  27561. allAttributeNames[key]=key;
  27562. }
  27563. }
  27564. // Step 3: Build unique property names to use for the _storeRefPropName and _itemNumPropName
  27565. // This should go really fast, it will generally never even run the loop.
  27566. while(allAttributeNames[this._storeRefPropName]){
  27567. this._storeRefPropName += "_";
  27568. }
  27569. while(allAttributeNames[this._itemNumPropName]){
  27570. this._itemNumPropName += "_";
  27571. }
  27572. while(allAttributeNames[this._reverseRefMap]){
  27573. this._reverseRefMap += "_";
  27574. }
  27575. // Step 4: Some data files specify an optional 'identifier', which is
  27576. // the name of an attribute that holds the identity of each item.
  27577. // If this data file specified an identifier attribute, then build a
  27578. // hash table of items keyed by the identity of the items.
  27579. var arrayOfValues;
  27580. var identifier = dataObject.identifier;
  27581. if(identifier){
  27582. this._itemsByIdentity = {};
  27583. this._features['dojo.data.api.Identity'] = identifier;
  27584. for(i = 0; i < this._arrayOfAllItems.length; ++i){
  27585. item = this._arrayOfAllItems[i];
  27586. arrayOfValues = item[identifier];
  27587. var identity = arrayOfValues[0];
  27588. if(!Object.hasOwnProperty.call(this._itemsByIdentity, identity)){
  27589. this._itemsByIdentity[identity] = item;
  27590. }else{
  27591. if(this._jsonFileUrl){
  27592. throw new Error("dojo.data.ItemFileReadStore: The json data as specified by: [" + this._jsonFileUrl + "] is malformed. Items within the list have identifier: [" + identifier + "]. Value collided: [" + identity + "]");
  27593. }else if(this._jsonData){
  27594. throw new Error("dojo.data.ItemFileReadStore: The json data provided by the creation arguments is malformed. Items within the list have identifier: [" + identifier + "]. Value collided: [" + identity + "]");
  27595. }
  27596. }
  27597. }
  27598. }else{
  27599. this._features['dojo.data.api.Identity'] = Number;
  27600. }
  27601. // Step 5: Walk through all the items, and set each item's properties
  27602. // for _storeRefPropName and _itemNumPropName, so that store.isItem() will return true.
  27603. for(i = 0; i < this._arrayOfAllItems.length; ++i){
  27604. item = this._arrayOfAllItems[i];
  27605. item[this._storeRefPropName] = this;
  27606. item[this._itemNumPropName] = i;
  27607. }
  27608. // Step 6: We walk through all the attribute values of all the items,
  27609. // looking for type/value literals and item-references.
  27610. //
  27611. // We replace item-references with pointers to items. For example, we change:
  27612. // { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
  27613. // into this:
  27614. // { name:['Kermit'], friends:[miss_piggy] }
  27615. // (where miss_piggy is the object representing the 'Miss Piggy' item).
  27616. //
  27617. // We replace type/value pairs with typed-literals. For example, we change:
  27618. // { name:['Nelson Mandela'], born:[{_type:'Date', _value:'1918-07-18'}] }
  27619. // into this:
  27620. // { name:['Kermit'], born:(new Date(1918, 6, 18)) }
  27621. //
  27622. // We also generate the associate map for all items for the O(1) isItem function.
  27623. for(i = 0; i < this._arrayOfAllItems.length; ++i){
  27624. item = this._arrayOfAllItems[i]; // example: { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
  27625. for(key in item){
  27626. arrayOfValues = item[key]; // example: [{_reference:{name:'Miss Piggy'}}]
  27627. for(var j = 0; j < arrayOfValues.length; ++j){
  27628. value = arrayOfValues[j]; // example: {_reference:{name:'Miss Piggy'}}
  27629. if(value !== null && typeof value == "object"){
  27630. if(("_type" in value) && ("_value" in value)){
  27631. var type = value._type; // examples: 'Date', 'Color', or 'ComplexNumber'
  27632. var mappingObj = this._datatypeMap[type]; // examples: Date, dojo.Color, foo.math.ComplexNumber, {type: dojo.Color, deserialize(value){ return new dojo.Color(value)}}
  27633. if(!mappingObj){
  27634. throw new Error("dojo.data.ItemFileReadStore: in the typeMap constructor arg, no object class was specified for the datatype '" + type + "'");
  27635. }else if(lang.isFunction(mappingObj)){
  27636. arrayOfValues[j] = new mappingObj(value._value);
  27637. }else if(lang.isFunction(mappingObj.deserialize)){
  27638. arrayOfValues[j] = mappingObj.deserialize(value._value);
  27639. }else{
  27640. throw new Error("dojo.data.ItemFileReadStore: Value provided in typeMap was neither a constructor, nor a an object with a deserialize function");
  27641. }
  27642. }
  27643. if(value._reference){
  27644. var referenceDescription = value._reference; // example: {name:'Miss Piggy'}
  27645. if(!lang.isObject(referenceDescription)){
  27646. // example: 'Miss Piggy'
  27647. // from an item like: { name:['Kermit'], friends:[{_reference:'Miss Piggy'}]}
  27648. arrayOfValues[j] = this._getItemByIdentity(referenceDescription);
  27649. }else{
  27650. // example: {name:'Miss Piggy'}
  27651. // from an item like: { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
  27652. for(var k = 0; k < this._arrayOfAllItems.length; ++k){
  27653. var candidateItem = this._arrayOfAllItems[k],
  27654. found = true;
  27655. for(var refKey in referenceDescription){
  27656. if(candidateItem[refKey] != referenceDescription[refKey]){
  27657. found = false;
  27658. }
  27659. }
  27660. if(found){
  27661. arrayOfValues[j] = candidateItem;
  27662. }
  27663. }
  27664. }
  27665. if(this.referenceIntegrity){
  27666. var refItem = arrayOfValues[j];
  27667. if(this.isItem(refItem)){
  27668. this._addReferenceToMap(refItem, item, key);
  27669. }
  27670. }
  27671. }else if(this.isItem(value)){
  27672. //It's a child item (not one referenced through _reference).
  27673. //We need to treat this as a referenced item, so it can be cleaned up
  27674. //in a write store easily.
  27675. if(this.referenceIntegrity){
  27676. this._addReferenceToMap(value, item, key);
  27677. }
  27678. }
  27679. }
  27680. }
  27681. }
  27682. }
  27683. },
  27684. _addReferenceToMap: function(/*item*/ refItem, /*item*/ parentItem, /*string*/ attribute){
  27685. // summary:
  27686. // Method to add an reference map entry for an item and attribute.
  27687. // description:
  27688. // Method to add an reference map entry for an item and attribute. //
  27689. // refItem:
  27690. // The item that is referenced.
  27691. // parentItem:
  27692. // The item that holds the new reference to refItem.
  27693. // attribute:
  27694. // The attribute on parentItem that contains the new reference.
  27695. //Stub function, does nothing. Real processing is in ItemFileWriteStore.
  27696. },
  27697. getIdentity: function(/* item */ item){
  27698. // summary:
  27699. // See dojo.data.api.Identity.getIdentity()
  27700. var identifier = this._features['dojo.data.api.Identity'];
  27701. if(identifier === Number){
  27702. return item[this._itemNumPropName]; // Number
  27703. }else{
  27704. var arrayOfValues = item[identifier];
  27705. if(arrayOfValues){
  27706. return arrayOfValues[0]; // Object || String
  27707. }
  27708. }
  27709. return null; // null
  27710. },
  27711. fetchItemByIdentity: function(/* Object */ keywordArgs){
  27712. // summary:
  27713. // See dojo.data.api.Identity.fetchItemByIdentity()
  27714. // Hasn't loaded yet, we have to trigger the load.
  27715. var item,
  27716. scope;
  27717. if(!this._loadFinished){
  27718. var self = this;
  27719. //Do a check on the JsonFileUrl and crosscheck it.
  27720. //If it doesn't match the cross-check, it needs to be updated
  27721. //This allows for either url or _jsonFileUrl to he changed to
  27722. //reset the store load location. Done this way for backwards
  27723. //compatibility. People use _jsonFileUrl (even though officially
  27724. //private.
  27725. if(this._jsonFileUrl !== this._ccUrl){
  27726. kernel.deprecated("dojo.data.ItemFileReadStore: ",
  27727. "To change the url, set the url property of the store," +
  27728. " not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");
  27729. this._ccUrl = this._jsonFileUrl;
  27730. this.url = this._jsonFileUrl;
  27731. }else if(this.url !== this._ccUrl){
  27732. this._jsonFileUrl = this.url;
  27733. this._ccUrl = this.url;
  27734. }
  27735. //See if there was any forced reset of data.
  27736. if(this.data != null && this._jsonData == null){
  27737. this._jsonData = this.data;
  27738. this.data = null;
  27739. }
  27740. if(this._jsonFileUrl){
  27741. if(this._loadInProgress){
  27742. this._queuedFetches.push({args: keywordArgs});
  27743. }else{
  27744. this._loadInProgress = true;
  27745. var getArgs = {
  27746. url: self._jsonFileUrl,
  27747. handleAs: "json-comment-optional",
  27748. preventCache: this.urlPreventCache,
  27749. failOk: this.failOk
  27750. };
  27751. var getHandler = xhr.get(getArgs);
  27752. getHandler.addCallback(function(data){
  27753. var scope = keywordArgs.scope?keywordArgs.scope:window.global;
  27754. try{
  27755. self._getItemsFromLoadedData(data);
  27756. self._loadFinished = true;
  27757. self._loadInProgress = false;
  27758. item = self._getItemByIdentity(keywordArgs.identity);
  27759. if(keywordArgs.onItem){
  27760. keywordArgs.onItem.call(scope, item);
  27761. }
  27762. self._handleQueuedFetches();
  27763. }catch(error){
  27764. self._loadInProgress = false;
  27765. if(keywordArgs.onError){
  27766. keywordArgs.onError.call(scope, error);
  27767. }
  27768. }
  27769. });
  27770. getHandler.addErrback(function(error){
  27771. self._loadInProgress = false;
  27772. if(keywordArgs.onError){
  27773. var scope = keywordArgs.scope?keywordArgs.scope:window.global;
  27774. keywordArgs.onError.call(scope, error);
  27775. }
  27776. });
  27777. }
  27778. }else if(this._jsonData){
  27779. // Passed in data, no need to xhr.
  27780. self._getItemsFromLoadedData(self._jsonData);
  27781. self._jsonData = null;
  27782. self._loadFinished = true;
  27783. item = self._getItemByIdentity(keywordArgs.identity);
  27784. if(keywordArgs.onItem){
  27785. scope = keywordArgs.scope?keywordArgs.scope:window.global;
  27786. keywordArgs.onItem.call(scope, item);
  27787. }
  27788. }
  27789. }else{
  27790. // Already loaded. We can just look it up and call back.
  27791. item = this._getItemByIdentity(keywordArgs.identity);
  27792. if(keywordArgs.onItem){
  27793. scope = keywordArgs.scope?keywordArgs.scope:window.global;
  27794. keywordArgs.onItem.call(scope, item);
  27795. }
  27796. }
  27797. },
  27798. _getItemByIdentity: function(/* Object */ identity){
  27799. // summary:
  27800. // Internal function to look an item up by its identity map.
  27801. var item = null;
  27802. if(this._itemsByIdentity){
  27803. // If this map is defined, we need to just try to get it. If it fails
  27804. // the item does not exist.
  27805. if(Object.hasOwnProperty.call(this._itemsByIdentity, identity)){
  27806. item = this._itemsByIdentity[identity];
  27807. }
  27808. }else if (Object.hasOwnProperty.call(this._arrayOfAllItems, identity)){
  27809. item = this._arrayOfAllItems[identity];
  27810. }
  27811. if(item === undefined){
  27812. item = null;
  27813. }
  27814. return item; // Object
  27815. },
  27816. getIdentityAttributes: function(/* item */ item){
  27817. // summary:
  27818. // See dojo.data.api.Identity.getIdentityAttributes()
  27819. var identifier = this._features['dojo.data.api.Identity'];
  27820. if(identifier === Number){
  27821. // If (identifier === Number) it means getIdentity() just returns
  27822. // an integer item-number for each item. The dojo.data.api.Identity
  27823. // spec says we need to return null if the identity is not composed
  27824. // of attributes
  27825. return null; // null
  27826. }else{
  27827. return [identifier]; // Array
  27828. }
  27829. },
  27830. _forceLoad: function(){
  27831. // summary:
  27832. // Internal function to force a load of the store if it hasn't occurred yet. This is required
  27833. // for specific functions to work properly.
  27834. var self = this;
  27835. //Do a check on the JsonFileUrl and crosscheck it.
  27836. //If it doesn't match the cross-check, it needs to be updated
  27837. //This allows for either url or _jsonFileUrl to he changed to
  27838. //reset the store load location. Done this way for backwards
  27839. //compatibility. People use _jsonFileUrl (even though officially
  27840. //private.
  27841. if(this._jsonFileUrl !== this._ccUrl){
  27842. kernel.deprecated("dojo.data.ItemFileReadStore: ",
  27843. "To change the url, set the url property of the store," +
  27844. " not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");
  27845. this._ccUrl = this._jsonFileUrl;
  27846. this.url = this._jsonFileUrl;
  27847. }else if(this.url !== this._ccUrl){
  27848. this._jsonFileUrl = this.url;
  27849. this._ccUrl = this.url;
  27850. }
  27851. //See if there was any forced reset of data.
  27852. if(this.data != null){
  27853. this._jsonData = this.data;
  27854. this.data = null;
  27855. }
  27856. if(this._jsonFileUrl){
  27857. var getArgs = {
  27858. url: this._jsonFileUrl,
  27859. handleAs: "json-comment-optional",
  27860. preventCache: this.urlPreventCache,
  27861. failOk: this.failOk,
  27862. sync: true
  27863. };
  27864. var getHandler = xhr.get(getArgs);
  27865. getHandler.addCallback(function(data){
  27866. try{
  27867. //Check to be sure there wasn't another load going on concurrently
  27868. //So we don't clobber data that comes in on it. If there is a load going on
  27869. //then do not save this data. It will potentially clobber current data.
  27870. //We mainly wanted to sync/wait here.
  27871. //TODO: Revisit the loading scheme of this store to improve multi-initial
  27872. //request handling.
  27873. if(self._loadInProgress !== true && !self._loadFinished){
  27874. self._getItemsFromLoadedData(data);
  27875. self._loadFinished = true;
  27876. }else if(self._loadInProgress){
  27877. //Okay, we hit an error state we can't recover from. A forced load occurred
  27878. //while an async load was occurring. Since we cannot block at this point, the best
  27879. //that can be managed is to throw an error.
  27880. throw new Error("dojo.data.ItemFileReadStore: Unable to perform a synchronous load, an async load is in progress.");
  27881. }
  27882. }catch(e){
  27883. console.log(e);
  27884. throw e;
  27885. }
  27886. });
  27887. getHandler.addErrback(function(error){
  27888. throw error;
  27889. });
  27890. }else if(this._jsonData){
  27891. self._getItemsFromLoadedData(self._jsonData);
  27892. self._jsonData = null;
  27893. self._loadFinished = true;
  27894. }
  27895. }
  27896. });
  27897. //Mix in the simple fetch implementation to this class.
  27898. lang.extend(ItemFileReadStore,simpleFetch);
  27899. return ItemFileReadStore;
  27900. });
  27901. },
  27902. 'dojo/html':function(){
  27903. define("dojo/html", ["./_base/kernel", "./_base/lang", "./_base/array", "./_base/declare", "./dom", "./dom-construct", "./parser"], function(dojo, lang, darray, declare, dom, domConstruct, parser) {
  27904. // module:
  27905. // dojo/html
  27906. // summary:
  27907. // TODOC
  27908. lang.getObject("html", true, dojo);
  27909. // the parser might be needed..
  27910. // idCounter is incremented with each instantiation to allow asignment of a unique id for tracking, logging purposes
  27911. var idCounter = 0;
  27912. dojo.html._secureForInnerHtml = function(/*String*/ cont){
  27913. // summary:
  27914. // removes !DOCTYPE and title elements from the html string.
  27915. //
  27916. // khtml is picky about dom faults, you can't attach a style or <title> node as child of body
  27917. // must go into head, so we need to cut out those tags
  27918. // cont:
  27919. // An html string for insertion into the dom
  27920. //
  27921. return cont.replace(/(?:\s*<!DOCTYPE\s[^>]+>|<title[^>]*>[\s\S]*?<\/title>)/ig, ""); // String
  27922. };
  27923. /*====
  27924. dojo.html._emptyNode = function(node){
  27925. // summary:
  27926. // removes all child nodes from the given node
  27927. // node: DOMNode
  27928. // the parent element
  27929. };
  27930. =====*/
  27931. dojo.html._emptyNode = domConstruct.empty;
  27932. dojo.html._setNodeContent = function(/* DomNode */ node, /* String|DomNode|NodeList */ cont){
  27933. // summary:
  27934. // inserts the given content into the given node
  27935. // node:
  27936. // the parent element
  27937. // content:
  27938. // the content to be set on the parent element.
  27939. // This can be an html string, a node reference or a NodeList, dojo.NodeList, Array or other enumerable list of nodes
  27940. // always empty
  27941. domConstruct.empty(node);
  27942. if(cont) {
  27943. if(typeof cont == "string") {
  27944. cont = domConstruct.toDom(cont, node.ownerDocument);
  27945. }
  27946. if(!cont.nodeType && lang.isArrayLike(cont)) {
  27947. // handle as enumerable, but it may shrink as we enumerate it
  27948. for(var startlen=cont.length, i=0; i<cont.length; i=startlen==cont.length ? i+1 : 0) {
  27949. domConstruct.place( cont[i], node, "last");
  27950. }
  27951. } else {
  27952. // pass nodes, documentFragments and unknowns through to dojo.place
  27953. domConstruct.place(cont, node, "last");
  27954. }
  27955. }
  27956. // return DomNode
  27957. return node;
  27958. };
  27959. // we wrap up the content-setting operation in a object
  27960. declare("dojo.html._ContentSetter", null,
  27961. {
  27962. // node: DomNode|String
  27963. // An node which will be the parent element that we set content into
  27964. node: "",
  27965. // content: String|DomNode|DomNode[]
  27966. // The content to be placed in the node. Can be an HTML string, a node reference, or a enumerable list of nodes
  27967. content: "",
  27968. // id: String?
  27969. // Usually only used internally, and auto-generated with each instance
  27970. id: "",
  27971. // cleanContent: Boolean
  27972. // Should the content be treated as a full html document,
  27973. // and the real content stripped of <html>, <body> wrapper before injection
  27974. cleanContent: false,
  27975. // extractContent: Boolean
  27976. // Should the content be treated as a full html document, and the real content stripped of <html>, <body> wrapper before injection
  27977. extractContent: false,
  27978. // parseContent: Boolean
  27979. // Should the node by passed to the parser after the new content is set
  27980. parseContent: false,
  27981. // parserScope: String
  27982. // Flag passed to parser. Root for attribute names to search for. If scopeName is dojo,
  27983. // will search for data-dojo-type (or dojoType). For backwards compatibility
  27984. // reasons defaults to dojo._scopeName (which is "dojo" except when
  27985. // multi-version support is used, when it will be something like dojo16, dojo20, etc.)
  27986. parserScope: dojo._scopeName,
  27987. // startup: Boolean
  27988. // Start the child widgets after parsing them. Only obeyed if parseContent is true.
  27989. startup: true,
  27990. // lifecyle methods
  27991. constructor: function(/* Object */params, /* String|DomNode */node){
  27992. // summary:
  27993. // Provides a configurable, extensible object to wrap the setting on content on a node
  27994. // call the set() method to actually set the content..
  27995. // the original params are mixed directly into the instance "this"
  27996. lang.mixin(this, params || {});
  27997. // give precedence to params.node vs. the node argument
  27998. // and ensure its a node, not an id string
  27999. node = this.node = dom.byId( this.node || node );
  28000. if(!this.id){
  28001. this.id = [
  28002. "Setter",
  28003. (node) ? node.id || node.tagName : "",
  28004. idCounter++
  28005. ].join("_");
  28006. }
  28007. },
  28008. set: function(/* String|DomNode|NodeList? */ cont, /* Object? */ params){
  28009. // summary:
  28010. // front-end to the set-content sequence
  28011. // cont:
  28012. // An html string, node or enumerable list of nodes for insertion into the dom
  28013. // If not provided, the object's content property will be used
  28014. if(undefined !== cont){
  28015. this.content = cont;
  28016. }
  28017. // in the re-use scenario, set needs to be able to mixin new configuration
  28018. if(params){
  28019. this._mixin(params);
  28020. }
  28021. this.onBegin();
  28022. this.setContent();
  28023. this.onEnd();
  28024. return this.node;
  28025. },
  28026. setContent: function(){
  28027. // summary:
  28028. // sets the content on the node
  28029. var node = this.node;
  28030. if(!node) {
  28031. // can't proceed
  28032. throw new Error(this.declaredClass + ": setContent given no node");
  28033. }
  28034. try{
  28035. node = dojo.html._setNodeContent(node, this.content);
  28036. }catch(e){
  28037. // check if a domfault occurs when we are appending this.errorMessage
  28038. // like for instance if domNode is a UL and we try append a DIV
  28039. // FIXME: need to allow the user to provide a content error message string
  28040. var errMess = this.onContentError(e);
  28041. try{
  28042. node.innerHTML = errMess;
  28043. }catch(e){
  28044. console.error('Fatal ' + this.declaredClass + '.setContent could not change content due to '+e.message, e);
  28045. }
  28046. }
  28047. // always put back the node for the next method
  28048. this.node = node; // DomNode
  28049. },
  28050. empty: function() {
  28051. // summary
  28052. // cleanly empty out existing content
  28053. // destroy any widgets from a previous run
  28054. // NOTE: if you dont want this you'll need to empty
  28055. // the parseResults array property yourself to avoid bad things happenning
  28056. if(this.parseResults && this.parseResults.length) {
  28057. darray.forEach(this.parseResults, function(w) {
  28058. if(w.destroy){
  28059. w.destroy();
  28060. }
  28061. });
  28062. delete this.parseResults;
  28063. }
  28064. // this is fast, but if you know its already empty or safe, you could
  28065. // override empty to skip this step
  28066. dojo.html._emptyNode(this.node);
  28067. },
  28068. onBegin: function(){
  28069. // summary
  28070. // Called after instantiation, but before set();
  28071. // It allows modification of any of the object properties
  28072. // - including the node and content provided - before the set operation actually takes place
  28073. // This default implementation checks for cleanContent and extractContent flags to
  28074. // optionally pre-process html string content
  28075. var cont = this.content;
  28076. if(lang.isString(cont)){
  28077. if(this.cleanContent){
  28078. cont = dojo.html._secureForInnerHtml(cont);
  28079. }
  28080. if(this.extractContent){
  28081. var match = cont.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
  28082. if(match){ cont = match[1]; }
  28083. }
  28084. }
  28085. // clean out the node and any cruft associated with it - like widgets
  28086. this.empty();
  28087. this.content = cont;
  28088. return this.node; /* DomNode */
  28089. },
  28090. onEnd: function(){
  28091. // summary
  28092. // Called after set(), when the new content has been pushed into the node
  28093. // It provides an opportunity for post-processing before handing back the node to the caller
  28094. // This default implementation checks a parseContent flag to optionally run the dojo parser over the new content
  28095. if(this.parseContent){
  28096. // populates this.parseResults if you need those..
  28097. this._parse();
  28098. }
  28099. return this.node; /* DomNode */
  28100. },
  28101. tearDown: function(){
  28102. // summary
  28103. // manually reset the Setter instance if its being re-used for example for another set()
  28104. // description
  28105. // tearDown() is not called automatically.
  28106. // In normal use, the Setter instance properties are simply allowed to fall out of scope
  28107. // but the tearDown method can be called to explicitly reset this instance.
  28108. delete this.parseResults;
  28109. delete this.node;
  28110. delete this.content;
  28111. },
  28112. onContentError: function(err){
  28113. return "Error occured setting content: " + err;
  28114. },
  28115. _mixin: function(params){
  28116. // mix properties/methods into the instance
  28117. // TODO: the intention with tearDown is to put the Setter's state
  28118. // back to that of the original constructor (vs. deleting/resetting everything regardless of ctor params)
  28119. // so we could do something here to move the original properties aside for later restoration
  28120. var empty = {}, key;
  28121. for(key in params){
  28122. if(key in empty){ continue; }
  28123. // TODO: here's our opportunity to mask the properties we dont consider configurable/overridable
  28124. // .. but history shows we'll almost always guess wrong
  28125. this[key] = params[key];
  28126. }
  28127. },
  28128. _parse: function(){
  28129. // summary:
  28130. // runs the dojo parser over the node contents, storing any results in this.parseResults
  28131. // Any errors resulting from parsing are passed to _onError for handling
  28132. var rootNode = this.node;
  28133. try{
  28134. // store the results (widgets, whatever) for potential retrieval
  28135. var inherited = {};
  28136. darray.forEach(["dir", "lang", "textDir"], function(name){
  28137. if(this[name]){
  28138. inherited[name] = this[name];
  28139. }
  28140. }, this);
  28141. this.parseResults = parser.parse({
  28142. rootNode: rootNode,
  28143. noStart: !this.startup,
  28144. inherited: inherited,
  28145. scope: this.parserScope
  28146. });
  28147. }catch(e){
  28148. this._onError('Content', e, "Error parsing in _ContentSetter#"+this.id);
  28149. }
  28150. },
  28151. _onError: function(type, err, consoleText){
  28152. // summary:
  28153. // shows user the string that is returned by on[type]Error
  28154. // overide/implement on[type]Error and return your own string to customize
  28155. var errText = this['on' + type + 'Error'].call(this, err);
  28156. if(consoleText){
  28157. console.error(consoleText, err);
  28158. }else if(errText){ // a empty string won't change current content
  28159. dojo.html._setNodeContent(this.node, errText, true);
  28160. }
  28161. }
  28162. }); // end dojo.declare()
  28163. dojo.html.set = function(/* DomNode */ node, /* String|DomNode|NodeList */ cont, /* Object? */ params){
  28164. // summary:
  28165. // inserts (replaces) the given content into the given node. dojo.place(cont, node, "only")
  28166. // may be a better choice for simple HTML insertion.
  28167. // description:
  28168. // Unless you need to use the params capabilities of this method, you should use
  28169. // dojo.place(cont, node, "only"). dojo.place() has more robust support for injecting
  28170. // an HTML string into the DOM, but it only handles inserting an HTML string as DOM
  28171. // elements, or inserting a DOM node. dojo.place does not handle NodeList insertions
  28172. // or the other capabilities as defined by the params object for this method.
  28173. // node:
  28174. // the parent element that will receive the content
  28175. // cont:
  28176. // the content to be set on the parent element.
  28177. // This can be an html string, a node reference or a NodeList, dojo.NodeList, Array or other enumerable list of nodes
  28178. // params:
  28179. // Optional flags/properties to configure the content-setting. See dojo.html._ContentSetter
  28180. // example:
  28181. // A safe string/node/nodelist content replacement/injection with hooks for extension
  28182. // Example Usage:
  28183. // dojo.html.set(node, "some string");
  28184. // dojo.html.set(node, contentNode, {options});
  28185. // dojo.html.set(node, myNode.childNodes, {options});
  28186. if(undefined == cont){
  28187. console.warn("dojo.html.set: no cont argument provided, using empty string");
  28188. cont = "";
  28189. }
  28190. if(!params){
  28191. // simple and fast
  28192. return dojo.html._setNodeContent(node, cont, true);
  28193. }else{
  28194. // more options but slower
  28195. // note the arguments are reversed in order, to match the convention for instantiation via the parser
  28196. var op = new dojo.html._ContentSetter(lang.mixin(
  28197. params,
  28198. { content: cont, node: node }
  28199. ));
  28200. return op.set();
  28201. }
  28202. };
  28203. return dojo.html;
  28204. });
  28205. },
  28206. 'url:dijit/templates/TitlePane.html':"<div>\r\n\t<div data-dojo-attach-event=\"onclick:_onTitleClick, onkeypress:_onTitleKey\"\r\n\t\t\tclass=\"dijitTitlePaneTitle\" data-dojo-attach-point=\"titleBarNode\">\r\n\t\t<div class=\"dijitTitlePaneTitleFocus\" data-dojo-attach-point=\"focusNode\">\r\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" data-dojo-attach-point=\"arrowNode\" class=\"dijitArrowNode\" role=\"presentation\"\r\n\t\t\t/><span data-dojo-attach-point=\"arrowNodeInner\" class=\"dijitArrowNodeInner\"></span\r\n\t\t\t><span data-dojo-attach-point=\"titleNode\" class=\"dijitTitlePaneTextNode\"></span>\r\n\t\t</div>\r\n\t</div>\r\n\t<div class=\"dijitTitlePaneContentOuter\" data-dojo-attach-point=\"hideNode\" role=\"presentation\">\r\n\t\t<div class=\"dijitReset\" data-dojo-attach-point=\"wipeNode\" role=\"presentation\">\r\n\t\t\t<div class=\"dijitTitlePaneContentInner\" data-dojo-attach-point=\"containerNode\" role=\"region\" id=\"${id}_pane\">\r\n\t\t\t\t<!-- nested divs because wipeIn()/wipeOut() doesn't work right on node w/padding etc. Put padding on inner div. -->\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n</div>\r\n",
  28207. 'dijit/form/ValidationTextBox':function(){
  28208. require({cache:{
  28209. 'url:dijit/form/templates/ValidationTextBox.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\"\r\n\tid=\"widget_${id}\" role=\"presentation\"\r\n\t><div class='dijitReset dijitValidationContainer'\r\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t/></div\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class=\"dijitReset dijitInputInner\" data-dojo-attach-point='textbox,focusNode' autocomplete=\"off\"\r\n\t\t\t${!nameAttrSetting} type='${type}'\r\n\t/></div\r\n></div>\r\n"}});
  28210. define("dijit/form/ValidationTextBox", [
  28211. "dojo/_base/declare", // declare
  28212. "dojo/i18n", // i18n.getLocalization
  28213. "./TextBox",
  28214. "../Tooltip",
  28215. "dojo/text!./templates/ValidationTextBox.html",
  28216. "dojo/i18n!./nls/validate"
  28217. ], function(declare, i18n, TextBox, Tooltip, template){
  28218. /*=====
  28219. var Tooltip = dijit.Tooltip;
  28220. var TextBox = dijit.form.TextBox;
  28221. =====*/
  28222. // module:
  28223. // dijit/form/ValidationTextBox
  28224. // summary:
  28225. // Base class for textbox widgets with the ability to validate content of various types and provide user feedback.
  28226. /*=====
  28227. dijit.form.ValidationTextBox.__Constraints = function(){
  28228. // locale: String
  28229. // locale used for validation, picks up value from this widget's lang attribute
  28230. // _flags_: anything
  28231. // various flags passed to regExpGen function
  28232. this.locale = "";
  28233. this._flags_ = "";
  28234. }
  28235. =====*/
  28236. return declare("dijit.form.ValidationTextBox", TextBox, {
  28237. // summary:
  28238. // Base class for textbox widgets with the ability to validate content of various types and provide user feedback.
  28239. // tags:
  28240. // protected
  28241. templateString: template,
  28242. baseClass: "dijitTextBox dijitValidationTextBox",
  28243. // required: Boolean
  28244. // User is required to enter data into this field.
  28245. required: false,
  28246. // promptMessage: String
  28247. // If defined, display this hint string immediately on focus to the textbox, if empty.
  28248. // Also displays if the textbox value is Incomplete (not yet valid but will be with additional input).
  28249. // Think of this like a tooltip that tells the user what to do, not an error message
  28250. // that tells the user what they've done wrong.
  28251. //
  28252. // Message disappears when user starts typing.
  28253. promptMessage: "",
  28254. // invalidMessage: String
  28255. // The message to display if value is invalid.
  28256. // The translated string value is read from the message file by default.
  28257. // Set to "" to use the promptMessage instead.
  28258. invalidMessage: "$_unset_$",
  28259. // missingMessage: String
  28260. // The message to display if value is empty and the field is required.
  28261. // The translated string value is read from the message file by default.
  28262. // Set to "" to use the invalidMessage instead.
  28263. missingMessage: "$_unset_$",
  28264. // message: String
  28265. // Currently error/prompt message.
  28266. // When using the default tooltip implementation, this will only be
  28267. // displayed when the field is focused.
  28268. message: "",
  28269. // constraints: dijit.form.ValidationTextBox.__Constraints
  28270. // user-defined object needed to pass parameters to the validator functions
  28271. constraints: {},
  28272. // regExp: [extension protected] String
  28273. // regular expression string used to validate the input
  28274. // Do not specify both regExp and regExpGen
  28275. regExp: ".*",
  28276. regExpGen: function(/*dijit.form.ValidationTextBox.__Constraints*/ /*===== constraints =====*/){
  28277. // summary:
  28278. // Overridable function used to generate regExp when dependent on constraints.
  28279. // Do not specify both regExp and regExpGen.
  28280. // tags:
  28281. // extension protected
  28282. return this.regExp; // String
  28283. },
  28284. // state: [readonly] String
  28285. // Shows current state (ie, validation result) of input (""=Normal, Incomplete, or Error)
  28286. state: "",
  28287. // tooltipPosition: String[]
  28288. // See description of `dijit.Tooltip.defaultPosition` for details on this parameter.
  28289. tooltipPosition: [],
  28290. _setValueAttr: function(){
  28291. // summary:
  28292. // Hook so set('value', ...) works.
  28293. this.inherited(arguments);
  28294. this.validate(this.focused);
  28295. },
  28296. validator: function(/*anything*/ value, /*dijit.form.ValidationTextBox.__Constraints*/ constraints){
  28297. // summary:
  28298. // Overridable function used to validate the text input against the regular expression.
  28299. // tags:
  28300. // protected
  28301. return (new RegExp("^(?:" + this.regExpGen(constraints) + ")"+(this.required?"":"?")+"$")).test(value) &&
  28302. (!this.required || !this._isEmpty(value)) &&
  28303. (this._isEmpty(value) || this.parse(value, constraints) !== undefined); // Boolean
  28304. },
  28305. _isValidSubset: function(){
  28306. // summary:
  28307. // Returns true if the value is either already valid or could be made valid by appending characters.
  28308. // This is used for validation while the user [may be] still typing.
  28309. return this.textbox.value.search(this._partialre) == 0;
  28310. },
  28311. isValid: function(/*Boolean*/ /*===== isFocused =====*/){
  28312. // summary:
  28313. // Tests if value is valid.
  28314. // Can override with your own routine in a subclass.
  28315. // tags:
  28316. // protected
  28317. return this.validator(this.textbox.value, this.constraints);
  28318. },
  28319. _isEmpty: function(value){
  28320. // summary:
  28321. // Checks for whitespace
  28322. return (this.trim ? /^\s*$/ : /^$/).test(value); // Boolean
  28323. },
  28324. getErrorMessage: function(/*Boolean*/ /*===== isFocused =====*/){
  28325. // summary:
  28326. // Return an error message to show if appropriate
  28327. // tags:
  28328. // protected
  28329. return (this.required && this._isEmpty(this.textbox.value)) ? this.missingMessage : this.invalidMessage; // String
  28330. },
  28331. getPromptMessage: function(/*Boolean*/ /*===== isFocused =====*/){
  28332. // summary:
  28333. // Return a hint message to show when widget is first focused
  28334. // tags:
  28335. // protected
  28336. return this.promptMessage; // String
  28337. },
  28338. _maskValidSubsetError: true,
  28339. validate: function(/*Boolean*/ isFocused){
  28340. // summary:
  28341. // Called by oninit, onblur, and onkeypress.
  28342. // description:
  28343. // Show missing or invalid messages if appropriate, and highlight textbox field.
  28344. // tags:
  28345. // protected
  28346. var message = "";
  28347. var isValid = this.disabled || this.isValid(isFocused);
  28348. if(isValid){ this._maskValidSubsetError = true; }
  28349. var isEmpty = this._isEmpty(this.textbox.value);
  28350. var isValidSubset = !isValid && isFocused && this._isValidSubset();
  28351. this._set("state", isValid ? "" : (((((!this._hasBeenBlurred || isFocused) && isEmpty) || isValidSubset) && this._maskValidSubsetError) ? "Incomplete" : "Error"));
  28352. this.focusNode.setAttribute("aria-invalid", isValid ? "false" : "true");
  28353. if(this.state == "Error"){
  28354. this._maskValidSubsetError = isFocused && isValidSubset; // we want the error to show up after a blur and refocus
  28355. message = this.getErrorMessage(isFocused);
  28356. }else if(this.state == "Incomplete"){
  28357. message = this.getPromptMessage(isFocused); // show the prompt whenever the value is not yet complete
  28358. this._maskValidSubsetError = !this._hasBeenBlurred || isFocused; // no Incomplete warnings while focused
  28359. }else if(isEmpty){
  28360. message = this.getPromptMessage(isFocused); // show the prompt whenever there's no error and no text
  28361. }
  28362. this.set("message", message);
  28363. return isValid;
  28364. },
  28365. displayMessage: function(/*String*/ message){
  28366. // summary:
  28367. // Overridable method to display validation errors/hints.
  28368. // By default uses a tooltip.
  28369. // tags:
  28370. // extension
  28371. if(message && this.focused){
  28372. Tooltip.show(message, this.domNode, this.tooltipPosition, !this.isLeftToRight());
  28373. }else{
  28374. Tooltip.hide(this.domNode);
  28375. }
  28376. },
  28377. _refreshState: function(){
  28378. // Overrides TextBox._refreshState()
  28379. this.validate(this.focused);
  28380. this.inherited(arguments);
  28381. },
  28382. //////////// INITIALIZATION METHODS ///////////////////////////////////////
  28383. constructor: function(){
  28384. this.constraints = {};
  28385. },
  28386. _setConstraintsAttr: function(/*Object*/ constraints){
  28387. if(!constraints.locale && this.lang){
  28388. constraints.locale = this.lang;
  28389. }
  28390. this._set("constraints", constraints);
  28391. this._computePartialRE();
  28392. },
  28393. _computePartialRE: function(){
  28394. var p = this.regExpGen(this.constraints);
  28395. this.regExp = p;
  28396. var partialre = "";
  28397. // parse the regexp and produce a new regexp that matches valid subsets
  28398. // if the regexp is .* then there's no use in matching subsets since everything is valid
  28399. if(p != ".*"){ this.regExp.replace(/\\.|\[\]|\[.*?[^\\]{1}\]|\{.*?\}|\(\?[=:!]|./g,
  28400. function(re){
  28401. switch(re.charAt(0)){
  28402. case '{':
  28403. case '+':
  28404. case '?':
  28405. case '*':
  28406. case '^':
  28407. case '$':
  28408. case '|':
  28409. case '(':
  28410. partialre += re;
  28411. break;
  28412. case ")":
  28413. partialre += "|$)";
  28414. break;
  28415. default:
  28416. partialre += "(?:"+re+"|$)";
  28417. break;
  28418. }
  28419. }
  28420. );}
  28421. try{ // this is needed for now since the above regexp parsing needs more test verification
  28422. "".search(partialre);
  28423. }catch(e){ // should never be here unless the original RE is bad or the parsing is bad
  28424. partialre = this.regExp;
  28425. console.warn('RegExp error in ' + this.declaredClass + ': ' + this.regExp);
  28426. } // should never be here unless the original RE is bad or the parsing is bad
  28427. this._partialre = "^(?:" + partialre + ")$";
  28428. },
  28429. postMixInProperties: function(){
  28430. this.inherited(arguments);
  28431. this.messages = i18n.getLocalization("dijit.form", "validate", this.lang);
  28432. if(this.invalidMessage == "$_unset_$"){ this.invalidMessage = this.messages.invalidMessage; }
  28433. if(!this.invalidMessage){ this.invalidMessage = this.promptMessage; }
  28434. if(this.missingMessage == "$_unset_$"){ this.missingMessage = this.messages.missingMessage; }
  28435. if(!this.missingMessage){ this.missingMessage = this.invalidMessage; }
  28436. this._setConstraintsAttr(this.constraints); // this needs to happen now (and later) due to codependency on _set*Attr calls attachPoints
  28437. },
  28438. _setDisabledAttr: function(/*Boolean*/ value){
  28439. this.inherited(arguments); // call FormValueWidget._setDisabledAttr()
  28440. this._refreshState();
  28441. },
  28442. _setRequiredAttr: function(/*Boolean*/ value){
  28443. this._set("required", value);
  28444. this.focusNode.setAttribute("aria-required", value);
  28445. this._refreshState();
  28446. },
  28447. _setMessageAttr: function(/*String*/ message){
  28448. this._set("message", message);
  28449. this.displayMessage(message);
  28450. },
  28451. reset:function(){
  28452. // Overrides dijit.form.TextBox.reset() by also
  28453. // hiding errors about partial matches
  28454. this._maskValidSubsetError = true;
  28455. this.inherited(arguments);
  28456. },
  28457. _onBlur: function(){
  28458. // the message still exists but for back-compat, and to erase the tooltip
  28459. // (if the message is being displayed as a tooltip), call displayMessage('')
  28460. this.displayMessage('');
  28461. this.inherited(arguments);
  28462. }
  28463. });
  28464. });
  28465. },
  28466. 'dijit/layout/BorderContainer':function(){
  28467. define("dijit/layout/BorderContainer", [
  28468. "dojo/_base/array", // array.filter array.forEach array.map
  28469. "dojo/cookie", // cookie
  28470. "dojo/_base/declare", // declare
  28471. "dojo/dom-class", // domClass.add domClass.remove domClass.toggle
  28472. "dojo/dom-construct", // domConstruct.destroy domConstruct.place
  28473. "dojo/dom-geometry", // domGeometry.marginBox
  28474. "dojo/dom-style", // domStyle.style
  28475. "dojo/_base/event", // event.stop
  28476. "dojo/keys",
  28477. "dojo/_base/lang", // lang.getObject lang.hitch
  28478. "dojo/on",
  28479. "dojo/touch",
  28480. "dojo/_base/window", // win.body win.doc win.doc.createElement
  28481. "../_WidgetBase",
  28482. "../_Widget",
  28483. "../_TemplatedMixin",
  28484. "./_LayoutWidget",
  28485. "./utils" // layoutUtils.layoutChildren
  28486. ], function(array, cookie, declare, domClass, domConstruct, domGeometry, domStyle, event, keys, lang, on, touch, win,
  28487. _WidgetBase, _Widget, _TemplatedMixin, _LayoutWidget, layoutUtils){
  28488. /*=====
  28489. var _WidgetBase = dijit._WidgetBase;
  28490. var _Widget = dijit._Widget;
  28491. var _TemplatedMixin = dijit._TemplatedMixin;
  28492. var _LayoutWidget = dijit.layout._LayoutWidget;
  28493. =====*/
  28494. // module:
  28495. // dijit/layout/BorderContainer
  28496. // summary:
  28497. // Provides layout in up to 5 regions, a mandatory center with optional borders along its 4 sides.
  28498. var _Splitter = declare("dijit.layout._Splitter", [_Widget, _TemplatedMixin ],
  28499. {
  28500. // summary:
  28501. // A draggable spacer between two items in a `dijit.layout.BorderContainer`.
  28502. // description:
  28503. // This is instantiated by `dijit.layout.BorderContainer`. Users should not
  28504. // create it directly.
  28505. // tags:
  28506. // private
  28507. /*=====
  28508. // container: [const] dijit.layout.BorderContainer
  28509. // Pointer to the parent BorderContainer
  28510. container: null,
  28511. // child: [const] dijit.layout._LayoutWidget
  28512. // Pointer to the pane associated with this splitter
  28513. child: null,
  28514. // region: [const] String
  28515. // Region of pane associated with this splitter.
  28516. // "top", "bottom", "left", "right".
  28517. region: null,
  28518. =====*/
  28519. // live: [const] Boolean
  28520. // If true, the child's size changes and the child widget is redrawn as you drag the splitter;
  28521. // otherwise, the size doesn't change until you drop the splitter (by mouse-up)
  28522. live: true,
  28523. 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>',
  28524. constructor: function(){
  28525. this._handlers = [];
  28526. },
  28527. postMixInProperties: function(){
  28528. this.inherited(arguments);
  28529. this.horizontal = /top|bottom/.test(this.region);
  28530. this._factor = /top|left/.test(this.region) ? 1 : -1;
  28531. this._cookieName = this.container.id + "_" + this.region;
  28532. },
  28533. buildRendering: function(){
  28534. this.inherited(arguments);
  28535. domClass.add(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V"));
  28536. if(this.container.persist){
  28537. // restore old size
  28538. var persistSize = cookie(this._cookieName);
  28539. if(persistSize){
  28540. this.child.domNode.style[this.horizontal ? "height" : "width"] = persistSize;
  28541. }
  28542. }
  28543. },
  28544. _computeMaxSize: function(){
  28545. // summary:
  28546. // Return the maximum size that my corresponding pane can be set to
  28547. var dim = this.horizontal ? 'h' : 'w',
  28548. childSize = domGeometry.getMarginBox(this.child.domNode)[dim],
  28549. center = array.filter(this.container.getChildren(), function(child){ return child.region == "center";})[0],
  28550. spaceAvailable = domGeometry.getMarginBox(center.domNode)[dim]; // can expand until center is crushed to 0
  28551. return Math.min(this.child.maxSize, childSize + spaceAvailable);
  28552. },
  28553. _startDrag: function(e){
  28554. if(!this.cover){
  28555. this.cover = win.doc.createElement('div');
  28556. domClass.add(this.cover, "dijitSplitterCover");
  28557. domConstruct.place(this.cover, this.child.domNode, "after");
  28558. }
  28559. domClass.add(this.cover, "dijitSplitterCoverActive");
  28560. // Safeguard in case the stop event was missed. Shouldn't be necessary if we always get the mouse up.
  28561. if(this.fake){ domConstruct.destroy(this.fake); }
  28562. if(!(this._resize = this.live)){ //TODO: disable live for IE6?
  28563. // create fake splitter to display at old position while we drag
  28564. (this.fake = this.domNode.cloneNode(true)).removeAttribute("id");
  28565. domClass.add(this.domNode, "dijitSplitterShadow");
  28566. domConstruct.place(this.fake, this.domNode, "after");
  28567. }
  28568. domClass.add(this.domNode, "dijitSplitterActive dijitSplitter" + (this.horizontal ? "H" : "V") + "Active");
  28569. if(this.fake){
  28570. domClass.remove(this.fake, "dijitSplitterHover dijitSplitter" + (this.horizontal ? "H" : "V") + "Hover");
  28571. }
  28572. //Performance: load data info local vars for onmousevent function closure
  28573. var factor = this._factor,
  28574. isHorizontal = this.horizontal,
  28575. axis = isHorizontal ? "pageY" : "pageX",
  28576. pageStart = e[axis],
  28577. splitterStyle = this.domNode.style,
  28578. dim = isHorizontal ? 'h' : 'w',
  28579. childStart = domGeometry.getMarginBox(this.child.domNode)[dim],
  28580. max = this._computeMaxSize(),
  28581. min = this.child.minSize || 20,
  28582. region = this.region,
  28583. splitterAttr = region == "top" || region == "bottom" ? "top" : "left", // style attribute of splitter to adjust
  28584. splitterStart = parseInt(splitterStyle[splitterAttr], 10),
  28585. resize = this._resize,
  28586. layoutFunc = lang.hitch(this.container, "_layoutChildren", this.child.id),
  28587. de = win.doc;
  28588. this._handlers = this._handlers.concat([
  28589. on(de, touch.move, this._drag = function(e, forceResize){
  28590. var delta = e[axis] - pageStart,
  28591. childSize = factor * delta + childStart,
  28592. boundChildSize = Math.max(Math.min(childSize, max), min);
  28593. if(resize || forceResize){
  28594. layoutFunc(boundChildSize);
  28595. }
  28596. // TODO: setting style directly (usually) sets content box size, need to set margin box size
  28597. splitterStyle[splitterAttr] = delta + splitterStart + factor*(boundChildSize - childSize) + "px";
  28598. }),
  28599. on(de, "dragstart", event.stop),
  28600. on(win.body(), "selectstart", event.stop),
  28601. on(de, touch.release, lang.hitch(this, "_stopDrag"))
  28602. ]);
  28603. event.stop(e);
  28604. },
  28605. _onMouse: function(e){
  28606. // summary:
  28607. // Handler for onmouseenter / onmouseleave events
  28608. var o = (e.type == "mouseover" || e.type == "mouseenter");
  28609. domClass.toggle(this.domNode, "dijitSplitterHover", o);
  28610. domClass.toggle(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V") + "Hover", o);
  28611. },
  28612. _stopDrag: function(e){
  28613. try{
  28614. if(this.cover){
  28615. domClass.remove(this.cover, "dijitSplitterCoverActive");
  28616. }
  28617. if(this.fake){ domConstruct.destroy(this.fake); }
  28618. domClass.remove(this.domNode, "dijitSplitterActive dijitSplitter"
  28619. + (this.horizontal ? "H" : "V") + "Active dijitSplitterShadow");
  28620. this._drag(e); //TODO: redundant with onmousemove?
  28621. this._drag(e, true);
  28622. }finally{
  28623. this._cleanupHandlers();
  28624. delete this._drag;
  28625. }
  28626. if(this.container.persist){
  28627. cookie(this._cookieName, this.child.domNode.style[this.horizontal ? "height" : "width"], {expires:365});
  28628. }
  28629. },
  28630. _cleanupHandlers: function(){
  28631. var h;
  28632. while(h = this._handlers.pop()){ h.remove(); }
  28633. },
  28634. _onKeyPress: function(/*Event*/ e){
  28635. // should we apply typematic to this?
  28636. this._resize = true;
  28637. var horizontal = this.horizontal;
  28638. var tick = 1;
  28639. switch(e.charOrCode){
  28640. case horizontal ? keys.UP_ARROW : keys.LEFT_ARROW:
  28641. tick *= -1;
  28642. // break;
  28643. case horizontal ? keys.DOWN_ARROW : keys.RIGHT_ARROW:
  28644. break;
  28645. default:
  28646. // this.inherited(arguments);
  28647. return;
  28648. }
  28649. var childSize = domGeometry.getMarginSize(this.child.domNode)[ horizontal ? 'h' : 'w' ] + this._factor * tick;
  28650. this.container._layoutChildren(this.child.id, Math.max(Math.min(childSize, this._computeMaxSize()), this.child.minSize));
  28651. event.stop(e);
  28652. },
  28653. destroy: function(){
  28654. this._cleanupHandlers();
  28655. delete this.child;
  28656. delete this.container;
  28657. delete this.cover;
  28658. delete this.fake;
  28659. this.inherited(arguments);
  28660. }
  28661. });
  28662. var _Gutter = declare("dijit.layout._Gutter", [_Widget, _TemplatedMixin],
  28663. {
  28664. // summary:
  28665. // Just a spacer div to separate side pane from center pane.
  28666. // Basically a trick to lookup the gutter/splitter width from the theme.
  28667. // description:
  28668. // Instantiated by `dijit.layout.BorderContainer`. Users should not
  28669. // create directly.
  28670. // tags:
  28671. // private
  28672. templateString: '<div class="dijitGutter" role="presentation"></div>',
  28673. postMixInProperties: function(){
  28674. this.inherited(arguments);
  28675. this.horizontal = /top|bottom/.test(this.region);
  28676. },
  28677. buildRendering: function(){
  28678. this.inherited(arguments);
  28679. domClass.add(this.domNode, "dijitGutter" + (this.horizontal ? "H" : "V"));
  28680. }
  28681. });
  28682. var BorderContainer = declare("dijit.layout.BorderContainer", _LayoutWidget, {
  28683. // summary:
  28684. // Provides layout in up to 5 regions, a mandatory center with optional borders along its 4 sides.
  28685. //
  28686. // description:
  28687. // A BorderContainer is a box with a specified size, such as style="width: 500px; height: 500px;",
  28688. // that contains a child widget marked region="center" and optionally children widgets marked
  28689. // region equal to "top", "bottom", "leading", "trailing", "left" or "right".
  28690. // Children along the edges will be laid out according to width or height dimensions and may
  28691. // include optional splitters (splitter="true") to make them resizable by the user. The remaining
  28692. // space is designated for the center region.
  28693. //
  28694. // The outer size must be specified on the BorderContainer node. Width must be specified for the sides
  28695. // and height for the top and bottom, respectively. No dimensions should be specified on the center;
  28696. // it will fill the remaining space. Regions named "leading" and "trailing" may be used just like
  28697. // "left" and "right" except that they will be reversed in right-to-left environments.
  28698. //
  28699. // For complex layouts, multiple children can be specified for a single region. In this case, the
  28700. // layoutPriority flag on the children determines which child is closer to the edge (low layoutPriority)
  28701. // and which child is closer to the center (high layoutPriority). layoutPriority can also be used
  28702. // instead of the design attribute to control layout precedence of horizontal vs. vertical panes.
  28703. // example:
  28704. // | <div data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design: 'sidebar', gutters: false"
  28705. // | style="width: 400px; height: 300px;">
  28706. // | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region: 'top'">header text</div>
  28707. // | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region: 'right', splitter: true" style="width: 200px;">table of contents</div>
  28708. // | <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region: 'center'">client area</div>
  28709. // | </div>
  28710. // design: String
  28711. // Which design is used for the layout:
  28712. // - "headline" (default) where the top and bottom extend
  28713. // the full width of the container
  28714. // - "sidebar" where the left and right sides extend from top to bottom.
  28715. design: "headline",
  28716. // gutters: [const] Boolean
  28717. // Give each pane a border and margin.
  28718. // Margin determined by domNode.paddingLeft.
  28719. // When false, only resizable panes have a gutter (i.e. draggable splitter) for resizing.
  28720. gutters: true,
  28721. // liveSplitters: [const] Boolean
  28722. // Specifies whether splitters resize as you drag (true) or only upon mouseup (false)
  28723. liveSplitters: true,
  28724. // persist: Boolean
  28725. // Save splitter positions in a cookie.
  28726. persist: false,
  28727. baseClass: "dijitBorderContainer",
  28728. // _splitterClass: Function||String
  28729. // Optional hook to override the default Splitter widget used by BorderContainer
  28730. _splitterClass: _Splitter,
  28731. postMixInProperties: function(){
  28732. // change class name to indicate that BorderContainer is being used purely for
  28733. // layout (like LayoutContainer) rather than for pretty formatting.
  28734. if(!this.gutters){
  28735. this.baseClass += "NoGutter";
  28736. }
  28737. this.inherited(arguments);
  28738. },
  28739. startup: function(){
  28740. if(this._started){ return; }
  28741. array.forEach(this.getChildren(), this._setupChild, this);
  28742. this.inherited(arguments);
  28743. },
  28744. _setupChild: function(/*dijit._Widget*/ child){
  28745. // Override _LayoutWidget._setupChild().
  28746. var region = child.region;
  28747. if(region){
  28748. this.inherited(arguments);
  28749. domClass.add(child.domNode, this.baseClass+"Pane");
  28750. var ltr = this.isLeftToRight();
  28751. if(region == "leading"){ region = ltr ? "left" : "right"; }
  28752. if(region == "trailing"){ region = ltr ? "right" : "left"; }
  28753. // Create draggable splitter for resizing pane,
  28754. // or alternately if splitter=false but BorderContainer.gutters=true then
  28755. // insert dummy div just for spacing
  28756. if(region != "center" && (child.splitter || this.gutters) && !child._splitterWidget){
  28757. var _Splitter = child.splitter ? this._splitterClass : _Gutter;
  28758. if(lang.isString(_Splitter)){
  28759. _Splitter = lang.getObject(_Splitter); // for back-compat, remove in 2.0
  28760. }
  28761. var splitter = new _Splitter({
  28762. id: child.id + "_splitter",
  28763. container: this,
  28764. child: child,
  28765. region: region,
  28766. live: this.liveSplitters
  28767. });
  28768. splitter.isSplitter = true;
  28769. child._splitterWidget = splitter;
  28770. domConstruct.place(splitter.domNode, child.domNode, "after");
  28771. // Splitters aren't added as Contained children, so we need to call startup explicitly
  28772. splitter.startup();
  28773. }
  28774. child.region = region; // TODO: technically wrong since it overwrites "trailing" with "left" etc.
  28775. }
  28776. },
  28777. layout: function(){
  28778. // Implement _LayoutWidget.layout() virtual method.
  28779. this._layoutChildren();
  28780. },
  28781. addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
  28782. // Override _LayoutWidget.addChild().
  28783. this.inherited(arguments);
  28784. if(this._started){
  28785. this.layout(); //OPT
  28786. }
  28787. },
  28788. removeChild: function(/*dijit._Widget*/ child){
  28789. // Override _LayoutWidget.removeChild().
  28790. var region = child.region;
  28791. var splitter = child._splitterWidget;
  28792. if(splitter){
  28793. splitter.destroy();
  28794. delete child._splitterWidget;
  28795. }
  28796. this.inherited(arguments);
  28797. if(this._started){
  28798. this._layoutChildren();
  28799. }
  28800. // Clean up whatever style changes we made to the child pane.
  28801. // Unclear how height and width should be handled.
  28802. domClass.remove(child.domNode, this.baseClass+"Pane");
  28803. domStyle.set(child.domNode, {
  28804. top: "auto",
  28805. bottom: "auto",
  28806. left: "auto",
  28807. right: "auto",
  28808. position: "static"
  28809. });
  28810. domStyle.set(child.domNode, region == "top" || region == "bottom" ? "width" : "height", "auto");
  28811. },
  28812. getChildren: function(){
  28813. // Override _LayoutWidget.getChildren() to only return real children, not the splitters.
  28814. return array.filter(this.inherited(arguments), function(widget){
  28815. return !widget.isSplitter;
  28816. });
  28817. },
  28818. // TODO: remove in 2.0
  28819. getSplitter: function(/*String*/region){
  28820. // summary:
  28821. // Returns the widget responsible for rendering the splitter associated with region
  28822. // tags:
  28823. // deprecated
  28824. return array.filter(this.getChildren(), function(child){
  28825. return child.region == region;
  28826. })[0]._splitterWidget;
  28827. },
  28828. resize: function(newSize, currentSize){
  28829. // Overrides _LayoutWidget.resize().
  28830. // resetting potential padding to 0px to provide support for 100% width/height + padding
  28831. // TODO: this hack doesn't respect the box model and is a temporary fix
  28832. if(!this.cs || !this.pe){
  28833. var node = this.domNode;
  28834. this.cs = domStyle.getComputedStyle(node);
  28835. this.pe = domGeometry.getPadExtents(node, this.cs);
  28836. this.pe.r = domStyle.toPixelValue(node, this.cs.paddingRight);
  28837. this.pe.b = domStyle.toPixelValue(node, this.cs.paddingBottom);
  28838. domStyle.set(node, "padding", "0px");
  28839. }
  28840. this.inherited(arguments);
  28841. },
  28842. _layoutChildren: function(/*String?*/ changedChildId, /*Number?*/ changedChildSize){
  28843. // summary:
  28844. // This is the main routine for setting size/position of each child.
  28845. // description:
  28846. // With no arguments, measures the height of top/bottom panes, the width
  28847. // of left/right panes, and then sizes all panes accordingly.
  28848. //
  28849. // With changedRegion specified (as "left", "top", "bottom", or "right"),
  28850. // it changes that region's width/height to changedRegionSize and
  28851. // then resizes other regions that were affected.
  28852. // changedChildId:
  28853. // Id of the child which should be resized because splitter was dragged.
  28854. // changedChildSize:
  28855. // The new width/height (in pixels) to make specified child
  28856. if(!this._borderBox || !this._borderBox.h){
  28857. // We are currently hidden, or we haven't been sized by our parent yet.
  28858. // Abort. Someone will resize us later.
  28859. return;
  28860. }
  28861. // Generate list of wrappers of my children in the order that I want layoutChildren()
  28862. // to process them (i.e. from the outside to the inside)
  28863. var wrappers = array.map(this.getChildren(), function(child, idx){
  28864. return {
  28865. pane: child,
  28866. weight: [
  28867. child.region == "center" ? Infinity : 0,
  28868. child.layoutPriority,
  28869. (this.design == "sidebar" ? 1 : -1) * (/top|bottom/.test(child.region) ? 1 : -1),
  28870. idx
  28871. ]
  28872. };
  28873. }, this);
  28874. wrappers.sort(function(a, b){
  28875. var aw = a.weight, bw = b.weight;
  28876. for(var i=0; i<aw.length; i++){
  28877. if(aw[i] != bw[i]){
  28878. return aw[i] - bw[i];
  28879. }
  28880. }
  28881. return 0;
  28882. });
  28883. // Make new list, combining the externally specified children with splitters and gutters
  28884. var childrenAndSplitters = [];
  28885. array.forEach(wrappers, function(wrapper){
  28886. var pane = wrapper.pane;
  28887. childrenAndSplitters.push(pane);
  28888. if(pane._splitterWidget){
  28889. childrenAndSplitters.push(pane._splitterWidget);
  28890. }
  28891. });
  28892. // Compute the box in which to lay out my children
  28893. var dim = {
  28894. l: this.pe.l,
  28895. t: this.pe.t,
  28896. w: this._borderBox.w - this.pe.w,
  28897. h: this._borderBox.h - this.pe.h
  28898. };
  28899. // Layout the children, possibly changing size due to a splitter drag
  28900. layoutUtils.layoutChildren(this.domNode, dim, childrenAndSplitters,
  28901. changedChildId, changedChildSize);
  28902. },
  28903. destroyRecursive: function(){
  28904. // Destroy splitters first, while getChildren() still works
  28905. array.forEach(this.getChildren(), function(child){
  28906. var splitter = child._splitterWidget;
  28907. if(splitter){
  28908. splitter.destroy();
  28909. }
  28910. delete child._splitterWidget;
  28911. });
  28912. // Then destroy the real children, and myself
  28913. this.inherited(arguments);
  28914. }
  28915. });
  28916. // This argument can be specified for the children of a BorderContainer.
  28917. // Since any widget can be specified as a LayoutContainer child, mix it
  28918. // into the base widget class. (This is a hack, but it's effective.)
  28919. lang.extend(_WidgetBase, {
  28920. // region: [const] String
  28921. // Parameter for children of `dijit.layout.BorderContainer`.
  28922. // Values: "top", "bottom", "leading", "trailing", "left", "right", "center".
  28923. // See the `dijit.layout.BorderContainer` description for details.
  28924. region: '',
  28925. // layoutPriority: [const] Number
  28926. // Parameter for children of `dijit.layout.BorderContainer`.
  28927. // Children with a higher layoutPriority will be placed closer to the BorderContainer center,
  28928. // between children with a lower layoutPriority.
  28929. layoutPriority: 0,
  28930. // splitter: [const] Boolean
  28931. // Parameter for child of `dijit.layout.BorderContainer` where region != "center".
  28932. // If true, enables user to resize the widget by putting a draggable splitter between
  28933. // this widget and the region=center widget.
  28934. splitter: false,
  28935. // minSize: [const] Number
  28936. // Parameter for children of `dijit.layout.BorderContainer`.
  28937. // Specifies a minimum size (in pixels) for this widget when resized by a splitter.
  28938. minSize: 0,
  28939. // maxSize: [const] Number
  28940. // Parameter for children of `dijit.layout.BorderContainer`.
  28941. // Specifies a maximum size (in pixels) for this widget when resized by a splitter.
  28942. maxSize: Infinity
  28943. });
  28944. // For monkey patching
  28945. BorderContainer._Splitter = _Splitter;
  28946. BorderContainer._Gutter = _Gutter;
  28947. return BorderContainer;
  28948. });
  28949. },
  28950. 'dojo/window':function(){
  28951. define("dojo/window", ["./_base/lang", "./_base/sniff", "./_base/window", "./dom", "./dom-geometry", "./dom-style"],
  28952. function(lang, has, baseWindow, dom, geom, style) {
  28953. // module:
  28954. // dojo/window
  28955. // summary:
  28956. // TODOC
  28957. var window = lang.getObject("dojo.window", true);
  28958. /*=====
  28959. dojo.window = {
  28960. // summary:
  28961. // TODO
  28962. };
  28963. window = dojo.window;
  28964. =====*/
  28965. window.getBox = function(){
  28966. // summary:
  28967. // Returns the dimensions and scroll position of the viewable area of a browser window
  28968. var
  28969. scrollRoot = (baseWindow.doc.compatMode == 'BackCompat') ? baseWindow.body() : baseWindow.doc.documentElement,
  28970. // get scroll position
  28971. scroll = geom.docScroll(), // scrollRoot.scrollTop/Left should work
  28972. w, h;
  28973. if(has("touch")){ // if(scrollbars not supported)
  28974. var uiWindow = baseWindow.doc.parentWindow || baseWindow.doc.defaultView; // use UI window, not dojo.global window. baseWindow.doc.parentWindow probably not needed since it's not defined for webkit
  28975. // on mobile, scrollRoot.clientHeight <= uiWindow.innerHeight <= scrollRoot.offsetHeight, return uiWindow.innerHeight
  28976. w = uiWindow.innerWidth || scrollRoot.clientWidth; // || scrollRoot.clientXXX probably never evaluated
  28977. h = uiWindow.innerHeight || scrollRoot.clientHeight;
  28978. }else{
  28979. // on desktops, scrollRoot.clientHeight <= scrollRoot.offsetHeight <= uiWindow.innerHeight, return scrollRoot.clientHeight
  28980. // uiWindow.innerWidth/Height includes the scrollbar and cannot be used
  28981. w = scrollRoot.clientWidth;
  28982. h = scrollRoot.clientHeight;
  28983. }
  28984. return {
  28985. l: scroll.x,
  28986. t: scroll.y,
  28987. w: w,
  28988. h: h
  28989. };
  28990. };
  28991. window.get = function(doc){
  28992. // summary:
  28993. // Get window object associated with document doc
  28994. // In some IE versions (at least 6.0), document.parentWindow does not return a
  28995. // reference to the real window object (maybe a copy), so we must fix it as well
  28996. // We use IE specific execScript to attach the real window reference to
  28997. // document._parentWindow for later use
  28998. if(has("ie") && window !== document.parentWindow){
  28999. /*
  29000. In IE 6, only the variable "window" can be used to connect events (others
  29001. may be only copies).
  29002. */
  29003. doc.parentWindow.execScript("document._parentWindow = window;", "Javascript");
  29004. //to prevent memory leak, unset it after use
  29005. //another possibility is to add an onUnload handler which seems overkill to me (liucougar)
  29006. var win = doc._parentWindow;
  29007. doc._parentWindow = null;
  29008. return win; // Window
  29009. }
  29010. return doc.parentWindow || doc.defaultView; // Window
  29011. };
  29012. window.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
  29013. // summary:
  29014. // Scroll the passed node into view, if it is not already.
  29015. // don't rely on node.scrollIntoView working just because the function is there
  29016. try{ // catch unexpected/unrecreatable errors (#7808) since we can recover using a semi-acceptable native method
  29017. node = dom.byId(node);
  29018. var doc = node.ownerDocument || baseWindow.doc,
  29019. body = doc.body || baseWindow.body(),
  29020. html = doc.documentElement || body.parentNode,
  29021. isIE = has("ie"), isWK = has("webkit");
  29022. // if an untested browser, then use the native method
  29023. if((!(has("mozilla") || isIE || isWK || has("opera")) || node == body || node == html) && (typeof node.scrollIntoView != "undefined")){
  29024. node.scrollIntoView(false); // short-circuit to native if possible
  29025. return;
  29026. }
  29027. var backCompat = doc.compatMode == 'BackCompat',
  29028. clientAreaRoot = (isIE >= 9 && node.ownerDocument.parentWindow.frameElement)
  29029. ? ((html.clientHeight > 0 && html.clientWidth > 0 && (body.clientHeight == 0 || body.clientWidth == 0 || body.clientHeight > html.clientHeight || body.clientWidth > html.clientWidth)) ? html : body)
  29030. : (backCompat ? body : html),
  29031. scrollRoot = isWK ? body : clientAreaRoot,
  29032. rootWidth = clientAreaRoot.clientWidth,
  29033. rootHeight = clientAreaRoot.clientHeight,
  29034. rtl = !geom.isBodyLtr(),
  29035. nodePos = pos || geom.position(node),
  29036. el = node.parentNode,
  29037. isFixed = function(el){
  29038. return ((isIE <= 6 || (isIE && backCompat))? false : (style.get(el, 'position').toLowerCase() == "fixed"));
  29039. };
  29040. if(isFixed(node)){ return; } // nothing to do
  29041. while(el){
  29042. if(el == body){ el = scrollRoot; }
  29043. var elPos = geom.position(el),
  29044. fixedPos = isFixed(el);
  29045. if(el == scrollRoot){
  29046. elPos.w = rootWidth; elPos.h = rootHeight;
  29047. if(scrollRoot == html && isIE && rtl){ elPos.x += scrollRoot.offsetWidth-elPos.w; } // IE workaround where scrollbar causes negative x
  29048. if(elPos.x < 0 || !isIE){ elPos.x = 0; } // IE can have values > 0
  29049. if(elPos.y < 0 || !isIE){ elPos.y = 0; }
  29050. }else{
  29051. var pb = geom.getPadBorderExtents(el);
  29052. elPos.w -= pb.w; elPos.h -= pb.h; elPos.x += pb.l; elPos.y += pb.t;
  29053. var clientSize = el.clientWidth,
  29054. scrollBarSize = elPos.w - clientSize;
  29055. if(clientSize > 0 && scrollBarSize > 0){
  29056. elPos.w = clientSize;
  29057. elPos.x += (rtl && (isIE || el.clientLeft > pb.l/*Chrome*/)) ? scrollBarSize : 0;
  29058. }
  29059. clientSize = el.clientHeight;
  29060. scrollBarSize = elPos.h - clientSize;
  29061. if(clientSize > 0 && scrollBarSize > 0){
  29062. elPos.h = clientSize;
  29063. }
  29064. }
  29065. if(fixedPos){ // bounded by viewport, not parents
  29066. if(elPos.y < 0){
  29067. elPos.h += elPos.y; elPos.y = 0;
  29068. }
  29069. if(elPos.x < 0){
  29070. elPos.w += elPos.x; elPos.x = 0;
  29071. }
  29072. if(elPos.y + elPos.h > rootHeight){
  29073. elPos.h = rootHeight - elPos.y;
  29074. }
  29075. if(elPos.x + elPos.w > rootWidth){
  29076. elPos.w = rootWidth - elPos.x;
  29077. }
  29078. }
  29079. // calculate overflow in all 4 directions
  29080. var l = nodePos.x - elPos.x, // beyond left: < 0
  29081. t = nodePos.y - Math.max(elPos.y, 0), // beyond top: < 0
  29082. r = l + nodePos.w - elPos.w, // beyond right: > 0
  29083. bot = t + nodePos.h - elPos.h; // beyond bottom: > 0
  29084. if(r * l > 0){
  29085. var s = Math[l < 0? "max" : "min"](l, r);
  29086. if(rtl && ((isIE == 8 && !backCompat) || isIE >= 9)){ s = -s; }
  29087. nodePos.x += el.scrollLeft;
  29088. el.scrollLeft += s;
  29089. nodePos.x -= el.scrollLeft;
  29090. }
  29091. if(bot * t > 0){
  29092. nodePos.y += el.scrollTop;
  29093. el.scrollTop += Math[t < 0? "max" : "min"](t, bot);
  29094. nodePos.y -= el.scrollTop;
  29095. }
  29096. el = (el != scrollRoot) && !fixedPos && el.parentNode;
  29097. }
  29098. }catch(error){
  29099. console.error('scrollIntoView: ' + error);
  29100. node.scrollIntoView(false);
  29101. }
  29102. };
  29103. return window;
  29104. });
  29105. },
  29106. 'dojo/number':function(){
  29107. define("dojo/number", ["./_base/kernel", "./_base/lang", "./i18n", "./i18n!./cldr/nls/number", "./string", "./regexp"],
  29108. function(dojo, lang, i18n, nlsNumber, dstring, dregexp) {
  29109. // module:
  29110. // dojo/number
  29111. // summary:
  29112. // TODOC
  29113. lang.getObject("number", true, dojo);
  29114. /*=====
  29115. dojo.number = {
  29116. // summary: localized formatting and parsing routines for Number
  29117. }
  29118. dojo.number.__FormatOptions = function(){
  29119. // pattern: String?
  29120. // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  29121. // with this string. Default value is based on locale. Overriding this property will defeat
  29122. // localization. Literal characters in patterns are not supported.
  29123. // type: String?
  29124. // choose a format type based on the locale from the following:
  29125. // decimal, scientific (not yet supported), percent, currency. decimal by default.
  29126. // places: Number?
  29127. // fixed number of decimal places to show. This overrides any
  29128. // information in the provided pattern.
  29129. // round: Number?
  29130. // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
  29131. // means do not round.
  29132. // locale: String?
  29133. // override the locale used to determine formatting rules
  29134. // fractional: Boolean?
  29135. // If false, show no decimal places, overriding places and pattern settings.
  29136. this.pattern = pattern;
  29137. this.type = type;
  29138. this.places = places;
  29139. this.round = round;
  29140. this.locale = locale;
  29141. this.fractional = fractional;
  29142. }
  29143. =====*/
  29144. dojo.number.format = function(/*Number*/value, /*dojo.number.__FormatOptions?*/options){
  29145. // summary:
  29146. // Format a Number as a String, using locale-specific settings
  29147. // description:
  29148. // Create a string from a Number using a known localized pattern.
  29149. // Formatting patterns appropriate to the locale are chosen from the
  29150. // [Common Locale Data Repository](http://unicode.org/cldr) as well as the appropriate symbols and
  29151. // delimiters.
  29152. // If value is Infinity, -Infinity, or is not a valid JavaScript number, return null.
  29153. // value:
  29154. // the number to be formatted
  29155. options = lang.mixin({}, options || {});
  29156. var locale = i18n.normalizeLocale(options.locale),
  29157. bundle = i18n.getLocalization("dojo.cldr", "number", locale);
  29158. options.customs = bundle;
  29159. var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"];
  29160. if(isNaN(value) || Math.abs(value) == Infinity){ return null; } // null
  29161. return dojo.number._applyPattern(value, pattern, options); // String
  29162. };
  29163. //dojo.number._numberPatternRE = /(?:[#0]*,?)*[#0](?:\.0*#*)?/; // not precise, but good enough
  29164. dojo.number._numberPatternRE = /[#0,]*[#0](?:\.0*#*)?/; // not precise, but good enough
  29165. dojo.number._applyPattern = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatOptions?*/options){
  29166. // summary:
  29167. // Apply pattern to format value as a string using options. Gives no
  29168. // consideration to local customs.
  29169. // value:
  29170. // the number to be formatted.
  29171. // pattern:
  29172. // a pattern string as described by
  29173. // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  29174. // options: dojo.number.__FormatOptions?
  29175. // _applyPattern is usually called via `dojo.number.format()` which
  29176. // populates an extra property in the options parameter, "customs".
  29177. // The customs object specifies group and decimal parameters if set.
  29178. //TODO: support escapes
  29179. options = options || {};
  29180. var group = options.customs.group,
  29181. decimal = options.customs.decimal,
  29182. patternList = pattern.split(';'),
  29183. positivePattern = patternList[0];
  29184. pattern = patternList[(value < 0) ? 1 : 0] || ("-" + positivePattern);
  29185. //TODO: only test against unescaped
  29186. if(pattern.indexOf('%') != -1){
  29187. value *= 100;
  29188. }else if(pattern.indexOf('\u2030') != -1){
  29189. value *= 1000; // per mille
  29190. }else if(pattern.indexOf('\u00a4') != -1){
  29191. group = options.customs.currencyGroup || group;//mixins instead?
  29192. decimal = options.customs.currencyDecimal || decimal;// Should these be mixins instead?
  29193. pattern = pattern.replace(/\u00a4{1,3}/, function(match){
  29194. var prop = ["symbol", "currency", "displayName"][match.length-1];
  29195. return options[prop] || options.currency || "";
  29196. });
  29197. }else if(pattern.indexOf('E') != -1){
  29198. throw new Error("exponential notation not supported");
  29199. }
  29200. //TODO: support @ sig figs?
  29201. var numberPatternRE = dojo.number._numberPatternRE;
  29202. var numberPattern = positivePattern.match(numberPatternRE);
  29203. if(!numberPattern){
  29204. throw new Error("unable to find a number expression in pattern: "+pattern);
  29205. }
  29206. if(options.fractional === false){ options.places = 0; }
  29207. return pattern.replace(numberPatternRE,
  29208. dojo.number._formatAbsolute(value, numberPattern[0], {decimal: decimal, group: group, places: options.places, round: options.round}));
  29209. };
  29210. dojo.number.round = function(/*Number*/value, /*Number?*/places, /*Number?*/increment){
  29211. // summary:
  29212. // Rounds to the nearest value with the given number of decimal places, away from zero
  29213. // description:
  29214. // Rounds to the nearest value with the given number of decimal places, away from zero if equal.
  29215. // Similar to Number.toFixed(), but compensates for browser quirks. Rounding can be done by
  29216. // fractional increments also, such as the nearest quarter.
  29217. // NOTE: Subject to floating point errors. See dojox.math.round for experimental workaround.
  29218. // value:
  29219. // The number to round
  29220. // places:
  29221. // The number of decimal places where rounding takes place. Defaults to 0 for whole rounding.
  29222. // Must be non-negative.
  29223. // increment:
  29224. // Rounds next place to nearest value of increment/10. 10 by default.
  29225. // example:
  29226. // >>> dojo.number.round(-0.5)
  29227. // -1
  29228. // >>> dojo.number.round(162.295, 2)
  29229. // 162.29 // note floating point error. Should be 162.3
  29230. // >>> dojo.number.round(10.71, 0, 2.5)
  29231. // 10.75
  29232. var factor = 10 / (increment || 10);
  29233. return (factor * +value).toFixed(places) / factor; // Number
  29234. };
  29235. if((0.9).toFixed() == 0){
  29236. // (isIE) toFixed() bug workaround: Rounding fails on IE when most significant digit
  29237. // is just after the rounding place and is >=5
  29238. var round = dojo.number.round;
  29239. dojo.number.round = function(v, p, m){
  29240. var d = Math.pow(10, -p || 0), a = Math.abs(v);
  29241. if(!v || a >= d || a * Math.pow(10, p + 1) < 5){
  29242. d = 0;
  29243. }
  29244. return round(v, p, m) + (v > 0 ? d : -d);
  29245. };
  29246. }
  29247. /*=====
  29248. dojo.number.__FormatAbsoluteOptions = function(){
  29249. // decimal: String?
  29250. // the decimal separator
  29251. // group: String?
  29252. // the group separator
  29253. // places: Number?|String?
  29254. // number of decimal places. the range "n,m" will format to m places.
  29255. // round: Number?
  29256. // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
  29257. // means don't round.
  29258. this.decimal = decimal;
  29259. this.group = group;
  29260. this.places = places;
  29261. this.round = round;
  29262. }
  29263. =====*/
  29264. dojo.number._formatAbsolute = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatAbsoluteOptions?*/options){
  29265. // summary:
  29266. // Apply numeric pattern to absolute value using options. Gives no
  29267. // consideration to local customs.
  29268. // value:
  29269. // the number to be formatted, ignores sign
  29270. // pattern:
  29271. // the number portion of a pattern (e.g. `#,##0.00`)
  29272. options = options || {};
  29273. if(options.places === true){options.places=0;}
  29274. if(options.places === Infinity){options.places=6;} // avoid a loop; pick a limit
  29275. var patternParts = pattern.split("."),
  29276. comma = typeof options.places == "string" && options.places.indexOf(","),
  29277. maxPlaces = options.places;
  29278. if(comma){
  29279. maxPlaces = options.places.substring(comma + 1);
  29280. }else if(!(maxPlaces >= 0)){
  29281. maxPlaces = (patternParts[1] || []).length;
  29282. }
  29283. if(!(options.round < 0)){
  29284. value = dojo.number.round(value, maxPlaces, options.round);
  29285. }
  29286. var valueParts = String(Math.abs(value)).split("."),
  29287. fractional = valueParts[1] || "";
  29288. if(patternParts[1] || options.places){
  29289. if(comma){
  29290. options.places = options.places.substring(0, comma);
  29291. }
  29292. // Pad fractional with trailing zeros
  29293. var pad = options.places !== undefined ? options.places : (patternParts[1] && patternParts[1].lastIndexOf("0") + 1);
  29294. if(pad > fractional.length){
  29295. valueParts[1] = dstring.pad(fractional, pad, '0', true);
  29296. }
  29297. // Truncate fractional
  29298. if(maxPlaces < fractional.length){
  29299. valueParts[1] = fractional.substr(0, maxPlaces);
  29300. }
  29301. }else{
  29302. if(valueParts[1]){ valueParts.pop(); }
  29303. }
  29304. // Pad whole with leading zeros
  29305. var patternDigits = patternParts[0].replace(',', '');
  29306. pad = patternDigits.indexOf("0");
  29307. if(pad != -1){
  29308. pad = patternDigits.length - pad;
  29309. if(pad > valueParts[0].length){
  29310. valueParts[0] = dstring.pad(valueParts[0], pad);
  29311. }
  29312. // Truncate whole
  29313. if(patternDigits.indexOf("#") == -1){
  29314. valueParts[0] = valueParts[0].substr(valueParts[0].length - pad);
  29315. }
  29316. }
  29317. // Add group separators
  29318. var index = patternParts[0].lastIndexOf(','),
  29319. groupSize, groupSize2;
  29320. if(index != -1){
  29321. groupSize = patternParts[0].length - index - 1;
  29322. var remainder = patternParts[0].substr(0, index);
  29323. index = remainder.lastIndexOf(',');
  29324. if(index != -1){
  29325. groupSize2 = remainder.length - index - 1;
  29326. }
  29327. }
  29328. var pieces = [];
  29329. for(var whole = valueParts[0]; whole;){
  29330. var off = whole.length - groupSize;
  29331. pieces.push((off > 0) ? whole.substr(off) : whole);
  29332. whole = (off > 0) ? whole.slice(0, off) : "";
  29333. if(groupSize2){
  29334. groupSize = groupSize2;
  29335. delete groupSize2;
  29336. }
  29337. }
  29338. valueParts[0] = pieces.reverse().join(options.group || ",");
  29339. return valueParts.join(options.decimal || ".");
  29340. };
  29341. /*=====
  29342. dojo.number.__RegexpOptions = function(){
  29343. // pattern: String?
  29344. // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  29345. // with this string. Default value is based on locale. Overriding this property will defeat
  29346. // localization.
  29347. // type: String?
  29348. // choose a format type based on the locale from the following:
  29349. // decimal, scientific (not yet supported), percent, currency. decimal by default.
  29350. // locale: String?
  29351. // override the locale used to determine formatting rules
  29352. // strict: Boolean?
  29353. // strict parsing, false by default. Strict parsing requires input as produced by the format() method.
  29354. // Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators
  29355. // places: Number|String?
  29356. // number of decimal places to accept: Infinity, a positive number, or
  29357. // a range "n,m". Defined by pattern or Infinity if pattern not provided.
  29358. this.pattern = pattern;
  29359. this.type = type;
  29360. this.locale = locale;
  29361. this.strict = strict;
  29362. this.places = places;
  29363. }
  29364. =====*/
  29365. dojo.number.regexp = function(/*dojo.number.__RegexpOptions?*/options){
  29366. // summary:
  29367. // Builds the regular needed to parse a number
  29368. // description:
  29369. // Returns regular expression with positive and negative match, group
  29370. // and decimal separators
  29371. return dojo.number._parseInfo(options).regexp; // String
  29372. };
  29373. dojo.number._parseInfo = function(/*Object?*/options){
  29374. options = options || {};
  29375. var locale = i18n.normalizeLocale(options.locale),
  29376. bundle = i18n.getLocalization("dojo.cldr", "number", locale),
  29377. pattern = options.pattern || bundle[(options.type || "decimal") + "Format"],
  29378. //TODO: memoize?
  29379. group = bundle.group,
  29380. decimal = bundle.decimal,
  29381. factor = 1;
  29382. if(pattern.indexOf('%') != -1){
  29383. factor /= 100;
  29384. }else if(pattern.indexOf('\u2030') != -1){
  29385. factor /= 1000; // per mille
  29386. }else{
  29387. var isCurrency = pattern.indexOf('\u00a4') != -1;
  29388. if(isCurrency){
  29389. group = bundle.currencyGroup || group;
  29390. decimal = bundle.currencyDecimal || decimal;
  29391. }
  29392. }
  29393. //TODO: handle quoted escapes
  29394. var patternList = pattern.split(';');
  29395. if(patternList.length == 1){
  29396. patternList.push("-" + patternList[0]);
  29397. }
  29398. var re = dregexp.buildGroupRE(patternList, function(pattern){
  29399. pattern = "(?:"+dregexp.escapeString(pattern, '.')+")";
  29400. return pattern.replace(dojo.number._numberPatternRE, function(format){
  29401. var flags = {
  29402. signed: false,
  29403. separator: options.strict ? group : [group,""],
  29404. fractional: options.fractional,
  29405. decimal: decimal,
  29406. exponent: false
  29407. },
  29408. parts = format.split('.'),
  29409. places = options.places;
  29410. // special condition for percent (factor != 1)
  29411. // allow decimal places even if not specified in pattern
  29412. if(parts.length == 1 && factor != 1){
  29413. parts[1] = "###";
  29414. }
  29415. if(parts.length == 1 || places === 0){
  29416. flags.fractional = false;
  29417. }else{
  29418. if(places === undefined){ places = options.pattern ? parts[1].lastIndexOf('0') + 1 : Infinity; }
  29419. if(places && options.fractional == undefined){flags.fractional = true;} // required fractional, unless otherwise specified
  29420. if(!options.places && (places < parts[1].length)){ places += "," + parts[1].length; }
  29421. flags.places = places;
  29422. }
  29423. var groups = parts[0].split(',');
  29424. if(groups.length > 1){
  29425. flags.groupSize = groups.pop().length;
  29426. if(groups.length > 1){
  29427. flags.groupSize2 = groups.pop().length;
  29428. }
  29429. }
  29430. return "("+dojo.number._realNumberRegexp(flags)+")";
  29431. });
  29432. }, true);
  29433. if(isCurrency){
  29434. // substitute the currency symbol for the placeholder in the pattern
  29435. re = re.replace(/([\s\xa0]*)(\u00a4{1,3})([\s\xa0]*)/g, function(match, before, target, after){
  29436. var prop = ["symbol", "currency", "displayName"][target.length-1],
  29437. symbol = dregexp.escapeString(options[prop] || options.currency || "");
  29438. before = before ? "[\\s\\xa0]" : "";
  29439. after = after ? "[\\s\\xa0]" : "";
  29440. if(!options.strict){
  29441. if(before){before += "*";}
  29442. if(after){after += "*";}
  29443. return "(?:"+before+symbol+after+")?";
  29444. }
  29445. return before+symbol+after;
  29446. });
  29447. }
  29448. //TODO: substitute localized sign/percent/permille/etc.?
  29449. // normalize whitespace and return
  29450. return {regexp: re.replace(/[\xa0 ]/g, "[\\s\\xa0]"), group: group, decimal: decimal, factor: factor}; // Object
  29451. };
  29452. /*=====
  29453. dojo.number.__ParseOptions = function(){
  29454. // pattern: String?
  29455. // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  29456. // with this string. Default value is based on locale. Overriding this property will defeat
  29457. // localization. Literal characters in patterns are not supported.
  29458. // type: String?
  29459. // choose a format type based on the locale from the following:
  29460. // decimal, scientific (not yet supported), percent, currency. decimal by default.
  29461. // locale: String?
  29462. // override the locale used to determine formatting rules
  29463. // strict: Boolean?
  29464. // strict parsing, false by default. Strict parsing requires input as produced by the format() method.
  29465. // Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators
  29466. // fractional: Boolean?|Array?
  29467. // Whether to include the fractional portion, where the number of decimal places are implied by pattern
  29468. // or explicit 'places' parameter. The value [true,false] makes the fractional portion optional.
  29469. this.pattern = pattern;
  29470. this.type = type;
  29471. this.locale = locale;
  29472. this.strict = strict;
  29473. this.fractional = fractional;
  29474. }
  29475. =====*/
  29476. dojo.number.parse = function(/*String*/expression, /*dojo.number.__ParseOptions?*/options){
  29477. // summary:
  29478. // Convert a properly formatted string to a primitive Number, using
  29479. // locale-specific settings.
  29480. // description:
  29481. // Create a Number from a string using a known localized pattern.
  29482. // Formatting patterns are chosen appropriate to the locale
  29483. // and follow the syntax described by
  29484. // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  29485. // Note that literal characters in patterns are not supported.
  29486. // expression:
  29487. // A string representation of a Number
  29488. var info = dojo.number._parseInfo(options),
  29489. results = (new RegExp("^"+info.regexp+"$")).exec(expression);
  29490. if(!results){
  29491. return NaN; //NaN
  29492. }
  29493. var absoluteMatch = results[1]; // match for the positive expression
  29494. if(!results[1]){
  29495. if(!results[2]){
  29496. return NaN; //NaN
  29497. }
  29498. // matched the negative pattern
  29499. absoluteMatch =results[2];
  29500. info.factor *= -1;
  29501. }
  29502. // Transform it to something Javascript can parse as a number. Normalize
  29503. // decimal point and strip out group separators or alternate forms of whitespace
  29504. absoluteMatch = absoluteMatch.
  29505. replace(new RegExp("["+info.group + "\\s\\xa0"+"]", "g"), "").
  29506. replace(info.decimal, ".");
  29507. // Adjust for negative sign, percent, etc. as necessary
  29508. return absoluteMatch * info.factor; //Number
  29509. };
  29510. /*=====
  29511. dojo.number.__RealNumberRegexpFlags = function(){
  29512. // places: Number?
  29513. // The integer number of decimal places or a range given as "n,m". If
  29514. // not given, the decimal part is optional and the number of places is
  29515. // unlimited.
  29516. // decimal: String?
  29517. // A string for the character used as the decimal point. Default
  29518. // is ".".
  29519. // fractional: Boolean?|Array?
  29520. // Whether decimal places are used. Can be true, false, or [true,
  29521. // false]. Default is [true, false] which means optional.
  29522. // exponent: Boolean?|Array?
  29523. // Express in exponential notation. Can be true, false, or [true,
  29524. // false]. Default is [true, false], (i.e. will match if the
  29525. // exponential part is present are not).
  29526. // eSigned: Boolean?|Array?
  29527. // The leading plus-or-minus sign on the exponent. Can be true,
  29528. // false, or [true, false]. Default is [true, false], (i.e. will
  29529. // match if it is signed or unsigned). flags in regexp.integer can be
  29530. // applied.
  29531. this.places = places;
  29532. this.decimal = decimal;
  29533. this.fractional = fractional;
  29534. this.exponent = exponent;
  29535. this.eSigned = eSigned;
  29536. }
  29537. =====*/
  29538. dojo.number._realNumberRegexp = function(/*dojo.number.__RealNumberRegexpFlags?*/flags){
  29539. // summary:
  29540. // Builds a regular expression to match a real number in exponential
  29541. // notation
  29542. // assign default values to missing parameters
  29543. flags = flags || {};
  29544. //TODO: use mixin instead?
  29545. if(!("places" in flags)){ flags.places = Infinity; }
  29546. if(typeof flags.decimal != "string"){ flags.decimal = "."; }
  29547. if(!("fractional" in flags) || /^0/.test(flags.places)){ flags.fractional = [true, false]; }
  29548. if(!("exponent" in flags)){ flags.exponent = [true, false]; }
  29549. if(!("eSigned" in flags)){ flags.eSigned = [true, false]; }
  29550. var integerRE = dojo.number._integerRegexp(flags),
  29551. decimalRE = dregexp.buildGroupRE(flags.fractional,
  29552. function(q){
  29553. var re = "";
  29554. if(q && (flags.places!==0)){
  29555. re = "\\" + flags.decimal;
  29556. if(flags.places == Infinity){
  29557. re = "(?:" + re + "\\d+)?";
  29558. }else{
  29559. re += "\\d{" + flags.places + "}";
  29560. }
  29561. }
  29562. return re;
  29563. },
  29564. true
  29565. );
  29566. var exponentRE = dregexp.buildGroupRE(flags.exponent,
  29567. function(q){
  29568. if(q){ return "([eE]" + dojo.number._integerRegexp({ signed: flags.eSigned}) + ")"; }
  29569. return "";
  29570. }
  29571. );
  29572. var realRE = integerRE + decimalRE;
  29573. // allow for decimals without integers, e.g. .25
  29574. if(decimalRE){realRE = "(?:(?:"+ realRE + ")|(?:" + decimalRE + "))";}
  29575. return realRE + exponentRE; // String
  29576. };
  29577. /*=====
  29578. dojo.number.__IntegerRegexpFlags = function(){
  29579. // signed: Boolean?
  29580. // The leading plus-or-minus sign. Can be true, false, or `[true,false]`.
  29581. // Default is `[true, false]`, (i.e. will match if it is signed
  29582. // or unsigned).
  29583. // separator: String?
  29584. // The character used as the thousands separator. Default is no
  29585. // separator. For more than one symbol use an array, e.g. `[",", ""]`,
  29586. // makes ',' optional.
  29587. // groupSize: Number?
  29588. // group size between separators
  29589. // groupSize2: Number?
  29590. // second grouping, where separators 2..n have a different interval than the first separator (for India)
  29591. this.signed = signed;
  29592. this.separator = separator;
  29593. this.groupSize = groupSize;
  29594. this.groupSize2 = groupSize2;
  29595. }
  29596. =====*/
  29597. dojo.number._integerRegexp = function(/*dojo.number.__IntegerRegexpFlags?*/flags){
  29598. // summary:
  29599. // Builds a regular expression that matches an integer
  29600. // assign default values to missing parameters
  29601. flags = flags || {};
  29602. if(!("signed" in flags)){ flags.signed = [true, false]; }
  29603. if(!("separator" in flags)){
  29604. flags.separator = "";
  29605. }else if(!("groupSize" in flags)){
  29606. flags.groupSize = 3;
  29607. }
  29608. var signRE = dregexp.buildGroupRE(flags.signed,
  29609. function(q){ return q ? "[-+]" : ""; },
  29610. true
  29611. );
  29612. var numberRE = dregexp.buildGroupRE(flags.separator,
  29613. function(sep){
  29614. if(!sep){
  29615. return "(?:\\d+)";
  29616. }
  29617. sep = dregexp.escapeString(sep);
  29618. if(sep == " "){ sep = "\\s"; }
  29619. else if(sep == "\xa0"){ sep = "\\s\\xa0"; }
  29620. var grp = flags.groupSize, grp2 = flags.groupSize2;
  29621. //TODO: should we continue to enforce that numbers with separators begin with 1-9? See #6933
  29622. if(grp2){
  29623. var grp2RE = "(?:0|[1-9]\\d{0," + (grp2-1) + "}(?:[" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})";
  29624. return ((grp-grp2) > 0) ? "(?:" + grp2RE + "|(?:0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE;
  29625. }
  29626. return "(?:0|[1-9]\\d{0," + (grp-1) + "}(?:[" + sep + "]\\d{" + grp + "})*)";
  29627. },
  29628. true
  29629. );
  29630. return signRE + numberRE; // String
  29631. };
  29632. return dojo.number;
  29633. });
  29634. },
  29635. 'dojox/timing':function(){
  29636. define("dojox/timing", ["./timing/_base"], function(timing){
  29637. return timing;
  29638. });
  29639. },
  29640. 'dijit/_FocusMixin':function(){
  29641. define("dijit/_FocusMixin", [
  29642. "./focus",
  29643. "./_WidgetBase",
  29644. "dojo/_base/declare", // declare
  29645. "dojo/_base/lang" // lang.extend
  29646. ], function(focus, _WidgetBase, declare, lang){
  29647. /*=====
  29648. var _WidgetBase = dijit._WidgetBase;
  29649. =====*/
  29650. // module:
  29651. // dijit/_FocusMixin
  29652. // summary:
  29653. // Mixin to widget to provide _onFocus() and _onBlur() methods that
  29654. // fire when a widget or it's descendants get/lose focus
  29655. // We don't know where _FocusMixin will occur in the inheritance chain, but we need the _onFocus()/_onBlur() below
  29656. // to be last in the inheritance chain, so mixin to _WidgetBase.
  29657. lang.extend(_WidgetBase, {
  29658. // focused: [readonly] Boolean
  29659. // This widget or a widget it contains has focus, or is "active" because
  29660. // it was recently clicked.
  29661. focused: false,
  29662. onFocus: function(){
  29663. // summary:
  29664. // Called when the widget becomes "active" because
  29665. // it or a widget inside of it either has focus, or has recently
  29666. // been clicked.
  29667. // tags:
  29668. // callback
  29669. },
  29670. onBlur: function(){
  29671. // summary:
  29672. // Called when the widget stops being "active" because
  29673. // focus moved to something outside of it, or the user
  29674. // clicked somewhere outside of it, or the widget was
  29675. // hidden.
  29676. // tags:
  29677. // callback
  29678. },
  29679. _onFocus: function(){
  29680. // summary:
  29681. // This is where widgets do processing for when they are active,
  29682. // such as changing CSS classes. See onFocus() for more details.
  29683. // tags:
  29684. // protected
  29685. this.onFocus();
  29686. },
  29687. _onBlur: function(){
  29688. // summary:
  29689. // This is where widgets do processing for when they stop being active,
  29690. // such as changing CSS classes. See onBlur() for more details.
  29691. // tags:
  29692. // protected
  29693. this.onBlur();
  29694. }
  29695. });
  29696. return declare("dijit._FocusMixin", null, {
  29697. // summary:
  29698. // Mixin to widget to provide _onFocus() and _onBlur() methods that
  29699. // fire when a widget or it's descendants get/lose focus
  29700. // flag that I want _onFocus()/_onBlur() notifications from focus manager
  29701. _focusManager: focus
  29702. });
  29703. });
  29704. },
  29705. 'dojo/data/util/filter':function(){
  29706. define("dojo/data/util/filter", ["dojo/_base/lang"], function(lang) {
  29707. // module:
  29708. // dojo/data/util/filter
  29709. // summary:
  29710. // TODOC
  29711. var filter = lang.getObject("dojo.data.util.filter", true);
  29712. filter.patternToRegExp = function(/*String*/pattern, /*boolean?*/ ignoreCase){
  29713. // summary:
  29714. // Helper function to convert a simple pattern to a regular expression for matching.
  29715. // description:
  29716. // Returns a regular expression object that conforms to the defined conversion rules.
  29717. // For example:
  29718. // ca* -> /^ca.*$/
  29719. // *ca* -> /^.*ca.*$/
  29720. // *c\*a* -> /^.*c\*a.*$/
  29721. // *c\*a?* -> /^.*c\*a..*$/
  29722. // and so on.
  29723. //
  29724. // pattern: string
  29725. // A simple matching pattern to convert that follows basic rules:
  29726. // * Means match anything, so ca* means match anything starting with ca
  29727. // ? Means match single character. So, b?b will match to bob and bab, and so on.
  29728. // \ is an escape character. So for example, \* means do not treat * as a match, but literal character *.
  29729. // To use a \ as a character in the string, it must be escaped. So in the pattern it should be
  29730. // represented by \\ to be treated as an ordinary \ character instead of an escape.
  29731. //
  29732. // ignoreCase:
  29733. // An optional flag to indicate if the pattern matching should be treated as case-sensitive or not when comparing
  29734. // By default, it is assumed case sensitive.
  29735. var rxp = "^";
  29736. var c = null;
  29737. for(var i = 0; i < pattern.length; i++){
  29738. c = pattern.charAt(i);
  29739. switch(c){
  29740. case '\\':
  29741. rxp += c;
  29742. i++;
  29743. rxp += pattern.charAt(i);
  29744. break;
  29745. case '*':
  29746. rxp += ".*"; break;
  29747. case '?':
  29748. rxp += "."; break;
  29749. case '$':
  29750. case '^':
  29751. case '/':
  29752. case '+':
  29753. case '.':
  29754. case '|':
  29755. case '(':
  29756. case ')':
  29757. case '{':
  29758. case '}':
  29759. case '[':
  29760. case ']':
  29761. rxp += "\\"; //fallthrough
  29762. default:
  29763. rxp += c;
  29764. }
  29765. }
  29766. rxp += "$";
  29767. if(ignoreCase){
  29768. return new RegExp(rxp,"mi"); //RegExp
  29769. }else{
  29770. return new RegExp(rxp,"m"); //RegExp
  29771. }
  29772. };
  29773. return filter;
  29774. });
  29775. },
  29776. 'dijit/_WidgetsInTemplateMixin':function(){
  29777. define("dijit/_WidgetsInTemplateMixin", [
  29778. "dojo/_base/array", // array.forEach
  29779. "dojo/_base/declare", // declare
  29780. "dojo/parser", // parser.parse
  29781. "dijit/registry" // registry.findWidgets
  29782. ], function(array, declare, parser, registry){
  29783. // module:
  29784. // dijit/_WidgetsInTemplateMixin
  29785. // summary:
  29786. // Mixin to supplement _TemplatedMixin when template contains widgets
  29787. return declare("dijit._WidgetsInTemplateMixin", null, {
  29788. // summary:
  29789. // Mixin to supplement _TemplatedMixin when template contains widgets
  29790. // _earlyTemplatedStartup: Boolean
  29791. // A fallback to preserve the 1.0 - 1.3 behavior of children in
  29792. // templates having their startup called before the parent widget
  29793. // fires postCreate. Defaults to 'false', causing child widgets to
  29794. // have their .startup() called immediately before a parent widget
  29795. // .startup(), but always after the parent .postCreate(). Set to
  29796. // 'true' to re-enable to previous, arguably broken, behavior.
  29797. _earlyTemplatedStartup: false,
  29798. // widgetsInTemplate: [protected] Boolean
  29799. // Should we parse the template to find widgets that might be
  29800. // declared in markup inside it? (Remove for 2.0 and assume true)
  29801. widgetsInTemplate: true,
  29802. _beforeFillContent: function(){
  29803. if(this.widgetsInTemplate){
  29804. // Before copying over content, instantiate widgets in template
  29805. var node = this.domNode;
  29806. var cw = (this._startupWidgets = parser.parse(node, {
  29807. noStart: !this._earlyTemplatedStartup,
  29808. template: true,
  29809. inherited: {dir: this.dir, lang: this.lang, textDir: this.textDir},
  29810. propsThis: this, // so data-dojo-props of widgets in the template can reference "this" to refer to me
  29811. scope: "dojo" // even in multi-version mode templates use dojoType/data-dojo-type
  29812. }));
  29813. this._supportingWidgets = registry.findWidgets(node);
  29814. this._attachTemplateNodes(cw, function(n,p){
  29815. return n[p];
  29816. });
  29817. }
  29818. },
  29819. startup: function(){
  29820. array.forEach(this._startupWidgets, function(w){
  29821. if(w && !w._started && w.startup){
  29822. w.startup();
  29823. }
  29824. });
  29825. this.inherited(arguments);
  29826. }
  29827. });
  29828. });
  29829. },
  29830. 'dojox/grid/_Builder':function(){
  29831. define("dojox/grid/_Builder", [
  29832. "../main",
  29833. "dojo/_base/array",
  29834. "dojo/_base/lang",
  29835. "dojo/_base/window",
  29836. "dojo/_base/event",
  29837. "dojo/_base/sniff",
  29838. "dojo/_base/connect",
  29839. "dojo/dnd/Moveable",
  29840. "dojox/html/metrics",
  29841. "./util",
  29842. "dojo/_base/html"
  29843. ], function(dojox, array, lang, win, event, has, connect, Moveable, metrics, util, html){
  29844. var dg = dojox.grid;
  29845. var getTdIndex = function(td){
  29846. return td.cellIndex >=0 ? td.cellIndex : array.indexOf(td.parentNode.cells, td);
  29847. };
  29848. var getTrIndex = function(tr){
  29849. return tr.rowIndex >=0 ? tr.rowIndex : array.indexOf(tr.parentNode.childNodes, tr);
  29850. };
  29851. var getTr = function(rowOwner, index){
  29852. return rowOwner && ((rowOwner.rows||0)[index] || rowOwner.childNodes[index]);
  29853. };
  29854. var findTable = function(node){
  29855. for(var n=node; n && n.tagName!='TABLE'; n=n.parentNode){}
  29856. return n;
  29857. };
  29858. var ascendDom = function(inNode, inWhile){
  29859. for(var n=inNode; n && inWhile(n); n=n.parentNode){}
  29860. return n;
  29861. };
  29862. var makeNotTagName = function(inTagName){
  29863. var name = inTagName.toUpperCase();
  29864. return function(node){ return node.tagName != name; };
  29865. };
  29866. var rowIndexTag = util.rowIndexTag;
  29867. var gridViewTag = util.gridViewTag;
  29868. // base class for generating markup for the views
  29869. var _Builder = dg._Builder = lang.extend(function(view){
  29870. if(view){
  29871. this.view = view;
  29872. this.grid = view.grid;
  29873. }
  29874. },{
  29875. view: null,
  29876. // boilerplate HTML
  29877. _table: '<table class="dojoxGridRowTable" border="0" cellspacing="0" cellpadding="0" role="presentation"',
  29878. // Returns the table variable as an array - and with the view width, if specified
  29879. getTableArray: function(){
  29880. var html = [this._table];
  29881. if(this.view.viewWidth){
  29882. html.push([' style="width:', this.view.viewWidth, ';"'].join(''));
  29883. }
  29884. html.push('>');
  29885. return html;
  29886. },
  29887. // generate starting tags for a cell
  29888. generateCellMarkup: function(inCell, inMoreStyles, inMoreClasses, isHeader){
  29889. var result = [], html;
  29890. if(isHeader){
  29891. var sortInfo = inCell.index != inCell.grid.getSortIndex() ? "" : inCell.grid.sortInfo > 0 ? 'aria-sort="ascending"' : 'aria-sort="descending"';
  29892. if (!inCell.id){
  29893. inCell.id = this.grid.id + "Hdr" + inCell.index;
  29894. }
  29895. // column headers are not editable, mark as aria-readonly=true
  29896. html = ['<th tabIndex="-1" aria-readonly="true" role="columnheader"', sortInfo, 'id="', inCell.id, '"'];
  29897. }else{
  29898. // cells inherit grid aria-readonly property; default value for aria-readonly is false(grid is editable)
  29899. // if grid is editable (had any editable cells), mark non editable cells as aria-readonly=true
  29900. // if no editable cells, grid's aria-readonly value will have been set to true and cells will inherit
  29901. var editInfo = this.grid.editable && !inCell.editable ? 'aria-readonly="true"' : "";
  29902. html = ['<td tabIndex="-1" role="gridcell"', editInfo];
  29903. }
  29904. if(inCell.colSpan){
  29905. html.push(' colspan="', inCell.colSpan, '"');
  29906. }
  29907. if(inCell.rowSpan){
  29908. html.push(' rowspan="', inCell.rowSpan, '"');
  29909. }
  29910. html.push(' class="dojoxGridCell ');
  29911. if(inCell.classes){
  29912. html.push(inCell.classes, ' ');
  29913. }
  29914. if(inMoreClasses){
  29915. html.push(inMoreClasses, ' ');
  29916. }
  29917. // result[0] => td opener, style
  29918. result.push(html.join(''));
  29919. // SLOT: result[1] => td classes
  29920. result.push('');
  29921. html = ['" idx="', inCell.index, '" style="'];
  29922. if(inMoreStyles && inMoreStyles[inMoreStyles.length-1] != ';'){
  29923. inMoreStyles += ';';
  29924. }
  29925. html.push(inCell.styles, inMoreStyles||'', inCell.hidden?'display:none;':'');
  29926. if(inCell.unitWidth){
  29927. html.push('width:', inCell.unitWidth, ';');
  29928. }
  29929. // result[2] => markup
  29930. result.push(html.join(''));
  29931. // SLOT: result[3] => td style
  29932. result.push('');
  29933. html = [ '"' ];
  29934. if(inCell.attrs){
  29935. html.push(" ", inCell.attrs);
  29936. }
  29937. html.push('>');
  29938. // result[4] => td postfix
  29939. result.push(html.join(''));
  29940. // SLOT: result[5] => content
  29941. result.push('');
  29942. // result[6] => td closes
  29943. result.push(isHeader?'</th>':'</td>');
  29944. return result; // Array
  29945. },
  29946. // cell finding
  29947. isCellNode: function(inNode){
  29948. return Boolean(inNode && inNode!=win.doc && html.attr(inNode, "idx"));
  29949. },
  29950. getCellNodeIndex: function(inCellNode){
  29951. return inCellNode ? Number(html.attr(inCellNode, "idx")) : -1;
  29952. },
  29953. getCellNode: function(inRowNode, inCellIndex){
  29954. for(var i=0, row; ((row = getTr(inRowNode.firstChild, i)) && row.cells); i++){
  29955. for(var j=0, cell; (cell = row.cells[j]); j++){
  29956. if(this.getCellNodeIndex(cell) == inCellIndex){
  29957. return cell;
  29958. }
  29959. }
  29960. }
  29961. return null;
  29962. },
  29963. findCellTarget: function(inSourceNode, inTopNode){
  29964. var n = inSourceNode;
  29965. while(n && (!this.isCellNode(n) || (n.offsetParent && gridViewTag in n.offsetParent.parentNode && n.offsetParent.parentNode[gridViewTag] != this.view.id)) && (n!=inTopNode)){
  29966. n = n.parentNode;
  29967. }
  29968. return n!=inTopNode ? n : null;
  29969. },
  29970. // event decoration
  29971. baseDecorateEvent: function(e){
  29972. e.dispatch = 'do' + e.type;
  29973. e.grid = this.grid;
  29974. e.sourceView = this.view;
  29975. e.cellNode = this.findCellTarget(e.target, e.rowNode);
  29976. e.cellIndex = this.getCellNodeIndex(e.cellNode);
  29977. e.cell = (e.cellIndex >= 0 ? this.grid.getCell(e.cellIndex) : null);
  29978. },
  29979. // event dispatch
  29980. findTarget: function(inSource, inTag){
  29981. var n = inSource;
  29982. while(n && (n!=this.domNode) && (!(inTag in n) || (gridViewTag in n && n[gridViewTag] != this.view.id))){
  29983. n = n.parentNode;
  29984. }
  29985. return (n != this.domNode) ? n : null;
  29986. },
  29987. findRowTarget: function(inSource){
  29988. return this.findTarget(inSource, rowIndexTag);
  29989. },
  29990. isIntraNodeEvent: function(e){
  29991. try{
  29992. return (e.cellNode && e.relatedTarget && html.isDescendant(e.relatedTarget, e.cellNode));
  29993. }catch(x){
  29994. // e.relatedTarget has permission problem in FF if it's an input: https://bugzilla.mozilla.org/show_bug.cgi?id=208427
  29995. return false;
  29996. }
  29997. },
  29998. isIntraRowEvent: function(e){
  29999. try{
  30000. var row = e.relatedTarget && this.findRowTarget(e.relatedTarget);
  30001. return !row && (e.rowIndex==-1) || row && (e.rowIndex==row.gridRowIndex);
  30002. }catch(x){
  30003. // e.relatedTarget on INPUT has permission problem in FF: https://bugzilla.mozilla.org/show_bug.cgi?id=208427
  30004. return false;
  30005. }
  30006. },
  30007. dispatchEvent: function(e){
  30008. if(e.dispatch in this){
  30009. return this[e.dispatch](e);
  30010. }
  30011. return false;
  30012. },
  30013. // dispatched event handlers
  30014. domouseover: function(e){
  30015. if(e.cellNode && (e.cellNode!=this.lastOverCellNode)){
  30016. this.lastOverCellNode = e.cellNode;
  30017. this.grid.onMouseOver(e);
  30018. }
  30019. this.grid.onMouseOverRow(e);
  30020. },
  30021. domouseout: function(e){
  30022. if(e.cellNode && (e.cellNode==this.lastOverCellNode) && !this.isIntraNodeEvent(e, this.lastOverCellNode)){
  30023. this.lastOverCellNode = null;
  30024. this.grid.onMouseOut(e);
  30025. if(!this.isIntraRowEvent(e)){
  30026. this.grid.onMouseOutRow(e);
  30027. }
  30028. }
  30029. },
  30030. domousedown: function(e){
  30031. if (e.cellNode)
  30032. this.grid.onMouseDown(e);
  30033. this.grid.onMouseDownRow(e);
  30034. }
  30035. });
  30036. // Produces html for grid data content. Owned by grid and used internally
  30037. // for rendering data. Override to implement custom rendering.
  30038. var _ContentBuilder = dg._ContentBuilder = lang.extend(function(view){
  30039. _Builder.call(this, view);
  30040. },_Builder.prototype,{
  30041. update: function(){
  30042. this.prepareHtml();
  30043. },
  30044. // cache html for rendering data rows
  30045. prepareHtml: function(){
  30046. var defaultGet=this.grid.get, cells=this.view.structure.cells;
  30047. for(var j=0, row; (row=cells[j]); j++){
  30048. for(var i=0, cell; (cell=row[i]); i++){
  30049. cell.get = cell.get || (cell.value == undefined) && defaultGet;
  30050. cell.markup = this.generateCellMarkup(cell, cell.cellStyles, cell.cellClasses, false);
  30051. if (!this.grid.editable && cell.editable){
  30052. this.grid.editable = true;
  30053. }
  30054. }
  30055. }
  30056. },
  30057. // time critical: generate html using cache and data source
  30058. generateHtml: function(inDataIndex, inRowIndex){
  30059. var
  30060. html = this.getTableArray(),
  30061. v = this.view,
  30062. cells = v.structure.cells,
  30063. item = this.grid.getItem(inRowIndex);
  30064. util.fire(this.view, "onBeforeRow", [inRowIndex, cells]);
  30065. for(var j=0, row; (row=cells[j]); j++){
  30066. if(row.hidden || row.header){
  30067. continue;
  30068. }
  30069. html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGridInvisible">');
  30070. for(var i=0, cell, m, cc, cs; (cell=row[i]); i++){
  30071. m = cell.markup; cc = cell.customClasses = []; cs = cell.customStyles = [];
  30072. // content (format can fill in cc and cs as side-effects)
  30073. m[5] = cell.format(inRowIndex, item);
  30074. if(has("ie") < 8 && (m[5] === null || m[5] === '' || /^\s+$/.test(m[5]))){
  30075. //fix IE 6/7 quirks - border style not effective for empty td
  30076. m[5] = '&nbsp;'
  30077. }
  30078. // classes
  30079. m[1] = cc.join(' ');
  30080. // styles
  30081. m[3] = cs.join(';');
  30082. // in-place concat
  30083. html.push.apply(html, m);
  30084. }
  30085. html.push('</tr>');
  30086. }
  30087. html.push('</table>');
  30088. return html.join(''); // String
  30089. },
  30090. decorateEvent: function(e){
  30091. e.rowNode = this.findRowTarget(e.target);
  30092. if(!e.rowNode){return false;}
  30093. e.rowIndex = e.rowNode[rowIndexTag];
  30094. this.baseDecorateEvent(e);
  30095. e.cell = this.grid.getCell(e.cellIndex);
  30096. return true; // Boolean
  30097. }
  30098. });
  30099. // Produces html for grid header content. Owned by grid and used internally
  30100. // for rendering data. Override to implement custom rendering.
  30101. var _HeaderBuilder = dg._HeaderBuilder = lang.extend(function(view){
  30102. this.moveable = null;
  30103. _Builder.call(this, view);
  30104. },_Builder.prototype,{
  30105. _skipBogusClicks: false,
  30106. overResizeWidth: 4,
  30107. minColWidth: 1,
  30108. update: function(){
  30109. if(this.tableMap){
  30110. this.tableMap.mapRows(this.view.structure.cells);
  30111. }else{
  30112. this.tableMap = new dg._TableMap(this.view.structure.cells);
  30113. }
  30114. },
  30115. generateHtml: function(inGetValue, inValue){
  30116. var html = this.getTableArray(), cells = this.view.structure.cells;
  30117. util.fire(this.view, "onBeforeRow", [-1, cells]);
  30118. for(var j=0, row; (row=cells[j]); j++){
  30119. if(row.hidden){
  30120. continue;
  30121. }
  30122. html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGridInvisible">');
  30123. for(var i=0, cell, markup; (cell=row[i]); i++){
  30124. cell.customClasses = [];
  30125. cell.customStyles = [];
  30126. if(this.view.simpleStructure){
  30127. if(cell.draggable){
  30128. if(cell.headerClasses){
  30129. if(cell.headerClasses.indexOf('dojoDndItem') == -1){
  30130. cell.headerClasses += ' dojoDndItem';
  30131. }
  30132. }else{
  30133. cell.headerClasses = 'dojoDndItem';
  30134. }
  30135. }
  30136. if(cell.attrs){
  30137. if(cell.attrs.indexOf("dndType='gridColumn_") == -1){
  30138. cell.attrs += " dndType='gridColumn_" + this.grid.id + "'";
  30139. }
  30140. }else{
  30141. cell.attrs = "dndType='gridColumn_" + this.grid.id + "'";
  30142. }
  30143. }
  30144. markup = this.generateCellMarkup(cell, cell.headerStyles, cell.headerClasses, true);
  30145. // content
  30146. markup[5] = (inValue != undefined ? inValue : inGetValue(cell));
  30147. // styles
  30148. markup[3] = cell.customStyles.join(';');
  30149. // classes
  30150. markup[1] = cell.customClasses.join(' '); //(cell.customClasses ? ' ' + cell.customClasses : '');
  30151. html.push(markup.join(''));
  30152. }
  30153. html.push('</tr>');
  30154. }
  30155. html.push('</table>');
  30156. return html.join('');
  30157. },
  30158. // event helpers
  30159. getCellX: function(e){
  30160. var n, x = e.layerX;
  30161. if(has("mozilla") || has("ie") >= 9){
  30162. n = ascendDom(e.target, makeNotTagName("th"));
  30163. x -= (n && n.offsetLeft) || 0;
  30164. var t = e.sourceView.getScrollbarWidth();
  30165. if(!this.grid.isLeftToRight()/*&& e.sourceView.headerNode.scrollLeft < t*/){
  30166. //fix #11253
  30167. table = ascendDom(n,makeNotTagName("table"));
  30168. x -= (table && table.offsetLeft) || 0;
  30169. }
  30170. //x -= getProp(ascendDom(e.target, mkNotTagName("td")), "offsetLeft") || 0;
  30171. }
  30172. n = ascendDom(e.target, function(){
  30173. if(!n || n == e.cellNode){
  30174. return false;
  30175. }
  30176. // Mozilla 1.8 (FF 1.5) has a bug that makes offsetLeft = -parent border width
  30177. // when parent has border, overflow: hidden, and is positioned
  30178. // handle this problem here ... not a general solution!
  30179. x += (n.offsetLeft < 0 ? 0 : n.offsetLeft);
  30180. return true;
  30181. });
  30182. return x;
  30183. },
  30184. // event decoration
  30185. decorateEvent: function(e){
  30186. this.baseDecorateEvent(e);
  30187. e.rowIndex = -1;
  30188. e.cellX = this.getCellX(e);
  30189. return true;
  30190. },
  30191. // event handlers
  30192. // resizing
  30193. prepareResize: function(e, mod){
  30194. do{
  30195. var i = e.cellIndex;
  30196. e.cellNode = (i ? e.cellNode.parentNode.cells[i+mod] : null);
  30197. e.cellIndex = (e.cellNode ? this.getCellNodeIndex(e.cellNode) : -1);
  30198. }while(e.cellNode && e.cellNode.style.display == "none");
  30199. return Boolean(e.cellNode);
  30200. },
  30201. canResize: function(e){
  30202. if(!e.cellNode || e.cellNode.colSpan > 1){
  30203. return false;
  30204. }
  30205. var cell = this.grid.getCell(e.cellIndex);
  30206. return !cell.noresize && cell.canResize();
  30207. },
  30208. overLeftResizeArea: function(e){
  30209. // We are never over a resize area if we are in the process of moving
  30210. if(html.hasClass(win.body(), "dojoDndMove")){
  30211. return false;
  30212. }
  30213. //Bugfix for crazy IE problem (#8807). IE returns position information for the icon and text arrow divs
  30214. //as if they were still on the left instead of returning the position they were 'float: right' to.
  30215. //So, the resize check ends up checking the wrong adjacent cell. This checks to see if the hover was over
  30216. //the image or text nodes, then just ignored them/treat them not in scale range.
  30217. if(has("ie")){
  30218. var tN = e.target;
  30219. if(html.hasClass(tN, "dojoxGridArrowButtonNode") ||
  30220. html.hasClass(tN, "dojoxGridArrowButtonChar") ||
  30221. html.hasClass(tN, "dojoxGridColCaption")){
  30222. return false;
  30223. }
  30224. }
  30225. if(this.grid.isLeftToRight()){
  30226. return (e.cellIndex>0) && (e.cellX > 0 && e.cellX < this.overResizeWidth) && this.prepareResize(e, -1);
  30227. }
  30228. var t = e.cellNode && (e.cellX > 0 && e.cellX < this.overResizeWidth);
  30229. return t;
  30230. },
  30231. overRightResizeArea: function(e){
  30232. // We are never over a resize area if we are in the process of moving
  30233. if(html.hasClass(win.body(), "dojoDndMove")){
  30234. return false;
  30235. }
  30236. //Bugfix for crazy IE problem (#8807). IE returns position information for the icon and text arrow divs
  30237. //as if they were still on the left instead of returning the position they were 'float: right' to.
  30238. //So, the resize check ends up checking the wrong adjacent cell. This checks to see if the hover was over
  30239. //the image or text nodes, then just ignored them/treat them not in scale range.
  30240. if(has("ie")){
  30241. var tN = e.target;
  30242. if(html.hasClass(tN, "dojoxGridArrowButtonNode") ||
  30243. html.hasClass(tN, "dojoxGridArrowButtonChar") ||
  30244. html.hasClass(tN, "dojoxGridColCaption")){
  30245. return false;
  30246. }
  30247. }
  30248. if(this.grid.isLeftToRight()){
  30249. return e.cellNode && (e.cellX >= e.cellNode.offsetWidth - this.overResizeWidth);
  30250. }
  30251. return (e.cellIndex>0) && (e.cellX >= e.cellNode.offsetWidth - this.overResizeWidth) && this.prepareResize(e, -1);
  30252. },
  30253. domousemove: function(e){
  30254. //console.log(e.cellIndex, e.cellX, e.cellNode.offsetWidth);
  30255. if(!this.moveable){
  30256. var c = (this.overRightResizeArea(e) ? 'dojoxGridColResize' : (this.overLeftResizeArea(e) ? 'dojoxGridColResize' : ''));
  30257. if(c && !this.canResize(e)){
  30258. c = 'dojoxGridColNoResize';
  30259. }
  30260. html.toggleClass(e.sourceView.headerNode, "dojoxGridColNoResize", (c == "dojoxGridColNoResize"));
  30261. html.toggleClass(e.sourceView.headerNode, "dojoxGridColResize", (c == "dojoxGridColResize"));
  30262. if(c){
  30263. event.stop(e);
  30264. }
  30265. }
  30266. },
  30267. domousedown: function(e){
  30268. if(!this.moveable){
  30269. if((this.overRightResizeArea(e) || this.overLeftResizeArea(e)) && this.canResize(e)){
  30270. this.beginColumnResize(e);
  30271. }else{
  30272. this.grid.onMouseDown(e);
  30273. this.grid.onMouseOverRow(e);
  30274. }
  30275. //else{
  30276. // this.beginMoveColumn(e);
  30277. //}
  30278. }
  30279. },
  30280. doclick: function(e) {
  30281. if(this._skipBogusClicks){
  30282. event.stop(e);
  30283. return true;
  30284. }
  30285. return false;
  30286. },
  30287. // column resizing
  30288. colResizeSetup: function(/*Event Object*/e, /*boolean*/ isMouse ){
  30289. //Set up the drag object for column resizing
  30290. // Called with mouse event in case of drag and drop,
  30291. // Also called from keyboard shift-arrow event when focus is on a header
  30292. var headContentBox = html.contentBox(e.sourceView.headerNode);
  30293. if(isMouse){ //IE draws line even with no mouse down so separate from keyboard
  30294. this.lineDiv = document.createElement('div');
  30295. var vw = html.position(e.sourceView.headerNode, true);
  30296. var bodyContentBox = html.contentBox(e.sourceView.domNode);
  30297. //fix #11340
  30298. var l = e.pageX;
  30299. if(!this.grid.isLeftToRight() && has("ie") < 8){
  30300. l -= metrics.getScrollbar().w;
  30301. }
  30302. html.style(this.lineDiv, {
  30303. top: vw.y + "px",
  30304. left: l + "px",
  30305. height: (bodyContentBox.h + headContentBox.h) + "px"
  30306. });
  30307. html.addClass(this.lineDiv, "dojoxGridResizeColLine");
  30308. this.lineDiv._origLeft = l;
  30309. win.body().appendChild(this.lineDiv);
  30310. }
  30311. var spanners = [], nodes = this.tableMap.findOverlappingNodes(e.cellNode);
  30312. for(var i=0, cell; (cell=nodes[i]); i++){
  30313. spanners.push({ node: cell, index: this.getCellNodeIndex(cell), width: cell.offsetWidth });
  30314. //console.log("spanner: " + this.getCellNodeIndex(cell));
  30315. }
  30316. var view = e.sourceView;
  30317. var adj = this.grid.isLeftToRight() ? 1 : -1;
  30318. var views = e.grid.views.views;
  30319. var followers = [];
  30320. for(var j=view.idx+adj, cView; (cView=views[j]); j=j+adj){
  30321. followers.push({ node: cView.headerNode, left: window.parseInt(cView.headerNode.style.left) });
  30322. }
  30323. var table = view.headerContentNode.firstChild;
  30324. var drag = {
  30325. scrollLeft: e.sourceView.headerNode.scrollLeft,
  30326. view: view,
  30327. node: e.cellNode,
  30328. index: e.cellIndex,
  30329. w: html.contentBox(e.cellNode).w,
  30330. vw: headContentBox.w,
  30331. table: table,
  30332. tw: html.contentBox(table).w,
  30333. spanners: spanners,
  30334. followers: followers
  30335. };
  30336. return drag;
  30337. },
  30338. beginColumnResize: function(e){
  30339. this.moverDiv = document.createElement("div");
  30340. html.style(this.moverDiv,{position: "absolute", left:0}); // to make DnD work with dir=rtl
  30341. win.body().appendChild(this.moverDiv);
  30342. html.addClass(this.grid.domNode, "dojoxGridColumnResizing");
  30343. var m = (this.moveable = new Moveable(this.moverDiv));
  30344. var drag = this.colResizeSetup(e,true);
  30345. m.onMove = lang.hitch(this, "doResizeColumn", drag);
  30346. connect.connect(m, "onMoveStop", lang.hitch(this, function(){
  30347. this.endResizeColumn(drag);
  30348. if(drag.node.releaseCapture){
  30349. drag.node.releaseCapture();
  30350. }
  30351. this.moveable.destroy();
  30352. delete this.moveable;
  30353. this.moveable = null;
  30354. html.removeClass(this.grid.domNode, "dojoxGridColumnResizing");
  30355. }));
  30356. if(e.cellNode.setCapture){
  30357. e.cellNode.setCapture();
  30358. }
  30359. m.onMouseDown(e);
  30360. },
  30361. doResizeColumn: function(inDrag, mover, leftTop){
  30362. var changeX = leftTop.l;
  30363. var data = {
  30364. deltaX: changeX,
  30365. w: inDrag.w + (this.grid.isLeftToRight() ? changeX : -changeX),//fix #11341
  30366. vw: inDrag.vw + changeX,
  30367. tw: inDrag.tw + changeX
  30368. };
  30369. this.dragRecord = {inDrag: inDrag, mover: mover, leftTop:leftTop};
  30370. if(data.w >= this.minColWidth){
  30371. if (!mover) { // we are using keyboard do immediate resize
  30372. this.doResizeNow(inDrag, data);
  30373. }
  30374. else{
  30375. html.style(this.lineDiv, "left", (this.lineDiv._origLeft + data.deltaX) + "px");
  30376. }
  30377. }
  30378. },
  30379. endResizeColumn: function(inDrag){
  30380. if(this.dragRecord){
  30381. var leftTop = this.dragRecord.leftTop;
  30382. var changeX = this.grid.isLeftToRight() ? leftTop.l : -leftTop.l;
  30383. // Make sure we are not under our minimum
  30384. // http://bugs.dojotoolkit.org/ticket/9390
  30385. changeX += Math.max(inDrag.w + changeX, this.minColWidth) - (inDrag.w + changeX);
  30386. if(has("webkit") && inDrag.spanners.length){
  30387. // Webkit needs the pad border extents back in
  30388. changeX += html._getPadBorderExtents(inDrag.spanners[0].node).w;
  30389. }
  30390. var data = {
  30391. deltaX: changeX,
  30392. w: inDrag.w + changeX,
  30393. vw: inDrag.vw + changeX,
  30394. tw: inDrag.tw + changeX
  30395. };
  30396. // Only resize the columns when the drag has finished
  30397. this.doResizeNow(inDrag, data);
  30398. delete this.dragRecord;
  30399. }
  30400. html.destroy(this.lineDiv);
  30401. html.destroy(this.moverDiv);
  30402. html.destroy(this.moverDiv);
  30403. delete this.moverDiv;
  30404. this._skipBogusClicks = true;
  30405. inDrag.view.update();
  30406. this._skipBogusClicks = false;
  30407. this.grid.onResizeColumn(inDrag.index);
  30408. },
  30409. doResizeNow: function(inDrag, data){
  30410. inDrag.view.convertColPctToFixed();
  30411. if(inDrag.view.flexCells && !inDrag.view.testFlexCells()){
  30412. var t = findTable(inDrag.node);
  30413. if(t){
  30414. (t.style.width = '');
  30415. }
  30416. }
  30417. var i, s, sw, f, fl;
  30418. for(i=0; (s=inDrag.spanners[i]); i++){
  30419. sw = s.width + data.deltaX;
  30420. if(sw > 0){
  30421. s.node.style.width = sw + 'px';
  30422. inDrag.view.setColWidth(s.index, sw);
  30423. }
  30424. }
  30425. if(this.grid.isLeftToRight() || !has("ie")){//fix #11339
  30426. for(i=0; (f=inDrag.followers[i]); i++){
  30427. fl = f.left + data.deltaX;
  30428. f.node.style.left = fl + 'px';
  30429. }
  30430. }
  30431. inDrag.node.style.width = data.w + 'px';
  30432. inDrag.view.setColWidth(inDrag.index, data.w);
  30433. inDrag.view.headerNode.style.width = data.vw + 'px';
  30434. inDrag.view.setColumnsWidth(data.tw);
  30435. if(!this.grid.isLeftToRight()){
  30436. inDrag.view.headerNode.scrollLeft = inDrag.scrollLeft + data.deltaX;
  30437. }
  30438. }
  30439. });
  30440. // Maps an html table into a structure parsable for information about cell row and col spanning.
  30441. // Used by HeaderBuilder.
  30442. dg._TableMap = lang.extend(function(rows){
  30443. this.mapRows(rows);
  30444. },{
  30445. map: null,
  30446. mapRows: function(inRows){
  30447. // summary: Map table topography
  30448. //console.log('mapRows');
  30449. // # of rows
  30450. var rowCount = inRows.length;
  30451. if(!rowCount){
  30452. return;
  30453. }
  30454. // map which columns and rows fill which cells
  30455. this.map = [];
  30456. var row;
  30457. for(var k=0; (row=inRows[k]); k++){
  30458. this.map[k] = [];
  30459. }
  30460. for(var j=0; (row=inRows[j]); j++){
  30461. for(var i=0, x=0, cell, colSpan, rowSpan; (cell=row[i]); i++){
  30462. while(this.map[j][x]){x++;}
  30463. this.map[j][x] = { c: i, r: j };
  30464. rowSpan = cell.rowSpan || 1;
  30465. colSpan = cell.colSpan || 1;
  30466. for(var y=0; y<rowSpan; y++){
  30467. for(var s=0; s<colSpan; s++){
  30468. this.map[j+y][x+s] = this.map[j][x];
  30469. }
  30470. }
  30471. x += colSpan;
  30472. }
  30473. }
  30474. //this.dumMap();
  30475. },
  30476. dumpMap: function(){
  30477. for(var j=0, row, h=''; (row=this.map[j]); j++,h=''){
  30478. for(var i=0, cell; (cell=row[i]); i++){
  30479. h += cell.r + ',' + cell.c + ' ';
  30480. }
  30481. }
  30482. },
  30483. getMapCoords: function(inRow, inCol){
  30484. // summary: Find node's map coords by it's structure coords
  30485. for(var j=0, row; (row=this.map[j]); j++){
  30486. for(var i=0, cell; (cell=row[i]); i++){
  30487. if(cell.c==inCol && cell.r == inRow){
  30488. return { j: j, i: i };
  30489. }
  30490. //else{console.log(inRow, inCol, ' : ', i, j, " : ", cell.r, cell.c); };
  30491. }
  30492. }
  30493. return { j: -1, i: -1 };
  30494. },
  30495. getNode: function(inTable, inRow, inCol){
  30496. // summary: Find a node in inNode's table with the given structure coords
  30497. var row = inTable && inTable.rows[inRow];
  30498. return row && row.cells[inCol];
  30499. },
  30500. _findOverlappingNodes: function(inTable, inRow, inCol){
  30501. var nodes = [];
  30502. var m = this.getMapCoords(inRow, inCol);
  30503. //console.log("node j: %d, i: %d", m.j, m.i);
  30504. for(var j=0, row; (row=this.map[j]); j++){
  30505. if(j == m.j){ continue; }
  30506. var rw = row[m.i];
  30507. //console.log("overlaps: r: %d, c: %d", rw.r, rw.c);
  30508. var n = (rw?this.getNode(inTable, rw.r, rw.c):null);
  30509. if(n){ nodes.push(n); }
  30510. }
  30511. //console.log(nodes);
  30512. return nodes;
  30513. },
  30514. findOverlappingNodes: function(inNode){
  30515. return this._findOverlappingNodes(findTable(inNode), getTrIndex(inNode.parentNode), getTdIndex(inNode));
  30516. }
  30517. });
  30518. return {
  30519. _Builder: _Builder,
  30520. _HeaderBuilder: _HeaderBuilder,
  30521. _ContentBuilder: _ContentBuilder
  30522. };
  30523. });
  30524. },
  30525. 'dojox/grid/_EditManager':function(){
  30526. define("dojox/grid/_EditManager", [
  30527. "dojo/_base/lang",
  30528. "dojo/_base/array",
  30529. "dojo/_base/declare",
  30530. "dojo/_base/connect",
  30531. "dojo/_base/sniff",
  30532. "./util"
  30533. ], function(lang, array, declare, connect, has, util){
  30534. return declare("dojox.grid._EditManager", null, {
  30535. // summary:
  30536. // Controls grid cell editing process. Owned by grid and used internally for editing.
  30537. constructor: function(inGrid){
  30538. // inGrid: dojox.Grid
  30539. // The dojox.Grid this editor should be attached to
  30540. this.grid = inGrid;
  30541. if(has("ie")){
  30542. this.connections = [connect.connect(document.body, "onfocus", lang.hitch(this, "_boomerangFocus"))];
  30543. }else{
  30544. this.connections = [connect.connect(this.grid, 'onBlur', this, 'apply')];
  30545. }
  30546. },
  30547. info: {},
  30548. destroy: function(){
  30549. array.forEach(this.connections, connect.disconnect);
  30550. },
  30551. cellFocus: function(inCell, inRowIndex){
  30552. // summary:
  30553. // Invoke editing when cell is focused
  30554. // inCell: cell object
  30555. // Grid cell object
  30556. // inRowIndex: Integer
  30557. // Grid row index
  30558. if(this.grid.singleClickEdit || this.isEditRow(inRowIndex)){
  30559. // if same row or quick editing, edit
  30560. this.setEditCell(inCell, inRowIndex);
  30561. }else{
  30562. // otherwise, apply any pending row edits
  30563. this.apply();
  30564. }
  30565. // if dynamic or static editing...
  30566. if(this.isEditing() || (inCell && inCell.editable && inCell.alwaysEditing)){
  30567. // let the editor focus itself as needed
  30568. this._focusEditor(inCell, inRowIndex);
  30569. }
  30570. },
  30571. rowClick: function(e){
  30572. if(this.isEditing() && !this.isEditRow(e.rowIndex)){
  30573. this.apply();
  30574. }
  30575. },
  30576. styleRow: function(inRow){
  30577. if(inRow.index == this.info.rowIndex){
  30578. inRow.customClasses += ' dojoxGridRowEditing';
  30579. }
  30580. },
  30581. dispatchEvent: function(e){
  30582. var c = e.cell, ed = (c && c["editable"]) ? c : 0;
  30583. return ed && ed.dispatchEvent(e.dispatch, e);
  30584. },
  30585. // Editing
  30586. isEditing: function(){
  30587. // summary:
  30588. // Indicates editing state of the grid.
  30589. // returns: Boolean
  30590. // True if grid is actively editing
  30591. return this.info.rowIndex !== undefined;
  30592. },
  30593. isEditCell: function(inRowIndex, inCellIndex){
  30594. // summary:
  30595. // Indicates if the given cell is being edited.
  30596. // inRowIndex: Integer
  30597. // Grid row index
  30598. // inCellIndex: Integer
  30599. // Grid cell index
  30600. // returns: Boolean
  30601. // True if given cell is being edited
  30602. return (this.info.rowIndex === inRowIndex) && (this.info.cell.index == inCellIndex);
  30603. },
  30604. isEditRow: function(inRowIndex){
  30605. // summary:
  30606. // Indicates if the given row is being edited.
  30607. // inRowIndex: Integer
  30608. // Grid row index
  30609. // returns: Boolean
  30610. // True if given row is being edited
  30611. return this.info.rowIndex === inRowIndex;
  30612. },
  30613. setEditCell: function(inCell, inRowIndex){
  30614. // summary:
  30615. // Set the given cell to be edited
  30616. // inRowIndex: Integer
  30617. // Grid row index
  30618. // inCell: Object
  30619. // Grid cell object
  30620. if(!this.isEditCell(inRowIndex, inCell.index) && this.grid.canEdit && this.grid.canEdit(inCell, inRowIndex)){
  30621. this.start(inCell, inRowIndex, this.isEditRow(inRowIndex) || inCell.editable);
  30622. }
  30623. },
  30624. _focusEditor: function(inCell, inRowIndex){
  30625. util.fire(inCell, "focus", [inRowIndex]);
  30626. },
  30627. focusEditor: function(){
  30628. if(this.isEditing()){
  30629. this._focusEditor(this.info.cell, this.info.rowIndex);
  30630. }
  30631. },
  30632. // implement fix for focus boomerang effect on IE
  30633. _boomerangWindow: 500,
  30634. _shouldCatchBoomerang: function(){
  30635. return this._catchBoomerang > new Date().getTime();
  30636. },
  30637. _boomerangFocus: function(){
  30638. //console.log("_boomerangFocus");
  30639. if(this._shouldCatchBoomerang()){
  30640. // make sure we don't utterly lose focus
  30641. this.grid.focus.focusGrid();
  30642. // let the editor focus itself as needed
  30643. this.focusEditor();
  30644. // only catch once
  30645. this._catchBoomerang = 0;
  30646. }
  30647. },
  30648. _doCatchBoomerang: function(){
  30649. // give ourselves a few ms to boomerang IE focus effects
  30650. if(has("ie")){this._catchBoomerang = new Date().getTime() + this._boomerangWindow;}
  30651. },
  30652. // end boomerang fix API
  30653. start: function(inCell, inRowIndex, inEditing){
  30654. if(!this._isValidInput()){
  30655. return;
  30656. }
  30657. this.grid.beginUpdate();
  30658. this.editorApply();
  30659. if(this.isEditing() && !this.isEditRow(inRowIndex)){
  30660. this.applyRowEdit();
  30661. this.grid.updateRow(inRowIndex);
  30662. }
  30663. if(inEditing){
  30664. this.info = { cell: inCell, rowIndex: inRowIndex };
  30665. this.grid.doStartEdit(inCell, inRowIndex);
  30666. this.grid.updateRow(inRowIndex);
  30667. }else{
  30668. this.info = {};
  30669. }
  30670. this.grid.endUpdate();
  30671. // make sure we don't utterly lose focus
  30672. this.grid.focus.focusGrid();
  30673. // let the editor focus itself as needed
  30674. this._focusEditor(inCell, inRowIndex);
  30675. // give ourselves a few ms to boomerang IE focus effects
  30676. this._doCatchBoomerang();
  30677. },
  30678. _editorDo: function(inMethod){
  30679. var c = this.info.cell;
  30680. //c && c.editor && c.editor[inMethod](c, this.info.rowIndex);
  30681. if(c && c.editable){
  30682. c[inMethod](this.info.rowIndex);
  30683. }
  30684. },
  30685. editorApply: function(){
  30686. this._editorDo("apply");
  30687. },
  30688. editorCancel: function(){
  30689. this._editorDo("cancel");
  30690. },
  30691. applyCellEdit: function(inValue, inCell, inRowIndex){
  30692. if(this.grid.canEdit(inCell, inRowIndex)){
  30693. this.grid.doApplyCellEdit(inValue, inRowIndex, inCell.field);
  30694. }
  30695. },
  30696. applyRowEdit: function(){
  30697. this.grid.doApplyEdit(this.info.rowIndex, this.info.cell.field);
  30698. },
  30699. apply: function(){
  30700. // summary:
  30701. // Apply a grid edit
  30702. if(this.isEditing() && this._isValidInput()){
  30703. this.grid.beginUpdate();
  30704. this.editorApply();
  30705. this.applyRowEdit();
  30706. this.info = {};
  30707. this.grid.endUpdate();
  30708. this.grid.focus.focusGrid();
  30709. this._doCatchBoomerang();
  30710. }
  30711. },
  30712. cancel: function(){
  30713. // summary:
  30714. // Cancel a grid edit
  30715. if(this.isEditing()){
  30716. this.grid.beginUpdate();
  30717. this.editorCancel();
  30718. this.info = {};
  30719. this.grid.endUpdate();
  30720. this.grid.focus.focusGrid();
  30721. this._doCatchBoomerang();
  30722. }
  30723. },
  30724. save: function(inRowIndex, inView){
  30725. // summary:
  30726. // Save the grid editing state
  30727. // inRowIndex: Integer
  30728. // Grid row index
  30729. // inView: Object
  30730. // Grid view
  30731. var c = this.info.cell;
  30732. if(this.isEditRow(inRowIndex) && (!inView || c.view==inView) && c.editable){
  30733. c.save(c, this.info.rowIndex);
  30734. }
  30735. },
  30736. restore: function(inView, inRowIndex){
  30737. // summary:
  30738. // Restores the grid editing state
  30739. // inRowIndex: Integer
  30740. // Grid row index
  30741. // inView: Object
  30742. // Grid view
  30743. var c = this.info.cell;
  30744. if(this.isEditRow(inRowIndex) && c.view == inView && c.editable){
  30745. c.restore(this.info.rowIndex);
  30746. }
  30747. },
  30748. _isValidInput: function(){
  30749. var w = (this.info.cell || {}).widget;
  30750. if(!w || !w.isValid){
  30751. //no validation needed
  30752. return true;
  30753. }
  30754. w.focused = true;
  30755. return w.isValid(true);
  30756. }
  30757. });
  30758. });
  30759. },
  30760. 'dojo/data/util/sorter':function(){
  30761. define("dojo/data/util/sorter", ["dojo/_base/lang"], function(lang) {
  30762. // module:
  30763. // dojo/data/util/sorter
  30764. // summary:
  30765. // TODOC
  30766. var sorter = lang.getObject("dojo.data.util.sorter", true);
  30767. sorter.basicComparator = function( /*anything*/ a,
  30768. /*anything*/ b){
  30769. // summary:
  30770. // Basic comparision function that compares if an item is greater or less than another item
  30771. // description:
  30772. // returns 1 if a > b, -1 if a < b, 0 if equal.
  30773. // 'null' values (null, undefined) are treated as larger values so that they're pushed to the end of the list.
  30774. // And compared to each other, null is equivalent to undefined.
  30775. //null is a problematic compare, so if null, we set to undefined.
  30776. //Makes the check logic simple, compact, and consistent
  30777. //And (null == undefined) === true, so the check later against null
  30778. //works for undefined and is less bytes.
  30779. var r = -1;
  30780. if(a === null){
  30781. a = undefined;
  30782. }
  30783. if(b === null){
  30784. b = undefined;
  30785. }
  30786. if(a == b){
  30787. r = 0;
  30788. }else if(a > b || a == null){
  30789. r = 1;
  30790. }
  30791. return r; //int {-1,0,1}
  30792. };
  30793. sorter.createSortFunction = function( /* attributes array */sortSpec, /*dojo.data.core.Read*/ store){
  30794. // summary:
  30795. // Helper function to generate the sorting function based off the list of sort attributes.
  30796. // description:
  30797. // The sort function creation will look for a property on the store called 'comparatorMap'. If it exists
  30798. // it will look in the mapping for comparisons function for the attributes. If one is found, it will
  30799. // use it instead of the basic comparator, which is typically used for strings, ints, booleans, and dates.
  30800. // Returns the sorting function for this particular list of attributes and sorting directions.
  30801. //
  30802. // sortSpec: array
  30803. // A JS object that array that defines out what attribute names to sort on and whether it should be descenting or asending.
  30804. // The objects should be formatted as follows:
  30805. // {
  30806. // attribute: "attributeName-string" || attribute,
  30807. // descending: true|false; // Default is false.
  30808. // }
  30809. // store: object
  30810. // The datastore object to look up item values from.
  30811. //
  30812. var sortFunctions=[];
  30813. function createSortFunction(attr, dir, comp, s){
  30814. //Passing in comp and s (comparator and store), makes this
  30815. //function much faster.
  30816. return function(itemA, itemB){
  30817. var a = s.getValue(itemA, attr);
  30818. var b = s.getValue(itemB, attr);
  30819. return dir * comp(a,b); //int
  30820. };
  30821. }
  30822. var sortAttribute;
  30823. var map = store.comparatorMap;
  30824. var bc = sorter.basicComparator;
  30825. for(var i = 0; i < sortSpec.length; i++){
  30826. sortAttribute = sortSpec[i];
  30827. var attr = sortAttribute.attribute;
  30828. if(attr){
  30829. var dir = (sortAttribute.descending) ? -1 : 1;
  30830. var comp = bc;
  30831. if(map){
  30832. if(typeof attr !== "string" && ("toString" in attr)){
  30833. attr = attr.toString();
  30834. }
  30835. comp = map[attr] || bc;
  30836. }
  30837. sortFunctions.push(createSortFunction(attr,
  30838. dir, comp, store));
  30839. }
  30840. }
  30841. return function(rowA, rowB){
  30842. var i=0;
  30843. while(i < sortFunctions.length){
  30844. var ret = sortFunctions[i++](rowA, rowB);
  30845. if(ret !== 0){
  30846. return ret;//int
  30847. }
  30848. }
  30849. return 0; //int
  30850. }; // Function
  30851. };
  30852. return sorter;
  30853. });
  30854. },
  30855. 'dijit/form/_ButtonMixin':function(){
  30856. define("dijit/form/_ButtonMixin", [
  30857. "dojo/_base/declare", // declare
  30858. "dojo/dom", // dom.setSelectable
  30859. "dojo/_base/event", // event.stop
  30860. "../registry" // registry.byNode
  30861. ], function(declare, dom, event, registry){
  30862. // module:
  30863. // dijit/form/_ButtonMixin
  30864. // summary:
  30865. // A mixin to add a thin standard API wrapper to a normal HTML button
  30866. return declare("dijit.form._ButtonMixin", null, {
  30867. // summary:
  30868. // A mixin to add a thin standard API wrapper to a normal HTML button
  30869. // description:
  30870. // A label should always be specified (through innerHTML) or the label attribute.
  30871. // Attach points:
  30872. // focusNode (required): this node receives focus
  30873. // valueNode (optional): this node's value gets submitted with FORM elements
  30874. // containerNode (optional): this node gets the innerHTML assignment for label
  30875. // example:
  30876. // | <button data-dojo-type="dijit.form.Button" onClick="...">Hello world</button>
  30877. //
  30878. // example:
  30879. // | var button1 = new dijit.form.Button({label: "hello world", onClick: foo});
  30880. // | dojo.body().appendChild(button1.domNode);
  30881. // label: HTML String
  30882. // Content to display in button.
  30883. label: "",
  30884. // type: [const] String
  30885. // Type of button (submit, reset, button, checkbox, radio)
  30886. type: "button",
  30887. _onClick: function(/*Event*/ e){
  30888. // summary:
  30889. // Internal function to handle click actions
  30890. if(this.disabled){
  30891. event.stop(e);
  30892. return false;
  30893. }
  30894. var preventDefault = this.onClick(e) === false; // user click actions
  30895. if(!preventDefault && this.type == "submit" && !(this.valueNode||this.focusNode).form){ // see if a non-form widget needs to be signalled
  30896. for(var node=this.domNode; node.parentNode; node=node.parentNode){
  30897. var widget=registry.byNode(node);
  30898. if(widget && typeof widget._onSubmit == "function"){
  30899. widget._onSubmit(e);
  30900. preventDefault = true;
  30901. break;
  30902. }
  30903. }
  30904. }
  30905. if(preventDefault){
  30906. e.preventDefault();
  30907. }
  30908. return !preventDefault;
  30909. },
  30910. postCreate: function(){
  30911. this.inherited(arguments);
  30912. dom.setSelectable(this.focusNode, false);
  30913. },
  30914. onClick: function(/*Event*/ /*===== e =====*/){
  30915. // summary:
  30916. // Callback for when button is clicked.
  30917. // If type="submit", return true to perform submit, or false to cancel it.
  30918. // type:
  30919. // callback
  30920. return true; // Boolean
  30921. },
  30922. _setLabelAttr: function(/*String*/ content){
  30923. // summary:
  30924. // Hook for set('label', ...) to work.
  30925. // description:
  30926. // Set the label (text) of the button; takes an HTML string.
  30927. this._set("label", content);
  30928. (this.containerNode||this.focusNode).innerHTML = content;
  30929. }
  30930. });
  30931. });
  30932. },
  30933. 'url:dijit/form/templates/Spinner.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\"\r\n\tid=\"widget_${id}\" role=\"presentation\"\r\n\t><div class=\"dijitReset dijitButtonNode dijitSpinnerButtonContainer\"\r\n\t\t><input class=\"dijitReset dijitInputField dijitSpinnerButtonInner\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t/><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitUpArrowButton\"\r\n\t\t\tdata-dojo-attach-point=\"upArrowNode\"\r\n\t\t\t><div class=\"dijitArrowButtonInner\"\r\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9650;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t\t\t\t${_buttonInputDisabled}\r\n\t\t\t/></div\r\n\t\t></div\r\n\t\t><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitDownArrowButton\"\r\n\t\t\tdata-dojo-attach-point=\"downArrowNode\"\r\n\t\t\t><div class=\"dijitArrowButtonInner\"\r\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9660;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t\t\t\t${_buttonInputDisabled}\r\n\t\t\t/></div\r\n\t\t></div\r\n\t></div\r\n\t><div class='dijitReset dijitValidationContainer'\r\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t/></div\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class='dijitReset dijitInputInner' data-dojo-attach-point=\"textbox,focusNode\" type=\"${type}\" data-dojo-attach-event=\"onkeypress:_onKeyPress\"\r\n\t\t\trole=\"spinbutton\" autocomplete=\"off\" ${!nameAttrSetting}\r\n\t/></div\r\n></div>\r\n",
  30934. 'dijit/registry':function(){
  30935. define("dijit/registry", [
  30936. "dojo/_base/array", // array.forEach array.map
  30937. "dojo/_base/sniff", // has("ie")
  30938. "dojo/_base/unload", // unload.addOnWindowUnload
  30939. "dojo/_base/window", // win.body
  30940. "." // dijit._scopeName
  30941. ], function(array, has, unload, win, dijit){
  30942. // module:
  30943. // dijit/registry
  30944. // summary:
  30945. // Registry of existing widget on page, plus some utility methods.
  30946. // Must be accessed through AMD api, ex:
  30947. // require(["dijit/registry"], function(registry){ registry.byId("foo"); })
  30948. var _widgetTypeCtr = {}, hash = {};
  30949. var registry = {
  30950. // summary:
  30951. // A set of widgets indexed by id
  30952. length: 0,
  30953. add: function(/*dijit._Widget*/ widget){
  30954. // summary:
  30955. // Add a widget to the registry. If a duplicate ID is detected, a error is thrown.
  30956. //
  30957. // widget: dijit._Widget
  30958. // Any dijit._Widget subclass.
  30959. if(hash[widget.id]){
  30960. throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered");
  30961. }
  30962. hash[widget.id] = widget;
  30963. this.length++;
  30964. },
  30965. remove: function(/*String*/ id){
  30966. // summary:
  30967. // Remove a widget from the registry. Does not destroy the widget; simply
  30968. // removes the reference.
  30969. if(hash[id]){
  30970. delete hash[id];
  30971. this.length--;
  30972. }
  30973. },
  30974. byId: function(/*String|Widget*/ id){
  30975. // summary:
  30976. // Find a widget by it's id.
  30977. // If passed a widget then just returns the widget.
  30978. return typeof id == "string" ? hash[id] : id; // dijit._Widget
  30979. },
  30980. byNode: function(/*DOMNode*/ node){
  30981. // summary:
  30982. // Returns the widget corresponding to the given DOMNode
  30983. return hash[node.getAttribute("widgetId")]; // dijit._Widget
  30984. },
  30985. toArray: function(){
  30986. // summary:
  30987. // Convert registry into a true Array
  30988. //
  30989. // example:
  30990. // Work with the widget .domNodes in a real Array
  30991. // | array.map(dijit.registry.toArray(), function(w){ return w.domNode; });
  30992. var ar = [];
  30993. for(var id in hash){
  30994. ar.push(hash[id]);
  30995. }
  30996. return ar; // dijit._Widget[]
  30997. },
  30998. getUniqueId: function(/*String*/widgetType){
  30999. // summary:
  31000. // Generates a unique id for a given widgetType
  31001. var id;
  31002. do{
  31003. id = widgetType + "_" +
  31004. (widgetType in _widgetTypeCtr ?
  31005. ++_widgetTypeCtr[widgetType] : _widgetTypeCtr[widgetType] = 0);
  31006. }while(hash[id]);
  31007. return dijit._scopeName == "dijit" ? id : dijit._scopeName + "_" + id; // String
  31008. },
  31009. findWidgets: function(/*DomNode*/ root){
  31010. // summary:
  31011. // Search subtree under root returning widgets found.
  31012. // Doesn't search for nested widgets (ie, widgets inside other widgets).
  31013. var outAry = [];
  31014. function getChildrenHelper(root){
  31015. for(var node = root.firstChild; node; node = node.nextSibling){
  31016. if(node.nodeType == 1){
  31017. var widgetId = node.getAttribute("widgetId");
  31018. if(widgetId){
  31019. var widget = hash[widgetId];
  31020. if(widget){ // may be null on page w/multiple dojo's loaded
  31021. outAry.push(widget);
  31022. }
  31023. }else{
  31024. getChildrenHelper(node);
  31025. }
  31026. }
  31027. }
  31028. }
  31029. getChildrenHelper(root);
  31030. return outAry;
  31031. },
  31032. _destroyAll: function(){
  31033. // summary:
  31034. // Code to destroy all widgets and do other cleanup on page unload
  31035. // Clean up focus manager lingering references to widgets and nodes
  31036. dijit._curFocus = null;
  31037. dijit._prevFocus = null;
  31038. dijit._activeStack = [];
  31039. // Destroy all the widgets, top down
  31040. array.forEach(registry.findWidgets(win.body()), function(widget){
  31041. // Avoid double destroy of widgets like Menu that are attached to <body>
  31042. // even though they are logically children of other widgets.
  31043. if(!widget._destroyed){
  31044. if(widget.destroyRecursive){
  31045. widget.destroyRecursive();
  31046. }else if(widget.destroy){
  31047. widget.destroy();
  31048. }
  31049. }
  31050. });
  31051. },
  31052. getEnclosingWidget: function(/*DOMNode*/ node){
  31053. // summary:
  31054. // Returns the widget whose DOM tree contains the specified DOMNode, or null if
  31055. // the node is not contained within the DOM tree of any widget
  31056. while(node){
  31057. var id = node.getAttribute && node.getAttribute("widgetId");
  31058. if(id){
  31059. return hash[id];
  31060. }
  31061. node = node.parentNode;
  31062. }
  31063. return null;
  31064. },
  31065. // In case someone needs to access hash.
  31066. // Actually, this is accessed from WidgetSet back-compatibility code
  31067. _hash: hash
  31068. };
  31069. /*=====
  31070. dijit.registry = {
  31071. // summary:
  31072. // A list of widgets on a page.
  31073. };
  31074. =====*/
  31075. dijit.registry = registry;
  31076. return registry;
  31077. });
  31078. },
  31079. 'dojo/date/locale':function(){
  31080. define("dojo/date/locale", [
  31081. "../_base/kernel",
  31082. "../_base/lang",
  31083. "../_base/array",
  31084. "../date",
  31085. "../cldr/supplemental",
  31086. "../regexp",
  31087. "../string",
  31088. "../i18n!../cldr/nls/gregorian"
  31089. ], function(dojo, lang, array, date, cldr, regexp, string, gregorian) {
  31090. // module:
  31091. // dojo/date/locale
  31092. // summary:
  31093. // This modules defines dojo.date.locale, localization methods for Date.
  31094. lang.getObject("date.locale", true, dojo);
  31095. // Localization methods for Date. Honor local customs using locale-dependent dojo.cldr data.
  31096. // Load the bundles containing localization information for
  31097. // names and formats
  31098. //NOTE: Everything in this module assumes Gregorian calendars.
  31099. // Other calendars will be implemented in separate modules.
  31100. // Format a pattern without literals
  31101. function formatPattern(dateObject, bundle, options, pattern){
  31102. return pattern.replace(/([a-z])\1*/ig, function(match){
  31103. var s, pad,
  31104. c = match.charAt(0),
  31105. l = match.length,
  31106. widthList = ["abbr", "wide", "narrow"];
  31107. switch(c){
  31108. case 'G':
  31109. s = bundle[(l < 4) ? "eraAbbr" : "eraNames"][dateObject.getFullYear() < 0 ? 0 : 1];
  31110. break;
  31111. case 'y':
  31112. s = dateObject.getFullYear();
  31113. switch(l){
  31114. case 1:
  31115. break;
  31116. case 2:
  31117. if(!options.fullYear){
  31118. s = String(s); s = s.substr(s.length - 2);
  31119. break;
  31120. }
  31121. // fallthrough
  31122. default:
  31123. pad = true;
  31124. }
  31125. break;
  31126. case 'Q':
  31127. case 'q':
  31128. s = Math.ceil((dateObject.getMonth()+1)/3);
  31129. // switch(l){
  31130. // case 1: case 2:
  31131. pad = true;
  31132. // break;
  31133. // case 3: case 4: // unimplemented
  31134. // }
  31135. break;
  31136. case 'M':
  31137. var m = dateObject.getMonth();
  31138. if(l<3){
  31139. s = m+1; pad = true;
  31140. }else{
  31141. var propM = ["months", "format", widthList[l-3]].join("-");
  31142. s = bundle[propM][m];
  31143. }
  31144. break;
  31145. case 'w':
  31146. var firstDay = 0;
  31147. s = dojo.date.locale._getWeekOfYear(dateObject, firstDay); pad = true;
  31148. break;
  31149. case 'd':
  31150. s = dateObject.getDate(); pad = true;
  31151. break;
  31152. case 'D':
  31153. s = dojo.date.locale._getDayOfYear(dateObject); pad = true;
  31154. break;
  31155. case 'E':
  31156. var d = dateObject.getDay();
  31157. if(l<3){
  31158. s = d+1; pad = true;
  31159. }else{
  31160. var propD = ["days", "format", widthList[l-3]].join("-");
  31161. s = bundle[propD][d];
  31162. }
  31163. break;
  31164. case 'a':
  31165. var timePeriod = (dateObject.getHours() < 12) ? 'am' : 'pm';
  31166. s = options[timePeriod] || bundle['dayPeriods-format-wide-' + timePeriod];
  31167. break;
  31168. case 'h':
  31169. case 'H':
  31170. case 'K':
  31171. case 'k':
  31172. var h = dateObject.getHours();
  31173. // strange choices in the date format make it impossible to write this succinctly
  31174. switch (c){
  31175. case 'h': // 1-12
  31176. s = (h % 12) || 12;
  31177. break;
  31178. case 'H': // 0-23
  31179. s = h;
  31180. break;
  31181. case 'K': // 0-11
  31182. s = (h % 12);
  31183. break;
  31184. case 'k': // 1-24
  31185. s = h || 24;
  31186. break;
  31187. }
  31188. pad = true;
  31189. break;
  31190. case 'm':
  31191. s = dateObject.getMinutes(); pad = true;
  31192. break;
  31193. case 's':
  31194. s = dateObject.getSeconds(); pad = true;
  31195. break;
  31196. case 'S':
  31197. s = Math.round(dateObject.getMilliseconds() * Math.pow(10, l-3)); pad = true;
  31198. break;
  31199. case 'v': // FIXME: don't know what this is. seems to be same as z?
  31200. case 'z':
  31201. // We only have one timezone to offer; the one from the browser
  31202. s = dojo.date.locale._getZone(dateObject, true, options);
  31203. if(s){break;}
  31204. l=4;
  31205. // fallthrough... use GMT if tz not available
  31206. case 'Z':
  31207. var offset = dojo.date.locale._getZone(dateObject, false, options);
  31208. var tz = [
  31209. (offset<=0 ? "+" : "-"),
  31210. string.pad(Math.floor(Math.abs(offset)/60), 2),
  31211. string.pad(Math.abs(offset)% 60, 2)
  31212. ];
  31213. if(l==4){
  31214. tz.splice(0, 0, "GMT");
  31215. tz.splice(3, 0, ":");
  31216. }
  31217. s = tz.join("");
  31218. break;
  31219. // case 'Y': case 'u': case 'W': case 'F': case 'g': case 'A': case 'e':
  31220. // console.log(match+" modifier unimplemented");
  31221. default:
  31222. throw new Error("dojo.date.locale.format: invalid pattern char: "+pattern);
  31223. }
  31224. if(pad){ s = string.pad(s, l); }
  31225. return s;
  31226. });
  31227. }
  31228. /*=====
  31229. dojo.date.locale.__FormatOptions = function(){
  31230. // selector: String
  31231. // choice of 'time','date' (default: date and time)
  31232. // formatLength: String
  31233. // choice of long, short, medium or full (plus any custom additions). Defaults to 'short'
  31234. // datePattern:String
  31235. // override pattern with this string
  31236. // timePattern:String
  31237. // override pattern with this string
  31238. // am: String
  31239. // override strings for am in times
  31240. // pm: String
  31241. // override strings for pm in times
  31242. // locale: String
  31243. // override the locale used to determine formatting rules
  31244. // fullYear: Boolean
  31245. // (format only) use 4 digit years whenever 2 digit years are called for
  31246. // strict: Boolean
  31247. // (parse only) strict parsing, off by default
  31248. this.selector = selector;
  31249. this.formatLength = formatLength;
  31250. this.datePattern = datePattern;
  31251. this.timePattern = timePattern;
  31252. this.am = am;
  31253. this.pm = pm;
  31254. this.locale = locale;
  31255. this.fullYear = fullYear;
  31256. this.strict = strict;
  31257. }
  31258. =====*/
  31259. dojo.date.locale._getZone = function(/*Date*/dateObject, /*boolean*/getName, /*dojo.date.locale.__FormatOptions?*/options){
  31260. // summary:
  31261. // Returns the zone (or offset) for the given date and options. This
  31262. // is broken out into a separate function so that it can be overridden
  31263. // by timezone-aware code.
  31264. //
  31265. // dateObject:
  31266. // the date and/or time being formatted.
  31267. //
  31268. // getName:
  31269. // Whether to return the timezone string (if true), or the offset (if false)
  31270. //
  31271. // options:
  31272. // The options being used for formatting
  31273. if(getName){
  31274. return date.getTimezoneName(dateObject);
  31275. }else{
  31276. return dateObject.getTimezoneOffset();
  31277. }
  31278. };
  31279. dojo.date.locale.format = function(/*Date*/dateObject, /*dojo.date.locale.__FormatOptions?*/options){
  31280. // summary:
  31281. // Format a Date object as a String, using locale-specific settings.
  31282. //
  31283. // description:
  31284. // Create a string from a Date object using a known localized pattern.
  31285. // By default, this method formats both date and time from dateObject.
  31286. // Formatting patterns are chosen appropriate to the locale. Different
  31287. // formatting lengths may be chosen, with "full" used by default.
  31288. // Custom patterns may be used or registered with translations using
  31289. // the dojo.date.locale.addCustomFormats method.
  31290. // Formatting patterns are implemented using [the syntax described at
  31291. // unicode.org](http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns)
  31292. //
  31293. // dateObject:
  31294. // the date and/or time to be formatted. If a time only is formatted,
  31295. // the values in the year, month, and day fields are irrelevant. The
  31296. // opposite is true when formatting only dates.
  31297. options = options || {};
  31298. var locale = dojo.i18n.normalizeLocale(options.locale),
  31299. formatLength = options.formatLength || 'short',
  31300. bundle = dojo.date.locale._getGregorianBundle(locale),
  31301. str = [],
  31302. sauce = lang.hitch(this, formatPattern, dateObject, bundle, options);
  31303. if(options.selector == "year"){
  31304. return _processPattern(bundle["dateFormatItem-yyyy"] || "yyyy", sauce);
  31305. }
  31306. var pattern;
  31307. if(options.selector != "date"){
  31308. pattern = options.timePattern || bundle["timeFormat-"+formatLength];
  31309. if(pattern){str.push(_processPattern(pattern, sauce));}
  31310. }
  31311. if(options.selector != "time"){
  31312. pattern = options.datePattern || bundle["dateFormat-"+formatLength];
  31313. if(pattern){str.push(_processPattern(pattern, sauce));}
  31314. }
  31315. return str.length == 1 ? str[0] : bundle["dateTimeFormat-"+formatLength].replace(/\{(\d+)\}/g,
  31316. function(match, key){ return str[key]; }); // String
  31317. };
  31318. dojo.date.locale.regexp = function(/*dojo.date.locale.__FormatOptions?*/options){
  31319. // summary:
  31320. // Builds the regular needed to parse a localized date
  31321. return dojo.date.locale._parseInfo(options).regexp; // String
  31322. };
  31323. dojo.date.locale._parseInfo = function(/*dojo.date.locale.__FormatOptions?*/options){
  31324. options = options || {};
  31325. var locale = dojo.i18n.normalizeLocale(options.locale),
  31326. bundle = dojo.date.locale._getGregorianBundle(locale),
  31327. formatLength = options.formatLength || 'short',
  31328. datePattern = options.datePattern || bundle["dateFormat-" + formatLength],
  31329. timePattern = options.timePattern || bundle["timeFormat-" + formatLength],
  31330. pattern;
  31331. if(options.selector == 'date'){
  31332. pattern = datePattern;
  31333. }else if(options.selector == 'time'){
  31334. pattern = timePattern;
  31335. }else{
  31336. pattern = bundle["dateTimeFormat-"+formatLength].replace(/\{(\d+)\}/g,
  31337. function(match, key){ return [timePattern, datePattern][key]; });
  31338. }
  31339. var tokens = [],
  31340. re = _processPattern(pattern, lang.hitch(this, _buildDateTimeRE, tokens, bundle, options));
  31341. return {regexp: re, tokens: tokens, bundle: bundle};
  31342. };
  31343. dojo.date.locale.parse = function(/*String*/value, /*dojo.date.locale.__FormatOptions?*/options){
  31344. // summary:
  31345. // Convert a properly formatted string to a primitive Date object,
  31346. // using locale-specific settings.
  31347. //
  31348. // description:
  31349. // Create a Date object from a string using a known localized pattern.
  31350. // By default, this method parses looking for both date and time in the string.
  31351. // Formatting patterns are chosen appropriate to the locale. Different
  31352. // formatting lengths may be chosen, with "full" used by default.
  31353. // Custom patterns may be used or registered with translations using
  31354. // the dojo.date.locale.addCustomFormats method.
  31355. //
  31356. // Formatting patterns are implemented using [the syntax described at
  31357. // unicode.org](http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns)
  31358. // When two digit years are used, a century is chosen according to a sliding
  31359. // window of 80 years before and 20 years after present year, for both `yy` and `yyyy` patterns.
  31360. // year < 100CE requires strict mode.
  31361. //
  31362. // value:
  31363. // A string representation of a date
  31364. // remove non-printing bidi control chars from input and pattern
  31365. var controlChars = /[\u200E\u200F\u202A\u202E]/g,
  31366. info = dojo.date.locale._parseInfo(options),
  31367. tokens = info.tokens, bundle = info.bundle,
  31368. re = new RegExp("^" + info.regexp.replace(controlChars, "") + "$",
  31369. info.strict ? "" : "i"),
  31370. match = re.exec(value && value.replace(controlChars, ""));
  31371. if(!match){ return null; } // null
  31372. var widthList = ['abbr', 'wide', 'narrow'],
  31373. result = [1970,0,1,0,0,0,0], // will get converted to a Date at the end
  31374. amPm = "",
  31375. valid = dojo.every(match, function(v, i){
  31376. if(!i){return true;}
  31377. var token=tokens[i-1];
  31378. var l=token.length;
  31379. switch(token.charAt(0)){
  31380. case 'y':
  31381. if(l != 2 && options.strict){
  31382. //interpret year literally, so '5' would be 5 A.D.
  31383. result[0] = v;
  31384. }else{
  31385. if(v<100){
  31386. v = Number(v);
  31387. //choose century to apply, according to a sliding window
  31388. //of 80 years before and 20 years after present year
  31389. var year = '' + new Date().getFullYear(),
  31390. century = year.substring(0, 2) * 100,
  31391. cutoff = Math.min(Number(year.substring(2, 4)) + 20, 99);
  31392. result[0] = (v < cutoff) ? century + v : century - 100 + v;
  31393. }else{
  31394. //we expected 2 digits and got more...
  31395. if(options.strict){
  31396. return false;
  31397. }
  31398. //interpret literally, so '150' would be 150 A.D.
  31399. //also tolerate '1950', if 'yyyy' input passed to 'yy' format
  31400. result[0] = v;
  31401. }
  31402. }
  31403. break;
  31404. case 'M':
  31405. if(l>2){
  31406. var months = bundle['months-format-' + widthList[l-3]].concat();
  31407. if(!options.strict){
  31408. //Tolerate abbreviating period in month part
  31409. //Case-insensitive comparison
  31410. v = v.replace(".","").toLowerCase();
  31411. months = dojo.map(months, function(s){ return s.replace(".","").toLowerCase(); } );
  31412. }
  31413. v = dojo.indexOf(months, v);
  31414. if(v == -1){
  31415. // console.log("dojo.date.locale.parse: Could not parse month name: '" + v + "'.");
  31416. return false;
  31417. }
  31418. }else{
  31419. v--;
  31420. }
  31421. result[1] = v;
  31422. break;
  31423. case 'E':
  31424. case 'e':
  31425. var days = bundle['days-format-' + widthList[l-3]].concat();
  31426. if(!options.strict){
  31427. //Case-insensitive comparison
  31428. v = v.toLowerCase();
  31429. days = dojo.map(days, function(d){return d.toLowerCase();});
  31430. }
  31431. v = dojo.indexOf(days, v);
  31432. if(v == -1){
  31433. // console.log("dojo.date.locale.parse: Could not parse weekday name: '" + v + "'.");
  31434. return false;
  31435. }
  31436. //TODO: not sure what to actually do with this input,
  31437. //in terms of setting something on the Date obj...?
  31438. //without more context, can't affect the actual date
  31439. //TODO: just validate?
  31440. break;
  31441. case 'D':
  31442. result[1] = 0;
  31443. // fallthrough...
  31444. case 'd':
  31445. result[2] = v;
  31446. break;
  31447. case 'a': //am/pm
  31448. var am = options.am || bundle['dayPeriods-format-wide-am'],
  31449. pm = options.pm || bundle['dayPeriods-format-wide-pm'];
  31450. if(!options.strict){
  31451. var period = /\./g;
  31452. v = v.replace(period,'').toLowerCase();
  31453. am = am.replace(period,'').toLowerCase();
  31454. pm = pm.replace(period,'').toLowerCase();
  31455. }
  31456. if(options.strict && v != am && v != pm){
  31457. // console.log("dojo.date.locale.parse: Could not parse am/pm part.");
  31458. return false;
  31459. }
  31460. // we might not have seen the hours field yet, so store the state and apply hour change later
  31461. amPm = (v == pm) ? 'p' : (v == am) ? 'a' : '';
  31462. break;
  31463. case 'K': //hour (1-24)
  31464. if(v == 24){ v = 0; }
  31465. // fallthrough...
  31466. case 'h': //hour (1-12)
  31467. case 'H': //hour (0-23)
  31468. case 'k': //hour (0-11)
  31469. //TODO: strict bounds checking, padding
  31470. if(v > 23){
  31471. // console.log("dojo.date.locale.parse: Illegal hours value");
  31472. return false;
  31473. }
  31474. //in the 12-hour case, adjusting for am/pm requires the 'a' part
  31475. //which could come before or after the hour, so we will adjust later
  31476. result[3] = v;
  31477. break;
  31478. case 'm': //minutes
  31479. result[4] = v;
  31480. break;
  31481. case 's': //seconds
  31482. result[5] = v;
  31483. break;
  31484. case 'S': //milliseconds
  31485. result[6] = v;
  31486. // break;
  31487. // case 'w':
  31488. //TODO var firstDay = 0;
  31489. // default:
  31490. //TODO: throw?
  31491. // console.log("dojo.date.locale.parse: unsupported pattern char=" + token.charAt(0));
  31492. }
  31493. return true;
  31494. });
  31495. var hours = +result[3];
  31496. if(amPm === 'p' && hours < 12){
  31497. result[3] = hours + 12; //e.g., 3pm -> 15
  31498. }else if(amPm === 'a' && hours == 12){
  31499. result[3] = 0; //12am -> 0
  31500. }
  31501. //TODO: implement a getWeekday() method in order to test
  31502. //validity of input strings containing 'EEE' or 'EEEE'...
  31503. var dateObject = new Date(result[0], result[1], result[2], result[3], result[4], result[5], result[6]); // Date
  31504. if(options.strict){
  31505. dateObject.setFullYear(result[0]);
  31506. }
  31507. // Check for overflow. The Date() constructor normalizes things like April 32nd...
  31508. //TODO: why isn't this done for times as well?
  31509. var allTokens = tokens.join(""),
  31510. dateToken = allTokens.indexOf('d') != -1,
  31511. monthToken = allTokens.indexOf('M') != -1;
  31512. if(!valid ||
  31513. (monthToken && dateObject.getMonth() > result[1]) ||
  31514. (dateToken && dateObject.getDate() > result[2])){
  31515. return null;
  31516. }
  31517. // Check for underflow, due to DST shifts. See #9366
  31518. // This assumes a 1 hour dst shift correction at midnight
  31519. // We could compare the timezone offset after the shift and add the difference instead.
  31520. if((monthToken && dateObject.getMonth() < result[1]) ||
  31521. (dateToken && dateObject.getDate() < result[2])){
  31522. dateObject = date.add(dateObject, "hour", 1);
  31523. }
  31524. return dateObject; // Date
  31525. };
  31526. function _processPattern(pattern, applyPattern, applyLiteral, applyAll){
  31527. //summary: Process a pattern with literals in it
  31528. // Break up on single quotes, treat every other one as a literal, except '' which becomes '
  31529. var identity = function(x){return x;};
  31530. applyPattern = applyPattern || identity;
  31531. applyLiteral = applyLiteral || identity;
  31532. applyAll = applyAll || identity;
  31533. //split on single quotes (which escape literals in date format strings)
  31534. //but preserve escaped single quotes (e.g., o''clock)
  31535. var chunks = pattern.match(/(''|[^'])+/g),
  31536. literal = pattern.charAt(0) == "'";
  31537. dojo.forEach(chunks, function(chunk, i){
  31538. if(!chunk){
  31539. chunks[i]='';
  31540. }else{
  31541. chunks[i]=(literal ? applyLiteral : applyPattern)(chunk.replace(/''/g, "'"));
  31542. literal = !literal;
  31543. }
  31544. });
  31545. return applyAll(chunks.join(''));
  31546. }
  31547. function _buildDateTimeRE(tokens, bundle, options, pattern){
  31548. pattern = regexp.escapeString(pattern);
  31549. if(!options.strict){ pattern = pattern.replace(" a", " ?a"); } // kludge to tolerate no space before am/pm
  31550. return pattern.replace(/([a-z])\1*/ig, function(match){
  31551. // Build a simple regexp. Avoid captures, which would ruin the tokens list
  31552. var s,
  31553. c = match.charAt(0),
  31554. l = match.length,
  31555. p2 = '', p3 = '';
  31556. if(options.strict){
  31557. if(l > 1){ p2 = '0' + '{'+(l-1)+'}'; }
  31558. if(l > 2){ p3 = '0' + '{'+(l-2)+'}'; }
  31559. }else{
  31560. p2 = '0?'; p3 = '0{0,2}';
  31561. }
  31562. switch(c){
  31563. case 'y':
  31564. s = '\\d{2,4}';
  31565. break;
  31566. case 'M':
  31567. s = (l>2) ? '\\S+?' : '1[0-2]|'+p2+'[1-9]';
  31568. break;
  31569. case 'D':
  31570. s = '[12][0-9][0-9]|3[0-5][0-9]|36[0-6]|'+p2+'[1-9][0-9]|'+p3+'[1-9]';
  31571. break;
  31572. case 'd':
  31573. s = '3[01]|[12]\\d|'+p2+'[1-9]';
  31574. break;
  31575. case 'w':
  31576. s = '[1-4][0-9]|5[0-3]|'+p2+'[1-9]';
  31577. break;
  31578. case 'E':
  31579. s = '\\S+';
  31580. break;
  31581. case 'h': //hour (1-12)
  31582. s = '1[0-2]|'+p2+'[1-9]';
  31583. break;
  31584. case 'k': //hour (0-11)
  31585. s = '1[01]|'+p2+'\\d';
  31586. break;
  31587. case 'H': //hour (0-23)
  31588. s = '1\\d|2[0-3]|'+p2+'\\d';
  31589. break;
  31590. case 'K': //hour (1-24)
  31591. s = '1\\d|2[0-4]|'+p2+'[1-9]';
  31592. break;
  31593. case 'm':
  31594. case 's':
  31595. s = '[0-5]\\d';
  31596. break;
  31597. case 'S':
  31598. s = '\\d{'+l+'}';
  31599. break;
  31600. case 'a':
  31601. var am = options.am || bundle['dayPeriods-format-wide-am'],
  31602. pm = options.pm || bundle['dayPeriods-format-wide-pm'];
  31603. s = am + '|' + pm;
  31604. if(!options.strict){
  31605. if(am != am.toLowerCase()){ s += '|' + am.toLowerCase(); }
  31606. if(pm != pm.toLowerCase()){ s += '|' + pm.toLowerCase(); }
  31607. if(s.indexOf('.') != -1){ s += '|' + s.replace(/\./g, ""); }
  31608. }
  31609. s = s.replace(/\./g, "\\.");
  31610. break;
  31611. default:
  31612. // case 'v':
  31613. // case 'z':
  31614. // case 'Z':
  31615. s = ".*";
  31616. // console.log("parse of date format, pattern=" + pattern);
  31617. }
  31618. if(tokens){ tokens.push(match); }
  31619. return "(" + s + ")"; // add capture
  31620. }).replace(/[\xa0 ]/g, "[\\s\\xa0]"); // normalize whitespace. Need explicit handling of \xa0 for IE.
  31621. }
  31622. var _customFormats = [];
  31623. dojo.date.locale.addCustomFormats = function(/*String*/packageName, /*String*/bundleName){
  31624. // summary:
  31625. // Add a reference to a bundle containing localized custom formats to be
  31626. // used by date/time formatting and parsing routines.
  31627. //
  31628. // description:
  31629. // The user may add custom localized formats where the bundle has properties following the
  31630. // same naming convention used by dojo.cldr: `dateFormat-xxxx` / `timeFormat-xxxx`
  31631. // The pattern string should match the format used by the CLDR.
  31632. // See dojo.date.locale.format() for details.
  31633. // The resources must be loaded by dojo.requireLocalization() prior to use
  31634. _customFormats.push({pkg:packageName,name:bundleName});
  31635. };
  31636. dojo.date.locale._getGregorianBundle = function(/*String*/locale){
  31637. var gregorian = {};
  31638. dojo.forEach(_customFormats, function(desc){
  31639. var bundle = dojo.i18n.getLocalization(desc.pkg, desc.name, locale);
  31640. gregorian = lang.mixin(gregorian, bundle);
  31641. }, this);
  31642. return gregorian; /*Object*/
  31643. };
  31644. dojo.date.locale.addCustomFormats("dojo.cldr","gregorian");
  31645. dojo.date.locale.getNames = function(/*String*/item, /*String*/type, /*String?*/context, /*String?*/locale){
  31646. // summary:
  31647. // Used to get localized strings from dojo.cldr for day or month names.
  31648. //
  31649. // item:
  31650. // 'months' || 'days'
  31651. // type:
  31652. // 'wide' || 'abbr' || 'narrow' (e.g. "Monday", "Mon", or "M" respectively, in English)
  31653. // context:
  31654. // 'standAlone' || 'format' (default)
  31655. // locale:
  31656. // override locale used to find the names
  31657. var label,
  31658. lookup = dojo.date.locale._getGregorianBundle(locale),
  31659. props = [item, context, type];
  31660. if(context == 'standAlone'){
  31661. var key = props.join('-');
  31662. label = lookup[key];
  31663. // Fall back to 'format' flavor of name
  31664. if(label[0] == 1){ label = undefined; } // kludge, in the absence of real aliasing support in dojo.cldr
  31665. }
  31666. props[1] = 'format';
  31667. // return by copy so changes won't be made accidentally to the in-memory model
  31668. return (label || lookup[props.join('-')]).concat(); /*Array*/
  31669. };
  31670. dojo.date.locale.isWeekend = function(/*Date?*/dateObject, /*String?*/locale){
  31671. // summary:
  31672. // Determines if the date falls on a weekend, according to local custom.
  31673. var weekend = cldr.getWeekend(locale),
  31674. day = (dateObject || new Date()).getDay();
  31675. if(weekend.end < weekend.start){
  31676. weekend.end += 7;
  31677. if(day < weekend.start){ day += 7; }
  31678. }
  31679. return day >= weekend.start && day <= weekend.end; // Boolean
  31680. };
  31681. // These are used only by format and strftime. Do they need to be public? Which module should they go in?
  31682. dojo.date.locale._getDayOfYear = function(/*Date*/dateObject){
  31683. // summary: gets the day of the year as represented by dateObject
  31684. return date.difference(new Date(dateObject.getFullYear(), 0, 1, dateObject.getHours()), dateObject) + 1; // Number
  31685. };
  31686. dojo.date.locale._getWeekOfYear = function(/*Date*/dateObject, /*Number*/firstDayOfWeek){
  31687. if(arguments.length == 1){ firstDayOfWeek = 0; } // Sunday
  31688. var firstDayOfYear = new Date(dateObject.getFullYear(), 0, 1).getDay(),
  31689. adj = (firstDayOfYear - firstDayOfWeek + 7) % 7,
  31690. week = Math.floor((dojo.date.locale._getDayOfYear(dateObject) + adj - 1) / 7);
  31691. // if year starts on the specified day, start counting weeks at 1
  31692. if(firstDayOfYear == firstDayOfWeek){ week++; }
  31693. return week; // Number
  31694. };
  31695. return dojo.date.locale;
  31696. });
  31697. },
  31698. 'url:dojox/grid/resources/View.html':"<div class=\"dojoxGridView\" role=\"presentation\">\r\n\t<div class=\"dojoxGridHeader\" dojoAttachPoint=\"headerNode\" role=\"presentation\">\r\n\t\t<div dojoAttachPoint=\"headerNodeContainer\" style=\"width:9000em\" role=\"presentation\">\r\n\t\t\t<div dojoAttachPoint=\"headerContentNode\" role=\"row\"></div>\r\n\t\t</div>\r\n\t</div>\r\n\t<input type=\"checkbox\" class=\"dojoxGridHiddenFocus\" dojoAttachPoint=\"hiddenFocusNode\" role=\"presentation\" />\r\n\t<input type=\"checkbox\" class=\"dojoxGridHiddenFocus\" role=\"presentation\" />\r\n\t<div class=\"dojoxGridScrollbox\" dojoAttachPoint=\"scrollboxNode\" role=\"presentation\">\r\n\t\t<div class=\"dojoxGridContent\" dojoAttachPoint=\"contentNode\" hidefocus=\"hidefocus\" role=\"presentation\"></div>\r\n\t</div>\r\n</div>\r\n",
  31699. 'dojox/grid/enhanced/_Plugin':function(){
  31700. define("dojox/grid/enhanced/_Plugin", [
  31701. "dojo/_base/kernel",
  31702. "dojo/_base/lang",
  31703. "dojo/_base/declare",
  31704. "dojo/_base/array",
  31705. "dojo/_base/connect",
  31706. "../EnhancedGrid"
  31707. ], function(dojo, lang, declare, array, connect){
  31708. return declare("dojox.grid.enhanced._Plugin", null, {
  31709. // summary:
  31710. // Base class for all plugins.
  31711. //
  31712. // description:
  31713. // Provides common plugin functionality and basic life cycle management.
  31714. //
  31715. // Each concrete plugin must have a name field and is responsible for registering itself to the global plugin registry
  31716. // e.g. for dnd plugin:
  31717. // | dojox.grid.EnhancedGrid.registerPlugin("dnd" /*plugin name*/,
  31718. // | dojox.grid.enhanced.plugins.DnD /*full class name of a plugin*/
  31719. // | {"preInit": false, "dependency": ["nestedSorting"]} /*properties*/);
  31720. //
  31721. // [Keywords] of plugin properties(case sensitive)
  31722. // - "preInit": boolean, whether a plugin should be created before EnhancedGrid.postCreate(),
  31723. // false by default(plugins are created after EnhancedGrid.postCreate()).
  31724. // - "dependency": array or string, plugin(s) indicated by "dependency" will be created before the current one.
  31725. // Note: recursive cycle dependencies are not supported e.g. following dependency is invalid:
  31726. // pluginA -> pluginB -> pluginA
  31727. //
  31728. // example:
  31729. // 1. Customize default DnD plugin
  31730. // | dojo.declare("mygrid.MyDnD", dojox.grid.enhanced.plugins.DnD, {
  31731. // | name:"dnd" //still reuse the plugin name
  31732. // | constructor: function(inGrid, option){ ... }
  31733. // | });
  31734. // | dojox.grid.EnhancedGrid.registerPlugin("dnd", mygrid.MyDnD);
  31735. //
  31736. // 2. Add new plugin - PluginA
  31737. // | dojo.declare("mygrid.PluginA", dojox.grid.enhanced._Plugin, {
  31738. // | name: "pA",
  31739. // | constructor: function(inGrid, option){ ... }
  31740. // | });
  31741. // | dojox.grid.EnhancedGrid.registerPlugin("pA",mygrid.PluginA);
  31742. //
  31743. // 3. Use plugins
  31744. // | dojo.require("mygrid.MyDnD");
  31745. // | dojo.require("mygrid.PluginA");
  31746. // | <script type="text/javascript">
  31747. // | var grid = new dojox.grid.EnhancedGrid(
  31748. // | {plugins: {dnd:true, pA:true}, ... }, dojo.byId("gridDiv"));
  31749. // | grid.startup();
  31750. // | </script>
  31751. //name: String
  31752. // Plugin name, e.g. 'nestedSorting', 'dnd'...
  31753. name: 'plugin',
  31754. //grid: Object
  31755. // Grid that the plugin belongs to
  31756. grid: null,
  31757. //option: Object
  31758. // Plugin properties - leveraged with default and user specified properties.
  31759. // e.g. for dnd plugin, it may look like {"class": dojox.grid.enhanced.plugins.DnD, "dependency": ["nestedSorting"], ...}
  31760. option: {},
  31761. //_connects: Array
  31762. // List of all connections.
  31763. _connects: [],
  31764. //_subscribes: Array
  31765. // List of all subscribes.
  31766. _subscribes: [],
  31767. //privates: Object
  31768. // Private properties/methods shouldn't be mixin-ed anytime.
  31769. privates: {},
  31770. constructor: function(inGrid, option){
  31771. this.grid = inGrid;
  31772. this.option = option;
  31773. this._connects = [];
  31774. this._subscribes = [];
  31775. this.privates = lang.mixin({},dojox.grid.enhanced._Plugin.prototype);
  31776. this.init();
  31777. },
  31778. init: function(){},
  31779. onPreInit: function(){},
  31780. onPostInit: function(){},
  31781. onStartUp: function(){},
  31782. connect: function(obj, event, method){
  31783. // summary:
  31784. // Connects specified obj/event to specified method of this object.
  31785. // example:
  31786. // | var plugin = new dojox.grid.enhanced._Plugin(grid,"myPlugin",{...});
  31787. // | // when foo.bar() is called, call the listener in the scope of plugin
  31788. // | plugin.connect(foo, "bar", function(){
  31789. // | console.debug(this.xxx());//"this" - plugin scope
  31790. // | });
  31791. var conn = connect.connect(obj, event, this, method);
  31792. this._connects.push(conn);
  31793. return conn;
  31794. },
  31795. disconnect: function(handle){
  31796. // summary:
  31797. // Disconnects handle and removes it from connection list.
  31798. array.some(this._connects, function(conn, i, conns){
  31799. if(conn == handle){
  31800. connect.disconnect(handle);
  31801. conns.splice(i, 1);
  31802. return true;
  31803. }
  31804. return false;
  31805. });
  31806. },
  31807. subscribe: function(topic, method){
  31808. // summary:
  31809. // Subscribes to the specified topic and calls the specified method
  31810. // of this object.
  31811. // example:
  31812. // | var plugin = new dojox.grid.enhanced._Plugin(grid,"myPlugin",{...});
  31813. // | // when /my/topic is published, call the subscriber in the scope of plugin
  31814. // | // with passed parameter - "v"
  31815. // | plugin.subscribe("/my/topic", function(v){
  31816. // | console.debug(this.xxx(v));//"this" - plugin scope
  31817. // | });
  31818. var subscribe = connect.subscribe(topic, this, method);
  31819. this._subscribes.push(subscribe);
  31820. return subscribe;
  31821. },
  31822. unsubscribe: function(handle){
  31823. // summary:
  31824. // Un-subscribes handle and removes it from subscriptions list.
  31825. array.some(this._subscribes, function(subscribe, i, subscribes){
  31826. if(subscribe == handle){
  31827. connect.unsubscribe(handle);
  31828. subscribes.splice(i, 1);
  31829. return true;
  31830. }
  31831. return false;
  31832. });
  31833. },
  31834. onSetStore: function(store){
  31835. // summary:
  31836. // Called when store is changed.
  31837. },
  31838. destroy: function(){
  31839. // summary:
  31840. // Destroy all resources.
  31841. array.forEach(this._connects, connect.disconnect);
  31842. array.forEach(this._subscribes, connect.unsubscribe);
  31843. delete this._connects;
  31844. delete this._subscribes;
  31845. delete this.option;
  31846. delete this.privates;
  31847. //console.log('Plugin [', this.name, '].destroy() executed!');
  31848. }
  31849. });
  31850. //Each plugin is responsible for registering itself
  31851. // e.g. for DnD plugin(name:'dnd'):
  31852. // | dojox.grid.EnhancedGrid.registerPlugin(dojox.grid.enhanced.plugins.DnD/*class*/,
  31853. // | {"dependency": ["nestedSorting"]}/*Optional - properties*/);
  31854. });
  31855. },
  31856. 'dojox/html/entities':function(){
  31857. define("dojox/html/entities", ["dojo/_base/lang"], function(lang) {
  31858. // dojox.html.entities.html [public] Array
  31859. // Entity characters for HTML, represented as an array of
  31860. // character code, entity name (minus & and ; wrapping.
  31861. // The function wrapper is to fix global leking with the build tools.
  31862. var dhe = lang.getObject("dojox.html.entities",true);
  31863. var _applyEncodingMap = function(str, map){
  31864. // summary:
  31865. // Private internal function for performing encoding of entity characters.
  31866. // tags:
  31867. // private
  31868. // Check to see if we have genned and cached a regexp for this map yet
  31869. // If we have, use it, if not, gen it, cache, then use.
  31870. var mapper, regexp;
  31871. if(map._encCache &&
  31872. map._encCache.regexp &&
  31873. map._encCache.mapper &&
  31874. map.length == map._encCache.length){
  31875. mapper = map._encCache.mapper;
  31876. regexp = map._encCache.regexp;
  31877. }else{
  31878. mapper = {};
  31879. regexp = ["["];
  31880. var i;
  31881. for(i = 0; i < map.length; i++){
  31882. mapper[map[i][0]] = "&" + map[i][1] + ";";
  31883. regexp.push(map[i][0]);
  31884. }
  31885. regexp.push("]");
  31886. regexp = new RegExp(regexp.join(""), "g");
  31887. map._encCache = {
  31888. mapper: mapper,
  31889. regexp: regexp,
  31890. length: map.length
  31891. };
  31892. }
  31893. str = str.replace(regexp, function(c){
  31894. return mapper[c];
  31895. });
  31896. return str;
  31897. };
  31898. var _applyDecodingMap = function(str, map){
  31899. // summary:
  31900. // Private internal function for performing decoding of entity characters.
  31901. // tags:
  31902. // private
  31903. var mapper, regexp;
  31904. if(map._decCache &&
  31905. map._decCache.regexp &&
  31906. map._decCache.mapper &&
  31907. map.length == map._decCache.length){
  31908. mapper = map._decCache.mapper;
  31909. regexp = map._decCache.regexp;
  31910. }else{
  31911. mapper = {};
  31912. regexp = ["("];
  31913. var i;
  31914. for(i = 0; i < map.length; i++){
  31915. var e = "&" + map[i][1] + ";";
  31916. if(i){regexp.push("|");}
  31917. mapper[e] = map[i][0];
  31918. regexp.push(e);
  31919. }
  31920. regexp.push(")");
  31921. regexp = new RegExp(regexp.join(""), "g");
  31922. map._decCache = {
  31923. mapper: mapper,
  31924. regexp: regexp,
  31925. length: map.length
  31926. };
  31927. }
  31928. str = str.replace(regexp, function(c){
  31929. return mapper[c];
  31930. });
  31931. return str;
  31932. };
  31933. dhe.html = [
  31934. ["\u0026","amp"], ["\u0022","quot"],["\u003C","lt"], ["\u003E","gt"],
  31935. ["\u00A0","nbsp"]
  31936. ];
  31937. // dojox.html.entities.latin [public] Array
  31938. // Entity characters for Latin characters and similar, represented as an array of
  31939. // character code, entity name (minus & and ; wrapping.
  31940. dhe.latin = [
  31941. ["\u00A1","iexcl"],["\u00A2","cent"],["\u00A3","pound"],["\u20AC","euro"],
  31942. ["\u00A4","curren"],["\u00A5","yen"],["\u00A6","brvbar"],["\u00A7","sect"],
  31943. ["\u00A8","uml"],["\u00A9","copy"],["\u00AA","ordf"],["\u00AB","laquo"],
  31944. ["\u00AC","not"],["\u00AD","shy"],["\u00AE","reg"],["\u00AF","macr"],
  31945. ["\u00B0","deg"],["\u00B1","plusmn"],["\u00B2","sup2"],["\u00B3","sup3"],
  31946. ["\u00B4","acute"],["\u00B5","micro"],["\u00B6","para"],["\u00B7","middot"],
  31947. ["\u00B8","cedil"],["\u00B9","sup1"],["\u00BA","ordm"],["\u00BB","raquo"],
  31948. ["\u00BC","frac14"],["\u00BD","frac12"],["\u00BE","frac34"],["\u00BF","iquest"],
  31949. ["\u00C0","Agrave"],["\u00C1","Aacute"],["\u00C2","Acirc"],["\u00C3","Atilde"],
  31950. ["\u00C4","Auml"],["\u00C5","Aring"],["\u00C6","AElig"],["\u00C7","Ccedil"],
  31951. ["\u00C8","Egrave"],["\u00C9","Eacute"],["\u00CA","Ecirc"],["\u00CB","Euml"],
  31952. ["\u00CC","Igrave"],["\u00CD","Iacute"],["\u00CE","Icirc"],["\u00CF","Iuml"],
  31953. ["\u00D0","ETH"],["\u00D1","Ntilde"],["\u00D2","Ograve"],["\u00D3","Oacute"],
  31954. ["\u00D4","Ocirc"],["\u00D5","Otilde"],["\u00D6","Ouml"],["\u00D7","times"],
  31955. ["\u00D8","Oslash"],["\u00D9","Ugrave"],["\u00DA","Uacute"],["\u00DB","Ucirc"],
  31956. ["\u00DC","Uuml"],["\u00DD","Yacute"],["\u00DE","THORN"],["\u00DF","szlig"],
  31957. ["\u00E0","agrave"],["\u00E1","aacute"],["\u00E2","acirc"],["\u00E3","atilde"],
  31958. ["\u00E4","auml"],["\u00E5","aring"],["\u00E6","aelig"],["\u00E7","ccedil"],
  31959. ["\u00E8","egrave"],["\u00E9","eacute"],["\u00EA","ecirc"],["\u00EB","euml"],
  31960. ["\u00EC","igrave"],["\u00ED","iacute"],["\u00EE","icirc"],["\u00EF","iuml"],
  31961. ["\u00F0","eth"],["\u00F1","ntilde"],["\u00F2","ograve"],["\u00F3","oacute"],
  31962. ["\u00F4","ocirc"],["\u00F5","otilde"],["\u00F6","ouml"],["\u00F7","divide"],
  31963. ["\u00F8","oslash"],["\u00F9","ugrave"],["\u00FA","uacute"],["\u00FB","ucirc"],
  31964. ["\u00FC","uuml"],["\u00FD","yacute"],["\u00FE","thorn"],["\u00FF","yuml"],
  31965. ["\u0192","fnof"],["\u0391","Alpha"],["\u0392","Beta"],["\u0393","Gamma"],
  31966. ["\u0394","Delta"],["\u0395","Epsilon"],["\u0396","Zeta"],["\u0397","Eta"],
  31967. ["\u0398","Theta"], ["\u0399","Iota"],["\u039A","Kappa"],["\u039B","Lambda"],
  31968. ["\u039C","Mu"],["\u039D","Nu"],["\u039E","Xi"],["\u039F","Omicron"],
  31969. ["\u03A0","Pi"],["\u03A1","Rho"],["\u03A3","Sigma"],["\u03A4","Tau"],
  31970. ["\u03A5","Upsilon"],["\u03A6","Phi"],["\u03A7","Chi"],["\u03A8","Psi"],
  31971. ["\u03A9","Omega"],["\u03B1","alpha"],["\u03B2","beta"],["\u03B3","gamma"],
  31972. ["\u03B4","delta"],["\u03B5","epsilon"],["\u03B6","zeta"],["\u03B7","eta"],
  31973. ["\u03B8","theta"],["\u03B9","iota"],["\u03BA","kappa"],["\u03BB","lambda"],
  31974. ["\u03BC","mu"],["\u03BD","nu"],["\u03BE","xi"],["\u03BF","omicron"],
  31975. ["\u03C0","pi"],["\u03C1","rho"],["\u03C2","sigmaf"],["\u03C3","sigma"],
  31976. ["\u03C4","tau"],["\u03C5","upsilon"],["\u03C6","phi"],["\u03C7","chi"],
  31977. ["\u03C8","psi"],["\u03C9","omega"],["\u03D1","thetasym"],["\u03D2","upsih"],
  31978. ["\u03D6","piv"],["\u2022","bull"],["\u2026","hellip"],["\u2032","prime"],
  31979. ["\u2033","Prime"],["\u203E","oline"],["\u2044","frasl"],["\u2118","weierp"],
  31980. ["\u2111","image"],["\u211C","real"],["\u2122","trade"],["\u2135","alefsym"],
  31981. ["\u2190","larr"],["\u2191","uarr"],["\u2192","rarr"],["\u2193","darr"],
  31982. ["\u2194","harr"],["\u21B5","crarr"],["\u21D0","lArr"],["\u21D1","uArr"],
  31983. ["\u21D2","rArr"],["\u21D3","dArr"],["\u21D4","hArr"],["\u2200","forall"],
  31984. ["\u2202","part"],["\u2203","exist"],["\u2205","empty"],["\u2207","nabla"],
  31985. ["\u2208","isin"],["\u2209","notin"],["\u220B","ni"],["\u220F","prod"],
  31986. ["\u2211","sum"],["\u2212","minus"],["\u2217","lowast"],["\u221A","radic"],
  31987. ["\u221D","prop"],["\u221E","infin"],["\u2220","ang"],["\u2227","and"],
  31988. ["\u2228","or"],["\u2229","cap"],["\u222A","cup"],["\u222B","int"],
  31989. ["\u2234","there4"],["\u223C","sim"],["\u2245","cong"],["\u2248","asymp"],
  31990. ["\u2260","ne"],["\u2261","equiv"],["\u2264","le"],["\u2265","ge"],
  31991. ["\u2282","sub"],["\u2283","sup"],["\u2284","nsub"],["\u2286","sube"],
  31992. ["\u2287","supe"],["\u2295","oplus"],["\u2297","otimes"],["\u22A5","perp"],
  31993. ["\u22C5","sdot"],["\u2308","lceil"],["\u2309","rceil"],["\u230A","lfloor"],
  31994. ["\u230B","rfloor"],["\u2329","lang"],["\u232A","rang"],["\u25CA","loz"],
  31995. ["\u2660","spades"],["\u2663","clubs"],["\u2665","hearts"],["\u2666","diams"],
  31996. ["\u0152","Elig"],["\u0153","oelig"],["\u0160","Scaron"],["\u0161","scaron"],
  31997. ["\u0178","Yuml"],["\u02C6","circ"],["\u02DC","tilde"],["\u2002","ensp"],
  31998. ["\u2003","emsp"],["\u2009","thinsp"],["\u200C","zwnj"],["\u200D","zwj"],
  31999. ["\u200E","lrm"],["\u200F","rlm"],["\u2013","ndash"],["\u2014","mdash"],
  32000. ["\u2018","lsquo"],["\u2019","rsquo"],["\u201A","sbquo"],["\u201C","ldquo"],
  32001. ["\u201D","rdquo"],["\u201E","bdquo"],["\u2020","dagger"],["\u2021","Dagger"],
  32002. ["\u2030","permil"],["\u2039","lsaquo"],["\u203A","rsaquo"]
  32003. ];
  32004. dhe.encode = function(str/*string*/, m /*array?*/){
  32005. // summary:
  32006. // Function to obtain an entity encoding for a specified character
  32007. // str:
  32008. // The string to process for possible entity encoding.
  32009. // m:
  32010. // An optional list of character to entity name mappings (array of
  32011. // arrays). If not provided, it uses the and Latin entities as the
  32012. // set to map and escape.
  32013. // tags:
  32014. // public
  32015. if(str){
  32016. if(!m){
  32017. // Apply the basic mappings. HTML should always come first when decoding
  32018. // as well.
  32019. str = _applyEncodingMap(str, dhe.html);
  32020. str = _applyEncodingMap(str, dhe.latin);
  32021. }else{
  32022. str = _applyEncodingMap(str, m);
  32023. }
  32024. }
  32025. return str;
  32026. };
  32027. dhe.decode = function(str/*string*/, m /*array?*/){
  32028. // summary:
  32029. // Function to obtain an entity encoding for a specified character
  32030. // str:
  32031. // The string to process for possible entity encoding to decode.
  32032. // m:
  32033. // An optional list of character to entity name mappings (array of
  32034. // arrays). If not provided, it uses the HTML and Latin entities as the
  32035. // set to map and decode.
  32036. // tags:
  32037. // public
  32038. if(str){
  32039. if(!m){
  32040. // Apply the basic mappings. HTML should always come first when decoding
  32041. // as well.
  32042. str = _applyDecodingMap(str, dhe.html);
  32043. str = _applyDecodingMap(str, dhe.latin);
  32044. }else{
  32045. str = _applyDecodingMap(str, m);
  32046. }
  32047. }
  32048. return str;
  32049. };
  32050. return dhe;
  32051. });
  32052. },
  32053. 'dijit/_editor/range':function(){
  32054. define("dijit/_editor/range", [
  32055. "dojo/_base/array", // array.every
  32056. "dojo/_base/declare", // declare
  32057. "dojo/_base/lang", // lang.isArray
  32058. "dojo/_base/window", // win.global
  32059. ".." // for exporting symbols to dijit, TODO: remove in 2.0
  32060. ], function(array, declare, lang, win, dijit){
  32061. // module:
  32062. // dijit/_editor/range
  32063. // summary:
  32064. // W3C range API
  32065. dijit.range={};
  32066. dijit.range.getIndex = function(/*DomNode*/node, /*DomNode*/parent){
  32067. // dojo.profile.start("dijit.range.getIndex");
  32068. var ret = [], retR = [];
  32069. var onode = node;
  32070. var pnode, n;
  32071. while(node != parent){
  32072. var i = 0;
  32073. pnode = node.parentNode;
  32074. while((n = pnode.childNodes[i++])){
  32075. if(n === node){
  32076. --i;
  32077. break;
  32078. }
  32079. }
  32080. //if(i>=pnode.childNodes.length){
  32081. //dojo.debug("Error finding index of a node in dijit.range.getIndex");
  32082. //}
  32083. ret.unshift(i);
  32084. retR.unshift(i - pnode.childNodes.length);
  32085. node = pnode;
  32086. }
  32087. //normalized() can not be called so often to prevent
  32088. //invalidating selection/range, so we have to detect
  32089. //here that any text nodes in a row
  32090. if(ret.length > 0 && onode.nodeType == 3){
  32091. n = onode.previousSibling;
  32092. while(n && n.nodeType == 3){
  32093. ret[ret.length - 1]--;
  32094. n = n.previousSibling;
  32095. }
  32096. n = onode.nextSibling;
  32097. while(n && n.nodeType == 3){
  32098. retR[retR.length - 1]++;
  32099. n = n.nextSibling;
  32100. }
  32101. }
  32102. // dojo.profile.end("dijit.range.getIndex");
  32103. return {o: ret, r:retR};
  32104. };
  32105. dijit.range.getNode = function(/*Array*/index, /*DomNode*/parent){
  32106. if(!lang.isArray(index) || index.length == 0){
  32107. return parent;
  32108. }
  32109. var node = parent;
  32110. // if(!node)debugger
  32111. array.every(index, function(i){
  32112. if(i >= 0 && i < node.childNodes.length){
  32113. node = node.childNodes[i];
  32114. }else{
  32115. node = null;
  32116. //console.debug('Error: can not find node with index',index,'under parent node',parent );
  32117. return false; //terminate array.every
  32118. }
  32119. return true; //carry on the every loop
  32120. });
  32121. return node;
  32122. };
  32123. dijit.range.getCommonAncestor = function(n1, n2, root){
  32124. root = root || n1.ownerDocument.body;
  32125. var getAncestors = function(n){
  32126. var as = [];
  32127. while(n){
  32128. as.unshift(n);
  32129. if(n !== root){
  32130. n = n.parentNode;
  32131. }else{
  32132. break;
  32133. }
  32134. }
  32135. return as;
  32136. };
  32137. var n1as = getAncestors(n1);
  32138. var n2as = getAncestors(n2);
  32139. var m = Math.min(n1as.length, n2as.length);
  32140. var com = n1as[0]; //at least, one element should be in the array: the root (BODY by default)
  32141. for(var i = 1; i < m; i++){
  32142. if(n1as[i] === n2as[i]){
  32143. com = n1as[i]
  32144. }else{
  32145. break;
  32146. }
  32147. }
  32148. return com;
  32149. };
  32150. dijit.range.getAncestor = function(/*DomNode*/node, /*RegEx?*/regex, /*DomNode?*/root){
  32151. root = root || node.ownerDocument.body;
  32152. while(node && node !== root){
  32153. var name = node.nodeName.toUpperCase();
  32154. if(regex.test(name)){
  32155. return node;
  32156. }
  32157. node = node.parentNode;
  32158. }
  32159. return null;
  32160. };
  32161. dijit.range.BlockTagNames = /^(?:P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|DT|DE)$/;
  32162. dijit.range.getBlockAncestor = function(/*DomNode*/node, /*RegEx?*/regex, /*DomNode?*/root){
  32163. root = root || node.ownerDocument.body;
  32164. regex = regex || dijit.range.BlockTagNames;
  32165. var block = null, blockContainer;
  32166. while(node && node !== root){
  32167. var name = node.nodeName.toUpperCase();
  32168. if(!block && regex.test(name)){
  32169. block = node;
  32170. }
  32171. if(!blockContainer && (/^(?:BODY|TD|TH|CAPTION)$/).test(name)){
  32172. blockContainer = node;
  32173. }
  32174. node = node.parentNode;
  32175. }
  32176. return {blockNode:block, blockContainer:blockContainer || node.ownerDocument.body};
  32177. };
  32178. dijit.range.atBeginningOfContainer = function(/*DomNode*/container, /*DomNode*/node, /*Int*/offset){
  32179. var atBeginning = false;
  32180. var offsetAtBeginning = (offset == 0);
  32181. if(!offsetAtBeginning && node.nodeType == 3){ //if this is a text node, check whether the left part is all space
  32182. if(/^[\s\xA0]+$/.test(node.nodeValue.substr(0, offset))){
  32183. offsetAtBeginning = true;
  32184. }
  32185. }
  32186. if(offsetAtBeginning){
  32187. var cnode = node;
  32188. atBeginning = true;
  32189. while(cnode && cnode !== container){
  32190. if(cnode.previousSibling){
  32191. atBeginning = false;
  32192. break;
  32193. }
  32194. cnode = cnode.parentNode;
  32195. }
  32196. }
  32197. return atBeginning;
  32198. };
  32199. dijit.range.atEndOfContainer = function(/*DomNode*/container, /*DomNode*/node, /*Int*/offset){
  32200. var atEnd = false;
  32201. var offsetAtEnd = (offset == (node.length || node.childNodes.length));
  32202. if(!offsetAtEnd && node.nodeType == 3){ //if this is a text node, check whether the right part is all space
  32203. if(/^[\s\xA0]+$/.test(node.nodeValue.substr(offset))){
  32204. offsetAtEnd = true;
  32205. }
  32206. }
  32207. if(offsetAtEnd){
  32208. var cnode = node;
  32209. atEnd = true;
  32210. while(cnode && cnode !== container){
  32211. if(cnode.nextSibling){
  32212. atEnd = false;
  32213. break;
  32214. }
  32215. cnode = cnode.parentNode;
  32216. }
  32217. }
  32218. return atEnd;
  32219. };
  32220. dijit.range.adjacentNoneTextNode = function(startnode, next){
  32221. var node = startnode;
  32222. var len = (0 - startnode.length) || 0;
  32223. var prop = next ? 'nextSibling' : 'previousSibling';
  32224. while(node){
  32225. if(node.nodeType != 3){
  32226. break;
  32227. }
  32228. len += node.length;
  32229. node = node[prop];
  32230. }
  32231. return [node,len];
  32232. };
  32233. dijit.range._w3c = Boolean(window['getSelection']);
  32234. dijit.range.create = function(/*Window?*/window){
  32235. if(dijit.range._w3c){
  32236. return (window || win.global).document.createRange();
  32237. }else{//IE
  32238. return new dijit.range.W3CRange;
  32239. }
  32240. };
  32241. dijit.range.getSelection = function(/*Window*/win, /*Boolean?*/ignoreUpdate){
  32242. if(dijit.range._w3c){
  32243. return win.getSelection();
  32244. }else{//IE
  32245. var s = new dijit.range.ie.selection(win);
  32246. if(!ignoreUpdate){
  32247. s._getCurrentSelection();
  32248. }
  32249. return s;
  32250. }
  32251. };
  32252. if(!dijit.range._w3c){
  32253. dijit.range.ie = {
  32254. cachedSelection: {},
  32255. selection: function(win){
  32256. this._ranges = [];
  32257. this.addRange = function(r, /*boolean*/internal){
  32258. this._ranges.push(r);
  32259. if(!internal){
  32260. r._select();
  32261. }
  32262. this.rangeCount = this._ranges.length;
  32263. };
  32264. this.removeAllRanges = function(){
  32265. //don't detach, the range may be used later
  32266. // for(var i=0;i<this._ranges.length;i++){
  32267. // this._ranges[i].detach();
  32268. // }
  32269. this._ranges = [];
  32270. this.rangeCount = 0;
  32271. };
  32272. var _initCurrentRange = function(){
  32273. var r = win.document.selection.createRange();
  32274. var type = win.document.selection.type.toUpperCase();
  32275. if(type == "CONTROL"){
  32276. //TODO: multiple range selection(?)
  32277. return new dijit.range.W3CRange(dijit.range.ie.decomposeControlRange(r));
  32278. }else{
  32279. return new dijit.range.W3CRange(dijit.range.ie.decomposeTextRange(r));
  32280. }
  32281. };
  32282. this.getRangeAt = function(i){
  32283. return this._ranges[i];
  32284. };
  32285. this._getCurrentSelection = function(){
  32286. this.removeAllRanges();
  32287. var r = _initCurrentRange();
  32288. if(r){
  32289. this.addRange(r, true);
  32290. this.isCollapsed = r.collapsed;
  32291. }else{
  32292. this.isCollapsed = true;
  32293. }
  32294. };
  32295. },
  32296. decomposeControlRange: function(range){
  32297. var firstnode = range.item(0), lastnode = range.item(range.length - 1);
  32298. var startContainer = firstnode.parentNode, endContainer = lastnode.parentNode;
  32299. var startOffset = dijit.range.getIndex(firstnode, startContainer).o[0];
  32300. var endOffset = dijit.range.getIndex(lastnode, endContainer).o[0] + 1;
  32301. return [startContainer, startOffset,endContainer, endOffset];
  32302. },
  32303. getEndPoint: function(range, end){
  32304. var atmrange = range.duplicate();
  32305. atmrange.collapse(!end);
  32306. var cmpstr = 'EndTo' + (end ? 'End' : 'Start');
  32307. var parentNode = atmrange.parentElement();
  32308. var startnode, startOffset, lastNode;
  32309. if(parentNode.childNodes.length > 0){
  32310. array.every(parentNode.childNodes, function(node, i){
  32311. var calOffset;
  32312. if(node.nodeType != 3){
  32313. atmrange.moveToElementText(node);
  32314. if(atmrange.compareEndPoints(cmpstr, range) > 0){
  32315. //startnode = node.previousSibling;
  32316. if(lastNode && lastNode.nodeType == 3){
  32317. //where shall we put the start? in the text node or after?
  32318. startnode = lastNode;
  32319. calOffset = true;
  32320. }else{
  32321. startnode = parentNode;
  32322. startOffset = i;
  32323. return false;
  32324. }
  32325. }else{
  32326. if(i == parentNode.childNodes.length - 1){
  32327. startnode = parentNode;
  32328. startOffset = parentNode.childNodes.length;
  32329. return false;
  32330. }
  32331. }
  32332. }else{
  32333. if(i == parentNode.childNodes.length - 1){//at the end of this node
  32334. startnode = node;
  32335. calOffset = true;
  32336. }
  32337. }
  32338. // try{
  32339. if(calOffset && startnode){
  32340. var prevnode = dijit.range.adjacentNoneTextNode(startnode)[0];
  32341. if(prevnode){
  32342. startnode = prevnode.nextSibling;
  32343. }else{
  32344. startnode = parentNode.firstChild; //firstChild must be a text node
  32345. }
  32346. var prevnodeobj = dijit.range.adjacentNoneTextNode(startnode);
  32347. prevnode = prevnodeobj[0];
  32348. var lenoffset = prevnodeobj[1];
  32349. if(prevnode){
  32350. atmrange.moveToElementText(prevnode);
  32351. atmrange.collapse(false);
  32352. }else{
  32353. atmrange.moveToElementText(parentNode);
  32354. }
  32355. atmrange.setEndPoint(cmpstr, range);
  32356. startOffset = atmrange.text.length - lenoffset;
  32357. return false;
  32358. }
  32359. // }catch(e){ debugger }
  32360. lastNode = node;
  32361. return true;
  32362. });
  32363. }else{
  32364. startnode = parentNode;
  32365. startOffset = 0;
  32366. }
  32367. //if at the end of startnode and we are dealing with start container, then
  32368. //move the startnode to nextSibling if it is a text node
  32369. //TODO: do this for end container?
  32370. if(!end && startnode.nodeType == 1 && startOffset == startnode.childNodes.length){
  32371. var nextnode = startnode.nextSibling;
  32372. if(nextnode && nextnode.nodeType == 3){
  32373. startnode = nextnode;
  32374. startOffset = 0;
  32375. }
  32376. }
  32377. return [startnode, startOffset];
  32378. },
  32379. setEndPoint: function(range, container, offset){
  32380. //text node
  32381. var atmrange = range.duplicate(), node, len;
  32382. if(container.nodeType != 3){ //normal node
  32383. if(offset > 0){
  32384. node = container.childNodes[offset - 1];
  32385. if(node){
  32386. if(node.nodeType == 3){
  32387. container = node;
  32388. offset = node.length;
  32389. //pass through
  32390. }else{
  32391. if(node.nextSibling && node.nextSibling.nodeType == 3){
  32392. container = node.nextSibling;
  32393. offset = 0;
  32394. //pass through
  32395. }else{
  32396. atmrange.moveToElementText(node.nextSibling ? node : container);
  32397. var parent = node.parentNode;
  32398. var tempNode = parent.insertBefore(node.ownerDocument.createTextNode(' '), node.nextSibling);
  32399. atmrange.collapse(false);
  32400. parent.removeChild(tempNode);
  32401. }
  32402. }
  32403. }
  32404. }else{
  32405. atmrange.moveToElementText(container);
  32406. atmrange.collapse(true);
  32407. }
  32408. }
  32409. if(container.nodeType == 3){
  32410. var prevnodeobj = dijit.range.adjacentNoneTextNode(container);
  32411. var prevnode = prevnodeobj[0];
  32412. len = prevnodeobj[1];
  32413. if(prevnode){
  32414. atmrange.moveToElementText(prevnode);
  32415. atmrange.collapse(false);
  32416. //if contentEditable is not inherit, the above collapse won't make the end point
  32417. //in the correctly position: it always has a -1 offset, so compensate it
  32418. if(prevnode.contentEditable != 'inherit'){
  32419. len++;
  32420. }
  32421. }else{
  32422. atmrange.moveToElementText(container.parentNode);
  32423. atmrange.collapse(true);
  32424. }
  32425. offset += len;
  32426. if(offset > 0){
  32427. if(atmrange.move('character', offset) != offset){
  32428. console.error('Error when moving!');
  32429. }
  32430. }
  32431. }
  32432. return atmrange;
  32433. },
  32434. decomposeTextRange: function(range){
  32435. var tmpary = dijit.range.ie.getEndPoint(range);
  32436. var startContainer = tmpary[0], startOffset = tmpary[1];
  32437. var endContainer = tmpary[0], endOffset = tmpary[1];
  32438. if(range.htmlText.length){
  32439. if(range.htmlText == range.text){ //in the same text node
  32440. endOffset = startOffset + range.text.length;
  32441. }else{
  32442. tmpary = dijit.range.ie.getEndPoint(range, true);
  32443. endContainer = tmpary[0],endOffset = tmpary[1];
  32444. // if(startContainer.tagName == "BODY"){
  32445. // startContainer = startContainer.firstChild;
  32446. // }
  32447. }
  32448. }
  32449. return [startContainer, startOffset, endContainer, endOffset];
  32450. },
  32451. setRange: function(range, startContainer, startOffset, endContainer, endOffset, collapsed){
  32452. var start = dijit.range.ie.setEndPoint(range, startContainer, startOffset);
  32453. range.setEndPoint('StartToStart', start);
  32454. if(!collapsed){
  32455. var end = dijit.range.ie.setEndPoint(range, endContainer, endOffset);
  32456. }
  32457. range.setEndPoint('EndToEnd', end || start);
  32458. return range;
  32459. }
  32460. };
  32461. declare("dijit.range.W3CRange",null, {
  32462. constructor: function(){
  32463. if(arguments.length>0){
  32464. this.setStart(arguments[0][0],arguments[0][1]);
  32465. this.setEnd(arguments[0][2],arguments[0][3]);
  32466. }else{
  32467. this.commonAncestorContainer = null;
  32468. this.startContainer = null;
  32469. this.startOffset = 0;
  32470. this.endContainer = null;
  32471. this.endOffset = 0;
  32472. this.collapsed = true;
  32473. }
  32474. },
  32475. _updateInternal: function(){
  32476. if(this.startContainer !== this.endContainer){
  32477. this.commonAncestorContainer = dijit.range.getCommonAncestor(this.startContainer, this.endContainer);
  32478. }else{
  32479. this.commonAncestorContainer = this.startContainer;
  32480. }
  32481. this.collapsed = (this.startContainer === this.endContainer) && (this.startOffset == this.endOffset);
  32482. },
  32483. setStart: function(node, offset){
  32484. offset=parseInt(offset);
  32485. if(this.startContainer === node && this.startOffset == offset){
  32486. return;
  32487. }
  32488. delete this._cachedBookmark;
  32489. this.startContainer = node;
  32490. this.startOffset = offset;
  32491. if(!this.endContainer){
  32492. this.setEnd(node, offset);
  32493. }else{
  32494. this._updateInternal();
  32495. }
  32496. },
  32497. setEnd: function(node, offset){
  32498. offset=parseInt(offset);
  32499. if(this.endContainer === node && this.endOffset == offset){
  32500. return;
  32501. }
  32502. delete this._cachedBookmark;
  32503. this.endContainer = node;
  32504. this.endOffset = offset;
  32505. if(!this.startContainer){
  32506. this.setStart(node, offset);
  32507. }else{
  32508. this._updateInternal();
  32509. }
  32510. },
  32511. setStartAfter: function(node, offset){
  32512. this._setPoint('setStart', node, offset, 1);
  32513. },
  32514. setStartBefore: function(node, offset){
  32515. this._setPoint('setStart', node, offset, 0);
  32516. },
  32517. setEndAfter: function(node, offset){
  32518. this._setPoint('setEnd', node, offset, 1);
  32519. },
  32520. setEndBefore: function(node, offset){
  32521. this._setPoint('setEnd', node, offset, 0);
  32522. },
  32523. _setPoint: function(what, node, offset, ext){
  32524. var index = dijit.range.getIndex(node, node.parentNode).o;
  32525. this[what](node.parentNode, index.pop()+ext);
  32526. },
  32527. _getIERange: function(){
  32528. var r = (this._body || this.endContainer.ownerDocument.body).createTextRange();
  32529. dijit.range.ie.setRange(r, this.startContainer, this.startOffset, this.endContainer, this.endOffset, this.collapsed);
  32530. return r;
  32531. },
  32532. getBookmark: function(){
  32533. this._getIERange();
  32534. return this._cachedBookmark;
  32535. },
  32536. _select: function(){
  32537. var r = this._getIERange();
  32538. r.select();
  32539. },
  32540. deleteContents: function(){
  32541. var s = this.startContainer, r = this._getIERange();
  32542. if(s.nodeType === 3 && !this.startOffset){
  32543. //if the range starts at the beginning of a
  32544. //text node, move it to before the textnode
  32545. //to make sure the range is still valid
  32546. //after deleteContents() finishes
  32547. this.setStartBefore(s);
  32548. }
  32549. r.pasteHTML('');
  32550. this.endContainer = this.startContainer;
  32551. this.endOffset = this.startOffset;
  32552. this.collapsed = true;
  32553. },
  32554. cloneRange: function(){
  32555. var r = new dijit.range.W3CRange([this.startContainer,this.startOffset,
  32556. this.endContainer,this.endOffset]);
  32557. r._body = this._body;
  32558. return r;
  32559. },
  32560. detach: function(){
  32561. this._body = null;
  32562. this.commonAncestorContainer = null;
  32563. this.startContainer = null;
  32564. this.startOffset = 0;
  32565. this.endContainer = null;
  32566. this.endOffset = 0;
  32567. this.collapsed = true;
  32568. }
  32569. });
  32570. } //if(!dijit.range._w3c)
  32571. return dijit.range;
  32572. });
  32573. },
  32574. 'dojo/store/util/QueryResults':function(){
  32575. define("dojo/store/util/QueryResults", ["../../_base/array", "../../_base/lang", "../../_base/Deferred"
  32576. ], function(array, lang, Deferred) {
  32577. // module:
  32578. // dojo/store/util/QueryResults
  32579. // summary:
  32580. // The module defines a query results wrapper
  32581. var util = lang.getObject("dojo.store.util", true);
  32582. util.QueryResults = function(results){
  32583. // summary:
  32584. // A function that wraps the results of a store query with additional
  32585. // methods.
  32586. //
  32587. // description:
  32588. // QueryResults is a basic wrapper that allows for array-like iteration
  32589. // over any kind of returned data from a query. While the simplest store
  32590. // will return a plain array of data, other stores may return deferreds or
  32591. // promises; this wrapper makes sure that *all* results can be treated
  32592. // the same.
  32593. //
  32594. // Additional methods include `forEach`, `filter` and `map`.
  32595. //
  32596. // returns: Object
  32597. // An array-like object that can be used for iterating over.
  32598. //
  32599. // example:
  32600. // Query a store and iterate over the results.
  32601. //
  32602. // | store.query({ prime: true }).forEach(function(item){
  32603. // | // do something
  32604. // | });
  32605. if(!results){
  32606. return results;
  32607. }
  32608. // if it is a promise it may be frozen
  32609. if(results.then){
  32610. results = lang.delegate(results);
  32611. }
  32612. function addIterativeMethod(method){
  32613. if(!results[method]){
  32614. results[method] = function(){
  32615. var args = arguments;
  32616. return Deferred.when(results, function(results){
  32617. Array.prototype.unshift.call(args, results);
  32618. return util.QueryResults(array[method].apply(array, args));
  32619. });
  32620. };
  32621. }
  32622. }
  32623. addIterativeMethod("forEach");
  32624. addIterativeMethod("filter");
  32625. addIterativeMethod("map");
  32626. if(!results.total){
  32627. results.total = Deferred.when(results, function(results){
  32628. return results.length;
  32629. });
  32630. }
  32631. return results;
  32632. };
  32633. return util.QueryResults;
  32634. });
  32635. },
  32636. 'dijit/form/_ListBase':function(){
  32637. define("dijit/form/_ListBase", [
  32638. "dojo/_base/declare", // declare
  32639. "dojo/window" // winUtils.scrollIntoView
  32640. ], function(declare, winUtils){
  32641. // module:
  32642. // dijit/form/_ListBase
  32643. // summary:
  32644. // Focus-less menu to handle UI events consistently
  32645. return declare( "dijit.form._ListBase", null, {
  32646. // summary:
  32647. // Focus-less menu to handle UI events consistently
  32648. // Abstract methods that must be defined externally:
  32649. // onSelect: item is active (mousedown but not yet mouseup, or keyboard arrow selected but no Enter)
  32650. // onDeselect: cancels onSelect
  32651. // tags:
  32652. // private
  32653. // selected: DOMnode
  32654. // currently selected node
  32655. selected: null,
  32656. _getTarget: function(/*Event*/ evt){
  32657. var tgt = evt.target;
  32658. var container = this.containerNode;
  32659. if(tgt == container || tgt == this.domNode){ return null; }
  32660. while(tgt && tgt.parentNode != container){
  32661. // recurse to the top
  32662. tgt = tgt.parentNode;
  32663. }
  32664. return tgt;
  32665. },
  32666. selectFirstNode: function(){
  32667. // summary:
  32668. // Select the first displayed item in the list.
  32669. var first = this.containerNode.firstChild;
  32670. while(first && first.style.display == "none"){
  32671. first = first.nextSibling;
  32672. }
  32673. this._setSelectedAttr(first);
  32674. },
  32675. selectLastNode: function(){
  32676. // summary:
  32677. // Select the last displayed item in the list
  32678. var last = this.containerNode.lastChild;
  32679. while(last && last.style.display == "none"){
  32680. last = last.previousSibling;
  32681. }
  32682. this._setSelectedAttr(last);
  32683. },
  32684. selectNextNode: function(){
  32685. // summary:
  32686. // Select the item just below the current selection.
  32687. // If nothing selected, select first node.
  32688. var selectedNode = this._getSelectedAttr();
  32689. if(!selectedNode){
  32690. this.selectFirstNode();
  32691. }else{
  32692. var next = selectedNode.nextSibling;
  32693. while(next && next.style.display == "none"){
  32694. next = next.nextSibling;
  32695. }
  32696. if(!next){
  32697. this.selectFirstNode();
  32698. }else{
  32699. this._setSelectedAttr(next);
  32700. }
  32701. }
  32702. },
  32703. selectPreviousNode: function(){
  32704. // summary:
  32705. // Select the item just above the current selection.
  32706. // If nothing selected, select last node (if
  32707. // you select Previous and try to keep scrolling up the list).
  32708. var selectedNode = this._getSelectedAttr();
  32709. if(!selectedNode){
  32710. this.selectLastNode();
  32711. }else{
  32712. var prev = selectedNode.previousSibling;
  32713. while(prev && prev.style.display == "none"){
  32714. prev = prev.previousSibling;
  32715. }
  32716. if(!prev){
  32717. this.selectLastNode();
  32718. }else{
  32719. this._setSelectedAttr(prev);
  32720. }
  32721. }
  32722. },
  32723. _setSelectedAttr: function(/*DomNode*/ node){
  32724. // summary:
  32725. // Does the actual select.
  32726. if(this.selected != node){
  32727. var selectedNode = this._getSelectedAttr();
  32728. if(selectedNode){
  32729. this.onDeselect(selectedNode);
  32730. this.selected = null;
  32731. }
  32732. if(node && node.parentNode == this.containerNode){
  32733. this.selected = node;
  32734. winUtils.scrollIntoView(node);
  32735. this.onSelect(node);
  32736. }
  32737. }else if(node){
  32738. this.onSelect(node);
  32739. }
  32740. },
  32741. _getSelectedAttr: function(){
  32742. // summary:
  32743. // Returns the selected node.
  32744. var v = this.selected;
  32745. return (v && v.parentNode == this.containerNode) ? v : (this.selected = null);
  32746. }
  32747. });
  32748. });
  32749. },
  32750. 'dijit/form/_FormWidget':function(){
  32751. define("dijit/form/_FormWidget", [
  32752. "dojo/_base/declare", // declare
  32753. "dojo/_base/kernel", // kernel.deprecated
  32754. "dojo/ready",
  32755. "../_Widget",
  32756. "../_CssStateMixin",
  32757. "../_TemplatedMixin",
  32758. "./_FormWidgetMixin"
  32759. ], function(declare, kernel, ready, _Widget, _CssStateMixin, _TemplatedMixin, _FormWidgetMixin){
  32760. /*=====
  32761. var _Widget = dijit._Widget;
  32762. var _TemplatedMixin = dijit._TemplatedMixin;
  32763. var _CssStateMixin = dijit._CssStateMixin;
  32764. var _FormWidgetMixin = dijit.form._FormWidgetMixin;
  32765. =====*/
  32766. // module:
  32767. // dijit/form/_FormWidget
  32768. // summary:
  32769. // FormWidget
  32770. // Back compat w/1.6, remove for 2.0
  32771. if(!kernel.isAsync){
  32772. ready(0, function(){
  32773. var requires = ["dijit/form/_FormValueWidget"];
  32774. require(requires); // use indirection so modules not rolled into a build
  32775. });
  32776. }
  32777. return declare("dijit.form._FormWidget", [_Widget, _TemplatedMixin, _CssStateMixin, _FormWidgetMixin], {
  32778. // summary:
  32779. // Base class for widgets corresponding to native HTML elements such as <checkbox> or <button>,
  32780. // which can be children of a <form> node or a `dijit.form.Form` widget.
  32781. //
  32782. // description:
  32783. // Represents a single HTML element.
  32784. // All these widgets should have these attributes just like native HTML input elements.
  32785. // You can set them during widget construction or afterwards, via `dijit._Widget.attr`.
  32786. //
  32787. // They also share some common methods.
  32788. setDisabled: function(/*Boolean*/ disabled){
  32789. // summary:
  32790. // Deprecated. Use set('disabled', ...) instead.
  32791. kernel.deprecated("setDisabled("+disabled+") is deprecated. Use set('disabled',"+disabled+") instead.", "", "2.0");
  32792. this.set('disabled', disabled);
  32793. },
  32794. setValue: function(/*String*/ value){
  32795. // summary:
  32796. // Deprecated. Use set('value', ...) instead.
  32797. kernel.deprecated("dijit.form._FormWidget:setValue("+value+") is deprecated. Use set('value',"+value+") instead.", "", "2.0");
  32798. this.set('value', value);
  32799. },
  32800. getValue: function(){
  32801. // summary:
  32802. // Deprecated. Use get('value') instead.
  32803. kernel.deprecated(this.declaredClass+"::getValue() is deprecated. Use get('value') instead.", "", "2.0");
  32804. return this.get('value');
  32805. },
  32806. postMixInProperties: function(){
  32807. // Setup name=foo string to be referenced from the template (but only if a name has been specified)
  32808. // Unfortunately we can't use _setNameAttr to set the name due to IE limitations, see #8484, #8660.
  32809. // Regarding escaping, see heading "Attribute values" in
  32810. // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
  32811. this.nameAttrSetting = this.name ? ('name="' + this.name.replace(/'/g, "&quot;") + '"') : '';
  32812. this.inherited(arguments);
  32813. },
  32814. // Override automatic assigning type --> focusNode, it causes exception on IE.
  32815. // Instead, type must be specified as ${type} in the template, as part of the original DOM
  32816. _setTypeAttr: null
  32817. });
  32818. });
  32819. },
  32820. 'dojo/dnd/common':function(){
  32821. define("dojo/dnd/common", ["../main"], function(dojo) {
  32822. // module:
  32823. // dojo/dnd/common
  32824. // summary:
  32825. // TODOC
  32826. dojo.getObject("dnd", true, dojo);
  32827. dojo.dnd.getCopyKeyState = dojo.isCopyKey;
  32828. dojo.dnd._uniqueId = 0;
  32829. dojo.dnd.getUniqueId = function(){
  32830. // summary:
  32831. // returns a unique string for use with any DOM element
  32832. var id;
  32833. do{
  32834. id = dojo._scopeName + "Unique" + (++dojo.dnd._uniqueId);
  32835. }while(dojo.byId(id));
  32836. return id;
  32837. };
  32838. dojo.dnd._empty = {};
  32839. dojo.dnd.isFormElement = function(/*Event*/ e){
  32840. // summary:
  32841. // returns true if user clicked on a form element
  32842. var t = e.target;
  32843. if(t.nodeType == 3 /*TEXT_NODE*/){
  32844. t = t.parentNode;
  32845. }
  32846. return " button textarea input select option ".indexOf(" " + t.tagName.toLowerCase() + " ") >= 0; // Boolean
  32847. };
  32848. return dojo.dnd;
  32849. });
  32850. },
  32851. 'dijit/CalendarLite':function(){
  32852. require({cache:{
  32853. 'url:dijit/templates/Calendar.html':"<table cellspacing=\"0\" cellpadding=\"0\" class=\"dijitCalendarContainer\" role=\"grid\" aria-labelledby=\"${id}_mddb ${id}_year\">\r\n\t<thead>\r\n\t\t<tr class=\"dijitReset dijitCalendarMonthContainer\" valign=\"top\">\r\n\t\t\t<th class='dijitReset dijitCalendarArrow' data-dojo-attach-point=\"decrementMonth\">\r\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarDecrease\" role=\"presentation\"/>\r\n\t\t\t\t<span data-dojo-attach-point=\"decreaseArrowNode\" class=\"dijitA11ySideArrow\">-</span>\r\n\t\t\t</th>\r\n\t\t\t<th class='dijitReset' colspan=\"5\">\r\n\t\t\t\t<div data-dojo-attach-point=\"monthNode\">\r\n\t\t\t\t</div>\r\n\t\t\t</th>\r\n\t\t\t<th class='dijitReset dijitCalendarArrow' data-dojo-attach-point=\"incrementMonth\">\r\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarIncrease\" role=\"presentation\"/>\r\n\t\t\t\t<span data-dojo-attach-point=\"increaseArrowNode\" class=\"dijitA11ySideArrow\">+</span>\r\n\t\t\t</th>\r\n\t\t</tr>\r\n\t\t<tr>\r\n\t\t\t${!dayCellsHtml}\r\n\t\t</tr>\r\n\t</thead>\r\n\t<tbody data-dojo-attach-point=\"dateRowsNode\" data-dojo-attach-event=\"onclick: _onDayClick\" class=\"dijitReset dijitCalendarBodyContainer\">\r\n\t\t\t${!dateRowsHtml}\r\n\t</tbody>\r\n\t<tfoot class=\"dijitReset dijitCalendarYearContainer\">\r\n\t\t<tr>\r\n\t\t\t<td class='dijitReset' valign=\"top\" colspan=\"7\" role=\"presentation\">\r\n\t\t\t\t<div class=\"dijitCalendarYearLabel\">\r\n\t\t\t\t\t<span data-dojo-attach-point=\"previousYearLabelNode\" class=\"dijitInline dijitCalendarPreviousYear\" role=\"button\"></span>\r\n\t\t\t\t\t<span data-dojo-attach-point=\"currentYearLabelNode\" class=\"dijitInline dijitCalendarSelectedYear\" role=\"button\" id=\"${id}_year\"></span>\r\n\t\t\t\t\t<span data-dojo-attach-point=\"nextYearLabelNode\" class=\"dijitInline dijitCalendarNextYear\" role=\"button\"></span>\r\n\t\t\t\t</div>\r\n\t\t\t</td>\r\n\t\t</tr>\r\n\t</tfoot>\r\n</table>\r\n"}});
  32854. define("dijit/CalendarLite", [
  32855. "dojo/_base/array", // array.forEach array.map
  32856. "dojo/_base/declare", // declare
  32857. "dojo/cldr/supplemental", // cldrSupplemental.getFirstDayOfWeek
  32858. "dojo/date", // date
  32859. "dojo/date/locale",
  32860. "dojo/dom", // dom.setSelectable
  32861. "dojo/dom-class", // domClass.contains
  32862. "dojo/_base/event", // event.stop
  32863. "dojo/_base/lang", // lang.getObject, lang.hitch
  32864. "dojo/_base/sniff", // has("ie") has("webkit")
  32865. "dojo/string", // string.substitute
  32866. "dojo/_base/window", // win.doc.createTextNode
  32867. "./_WidgetBase",
  32868. "./_TemplatedMixin",
  32869. "dojo/text!./templates/Calendar.html"
  32870. ], function(array, declare, cldrSupplemental, date, local, dom, domClass, event, lang, has, string, win,
  32871. _WidgetBase, _TemplatedMixin, template){
  32872. /*=====
  32873. var _WidgetBase = dijit._WidgetBase;
  32874. var _TemplatedMixin = dijit._TemplatedMixin;
  32875. =====*/
  32876. // module:
  32877. // dijit/CalendarLite
  32878. // summary:
  32879. // Lightweight version of Calendar widget aimed towards mobile use
  32880. var CalendarLite = declare("dijit.CalendarLite", [_WidgetBase, _TemplatedMixin], {
  32881. // summary:
  32882. // Lightweight version of Calendar widget aimed towards mobile use
  32883. //
  32884. // description:
  32885. // A simple GUI for choosing a date in the context of a monthly calendar.
  32886. // This widget can't be used in a form because it doesn't serialize the date to an
  32887. // `<input>` field. For a form element, use dijit.form.DateTextBox instead.
  32888. //
  32889. // Note that the parser takes all dates attributes passed in the
  32890. // [RFC 3339 format](http://www.faqs.org/rfcs/rfc3339.html), e.g. `2005-06-30T08:05:00-07:00`
  32891. // so that they are serializable and locale-independent.
  32892. //
  32893. // Also note that this widget isn't keyboard accessible; use dijit.Calendar for that
  32894. // example:
  32895. // | var calendar = new dijit.CalendarLite({}, dojo.byId("calendarNode"));
  32896. //
  32897. // example:
  32898. // | <div data-dojo-type="dijit.CalendarLite"></div>
  32899. // Template for main calendar
  32900. templateString: template,
  32901. // Template for cell for a day of the week (ex: M)
  32902. dowTemplateString: '<th class="dijitReset dijitCalendarDayLabelTemplate" role="columnheader"><span class="dijitCalendarDayLabel">${d}</span></th>',
  32903. // Templates for a single date (ex: 13), and for a row for a week (ex: 20 21 22 23 24 25 26)
  32904. dateTemplateString: '<td class="dijitReset" role="gridcell" data-dojo-attach-point="dateCells"><span class="dijitCalendarDateLabel" data-dojo-attach-point="dateLabels"></span></td>',
  32905. weekTemplateString: '<tr class="dijitReset dijitCalendarWeekTemplate" role="row">${d}${d}${d}${d}${d}${d}${d}</tr>',
  32906. // value: Date
  32907. // The currently selected Date, initially set to invalid date to indicate no selection.
  32908. value: new Date(""),
  32909. // TODO: for 2.0 make this a string (ISO format) rather than a Date
  32910. // datePackage: String
  32911. // JavaScript object containing Calendar functions. Uses Gregorian Calendar routines
  32912. // from dojo.date by default.
  32913. datePackage: date,
  32914. // dayWidth: String
  32915. // How to represent the days of the week in the calendar header. See locale
  32916. dayWidth: "narrow",
  32917. // tabIndex: Integer
  32918. // Order fields are traversed when user hits the tab key
  32919. tabIndex: "0",
  32920. // currentFocus: Date
  32921. // Date object containing the currently focused date, or the date which would be focused
  32922. // if the calendar itself was focused. Also indicates which year and month to display,
  32923. // i.e. the current "page" the calendar is on.
  32924. currentFocus: new Date(),
  32925. baseClass:"dijitCalendar",
  32926. _isValidDate: function(/*Date*/ value){
  32927. // summary:
  32928. // Runs various tests on the value, checking that it's a valid date, rather
  32929. // than blank or NaN.
  32930. // tags:
  32931. // private
  32932. return value && !isNaN(value) && typeof value == "object" &&
  32933. value.toString() != this.constructor.prototype.value.toString();
  32934. },
  32935. _getValueAttr: function(){
  32936. // summary:
  32937. // Support get('value')
  32938. // this.value is set to 1AM, but return midnight, local time for back-compat
  32939. if(this.value && !isNaN(this.value)){
  32940. var value = new this.dateClassObj(this.value);
  32941. value.setHours(0, 0, 0, 0);
  32942. // If daylight savings pushes midnight to the previous date, fix the Date
  32943. // object to point at 1am so it will represent the correct day. See #9366
  32944. if(value.getDate() < this.value.getDate()){
  32945. value = this.dateFuncObj.add(value, "hour", 1);
  32946. }
  32947. return value;
  32948. }else{
  32949. return null;
  32950. }
  32951. },
  32952. _setValueAttr: function(/*Date|Number*/ value, /*Boolean*/ priorityChange){
  32953. // summary:
  32954. // Support set("value", ...)
  32955. // description:
  32956. // Set the current date and update the UI. If the date is disabled, the value will
  32957. // not change, but the display will change to the corresponding month.
  32958. // value:
  32959. // Either a Date or the number of seconds since 1970.
  32960. // tags:
  32961. // protected
  32962. if(value){
  32963. // convert from Number to Date, or make copy of Date object so that setHours() call below
  32964. // doesn't affect original value
  32965. value = new this.dateClassObj(value);
  32966. }
  32967. if(this._isValidDate(value)){
  32968. if(!this._isValidDate(this.value) || this.dateFuncObj.compare(value, this.value)){
  32969. value.setHours(1, 0, 0, 0); // round to nearest day (1am to avoid issues when DST shift occurs at midnight, see #8521, #9366)
  32970. if(!this.isDisabledDate(value, this.lang)){
  32971. this._set("value", value);
  32972. // Set focus cell to the new value. Arguably this should only happen when there isn't a current
  32973. // focus point. This will also repopulate the grid, showing the new selected value (and possibly
  32974. // new month/year).
  32975. this.set("currentFocus", value);
  32976. if(priorityChange || typeof priorityChange == "undefined"){
  32977. this.onChange(this.get('value'));
  32978. }
  32979. }
  32980. }
  32981. }else{
  32982. // clear value, and repopulate grid (to deselect the previously selected day) without changing currentFocus
  32983. this._set("value", null);
  32984. this.set("currentFocus", this.currentFocus);
  32985. }
  32986. },
  32987. _setText: function(node, text){
  32988. // summary:
  32989. // This just sets the content of node to the specified text.
  32990. // Can't do "node.innerHTML=text" because of an IE bug w/tables, see #3434.
  32991. // tags:
  32992. // private
  32993. while(node.firstChild){
  32994. node.removeChild(node.firstChild);
  32995. }
  32996. node.appendChild(win.doc.createTextNode(text));
  32997. },
  32998. _populateGrid: function(){
  32999. // summary:
  33000. // Fills in the calendar grid with each day (1-31)
  33001. // tags:
  33002. // private
  33003. var month = new this.dateClassObj(this.currentFocus);
  33004. month.setDate(1);
  33005. var firstDay = month.getDay(),
  33006. daysInMonth = this.dateFuncObj.getDaysInMonth(month),
  33007. daysInPreviousMonth = this.dateFuncObj.getDaysInMonth(this.dateFuncObj.add(month, "month", -1)),
  33008. today = new this.dateClassObj(),
  33009. dayOffset = cldrSupplemental.getFirstDayOfWeek(this.lang);
  33010. if(dayOffset > firstDay){ dayOffset -= 7; }
  33011. // Mapping from date (as specified by number returned from Date.valueOf()) to corresponding <td>
  33012. this._date2cell = {};
  33013. // Iterate through dates in the calendar and fill in date numbers and style info
  33014. array.forEach(this.dateCells, function(template, idx){
  33015. var i = idx + dayOffset;
  33016. var date = new this.dateClassObj(month),
  33017. number, clazz = "dijitCalendar", adj = 0;
  33018. if(i < firstDay){
  33019. number = daysInPreviousMonth - firstDay + i + 1;
  33020. adj = -1;
  33021. clazz += "Previous";
  33022. }else if(i >= (firstDay + daysInMonth)){
  33023. number = i - firstDay - daysInMonth + 1;
  33024. adj = 1;
  33025. clazz += "Next";
  33026. }else{
  33027. number = i - firstDay + 1;
  33028. clazz += "Current";
  33029. }
  33030. if(adj){
  33031. date = this.dateFuncObj.add(date, "month", adj);
  33032. }
  33033. date.setDate(number);
  33034. if(!this.dateFuncObj.compare(date, today, "date")){
  33035. clazz = "dijitCalendarCurrentDate " + clazz;
  33036. }
  33037. if(this._isSelectedDate(date, this.lang)){
  33038. clazz = "dijitCalendarSelectedDate " + clazz;
  33039. template.setAttribute("aria-selected", true);
  33040. }else{
  33041. template.setAttribute("aria-selected", false);
  33042. }
  33043. if(this.isDisabledDate(date, this.lang)){
  33044. clazz = "dijitCalendarDisabledDate " + clazz;
  33045. template.setAttribute("aria-disabled", true);
  33046. }else{
  33047. clazz = "dijitCalendarEnabledDate " + clazz;
  33048. template.removeAttribute("aria-disabled");
  33049. }
  33050. var clazz2 = this.getClassForDate(date, this.lang);
  33051. if(clazz2){
  33052. clazz = clazz2 + " " + clazz;
  33053. }
  33054. template.className = clazz + "Month dijitCalendarDateTemplate";
  33055. // Each cell has an associated integer value representing it's date
  33056. var dateVal = date.valueOf();
  33057. this._date2cell[dateVal] = template;
  33058. template.dijitDateValue = dateVal;
  33059. // Set Date string (ex: "13").
  33060. this._setText(this.dateLabels[idx], date.getDateLocalized ? date.getDateLocalized(this.lang) : date.getDate());
  33061. }, this);
  33062. // set name of this month
  33063. this.monthWidget.set("month", month);
  33064. // Fill in localized prev/current/next years
  33065. var y = month.getFullYear() - 1;
  33066. var d = new this.dateClassObj();
  33067. array.forEach(["previous", "current", "next"], function(name){
  33068. d.setFullYear(y++);
  33069. this._setText(this[name+"YearLabelNode"],
  33070. this.dateLocaleModule.format(d, {selector:'year', locale:this.lang}));
  33071. }, this);
  33072. },
  33073. goToToday: function(){
  33074. // summary:
  33075. // Sets calendar's value to today's date
  33076. this.set('value', new this.dateClassObj());
  33077. },
  33078. constructor: function(/*Object*/args){
  33079. this.datePackage = args.datePackage || this.datePackage;
  33080. this.dateFuncObj = typeof this.datePackage == "string" ?
  33081. lang.getObject(this.datePackage, false) :// "string" part for back-compat, remove for 2.0
  33082. this.datePackage;
  33083. this.dateClassObj = this.dateFuncObj.Date || Date;
  33084. this.dateLocaleModule = lang.getObject("locale", false, this.dateFuncObj);
  33085. },
  33086. _createMonthWidget: function(){
  33087. // summary:
  33088. // Creates the drop down button that displays the current month and lets user pick a new one
  33089. return CalendarLite._MonthWidget({
  33090. id: this.id + "_mw",
  33091. lang: this.lang,
  33092. dateLocaleModule: this.dateLocaleModule
  33093. }, this.monthNode);
  33094. },
  33095. buildRendering: function(){
  33096. // Markup for days of the week (referenced from template)
  33097. var d = this.dowTemplateString,
  33098. dayNames = this.dateLocaleModule.getNames('days', this.dayWidth, 'standAlone', this.lang),
  33099. dayOffset = cldrSupplemental.getFirstDayOfWeek(this.lang);
  33100. this.dayCellsHtml = string.substitute([d,d,d,d,d,d,d].join(""), {d: ""}, function(){
  33101. return dayNames[dayOffset++ % 7]
  33102. });
  33103. // Markup for dates of the month (referenced from template), but without numbers filled in
  33104. var r = string.substitute(this.weekTemplateString, {d: this.dateTemplateString});
  33105. this.dateRowsHtml = [r,r,r,r,r,r].join("");
  33106. // Instantiate from template.
  33107. // dateCells and dateLabels arrays filled when _Templated parses my template.
  33108. this.dateCells = [];
  33109. this.dateLabels = [];
  33110. this.inherited(arguments);
  33111. dom.setSelectable(this.domNode, false);
  33112. var dateObj = new this.dateClassObj(this.currentFocus);
  33113. this._supportingWidgets.push(this.monthWidget = this._createMonthWidget());
  33114. this.set('currentFocus', dateObj, false); // draw the grid to the month specified by currentFocus
  33115. // Set up connects for increment/decrement of months/years
  33116. var connect = lang.hitch(this, function(nodeProp, part, amount){
  33117. this.connect(this[nodeProp], "onclick", function(){
  33118. this._setCurrentFocusAttr(this.dateFuncObj.add(this.currentFocus, part, amount));
  33119. });
  33120. });
  33121. connect("incrementMonth", "month", 1);
  33122. connect("decrementMonth", "month", -1);
  33123. connect("nextYearLabelNode", "year", 1);
  33124. connect("previousYearLabelNode", "year", -1);
  33125. },
  33126. _setCurrentFocusAttr: function(/*Date*/ date, /*Boolean*/ forceFocus){
  33127. // summary:
  33128. // If the calendar currently has focus, then focuses specified date,
  33129. // changing the currently displayed month/year if necessary.
  33130. // If the calendar doesn't have focus, updates currently
  33131. // displayed month/year, and sets the cell that will get focus.
  33132. // forceFocus:
  33133. // If true, will focus() the cell even if calendar itself doesn't have focus
  33134. var oldFocus = this.currentFocus,
  33135. oldCell = oldFocus && this._date2cell ? this._date2cell[oldFocus.valueOf()] : null;
  33136. // round specified value to nearest day (1am to avoid issues when DST shift occurs at midnight, see #8521, #9366)
  33137. date = new this.dateClassObj(date);
  33138. date.setHours(1, 0, 0, 0);
  33139. this._set("currentFocus", date);
  33140. // TODO: only re-populate grid when month/year has changed
  33141. this._populateGrid();
  33142. // set tabIndex=0 on new cell, and focus it (but only if Calendar itself is focused)
  33143. var newCell = this._date2cell[date.valueOf()];
  33144. newCell.setAttribute("tabIndex", this.tabIndex);
  33145. if(this.focused || forceFocus){
  33146. newCell.focus();
  33147. }
  33148. // set tabIndex=-1 on old focusable cell
  33149. if(oldCell && oldCell != newCell){
  33150. if(has("webkit")){ // see #11064 about webkit bug
  33151. oldCell.setAttribute("tabIndex", "-1");
  33152. }else{
  33153. oldCell.removeAttribute("tabIndex");
  33154. }
  33155. }
  33156. },
  33157. focus: function(){
  33158. // summary:
  33159. // Focus the calendar by focusing one of the calendar cells
  33160. this._setCurrentFocusAttr(this.currentFocus, true);
  33161. },
  33162. _onDayClick: function(/*Event*/ evt){
  33163. // summary:
  33164. // Handler for day clicks, selects the date if appropriate
  33165. // tags:
  33166. // protected
  33167. event.stop(evt);
  33168. for(var node = evt.target; node && !node.dijitDateValue; node = node.parentNode);
  33169. if(node && !domClass.contains(node, "dijitCalendarDisabledDate")){
  33170. this.set('value', node.dijitDateValue);
  33171. }
  33172. },
  33173. onChange: function(/*Date*/ /*===== date =====*/){
  33174. // summary:
  33175. // Called only when the selected date has changed
  33176. },
  33177. _isSelectedDate: function(dateObject /*===== , locale =====*/){
  33178. // summary:
  33179. // Extension point so developers can subclass Calendar to
  33180. // support multiple (concurrently) selected dates
  33181. // dateObject: Date
  33182. // locale: String?
  33183. // tags:
  33184. // protected extension
  33185. return this._isValidDate(this.value) && !this.dateFuncObj.compare(dateObject, this.value, "date")
  33186. },
  33187. isDisabledDate: function(/*===== dateObject, locale =====*/){
  33188. // summary:
  33189. // May be overridden to disable certain dates in the calendar e.g. `isDisabledDate=dojo.date.locale.isWeekend`
  33190. // dateObject: Date
  33191. // locale: String?
  33192. // tags:
  33193. // extension
  33194. /*=====
  33195. return false; // Boolean
  33196. =====*/
  33197. },
  33198. getClassForDate: function(/*===== dateObject, locale =====*/){
  33199. // summary:
  33200. // May be overridden to return CSS classes to associate with the date entry for the given dateObject,
  33201. // for example to indicate a holiday in specified locale.
  33202. // dateObject: Date
  33203. // locale: String?
  33204. // tags:
  33205. // extension
  33206. /*=====
  33207. return ""; // String
  33208. =====*/
  33209. }
  33210. });
  33211. CalendarLite._MonthWidget = declare("dijit.CalendarLite._MonthWidget", _WidgetBase, {
  33212. // summary:
  33213. // Displays name of current month padded to the width of the month
  33214. // w/the longest name, so that changing months doesn't change width.
  33215. //
  33216. // Create as new dijit.Calendar._MonthWidget({
  33217. // lang: ...,
  33218. // dateLocaleModule: ...
  33219. // })
  33220. _setMonthAttr: function(month){
  33221. // summary:
  33222. // Set the current month to display as a label
  33223. var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, month),
  33224. spacer =
  33225. (has("ie") == 6 ? "" : "<div class='dijitSpacer'>" +
  33226. array.map(monthNames, function(s){ return "<div>" + s + "</div>"; }).join("") + "</div>");
  33227. // Set name of current month and also fill in spacer element with all the month names
  33228. // (invisible) so that the maximum width will affect layout. But not on IE6 because then
  33229. // the center <TH> overlaps the right <TH> (due to a browser bug).
  33230. this.domNode.innerHTML =
  33231. spacer +
  33232. "<div class='dijitCalendarMonthLabel dijitCalendarCurrentMonthLabel'>" +
  33233. monthNames[month.getMonth()] + "</div>";
  33234. }
  33235. });
  33236. return CalendarLite;
  33237. });
  33238. },
  33239. 'dojox/grid/_Events':function(){
  33240. define("dojox/grid/_Events", [
  33241. "dojo/keys",
  33242. "dojo/dom-class",
  33243. "dojo/_base/declare",
  33244. "dojo/_base/event",
  33245. "dojo/_base/sniff"
  33246. ], function(keys, domClass, declare, event, has){
  33247. return declare("dojox.grid._Events", null, {
  33248. // summary:
  33249. // _Grid mixin that provides default implementations for grid events.
  33250. // description:
  33251. // Default synthetic events dispatched for _Grid. dojo.connect to events to
  33252. // retain default implementation or override them for custom handling.
  33253. // cellOverClass: String
  33254. // css class to apply to grid cells over which the cursor is placed.
  33255. cellOverClass: "dojoxGridCellOver",
  33256. onKeyEvent: function(e){
  33257. // summary: top level handler for Key Events
  33258. this.dispatchKeyEvent(e);
  33259. },
  33260. onContentEvent: function(e){
  33261. // summary: Top level handler for Content events
  33262. this.dispatchContentEvent(e);
  33263. },
  33264. onHeaderEvent: function(e){
  33265. // summary: Top level handler for header events
  33266. this.dispatchHeaderEvent(e);
  33267. },
  33268. onStyleRow: function(inRow){
  33269. // summary:
  33270. // Perform row styling on a given row. Called whenever row styling is updated.
  33271. //
  33272. // inRow: Object
  33273. // Object containing row state information: selected, true if the row is selcted; over:
  33274. // true of the mouse is over the row; odd: true if the row is odd. Use customClasses and
  33275. // customStyles to control row css classes and styles; both properties are strings.
  33276. //
  33277. // example: onStyleRow({ selected: true, over:true, odd:false })
  33278. var i = inRow;
  33279. i.customClasses += (i.odd?" dojoxGridRowOdd":"") + (i.selected?" dojoxGridRowSelected":"") + (i.over?" dojoxGridRowOver":"");
  33280. this.focus.styleRow(inRow);
  33281. this.edit.styleRow(inRow);
  33282. },
  33283. onKeyDown: function(e){
  33284. // summary:
  33285. // Grid key event handler. By default enter begins editing and applies edits, escape cancels an edit,
  33286. // tab, shift-tab, and arrow keys move grid cell focus.
  33287. if(e.altKey || e.metaKey){
  33288. return;
  33289. }
  33290. var colIdx;
  33291. switch(e.keyCode){
  33292. case keys.ESCAPE:
  33293. this.edit.cancel();
  33294. break;
  33295. case keys.ENTER:
  33296. if(!this.edit.isEditing()){
  33297. colIdx = this.focus.getHeaderIndex();
  33298. if(colIdx >= 0) {
  33299. this.setSortIndex(colIdx);
  33300. break;
  33301. }else {
  33302. this.selection.clickSelect(this.focus.rowIndex, dojo.isCopyKey(e), e.shiftKey);
  33303. }
  33304. event.stop(e);
  33305. }
  33306. if(!e.shiftKey){
  33307. var isEditing = this.edit.isEditing();
  33308. this.edit.apply();
  33309. if(!isEditing){
  33310. this.edit.setEditCell(this.focus.cell, this.focus.rowIndex);
  33311. }
  33312. }
  33313. if (!this.edit.isEditing()){
  33314. var curView = this.focus.focusView || this.views.views[0]; //if no focusView than only one view
  33315. curView.content.decorateEvent(e);
  33316. this.onRowClick(e);
  33317. event.stop(e);
  33318. }
  33319. break;
  33320. case keys.SPACE:
  33321. if(!this.edit.isEditing()){
  33322. colIdx = this.focus.getHeaderIndex();
  33323. if(colIdx >= 0) {
  33324. this.setSortIndex(colIdx);
  33325. break;
  33326. }else {
  33327. this.selection.clickSelect(this.focus.rowIndex, dojo.isCopyKey(e), e.shiftKey);
  33328. }
  33329. event.stop(e);
  33330. }
  33331. break;
  33332. case keys.TAB:
  33333. this.focus[e.shiftKey ? 'previousKey' : 'nextKey'](e);
  33334. break;
  33335. case keys.LEFT_ARROW:
  33336. case keys.RIGHT_ARROW:
  33337. if(!this.edit.isEditing()){
  33338. var keyCode = e.keyCode; // IE seems to lose after stopEvent when modifier keys
  33339. event.stop(e);
  33340. colIdx = this.focus.getHeaderIndex();
  33341. if (colIdx >= 0 && (e.shiftKey && e.ctrlKey)){
  33342. this.focus.colSizeAdjust(e, colIdx, (keyCode == keys.LEFT_ARROW ? -1 : 1)*5);
  33343. }
  33344. else{
  33345. var offset = (keyCode == keys.LEFT_ARROW) ? 1 : -1;
  33346. if(this.isLeftToRight()){ offset *= -1; }
  33347. this.focus.move(0, offset);
  33348. }
  33349. }
  33350. break;
  33351. case keys.UP_ARROW:
  33352. if(!this.edit.isEditing() && this.focus.rowIndex !== 0){
  33353. event.stop(e);
  33354. this.focus.move(-1, 0);
  33355. }
  33356. break;
  33357. case keys.DOWN_ARROW:
  33358. if(!this.edit.isEditing() && this.focus.rowIndex+1 != this.rowCount){
  33359. event.stop(e);
  33360. this.focus.move(1, 0);
  33361. }
  33362. break;
  33363. case keys.PAGE_UP:
  33364. if(!this.edit.isEditing() && this.focus.rowIndex !== 0){
  33365. event.stop(e);
  33366. if(this.focus.rowIndex != this.scroller.firstVisibleRow+1){
  33367. this.focus.move(this.scroller.firstVisibleRow-this.focus.rowIndex, 0);
  33368. }else{
  33369. this.setScrollTop(this.scroller.findScrollTop(this.focus.rowIndex-1));
  33370. this.focus.move(this.scroller.firstVisibleRow-this.scroller.lastVisibleRow+1, 0);
  33371. }
  33372. }
  33373. break;
  33374. case keys.PAGE_DOWN:
  33375. if(!this.edit.isEditing() && this.focus.rowIndex+1 != this.rowCount){
  33376. event.stop(e);
  33377. if(this.focus.rowIndex != this.scroller.lastVisibleRow-1){
  33378. this.focus.move(this.scroller.lastVisibleRow-this.focus.rowIndex-1, 0);
  33379. }else{
  33380. this.setScrollTop(this.scroller.findScrollTop(this.focus.rowIndex+1));
  33381. this.focus.move(this.scroller.lastVisibleRow-this.scroller.firstVisibleRow-1, 0);
  33382. }
  33383. }
  33384. break;
  33385. default:
  33386. break;
  33387. }
  33388. },
  33389. onMouseOver: function(e){
  33390. // summary:
  33391. // Event fired when mouse is over the grid.
  33392. // e: Event
  33393. // Decorated event object contains reference to grid, cell, and rowIndex
  33394. e.rowIndex == -1 ? this.onHeaderCellMouseOver(e) : this.onCellMouseOver(e);
  33395. },
  33396. onMouseOut: function(e){
  33397. // summary:
  33398. // Event fired when mouse moves out of the grid.
  33399. // e: Event
  33400. // Decorated event object that contains reference to grid, cell, and rowIndex
  33401. e.rowIndex == -1 ? this.onHeaderCellMouseOut(e) : this.onCellMouseOut(e);
  33402. },
  33403. onMouseDown: function(e){
  33404. // summary:
  33405. // Event fired when mouse is down inside grid.
  33406. // e: Event
  33407. // Decorated event object that contains reference to grid, cell, and rowIndex
  33408. e.rowIndex == -1 ? this.onHeaderCellMouseDown(e) : this.onCellMouseDown(e);
  33409. },
  33410. onMouseOverRow: function(e){
  33411. // summary:
  33412. // Event fired when mouse is over any row (data or header).
  33413. // e: Event
  33414. // Decorated event object contains reference to grid, cell, and rowIndex
  33415. if(!this.rows.isOver(e.rowIndex)){
  33416. this.rows.setOverRow(e.rowIndex);
  33417. e.rowIndex == -1 ? this.onHeaderMouseOver(e) : this.onRowMouseOver(e);
  33418. }
  33419. },
  33420. onMouseOutRow: function(e){
  33421. // summary:
  33422. // Event fired when mouse moves out of any row (data or header).
  33423. // e: Event
  33424. // Decorated event object contains reference to grid, cell, and rowIndex
  33425. if(this.rows.isOver(-1)){
  33426. this.onHeaderMouseOut(e);
  33427. }else if(!this.rows.isOver(-2)){
  33428. this.rows.setOverRow(-2);
  33429. this.onRowMouseOut(e);
  33430. }
  33431. },
  33432. onMouseDownRow: function(e){
  33433. // summary:
  33434. // Event fired when mouse is down inside grid row
  33435. // e: Event
  33436. // Decorated event object that contains reference to grid, cell, and rowIndex
  33437. if(e.rowIndex != -1)
  33438. this.onRowMouseDown(e);
  33439. },
  33440. // cell events
  33441. onCellMouseOver: function(e){
  33442. // summary:
  33443. // Event fired when mouse is over a cell.
  33444. // e: Event
  33445. // Decorated event object contains reference to grid, cell, and rowIndex
  33446. if(e.cellNode){
  33447. domClass.add(e.cellNode, this.cellOverClass);
  33448. }
  33449. },
  33450. onCellMouseOut: function(e){
  33451. // summary:
  33452. // Event fired when mouse moves out of a cell.
  33453. // e: Event
  33454. // Decorated event object which contains reference to grid, cell, and rowIndex
  33455. if(e.cellNode){
  33456. domClass.remove(e.cellNode, this.cellOverClass);
  33457. }
  33458. },
  33459. onCellMouseDown: function(e){
  33460. // summary:
  33461. // Event fired when mouse is down in a header cell.
  33462. // e: Event
  33463. // Decorated event object which contains reference to grid, cell, and rowIndex
  33464. },
  33465. onCellClick: function(e){
  33466. // summary:
  33467. // Event fired when a cell is clicked.
  33468. // e: Event
  33469. // Decorated event object which contains reference to grid, cell, and rowIndex
  33470. this._click[0] = this._click[1];
  33471. this._click[1] = e;
  33472. if(!this.edit.isEditCell(e.rowIndex, e.cellIndex)){
  33473. this.focus.setFocusCell(e.cell, e.rowIndex);
  33474. }
  33475. // in some cases click[0] is null which causes false doubeClicks. Fixes #100703
  33476. if(this._click.length > 1 && this._click[0] == null){
  33477. this._click.shift();
  33478. }
  33479. this.onRowClick(e);
  33480. },
  33481. onCellDblClick: function(e){
  33482. // summary:
  33483. // Event fired when a cell is double-clicked.
  33484. // e: Event
  33485. // Decorated event object contains reference to grid, cell, and rowIndex
  33486. var event;
  33487. if(this._click.length > 1 && has("ie")){
  33488. event = this._click[1];
  33489. }else if(this._click.length > 1 && this._click[0].rowIndex != this._click[1].rowIndex){
  33490. event = this._click[0];
  33491. }else{
  33492. event = e;
  33493. }
  33494. this.focus.setFocusCell(event.cell, event.rowIndex);
  33495. this.onRowClick(event);
  33496. this.edit.setEditCell(event.cell, event.rowIndex);
  33497. this.onRowDblClick(e);
  33498. },
  33499. onCellContextMenu: function(e){
  33500. // summary:
  33501. // Event fired when a cell context menu is accessed via mouse right click.
  33502. // e: Event
  33503. // Decorated event object which contains reference to grid, cell, and rowIndex
  33504. this.onRowContextMenu(e);
  33505. },
  33506. onCellFocus: function(inCell, inRowIndex){
  33507. // summary:
  33508. // Event fired when a cell receives focus.
  33509. // inCell: Object
  33510. // Cell object containing properties of the grid column.
  33511. // inRowIndex: Integer
  33512. // Index of the grid row
  33513. this.edit.cellFocus(inCell, inRowIndex);
  33514. },
  33515. // row events
  33516. onRowClick: function(e){
  33517. // summary:
  33518. // Event fired when a row is clicked.
  33519. // e: Event
  33520. // Decorated event object which contains reference to grid, cell, and rowIndex
  33521. this.edit.rowClick(e);
  33522. this.selection.clickSelectEvent(e);
  33523. },
  33524. onRowDblClick: function(e){
  33525. // summary:
  33526. // Event fired when a row is double clicked.
  33527. // e: Event
  33528. // decorated event object which contains reference to grid, cell, and rowIndex
  33529. },
  33530. onRowMouseOver: function(e){
  33531. // summary:
  33532. // Event fired when mouse moves over a data row.
  33533. // e: Event
  33534. // Decorated event object which contains reference to grid, cell, and rowIndex
  33535. },
  33536. onRowMouseOut: function(e){
  33537. // summary:
  33538. // Event fired when mouse moves out of a data row.
  33539. // e: Event
  33540. // Decorated event object contains reference to grid, cell, and rowIndex
  33541. },
  33542. onRowMouseDown: function(e){
  33543. // summary:
  33544. // Event fired when mouse is down in a row.
  33545. // e: Event
  33546. // Decorated event object which contains reference to grid, cell, and rowIndex
  33547. },
  33548. onRowContextMenu: function(e){
  33549. // summary:
  33550. // Event fired when a row context menu is accessed via mouse right click.
  33551. // e: Event
  33552. // Decorated event object which contains reference to grid, cell, and rowIndex
  33553. event.stop(e);
  33554. },
  33555. // header events
  33556. onHeaderMouseOver: function(e){
  33557. // summary:
  33558. // Event fired when mouse moves over the grid header.
  33559. // e: Event
  33560. // Decorated event object contains reference to grid, cell, and rowIndex
  33561. },
  33562. onHeaderMouseOut: function(e){
  33563. // summary:
  33564. // Event fired when mouse moves out of the grid header.
  33565. // e: Event
  33566. // Decorated event object which contains reference to grid, cell, and rowIndex
  33567. },
  33568. onHeaderCellMouseOver: function(e){
  33569. // summary:
  33570. // Event fired when mouse moves over a header cell.
  33571. // e: Event
  33572. // Decorated event object which contains reference to grid, cell, and rowIndex
  33573. if(e.cellNode){
  33574. domClass.add(e.cellNode, this.cellOverClass);
  33575. }
  33576. },
  33577. onHeaderCellMouseOut: function(e){
  33578. // summary:
  33579. // Event fired when mouse moves out of a header cell.
  33580. // e: Event
  33581. // Decorated event object which contains reference to grid, cell, and rowIndex
  33582. if(e.cellNode){
  33583. domClass.remove(e.cellNode, this.cellOverClass);
  33584. }
  33585. },
  33586. onHeaderCellMouseDown: function(e) {
  33587. // summary:
  33588. // Event fired when mouse is down in a header cell.
  33589. // e: Event
  33590. // Decorated event object which contains reference to grid, cell, and rowIndex
  33591. },
  33592. onHeaderClick: function(e){
  33593. // summary:
  33594. // Event fired when the grid header is clicked.
  33595. // e: Event
  33596. // Decorated event object which contains reference to grid, cell, and rowIndex
  33597. },
  33598. onHeaderCellClick: function(e){
  33599. // summary:
  33600. // Event fired when a header cell is clicked.
  33601. // e: Event
  33602. // Decorated event object which contains reference to grid, cell, and rowIndex
  33603. this.setSortIndex(e.cell.index);
  33604. this.onHeaderClick(e);
  33605. },
  33606. onHeaderDblClick: function(e){
  33607. // summary:
  33608. // Event fired when the grid header is double clicked.
  33609. // e: Event
  33610. // Decorated event object which contains reference to grid, cell, and rowIndex
  33611. },
  33612. onHeaderCellDblClick: function(e){
  33613. // summary:
  33614. // Event fired when a header cell is double clicked.
  33615. // e: Event
  33616. // Decorated event object which contains reference to grid, cell, and rowIndex
  33617. this.onHeaderDblClick(e);
  33618. },
  33619. onHeaderCellContextMenu: function(e){
  33620. // summary:
  33621. // Event fired when a header cell context menu is accessed via mouse right click.
  33622. // e: Event
  33623. // Decorated event object which contains reference to grid, cell, and rowIndex
  33624. this.onHeaderContextMenu(e);
  33625. },
  33626. onHeaderContextMenu: function(e){
  33627. // summary:
  33628. // Event fired when the grid header context menu is accessed via mouse right click.
  33629. // e: Event
  33630. // Decorated event object which contains reference to grid, cell, and rowIndex
  33631. if(!this.headerMenu){
  33632. event.stop(e);
  33633. }
  33634. },
  33635. // editing
  33636. onStartEdit: function(inCell, inRowIndex){
  33637. // summary:
  33638. // Event fired when editing is started for a given grid cell
  33639. // inCell: Object
  33640. // Cell object containing properties of the grid column.
  33641. // inRowIndex: Integer
  33642. // Index of the grid row
  33643. },
  33644. onApplyCellEdit: function(inValue, inRowIndex, inFieldIndex){
  33645. // summary:
  33646. // Event fired when editing is applied for a given grid cell
  33647. // inValue: String
  33648. // Value from cell editor
  33649. // inRowIndex: Integer
  33650. // Index of the grid row
  33651. // inFieldIndex: Integer
  33652. // Index in the grid's data store
  33653. },
  33654. onCancelEdit: function(inRowIndex){
  33655. // summary:
  33656. // Event fired when editing is cancelled for a given grid cell
  33657. // inRowIndex: Integer
  33658. // Index of the grid row
  33659. },
  33660. onApplyEdit: function(inRowIndex){
  33661. // summary:
  33662. // Event fired when editing is applied for a given grid row
  33663. // inRowIndex: Integer
  33664. // Index of the grid row
  33665. },
  33666. onCanSelect: function(inRowIndex){
  33667. // summary:
  33668. // Event to determine if a grid row may be selected
  33669. // inRowIndex: Integer
  33670. // Index of the grid row
  33671. // returns: Boolean
  33672. // true if the row can be selected
  33673. return true;
  33674. },
  33675. onCanDeselect: function(inRowIndex){
  33676. // summary:
  33677. // Event to determine if a grid row may be deselected
  33678. // inRowIndex: Integer
  33679. // Index of the grid row
  33680. // returns: Boolean
  33681. // true if the row can be deselected
  33682. return true;
  33683. },
  33684. onSelected: function(inRowIndex){
  33685. // summary:
  33686. // Event fired when a grid row is selected
  33687. // inRowIndex: Integer
  33688. // Index of the grid row
  33689. this.updateRowStyles(inRowIndex);
  33690. },
  33691. onDeselected: function(inRowIndex){
  33692. // summary:
  33693. // Event fired when a grid row is deselected
  33694. // inRowIndex: Integer
  33695. // Index of the grid row
  33696. this.updateRowStyles(inRowIndex);
  33697. },
  33698. onSelectionChanged: function(){
  33699. }
  33700. });
  33701. });
  33702. },
  33703. 'dijit/CheckedMenuItem':function(){
  33704. require({cache:{
  33705. 'url:dijit/templates/CheckedMenuItem.html':"<tr class=\"dijitReset dijitMenuItem\" data-dojo-attach-point=\"focusNode\" role=\"menuitemcheckbox\" tabIndex=\"-1\"\r\n\t\tdata-dojo-attach-event=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\r\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\r\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuItemIcon dijitCheckedMenuItemIcon\" data-dojo-attach-point=\"iconNode\"/>\r\n\t\t<span class=\"dijitCheckedMenuItemIconChar\">&#10003;</span>\r\n\t</td>\r\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" data-dojo-attach-point=\"containerNode,labelNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" data-dojo-attach-point=\"accelKeyNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">&#160;</td>\r\n</tr>\r\n"}});
  33706. define("dijit/CheckedMenuItem", [
  33707. "dojo/_base/declare", // declare
  33708. "dojo/dom-class", // domClass.toggle
  33709. "./MenuItem",
  33710. "dojo/text!./templates/CheckedMenuItem.html",
  33711. "./hccss"
  33712. ], function(declare, domClass, MenuItem, template){
  33713. /*=====
  33714. var MenuItem = dijit.MenuItem;
  33715. =====*/
  33716. // module:
  33717. // dijit/CheckedMenuItem
  33718. // summary:
  33719. // A checkbox-like menu item for toggling on and off
  33720. return declare("dijit.CheckedMenuItem", MenuItem, {
  33721. // summary:
  33722. // A checkbox-like menu item for toggling on and off
  33723. templateString: template,
  33724. // checked: Boolean
  33725. // Our checked state
  33726. checked: false,
  33727. _setCheckedAttr: function(/*Boolean*/ checked){
  33728. // summary:
  33729. // Hook so attr('checked', bool) works.
  33730. // Sets the class and state for the check box.
  33731. domClass.toggle(this.domNode, "dijitCheckedMenuItemChecked", checked);
  33732. this.domNode.setAttribute("aria-checked", checked);
  33733. this._set("checked", checked);
  33734. },
  33735. iconClass: "", // override dijitNoIcon
  33736. onChange: function(/*Boolean*/ /*===== checked =====*/){
  33737. // summary:
  33738. // User defined function to handle check/uncheck events
  33739. // tags:
  33740. // callback
  33741. },
  33742. _onClick: function(/*Event*/ e){
  33743. // summary:
  33744. // Clicking this item just toggles its state
  33745. // tags:
  33746. // private
  33747. if(!this.disabled){
  33748. this.set("checked", !this.checked);
  33749. this.onChange(this.checked);
  33750. }
  33751. this.inherited(arguments);
  33752. }
  33753. });
  33754. });
  33755. },
  33756. 'dojox/io/xhrMultiPart':function(){
  33757. define("dojox/io/xhrMultiPart", [
  33758. "dojo/_base/kernel",
  33759. "dojo/_base/array",
  33760. "dojo/_base/xhr",
  33761. "dojo/query",
  33762. "dojox/uuid/generateRandomUuid"
  33763. ], function(dojo, array, xhr, query, generateRandomUuid){
  33764. dojo.getObject("io.xhrMultiPart", true, dojox);
  33765. /*=====
  33766. dojox.io.__xhrContentArgs = function(){
  33767. // name: String
  33768. // Name of the form value.
  33769. // content: String
  33770. // The contents of the value.
  33771. // filename: String?
  33772. // An optional filename to pass to the server, as defined by the boundary.
  33773. // contentType: String?
  33774. // An optional content-type (MIME) to pass to the server, if value is being
  33775. // treated as a file.
  33776. // charset: String?
  33777. // Optional charset to pass, for the server to interpret the file correctly.
  33778. // contentTransferEncoding: String?
  33779. // Optional transfer encoding header value.
  33780. this.name = name;
  33781. this.content = content;
  33782. this.filename = filename;
  33783. this.contentType = contentType;
  33784. this.charset = charset;
  33785. this.contentTransferEncoding = contentTransferEncoding;
  33786. }
  33787. =====*/
  33788. function _createPart(/* dojox.io.__xhrContentArgs */args, /* String */boundary){
  33789. // summary
  33790. // Assemble an array of boundary parts based on the passed values in args.
  33791. if(!args["name"] && !args["content"]){
  33792. throw new Error("Each part of a multi-part request requires 'name' and 'content'.");
  33793. }
  33794. var tmp = [];
  33795. tmp.push(
  33796. "--" + boundary,
  33797. "Content-Disposition: form-data; name=\"" + args.name + "\"" + (args["filename"] ? "; filename=\"" + args.filename + "\"" : "")
  33798. );
  33799. if(args["contentType"]){
  33800. var ct = "Content-Type: " + args.contentType;
  33801. if(args["charset"]){
  33802. ct += "; Charset=" + args.charset;
  33803. }
  33804. tmp.push(ct);
  33805. }
  33806. if(args["contentTransferEncoding"]){
  33807. tmp.push("Content-Transfer-Encoding: " + args.contentTransferEncoding);
  33808. }
  33809. tmp.push("", args.content);
  33810. return tmp; // Array
  33811. }
  33812. function _partsFromNode(/* DOMNode */node, /* String */boundary){
  33813. // summary
  33814. // Assemble an array of boundary parts based on the passed FORM node.
  33815. var o=dojo.formToObject(node), parts=[];
  33816. for(var p in o){
  33817. if(dojo.isArray(o[p])){
  33818. dojo.forEach(o[p], function(item){
  33819. parts = parts.concat(_createPart({ name: p, content: item }, boundary));
  33820. });
  33821. } else {
  33822. parts = parts.concat(_createPart({ name: p, content: o[p] }, boundary));
  33823. }
  33824. }
  33825. return parts; // Array
  33826. }
  33827. /*=====
  33828. dojox.io.__xhrMultiArgs = function(){
  33829. // url: String
  33830. // URL to server endpoint.
  33831. // content: Object?
  33832. // Contains properties with string values. These
  33833. // properties will be serialized using multi-part
  33834. // boundaries.
  33835. // file: Object?
  33836. // Alias for "content". Provided for backwards compatibility.
  33837. // timeout: Integer?
  33838. // Milliseconds to wait for the response. If this time
  33839. // passes, the then error callbacks are called.
  33840. // form: DOMNode?
  33841. // DOM node for a form. Used to extract the form values
  33842. // and send to the server; each form value will be serialized
  33843. // using multi-part boundaries.
  33844. // preventCache: Boolean?
  33845. // Default is false. If true, then a
  33846. // "dojo.preventCache" parameter is sent in the request
  33847. // with a value that changes with each request
  33848. // (timestamp). Useful only with GET-type requests.
  33849. // handleAs: String?
  33850. // Acceptable values depend on the type of IO
  33851. // transport (see specific IO calls for more information).
  33852. // load: Function?
  33853. // function(response, ioArgs){}. response is an Object, ioArgs
  33854. // is of type dojo.__IoCallbackArgs. The load function will be
  33855. // called on a successful response.
  33856. // error: Function?
  33857. // function(response, ioArgs){}. response is an Object, ioArgs
  33858. // is of type dojo.__IoCallbackArgs. The error function will
  33859. // be called in an error case.
  33860. // handle: Function?
  33861. // function(response, ioArgs){}. response is an Object, ioArgs
  33862. // is of type dojo.__IoCallbackArgs. The handle function will
  33863. // be called in either the successful or error case.
  33864. this.url = url;
  33865. this.content = content;
  33866. this.file = file;
  33867. this.timeout = timeout;
  33868. this.form = form;
  33869. this.preventCache = preventCache;
  33870. this.handleAs = handleAs;
  33871. this.load = load;
  33872. this.error = error;
  33873. this.handle = handle;
  33874. }
  33875. =====*/
  33876. dojox.io.xhrMultiPart = function(/* dojox.io.__xhrMultiArgs */args){
  33877. if(!args["file"] && !args["content"] && !args["form"]){
  33878. throw new Error("content, file or form must be provided to dojox.io.xhrMultiPart's arguments");
  33879. }
  33880. // unique guid as a boundary value for multipart posts
  33881. var boundary=generateRandomUuid(), tmp=[], out="";
  33882. if(args["file"] || args["content"]){
  33883. var v = args["file"] || args["content"];
  33884. dojo.forEach((dojo.isArray(v) ? v : [v]), function(item){
  33885. tmp = tmp.concat(_createPart(item, boundary));
  33886. });
  33887. }
  33888. else if(args["form"]){
  33889. if(query("input[type=file]", args["form"]).length){
  33890. throw new Error("dojox.io.xhrMultiPart cannot post files that are values of an INPUT TYPE=FILE. Use dojo.io.iframe.send() instead.");
  33891. }
  33892. tmp = _partsFromNode(args["form"], boundary);
  33893. }
  33894. if(tmp.length){
  33895. tmp.push("--"+boundary+"--", "");
  33896. out = tmp.join("\r\n");
  33897. }
  33898. console.log(out);
  33899. return dojo.rawXhrPost(dojo.mixin(args, {
  33900. contentType: "multipart/form-data; boundary=" + boundary,
  33901. postData: out
  33902. })); // dojo.Deferred
  33903. };
  33904. return dojox.io.xhrMultiPart;
  33905. });
  33906. },
  33907. 'dojo/io/iframe':function(){
  33908. define("dojo/io/iframe", ["../main", "require"], function(dojo, require) {
  33909. // module:
  33910. // dojo/io/iframe
  33911. // summary:
  33912. // TODOC
  33913. dojo.getObject("io", true, dojo);
  33914. /*=====
  33915. dojo.declare("dojo.io.iframe.__ioArgs", dojo.__IoArgs, {
  33916. constructor: function(){
  33917. // summary:
  33918. // All the properties described in the dojo.__ioArgs type, apply
  33919. // to this type. The following additional properties are allowed
  33920. // for dojo.io.iframe.send():
  33921. // method: String?
  33922. // The HTTP method to use. "GET" or "POST" are the only supported
  33923. // values. It will try to read the value from the form node's
  33924. // method, then try this argument. If neither one exists, then it
  33925. // defaults to POST.
  33926. // handleAs: String?
  33927. // Specifies what format the result data should be given to the
  33928. // load/handle callback. Valid values are: text, html, xml, json,
  33929. // javascript. IMPORTANT: For all values EXCEPT html and xml, The
  33930. // server response should be an HTML file with a textarea element.
  33931. // The response data should be inside the textarea element. Using an
  33932. // HTML document the only reliable, cross-browser way this
  33933. // transport can know when the response has loaded. For the html
  33934. // handleAs value, just return a normal HTML document. NOTE: xml
  33935. // is now supported with this transport (as of 1.1+); a known issue
  33936. // is if the XML document in question is malformed, Internet Explorer
  33937. // will throw an uncatchable error.
  33938. // content: Object?
  33939. // If "form" is one of the other args properties, then the content
  33940. // object properties become hidden form form elements. For
  33941. // instance, a content object of {name1 : "value1"} is converted
  33942. // to a hidden form element with a name of "name1" and a value of
  33943. // "value1". If there is not a "form" property, then the content
  33944. // object is converted into a name=value&name=value string, by
  33945. // using dojo.objectToQuery().
  33946. this.method = method;
  33947. this.handleAs = handleAs;
  33948. this.content = content;
  33949. }
  33950. });
  33951. =====*/
  33952. dojo.io.iframe = {
  33953. // summary:
  33954. // Sends an Ajax I/O call using and Iframe (for instance, to upload files)
  33955. create: function(/*String*/fname, /*String*/onloadstr, /*String?*/uri){
  33956. // summary:
  33957. // Creates a hidden iframe in the page. Used mostly for IO
  33958. // transports. You do not need to call this to start a
  33959. // dojo.io.iframe request. Just call send().
  33960. // fname: String
  33961. // The name of the iframe. Used for the name attribute on the
  33962. // iframe.
  33963. // onloadstr: String
  33964. // A string of JavaScript that will be executed when the content
  33965. // in the iframe loads.
  33966. // uri: String
  33967. // The value of the src attribute on the iframe element. If a
  33968. // value is not given, then dojo/resources/blank.html will be
  33969. // used.
  33970. if(window[fname]){ return window[fname]; }
  33971. if(window.frames[fname]){ return window.frames[fname]; }
  33972. var turi = uri;
  33973. if(!turi){
  33974. if(dojo.config["useXDomain"] && !dojo.config["dojoBlankHtmlUrl"]){
  33975. console.warn("dojo.io.iframe.create: When using cross-domain Dojo builds,"
  33976. + " please save dojo/resources/blank.html to your domain and set djConfig.dojoBlankHtmlUrl"
  33977. + " to the path on your domain to blank.html");
  33978. }
  33979. turi = (dojo.config["dojoBlankHtmlUrl"]||require.toUrl("../resources/blank.html"));
  33980. }
  33981. var cframe = dojo.place(
  33982. '<iframe id="'+fname+'" name="'+fname+'" src="'+turi+'" onload="'+onloadstr+
  33983. '" style="position: absolute; left: 1px; top: 1px; height: 1px; width: 1px; visibility: hidden">',
  33984. dojo.body());
  33985. window[fname] = cframe;
  33986. return cframe;
  33987. },
  33988. setSrc: function(/*DOMNode*/iframe, /*String*/src, /*Boolean*/replace){
  33989. //summary:
  33990. // Sets the URL that is loaded in an IFrame. The replace parameter
  33991. // indicates whether location.replace() should be used when
  33992. // changing the location of the iframe.
  33993. try{
  33994. if(!replace){
  33995. if(dojo.isWebKit){
  33996. iframe.location = src;
  33997. }else{
  33998. frames[iframe.name].location = src;
  33999. }
  34000. }else{
  34001. // Fun with DOM 0 incompatibilities!
  34002. var idoc;
  34003. if(dojo.isIE || dojo.isWebKit){
  34004. idoc = iframe.contentWindow.document;
  34005. }else{ // if(d.isMozilla){
  34006. idoc = iframe.contentWindow;
  34007. }
  34008. //For Safari (at least 2.0.3) and Opera, if the iframe
  34009. //has just been created but it doesn't have content
  34010. //yet, then iframe.document may be null. In that case,
  34011. //use iframe.location and return.
  34012. if(!idoc){
  34013. iframe.location = src;
  34014. }else{
  34015. idoc.location.replace(src);
  34016. }
  34017. }
  34018. }catch(e){
  34019. console.log("dojo.io.iframe.setSrc: ", e);
  34020. }
  34021. },
  34022. doc: function(/*DOMNode*/iframeNode){
  34023. //summary: Returns the document object associated with the iframe DOM Node argument.
  34024. return iframeNode.contentDocument || // W3
  34025. (
  34026. (
  34027. (iframeNode.name) && (iframeNode.document) &&
  34028. (dojo.doc.getElementsByTagName("iframe")[iframeNode.name].contentWindow) &&
  34029. (dojo.doc.getElementsByTagName("iframe")[iframeNode.name].contentWindow.document)
  34030. )
  34031. ) || // IE
  34032. (
  34033. (iframeNode.name)&&(dojo.doc.frames[iframeNode.name])&&
  34034. (dojo.doc.frames[iframeNode.name].document)
  34035. ) || null;
  34036. },
  34037. send: function(/*dojo.io.iframe.__ioArgs*/args){
  34038. //summary:
  34039. // Function that sends the request to the server.
  34040. // This transport can only process one send() request at a time, so if send() is called
  34041. //multiple times, it will queue up the calls and only process one at a time.
  34042. if(!this["_frame"]){
  34043. this._frame = this.create(this._iframeName, dojo._scopeName + ".io.iframe._iframeOnload();");
  34044. }
  34045. //Set up the deferred.
  34046. var dfd = dojo._ioSetArgs(
  34047. args,
  34048. function(/*Deferred*/dfd){
  34049. //summary: canceller function for dojo._ioSetArgs call.
  34050. dfd.canceled = true;
  34051. dfd.ioArgs._callNext();
  34052. },
  34053. function(/*Deferred*/dfd){
  34054. //summary: okHandler function for dojo._ioSetArgs call.
  34055. var value = null;
  34056. try{
  34057. var ioArgs = dfd.ioArgs;
  34058. var dii = dojo.io.iframe;
  34059. var ifd = dii.doc(dii._frame);
  34060. var handleAs = ioArgs.handleAs;
  34061. //Assign correct value based on handleAs value.
  34062. value = ifd; //html
  34063. if(handleAs != "html"){
  34064. if(handleAs == "xml"){
  34065. // FF, Saf 3+ and Opera all seem to be fine with ifd being xml. We have to
  34066. // do it manually for IE6-8. Refs #6334.
  34067. if(dojo.isIE < 9 || (dojo.isIE && dojo.isQuirks)){
  34068. dojo.query("a", dii._frame.contentWindow.document.documentElement).orphan();
  34069. var xmlText=(dii._frame.contentWindow.document).documentElement.innerText;
  34070. xmlText=xmlText.replace(/>\s+</g, "><");
  34071. xmlText=dojo.trim(xmlText);
  34072. //Reusing some code in base dojo for handling XML content. Simpler and keeps
  34073. //Core from duplicating the effort needed to locate the XML Parser on IE.
  34074. var fauxXhr = { responseText: xmlText };
  34075. value = dojo._contentHandlers["xml"](fauxXhr); // DOMDocument
  34076. }
  34077. }else{
  34078. value = ifd.getElementsByTagName("textarea")[0].value; //text
  34079. if(handleAs == "json"){
  34080. value = dojo.fromJson(value); //json
  34081. }else if(handleAs == "javascript"){
  34082. value = dojo.eval(value); //javascript
  34083. }
  34084. }
  34085. }
  34086. }catch(e){
  34087. value = e;
  34088. }finally{
  34089. ioArgs._callNext();
  34090. }
  34091. return value;
  34092. },
  34093. function(/*Error*/error, /*Deferred*/dfd){
  34094. //summary: errHandler function for dojo._ioSetArgs call.
  34095. dfd.ioArgs._hasError = true;
  34096. dfd.ioArgs._callNext();
  34097. return error;
  34098. }
  34099. );
  34100. //Set up a function that will fire the next iframe request. Make sure it only
  34101. //happens once per deferred.
  34102. dfd.ioArgs._callNext = function(){
  34103. if(!this["_calledNext"]){
  34104. this._calledNext = true;
  34105. dojo.io.iframe._currentDfd = null;
  34106. dojo.io.iframe._fireNextRequest();
  34107. }
  34108. };
  34109. this._dfdQueue.push(dfd);
  34110. this._fireNextRequest();
  34111. //Add it the IO watch queue, to get things like timeout support.
  34112. dojo._ioWatch(
  34113. dfd,
  34114. function(/*Deferred*/dfd){
  34115. //validCheck
  34116. return !dfd.ioArgs["_hasError"];
  34117. },
  34118. function(dfd){
  34119. //ioCheck
  34120. return (!!dfd.ioArgs["_finished"]);
  34121. },
  34122. function(dfd){
  34123. //resHandle
  34124. if(dfd.ioArgs._finished){
  34125. dfd.callback(dfd);
  34126. }else{
  34127. dfd.errback(new Error("Invalid dojo.io.iframe request state"));
  34128. }
  34129. }
  34130. );
  34131. return dfd;
  34132. },
  34133. _currentDfd: null,
  34134. _dfdQueue: [],
  34135. _iframeName: dojo._scopeName + "IoIframe",
  34136. _fireNextRequest: function(){
  34137. //summary: Internal method used to fire the next request in the bind queue.
  34138. try{
  34139. if((this._currentDfd)||(this._dfdQueue.length == 0)){ return; }
  34140. //Find next deferred, skip the canceled ones.
  34141. do{
  34142. var dfd = this._currentDfd = this._dfdQueue.shift();
  34143. } while(dfd && dfd.canceled && this._dfdQueue.length);
  34144. //If no more dfds, cancel.
  34145. if(!dfd || dfd.canceled){
  34146. this._currentDfd = null;
  34147. return;
  34148. }
  34149. var ioArgs = dfd.ioArgs;
  34150. var args = ioArgs.args;
  34151. ioArgs._contentToClean = [];
  34152. var fn = dojo.byId(args["form"]);
  34153. var content = args["content"] || {};
  34154. if(fn){
  34155. if(content){
  34156. // if we have things in content, we need to add them to the form
  34157. // before submission
  34158. var pHandler = function(name, value) {
  34159. dojo.create("input", {type: "hidden", name: name, value: value}, fn);
  34160. ioArgs._contentToClean.push(name);
  34161. };
  34162. for(var x in content){
  34163. var val = content[x];
  34164. if(dojo.isArray(val) && val.length > 1){
  34165. var i;
  34166. for (i = 0; i < val.length; i++) {
  34167. pHandler(x,val[i]);
  34168. }
  34169. }else{
  34170. if(!fn[x]){
  34171. pHandler(x,val);
  34172. }else{
  34173. fn[x].value = val;
  34174. }
  34175. }
  34176. }
  34177. }
  34178. //IE requires going through getAttributeNode instead of just getAttribute in some form cases,
  34179. //so use it for all. See #2844
  34180. var actnNode = fn.getAttributeNode("action");
  34181. var mthdNode = fn.getAttributeNode("method");
  34182. var trgtNode = fn.getAttributeNode("target");
  34183. if(args["url"]){
  34184. ioArgs._originalAction = actnNode ? actnNode.value : null;
  34185. if(actnNode){
  34186. actnNode.value = args.url;
  34187. }else{
  34188. fn.setAttribute("action",args.url);
  34189. }
  34190. }
  34191. if(!mthdNode || !mthdNode.value){
  34192. if(mthdNode){
  34193. mthdNode.value= (args["method"]) ? args["method"] : "post";
  34194. }else{
  34195. fn.setAttribute("method", (args["method"]) ? args["method"] : "post");
  34196. }
  34197. }
  34198. ioArgs._originalTarget = trgtNode ? trgtNode.value: null;
  34199. if(trgtNode){
  34200. trgtNode.value = this._iframeName;
  34201. }else{
  34202. fn.setAttribute("target", this._iframeName);
  34203. }
  34204. fn.target = this._iframeName;
  34205. dojo._ioNotifyStart(dfd);
  34206. fn.submit();
  34207. }else{
  34208. // otherwise we post a GET string by changing URL location for the
  34209. // iframe
  34210. var tmpUrl = args.url + (args.url.indexOf("?") > -1 ? "&" : "?") + ioArgs.query;
  34211. dojo._ioNotifyStart(dfd);
  34212. this.setSrc(this._frame, tmpUrl, true);
  34213. }
  34214. }catch(e){
  34215. dfd.errback(e);
  34216. }
  34217. },
  34218. _iframeOnload: function(){
  34219. var dfd = this._currentDfd;
  34220. if(!dfd){
  34221. this._fireNextRequest();
  34222. return;
  34223. }
  34224. var ioArgs = dfd.ioArgs;
  34225. var args = ioArgs.args;
  34226. var fNode = dojo.byId(args.form);
  34227. if(fNode){
  34228. // remove all the hidden content inputs
  34229. var toClean = ioArgs._contentToClean;
  34230. for(var i = 0; i < toClean.length; i++) {
  34231. var key = toClean[i];
  34232. //Need to cycle over all nodes since we may have added
  34233. //an array value which means that more than one node could
  34234. //have the same .name value.
  34235. for(var j = 0; j < fNode.childNodes.length; j++){
  34236. var chNode = fNode.childNodes[j];
  34237. if(chNode.name == key){
  34238. dojo.destroy(chNode);
  34239. break;
  34240. }
  34241. }
  34242. }
  34243. // restore original action + target
  34244. if(ioArgs["_originalAction"]){
  34245. fNode.setAttribute("action", ioArgs._originalAction);
  34246. }
  34247. if(ioArgs["_originalTarget"]){
  34248. fNode.setAttribute("target", ioArgs._originalTarget);
  34249. fNode.target = ioArgs._originalTarget;
  34250. }
  34251. }
  34252. ioArgs._finished = true;
  34253. }
  34254. };
  34255. return dojo.io.iframe;
  34256. });
  34257. },
  34258. 'dojox/form/uploader/plugins/IFrame':function(){
  34259. define("dojox/form/uploader/plugins/IFrame", [
  34260. "dojo/dom-construct",
  34261. "dojo/_base/declare",
  34262. "dojo/_base/lang",
  34263. "dojo/_base/array",
  34264. "dojo/io/iframe",
  34265. "dojox/form/uploader/plugins/HTML5"
  34266. ],function(domConstruct, declare, lang, array, ioIframe, formUploaderPluginsHTML5){
  34267. var pluginsIFrame = declare("dojox.form.uploader.plugins.IFrame", [], {
  34268. //
  34269. // Version: 1.6
  34270. //
  34271. // summary:
  34272. // A plugin for dojox.form.Uploader that adds Ajax upload capabilities.
  34273. //
  34274. // description:
  34275. // Only supported by IE, due to the specifc iFrame hack used. The
  34276. // formUploaderPluginsHTML5 plugin should be used along with this to add HTML5
  34277. // capabilities to browsers that support them. Progress events are not supported.
  34278. // Inherits all properties from dojox.form.Uploader and formUploaderPluginsHTML5.
  34279. //
  34280. force:"",
  34281. postMixInProperties: function(){
  34282. this.inherited(arguments);
  34283. if(!this.supports("multiple") || this.force =="iframe"){
  34284. this.uploadType = "iframe";
  34285. this.upload = this.uploadIFrame;
  34286. }
  34287. },
  34288. uploadIFrame: function(data){
  34289. // summary:
  34290. // Internal. You could use this, but you should use upload() or submit();
  34291. // which can also handle the post data.
  34292. //
  34293. var form, destroyAfter = false;
  34294. if(!this.getForm()){
  34295. //enctype can't be changed once a form element is created
  34296. form = domConstruct.place('<form enctype="multipart/form-data" method="post"></form>', this.domNode);
  34297. array.forEach(this._inputs, function(n, i){
  34298. if(n.value) form.appendChild(n);
  34299. }, this);
  34300. destroyAfter = true;
  34301. }else{
  34302. form = this.form;
  34303. }
  34304. var url = this.getUrl();
  34305. var dfd = ioIframe.send({
  34306. url: url,
  34307. form: form,
  34308. handleAs: "json",
  34309. content: data,
  34310. error: lang.hitch(this, function(err){
  34311. if(destroyAfter){ domConstruct.destroy(form); }
  34312. this.onError(err);
  34313. }),
  34314. load: lang.hitch(this, function(data, ioArgs, widgetRef){
  34315. if(destroyAfter){ domConstruct.destroy(form); }
  34316. if(data["ERROR"] || data["error"]){
  34317. this.onError(data);
  34318. }else{
  34319. this.onComplete(data);
  34320. }
  34321. })
  34322. });
  34323. }
  34324. });
  34325. dojox.form.addUploaderPlugin(pluginsIFrame);
  34326. return pluginsIFrame;
  34327. });
  34328. },
  34329. 'dojox/grid/enhanced/plugins/AutoScroll':function(){
  34330. define("dojox/grid/enhanced/plugins/AutoScroll", [
  34331. "dojo/_base/declare",
  34332. "dojo/_base/array",
  34333. "dojo/_base/lang",
  34334. "dojo/_base/html",
  34335. "dojo/_base/window",
  34336. "../_Plugin",
  34337. "../../_RowSelector",
  34338. "../../EnhancedGrid"
  34339. ], function(declare, array, lang, html, win, _Plugin, _RowSelector, EnhancedGrid){
  34340. var AutoScroll = declare("dojox.grid.enhanced.plugins.AutoScroll", _Plugin, {
  34341. // summary:
  34342. // Provides horizontal and vertical auto-scroll for grid.
  34343. // name: String
  34344. // Plugin name
  34345. name: "autoScroll",
  34346. // autoScrollInterval: Integer
  34347. // The time interval (in miliseconds) between 2 scrolling.
  34348. autoScrollInterval: 1000,
  34349. // autoScrollMargin: Integer
  34350. // The width (in pixel) of the margin area where autoscroll can be triggered.
  34351. autoScrollMargin: 30,
  34352. constructor: function(grid, args){
  34353. this.grid = grid;
  34354. this.readyForAutoScroll = false;
  34355. this._scrolling = false;
  34356. args = lang.isObject(args) ? args : {};
  34357. if("interval" in args){
  34358. this.autoScrollInterval = args.interval;
  34359. }
  34360. if("margin" in args){
  34361. this.autoScrollMargin = args.margin;
  34362. }
  34363. this._initEvents();
  34364. this._mixinGrid();
  34365. },
  34366. _initEvents: function(){
  34367. var g = this.grid;
  34368. this.connect(g, "onCellMouseDown", function(){
  34369. this.readyForAutoScroll = true;
  34370. });
  34371. this.connect(g, "onHeaderCellMouseDown", function(){
  34372. this.readyForAutoScroll = true;
  34373. });
  34374. this.connect(g, "onRowSelectorMouseDown", function(){
  34375. this.readyForAutoScroll = true;
  34376. });
  34377. this.connect(win.doc, "onmouseup", function(evt){
  34378. this._manageAutoScroll(true);
  34379. this.readyForAutoScroll = false;
  34380. });
  34381. this.connect(win.doc, "onmousemove", function(evt){
  34382. if(this.readyForAutoScroll){
  34383. this._event = evt;
  34384. var gridPos = html.position(g.domNode),
  34385. hh = g._getHeaderHeight(),
  34386. margin = this.autoScrollMargin,
  34387. ey = evt.clientY, ex = evt.clientX,
  34388. gy = gridPos.y, gx = gridPos.x,
  34389. gh = gridPos.h, gw = gridPos.w;
  34390. if(ex >= gx && ex <= gx + gw){
  34391. if(ey >= gy + hh && ey < gy + hh + margin){
  34392. this._manageAutoScroll(false, true, false);
  34393. return;
  34394. }else if(ey > gy + gh - margin && ey <= gy + gh){
  34395. this._manageAutoScroll(false, true, true);
  34396. return;
  34397. }else if(ey >= gy && ey <= gy + gh){
  34398. var withinSomeview = array.some(g.views.views, function(view, i){
  34399. if(view instanceof _RowSelector){
  34400. return false;
  34401. }
  34402. var viewPos = html.position(view.domNode);
  34403. if(ex < viewPos.x + margin && ex >= viewPos.x){
  34404. this._manageAutoScroll(false, false, false, view);
  34405. return true;
  34406. }else if(ex > viewPos.x + viewPos.w - margin && ex < viewPos.x + viewPos.w){
  34407. this._manageAutoScroll(false, false, true, view);
  34408. return true;
  34409. }
  34410. return false;
  34411. }, this);
  34412. if(withinSomeview){
  34413. return;
  34414. }
  34415. }
  34416. }
  34417. //stop autoscroll.
  34418. this._manageAutoScroll(true);
  34419. }
  34420. });
  34421. },
  34422. _mixinGrid: function(){
  34423. var g = this.grid;
  34424. g.onStartAutoScroll = function(/*isVertical, isForward*/){};
  34425. g.onEndAutoScroll = function(/*isVertical, isForward, view, scrollToRowIndex, event*/){};
  34426. },
  34427. _fireEvent: function(eventName, args){
  34428. var g = this.grid;
  34429. switch(eventName){
  34430. case "start":
  34431. g.onStartAutoScroll.apply(g, args);
  34432. break;
  34433. case "end":
  34434. g.onEndAutoScroll.apply(g, args);
  34435. break;
  34436. }
  34437. },
  34438. _manageAutoScroll: function(toStop, isVertical, isForward, view){
  34439. if(toStop){
  34440. this._scrolling = false;
  34441. clearInterval(this._handler);
  34442. }else if(!this._scrolling){
  34443. this._scrolling = true;
  34444. this._fireEvent("start", [isVertical, isForward, view]);
  34445. this._autoScroll(isVertical, isForward, view);
  34446. this._handler = setInterval(lang.hitch(this, "_autoScroll", isVertical, isForward, view), this.autoScrollInterval);
  34447. }
  34448. },
  34449. _autoScroll: function(isVertical, isForward, view){
  34450. var g = this.grid,
  34451. target = null;
  34452. if(isVertical){
  34453. var targetRow = g.scroller.firstVisibleRow + (isForward ? 1 : -1);
  34454. if(targetRow >= 0 && targetRow < g.rowCount){
  34455. g.scrollToRow(targetRow);
  34456. target = targetRow;
  34457. }
  34458. }else{
  34459. target = this._scrollColumn(isForward, view);
  34460. }
  34461. if(target !== null){
  34462. this._fireEvent("end", [isVertical, isForward, view, target, this._event]);
  34463. }
  34464. },
  34465. _scrollColumn: function(isForward, view){
  34466. var node = view.scrollboxNode,
  34467. target = null;
  34468. if(node.clientWidth < node.scrollWidth){
  34469. var cells = array.filter(this.grid.layout.cells, function(cell){
  34470. return !cell.hidden;
  34471. });
  34472. var viewPos = html.position(view.domNode);
  34473. var limit, edge, headerPos, i;
  34474. if(isForward){
  34475. limit = node.clientWidth;
  34476. for(i = 0; i < cells.length; ++i){
  34477. headerPos = html.position(cells[i].getHeaderNode());
  34478. edge = headerPos.x - viewPos.x + headerPos.w;
  34479. if(edge > limit){
  34480. target = cells[i].index;
  34481. node.scrollLeft += edge - limit + 10;
  34482. break;
  34483. }
  34484. }
  34485. }else{
  34486. limit = 0;
  34487. for(i = cells.length - 1; i >= 0; --i){
  34488. headerPos = html.position(cells[i].getHeaderNode());
  34489. edge = headerPos.x - viewPos.x;
  34490. if(edge < limit){
  34491. target = cells[i].index;
  34492. node.scrollLeft += edge - limit - 10;
  34493. break;
  34494. }
  34495. }
  34496. }
  34497. }
  34498. return target;
  34499. }
  34500. });
  34501. EnhancedGrid.registerPlugin(AutoScroll);
  34502. return AutoScroll;
  34503. });
  34504. },
  34505. 'dojox/grid/util':function(){
  34506. define("dojox/grid/util", [
  34507. "../main",
  34508. "dojo/_base/lang",
  34509. "dojo/dom"
  34510. ], function(dojox, lang, dom){
  34511. // summary: grid utility library
  34512. var dgu = lang.getObject("grid.util", true, dojox);
  34513. dgu.na = '...';
  34514. dgu.rowIndexTag = "gridRowIndex";
  34515. dgu.gridViewTag = "gridView";
  34516. dgu.fire = function(ob, ev, args){
  34517. var fn = ob && ev && ob[ev];
  34518. return fn && (args ? fn.apply(ob, args) : ob[ev]());
  34519. };
  34520. dgu.setStyleHeightPx = function(inElement, inHeight){
  34521. if(inHeight >= 0){
  34522. var s = inElement.style;
  34523. var v = inHeight + 'px';
  34524. if(inElement && s['height'] != v){
  34525. s['height'] = v;
  34526. }
  34527. }
  34528. };
  34529. dgu.mouseEvents = [ 'mouseover', 'mouseout', /*'mousemove',*/ 'mousedown', 'mouseup', 'click', 'dblclick', 'contextmenu' ];
  34530. dgu.keyEvents = [ 'keyup', 'keydown', 'keypress' ];
  34531. dgu.funnelEvents = function(inNode, inObject, inMethod, inEvents){
  34532. var evts = (inEvents ? inEvents : dgu.mouseEvents.concat(dgu.keyEvents));
  34533. for (var i=0, l=evts.length; i<l; i++){
  34534. inObject.connect(inNode, 'on' + evts[i], inMethod);
  34535. }
  34536. };
  34537. dgu.removeNode = function(inNode){
  34538. inNode = dom.byId(inNode);
  34539. inNode && inNode.parentNode && inNode.parentNode.removeChild(inNode);
  34540. return inNode;
  34541. };
  34542. dgu.arrayCompare = function(inA, inB){
  34543. for(var i=0,l=inA.length; i<l; i++){
  34544. if(inA[i] != inB[i]){return false;}
  34545. }
  34546. return (inA.length == inB.length);
  34547. };
  34548. dgu.arrayInsert = function(inArray, inIndex, inValue){
  34549. if(inArray.length <= inIndex){
  34550. inArray[inIndex] = inValue;
  34551. }else{
  34552. inArray.splice(inIndex, 0, inValue);
  34553. }
  34554. };
  34555. dgu.arrayRemove = function(inArray, inIndex){
  34556. inArray.splice(inIndex, 1);
  34557. };
  34558. dgu.arraySwap = function(inArray, inI, inJ){
  34559. var cache = inArray[inI];
  34560. inArray[inI] = inArray[inJ];
  34561. inArray[inJ] = cache;
  34562. };
  34563. return dojox.grid.util;
  34564. });
  34565. },
  34566. 'dijit/form/_ComboBoxMenu':function(){
  34567. define("dijit/form/_ComboBoxMenu", [
  34568. "dojo/_base/declare", // declare
  34569. "dojo/dom-class", // domClass.add domClass.remove
  34570. "dojo/dom-construct", // domConstruct.create
  34571. "dojo/dom-style", // domStyle.get
  34572. "dojo/keys", // keys.DOWN_ARROW keys.PAGE_DOWN keys.PAGE_UP keys.UP_ARROW
  34573. "../_WidgetBase",
  34574. "../_TemplatedMixin",
  34575. "./_ComboBoxMenuMixin",
  34576. "./_ListMouseMixin"
  34577. ], function(declare, domClass, domConstruct, domStyle, keys,
  34578. _WidgetBase, _TemplatedMixin, _ComboBoxMenuMixin, _ListMouseMixin){
  34579. /*=====
  34580. var _WidgetBase = dijit._WidgetBase;
  34581. var _TemplatedMixin = dijit._TemplatedMixin;
  34582. var _ComboBoxMenuMixin = dijit.form._ComboBoxMenuMixin;
  34583. var _ListMouseMixin = dijit.form._ListMouseMixin;
  34584. =====*/
  34585. // module:
  34586. // dijit/form/_ComboBoxMenu
  34587. // summary:
  34588. // Focus-less menu for internal use in `dijit.form.ComboBox`
  34589. return declare("dijit.form._ComboBoxMenu",[_WidgetBase, _TemplatedMixin, _ListMouseMixin, _ComboBoxMenuMixin], {
  34590. // summary:
  34591. // Focus-less menu for internal use in `dijit.form.ComboBox`
  34592. // Abstract methods that must be defined externally:
  34593. // onChange: item was explicitly chosen (mousedown somewhere on the menu and mouseup somewhere on the menu)
  34594. // onPage: next(1) or previous(-1) button pressed
  34595. // tags:
  34596. // private
  34597. templateString: "<div class='dijitReset dijitMenu' data-dojo-attach-point='containerNode' style='overflow: auto; overflow-x: hidden;'>"
  34598. +"<div class='dijitMenuItem dijitMenuPreviousButton' data-dojo-attach-point='previousButton' role='option'></div>"
  34599. +"<div class='dijitMenuItem dijitMenuNextButton' data-dojo-attach-point='nextButton' role='option'></div>"
  34600. +"</div>",
  34601. baseClass: "dijitComboBoxMenu",
  34602. postCreate: function(){
  34603. this.inherited(arguments);
  34604. if(!this.isLeftToRight()){
  34605. domClass.add(this.previousButton, "dijitMenuItemRtl");
  34606. domClass.add(this.nextButton, "dijitMenuItemRtl");
  34607. }
  34608. },
  34609. _createMenuItem: function(){
  34610. return domConstruct.create("div", {
  34611. "class": "dijitReset dijitMenuItem" +(this.isLeftToRight() ? "" : " dijitMenuItemRtl"),
  34612. role: "option"
  34613. });
  34614. },
  34615. onHover: function(/*DomNode*/ node){
  34616. // summary:
  34617. // Add hover CSS
  34618. domClass.add(node, "dijitMenuItemHover");
  34619. },
  34620. onUnhover: function(/*DomNode*/ node){
  34621. // summary:
  34622. // Remove hover CSS
  34623. domClass.remove(node, "dijitMenuItemHover");
  34624. },
  34625. onSelect: function(/*DomNode*/ node){
  34626. // summary:
  34627. // Add selected CSS
  34628. domClass.add(node, "dijitMenuItemSelected");
  34629. },
  34630. onDeselect: function(/*DomNode*/ node){
  34631. // summary:
  34632. // Remove selected CSS
  34633. domClass.remove(node, "dijitMenuItemSelected");
  34634. },
  34635. _page: function(/*Boolean*/ up){
  34636. // summary:
  34637. // Handles page-up and page-down keypresses
  34638. var scrollamount = 0;
  34639. var oldscroll = this.domNode.scrollTop;
  34640. var height = domStyle.get(this.domNode, "height");
  34641. // if no item is highlighted, highlight the first option
  34642. if(!this.getHighlightedOption()){
  34643. this.selectNextNode();
  34644. }
  34645. while(scrollamount<height){
  34646. var highlighted_option = this.getHighlightedOption();
  34647. if(up){
  34648. // stop at option 1
  34649. if(!highlighted_option.previousSibling ||
  34650. highlighted_option.previousSibling.style.display == "none"){
  34651. break;
  34652. }
  34653. this.selectPreviousNode();
  34654. }else{
  34655. // stop at last option
  34656. if(!highlighted_option.nextSibling ||
  34657. highlighted_option.nextSibling.style.display == "none"){
  34658. break;
  34659. }
  34660. this.selectNextNode();
  34661. }
  34662. // going backwards
  34663. var newscroll = this.domNode.scrollTop;
  34664. scrollamount += (newscroll-oldscroll)*(up ? -1:1);
  34665. oldscroll = newscroll;
  34666. }
  34667. },
  34668. handleKey: function(evt){
  34669. // summary:
  34670. // Handle keystroke event forwarded from ComboBox, returning false if it's
  34671. // a keystroke I recognize and process, true otherwise.
  34672. switch(evt.charOrCode){
  34673. case keys.DOWN_ARROW:
  34674. this.selectNextNode();
  34675. return false;
  34676. case keys.PAGE_DOWN:
  34677. this._page(false);
  34678. return false;
  34679. case keys.UP_ARROW:
  34680. this.selectPreviousNode();
  34681. return false;
  34682. case keys.PAGE_UP:
  34683. this._page(true);
  34684. return false;
  34685. default:
  34686. return true;
  34687. }
  34688. }
  34689. });
  34690. });
  34691. },
  34692. 'dojox/grid/cells/_base':function(){
  34693. define("dojox/grid/cells/_base", [
  34694. "dojo/_base/kernel",
  34695. "dojo/_base/declare",
  34696. "dojo/_base/lang",
  34697. "dojo/_base/event",
  34698. "dojo/_base/connect",
  34699. "dojo/_base/array",
  34700. "dojo/_base/sniff",
  34701. "dojo/dom",
  34702. "dojo/dom-attr",
  34703. "dojo/dom-construct",
  34704. "dijit/_Widget",
  34705. "../util"
  34706. ], function(dojo, declare, lang, event, connect, array, has, dom, domAttr, domConstruct, _Widget, util){
  34707. var _DeferredTextWidget = declare("dojox.grid._DeferredTextWidget", _Widget, {
  34708. deferred: null,
  34709. _destroyOnRemove: true,
  34710. postCreate: function(){
  34711. if(this.deferred){
  34712. this.deferred.addBoth(lang.hitch(this, function(text){
  34713. if(this.domNode){
  34714. this.domNode.innerHTML = text;
  34715. }
  34716. }));
  34717. }
  34718. }
  34719. });
  34720. var focusSelectNode = function(inNode){
  34721. try{
  34722. util.fire(inNode, "focus");
  34723. util.fire(inNode, "select");
  34724. }catch(e){// IE sux bad
  34725. }
  34726. };
  34727. var whenIdle = function(/*inContext, inMethod, args ...*/){
  34728. setTimeout(lang.hitch.apply(dojo, arguments), 0);
  34729. };
  34730. var BaseCell = declare("dojox.grid.cells._Base", null, {
  34731. // summary:
  34732. // Respresents a grid cell and contains information about column options and methods
  34733. // for retrieving cell related information.
  34734. // Each column in a grid layout has a cell object and most events and many methods
  34735. // provide access to these objects.
  34736. styles: '',
  34737. classes: '',
  34738. editable: false,
  34739. alwaysEditing: false,
  34740. formatter: null,
  34741. defaultValue: '...',
  34742. value: null,
  34743. hidden: false,
  34744. noresize: false,
  34745. draggable: true,
  34746. //private
  34747. _valueProp: "value",
  34748. _formatPending: false,
  34749. constructor: function(inProps){
  34750. this._props = inProps || {};
  34751. lang.mixin(this, inProps);
  34752. if(this.draggable === undefined){
  34753. this.draggable = true;
  34754. }
  34755. },
  34756. _defaultFormat: function(inValue, callArgs){
  34757. var s = this.grid.formatterScope || this;
  34758. var f = this.formatter;
  34759. if(f && s && typeof f == "string"){
  34760. f = this.formatter = s[f];
  34761. }
  34762. var v = (inValue != this.defaultValue && f) ? f.apply(s, callArgs) : inValue;
  34763. if(typeof v == "undefined"){
  34764. return this.defaultValue;
  34765. }
  34766. if(v && v.addBoth){
  34767. // Check if it's a deferred
  34768. v = new _DeferredTextWidget({deferred: v},
  34769. domConstruct.create("span", {innerHTML: this.defaultValue}));
  34770. }
  34771. if(v && v.declaredClass && v.startup){
  34772. return "<div class='dojoxGridStubNode' linkWidget='" +
  34773. v.id +
  34774. "' cellIdx='" +
  34775. this.index +
  34776. "'>" +
  34777. this.defaultValue +
  34778. "</div>";
  34779. }
  34780. return v;
  34781. },
  34782. // data source
  34783. format: function(inRowIndex, inItem){
  34784. // summary:
  34785. // provides the html for a given grid cell.
  34786. // inRowIndex: int
  34787. // grid row index
  34788. // returns: html for a given grid cell
  34789. var f, i=this.grid.edit.info, d=this.get ? this.get(inRowIndex, inItem) : (this.value || this.defaultValue);
  34790. d = (d && d.replace && this.grid.escapeHTMLInData) ? d.replace(/&/g, '&amp;').replace(/</g, '&lt;') : d;
  34791. if (this.editable && (this.alwaysEditing || (i.rowIndex==inRowIndex && i.cell==this))) {
  34792. return this.formatEditing(i.value ? i.value : d, inRowIndex);
  34793. } else {
  34794. return this._defaultFormat(d, [d, inRowIndex, this]);
  34795. }
  34796. },
  34797. formatEditing: function(inDatum, inRowIndex){
  34798. // summary:
  34799. // formats the cell for editing
  34800. // inDatum: anything
  34801. // cell data to edit
  34802. // inRowIndex: int
  34803. // grid row index
  34804. // returns: string of html to place in grid cell
  34805. },
  34806. // utility
  34807. getNode: function(inRowIndex){
  34808. // summary:
  34809. // gets the dom node for a given grid cell.
  34810. // inRowIndex: int
  34811. // grid row index
  34812. // returns: dom node for a given grid cell
  34813. return this.view.getCellNode(inRowIndex, this.index);
  34814. },
  34815. getHeaderNode: function(){
  34816. return this.view.getHeaderCellNode(this.index);
  34817. },
  34818. getEditNode: function(inRowIndex){
  34819. return (this.getNode(inRowIndex) || 0).firstChild || 0;
  34820. },
  34821. canResize: function(){
  34822. var uw = this.unitWidth;
  34823. return uw && (uw!=='auto');
  34824. },
  34825. isFlex: function(){
  34826. var uw = this.unitWidth;
  34827. return uw && lang.isString(uw) && (uw=='auto' || uw.slice(-1)=='%');
  34828. },
  34829. // edit support
  34830. applyEdit: function(inValue, inRowIndex){
  34831. if(this.getNode(inRowIndex)){
  34832. this.grid.edit.applyCellEdit(inValue, this, inRowIndex);
  34833. }
  34834. },
  34835. cancelEdit: function(inRowIndex){
  34836. this.grid.doCancelEdit(inRowIndex);
  34837. },
  34838. _onEditBlur: function(inRowIndex){
  34839. if(this.grid.edit.isEditCell(inRowIndex, this.index)){
  34840. //console.log('editor onblur', e);
  34841. this.grid.edit.apply();
  34842. }
  34843. },
  34844. registerOnBlur: function(inNode, inRowIndex){
  34845. if(this.commitOnBlur){
  34846. connect.connect(inNode, "onblur", function(e){
  34847. // hack: if editor still thinks this editor is current some ms after it blurs, assume we've focused away from grid
  34848. setTimeout(lang.hitch(this, "_onEditBlur", inRowIndex), 250);
  34849. });
  34850. }
  34851. },
  34852. //protected
  34853. needFormatNode: function(inDatum, inRowIndex){
  34854. this._formatPending = true;
  34855. whenIdle(this, "_formatNode", inDatum, inRowIndex);
  34856. },
  34857. cancelFormatNode: function(){
  34858. this._formatPending = false;
  34859. },
  34860. //private
  34861. _formatNode: function(inDatum, inRowIndex){
  34862. if(this._formatPending){
  34863. this._formatPending = false;
  34864. // make cell selectable
  34865. if(!has("ie")){
  34866. dom.setSelectable(this.grid.domNode, true);
  34867. }
  34868. this.formatNode(this.getEditNode(inRowIndex), inDatum, inRowIndex);
  34869. }
  34870. },
  34871. //protected
  34872. formatNode: function(inNode, inDatum, inRowIndex){
  34873. // summary:
  34874. // format the editing dom node. Use when editor is a widget.
  34875. // inNode: dom node
  34876. // dom node for the editor
  34877. // inDatum: anything
  34878. // cell data to edit
  34879. // inRowIndex: int
  34880. // grid row index
  34881. if(has("ie")){
  34882. // IE sux bad
  34883. whenIdle(this, "focus", inRowIndex, inNode);
  34884. }else{
  34885. this.focus(inRowIndex, inNode);
  34886. }
  34887. },
  34888. dispatchEvent: function(m, e){
  34889. if(m in this){
  34890. return this[m](e);
  34891. }
  34892. },
  34893. //public
  34894. getValue: function(inRowIndex){
  34895. // summary:
  34896. // returns value entered into editor
  34897. // inRowIndex: int
  34898. // grid row index
  34899. // returns:
  34900. // value of editor
  34901. return this.getEditNode(inRowIndex)[this._valueProp];
  34902. },
  34903. setValue: function(inRowIndex, inValue){
  34904. // summary:
  34905. // set the value of the grid editor
  34906. // inRowIndex: int
  34907. // grid row index
  34908. // inValue: anything
  34909. // value of editor
  34910. var n = this.getEditNode(inRowIndex);
  34911. if(n){
  34912. n[this._valueProp] = inValue;
  34913. }
  34914. },
  34915. focus: function(inRowIndex, inNode){
  34916. // summary:
  34917. // focus the grid editor
  34918. // inRowIndex: int
  34919. // grid row index
  34920. // inNode: dom node
  34921. // editor node
  34922. focusSelectNode(inNode || this.getEditNode(inRowIndex));
  34923. },
  34924. save: function(inRowIndex){
  34925. // summary:
  34926. // save editor state
  34927. // inRowIndex: int
  34928. // grid row index
  34929. this.value = this.value || this.getValue(inRowIndex);
  34930. //console.log("save", this.value, inCell.index, inRowIndex);
  34931. },
  34932. restore: function(inRowIndex){
  34933. // summary:
  34934. // restore editor state
  34935. // inRowIndex: int
  34936. // grid row index
  34937. this.setValue(inRowIndex, this.value);
  34938. //console.log("restore", this.value, inCell.index, inRowIndex);
  34939. },
  34940. //protected
  34941. _finish: function(inRowIndex){
  34942. // summary:
  34943. // called when editing is completed to clean up editor
  34944. // inRowIndex: int
  34945. // grid row index
  34946. dom.setSelectable(this.grid.domNode, false);
  34947. this.cancelFormatNode();
  34948. },
  34949. //public
  34950. apply: function(inRowIndex){
  34951. // summary:
  34952. // apply edit from cell editor
  34953. // inRowIndex: int
  34954. // grid row index
  34955. this.applyEdit(this.getValue(inRowIndex), inRowIndex);
  34956. this._finish(inRowIndex);
  34957. },
  34958. cancel: function(inRowIndex){
  34959. // summary:
  34960. // cancel cell edit
  34961. // inRowIndex: int
  34962. // grid row index
  34963. this.cancelEdit(inRowIndex);
  34964. this._finish(inRowIndex);
  34965. }
  34966. });
  34967. BaseCell.markupFactory = function(node, cellDef){
  34968. var formatter = lang.trim(domAttr.get(node, "formatter")||"");
  34969. if(formatter){
  34970. cellDef.formatter = lang.getObject(formatter)||formatter;
  34971. }
  34972. var get = lang.trim(domAttr.get(node, "get")||"");
  34973. if(get){
  34974. cellDef.get = lang.getObject(get);
  34975. }
  34976. var getBoolAttr = function(attr, cell, cellAttr){
  34977. var value = lang.trim(domAttr.get(node, attr)||"");
  34978. if(value){ cell[cellAttr||attr] = !(value.toLowerCase()=="false"); }
  34979. };
  34980. getBoolAttr("sortDesc", cellDef);
  34981. getBoolAttr("editable", cellDef);
  34982. getBoolAttr("alwaysEditing", cellDef);
  34983. getBoolAttr("noresize", cellDef);
  34984. getBoolAttr("draggable", cellDef);
  34985. var value = lang.trim(domAttr.get(node, "loadingText")||domAttr.get(node, "defaultValue")||"");
  34986. if(value){
  34987. cellDef.defaultValue = value;
  34988. }
  34989. var getStrAttr = function(attr, cell, cellAttr){
  34990. var value = lang.trim(domAttr.get(node, attr)||"")||undefined;
  34991. if(value){ cell[cellAttr||attr] = value; }
  34992. };
  34993. getStrAttr("styles", cellDef);
  34994. getStrAttr("headerStyles", cellDef);
  34995. getStrAttr("cellStyles", cellDef);
  34996. getStrAttr("classes", cellDef);
  34997. getStrAttr("headerClasses", cellDef);
  34998. getStrAttr("cellClasses", cellDef);
  34999. };
  35000. var Cell = declare("dojox.grid.cells.Cell", BaseCell, {
  35001. // summary
  35002. // grid cell that provides a standard text input box upon editing
  35003. constructor: function(){
  35004. this.keyFilter = this.keyFilter;
  35005. },
  35006. // keyFilter: RegExp
  35007. // optional regex for disallowing keypresses
  35008. keyFilter: null,
  35009. formatEditing: function(inDatum, inRowIndex){
  35010. this.needFormatNode(inDatum, inRowIndex);
  35011. if (inDatum && inDatum.replace) {
  35012. // escape quotes to avoid XSS
  35013. inDatum = inDatum.replace(/"/g, '&quot;')
  35014. }
  35015. return '<input class="dojoxGridInput" type="text" value="' + inDatum + '">';
  35016. },
  35017. formatNode: function(inNode, inDatum, inRowIndex){
  35018. this.inherited(arguments);
  35019. // FIXME: feels too specific for this interface
  35020. this.registerOnBlur(inNode, inRowIndex);
  35021. },
  35022. doKey: function(e){
  35023. if(this.keyFilter){
  35024. var key = String.fromCharCode(e.charCode);
  35025. if(key.search(this.keyFilter) == -1){
  35026. event.stop(e);
  35027. }
  35028. }
  35029. },
  35030. _finish: function(inRowIndex){
  35031. this.inherited(arguments);
  35032. var n = this.getEditNode(inRowIndex);
  35033. try{
  35034. util.fire(n, "blur");
  35035. }catch(e){}
  35036. }
  35037. });
  35038. Cell.markupFactory = function(node, cellDef){
  35039. BaseCell.markupFactory(node, cellDef);
  35040. var keyFilter = lang.trim(domAttr.get(node, "keyFilter")||"");
  35041. if(keyFilter){
  35042. cellDef.keyFilter = new RegExp(keyFilter);
  35043. }
  35044. };
  35045. var RowIndex = declare("dojox.grid.cells.RowIndex", Cell, {
  35046. name: 'Row',
  35047. postscript: function(){
  35048. this.editable = false;
  35049. },
  35050. get: function(inRowIndex){
  35051. return inRowIndex + 1;
  35052. }
  35053. });
  35054. RowIndex.markupFactory = function(node, cellDef){
  35055. Cell.markupFactory(node, cellDef);
  35056. };
  35057. var Select = declare("dojox.grid.cells.Select", Cell, {
  35058. // summary:
  35059. // grid cell that provides a standard select for editing
  35060. // options: Array
  35061. // text of each item
  35062. options: null,
  35063. // values: Array
  35064. // value for each item
  35065. values: null,
  35066. // returnIndex: Integer
  35067. // editor returns only the index of the selected option and not the value
  35068. returnIndex: -1,
  35069. constructor: function(inCell){
  35070. this.values = this.values || this.options;
  35071. },
  35072. formatEditing: function(inDatum, inRowIndex){
  35073. this.needFormatNode(inDatum, inRowIndex);
  35074. var h = [ '<select class="dojoxGridSelect">' ];
  35075. for (var i=0, o, v; ((o=this.options[i]) !== undefined)&&((v=this.values[i]) !== undefined); i++){
  35076. v = v.replace ? v.replace(/&/g, '&amp;').replace(/</g, '&lt;') : v;
  35077. o = o.replace ? o.replace(/&/g, '&amp;').replace(/</g, '&lt;') : o;
  35078. h.push("<option", (inDatum==v ? ' selected' : ''), ' value="' + v + '"', ">", o, "</option>");
  35079. }
  35080. h.push('</select>');
  35081. return h.join('');
  35082. },
  35083. _defaultFormat: function(inValue, callArgs){
  35084. var v = this.inherited(arguments);
  35085. // when 'values' and 'options' both provided and there is no cutomized formatter,
  35086. // then we use 'options' as label in order to be consistent
  35087. if(!this.formatter && this.values && this.options){
  35088. var i = array.indexOf(this.values, v);
  35089. if(i >= 0){
  35090. v = this.options[i];
  35091. }
  35092. }
  35093. return v;
  35094. },
  35095. getValue: function(inRowIndex){
  35096. var n = this.getEditNode(inRowIndex);
  35097. if(n){
  35098. var i = n.selectedIndex, o = n.options[i];
  35099. return this.returnIndex > -1 ? i : o.value || o.innerHTML;
  35100. }
  35101. }
  35102. });
  35103. Select.markupFactory = function(node, cell){
  35104. Cell.markupFactory(node, cell);
  35105. var options = lang.trim(domAttr.get(node, "options")||"");
  35106. if(options){
  35107. var o = options.split(',');
  35108. if(o[0] != options){
  35109. cell.options = o;
  35110. }
  35111. }
  35112. var values = lang.trim(domAttr.get(node, "values")||"");
  35113. if(values){
  35114. var v = values.split(',');
  35115. if(v[0] != values){
  35116. cell.values = v;
  35117. }
  35118. }
  35119. };
  35120. var AlwaysEdit = declare("dojox.grid.cells.AlwaysEdit", Cell, {
  35121. // summary:
  35122. // grid cell that is always in an editable state, regardless of grid editing state
  35123. alwaysEditing: true,
  35124. _formatNode: function(inDatum, inRowIndex){
  35125. this.formatNode(this.getEditNode(inRowIndex), inDatum, inRowIndex);
  35126. },
  35127. applyStaticValue: function(inRowIndex){
  35128. var e = this.grid.edit;
  35129. e.applyCellEdit(this.getValue(inRowIndex), this, inRowIndex);
  35130. e.start(this, inRowIndex, true);
  35131. }
  35132. });
  35133. AlwaysEdit.markupFactory = function(node, cell){
  35134. Cell.markupFactory(node, cell);
  35135. };
  35136. var Bool = declare("dojox.grid.cells.Bool", AlwaysEdit, {
  35137. // summary:
  35138. // grid cell that provides a standard checkbox that is always on for editing
  35139. _valueProp: "checked",
  35140. formatEditing: function(inDatum, inRowIndex){
  35141. return '<input class="dojoxGridInput" type="checkbox"' + (inDatum ? ' checked="checked"' : '') + ' style="width: auto" />';
  35142. },
  35143. doclick: function(e){
  35144. if(e.target.tagName == 'INPUT'){
  35145. this.applyStaticValue(e.rowIndex);
  35146. }
  35147. }
  35148. });
  35149. Bool.markupFactory = function(node, cell){
  35150. AlwaysEdit.markupFactory(node, cell);
  35151. };
  35152. return BaseCell;
  35153. });
  35154. },
  35155. 'dijit/form/_DateTimeTextBox':function(){
  35156. require({cache:{
  35157. 'url:dijit/form/templates/DropDownBox.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\"\r\n\tid=\"widget_${id}\"\r\n\trole=\"combobox\"\r\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\r\n\t\tdata-dojo-attach-point=\"_buttonNode, _popupStateNode\" role=\"presentation\"\r\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t\t${_buttonInputDisabled}\r\n\t/></div\r\n\t><div class='dijitReset dijitValidationContainer'\r\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t/></div\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\r\n\t\t\tdata-dojo-attach-point=\"textbox,focusNode\" role=\"textbox\" aria-haspopup=\"true\"\r\n\t/></div\r\n></div>\r\n"}});
  35158. define("dijit/form/_DateTimeTextBox", [
  35159. "dojo/date", // date date.compare
  35160. "dojo/date/locale", // locale.regexp
  35161. "dojo/date/stamp", // stamp.fromISOString stamp.toISOString
  35162. "dojo/_base/declare", // declare
  35163. "dojo/_base/lang", // lang.getObject
  35164. "./RangeBoundTextBox",
  35165. "../_HasDropDown",
  35166. "dojo/text!./templates/DropDownBox.html"
  35167. ], function(date, locale, stamp, declare, lang, RangeBoundTextBox, _HasDropDown, template){
  35168. /*=====
  35169. var _HasDropDown = dijit._HasDropDown;
  35170. var RangeBoundTextBox = dijit.form.RangeBoundTextBox;
  35171. =====*/
  35172. // module:
  35173. // dijit/form/_DateTimeTextBox
  35174. // summary:
  35175. // Base class for validating, serializable, range-bound date or time text box.
  35176. new Date("X"); // workaround for #11279, new Date("") == NaN
  35177. /*=====
  35178. declare(
  35179. "dijit.form._DateTimeTextBox.__Constraints",
  35180. [RangeBoundTextBox.__Constraints, locale.__FormatOptions], {
  35181. // summary:
  35182. // Specifies both the rules on valid/invalid values (first/last date/time allowed),
  35183. // and also formatting options for how the date/time is displayed.
  35184. // example:
  35185. // To restrict to dates within 2004, displayed in a long format like "December 25, 2005":
  35186. // | {min:'2004-01-01',max:'2004-12-31', formatLength:'long'}
  35187. });
  35188. =====*/
  35189. var _DateTimeTextBox = declare("dijit.form._DateTimeTextBox", [RangeBoundTextBox, _HasDropDown], {
  35190. // summary:
  35191. // Base class for validating, serializable, range-bound date or time text box.
  35192. templateString: template,
  35193. // hasDownArrow: [const] Boolean
  35194. // Set this textbox to display a down arrow button, to open the drop down list.
  35195. hasDownArrow: true,
  35196. // openOnClick: [const] Boolean
  35197. // Set to true to open drop down upon clicking anywhere on the textbox.
  35198. openOnClick: true,
  35199. /*=====
  35200. // constraints: dijit.form._DateTimeTextBox.__Constraints
  35201. // Despite the name, this parameter specifies both constraints on the input
  35202. // (including starting/ending dates/times allowed) as well as
  35203. // formatting options like whether the date is displayed in long (ex: December 25, 2005)
  35204. // or short (ex: 12/25/2005) format. See `dijit.form._DateTimeTextBox.__Constraints` for details.
  35205. constraints: {},
  35206. ======*/
  35207. // Override ValidationTextBox.regExpGen().... we use a reg-ex generating function rather
  35208. // than a straight regexp to deal with locale (plus formatting options too?)
  35209. regExpGen: locale.regexp,
  35210. // datePackage: String
  35211. // JavaScript namespace to find calendar routines. Uses Gregorian calendar routines
  35212. // at dojo.date, by default.
  35213. datePackage: date,
  35214. postMixInProperties: function(){
  35215. this.inherited(arguments);
  35216. this._set("type", "text"); // in case type="date"|"time" was specified which messes up parse/format
  35217. },
  35218. // Override _FormWidget.compare() to work for dates/times
  35219. compare: function(/*Date*/ val1, /*Date*/ val2){
  35220. var isInvalid1 = this._isInvalidDate(val1);
  35221. var isInvalid2 = this._isInvalidDate(val2);
  35222. return isInvalid1 ? (isInvalid2 ? 0 : -1) : (isInvalid2 ? 1 : date.compare(val1, val2, this._selector));
  35223. },
  35224. // flag to _HasDropDown to make drop down Calendar width == <input> width
  35225. forceWidth: true,
  35226. format: function(/*Date*/ value, /*dojo.date.locale.__FormatOptions*/ constraints){
  35227. // summary:
  35228. // Formats the value as a Date, according to specified locale (second argument)
  35229. // tags:
  35230. // protected
  35231. if(!value){ return ''; }
  35232. return this.dateLocaleModule.format(value, constraints);
  35233. },
  35234. "parse": function(/*String*/ value, /*dojo.date.locale.__FormatOptions*/ constraints){
  35235. // summary:
  35236. // Parses as string as a Date, according to constraints
  35237. // tags:
  35238. // protected
  35239. return this.dateLocaleModule.parse(value, constraints) || (this._isEmpty(value) ? null : undefined); // Date
  35240. },
  35241. // Overrides ValidationTextBox.serialize() to serialize a date in canonical ISO format.
  35242. serialize: function(/*anything*/ val, /*Object?*/ options){
  35243. if(val.toGregorian){
  35244. val = val.toGregorian();
  35245. }
  35246. return stamp.toISOString(val, options);
  35247. },
  35248. // dropDownDefaultValue: Date
  35249. // The default value to focus in the popupClass widget when the textbox value is empty.
  35250. dropDownDefaultValue : new Date(),
  35251. // value: Date
  35252. // The value of this widget as a JavaScript Date object. Use get("value") / set("value", val) to manipulate.
  35253. // When passed to the parser in markup, must be specified according to `dojo.date.stamp.fromISOString`
  35254. value: new Date(""), // value.toString()="NaN"
  35255. _blankValue: null, // used by filter() when the textbox is blank
  35256. // popupClass: [protected extension] String
  35257. // Name of the popup widget class used to select a date/time.
  35258. // Subclasses should specify this.
  35259. popupClass: "", // default is no popup = text only
  35260. // _selector: [protected extension] String
  35261. // Specifies constraints.selector passed to dojo.date functions, should be either
  35262. // "date" or "time".
  35263. // Subclass must specify this.
  35264. _selector: "",
  35265. constructor: function(/*Object*/ args){
  35266. this.datePackage = args.datePackage || this.datePackage;
  35267. this.dateFuncObj = typeof this.datePackage == "string" ?
  35268. lang.getObject(this.datePackage, false) :// "string" part for back-compat, remove for 2.0
  35269. this.datePackage;
  35270. this.dateClassObj = this.dateFuncObj.Date || Date;
  35271. this.dateLocaleModule = lang.getObject("locale", false, this.dateFuncObj);
  35272. this.regExpGen = this.dateLocaleModule.regexp;
  35273. this._invalidDate = this.constructor.prototype.value.toString();
  35274. },
  35275. buildRendering: function(){
  35276. this.inherited(arguments);
  35277. if(!this.hasDownArrow){
  35278. this._buttonNode.style.display = "none";
  35279. }
  35280. // If openOnClick is true, we basically just want to treat the whole widget as the
  35281. // button. We need to do that also if the actual drop down button will be hidden,
  35282. // so that there's a mouse method for opening the drop down.
  35283. if(this.openOnClick || !this.hasDownArrow){
  35284. this._buttonNode = this.domNode;
  35285. this.baseClass += " dijitComboBoxOpenOnClick";
  35286. }
  35287. },
  35288. _setConstraintsAttr: function(/*Object*/ constraints){
  35289. constraints.selector = this._selector;
  35290. constraints.fullYear = true; // see #5465 - always format with 4-digit years
  35291. var fromISO = stamp.fromISOString;
  35292. if(typeof constraints.min == "string"){ constraints.min = fromISO(constraints.min); }
  35293. if(typeof constraints.max == "string"){ constraints.max = fromISO(constraints.max); }
  35294. this.inherited(arguments);
  35295. },
  35296. _isInvalidDate: function(/*Date*/ value){
  35297. // summary:
  35298. // Runs various tests on the value, checking for invalid conditions
  35299. // tags:
  35300. // private
  35301. return !value || isNaN(value) || typeof value != "object" || value.toString() == this._invalidDate;
  35302. },
  35303. _setValueAttr: function(/*Date|String*/ value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
  35304. // summary:
  35305. // Sets the date on this textbox. Note: value can be a JavaScript Date literal or a string to be parsed.
  35306. if(value !== undefined){
  35307. if(typeof value == "string"){
  35308. value = stamp.fromISOString(value);
  35309. }
  35310. if(this._isInvalidDate(value)){
  35311. value = null;
  35312. }
  35313. if(value instanceof Date && !(this.dateClassObj instanceof Date)){
  35314. value = new this.dateClassObj(value);
  35315. }
  35316. }
  35317. this.inherited(arguments);
  35318. if(this.value instanceof Date){
  35319. this.filterString = "";
  35320. }
  35321. if(this.dropDown){
  35322. this.dropDown.set('value', value, false);
  35323. }
  35324. },
  35325. _set: function(attr, value){
  35326. // Avoid spurious watch() notifications when value is changed to new Date object w/the same value
  35327. if(attr == "value" && this.value instanceof Date && this.compare(value, this.value) == 0){
  35328. return;
  35329. }
  35330. this.inherited(arguments);
  35331. },
  35332. _setDropDownDefaultValueAttr: function(/*Date*/ val){
  35333. if(this._isInvalidDate(val)){
  35334. // convert null setting into today's date, since there needs to be *some* default at all times.
  35335. val = new this.dateClassObj();
  35336. }
  35337. this.dropDownDefaultValue = val;
  35338. },
  35339. openDropDown: function(/*Function*/ callback){
  35340. // rebuild drop down every time, so that constraints get copied (#6002)
  35341. if(this.dropDown){
  35342. this.dropDown.destroy();
  35343. }
  35344. var PopupProto = lang.isString(this.popupClass) ? lang.getObject(this.popupClass, false) : this.popupClass,
  35345. textBox = this,
  35346. value = this.get("value");
  35347. this.dropDown = new PopupProto({
  35348. onChange: function(value){
  35349. // this will cause InlineEditBox and other handlers to do stuff so make sure it's last
  35350. textBox.set('value', value, true);
  35351. },
  35352. id: this.id + "_popup",
  35353. dir: textBox.dir,
  35354. lang: textBox.lang,
  35355. value: value,
  35356. currentFocus: !this._isInvalidDate(value) ? value : this.dropDownDefaultValue,
  35357. constraints: textBox.constraints,
  35358. filterString: textBox.filterString, // for TimeTextBox, to filter times shown
  35359. datePackage: textBox.datePackage,
  35360. isDisabledDate: function(/*Date*/ date){
  35361. // summary:
  35362. // disables dates outside of the min/max of the _DateTimeTextBox
  35363. return !textBox.rangeCheck(date, textBox.constraints);
  35364. }
  35365. });
  35366. this.inherited(arguments);
  35367. },
  35368. _getDisplayedValueAttr: function(){
  35369. return this.textbox.value;
  35370. },
  35371. _setDisplayedValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange){
  35372. this._setValueAttr(this.parse(value, this.constraints), priorityChange, value);
  35373. }
  35374. });
  35375. return _DateTimeTextBox;
  35376. });
  35377. },
  35378. 'dijit/_base/focus':function(){
  35379. define("dijit/_base/focus", [
  35380. "dojo/_base/array", // array.forEach
  35381. "dojo/dom", // dom.isDescendant
  35382. "dojo/_base/lang", // lang.isArray
  35383. "dojo/topic", // publish
  35384. "dojo/_base/window", // win.doc win.doc.selection win.global win.global.getSelection win.withGlobal
  35385. "../focus",
  35386. ".." // for exporting symbols to dijit
  35387. ], function(array, dom, lang, topic, win, focus, dijit){
  35388. // module:
  35389. // dijit/_base/focus
  35390. // summary:
  35391. // Deprecated module to monitor currently focused node and stack of currently focused widgets.
  35392. // New code should access dijit/focus directly.
  35393. lang.mixin(dijit, {
  35394. // _curFocus: DomNode
  35395. // Currently focused item on screen
  35396. _curFocus: null,
  35397. // _prevFocus: DomNode
  35398. // Previously focused item on screen
  35399. _prevFocus: null,
  35400. isCollapsed: function(){
  35401. // summary:
  35402. // Returns true if there is no text selected
  35403. return dijit.getBookmark().isCollapsed;
  35404. },
  35405. getBookmark: function(){
  35406. // summary:
  35407. // Retrieves a bookmark that can be used with moveToBookmark to return to the same range
  35408. var bm, rg, tg, sel = win.doc.selection, cf = focus.curNode;
  35409. if(win.global.getSelection){
  35410. //W3C Range API for selections.
  35411. sel = win.global.getSelection();
  35412. if(sel){
  35413. if(sel.isCollapsed){
  35414. tg = cf? cf.tagName : "";
  35415. if(tg){
  35416. //Create a fake rangelike item to restore selections.
  35417. tg = tg.toLowerCase();
  35418. if(tg == "textarea" ||
  35419. (tg == "input" && (!cf.type || cf.type.toLowerCase() == "text"))){
  35420. sel = {
  35421. start: cf.selectionStart,
  35422. end: cf.selectionEnd,
  35423. node: cf,
  35424. pRange: true
  35425. };
  35426. return {isCollapsed: (sel.end <= sel.start), mark: sel}; //Object.
  35427. }
  35428. }
  35429. bm = {isCollapsed:true};
  35430. if(sel.rangeCount){
  35431. bm.mark = sel.getRangeAt(0).cloneRange();
  35432. }
  35433. }else{
  35434. rg = sel.getRangeAt(0);
  35435. bm = {isCollapsed: false, mark: rg.cloneRange()};
  35436. }
  35437. }
  35438. }else if(sel){
  35439. // If the current focus was a input of some sort and no selection, don't bother saving
  35440. // a native bookmark. This is because it causes issues with dialog/page selection restore.
  35441. // So, we need to create psuedo bookmarks to work with.
  35442. tg = cf ? cf.tagName : "";
  35443. tg = tg.toLowerCase();
  35444. if(cf && tg && (tg == "button" || tg == "textarea" || tg == "input")){
  35445. if(sel.type && sel.type.toLowerCase() == "none"){
  35446. return {
  35447. isCollapsed: true,
  35448. mark: null
  35449. }
  35450. }else{
  35451. rg = sel.createRange();
  35452. return {
  35453. isCollapsed: rg.text && rg.text.length?false:true,
  35454. mark: {
  35455. range: rg,
  35456. pRange: true
  35457. }
  35458. };
  35459. }
  35460. }
  35461. bm = {};
  35462. //'IE' way for selections.
  35463. try{
  35464. // createRange() throws exception when dojo in iframe
  35465. //and nothing selected, see #9632
  35466. rg = sel.createRange();
  35467. bm.isCollapsed = !(sel.type == 'Text' ? rg.htmlText.length : rg.length);
  35468. }catch(e){
  35469. bm.isCollapsed = true;
  35470. return bm;
  35471. }
  35472. if(sel.type.toUpperCase() == 'CONTROL'){
  35473. if(rg.length){
  35474. bm.mark=[];
  35475. var i=0,len=rg.length;
  35476. while(i<len){
  35477. bm.mark.push(rg.item(i++));
  35478. }
  35479. }else{
  35480. bm.isCollapsed = true;
  35481. bm.mark = null;
  35482. }
  35483. }else{
  35484. bm.mark = rg.getBookmark();
  35485. }
  35486. }else{
  35487. console.warn("No idea how to store the current selection for this browser!");
  35488. }
  35489. return bm; // Object
  35490. },
  35491. moveToBookmark: function(/*Object*/ bookmark){
  35492. // summary:
  35493. // Moves current selection to a bookmark
  35494. // bookmark:
  35495. // This should be a returned object from dijit.getBookmark()
  35496. var _doc = win.doc,
  35497. mark = bookmark.mark;
  35498. if(mark){
  35499. if(win.global.getSelection){
  35500. //W3C Rangi API (FF, WebKit, Opera, etc)
  35501. var sel = win.global.getSelection();
  35502. if(sel && sel.removeAllRanges){
  35503. if(mark.pRange){
  35504. var n = mark.node;
  35505. n.selectionStart = mark.start;
  35506. n.selectionEnd = mark.end;
  35507. }else{
  35508. sel.removeAllRanges();
  35509. sel.addRange(mark);
  35510. }
  35511. }else{
  35512. console.warn("No idea how to restore selection for this browser!");
  35513. }
  35514. }else if(_doc.selection && mark){
  35515. //'IE' way.
  35516. var rg;
  35517. if(mark.pRange){
  35518. rg = mark.range;
  35519. }else if(lang.isArray(mark)){
  35520. rg = _doc.body.createControlRange();
  35521. //rg.addElement does not have call/apply method, so can not call it directly
  35522. //rg is not available in "range.addElement(item)", so can't use that either
  35523. array.forEach(mark, function(n){
  35524. rg.addElement(n);
  35525. });
  35526. }else{
  35527. rg = _doc.body.createTextRange();
  35528. rg.moveToBookmark(mark);
  35529. }
  35530. rg.select();
  35531. }
  35532. }
  35533. },
  35534. getFocus: function(/*Widget?*/ menu, /*Window?*/ openedForWindow){
  35535. // summary:
  35536. // Called as getFocus(), this returns an Object showing the current focus
  35537. // and selected text.
  35538. //
  35539. // Called as getFocus(widget), where widget is a (widget representing) a button
  35540. // that was just pressed, it returns where focus was before that button
  35541. // was pressed. (Pressing the button may have either shifted focus to the button,
  35542. // or removed focus altogether.) In this case the selected text is not returned,
  35543. // since it can't be accurately determined.
  35544. //
  35545. // menu: dijit._Widget or {domNode: DomNode} structure
  35546. // The button that was just pressed. If focus has disappeared or moved
  35547. // to this button, returns the previous focus. In this case the bookmark
  35548. // information is already lost, and null is returned.
  35549. //
  35550. // openedForWindow:
  35551. // iframe in which menu was opened
  35552. //
  35553. // returns:
  35554. // A handle to restore focus/selection, to be passed to `dijit.focus`
  35555. var node = !focus.curNode || (menu && dom.isDescendant(focus.curNode, menu.domNode)) ? dijit._prevFocus : focus.curNode;
  35556. return {
  35557. node: node,
  35558. bookmark: node && (node == focus.curNode) && win.withGlobal(openedForWindow || win.global, dijit.getBookmark),
  35559. openedForWindow: openedForWindow
  35560. }; // Object
  35561. },
  35562. // _activeStack: dijit._Widget[]
  35563. // List of currently active widgets (focused widget and it's ancestors)
  35564. _activeStack: [],
  35565. registerIframe: function(/*DomNode*/ iframe){
  35566. // summary:
  35567. // Registers listeners on the specified iframe so that any click
  35568. // or focus event on that iframe (or anything in it) is reported
  35569. // as a focus/click event on the <iframe> itself.
  35570. // description:
  35571. // Currently only used by editor.
  35572. // returns:
  35573. // Handle to pass to unregisterIframe()
  35574. return focus.registerIframe(iframe);
  35575. },
  35576. unregisterIframe: function(/*Object*/ handle){
  35577. // summary:
  35578. // Unregisters listeners on the specified iframe created by registerIframe.
  35579. // After calling be sure to delete or null out the handle itself.
  35580. // handle:
  35581. // Handle returned by registerIframe()
  35582. handle && handle.remove();
  35583. },
  35584. registerWin: function(/*Window?*/targetWindow, /*DomNode?*/ effectiveNode){
  35585. // summary:
  35586. // Registers listeners on the specified window (either the main
  35587. // window or an iframe's window) to detect when the user has clicked somewhere
  35588. // or focused somewhere.
  35589. // description:
  35590. // Users should call registerIframe() instead of this method.
  35591. // targetWindow:
  35592. // If specified this is the window associated with the iframe,
  35593. // i.e. iframe.contentWindow.
  35594. // effectiveNode:
  35595. // If specified, report any focus events inside targetWindow as
  35596. // an event on effectiveNode, rather than on evt.target.
  35597. // returns:
  35598. // Handle to pass to unregisterWin()
  35599. return focus.registerWin(targetWindow, effectiveNode);
  35600. },
  35601. unregisterWin: function(/*Handle*/ handle){
  35602. // summary:
  35603. // Unregisters listeners on the specified window (either the main
  35604. // window or an iframe's window) according to handle returned from registerWin().
  35605. // After calling be sure to delete or null out the handle itself.
  35606. handle && handle.remove();
  35607. }
  35608. });
  35609. // Override focus singleton's focus function so that dijit.focus()
  35610. // has backwards compatible behavior of restoring selection (although
  35611. // probably no one is using that).
  35612. focus.focus = function(/*Object || DomNode */ handle){
  35613. // summary:
  35614. // Sets the focused node and the selection according to argument.
  35615. // To set focus to an iframe's content, pass in the iframe itself.
  35616. // handle:
  35617. // object returned by get(), or a DomNode
  35618. if(!handle){ return; }
  35619. var node = "node" in handle ? handle.node : handle, // because handle is either DomNode or a composite object
  35620. bookmark = handle.bookmark,
  35621. openedForWindow = handle.openedForWindow,
  35622. collapsed = bookmark ? bookmark.isCollapsed : false;
  35623. // Set the focus
  35624. // Note that for iframe's we need to use the <iframe> to follow the parentNode chain,
  35625. // but we need to set focus to iframe.contentWindow
  35626. if(node){
  35627. var focusNode = (node.tagName.toLowerCase() == "iframe") ? node.contentWindow : node;
  35628. if(focusNode && focusNode.focus){
  35629. try{
  35630. // Gecko throws sometimes if setting focus is impossible,
  35631. // node not displayed or something like that
  35632. focusNode.focus();
  35633. }catch(e){/*quiet*/}
  35634. }
  35635. focus._onFocusNode(node);
  35636. }
  35637. // set the selection
  35638. // do not need to restore if current selection is not empty
  35639. // (use keyboard to select a menu item) or if previous selection was collapsed
  35640. // as it may cause focus shift (Esp in IE).
  35641. if(bookmark && win.withGlobal(openedForWindow || win.global, dijit.isCollapsed) && !collapsed){
  35642. if(openedForWindow){
  35643. openedForWindow.focus();
  35644. }
  35645. try{
  35646. win.withGlobal(openedForWindow || win.global, dijit.moveToBookmark, null, [bookmark]);
  35647. }catch(e2){
  35648. /*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */
  35649. }
  35650. }
  35651. };
  35652. // For back compatibility, monitor changes to focused node and active widget stack,
  35653. // publishing events and copying changes from focus manager variables into dijit (top level) variables
  35654. focus.watch("curNode", function(name, oldVal, newVal){
  35655. dijit._curFocus = newVal;
  35656. dijit._prevFocus = oldVal;
  35657. if(newVal){
  35658. topic.publish("focusNode", newVal); // publish
  35659. }
  35660. });
  35661. focus.watch("activeStack", function(name, oldVal, newVal){
  35662. dijit._activeStack = newVal;
  35663. });
  35664. focus.on("widget-blur", function(widget, by){
  35665. topic.publish("widgetBlur", widget, by); // publish
  35666. });
  35667. focus.on("widget-focus", function(widget, by){
  35668. topic.publish("widgetFocus", widget, by); // publish
  35669. });
  35670. return dijit;
  35671. });
  35672. },
  35673. 'dijit/a11y':function(){
  35674. define("dijit/a11y", [
  35675. "dojo/_base/array", // array.forEach array.map
  35676. "dojo/_base/config", // defaultDuration
  35677. "dojo/_base/declare", // declare
  35678. "dojo/dom", // dom.byId
  35679. "dojo/dom-attr", // domAttr.attr domAttr.has
  35680. "dojo/dom-style", // style.style
  35681. "dojo/_base/sniff", // has("ie")
  35682. "./_base/manager", // manager._isElementShown
  35683. "." // for exporting methods to dijit namespace
  35684. ], function(array, config, declare, dom, domAttr, domStyle, has, manager, dijit){
  35685. // module:
  35686. // dijit/a11y
  35687. // summary:
  35688. // Accessibility utility functions (keyboard, tab stops, etc.)
  35689. var shown = (dijit._isElementShown = function(/*Element*/ elem){
  35690. var s = domStyle.get(elem);
  35691. return (s.visibility != "hidden")
  35692. && (s.visibility != "collapsed")
  35693. && (s.display != "none")
  35694. && (domAttr.get(elem, "type") != "hidden");
  35695. });
  35696. dijit.hasDefaultTabStop = function(/*Element*/ elem){
  35697. // summary:
  35698. // Tests if element is tab-navigable even without an explicit tabIndex setting
  35699. // No explicit tabIndex setting, need to investigate node type
  35700. switch(elem.nodeName.toLowerCase()){
  35701. case "a":
  35702. // An <a> w/out a tabindex is only navigable if it has an href
  35703. return domAttr.has(elem, "href");
  35704. case "area":
  35705. case "button":
  35706. case "input":
  35707. case "object":
  35708. case "select":
  35709. case "textarea":
  35710. // These are navigable by default
  35711. return true;
  35712. case "iframe":
  35713. // If it's an editor <iframe> then it's tab navigable.
  35714. var body;
  35715. try{
  35716. // non-IE
  35717. var contentDocument = elem.contentDocument;
  35718. if("designMode" in contentDocument && contentDocument.designMode == "on"){
  35719. return true;
  35720. }
  35721. body = contentDocument.body;
  35722. }catch(e1){
  35723. // contentWindow.document isn't accessible within IE7/8
  35724. // if the iframe.src points to a foreign url and this
  35725. // page contains an element, that could get focus
  35726. try{
  35727. body = elem.contentWindow.document.body;
  35728. }catch(e2){
  35729. return false;
  35730. }
  35731. }
  35732. return body && (body.contentEditable == 'true' ||
  35733. (body.firstChild && body.firstChild.contentEditable == 'true'));
  35734. default:
  35735. return elem.contentEditable == 'true';
  35736. }
  35737. };
  35738. var isTabNavigable = (dijit.isTabNavigable = function(/*Element*/ elem){
  35739. // summary:
  35740. // Tests if an element is tab-navigable
  35741. // TODO: convert (and rename method) to return effective tabIndex; will save time in _getTabNavigable()
  35742. if(domAttr.get(elem, "disabled")){
  35743. return false;
  35744. }else if(domAttr.has(elem, "tabIndex")){
  35745. // Explicit tab index setting
  35746. return domAttr.get(elem, "tabIndex") >= 0; // boolean
  35747. }else{
  35748. // No explicit tabIndex setting, so depends on node type
  35749. return dijit.hasDefaultTabStop(elem);
  35750. }
  35751. });
  35752. dijit._getTabNavigable = function(/*DOMNode*/ root){
  35753. // summary:
  35754. // Finds descendants of the specified root node.
  35755. //
  35756. // description:
  35757. // Finds the following descendants of the specified root node:
  35758. // * the first tab-navigable element in document order
  35759. // without a tabIndex or with tabIndex="0"
  35760. // * the last tab-navigable element in document order
  35761. // without a tabIndex or with tabIndex="0"
  35762. // * the first element in document order with the lowest
  35763. // positive tabIndex value
  35764. // * the last element in document order with the highest
  35765. // positive tabIndex value
  35766. var first, last, lowest, lowestTabindex, highest, highestTabindex, radioSelected = {};
  35767. function radioName(node){
  35768. // If this element is part of a radio button group, return the name for that group.
  35769. return node && node.tagName.toLowerCase() == "input" &&
  35770. node.type && node.type.toLowerCase() == "radio" &&
  35771. node.name && node.name.toLowerCase();
  35772. }
  35773. var walkTree = function(/*DOMNode*/parent){
  35774. for(var child = parent.firstChild; child; child = child.nextSibling){
  35775. // Skip text elements, hidden elements, and also non-HTML elements (those in custom namespaces) in IE,
  35776. // since show() invokes getAttribute("type"), which crash on VML nodes in IE.
  35777. if(child.nodeType != 1 || (has("ie") && child.scopeName !== "HTML") || !shown(child)){
  35778. continue;
  35779. }
  35780. if(isTabNavigable(child)){
  35781. var tabindex = domAttr.get(child, "tabIndex");
  35782. if(!domAttr.has(child, "tabIndex") || tabindex == 0){
  35783. if(!first){
  35784. first = child;
  35785. }
  35786. last = child;
  35787. }else if(tabindex > 0){
  35788. if(!lowest || tabindex < lowestTabindex){
  35789. lowestTabindex = tabindex;
  35790. lowest = child;
  35791. }
  35792. if(!highest || tabindex >= highestTabindex){
  35793. highestTabindex = tabindex;
  35794. highest = child;
  35795. }
  35796. }
  35797. var rn = radioName(child);
  35798. if(domAttr.get(child, "checked") && rn){
  35799. radioSelected[rn] = child;
  35800. }
  35801. }
  35802. if(child.nodeName.toUpperCase() != 'SELECT'){
  35803. walkTree(child);
  35804. }
  35805. }
  35806. };
  35807. if(shown(root)){
  35808. walkTree(root);
  35809. }
  35810. function rs(node){
  35811. // substitute checked radio button for unchecked one, if there is a checked one with the same name.
  35812. return radioSelected[radioName(node)] || node;
  35813. }
  35814. return { first: rs(first), last: rs(last), lowest: rs(lowest), highest: rs(highest) };
  35815. };
  35816. dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/ root){
  35817. // summary:
  35818. // Finds the descendant of the specified root node
  35819. // that is first in the tabbing order
  35820. var elems = dijit._getTabNavigable(dom.byId(root));
  35821. return elems.lowest ? elems.lowest : elems.first; // DomNode
  35822. };
  35823. dijit.getLastInTabbingOrder = function(/*String|DOMNode*/ root){
  35824. // summary:
  35825. // Finds the descendant of the specified root node
  35826. // that is last in the tabbing order
  35827. var elems = dijit._getTabNavigable(dom.byId(root));
  35828. return elems.last ? elems.last : elems.highest; // DomNode
  35829. };
  35830. return {
  35831. hasDefaultTabStop: dijit.hasDefaultTabStop,
  35832. isTabNavigable: dijit.isTabNavigable,
  35833. _getTabNavigable: dijit._getTabNavigable,
  35834. getFirstInTabbingOrder: dijit.getFirstInTabbingOrder,
  35835. getLastInTabbingOrder: dijit.getLastInTabbingOrder
  35836. };
  35837. });
  35838. },
  35839. 'dojox/grid/_Scroller':function(){
  35840. define("dojox/grid/_Scroller", [
  35841. "dijit/registry",
  35842. "dojo/_base/declare",
  35843. "dojo/_base/lang",
  35844. "./util",
  35845. "dojo/_base/html"
  35846. ], function(dijitRegistry, declare, lang, util, html){
  35847. var indexInParent = function(inNode){
  35848. var i=0, n, p=inNode.parentNode;
  35849. while((n = p.childNodes[i++])){
  35850. if(n == inNode){
  35851. return i - 1;
  35852. }
  35853. }
  35854. return -1;
  35855. };
  35856. var cleanNode = function(inNode){
  35857. if(!inNode){
  35858. return;
  35859. }
  35860. dojo.forEach(dijitRegistry.toArray(), function(w){
  35861. if(w.domNode && html.isDescendant(w.domNode, inNode, true)){
  35862. w.destroy();
  35863. }
  35864. });
  35865. };
  35866. var getTagName = function(inNodeOrId){
  35867. var node = html.byId(inNodeOrId);
  35868. return (node && node.tagName ? node.tagName.toLowerCase() : '');
  35869. };
  35870. var nodeKids = function(inNode, inTag){
  35871. var result = [];
  35872. var i=0, n;
  35873. while((n = inNode.childNodes[i])){
  35874. i++;
  35875. if(getTagName(n) == inTag){
  35876. result.push(n);
  35877. }
  35878. }
  35879. return result;
  35880. };
  35881. var divkids = function(inNode){
  35882. return nodeKids(inNode, 'div');
  35883. };
  35884. return declare("dojox.grid._Scroller", null, {
  35885. constructor: function(inContentNodes){
  35886. this.setContentNodes(inContentNodes);
  35887. this.pageHeights = [];
  35888. this.pageNodes = [];
  35889. this.stack = [];
  35890. },
  35891. // specified
  35892. rowCount: 0, // total number of rows to manage
  35893. defaultRowHeight: 32, // default height of a row
  35894. keepRows: 100, // maximum number of rows that should exist at one time
  35895. contentNode: null, // node to contain pages
  35896. scrollboxNode: null, // node that controls scrolling
  35897. // calculated
  35898. defaultPageHeight: 0, // default height of a page
  35899. keepPages: 10, // maximum number of pages that should exists at one time
  35900. pageCount: 0,
  35901. windowHeight: 0,
  35902. firstVisibleRow: 0,
  35903. lastVisibleRow: 0,
  35904. averageRowHeight: 0, // the average height of a row
  35905. // private
  35906. page: 0,
  35907. pageTop: 0,
  35908. // init
  35909. init: function(inRowCount, inKeepRows, inRowsPerPage){
  35910. switch(arguments.length){
  35911. case 3: this.rowsPerPage = inRowsPerPage;
  35912. case 2: this.keepRows = inKeepRows;
  35913. case 1: this.rowCount = inRowCount;
  35914. default: break;
  35915. }
  35916. this.defaultPageHeight = this.defaultRowHeight * this.rowsPerPage;
  35917. this.pageCount = this._getPageCount(this.rowCount, this.rowsPerPage);
  35918. this.setKeepInfo(this.keepRows);
  35919. this.invalidate();
  35920. if(this.scrollboxNode){
  35921. this.scrollboxNode.scrollTop = 0;
  35922. this.scroll(0);
  35923. this.scrollboxNode.onscroll = lang.hitch(this, 'onscroll');
  35924. }
  35925. },
  35926. _getPageCount: function(rowCount, rowsPerPage){
  35927. return rowCount ? (Math.ceil(rowCount / rowsPerPage) || 1) : 0;
  35928. },
  35929. destroy: function(){
  35930. this.invalidateNodes();
  35931. delete this.contentNodes;
  35932. delete this.contentNode;
  35933. delete this.scrollboxNode;
  35934. },
  35935. setKeepInfo: function(inKeepRows){
  35936. this.keepRows = inKeepRows;
  35937. this.keepPages = !this.keepRows ? this.keepPages : Math.max(Math.ceil(this.keepRows / this.rowsPerPage), 2);
  35938. },
  35939. // nodes
  35940. setContentNodes: function(inNodes){
  35941. this.contentNodes = inNodes;
  35942. this.colCount = (this.contentNodes ? this.contentNodes.length : 0);
  35943. this.pageNodes = [];
  35944. for(var i=0; i<this.colCount; i++){
  35945. this.pageNodes[i] = [];
  35946. }
  35947. },
  35948. getDefaultNodes: function(){
  35949. return this.pageNodes[0] || [];
  35950. },
  35951. // updating
  35952. invalidate: function(){
  35953. this._invalidating = true;
  35954. this.invalidateNodes();
  35955. this.pageHeights = [];
  35956. this.height = (this.pageCount ? (this.pageCount - 1)* this.defaultPageHeight + this.calcLastPageHeight() : 0);
  35957. this.resize();
  35958. this._invalidating = false;
  35959. },
  35960. updateRowCount: function(inRowCount){
  35961. this.invalidateNodes();
  35962. this.rowCount = inRowCount;
  35963. // update page count, adjust document height
  35964. var oldPageCount = this.pageCount;
  35965. if(oldPageCount === 0){
  35966. //We want to have at least 1px in height to keep scroller. Otherwise with an
  35967. //empty grid you can't scroll to see the header.
  35968. this.height = 1;
  35969. }
  35970. this.pageCount = this._getPageCount(this.rowCount, this.rowsPerPage);
  35971. if(this.pageCount < oldPageCount){
  35972. for(var i=oldPageCount-1; i>=this.pageCount; i--){
  35973. this.height -= this.getPageHeight(i);
  35974. delete this.pageHeights[i];
  35975. }
  35976. }else if(this.pageCount > oldPageCount){
  35977. this.height += this.defaultPageHeight * (this.pageCount - oldPageCount - 1) + this.calcLastPageHeight();
  35978. }
  35979. this.resize();
  35980. },
  35981. // implementation for page manager
  35982. pageExists: function(inPageIndex){
  35983. return Boolean(this.getDefaultPageNode(inPageIndex));
  35984. },
  35985. measurePage: function(inPageIndex){
  35986. if(this.grid.rowHeight){
  35987. var height = this.grid.rowHeight + 1;
  35988. return ((inPageIndex + 1) * this.rowsPerPage > this.rowCount ?
  35989. this.rowCount - inPageIndex * this.rowsPerPage :
  35990. this.rowsPerPage) * height;
  35991. }
  35992. var n = this.getDefaultPageNode(inPageIndex);
  35993. return (n && n.innerHTML) ? n.offsetHeight : undefined;
  35994. },
  35995. positionPage: function(inPageIndex, inPos){
  35996. for(var i=0; i<this.colCount; i++){
  35997. this.pageNodes[i][inPageIndex].style.top = inPos + 'px';
  35998. }
  35999. },
  36000. repositionPages: function(inPageIndex){
  36001. var nodes = this.getDefaultNodes();
  36002. var last = 0;
  36003. for(var i=0; i<this.stack.length; i++){
  36004. last = Math.max(this.stack[i], last);
  36005. }
  36006. //
  36007. var n = nodes[inPageIndex];
  36008. var y = (n ? this.getPageNodePosition(n) + this.getPageHeight(inPageIndex) : 0);
  36009. for(var p=inPageIndex+1; p<=last; p++){
  36010. n = nodes[p];
  36011. if(n){
  36012. if(this.getPageNodePosition(n) == y){
  36013. return;
  36014. }
  36015. this.positionPage(p, y);
  36016. }
  36017. y += this.getPageHeight(p);
  36018. }
  36019. },
  36020. installPage: function(inPageIndex){
  36021. for(var i=0; i<this.colCount; i++){
  36022. this.contentNodes[i].appendChild(this.pageNodes[i][inPageIndex]);
  36023. }
  36024. },
  36025. preparePage: function(inPageIndex, inReuseNode){
  36026. var p = (inReuseNode ? this.popPage() : null);
  36027. for(var i=0; i<this.colCount; i++){
  36028. var nodes = this.pageNodes[i];
  36029. var new_p = (p === null ? this.createPageNode() : this.invalidatePageNode(p, nodes));
  36030. new_p.pageIndex = inPageIndex;
  36031. nodes[inPageIndex] = new_p;
  36032. }
  36033. },
  36034. // rendering implementation
  36035. renderPage: function(inPageIndex){
  36036. var nodes = [];
  36037. var i, j;
  36038. for(i=0; i<this.colCount; i++){
  36039. nodes[i] = this.pageNodes[i][inPageIndex];
  36040. }
  36041. for(i=0, j=inPageIndex*this.rowsPerPage; (i<this.rowsPerPage)&&(j<this.rowCount); i++, j++){
  36042. this.renderRow(j, nodes);
  36043. }
  36044. },
  36045. removePage: function(inPageIndex){
  36046. for(var i=0, j=inPageIndex*this.rowsPerPage; i<this.rowsPerPage; i++, j++){
  36047. this.removeRow(j);
  36048. }
  36049. },
  36050. destroyPage: function(inPageIndex){
  36051. for(var i=0; i<this.colCount; i++){
  36052. var n = this.invalidatePageNode(inPageIndex, this.pageNodes[i]);
  36053. if(n){
  36054. html.destroy(n);
  36055. }
  36056. }
  36057. },
  36058. pacify: function(inShouldPacify){
  36059. },
  36060. // pacification
  36061. pacifying: false,
  36062. pacifyTicks: 200,
  36063. setPacifying: function(inPacifying){
  36064. if(this.pacifying != inPacifying){
  36065. this.pacifying = inPacifying;
  36066. this.pacify(this.pacifying);
  36067. }
  36068. },
  36069. startPacify: function(){
  36070. this.startPacifyTicks = new Date().getTime();
  36071. },
  36072. doPacify: function(){
  36073. var result = (new Date().getTime() - this.startPacifyTicks) > this.pacifyTicks;
  36074. this.setPacifying(true);
  36075. this.startPacify();
  36076. return result;
  36077. },
  36078. endPacify: function(){
  36079. this.setPacifying(false);
  36080. },
  36081. // default sizing implementation
  36082. resize: function(){
  36083. if(this.scrollboxNode){
  36084. this.windowHeight = this.scrollboxNode.clientHeight;
  36085. }
  36086. for(var i=0; i<this.colCount; i++){
  36087. //We want to have 1px in height min to keep scroller. Otherwise can't scroll
  36088. //and see header in empty grid.
  36089. util.setStyleHeightPx(this.contentNodes[i], Math.max(1,this.height));
  36090. }
  36091. // Calculate the average row height and update the defaults (row and page).
  36092. var needPage = (!this._invalidating);
  36093. if(!needPage){
  36094. var ah = this.grid.get("autoHeight");
  36095. if(typeof ah == "number" && ah <= Math.min(this.rowsPerPage, this.rowCount)){
  36096. needPage = true;
  36097. }
  36098. }
  36099. if(needPage){
  36100. this.needPage(this.page, this.pageTop);
  36101. }
  36102. var rowsOnPage = (this.page < this.pageCount - 1) ? this.rowsPerPage : ((this.rowCount % this.rowsPerPage) || this.rowsPerPage);
  36103. var pageHeight = this.getPageHeight(this.page);
  36104. this.averageRowHeight = (pageHeight > 0 && rowsOnPage > 0) ? (pageHeight / rowsOnPage) : 0;
  36105. },
  36106. calcLastPageHeight: function(){
  36107. if(!this.pageCount){
  36108. return 0;
  36109. }
  36110. var lastPage = this.pageCount - 1;
  36111. var lastPageHeight = ((this.rowCount % this.rowsPerPage)||(this.rowsPerPage)) * this.defaultRowHeight;
  36112. this.pageHeights[lastPage] = lastPageHeight;
  36113. return lastPageHeight;
  36114. },
  36115. updateContentHeight: function(inDh){
  36116. this.height += inDh;
  36117. this.resize();
  36118. },
  36119. updatePageHeight: function(inPageIndex, fromBuild, fromAsynRendering){
  36120. if(this.pageExists(inPageIndex)){
  36121. var oh = this.getPageHeight(inPageIndex);
  36122. var h = (this.measurePage(inPageIndex));
  36123. if(h === undefined){
  36124. h = oh;
  36125. }
  36126. this.pageHeights[inPageIndex] = h;
  36127. if(oh != h){
  36128. this.updateContentHeight(h - oh);
  36129. var ah = this.grid.get("autoHeight");
  36130. if((typeof ah == "number" && ah > this.rowCount)||(ah === true && !fromBuild)){
  36131. if(!fromAsynRendering){
  36132. this.grid.sizeChange();
  36133. }else{//fix #11101 by using fromAsynRendering to avoid deadlock
  36134. var ns = this.grid.viewsNode.style;
  36135. ns.height = parseInt(ns.height) + h - oh + 'px';
  36136. this.repositionPages(inPageIndex);
  36137. }
  36138. }else{
  36139. this.repositionPages(inPageIndex);
  36140. }
  36141. }
  36142. return h;
  36143. }
  36144. return 0;
  36145. },
  36146. rowHeightChanged: function(inRowIndex, fromAsynRendering){
  36147. this.updatePageHeight(Math.floor(inRowIndex / this.rowsPerPage), false, fromAsynRendering);
  36148. },
  36149. // scroller core
  36150. invalidateNodes: function(){
  36151. while(this.stack.length){
  36152. this.destroyPage(this.popPage());
  36153. }
  36154. },
  36155. createPageNode: function(){
  36156. var p = document.createElement('div');
  36157. html.attr(p,"role","presentation");
  36158. p.style.position = 'absolute';
  36159. //p.style.width = '100%';
  36160. p.style[this.grid.isLeftToRight() ? "left" : "right"] = '0';
  36161. return p;
  36162. },
  36163. getPageHeight: function(inPageIndex){
  36164. var ph = this.pageHeights[inPageIndex];
  36165. return (ph !== undefined ? ph : this.defaultPageHeight);
  36166. },
  36167. // FIXME: this is not a stack, it's a FIFO list
  36168. pushPage: function(inPageIndex){
  36169. return this.stack.push(inPageIndex);
  36170. },
  36171. popPage: function(){
  36172. return this.stack.shift();
  36173. },
  36174. findPage: function(inTop){
  36175. var i = 0, h = 0;
  36176. for(var ph = 0; i<this.pageCount; i++, h += ph){
  36177. ph = this.getPageHeight(i);
  36178. if(h + ph >= inTop){
  36179. break;
  36180. }
  36181. }
  36182. this.page = i;
  36183. this.pageTop = h;
  36184. },
  36185. buildPage: function(inPageIndex, inReuseNode, inPos){
  36186. this.preparePage(inPageIndex, inReuseNode);
  36187. this.positionPage(inPageIndex, inPos);
  36188. // order of operations is key below
  36189. this.installPage(inPageIndex);
  36190. this.renderPage(inPageIndex);
  36191. // order of operations is key above
  36192. this.pushPage(inPageIndex);
  36193. },
  36194. needPage: function(inPageIndex, inPos){
  36195. var h = this.getPageHeight(inPageIndex), oh = h;
  36196. if(!this.pageExists(inPageIndex)){
  36197. this.buildPage(inPageIndex, (!this.grid._autoHeight/*fix #10543*/ && this.keepPages&&(this.stack.length >= this.keepPages)), inPos);
  36198. h = this.updatePageHeight(inPageIndex, true);
  36199. }else{
  36200. this.positionPage(inPageIndex, inPos);
  36201. }
  36202. return h;
  36203. },
  36204. onscroll: function(){
  36205. this.scroll(this.scrollboxNode.scrollTop);
  36206. },
  36207. scroll: function(inTop){
  36208. this.grid.scrollTop = inTop;
  36209. if(this.colCount){
  36210. this.startPacify();
  36211. this.findPage(inTop);
  36212. var h = this.height;
  36213. var b = this.getScrollBottom(inTop);
  36214. for(var p=this.page, y=this.pageTop; (p<this.pageCount)&&((b<0)||(y<b)); p++){
  36215. y += this.needPage(p, y);
  36216. }
  36217. this.firstVisibleRow = this.getFirstVisibleRow(this.page, this.pageTop, inTop);
  36218. this.lastVisibleRow = this.getLastVisibleRow(p - 1, y, b);
  36219. // indicates some page size has been updated
  36220. if(h != this.height){
  36221. this.repositionPages(p-1);
  36222. }
  36223. this.endPacify();
  36224. }
  36225. },
  36226. getScrollBottom: function(inTop){
  36227. return (this.windowHeight >= 0 ? inTop + this.windowHeight : -1);
  36228. },
  36229. // events
  36230. processNodeEvent: function(e, inNode){
  36231. var t = e.target;
  36232. while(t && (t != inNode) && t.parentNode && (t.parentNode.parentNode != inNode)){
  36233. t = t.parentNode;
  36234. }
  36235. if(!t || !t.parentNode || (t.parentNode.parentNode != inNode)){
  36236. return false;
  36237. }
  36238. var page = t.parentNode;
  36239. e.topRowIndex = page.pageIndex * this.rowsPerPage;
  36240. e.rowIndex = e.topRowIndex + indexInParent(t);
  36241. e.rowTarget = t;
  36242. return true;
  36243. },
  36244. processEvent: function(e){
  36245. return this.processNodeEvent(e, this.contentNode);
  36246. },
  36247. // virtual rendering interface
  36248. renderRow: function(inRowIndex, inPageNode){
  36249. },
  36250. removeRow: function(inRowIndex){
  36251. },
  36252. // page node operations
  36253. getDefaultPageNode: function(inPageIndex){
  36254. return this.getDefaultNodes()[inPageIndex];
  36255. },
  36256. positionPageNode: function(inNode, inPos){
  36257. },
  36258. getPageNodePosition: function(inNode){
  36259. return inNode.offsetTop;
  36260. },
  36261. invalidatePageNode: function(inPageIndex, inNodes){
  36262. var p = inNodes[inPageIndex];
  36263. if(p){
  36264. delete inNodes[inPageIndex];
  36265. this.removePage(inPageIndex, p);
  36266. cleanNode(p);
  36267. p.innerHTML = '';
  36268. }
  36269. return p;
  36270. },
  36271. // scroll control
  36272. getPageRow: function(inPage){
  36273. return inPage * this.rowsPerPage;
  36274. },
  36275. getLastPageRow: function(inPage){
  36276. return Math.min(this.rowCount, this.getPageRow(inPage + 1)) - 1;
  36277. },
  36278. getFirstVisibleRow: function(inPage, inPageTop, inScrollTop){
  36279. if(!this.pageExists(inPage)){
  36280. return 0;
  36281. }
  36282. var row = this.getPageRow(inPage);
  36283. var nodes = this.getDefaultNodes();
  36284. var rows = divkids(nodes[inPage]);
  36285. for(var i=0,l=rows.length; i<l && inPageTop<inScrollTop; i++, row++){
  36286. inPageTop += rows[i].offsetHeight;
  36287. }
  36288. return (row ? row - 1 : row);
  36289. },
  36290. getLastVisibleRow: function(inPage, inBottom, inScrollBottom){
  36291. if(!this.pageExists(inPage)){
  36292. return 0;
  36293. }
  36294. var nodes = this.getDefaultNodes();
  36295. var row = this.getLastPageRow(inPage);
  36296. var rows = divkids(nodes[inPage]);
  36297. for(var i=rows.length-1; i>=0 && inBottom>inScrollBottom; i--, row--){
  36298. inBottom -= rows[i].offsetHeight;
  36299. }
  36300. return row + 1;
  36301. },
  36302. findTopRow: function(inScrollTop){
  36303. var nodes = this.getDefaultNodes();
  36304. var rows = divkids(nodes[this.page]);
  36305. for(var i=0,l=rows.length,t=this.pageTop,h; i<l; i++){
  36306. h = rows[i].offsetHeight;
  36307. t += h;
  36308. if(t >= inScrollTop){
  36309. this.offset = h - (t - inScrollTop);
  36310. return i + this.page * this.rowsPerPage;
  36311. }
  36312. }
  36313. return -1;
  36314. },
  36315. findScrollTop: function(inRow){
  36316. var rowPage = Math.floor(inRow / this.rowsPerPage);
  36317. var t = 0;
  36318. var i, l;
  36319. for(i=0; i<rowPage; i++){
  36320. t += this.getPageHeight(i);
  36321. }
  36322. this.pageTop = t;
  36323. this.page = rowPage;//fix #10543
  36324. this.needPage(rowPage, this.pageTop);
  36325. var nodes = this.getDefaultNodes();
  36326. var rows = divkids(nodes[rowPage]);
  36327. var r = inRow - this.rowsPerPage * rowPage;
  36328. for(i=0,l=rows.length; i<l && i<r; i++){
  36329. t += rows[i].offsetHeight;
  36330. }
  36331. return t;
  36332. },
  36333. dummy: 0
  36334. });
  36335. });
  36336. },
  36337. 'dijit/Calendar':function(){
  36338. define("dijit/Calendar", [
  36339. "dojo/_base/array", // array.map
  36340. "dojo/date",
  36341. "dojo/date/locale",
  36342. "dojo/_base/declare", // declare
  36343. "dojo/dom-attr", // domAttr.get
  36344. "dojo/dom-class", // domClass.add domClass.contains domClass.remove domClass.toggle
  36345. "dojo/_base/event", // event.stop
  36346. "dojo/_base/kernel", // kernel.deprecated
  36347. "dojo/keys", // keys
  36348. "dojo/_base/lang", // lang.hitch
  36349. "dojo/_base/sniff", // has("ie")
  36350. "./CalendarLite",
  36351. "./_Widget",
  36352. "./_CssStateMixin",
  36353. "./_TemplatedMixin",
  36354. "./form/DropDownButton",
  36355. "./hccss" // not used directly, but sets CSS class on <body>
  36356. ], function(array, date, local, declare, domAttr, domClass, event, kernel, keys, lang, has,
  36357. CalendarLite, _Widget, _CssStateMixin, _TemplatedMixin, DropDownButton){
  36358. /*=====
  36359. var CalendarLite = dijit.CalendarLite;
  36360. var _CssStateMixin = dijit._CssStateMixin;
  36361. var _Widget = dijit._Widget;
  36362. var _TemplatedMixin = dijit._TemplatedMixin;
  36363. var DropDownButton = dijit.form.DropDownButton;
  36364. =====*/
  36365. // module:
  36366. // dijit/Calendar
  36367. // summary:
  36368. // A simple GUI for choosing a date in the context of a monthly calendar.
  36369. var Calendar = declare("dijit.Calendar",
  36370. [CalendarLite, _Widget, _CssStateMixin], // _Widget for deprecated methods like setAttribute()
  36371. {
  36372. // summary:
  36373. // A simple GUI for choosing a date in the context of a monthly calendar.
  36374. //
  36375. // description:
  36376. // See CalendarLite for general description. Calendar extends CalendarLite, adding:
  36377. // - month drop down list
  36378. // - keyboard navigation
  36379. // - CSS classes for hover/mousepress on date, month, and year nodes
  36380. // - support of deprecated methods (will be removed in 2.0)
  36381. // Set node classes for various mouse events, see dijit._CssStateMixin for more details
  36382. cssStateNodes: {
  36383. "decrementMonth": "dijitCalendarArrow",
  36384. "incrementMonth": "dijitCalendarArrow",
  36385. "previousYearLabelNode": "dijitCalendarPreviousYear",
  36386. "nextYearLabelNode": "dijitCalendarNextYear"
  36387. },
  36388. setValue: function(/*Date*/ value){
  36389. // summary:
  36390. // Deprecated. Use set('value', ...) instead.
  36391. // tags:
  36392. // deprecated
  36393. kernel.deprecated("dijit.Calendar:setValue() is deprecated. Use set('value', ...) instead.", "", "2.0");
  36394. this.set('value', value);
  36395. },
  36396. _createMonthWidget: function(){
  36397. // summary:
  36398. // Creates the drop down button that displays the current month and lets user pick a new one
  36399. return new Calendar._MonthDropDownButton({
  36400. id: this.id + "_mddb",
  36401. tabIndex: -1,
  36402. onMonthSelect: lang.hitch(this, "_onMonthSelect"),
  36403. lang: this.lang,
  36404. dateLocaleModule: this.dateLocaleModule
  36405. }, this.monthNode);
  36406. },
  36407. buildRendering: function(){
  36408. this.inherited(arguments);
  36409. // Events specific to Calendar, not used in CalendarLite
  36410. this.connect(this.domNode, "onkeypress", "_onKeyPress");
  36411. this.connect(this.dateRowsNode, "onmouseover", "_onDayMouseOver");
  36412. this.connect(this.dateRowsNode, "onmouseout", "_onDayMouseOut");
  36413. this.connect(this.dateRowsNode, "onmousedown", "_onDayMouseDown");
  36414. this.connect(this.dateRowsNode, "onmouseup", "_onDayMouseUp");
  36415. },
  36416. _onMonthSelect: function(/*Number*/ newMonth){
  36417. // summary:
  36418. // Handler for when user selects a month from the drop down list
  36419. // tags:
  36420. // protected
  36421. // move to selected month, bounding by the number of days in the month
  36422. // (ex: dec 31 --> jan 28, not jan 31)
  36423. this._setCurrentFocusAttr(this.dateFuncObj.add(this.currentFocus, "month",
  36424. newMonth - this.currentFocus.getMonth()));
  36425. },
  36426. _onDayMouseOver: function(/*Event*/ evt){
  36427. // summary:
  36428. // Handler for mouse over events on days, sets hovered style
  36429. // tags:
  36430. // protected
  36431. // event can occur on <td> or the <span> inside the td,
  36432. // set node to the <td>.
  36433. var node =
  36434. domClass.contains(evt.target, "dijitCalendarDateLabel") ?
  36435. evt.target.parentNode :
  36436. evt.target;
  36437. if(node && (
  36438. (node.dijitDateValue && !domClass.contains(node, "dijitCalendarDisabledDate"))
  36439. || node == this.previousYearLabelNode || node == this.nextYearLabelNode
  36440. )){
  36441. domClass.add(node, "dijitCalendarHoveredDate");
  36442. this._currentNode = node;
  36443. }
  36444. },
  36445. _onDayMouseOut: function(/*Event*/ evt){
  36446. // summary:
  36447. // Handler for mouse out events on days, clears hovered style
  36448. // tags:
  36449. // protected
  36450. if(!this._currentNode){ return; }
  36451. // if mouse out occurs moving from <td> to <span> inside <td>, ignore it
  36452. if(evt.relatedTarget && evt.relatedTarget.parentNode == this._currentNode){ return; }
  36453. var cls = "dijitCalendarHoveredDate";
  36454. if(domClass.contains(this._currentNode, "dijitCalendarActiveDate")){
  36455. cls += " dijitCalendarActiveDate";
  36456. }
  36457. domClass.remove(this._currentNode, cls);
  36458. this._currentNode = null;
  36459. },
  36460. _onDayMouseDown: function(/*Event*/ evt){
  36461. var node = evt.target.parentNode;
  36462. if(node && node.dijitDateValue && !domClass.contains(node, "dijitCalendarDisabledDate")){
  36463. domClass.add(node, "dijitCalendarActiveDate");
  36464. this._currentNode = node;
  36465. }
  36466. },
  36467. _onDayMouseUp: function(/*Event*/ evt){
  36468. var node = evt.target.parentNode;
  36469. if(node && node.dijitDateValue){
  36470. domClass.remove(node, "dijitCalendarActiveDate");
  36471. }
  36472. },
  36473. handleKey: function(/*Event*/ evt){
  36474. // summary:
  36475. // Provides keyboard navigation of calendar.
  36476. // description:
  36477. // Called from _onKeyPress() to handle keypress on a stand alone Calendar,
  36478. // and also from `dijit.form._DateTimeTextBox` to pass a keypress event
  36479. // from the `dijit.form.DateTextBox` to be handled in this widget
  36480. // returns:
  36481. // False if the key was recognized as a navigation key,
  36482. // to indicate that the event was handled by Calendar and shouldn't be propogated
  36483. // tags:
  36484. // protected
  36485. var increment = -1,
  36486. interval,
  36487. newValue = this.currentFocus;
  36488. switch(evt.charOrCode){
  36489. case keys.RIGHT_ARROW:
  36490. increment = 1;
  36491. //fallthrough...
  36492. case keys.LEFT_ARROW:
  36493. interval = "day";
  36494. if(!this.isLeftToRight()){ increment *= -1; }
  36495. break;
  36496. case keys.DOWN_ARROW:
  36497. increment = 1;
  36498. //fallthrough...
  36499. case keys.UP_ARROW:
  36500. interval = "week";
  36501. break;
  36502. case keys.PAGE_DOWN:
  36503. increment = 1;
  36504. //fallthrough...
  36505. case keys.PAGE_UP:
  36506. interval = evt.ctrlKey || evt.altKey ? "year" : "month";
  36507. break;
  36508. case keys.END:
  36509. // go to the next month
  36510. newValue = this.dateFuncObj.add(newValue, "month", 1);
  36511. // subtract a day from the result when we're done
  36512. interval = "day";
  36513. //fallthrough...
  36514. case keys.HOME:
  36515. newValue = new this.dateClassObj(newValue);
  36516. newValue.setDate(1);
  36517. break;
  36518. case keys.ENTER:
  36519. case " ":
  36520. this.set("value", this.currentFocus);
  36521. break;
  36522. default:
  36523. return true;
  36524. }
  36525. if(interval){
  36526. newValue = this.dateFuncObj.add(newValue, interval, increment);
  36527. }
  36528. this._setCurrentFocusAttr(newValue);
  36529. return false;
  36530. },
  36531. _onKeyPress: function(/*Event*/ evt){
  36532. // summary:
  36533. // For handling keypress events on a stand alone calendar
  36534. if(!this.handleKey(evt)){
  36535. event.stop(evt);
  36536. }
  36537. },
  36538. onValueSelected: function(/*Date*/ /*===== date =====*/){
  36539. // summary:
  36540. // Deprecated. Notification that a date cell was selected. It may be the same as the previous value.
  36541. // description:
  36542. // Formerly used by `dijit.form._DateTimeTextBox` (and thus `dijit.form.DateTextBox`)
  36543. // to get notification when the user has clicked a date. Now onExecute() (above) is used.
  36544. // tags:
  36545. // protected
  36546. },
  36547. onChange: function(value){
  36548. this.onValueSelected(value); // remove in 2.0
  36549. },
  36550. getClassForDate: function(/*===== dateObject, locale =====*/){
  36551. // summary:
  36552. // May be overridden to return CSS classes to associate with the date entry for the given dateObject,
  36553. // for example to indicate a holiday in specified locale.
  36554. // dateObject: Date
  36555. // locale: String?
  36556. // tags:
  36557. // extension
  36558. /*=====
  36559. return ""; // String
  36560. =====*/
  36561. }
  36562. });
  36563. Calendar._MonthDropDownButton = declare("dijit.Calendar._MonthDropDownButton", DropDownButton, {
  36564. // summary:
  36565. // DropDownButton for the current month. Displays name of current month
  36566. // and a list of month names in the drop down
  36567. onMonthSelect: function(){ },
  36568. postCreate: function(){
  36569. this.inherited(arguments);
  36570. this.dropDown = new Calendar._MonthDropDown({
  36571. id: this.id + "_mdd", //do not change this id because it is referenced in the template
  36572. onChange: this.onMonthSelect
  36573. });
  36574. },
  36575. _setMonthAttr: function(month){
  36576. // summary:
  36577. // Set the current month to display as a label
  36578. var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, month);
  36579. this.dropDown.set("months", monthNames);
  36580. // Set name of current month and also fill in spacer element with all the month names
  36581. // (invisible) so that the maximum width will affect layout. But not on IE6 because then
  36582. // the center <TH> overlaps the right <TH> (due to a browser bug).
  36583. this.containerNode.innerHTML =
  36584. (has("ie") == 6 ? "" : "<div class='dijitSpacer'>" + this.dropDown.domNode.innerHTML + "</div>") +
  36585. "<div class='dijitCalendarMonthLabel dijitCalendarCurrentMonthLabel'>" + monthNames[month.getMonth()] + "</div>";
  36586. }
  36587. });
  36588. Calendar._MonthDropDown = declare("dijit.Calendar._MonthDropDown", [_Widget, _TemplatedMixin], {
  36589. // summary:
  36590. // The list-of-months drop down from the MonthDropDownButton
  36591. // months: String[]
  36592. // List of names of months, possibly w/some undefined entries for Hebrew leap months
  36593. // (ex: ["January", "February", undefined, "April", ...])
  36594. months: [],
  36595. templateString: "<div class='dijitCalendarMonthMenu dijitMenu' " +
  36596. "data-dojo-attach-event='onclick:_onClick,onmouseover:_onMenuHover,onmouseout:_onMenuHover'></div>",
  36597. _setMonthsAttr: function(/*String[]*/ months){
  36598. this.domNode.innerHTML = array.map(months, function(month, idx){
  36599. return month ? "<div class='dijitCalendarMonthLabel' month='" + idx +"'>" + month + "</div>" : "";
  36600. }).join("");
  36601. },
  36602. _onClick: function(/*Event*/ evt){
  36603. this.onChange(domAttr.get(evt.target, "month"));
  36604. },
  36605. onChange: function(/*Number*/ /*===== month =====*/){
  36606. // summary:
  36607. // Callback when month is selected from drop down
  36608. },
  36609. _onMenuHover: function(evt){
  36610. domClass.toggle(evt.target, "dijitCalendarMonthLabelHover", evt.type == "mouseover");
  36611. }
  36612. });
  36613. return Calendar;
  36614. });
  36615. },
  36616. 'dijit/form/_ToggleButtonMixin':function(){
  36617. define("dijit/form/_ToggleButtonMixin", [
  36618. "dojo/_base/declare", // declare
  36619. "dojo/dom-attr" // domAttr.set
  36620. ], function(declare, domAttr){
  36621. // module:
  36622. // dijit/form/_ToggleButtonMixin
  36623. // summary:
  36624. // A mixin to provide functionality to allow a button that can be in two states (checked or not).
  36625. return declare("dijit.form._ToggleButtonMixin", null, {
  36626. // summary:
  36627. // A mixin to provide functionality to allow a button that can be in two states (checked or not).
  36628. // checked: Boolean
  36629. // Corresponds to the native HTML <input> element's attribute.
  36630. // In markup, specified as "checked='checked'" or just "checked".
  36631. // True if the button is depressed, or the checkbox is checked,
  36632. // or the radio button is selected, etc.
  36633. checked: false,
  36634. // aria-pressed for toggle buttons, and aria-checked for checkboxes
  36635. _aria_attr: "aria-pressed",
  36636. _onClick: function(/*Event*/ evt){
  36637. var original = this.checked;
  36638. this._set('checked', !original); // partially set the toggled value, assuming the toggle will work, so it can be overridden in the onclick handler
  36639. var ret = this.inherited(arguments); // the user could reset the value here
  36640. this.set('checked', ret ? this.checked : original); // officially set the toggled or user value, or reset it back
  36641. return ret;
  36642. },
  36643. _setCheckedAttr: function(/*Boolean*/ value, /*Boolean?*/ priorityChange){
  36644. this._set("checked", value);
  36645. domAttr.set(this.focusNode || this.domNode, "checked", value);
  36646. (this.focusNode || this.domNode).setAttribute(this._aria_attr, value ? "true" : "false"); // aria values should be strings
  36647. this._handleOnChange(value, priorityChange);
  36648. },
  36649. reset: function(){
  36650. // summary:
  36651. // Reset the widget's value to what it was at initialization time
  36652. this._hasBeenBlurred = false;
  36653. // set checked state to original setting
  36654. this.set('checked', this.params.checked || false);
  36655. }
  36656. });
  36657. });
  36658. },
  36659. 'dojox/grid/enhanced/plugins/Selector':function(){
  36660. define("dojox/grid/enhanced/plugins/Selector", [
  36661. "dojo/_base/kernel",
  36662. "dojo/_base/lang",
  36663. "dojo/_base/declare",
  36664. "dojo/_base/array",
  36665. "dojo/_base/event",
  36666. "dojo/keys",
  36667. "dojo/query",
  36668. "dojo/_base/html",
  36669. "dojo/_base/window",
  36670. "dijit/focus",
  36671. "../../_RowSelector",
  36672. "../_Plugin",
  36673. "../../EnhancedGrid",
  36674. "../../cells/_base",
  36675. "./AutoScroll"
  36676. ], function(dojo, lang, declare, array, event, keys, query, html, win, dijitFocus, _RowSelector, _Plugin, EnhancedGrid){
  36677. /*=====
  36678. dojo.declare("__SelectItem", null,{
  36679. // summary:
  36680. // An abstract representation of an item.
  36681. });
  36682. dojo.declare("__SelectCellItem", __SelectItem,{
  36683. // summary:
  36684. // An abstract representation of a cell.
  36685. // row: Integer
  36686. // Row index of this cell
  36687. row: 0,
  36688. // col: Integer
  36689. // Column index of this cell
  36690. col: 0
  36691. });
  36692. dojo.declare("__SelectRowItem", __SelectItem,{
  36693. // summary:
  36694. // An abstract representation of a row.
  36695. // row: Integer
  36696. // Row index of this row
  36697. row: 0,
  36698. // except: Integer[]
  36699. // An array of column indexes of all the unselected cells in this row.
  36700. except: []
  36701. });
  36702. dojo.declare("__SelectColItem", __SelectItem,{
  36703. // summary:
  36704. // An abstract representation of a column.
  36705. // col: Integer
  36706. // Column index of this column
  36707. col: 0,
  36708. // except: Integer[]
  36709. // An array of row indexes of all the unselected cells in this column.
  36710. except: []
  36711. });
  36712. =====*/
  36713. var DISABLED = 0, SINGLE = 1, MULTI = 2,
  36714. _theOther = { col: "row", row: "col" },
  36715. _inRange = function(type, value, start, end, halfClose){
  36716. if(type !== "cell"){
  36717. value = value[type];
  36718. start = start[type];
  36719. end = end[type];
  36720. if(typeof value !== "number" || typeof start !== "number" || typeof end !== "number"){
  36721. return false;
  36722. }
  36723. return halfClose ? ((value >= start && value < end) || (value > end && value <= start))
  36724. : ((value >= start && value <= end) || (value >= end && value <= start));
  36725. }else{
  36726. return _inRange("col", value, start, end, halfClose) && _inRange("row", value, start, end, halfClose);
  36727. }
  36728. },
  36729. _isEqual = function(type, v1, v2){
  36730. try{
  36731. if(v1 && v2){
  36732. switch(type){
  36733. case "col": case "row":
  36734. return v1[type] == v2[type] && typeof v1[type] == "number" &&
  36735. !(_theOther[type] in v1) && !(_theOther[type] in v2);
  36736. case "cell":
  36737. return v1.col == v2.col && v1.row == v2.row && typeof v1.col == "number" && typeof v1.row == "number";
  36738. }
  36739. }
  36740. }catch(e){}
  36741. return false;
  36742. },
  36743. _stopEvent = function(evt){
  36744. try{
  36745. if(evt && evt.preventDefault){
  36746. event.stop(evt);
  36747. }
  36748. }catch(e){}
  36749. },
  36750. _createItem = function(type, rowIndex, colIndex){
  36751. switch(type){
  36752. case "col":
  36753. return {
  36754. "col": typeof colIndex == "undefined" ? rowIndex : colIndex,
  36755. "except": []
  36756. };
  36757. case "row":
  36758. return {
  36759. "row": rowIndex,
  36760. "except": []
  36761. };
  36762. case "cell":
  36763. return {
  36764. "row": rowIndex,
  36765. "col": colIndex
  36766. };
  36767. }
  36768. return null;
  36769. };
  36770. var Selector = declare("dojox.grid.enhanced.plugins.Selector", _Plugin, {
  36771. // summary:
  36772. // Provides standard extended selection for grid.
  36773. // Supports mouse/keyboard selection, multi-selection, and de-selection.
  36774. // Acceptable plugin parameters:
  36775. // The whole plugin parameter object is a config object passed to the setupConfig function.
  36776. //
  36777. // Acceptable cell parameters defined in layout:
  36778. // 1. notselectable: boolean
  36779. // Whether this column is (and all the cells in it are) selectable.
  36780. // name: String
  36781. // plugin name
  36782. name: "selector",
  36783. // noClear: Boolean
  36784. // Not to clear rows selected by IndirectSelection.
  36785. /*
  36786. // _config: null,
  36787. // _enabled: true,
  36788. // _selecting: {
  36789. // row: false,
  36790. // col: false,
  36791. // cell: false
  36792. // },
  36793. // _selected: {
  36794. // row: [],
  36795. // col: [],
  36796. // cell: []
  36797. // },
  36798. // _startPoint: {},
  36799. // _currentPoint: {},
  36800. // _lastAnchorPoint: {},
  36801. // _lastEndPoint: {},
  36802. // _lastSelectedAnchorPoint: {},
  36803. // _lastSelectedEndPoint: {},
  36804. // _keyboardSelect: {
  36805. // row: 0,
  36806. // col: 0,
  36807. // cell: 0
  36808. // },
  36809. // _curType: null,
  36810. // _lastType: null,
  36811. // _usingKeyboard: false,
  36812. // _toSelect: true,
  36813. */
  36814. constructor: function(grid, args){
  36815. this.grid = grid;
  36816. this._config = {
  36817. row: MULTI,
  36818. col: MULTI,
  36819. cell: MULTI
  36820. };
  36821. this.noClear = args && args.noClear;
  36822. this.setupConfig(args);
  36823. if(grid.selectionMode === "single"){
  36824. this._config.row = SINGLE;
  36825. }
  36826. this._enabled = true;
  36827. this._selecting = {};
  36828. this._selected = {
  36829. "col": [],
  36830. "row": [],
  36831. "cell": []
  36832. };
  36833. this._startPoint = {};
  36834. this._currentPoint = {};
  36835. this._lastAnchorPoint = {};
  36836. this._lastEndPoint = {};
  36837. this._lastSelectedAnchorPoint = {};
  36838. this._lastSelectedEndPoint = {};
  36839. this._keyboardSelect = {};
  36840. this._lastType = null;
  36841. this._selectedRowModified = {};
  36842. this._hacks();
  36843. this._initEvents();
  36844. this._initAreas();
  36845. this._mixinGrid();
  36846. },
  36847. destroy: function(){
  36848. this.inherited(arguments);
  36849. },
  36850. //------------public--------------------
  36851. setupConfig: function(config){
  36852. // summary:
  36853. // Set selection mode for row/col/cell.
  36854. // config: Object
  36855. // An object with the following structure (all properties are optional):
  36856. // {
  36857. // //Default is "multi", all other values are same as "multi".
  36858. // row: false|"disabled"|"single",
  36859. // col: false|"disabled"|"single",
  36860. // cell: false|"disabled"|"single"
  36861. // }
  36862. if(!config || !lang.isObject(config)){
  36863. return;
  36864. }
  36865. var types = ["row", "col", "cell"];
  36866. for(var type in config){
  36867. if(array.indexOf(types, type) >= 0){
  36868. if(!config[type] || config[type] == "disabled"){
  36869. this._config[type] = DISABLED;
  36870. }else if(config[type] == "single"){
  36871. this._config[type] = SINGLE;
  36872. }else{
  36873. this._config[type] = MULTI;
  36874. }
  36875. }
  36876. }
  36877. //Have to set mode to default grid selection.
  36878. var mode = ["none","single","extended"][this._config.row];
  36879. this.grid.selection.setMode(mode);
  36880. },
  36881. isSelected: function(type, rowIndex, colIndex){
  36882. // summary:
  36883. // Check whether a location (a cell, a column or a row) is selected.
  36884. // tag:
  36885. // public
  36886. // type: String
  36887. // "row" or "col" or "cell"
  36888. // rowIndex: Integer
  36889. // If type is "row" or "cell", this is the row index.
  36890. // If type if "col", this is the column index.
  36891. // colIndex: Integer?
  36892. // Only valid when type is "cell"
  36893. // return: Boolean
  36894. // true if selected, false if not. If cell is covered by a selected column, it's selected.
  36895. return this._isSelected(type, _createItem(type, rowIndex, colIndex));
  36896. },
  36897. toggleSelect: function(type, rowIndex, colIndex){
  36898. this._startSelect(type, _createItem(type, rowIndex, colIndex), this._config[type] === MULTI, false, false, !this.isSelected(type, rowIndex, colIndex));
  36899. this._endSelect(type);
  36900. },
  36901. select: function(type, rowIndex, colIndex){
  36902. // summary:
  36903. // Select a location (a cell, a column or a row).
  36904. // tag:
  36905. // public
  36906. // type: String
  36907. // "row" or "col" or "cell"
  36908. // rowIndex: Integer
  36909. // If type is "row" or "cell", this is the row index.
  36910. // If type if "col", this is the column index.
  36911. // colIndex: Integer?
  36912. // Only valid when type is "cell"
  36913. if(!this.isSelected(type, rowIndex, colIndex)){
  36914. this.toggleSelect(type, rowIndex, colIndex);
  36915. }
  36916. },
  36917. deselect: function(type, rowIndex, colIndex){
  36918. if(this.isSelected(type, rowIndex, colIndex)){
  36919. this.toggleSelect(type, rowIndex, colIndex);
  36920. }
  36921. },
  36922. selectRange: function(type, start, end, toSelect){
  36923. // summary:
  36924. // Select a continuous range (a block of cells, a set of continuous columns or rows)
  36925. // tag:
  36926. // public
  36927. // type: String
  36928. // "row" or "col" or "cell"
  36929. // start: Integer | Object
  36930. // If type is "row" or "col", this is the index of the starting row or column.
  36931. // If type if "cell", this is the left-top cell of the range.
  36932. // end: Integer | Object
  36933. // If type is "row" or "col", this is the index of the ending row or column.
  36934. // If type if "cell", this is the right-bottom cell of the range.
  36935. this.grid._selectingRange = true;
  36936. var startPoint = type == "cell" ? _createItem(type, start.row, start.col) : _createItem(type, start),
  36937. endPoint = type == "cell" ? _createItem(type, end.row, end.col) : _createItem(type, end);
  36938. this._startSelect(type, startPoint, false, false, false, toSelect);
  36939. this._highlight(type, endPoint, toSelect === undefined ? true : toSelect);
  36940. this._endSelect(type);
  36941. this.grid._selectingRange = false;
  36942. },
  36943. clear: function(type){
  36944. // summary:
  36945. // Clear all selections.
  36946. // tag:
  36947. // public
  36948. // type: String?
  36949. // "row" or "col" or "cell". If omitted, clear all.
  36950. this._clearSelection(type || "all");
  36951. },
  36952. isSelecting: function(type){
  36953. // summary:
  36954. // Check whether the user is currently selecting something.
  36955. // tag:
  36956. // public
  36957. // type: String
  36958. // "row" or "col" or "cell"
  36959. // return: Boolean
  36960. // true if is selection, false otherwise.
  36961. if(typeof type == "undefined"){
  36962. return this._selecting.col || this._selecting.row || this._selecting.cell;
  36963. }
  36964. return this._selecting[type];
  36965. },
  36966. selectEnabled: function(toEnable){
  36967. // summary:
  36968. // Turn on/off this selection functionality if *toEnable* is provided.
  36969. // Check whether this selection functionality is enabled if nothing is passed in.
  36970. // tag:
  36971. // public
  36972. // toEnable: Boolean?
  36973. // To enable or not. Optional.
  36974. // return: Boolean | undefined
  36975. // Enabled or not.
  36976. if(typeof toEnable != "undefined" && !this.isSelecting()){
  36977. this._enabled = !!toEnable;
  36978. }
  36979. return this._enabled;
  36980. },
  36981. getSelected: function(type, includeExceptions){
  36982. // summary:
  36983. // Get an array of selected locations.
  36984. // tag:
  36985. // public
  36986. // type: String
  36987. // "row" or "col" or "cell"
  36988. // includeExceptions: Boolean
  36989. // Only meaningful for rows/columns. If true, all selected rows/cols, even they are partly selected, are all returned.
  36990. // return: __SelectItem[]
  36991. switch(type){
  36992. case "cell":
  36993. return array.map(this._selected[type], function(item){ return item; });
  36994. case "col": case "row":
  36995. return array.map(includeExceptions ? this._selected[type]
  36996. : array.filter(this._selected[type], function(item){
  36997. return item.except.length === 0;
  36998. }), function(item){
  36999. return includeExceptions ? item : item[type];
  37000. });
  37001. }
  37002. return [];
  37003. },
  37004. getSelectedCount: function(type, includeExceptions){
  37005. // summary:
  37006. // Get the number of selected items.
  37007. // tag:
  37008. // public
  37009. // type: String
  37010. // "row" or "col" or "cell"
  37011. // includeExceptions: Boolean
  37012. // Only meaningful for rows/columns. If true, all selected rows/cols, even they are partly selected, are all returned.
  37013. // return: Integer
  37014. // The number of selected items.
  37015. switch(type){
  37016. case "cell":
  37017. return this._selected[type].length;
  37018. case "col": case "row":
  37019. return (includeExceptions ? this._selected[type]
  37020. : array.filter(this._selected[type], function(item){
  37021. return item.except.length === 0;
  37022. })).length;
  37023. }
  37024. return 0;
  37025. },
  37026. getSelectedType: function(){
  37027. // summary:
  37028. // Get the type of selected items.
  37029. // tag:
  37030. // public
  37031. // return: String
  37032. // "row" or "col" or "cell", or any mix of these (separator is | ).
  37033. var s = this._selected;
  37034. return ["", "cell", "row", "row|cell",
  37035. "col", "col|cell", "col|row", "col|row|cell"
  37036. ][(!!s.cell.length) | (!!s.row.length << 1) | (!!s.col.length << 2)];
  37037. },
  37038. getLastSelectedRange: function(type){
  37039. // summary:
  37040. // Get last selected range of the given type.
  37041. // tag:
  37042. // public
  37043. // return: Object
  37044. // {start: __SelectItem, end: __SelectItem}
  37045. // return null if nothing is selected.
  37046. return this._lastAnchorPoint[type] ? {
  37047. "start": this._lastAnchorPoint[type],
  37048. "end": this._lastEndPoint[type]
  37049. } : null;
  37050. },
  37051. //--------------------------private----------------------------
  37052. _hacks: function(){
  37053. // summary:
  37054. // Complete the event system of grid, hack some grid functions to prevent default behavior.
  37055. var g = this.grid;
  37056. var doContentMouseUp = function(e){
  37057. if(e.cellNode){
  37058. g.onMouseUp(e);
  37059. }
  37060. g.onMouseUpRow(e);
  37061. };
  37062. var mouseUp = lang.hitch(g, "onMouseUp");
  37063. var mouseDown = lang.hitch(g, "onMouseDown");
  37064. var doRowSelectorFocus = function(e){
  37065. e.cellNode.style.border = "solid 1px";
  37066. };
  37067. array.forEach(g.views.views, function(view){
  37068. view.content.domouseup = doContentMouseUp;
  37069. view.header.domouseup = mouseUp;
  37070. if(view.declaredClass == "dojox.grid._RowSelector"){
  37071. view.domousedown = mouseDown;
  37072. view.domouseup = mouseUp;
  37073. view.dofocus = doRowSelectorFocus;
  37074. }
  37075. });
  37076. //Disable default selection.
  37077. g.selection.clickSelect = function(){};
  37078. this._oldDeselectAll = g.selection.deselectAll;
  37079. var _this = this;
  37080. g.selection.selectRange = function(from, to){
  37081. _this.selectRange("row", from, to, true);
  37082. if(g.selection.preserver){
  37083. g.selection.preserver._updateMapping(true, true, false, from, to);
  37084. }
  37085. g.selection.onChanged();
  37086. };
  37087. g.selection.deselectRange = function(from, to){
  37088. _this.selectRange("row", from, to, false);
  37089. if(g.selection.preserver){
  37090. g.selection.preserver._updateMapping(true, false, false, from, to);
  37091. }
  37092. g.selection.onChanged();
  37093. };
  37094. g.selection.deselectAll = function(){
  37095. g._selectingRange = true;
  37096. _this._oldDeselectAll.apply(g.selection, arguments);
  37097. _this._clearSelection("all");
  37098. g._selectingRange = false;
  37099. if(g.selection.preserver){
  37100. g.selection.preserver._updateMapping(true, false, true);
  37101. }
  37102. g.selection.onChanged();
  37103. };
  37104. var rowSelector = g.views.views[0];
  37105. //The default function re-write the whole className, so can not insert any other classes.
  37106. if(rowSelector instanceof _RowSelector){
  37107. rowSelector.doStyleRowNode = function(inRowIndex, inRowNode){
  37108. html.removeClass(inRowNode, "dojoxGridRow");
  37109. html.addClass(inRowNode, "dojoxGridRowbar");
  37110. html.addClass(inRowNode, "dojoxGridNonNormalizedCell");
  37111. html.toggleClass(inRowNode, "dojoxGridRowbarOver", g.rows.isOver(inRowIndex));
  37112. html.toggleClass(inRowNode, "dojoxGridRowbarSelected", !!g.selection.isSelected(inRowIndex));
  37113. };
  37114. }
  37115. this.connect(g, "updateRow", function(rowIndex){
  37116. array.forEach(g.layout.cells, function(cell){
  37117. if(this.isSelected("cell", rowIndex, cell.index)){
  37118. this._highlightNode(cell.getNode(rowIndex), true);
  37119. }
  37120. }, this);
  37121. });
  37122. },
  37123. _mixinGrid: function(){
  37124. // summary:
  37125. // Expose events to grid.
  37126. var g = this.grid;
  37127. g.setupSelectorConfig = lang.hitch(this, this.setupConfig);
  37128. g.onStartSelect = function(){};
  37129. g.onEndSelect = function(){};
  37130. g.onStartDeselect = function(){};
  37131. g.onEndDeselect = function(){};
  37132. g.onSelectCleared = function(){};
  37133. },
  37134. _initEvents: function(){
  37135. // summary:
  37136. // Connect events, create event handlers.
  37137. var g = this.grid,
  37138. _this = this,
  37139. dp = lang.partial,
  37140. starter = function(type, e){
  37141. if(type === "row"){
  37142. _this._isUsingRowSelector = true;
  37143. }
  37144. //only left mouse button can select.
  37145. if(_this.selectEnabled() && _this._config[type] && e.button != 2){
  37146. if(_this._keyboardSelect.col || _this._keyboardSelect.row || _this._keyboardSelect.cell){
  37147. _this._endSelect("all");
  37148. _this._keyboardSelect.col = _this._keyboardSelect.row = _this._keyboardSelect.cell = 0;
  37149. }
  37150. if(_this._usingKeyboard){
  37151. _this._usingKeyboard = false;
  37152. }
  37153. var target = _createItem(type, e.rowIndex, e.cell && e.cell.index);
  37154. _this._startSelect(type, target, e.ctrlKey, e.shiftKey);
  37155. }
  37156. },
  37157. ender = lang.hitch(this, "_endSelect");
  37158. this.connect(g, "onHeaderCellMouseDown", dp(starter, "col"));
  37159. this.connect(g, "onHeaderCellMouseUp", dp(ender, "col"));
  37160. this.connect(g, "onRowSelectorMouseDown", dp(starter, "row"));
  37161. this.connect(g, "onRowSelectorMouseUp", dp(ender, "row"));
  37162. this.connect(g, "onCellMouseDown", function(e){
  37163. if(e.cell && e.cell.isRowSelector){ return; }
  37164. if(g.singleClickEdit){
  37165. _this._singleClickEdit = true;
  37166. g.singleClickEdit = false;
  37167. }
  37168. starter(_this._config["cell"] == DISABLED ? "row" : "cell", e);
  37169. });
  37170. this.connect(g, "onCellMouseUp", function(e){
  37171. if(_this._singleClickEdit){
  37172. delete _this._singleClickEdit;
  37173. g.singleClickEdit = true;
  37174. }
  37175. ender("all", e);
  37176. });
  37177. this.connect(g, "onCellMouseOver", function(e){
  37178. if(_this._curType != "row" && _this._selecting[_this._curType] && _this._config[_this._curType] == MULTI){
  37179. _this._highlight("col", _createItem("col", e.cell.index), _this._toSelect);
  37180. if(!_this._keyboardSelect.cell){
  37181. _this._highlight("cell", _createItem("cell", e.rowIndex, e.cell.index), _this._toSelect);
  37182. }
  37183. }
  37184. });
  37185. this.connect(g, "onHeaderCellMouseOver", function(e){
  37186. if(_this._selecting.col && _this._config.col == MULTI){
  37187. _this._highlight("col", _createItem("col", e.cell.index), _this._toSelect);
  37188. }
  37189. });
  37190. this.connect(g, "onRowMouseOver", function(e){
  37191. if(_this._selecting.row && _this._config.row == MULTI){
  37192. _this._highlight("row", _createItem("row", e.rowIndex), _this._toSelect);
  37193. }
  37194. });
  37195. //When row order has changed in a unpredictable way (sorted or filtered), map the new rowindex.
  37196. this.connect(g, "onSelectedById", "_onSelectedById");
  37197. //When the grid refreshes, all those selected should still appear selected.
  37198. this.connect(g, "_onFetchComplete", function(){
  37199. //console.debug("refresh after buildPage:", g._notRefreshSelection);
  37200. if(!g._notRefreshSelection){
  37201. this._refreshSelected(true);
  37202. }
  37203. });
  37204. //Small scroll might not refresh the grid.
  37205. this.connect(g.scroller, "buildPage", function(){
  37206. //console.debug("refresh after buildPage:", g._notRefreshSelection);
  37207. if(!g._notRefreshSelection){
  37208. this._refreshSelected(true);
  37209. }
  37210. });
  37211. //Whenever the mouse is up, end selecting.
  37212. this.connect(win.doc, "onmouseup", dp(ender, "all"));
  37213. //If autoscroll is enabled, connect to it.
  37214. this.connect(g, "onEndAutoScroll", function(isVertical, isForward, view, target){
  37215. var selectCell = _this._selecting.cell,
  37216. type, current, dir = isForward ? 1 : -1;
  37217. if(isVertical && (selectCell || _this._selecting.row)){
  37218. type = selectCell ? "cell" : "row";
  37219. current = _this._currentPoint[type];
  37220. _this._highlight(type, _createItem(type, current.row + dir, current.col), _this._toSelect);
  37221. }else if(!isVertical && (selectCell || _this._selecting.col)){
  37222. type = selectCell ? "cell" : "col";
  37223. current = _this._currentPoint[type];
  37224. _this._highlight(type, _createItem(type, current.row, target), _this._toSelect);
  37225. }
  37226. });
  37227. //If the grid is changed, selection should be consistent.
  37228. this.subscribe("dojox/grid/rearrange/move/" + g.id, "_onInternalRearrange");
  37229. this.subscribe("dojox/grid/rearrange/copy/" + g.id, "_onInternalRearrange");
  37230. this.subscribe("dojox/grid/rearrange/change/" + g.id, "_onExternalChange");
  37231. this.subscribe("dojox/grid/rearrange/insert/" + g.id, "_onExternalChange");
  37232. this.subscribe("dojox/grid/rearrange/remove/" + g.id, "clear");
  37233. //have to also select when the grid's default select is used.
  37234. this.connect(g, "onSelected", function(rowIndex){
  37235. if(this._selectedRowModified && this._isUsingRowSelector){
  37236. delete this._selectedRowModified;
  37237. }else if(!this.grid._selectingRange){
  37238. this.select("row", rowIndex);
  37239. }
  37240. });
  37241. this.connect(g, "onDeselected", function(rowIndex){
  37242. if(this._selectedRowModified && this._isUsingRowSelector){
  37243. delete this._selectedRowModified;
  37244. }else if(!this.grid._selectingRange){
  37245. this.deselect("row", rowIndex);
  37246. }
  37247. });
  37248. },
  37249. _onSelectedById: function(id, newIndex, isSelected){
  37250. if(this.grid._noInternalMapping){
  37251. return;
  37252. }
  37253. var pointSet = [this._lastAnchorPoint.row, this._lastEndPoint.row,
  37254. this._lastSelectedAnchorPoint.row, this._lastSelectedEndPoint.row];
  37255. pointSet = pointSet.concat(this._selected.row);
  37256. var found = false;
  37257. array.forEach(pointSet, function(item){
  37258. if(item){
  37259. if(item.id === id){
  37260. found = true;
  37261. item.row = newIndex;
  37262. }else if(item.row === newIndex && item.id){
  37263. item.row = -1;
  37264. }
  37265. }
  37266. });
  37267. if(!found && isSelected){
  37268. array.some(this._selected.row, function(item){
  37269. if(item && !item.id && !item.except.length){
  37270. item.id = id;
  37271. item.row = newIndex;
  37272. return true;
  37273. }
  37274. return false;
  37275. });
  37276. }
  37277. found = false;
  37278. pointSet = [this._lastAnchorPoint.cell, this._lastEndPoint.cell,
  37279. this._lastSelectedAnchorPoint.cell, this._lastSelectedEndPoint.cell];
  37280. pointSet = pointSet.concat(this._selected.cell);
  37281. array.forEach(pointSet, function(item){
  37282. if(item){
  37283. if(item.id === id){
  37284. found = true;
  37285. item.row = newIndex;
  37286. }else if(item.row === newIndex && item.id){
  37287. item.row = -1;
  37288. }
  37289. }
  37290. });
  37291. },
  37292. onSetStore: function(){
  37293. this._clearSelection("all");
  37294. },
  37295. _onInternalRearrange: function(type, mapping){
  37296. try{
  37297. //The column can not refresh it self!
  37298. this._refresh("col", false);
  37299. array.forEach(this._selected.row, function(item){
  37300. array.forEach(this.grid.layout.cells, function(cell){
  37301. this._highlightNode(cell.getNode(item.row), false);
  37302. }, this);
  37303. }, this);
  37304. //The rowbar must be cleaned manually
  37305. query(".dojoxGridRowSelectorSelected").forEach(function(node){
  37306. html.removeClass(node, "dojoxGridRowSelectorSelected");
  37307. html.removeClass(node, "dojoxGridRowSelectorSelectedUp");
  37308. html.removeClass(node, "dojoxGridRowSelectorSelectedDown");
  37309. });
  37310. var cleanUp = function(item){
  37311. if(item){
  37312. delete item.converted;
  37313. }
  37314. },
  37315. pointSet = [this._lastAnchorPoint[type], this._lastEndPoint[type],
  37316. this._lastSelectedAnchorPoint[type], this._lastSelectedEndPoint[type]];
  37317. if(type === "cell"){
  37318. this.selectRange("cell", mapping.to.min, mapping.to.max);
  37319. var cells = this.grid.layout.cells;
  37320. array.forEach(pointSet, function(item){
  37321. if(item.converted){ return; }
  37322. for(var r = mapping.from.min.row, tr = mapping.to.min.row; r <= mapping.from.max.row; ++r, ++tr){
  37323. for(var c = mapping.from.min.col, tc = mapping.to.min.col; c <= mapping.from.max.col; ++c, ++tc){
  37324. while(cells[c].hidden){ ++c; }
  37325. while(cells[tc].hidden){ ++tc; }
  37326. if(item.row == r && item.col == c){
  37327. //console.log('mapping found: (', item.row, ",",item.col,") to (", tr, ",", tc,")");
  37328. item.row = tr;
  37329. item.col = tc;
  37330. item.converted = true;
  37331. return;
  37332. }
  37333. }
  37334. }
  37335. });
  37336. }else{
  37337. pointSet = this._selected.cell.concat(this._selected[type]).concat(pointSet).concat(
  37338. [this._lastAnchorPoint.cell, this._lastEndPoint.cell,
  37339. this._lastSelectedAnchorPoint.cell, this._lastSelectedEndPoint.cell]);
  37340. array.forEach(pointSet, function(item){
  37341. if(item && !item.converted){
  37342. var from = item[type];
  37343. if(from in mapping){
  37344. item[type] = mapping[from];
  37345. }
  37346. item.converted = true;
  37347. }
  37348. });
  37349. array.forEach(this._selected[_theOther[type]], function(item){
  37350. for(var i = 0, len = item.except.length; i < len; ++i){
  37351. var from = item.except[i];
  37352. if(from in mapping){
  37353. item.except[i] = mapping[from];
  37354. }
  37355. }
  37356. });
  37357. }
  37358. array.forEach(pointSet, cleanUp);
  37359. this._refreshSelected(true);
  37360. this._focusPoint(type, this._lastEndPoint);
  37361. }catch(e){
  37362. console.warn("Selector._onInternalRearrange() error",e);
  37363. }
  37364. },
  37365. _onExternalChange: function(type, target){
  37366. var start = type == "cell" ? target.min : target[0],
  37367. end = type == "cell" ? target.max : target[target.length - 1];
  37368. this.selectRange(type, start, end);
  37369. },
  37370. _refresh: function(type, toHighlight){
  37371. if(!this._keyboardSelect[type]){
  37372. array.forEach(this._selected[type], function(item){
  37373. this._highlightSingle(type, toHighlight, item, undefined, true);
  37374. }, this);
  37375. }
  37376. },
  37377. _refreshSelected: function(){
  37378. this._refresh("col", true);
  37379. this._refresh("row", true);
  37380. this._refresh("cell", true);
  37381. },
  37382. _initAreas: function(){
  37383. var g = this.grid, f = g.focus, _this = this,
  37384. keyboardSelectReady = 1, duringKeyboardSelect = 2,
  37385. onmove = function(type, createNewEnd, rowStep, colStep, evt){
  37386. //Keyboard swipe selection is SHIFT + Direction Keys.
  37387. var ks = _this._keyboardSelect;
  37388. //Tricky, rely on valid status not being 0.
  37389. if(evt.shiftKey && ks[type]){
  37390. if(ks[type] === keyboardSelectReady){
  37391. if(type === "cell"){
  37392. var item = _this._lastEndPoint[type];
  37393. if(f.cell != g.layout.cells[item.col + colStep] || f.rowIndex != item.row + rowStep){
  37394. ks[type] = 0;
  37395. return;
  37396. }
  37397. }
  37398. //If selecting is not started, start it
  37399. _this._startSelect(type, _this._lastAnchorPoint[type], true, false, true);
  37400. _this._highlight(type, _this._lastEndPoint[type], _this._toSelect);
  37401. ks[type] = duringKeyboardSelect;
  37402. }
  37403. //Highlight to the new end point.
  37404. var newEnd = createNewEnd(type, rowStep, colStep, evt);
  37405. if(_this._isValid(type, newEnd, g)){
  37406. _this._highlight(type, newEnd, _this._toSelect);
  37407. }
  37408. _stopEvent(evt);
  37409. }
  37410. },
  37411. onkeydown = function(type, getTarget, evt, isBubble){
  37412. if(isBubble && _this.selectEnabled() && _this._config[type] != DISABLED){
  37413. switch(evt.keyCode){
  37414. case keys.SPACE:
  37415. //Keyboard single point selection is SPACE.
  37416. _this._startSelect(type, getTarget(), evt.ctrlKey, evt.shiftKey);
  37417. _this._endSelect(type);
  37418. break;
  37419. case keys.SHIFT:
  37420. //Keyboard swipe selection starts with SHIFT.
  37421. if(_this._config[type] == MULTI && _this._isValid(type, _this._lastAnchorPoint[type], g)){
  37422. //End last selection if any.
  37423. _this._endSelect(type);
  37424. _this._keyboardSelect[type] = keyboardSelectReady;
  37425. _this._usingKeyboard = true;
  37426. }
  37427. }
  37428. }
  37429. },
  37430. onkeyup = function(type, evt, isBubble){
  37431. if(isBubble && evt.keyCode == keys.SHIFT && _this._keyboardSelect[type]){
  37432. _this._endSelect(type);
  37433. _this._keyboardSelect[type] = 0;
  37434. }
  37435. };
  37436. //TODO: this area "rowHeader" should be put outside, same level as header/content.
  37437. if(g.views.views[0] instanceof _RowSelector){
  37438. this._lastFocusedRowBarIdx = 0;
  37439. f.addArea({
  37440. name:"rowHeader",
  37441. onFocus: function(evt, step){
  37442. var view = g.views.views[0];
  37443. if(view instanceof _RowSelector){
  37444. var rowBarNode = view.getCellNode(_this._lastFocusedRowBarIdx, 0);
  37445. if(rowBarNode){
  37446. html.toggleClass(rowBarNode, f.focusClass, false);
  37447. }
  37448. //evt might not be real event, it may be a mock object instead.
  37449. if(evt && "rowIndex" in evt){
  37450. if(evt.rowIndex >= 0){
  37451. _this._lastFocusedRowBarIdx = evt.rowIndex;
  37452. }else if(!_this._lastFocusedRowBarIdx){
  37453. _this._lastFocusedRowBarIdx = 0;
  37454. }
  37455. }
  37456. rowBarNode = view.getCellNode(_this._lastFocusedRowBarIdx, 0);
  37457. if(rowBarNode){
  37458. dijitFocus.focus(rowBarNode);
  37459. html.toggleClass(rowBarNode, f.focusClass, true);
  37460. }
  37461. f.rowIndex = _this._lastFocusedRowBarIdx;
  37462. _stopEvent(evt);
  37463. return true;
  37464. }
  37465. return false;
  37466. },
  37467. onBlur: function(evt, step){
  37468. var view = g.views.views[0];
  37469. if(view instanceof _RowSelector){
  37470. var rowBarNode = view.getCellNode(_this._lastFocusedRowBarIdx, 0);
  37471. if(rowBarNode){
  37472. html.toggleClass(rowBarNode, f.focusClass, false);
  37473. }
  37474. _stopEvent(evt);
  37475. }
  37476. return true;
  37477. },
  37478. onMove: function(rowStep, colStep, evt){
  37479. var view = g.views.views[0];
  37480. if(rowStep && view instanceof _RowSelector){
  37481. var next = _this._lastFocusedRowBarIdx + rowStep;
  37482. if(next >= 0 && next < g.rowCount){
  37483. //TODO: these logic require a better Scroller.
  37484. _stopEvent(evt);
  37485. var rowBarNode = view.getCellNode(_this._lastFocusedRowBarIdx, 0);
  37486. html.toggleClass(rowBarNode, f.focusClass, false);
  37487. //If the row is not fetched, fetch it.
  37488. var sc = g.scroller;
  37489. var lastPageRow = sc.getLastPageRow(sc.page);
  37490. var rc = g.rowCount - 1, row = Math.min(rc, next);
  37491. if(next > lastPageRow){
  37492. g.setScrollTop(g.scrollTop + sc.findScrollTop(row) - sc.findScrollTop(_this._lastFocusedRowBarIdx));
  37493. }
  37494. //Now we have fetched the row.
  37495. rowBarNode = view.getCellNode(next, 0);
  37496. dijitFocus.focus(rowBarNode);
  37497. html.toggleClass(rowBarNode, f.focusClass, true);
  37498. _this._lastFocusedRowBarIdx = next;
  37499. //If the row is out of view, scroll to it.
  37500. f.cell = rowBarNode;
  37501. f.cell.view = view;
  37502. f.cell.getNode = function(index){
  37503. return f.cell;
  37504. };
  37505. f.rowIndex = _this._lastFocusedRowBarIdx;
  37506. f.scrollIntoView();
  37507. f.cell = null;
  37508. }
  37509. }
  37510. }
  37511. });
  37512. f.placeArea("rowHeader","before","content");
  37513. }
  37514. //Support keyboard selection.
  37515. f.addArea({
  37516. name:"cellselect",
  37517. onMove: lang.partial(onmove, "cell", function(type, rowStep, colStep, evt){
  37518. var current = _this._currentPoint[type];
  37519. return _createItem("cell", current.row + rowStep, current.col + colStep);
  37520. }),
  37521. onKeyDown: lang.partial(onkeydown, "cell", function(){
  37522. return _createItem("cell", f.rowIndex, f.cell.index);
  37523. }),
  37524. onKeyUp: lang.partial(onkeyup, "cell")
  37525. });
  37526. f.placeArea("cellselect","below","content");
  37527. f.addArea({
  37528. name:"colselect",
  37529. onMove: lang.partial(onmove, "col", function(type, rowStep, colStep, evt){
  37530. var current = _this._currentPoint[type];
  37531. return _createItem("col", current.col + colStep);
  37532. }),
  37533. onKeyDown: lang.partial(onkeydown, "col", function(){
  37534. return _createItem("col", f.getHeaderIndex());
  37535. }),
  37536. onKeyUp: lang.partial(onkeyup, "col")
  37537. });
  37538. f.placeArea("colselect","below","header");
  37539. f.addArea({
  37540. name:"rowselect",
  37541. onMove: lang.partial(onmove, "row", function(type, rowStep, colStep, evt){
  37542. return _createItem("row", f.rowIndex);
  37543. }),
  37544. onKeyDown: lang.partial(onkeydown, "row", function(){
  37545. return _createItem("row", f.rowIndex);
  37546. }),
  37547. onKeyUp: lang.partial(onkeyup, "row")
  37548. });
  37549. f.placeArea("rowselect","below","rowHeader");
  37550. },
  37551. _clearSelection: function(type, reservedItem){
  37552. // summary:
  37553. // Clear selection for given type and fire events, but retain the highlight for *reservedItem*,
  37554. // thus avoid "flashing".
  37555. // tag:
  37556. // private
  37557. // type: String
  37558. // "row", "col", or "cell
  37559. // reservedItem: __SelectItem
  37560. // The item to retain highlight.
  37561. if(type == "all"){
  37562. this._clearSelection("cell", reservedItem);
  37563. this._clearSelection("col", reservedItem);
  37564. this._clearSelection("row", reservedItem);
  37565. return;
  37566. }
  37567. this._isUsingRowSelector = true;
  37568. array.forEach(this._selected[type], function(item){
  37569. if(!_isEqual(type, reservedItem, item)){
  37570. this._highlightSingle(type, false, item);
  37571. }
  37572. }, this);
  37573. this._blurPoint(type, this._currentPoint);
  37574. this._selecting[type] = false;
  37575. this._startPoint[type] = this._currentPoint[type] = null;
  37576. this._selected[type] = [];
  37577. //Have to also deselect default grid selection.
  37578. if(type == "row" && !this.grid._selectingRange){
  37579. this._oldDeselectAll.call(this.grid.selection);
  37580. this.grid.selection._selectedById = {};
  37581. }
  37582. //Fire events.
  37583. this.grid.onEndDeselect(type, null, null, this._selected);
  37584. this.grid.onSelectCleared(type);
  37585. },
  37586. _startSelect: function(type, start, extending, isRange, mandatarySelect, toSelect){
  37587. // summary:
  37588. // Start selection, setup start point and current point, fire events.
  37589. // tag:
  37590. // private
  37591. // type: String
  37592. // "row", "col", or "cell"
  37593. // extending: Boolean
  37594. // Whether this is a multi selection
  37595. // isRange: Boolean
  37596. // Whether this is a range selection (i.e. select from the last end point to this point)
  37597. // start: __SelectItem
  37598. // The start point
  37599. // mandatarySelect: Boolean
  37600. // If true, toSelect will be same as the original selection status.
  37601. if(!this._isValid(type, start)){
  37602. return;
  37603. }
  37604. var lastIsSelected = this._isSelected(type, this._lastEndPoint[type]),
  37605. isSelected = this._isSelected(type, start);
  37606. if(this.noClear && !extending){
  37607. this._toSelect = toSelect === undefined ? true : toSelect;
  37608. }else{
  37609. //If we are modifying the selection using keyboard, retain the old status.
  37610. this._toSelect = mandatarySelect ? isSelected : !isSelected;
  37611. }
  37612. //If CTRL is not pressed or it's SINGLE mode, this is a brand new selection.
  37613. if(!extending || (!isSelected && this._config[type] == SINGLE)){
  37614. this._clearSelection("col", start);
  37615. this._clearSelection("cell", start);
  37616. if(!this.noClear || (type === 'row' && this._config[type] == SINGLE)){
  37617. this._clearSelection('row', start);
  37618. }
  37619. this._toSelect = toSelect === undefined ? true : toSelect;
  37620. }
  37621. this._selecting[type] = true;
  37622. this._currentPoint[type] = null;
  37623. //We're holding SHIFT while clicking, it's a Click-Range selection.
  37624. if(isRange && this._lastType == type && lastIsSelected == this._toSelect && this._config[type] == MULTI){
  37625. if(type === "row"){
  37626. this._isUsingRowSelector = true;
  37627. }
  37628. this._startPoint[type] = this._lastEndPoint[type];
  37629. this._highlight(type, this._startPoint[type]);
  37630. this._isUsingRowSelector = false;
  37631. }else{
  37632. this._startPoint[type] = start;
  37633. }
  37634. //Now start selection
  37635. this._curType = type;
  37636. this._fireEvent("start", type);
  37637. this._isStartFocus = true;
  37638. this._isUsingRowSelector = true;
  37639. this._highlight(type, start, this._toSelect);
  37640. this._isStartFocus = false;
  37641. },
  37642. _endSelect: function(type){
  37643. // summary:
  37644. // End selection. Keep records, fire events and cleanup status.
  37645. // tag:
  37646. // private
  37647. // type: String
  37648. // "row", "col", or "cell"
  37649. if(type === "row"){
  37650. delete this._isUsingRowSelector;
  37651. }
  37652. if(type == "all"){
  37653. this._endSelect("col");
  37654. this._endSelect("row");
  37655. this._endSelect("cell");
  37656. }else if(this._selecting[type]){
  37657. this._addToSelected(type);
  37658. this._lastAnchorPoint[type] = this._startPoint[type];
  37659. this._lastEndPoint[type] = this._currentPoint[type];
  37660. if(this._toSelect){
  37661. this._lastSelectedAnchorPoint[type] = this._lastAnchorPoint[type];
  37662. this._lastSelectedEndPoint[type] = this._lastEndPoint[type];
  37663. }
  37664. this._startPoint[type] = this._currentPoint[type] = null;
  37665. this._selecting[type] = false;
  37666. this._lastType = type;
  37667. this._fireEvent("end", type);
  37668. }
  37669. },
  37670. _fireEvent: function(evtName, type){
  37671. switch(evtName){
  37672. case "start":
  37673. this.grid[this._toSelect ? "onStartSelect" : "onStartDeselect"](type, this._startPoint[type], this._selected);
  37674. break;
  37675. case "end":
  37676. this.grid[this._toSelect ? "onEndSelect" : "onEndDeselect"](type, this._lastAnchorPoint[type], this._lastEndPoint[type], this._selected);
  37677. break;
  37678. }
  37679. },
  37680. _calcToHighlight: function(type, target, toHighlight, toSelect){
  37681. // summary:
  37682. // Calculate what status should *target* have.
  37683. // If *toSelect* is not provided, this is a no op.
  37684. // This function is time-critical!!
  37685. if(toSelect !== undefined){
  37686. var sltd;
  37687. if(this._usingKeyboard && !toHighlight){
  37688. var last = this._isInLastRange(this._lastType, target);
  37689. if(last){
  37690. sltd = this._isSelected(type, target);
  37691. //This 2 cases makes the keyboard swipe selection valid!
  37692. if(toSelect && sltd){
  37693. return false;
  37694. }
  37695. if(!toSelect && !sltd && this._isInLastRange(this._lastType, target, true)){
  37696. return true;
  37697. }
  37698. }
  37699. }
  37700. return toHighlight ? toSelect : (sltd || this._isSelected(type, target));
  37701. }
  37702. return toHighlight;
  37703. },
  37704. _highlightNode: function(node, toHighlight){
  37705. // summary:
  37706. // Do the actual highlight work.
  37707. if(node){
  37708. var selectCSSClass = "dojoxGridRowSelected";
  37709. var selectCellClass = "dojoxGridCellSelected";
  37710. html.toggleClass(node, selectCSSClass, toHighlight);
  37711. html.toggleClass(node, selectCellClass, toHighlight);
  37712. }
  37713. },
  37714. _highlightHeader: function(colIdx, toHighlight){
  37715. var cells = this.grid.layout.cells;
  37716. var node = cells[colIdx].getHeaderNode();
  37717. var selectedClass = "dojoxGridHeaderSelected";
  37718. html.toggleClass(node, selectedClass, toHighlight);
  37719. },
  37720. _highlightRowSelector: function(rowIdx, toHighlight){
  37721. //var t1 = (new Date()).getTime();
  37722. var rowSelector = this.grid.views.views[0];
  37723. if(rowSelector instanceof _RowSelector){
  37724. var node = rowSelector.getRowNode(rowIdx);
  37725. if(node){
  37726. var selectedClass = "dojoxGridRowSelectorSelected";
  37727. html.toggleClass(node, selectedClass, toHighlight);
  37728. }
  37729. }
  37730. //console.log((new Date()).getTime() - t1);
  37731. },
  37732. _highlightSingle: function(type, toHighlight, target, toSelect, isRefresh){
  37733. // summary:
  37734. // Highlight a single item.
  37735. // This function is time critical!!
  37736. var _this = this, toHL, g = _this.grid, cells = g.layout.cells;
  37737. switch(type){
  37738. case "cell":
  37739. toHL = this._calcToHighlight(type, target, toHighlight, toSelect);
  37740. var c = cells[target.col];
  37741. if(!c.hidden && !c.notselectable){
  37742. this._highlightNode(target.node || c.getNode(target.row), toHL);
  37743. }
  37744. break;
  37745. case "col":
  37746. toHL = this._calcToHighlight(type, target, toHighlight, toSelect);
  37747. this._highlightHeader(target.col, toHL);
  37748. query("td[idx='" + target.col + "']", g.domNode).forEach(function(cellNode){
  37749. var rowNode = cells[target.col].view.content.findRowTarget(cellNode);
  37750. if(rowNode){
  37751. var rowIndex = rowNode[dojox.grid.util.rowIndexTag];
  37752. _this._highlightSingle("cell", toHL, {
  37753. "row": rowIndex,
  37754. "col": target.col,
  37755. "node": cellNode
  37756. });
  37757. }
  37758. });
  37759. break;
  37760. case "row":
  37761. toHL = this._calcToHighlight(type, target, toHighlight, toSelect);
  37762. this._highlightRowSelector(target.row, toHL);
  37763. if(this._config.cell){
  37764. array.forEach(cells, function(cell){
  37765. _this._highlightSingle("cell", toHL, {
  37766. "row": target.row,
  37767. "col": cell.index,
  37768. "node": cell.getNode(target.row)
  37769. });
  37770. });
  37771. }
  37772. //To avoid dead lock
  37773. this._selectedRowModified = true;
  37774. if(!isRefresh){
  37775. g.selection.setSelected(target.row, toHL);
  37776. }
  37777. }
  37778. },
  37779. _highlight: function(type, target, toSelect){
  37780. // summary:
  37781. // Highlight from start point to target.
  37782. // toSelect: Boolean
  37783. // Whether we are selecting or deselecting.
  37784. // This function is time critical!!
  37785. if(this._selecting[type] && target !== null){
  37786. var start = this._startPoint[type],
  37787. current = this._currentPoint[type],
  37788. _this = this,
  37789. highlight = function(from, to, toHL){
  37790. _this._forEach(type, from, to, function(item){
  37791. _this._highlightSingle(type, toHL, item, toSelect);
  37792. }, true);
  37793. };
  37794. switch(type){
  37795. case "col": case "row":
  37796. if(current !== null){
  37797. if(_inRange(type, target, start, current, true)){
  37798. //target is between start and current, some selected should be deselected.
  37799. highlight(current, target, false);
  37800. }else{
  37801. if(_inRange(type, start, target, current, true)){
  37802. //selection has jumped to different direction, all should be deselected.
  37803. highlight(current, start, false);
  37804. current = start;
  37805. }
  37806. highlight(target, current, true);
  37807. }
  37808. }else{
  37809. //First time select.
  37810. this._highlightSingle(type, true, target, toSelect);
  37811. }
  37812. break;
  37813. case "cell":
  37814. if(current !== null){
  37815. if(_inRange("row", target, start, current, true) ||
  37816. _inRange("col", target, start, current, true) ||
  37817. _inRange("row", start, target, current, true) ||
  37818. _inRange("col", start, target, current, true)){
  37819. highlight(start, current, false);
  37820. }
  37821. }
  37822. highlight(start, target, true);
  37823. }
  37824. this._currentPoint[type] = target;
  37825. this._focusPoint(type, this._currentPoint);
  37826. }
  37827. },
  37828. _focusPoint: function(type, point){
  37829. // summary:
  37830. // Focus the current point, so when you move mouse, the focus indicator follows you.
  37831. if(!this._isStartFocus){
  37832. var current = point[type],
  37833. f = this.grid.focus;
  37834. if(type == "col"){
  37835. f._colHeadFocusIdx = current.col;
  37836. f.focusArea("header");
  37837. }else if(type == "row"){
  37838. f.focusArea("rowHeader", {
  37839. "rowIndex": current.row
  37840. });
  37841. }else if(type == "cell"){
  37842. f.setFocusIndex(current.row, current.col);
  37843. }
  37844. }
  37845. },
  37846. _blurPoint: function(type, point){
  37847. // summary:
  37848. // Blur the current point.
  37849. var f = this.grid.focus;
  37850. if(type == "cell"){
  37851. f._blurContent();
  37852. }
  37853. },
  37854. _addToSelected: function(type){
  37855. // summary:
  37856. // Record the selected items.
  37857. var toSelect = this._toSelect, _this = this,
  37858. toAdd = [], toRemove = [],
  37859. start = this._startPoint[type],
  37860. end = this._currentPoint[type];
  37861. if(this._usingKeyboard){
  37862. //If using keyboard, selection will be ended after every move. But we have to remember the original selection status,
  37863. //so as to return to correct status when we shrink the selection region.
  37864. this._forEach(type, this._lastAnchorPoint[type], this._lastEndPoint[type], function(item){
  37865. //If the original selected item is not in current range, change its status.
  37866. if(!_inRange(type, item, start, end)){
  37867. (toSelect ? toRemove : toAdd).push(item);
  37868. }
  37869. });
  37870. }
  37871. this._forEach(type, start, end, function(item){
  37872. var isSelected = _this._isSelected(type, item);
  37873. if(toSelect && !isSelected){
  37874. //Add new selected items
  37875. toAdd.push(item);
  37876. }else if(!toSelect){
  37877. //Remove deselected items.
  37878. toRemove.push(item);
  37879. }
  37880. });
  37881. this._add(type, toAdd);
  37882. this._remove(type, toRemove);
  37883. // have to keep record in original grid selection
  37884. array.forEach(this._selected.row, function(item){
  37885. if(item.except.length > 0){
  37886. //to avoid dead lock
  37887. this._selectedRowModified = true;
  37888. this.grid.selection.setSelected(item.row, false);
  37889. }
  37890. }, this);
  37891. },
  37892. _forEach: function(type, start, end, func, halfClose){
  37893. // summary:
  37894. // Go through items from *start* point to *end* point.
  37895. // This function is time critical!!
  37896. if(!this._isValid(type, start, true) || !this._isValid(type, end, true)){
  37897. return;
  37898. }
  37899. switch(type){
  37900. case "col": case "row":
  37901. start = start[type];
  37902. end = end[type];
  37903. var dir = end > start ? 1 : -1;
  37904. if(!halfClose){
  37905. end += dir;
  37906. }
  37907. for(; start != end; start += dir){
  37908. func(_createItem(type, start));
  37909. }
  37910. break;
  37911. case "cell":
  37912. var colDir = end.col > start.col ? 1 : -1,
  37913. rowDir = end.row > start.row ? 1 : -1;
  37914. for(var i = start.row, p = end.row + rowDir; i != p; i += rowDir){
  37915. for(var j = start.col, q = end.col + colDir; j != q; j += colDir){
  37916. func(_createItem(type, i, j));
  37917. }
  37918. }
  37919. }
  37920. },
  37921. _makeupForExceptions: function(type, newCellItems){
  37922. // summary:
  37923. // When new cells is selected, maybe they will fill in the "holes" in selected rows and columns.
  37924. var makedUps = [];
  37925. array.forEach(this._selected[type], function(v1){
  37926. array.forEach(newCellItems, function(v2){
  37927. if(v1[type] == v2[type]){
  37928. var pos = array.indexOf(v1.except, v2[_theOther[type]]);
  37929. if(pos >= 0){
  37930. v1.except.splice(pos, 1);
  37931. }
  37932. makedUps.push(v2);
  37933. }
  37934. });
  37935. });
  37936. return makedUps;
  37937. },
  37938. _makeupForCells: function(type, newItems){
  37939. // summary:
  37940. // When some rows/cols are selected, maybe they can cover some of the selected cells,
  37941. // and fill some of the "holes" in the selected cols/rows.
  37942. var toRemove = [];
  37943. array.forEach(this._selected.cell, function(v1){
  37944. array.some(newItems, function(v2){
  37945. if(v1[type] == v2[type]){
  37946. toRemove.push(v1);
  37947. return true;
  37948. }
  37949. return false;
  37950. });
  37951. });
  37952. this._remove("cell", toRemove);
  37953. array.forEach(this._selected[_theOther[type]], function(v1){
  37954. array.forEach(newItems, function(v2){
  37955. var pos = array.indexOf(v1.except, v2[type]);
  37956. if(pos >= 0){
  37957. v1.except.splice(pos, 1);
  37958. }
  37959. });
  37960. });
  37961. },
  37962. _addException: function(type, items){
  37963. // summary:
  37964. // If some rows/cols are deselected, maybe they have created "holes" in selected cols/rows.
  37965. array.forEach(this._selected[type], function(v1){
  37966. array.forEach(items, function(v2){
  37967. v1.except.push(v2[_theOther[type]]);
  37968. });
  37969. });
  37970. },
  37971. _addCellException: function(type, items){
  37972. // summary:
  37973. // If some cells are deselected, maybe they have created "holes" in selected rows/cols.
  37974. array.forEach(this._selected[type], function(v1){
  37975. array.forEach(items, function(v2){
  37976. if(v1[type] == v2[type]){
  37977. v1.except.push(v2[_theOther[type]]);
  37978. }
  37979. });
  37980. });
  37981. },
  37982. _add: function(type, items){
  37983. // summary:
  37984. // Add to the selection record.
  37985. var cells = this.grid.layout.cells;
  37986. if(type == "cell"){
  37987. var colMakedup = this._makeupForExceptions("col", items);
  37988. var rowMakedup = this._makeupForExceptions("row", items);
  37989. //Step over hidden columns.
  37990. items = array.filter(items, function(item){
  37991. return array.indexOf(colMakedup, item) < 0 && array.indexOf(rowMakedup, item) < 0 &&
  37992. !cells[item.col].hidden && !cells[item.col].notselectable;
  37993. });
  37994. }else{
  37995. if(type == "col"){
  37996. //Step over hidden columns.
  37997. items = array.filter(items, function(item){
  37998. return !cells[item.col].hidden && !cells[item.col].notselectable;
  37999. });
  38000. }
  38001. this._makeupForCells(type, items);
  38002. this._selected[type] = array.filter(this._selected[type], function(v){
  38003. return array.every(items, function(item){
  38004. return v[type] !== item[type];
  38005. });
  38006. });
  38007. }
  38008. if(type != "col" && this.grid._hasIdentity){
  38009. array.forEach(items, function(item){
  38010. var record = this.grid._by_idx[item.row];
  38011. if(record){
  38012. item.id = record.idty;
  38013. }
  38014. }, this);
  38015. }
  38016. this._selected[type] = this._selected[type].concat(items);
  38017. },
  38018. _remove: function(type, items){
  38019. // summary:
  38020. // Remove from the selection record.
  38021. var comp = lang.partial(_isEqual, type);
  38022. this._selected[type] = array.filter(this._selected[type], function(v1){
  38023. return !array.some(items, function(v2){
  38024. return comp(v1, v2);
  38025. });
  38026. });
  38027. if(type == "cell"){
  38028. this._addCellException("col", items);
  38029. this._addCellException("row", items);
  38030. }else if(this._config.cell){
  38031. this._addException(_theOther[type], items);
  38032. }
  38033. },
  38034. _isCellNotInExcept: function(type, item){
  38035. // summary:
  38036. // Return true only when a cell is covered by selected row/col, and its not a "hole".
  38037. var attr = item[type], corres = item[_theOther[type]];
  38038. return array.some(this._selected[type], function(v){
  38039. return v[type] == attr && array.indexOf(v.except, corres) < 0;
  38040. });
  38041. },
  38042. _isSelected: function(type, item){
  38043. // summary:
  38044. // Return true when the item is selected. (or logically selected, i.e, covered by a row/col).
  38045. if(!item){ return false; }
  38046. var res = array.some(this._selected[type], function(v){
  38047. var ret = _isEqual(type, item, v);
  38048. if(ret && type !== "cell"){
  38049. return v.except.length === 0;
  38050. }
  38051. return ret;
  38052. });
  38053. if(!res && type === "cell"){
  38054. res = (this._isCellNotInExcept("col", item) || this._isCellNotInExcept("row", item));
  38055. if(type === "cell"){
  38056. res = res && !this.grid.layout.cells[item.col].notselectable;
  38057. }
  38058. }
  38059. return res;
  38060. },
  38061. _isInLastRange: function(type, item, isSelected){
  38062. // summary:
  38063. // Return true only when the item is in the last seletion/deseletion range.
  38064. var start = this[isSelected ? "_lastSelectedAnchorPoint" : "_lastAnchorPoint"][type],
  38065. end = this[isSelected ? "_lastSelectedEndPoint" : "_lastEndPoint"][type];
  38066. if(!item || !start || !end){ return false; }
  38067. return _inRange(type, item, start, end);
  38068. },
  38069. _isValid: function(type, item, allowNotSelectable){
  38070. // summary:
  38071. // Check whether the item is a valid __SelectItem for the given type.
  38072. if(!item){ return false; }
  38073. try{
  38074. var g = this.grid, index = item[type];
  38075. switch(type){
  38076. case "col":
  38077. return index >= 0 && index < g.layout.cells.length && lang.isArray(item.except) &&
  38078. (allowNotSelectable || !g.layout.cells[index].notselectable);
  38079. case "row":
  38080. return index >= 0 && index < g.rowCount && lang.isArray(item.except);
  38081. case "cell":
  38082. return item.col >= 0 && item.col < g.layout.cells.length &&
  38083. item.row >= 0 && item.row < g.rowCount &&
  38084. (allowNotSelectable || !g.layout.cells[item.col].notselectable);
  38085. }
  38086. }catch(e){}
  38087. return false;
  38088. }
  38089. });
  38090. EnhancedGrid.registerPlugin(Selector/*name:'selector'*/, {
  38091. "dependency": ["autoScroll"]
  38092. });
  38093. return Selector;
  38094. });
  38095. },
  38096. 'dojo/dnd/Container':function(){
  38097. define("dojo/dnd/Container", ["../main", "../Evented", "./common", "../parser"], function(dojo, Evented) {
  38098. // module:
  38099. // dojo/dnd/Container
  38100. // summary:
  38101. // TODOC
  38102. /*
  38103. Container states:
  38104. "" - normal state
  38105. "Over" - mouse over a container
  38106. Container item states:
  38107. "" - normal state
  38108. "Over" - mouse over a container item
  38109. */
  38110. /*=====
  38111. dojo.declare("dojo.dnd.__ContainerArgs", [], {
  38112. creator: function(){
  38113. // summary:
  38114. // a creator function, which takes a data item, and returns an object like that:
  38115. // {node: newNode, data: usedData, type: arrayOfStrings}
  38116. },
  38117. // skipForm: Boolean
  38118. // don't start the drag operation, if clicked on form elements
  38119. skipForm: false,
  38120. // dropParent: Node||String
  38121. // node or node's id to use as the parent node for dropped items
  38122. // (must be underneath the 'node' parameter in the DOM)
  38123. dropParent: null,
  38124. // _skipStartup: Boolean
  38125. // skip startup(), which collects children, for deferred initialization
  38126. // (this is used in the markup mode)
  38127. _skipStartup: false
  38128. });
  38129. dojo.dnd.Item = function(){
  38130. // summary:
  38131. // Represents (one of) the source node(s) being dragged.
  38132. // Contains (at least) the "type" and "data" attributes.
  38133. // type: String[]
  38134. // Type(s) of this item, by default this is ["text"]
  38135. // data: Object
  38136. // Logical representation of the object being dragged.
  38137. // If the drag object's type is "text" then data is a String,
  38138. // if it's another type then data could be a different Object,
  38139. // perhaps a name/value hash.
  38140. this.type = type;
  38141. this.data = data;
  38142. }
  38143. =====*/
  38144. dojo.declare("dojo.dnd.Container", Evented, {
  38145. // summary:
  38146. // a Container object, which knows when mouse hovers over it,
  38147. // and over which element it hovers
  38148. // object attributes (for markup)
  38149. skipForm: false,
  38150. /*=====
  38151. // current: DomNode
  38152. // The DOM node the mouse is currently hovered over
  38153. current: null,
  38154. // map: Hash<String, dojo.dnd.Item>
  38155. // Map from an item's id (which is also the DOMNode's id) to
  38156. // the dojo.dnd.Item itself.
  38157. map: {},
  38158. =====*/
  38159. constructor: function(node, params){
  38160. // summary:
  38161. // a constructor of the Container
  38162. // node: Node
  38163. // node or node's id to build the container on
  38164. // params: dojo.dnd.__ContainerArgs
  38165. // a dictionary of parameters
  38166. this.node = dojo.byId(node);
  38167. if(!params){ params = {}; }
  38168. this.creator = params.creator || null;
  38169. this.skipForm = params.skipForm;
  38170. this.parent = params.dropParent && dojo.byId(params.dropParent);
  38171. // class-specific variables
  38172. this.map = {};
  38173. this.current = null;
  38174. // states
  38175. this.containerState = "";
  38176. dojo.addClass(this.node, "dojoDndContainer");
  38177. // mark up children
  38178. if(!(params && params._skipStartup)){
  38179. this.startup();
  38180. }
  38181. // set up events
  38182. this.events = [
  38183. dojo.connect(this.node, "onmouseover", this, "onMouseOver"),
  38184. dojo.connect(this.node, "onmouseout", this, "onMouseOut"),
  38185. // cancel text selection and text dragging
  38186. dojo.connect(this.node, "ondragstart", this, "onSelectStart"),
  38187. dojo.connect(this.node, "onselectstart", this, "onSelectStart")
  38188. ];
  38189. },
  38190. // object attributes (for markup)
  38191. creator: function(){
  38192. // summary:
  38193. // creator function, dummy at the moment
  38194. },
  38195. // abstract access to the map
  38196. getItem: function(/*String*/ key){
  38197. // summary:
  38198. // returns a data item by its key (id)
  38199. return this.map[key]; // dojo.dnd.Item
  38200. },
  38201. setItem: function(/*String*/ key, /*dojo.dnd.Item*/ data){
  38202. // summary:
  38203. // associates a data item with its key (id)
  38204. this.map[key] = data;
  38205. },
  38206. delItem: function(/*String*/ key){
  38207. // summary:
  38208. // removes a data item from the map by its key (id)
  38209. delete this.map[key];
  38210. },
  38211. forInItems: function(/*Function*/ f, /*Object?*/ o){
  38212. // summary:
  38213. // iterates over a data map skipping members that
  38214. // are present in the empty object (IE and/or 3rd-party libraries).
  38215. o = o || dojo.global;
  38216. var m = this.map, e = dojo.dnd._empty;
  38217. for(var i in m){
  38218. if(i in e){ continue; }
  38219. f.call(o, m[i], i, this);
  38220. }
  38221. return o; // Object
  38222. },
  38223. clearItems: function(){
  38224. // summary:
  38225. // removes all data items from the map
  38226. this.map = {};
  38227. },
  38228. // methods
  38229. getAllNodes: function(){
  38230. // summary:
  38231. // returns a list (an array) of all valid child nodes
  38232. return dojo.query("> .dojoDndItem", this.parent); // NodeList
  38233. },
  38234. sync: function(){
  38235. // summary:
  38236. // sync up the node list with the data map
  38237. var map = {};
  38238. this.getAllNodes().forEach(function(node){
  38239. if(node.id){
  38240. var item = this.getItem(node.id);
  38241. if(item){
  38242. map[node.id] = item;
  38243. return;
  38244. }
  38245. }else{
  38246. node.id = dojo.dnd.getUniqueId();
  38247. }
  38248. var type = node.getAttribute("dndType"),
  38249. data = node.getAttribute("dndData");
  38250. map[node.id] = {
  38251. data: data || node.innerHTML,
  38252. type: type ? type.split(/\s*,\s*/) : ["text"]
  38253. };
  38254. }, this);
  38255. this.map = map;
  38256. return this; // self
  38257. },
  38258. insertNodes: function(data, before, anchor){
  38259. // summary:
  38260. // inserts an array of new nodes before/after an anchor node
  38261. // data: Array
  38262. // a list of data items, which should be processed by the creator function
  38263. // before: Boolean
  38264. // insert before the anchor, if true, and after the anchor otherwise
  38265. // anchor: Node
  38266. // the anchor node to be used as a point of insertion
  38267. if(!this.parent.firstChild){
  38268. anchor = null;
  38269. }else if(before){
  38270. if(!anchor){
  38271. anchor = this.parent.firstChild;
  38272. }
  38273. }else{
  38274. if(anchor){
  38275. anchor = anchor.nextSibling;
  38276. }
  38277. }
  38278. if(anchor){
  38279. for(var i = 0; i < data.length; ++i){
  38280. var t = this._normalizedCreator(data[i]);
  38281. this.setItem(t.node.id, {data: t.data, type: t.type});
  38282. this.parent.insertBefore(t.node, anchor);
  38283. }
  38284. }else{
  38285. for(var i = 0; i < data.length; ++i){
  38286. var t = this._normalizedCreator(data[i]);
  38287. this.setItem(t.node.id, {data: t.data, type: t.type});
  38288. this.parent.appendChild(t.node);
  38289. }
  38290. }
  38291. return this; // self
  38292. },
  38293. destroy: function(){
  38294. // summary:
  38295. // prepares this object to be garbage-collected
  38296. dojo.forEach(this.events, dojo.disconnect);
  38297. this.clearItems();
  38298. this.node = this.parent = this.current = null;
  38299. },
  38300. // markup methods
  38301. markupFactory: function(params, node, ctor){
  38302. params._skipStartup = true;
  38303. return new ctor(node, params);
  38304. },
  38305. startup: function(){
  38306. // summary:
  38307. // collects valid child items and populate the map
  38308. // set up the real parent node
  38309. if(!this.parent){
  38310. // use the standard algorithm, if not assigned
  38311. this.parent = this.node;
  38312. if(this.parent.tagName.toLowerCase() == "table"){
  38313. var c = this.parent.getElementsByTagName("tbody");
  38314. if(c && c.length){ this.parent = c[0]; }
  38315. }
  38316. }
  38317. this.defaultCreator = dojo.dnd._defaultCreator(this.parent);
  38318. // process specially marked children
  38319. this.sync();
  38320. },
  38321. // mouse events
  38322. onMouseOver: function(e){
  38323. // summary:
  38324. // event processor for onmouseover
  38325. // e: Event
  38326. // mouse event
  38327. var n = e.relatedTarget;
  38328. while(n){
  38329. if(n == this.node){ break; }
  38330. try{
  38331. n = n.parentNode;
  38332. }catch(x){
  38333. n = null;
  38334. }
  38335. }
  38336. if(!n){
  38337. this._changeState("Container", "Over");
  38338. this.onOverEvent();
  38339. }
  38340. n = this._getChildByEvent(e);
  38341. if(this.current == n){ return; }
  38342. if(this.current){ this._removeItemClass(this.current, "Over"); }
  38343. if(n){ this._addItemClass(n, "Over"); }
  38344. this.current = n;
  38345. },
  38346. onMouseOut: function(e){
  38347. // summary:
  38348. // event processor for onmouseout
  38349. // e: Event
  38350. // mouse event
  38351. for(var n = e.relatedTarget; n;){
  38352. if(n == this.node){ return; }
  38353. try{
  38354. n = n.parentNode;
  38355. }catch(x){
  38356. n = null;
  38357. }
  38358. }
  38359. if(this.current){
  38360. this._removeItemClass(this.current, "Over");
  38361. this.current = null;
  38362. }
  38363. this._changeState("Container", "");
  38364. this.onOutEvent();
  38365. },
  38366. onSelectStart: function(e){
  38367. // summary:
  38368. // event processor for onselectevent and ondragevent
  38369. // e: Event
  38370. // mouse event
  38371. if(!this.skipForm || !dojo.dnd.isFormElement(e)){
  38372. dojo.stopEvent(e);
  38373. }
  38374. },
  38375. // utilities
  38376. onOverEvent: function(){
  38377. // summary:
  38378. // this function is called once, when mouse is over our container
  38379. },
  38380. onOutEvent: function(){
  38381. // summary:
  38382. // this function is called once, when mouse is out of our container
  38383. },
  38384. _changeState: function(type, newState){
  38385. // summary:
  38386. // changes a named state to new state value
  38387. // type: String
  38388. // a name of the state to change
  38389. // newState: String
  38390. // new state
  38391. var prefix = "dojoDnd" + type;
  38392. var state = type.toLowerCase() + "State";
  38393. //dojo.replaceClass(this.node, prefix + newState, prefix + this[state]);
  38394. dojo.replaceClass(this.node, prefix + newState, prefix + this[state]);
  38395. this[state] = newState;
  38396. },
  38397. _addItemClass: function(node, type){
  38398. // summary:
  38399. // adds a class with prefix "dojoDndItem"
  38400. // node: Node
  38401. // a node
  38402. // type: String
  38403. // a variable suffix for a class name
  38404. dojo.addClass(node, "dojoDndItem" + type);
  38405. },
  38406. _removeItemClass: function(node, type){
  38407. // summary:
  38408. // removes a class with prefix "dojoDndItem"
  38409. // node: Node
  38410. // a node
  38411. // type: String
  38412. // a variable suffix for a class name
  38413. dojo.removeClass(node, "dojoDndItem" + type);
  38414. },
  38415. _getChildByEvent: function(e){
  38416. // summary:
  38417. // gets a child, which is under the mouse at the moment, or null
  38418. // e: Event
  38419. // a mouse event
  38420. var node = e.target;
  38421. if(node){
  38422. for(var parent = node.parentNode; parent; node = parent, parent = node.parentNode){
  38423. if(parent == this.parent && dojo.hasClass(node, "dojoDndItem")){ return node; }
  38424. }
  38425. }
  38426. return null;
  38427. },
  38428. _normalizedCreator: function(/*dojo.dnd.Item*/ item, /*String*/ hint){
  38429. // summary:
  38430. // adds all necessary data to the output of the user-supplied creator function
  38431. var t = (this.creator || this.defaultCreator).call(this, item, hint);
  38432. if(!dojo.isArray(t.type)){ t.type = ["text"]; }
  38433. if(!t.node.id){ t.node.id = dojo.dnd.getUniqueId(); }
  38434. dojo.addClass(t.node, "dojoDndItem");
  38435. return t;
  38436. }
  38437. });
  38438. dojo.dnd._createNode = function(tag){
  38439. // summary:
  38440. // returns a function, which creates an element of given tag
  38441. // (SPAN by default) and sets its innerHTML to given text
  38442. // tag: String
  38443. // a tag name or empty for SPAN
  38444. if(!tag){ return dojo.dnd._createSpan; }
  38445. return function(text){ // Function
  38446. return dojo.create(tag, {innerHTML: text}); // Node
  38447. };
  38448. };
  38449. dojo.dnd._createTrTd = function(text){
  38450. // summary:
  38451. // creates a TR/TD structure with given text as an innerHTML of TD
  38452. // text: String
  38453. // a text for TD
  38454. var tr = dojo.create("tr");
  38455. dojo.create("td", {innerHTML: text}, tr);
  38456. return tr; // Node
  38457. };
  38458. dojo.dnd._createSpan = function(text){
  38459. // summary:
  38460. // creates a SPAN element with given text as its innerHTML
  38461. // text: String
  38462. // a text for SPAN
  38463. return dojo.create("span", {innerHTML: text}); // Node
  38464. };
  38465. // dojo.dnd._defaultCreatorNodes: Object
  38466. // a dictionary that maps container tag names to child tag names
  38467. dojo.dnd._defaultCreatorNodes = {ul: "li", ol: "li", div: "div", p: "div"};
  38468. dojo.dnd._defaultCreator = function(node){
  38469. // summary:
  38470. // takes a parent node, and returns an appropriate creator function
  38471. // node: Node
  38472. // a container node
  38473. var tag = node.tagName.toLowerCase();
  38474. var c = tag == "tbody" || tag == "thead" ? dojo.dnd._createTrTd :
  38475. dojo.dnd._createNode(dojo.dnd._defaultCreatorNodes[tag]);
  38476. return function(item, hint){ // Function
  38477. var isObj = item && dojo.isObject(item), data, type, n;
  38478. if(isObj && item.tagName && item.nodeType && item.getAttribute){
  38479. // process a DOM node
  38480. data = item.getAttribute("dndData") || item.innerHTML;
  38481. type = item.getAttribute("dndType");
  38482. type = type ? type.split(/\s*,\s*/) : ["text"];
  38483. n = item; // this node is going to be moved rather than copied
  38484. }else{
  38485. // process a DnD item object or a string
  38486. data = (isObj && item.data) ? item.data : item;
  38487. type = (isObj && item.type) ? item.type : ["text"];
  38488. n = (hint == "avatar" ? dojo.dnd._createSpan : c)(String(data));
  38489. }
  38490. if(!n.id){
  38491. n.id = dojo.dnd.getUniqueId();
  38492. }
  38493. return {node: n, data: data, type: type};
  38494. };
  38495. };
  38496. return dojo.dnd.Container;
  38497. });
  38498. },
  38499. 'dijit/_Widget':function(){
  38500. define("dijit/_Widget", [
  38501. "dojo/aspect", // aspect.around
  38502. "dojo/_base/config", // config.isDebug
  38503. "dojo/_base/connect", // connect.connect
  38504. "dojo/_base/declare", // declare
  38505. "dojo/_base/kernel", // kernel.deprecated
  38506. "dojo/_base/lang", // lang.hitch
  38507. "dojo/query",
  38508. "dojo/ready",
  38509. "./registry", // registry.byNode
  38510. "./_WidgetBase",
  38511. "./_OnDijitClickMixin",
  38512. "./_FocusMixin",
  38513. "dojo/uacss", // browser sniffing (included for back-compat; subclasses may be using)
  38514. "./hccss" // high contrast mode sniffing (included to set CSS classes on <body>, module ret value unused)
  38515. ], function(aspect, config, connect, declare, kernel, lang, query, ready,
  38516. registry, _WidgetBase, _OnDijitClickMixin, _FocusMixin){
  38517. /*=====
  38518. var _WidgetBase = dijit._WidgetBase;
  38519. var _OnDijitClickMixin = dijit._OnDijitClickMixin;
  38520. var _FocusMixin = dijit._FocusMixin;
  38521. =====*/
  38522. // module:
  38523. // dijit/_Widget
  38524. // summary:
  38525. // Old base for widgets. New widgets should extend _WidgetBase instead
  38526. function connectToDomNode(){
  38527. // summary:
  38528. // If user connects to a widget method === this function, then they will
  38529. // instead actually be connecting the equivalent event on this.domNode
  38530. }
  38531. // Trap dojo.connect() calls to connectToDomNode methods, and redirect to _Widget.on()
  38532. function aroundAdvice(originalConnect){
  38533. return function(obj, event, scope, method){
  38534. if(obj && typeof event == "string" && obj[event] == connectToDomNode){
  38535. return obj.on(event.substring(2).toLowerCase(), lang.hitch(scope, method));
  38536. }
  38537. return originalConnect.apply(connect, arguments);
  38538. };
  38539. }
  38540. aspect.around(connect, "connect", aroundAdvice);
  38541. if(kernel.connect){
  38542. aspect.around(kernel, "connect", aroundAdvice);
  38543. }
  38544. var _Widget = declare("dijit._Widget", [_WidgetBase, _OnDijitClickMixin, _FocusMixin], {
  38545. // summary:
  38546. // Base class for all Dijit widgets.
  38547. //
  38548. // Extends _WidgetBase, adding support for:
  38549. // - declaratively/programatically specifying widget initialization parameters like
  38550. // onMouseMove="foo" that call foo when this.domNode gets a mousemove event
  38551. // - ondijitclick
  38552. // Support new data-dojo-attach-event="ondijitclick: ..." that is triggered by a mouse click or a SPACE/ENTER keypress
  38553. // - focus related functions
  38554. // In particular, the onFocus()/onBlur() callbacks. Driven internally by
  38555. // dijit/_base/focus.js.
  38556. // - deprecated methods
  38557. // - onShow(), onHide(), onClose()
  38558. //
  38559. // Also, by loading code in dijit/_base, turns on:
  38560. // - browser sniffing (putting browser id like .dj_ie on <html> node)
  38561. // - high contrast mode sniffing (add .dijit_a11y class to <body> if machine is in high contrast mode)
  38562. ////////////////// DEFERRED CONNECTS ///////////////////
  38563. onClick: connectToDomNode,
  38564. /*=====
  38565. onClick: function(event){
  38566. // summary:
  38567. // Connect to this function to receive notifications of mouse click events.
  38568. // event:
  38569. // mouse Event
  38570. // tags:
  38571. // callback
  38572. },
  38573. =====*/
  38574. onDblClick: connectToDomNode,
  38575. /*=====
  38576. onDblClick: function(event){
  38577. // summary:
  38578. // Connect to this function to receive notifications of mouse double click events.
  38579. // event:
  38580. // mouse Event
  38581. // tags:
  38582. // callback
  38583. },
  38584. =====*/
  38585. onKeyDown: connectToDomNode,
  38586. /*=====
  38587. onKeyDown: function(event){
  38588. // summary:
  38589. // Connect to this function to receive notifications of keys being pressed down.
  38590. // event:
  38591. // key Event
  38592. // tags:
  38593. // callback
  38594. },
  38595. =====*/
  38596. onKeyPress: connectToDomNode,
  38597. /*=====
  38598. onKeyPress: function(event){
  38599. // summary:
  38600. // Connect to this function to receive notifications of printable keys being typed.
  38601. // event:
  38602. // key Event
  38603. // tags:
  38604. // callback
  38605. },
  38606. =====*/
  38607. onKeyUp: connectToDomNode,
  38608. /*=====
  38609. onKeyUp: function(event){
  38610. // summary:
  38611. // Connect to this function to receive notifications of keys being released.
  38612. // event:
  38613. // key Event
  38614. // tags:
  38615. // callback
  38616. },
  38617. =====*/
  38618. onMouseDown: connectToDomNode,
  38619. /*=====
  38620. onMouseDown: function(event){
  38621. // summary:
  38622. // Connect to this function to receive notifications of when the mouse button is pressed down.
  38623. // event:
  38624. // mouse Event
  38625. // tags:
  38626. // callback
  38627. },
  38628. =====*/
  38629. onMouseMove: connectToDomNode,
  38630. /*=====
  38631. onMouseMove: function(event){
  38632. // summary:
  38633. // Connect to this function to receive notifications of when the mouse moves over nodes contained within this widget.
  38634. // event:
  38635. // mouse Event
  38636. // tags:
  38637. // callback
  38638. },
  38639. =====*/
  38640. onMouseOut: connectToDomNode,
  38641. /*=====
  38642. onMouseOut: function(event){
  38643. // summary:
  38644. // Connect to this function to receive notifications of when the mouse moves off of nodes contained within this widget.
  38645. // event:
  38646. // mouse Event
  38647. // tags:
  38648. // callback
  38649. },
  38650. =====*/
  38651. onMouseOver: connectToDomNode,
  38652. /*=====
  38653. onMouseOver: function(event){
  38654. // summary:
  38655. // Connect to this function to receive notifications of when the mouse moves onto nodes contained within this widget.
  38656. // event:
  38657. // mouse Event
  38658. // tags:
  38659. // callback
  38660. },
  38661. =====*/
  38662. onMouseLeave: connectToDomNode,
  38663. /*=====
  38664. onMouseLeave: function(event){
  38665. // summary:
  38666. // Connect to this function to receive notifications of when the mouse moves off of this widget.
  38667. // event:
  38668. // mouse Event
  38669. // tags:
  38670. // callback
  38671. },
  38672. =====*/
  38673. onMouseEnter: connectToDomNode,
  38674. /*=====
  38675. onMouseEnter: function(event){
  38676. // summary:
  38677. // Connect to this function to receive notifications of when the mouse moves onto this widget.
  38678. // event:
  38679. // mouse Event
  38680. // tags:
  38681. // callback
  38682. },
  38683. =====*/
  38684. onMouseUp: connectToDomNode,
  38685. /*=====
  38686. onMouseUp: function(event){
  38687. // summary:
  38688. // Connect to this function to receive notifications of when the mouse button is released.
  38689. // event:
  38690. // mouse Event
  38691. // tags:
  38692. // callback
  38693. },
  38694. =====*/
  38695. constructor: function(params){
  38696. // extract parameters like onMouseMove that should connect directly to this.domNode
  38697. this._toConnect = {};
  38698. for(var name in params){
  38699. if(this[name] === connectToDomNode){
  38700. this._toConnect[name.replace(/^on/, "").toLowerCase()] = params[name];
  38701. delete params[name];
  38702. }
  38703. }
  38704. },
  38705. postCreate: function(){
  38706. this.inherited(arguments);
  38707. // perform connection from this.domNode to user specified handlers (ex: onMouseMove)
  38708. for(var name in this._toConnect){
  38709. this.on(name, this._toConnect[name]);
  38710. }
  38711. delete this._toConnect;
  38712. },
  38713. on: function(/*String*/ type, /*Function*/ func){
  38714. if(this[this._onMap(type)] === connectToDomNode){
  38715. // Use connect.connect() rather than on() to get handling for "onmouseenter" on non-IE, etc.
  38716. // Also, need to specify context as "this" rather than the default context of the DOMNode
  38717. return connect.connect(this.domNode, type.toLowerCase(), this, func);
  38718. }
  38719. return this.inherited(arguments);
  38720. },
  38721. _setFocusedAttr: function(val){
  38722. // Remove this method in 2.0 (or sooner), just here to set _focused == focused, for back compat
  38723. // (but since it's a private variable we aren't required to keep supporting it).
  38724. this._focused = val;
  38725. this._set("focused", val);
  38726. },
  38727. ////////////////// DEPRECATED METHODS ///////////////////
  38728. setAttribute: function(/*String*/ attr, /*anything*/ value){
  38729. // summary:
  38730. // Deprecated. Use set() instead.
  38731. // tags:
  38732. // deprecated
  38733. kernel.deprecated(this.declaredClass+"::setAttribute(attr, value) is deprecated. Use set() instead.", "", "2.0");
  38734. this.set(attr, value);
  38735. },
  38736. attr: function(/*String|Object*/name, /*Object?*/value){
  38737. // summary:
  38738. // Set or get properties on a widget instance.
  38739. // name:
  38740. // The property to get or set. If an object is passed here and not
  38741. // a string, its keys are used as names of attributes to be set
  38742. // and the value of the object as values to set in the widget.
  38743. // value:
  38744. // Optional. If provided, attr() operates as a setter. If omitted,
  38745. // the current value of the named property is returned.
  38746. // description:
  38747. // This method is deprecated, use get() or set() directly.
  38748. // Print deprecation warning but only once per calling function
  38749. if(config.isDebug){
  38750. var alreadyCalledHash = arguments.callee._ach || (arguments.callee._ach = {}),
  38751. caller = (arguments.callee.caller || "unknown caller").toString();
  38752. if(!alreadyCalledHash[caller]){
  38753. kernel.deprecated(this.declaredClass + "::attr() is deprecated. Use get() or set() instead, called from " +
  38754. caller, "", "2.0");
  38755. alreadyCalledHash[caller] = true;
  38756. }
  38757. }
  38758. var args = arguments.length;
  38759. if(args >= 2 || typeof name === "object"){ // setter
  38760. return this.set.apply(this, arguments);
  38761. }else{ // getter
  38762. return this.get(name);
  38763. }
  38764. },
  38765. getDescendants: function(){
  38766. // summary:
  38767. // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode.
  38768. // This method should generally be avoided as it returns widgets declared in templates, which are
  38769. // supposed to be internal/hidden, but it's left here for back-compat reasons.
  38770. kernel.deprecated(this.declaredClass+"::getDescendants() is deprecated. Use getChildren() instead.", "", "2.0");
  38771. return this.containerNode ? query('[widgetId]', this.containerNode).map(registry.byNode) : []; // dijit._Widget[]
  38772. },
  38773. ////////////////// MISCELLANEOUS METHODS ///////////////////
  38774. _onShow: function(){
  38775. // summary:
  38776. // Internal method called when this widget is made visible.
  38777. // See `onShow` for details.
  38778. this.onShow();
  38779. },
  38780. onShow: function(){
  38781. // summary:
  38782. // Called when this widget becomes the selected pane in a
  38783. // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
  38784. // `dijit.layout.AccordionContainer`, etc.
  38785. //
  38786. // Also called to indicate display of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
  38787. // tags:
  38788. // callback
  38789. },
  38790. onHide: function(){
  38791. // summary:
  38792. // Called when another widget becomes the selected pane in a
  38793. // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
  38794. // `dijit.layout.AccordionContainer`, etc.
  38795. //
  38796. // Also called to indicate hide of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
  38797. // tags:
  38798. // callback
  38799. },
  38800. onClose: function(){
  38801. // summary:
  38802. // Called when this widget is being displayed as a popup (ex: a Calendar popped
  38803. // up from a DateTextBox), and it is hidden.
  38804. // This is called from the dijit.popup code, and should not be called directly.
  38805. //
  38806. // Also used as a parameter for children of `dijit.layout.StackContainer` or subclasses.
  38807. // Callback if a user tries to close the child. Child will be closed if this function returns true.
  38808. // tags:
  38809. // extension
  38810. return true; // Boolean
  38811. }
  38812. });
  38813. // For back-compat, remove in 2.0.
  38814. if(!kernel.isAsync){
  38815. ready(0, function(){
  38816. var requires = ["dijit/_base"];
  38817. require(requires); // use indirection so modules not rolled into a build
  38818. });
  38819. }
  38820. return _Widget;
  38821. });
  38822. },
  38823. 'dojo/touch':function(){
  38824. define("dojo/touch", ["./_base/kernel", "./on", "./has", "./mouse"], function(dojo, on, has, mouse){
  38825. // module:
  38826. // dojo/touch
  38827. /*=====
  38828. dojo.touch = {
  38829. // summary:
  38830. // This module provides unified touch event handlers by exporting
  38831. // press, move, release and cancel which can also run well on desktop.
  38832. // Based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
  38833. //
  38834. // example:
  38835. // 1. Used with dojo.connect()
  38836. // | dojo.connect(node, dojo.touch.press, function(e){});
  38837. // | dojo.connect(node, dojo.touch.move, function(e){});
  38838. // | dojo.connect(node, dojo.touch.release, function(e){});
  38839. // | dojo.connect(node, dojo.touch.cancel, function(e){});
  38840. //
  38841. // 2. Used with dojo.on
  38842. // | define(["dojo/on", "dojo/touch"], function(on, touch){
  38843. // | on(node, touch.press, function(e){});
  38844. // | on(node, touch.move, function(e){});
  38845. // | on(node, touch.release, function(e){});
  38846. // | on(node, touch.cancel, function(e){});
  38847. //
  38848. // 3. Used with dojo.touch.* directly
  38849. // | dojo.touch.press(node, function(e){});
  38850. // | dojo.touch.move(node, function(e){});
  38851. // | dojo.touch.release(node, function(e){});
  38852. // | dojo.touch.cancel(node, function(e){});
  38853. press: function(node, listener){
  38854. // summary:
  38855. // Register a listener to 'touchstart'|'mousedown' for the given node
  38856. // node: Dom
  38857. // Target node to listen to
  38858. // listener: Function
  38859. // Callback function
  38860. // returns:
  38861. // A handle which will be used to remove the listener by handle.remove()
  38862. },
  38863. move: function(node, listener){
  38864. // summary:
  38865. // Register a listener to 'touchmove'|'mousemove' for the given node
  38866. // node: Dom
  38867. // Target node to listen to
  38868. // listener: Function
  38869. // Callback function
  38870. // returns:
  38871. // A handle which will be used to remove the listener by handle.remove()
  38872. },
  38873. release: function(node, listener){
  38874. // summary:
  38875. // Register a listener to 'touchend'|'mouseup' for the given node
  38876. // node: Dom
  38877. // Target node to listen to
  38878. // listener: Function
  38879. // Callback function
  38880. // returns:
  38881. // A handle which will be used to remove the listener by handle.remove()
  38882. },
  38883. cancel: function(node, listener){
  38884. // summary:
  38885. // Register a listener to 'touchcancel'|'mouseleave' for the given node
  38886. // node: Dom
  38887. // Target node to listen to
  38888. // listener: Function
  38889. // Callback function
  38890. // returns:
  38891. // A handle which will be used to remove the listener by handle.remove()
  38892. }
  38893. };
  38894. =====*/
  38895. function _handle(/*String - press | move | release | cancel*/type){
  38896. return function(node, listener){//called by on(), see dojo.on
  38897. return on(node, type, listener);
  38898. };
  38899. }
  38900. var touch = has("touch");
  38901. //device neutral events - dojo.touch.press|move|release|cancel
  38902. dojo.touch = {
  38903. press: _handle(touch ? "touchstart": "mousedown"),
  38904. move: _handle(touch ? "touchmove": "mousemove"),
  38905. release: _handle(touch ? "touchend": "mouseup"),
  38906. cancel: touch ? _handle("touchcancel") : mouse.leave
  38907. };
  38908. return dojo.touch;
  38909. });
  38910. },
  38911. 'dojox/grid/DataSelection':function(){
  38912. define("dojox/grid/DataSelection", [
  38913. "dojo/_base/declare",
  38914. "./_SelectionPreserver",
  38915. "./Selection"
  38916. ], function(declare, _SelectionPreserver, Selection){
  38917. return declare("dojox.grid.DataSelection", Selection, {
  38918. constructor: function(grid){
  38919. if(grid.keepSelection){
  38920. this.preserver = new _SelectionPreserver(this);
  38921. }
  38922. },
  38923. destroy: function(){
  38924. if(this.preserver){
  38925. this.preserver.destroy();
  38926. }
  38927. },
  38928. getFirstSelected: function(){
  38929. var idx = Selection.prototype.getFirstSelected.call(this);
  38930. if(idx == -1){ return null; }
  38931. return this.grid.getItem(idx);
  38932. },
  38933. getNextSelected: function(inPrev){
  38934. var old_idx = this.grid.getItemIndex(inPrev);
  38935. var idx = Selection.prototype.getNextSelected.call(this, old_idx);
  38936. if(idx == -1){ return null; }
  38937. return this.grid.getItem(idx);
  38938. },
  38939. getSelected: function(){
  38940. var result = [];
  38941. for(var i=0, l=this.selected.length; i<l; i++){
  38942. if(this.selected[i]){
  38943. result.push(this.grid.getItem(i));
  38944. }
  38945. }
  38946. return result;
  38947. },
  38948. addToSelection: function(inItemOrIndex){
  38949. if(this.mode == 'none'){ return; }
  38950. var idx = null;
  38951. if(typeof inItemOrIndex == "number" || typeof inItemOrIndex == "string"){
  38952. idx = inItemOrIndex;
  38953. }else{
  38954. idx = this.grid.getItemIndex(inItemOrIndex);
  38955. }
  38956. Selection.prototype.addToSelection.call(this, idx);
  38957. },
  38958. deselect: function(inItemOrIndex){
  38959. if(this.mode == 'none'){ return; }
  38960. var idx = null;
  38961. if(typeof inItemOrIndex == "number" || typeof inItemOrIndex == "string"){
  38962. idx = inItemOrIndex;
  38963. }else{
  38964. idx = this.grid.getItemIndex(inItemOrIndex);
  38965. }
  38966. Selection.prototype.deselect.call(this, idx);
  38967. },
  38968. deselectAll: function(inItemOrIndex){
  38969. var idx = null;
  38970. if(inItemOrIndex || typeof inItemOrIndex == "number"){
  38971. if(typeof inItemOrIndex == "number" || typeof inItemOrIndex == "string"){
  38972. idx = inItemOrIndex;
  38973. }else{
  38974. idx = this.grid.getItemIndex(inItemOrIndex);
  38975. }
  38976. Selection.prototype.deselectAll.call(this, idx);
  38977. }else{
  38978. this.inherited(arguments);
  38979. }
  38980. }
  38981. });
  38982. });
  38983. },
  38984. 'dijit/_editor/selection':function(){
  38985. define("dijit/_editor/selection", [
  38986. "dojo/dom", // dom.byId
  38987. "dojo/_base/lang",
  38988. "dojo/_base/sniff", // has("ie") has("opera")
  38989. "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
  38990. ".." // for exporting symbols to dijit._editor.selection (TODO: remove in 2.0)
  38991. ], function(dom, lang, has, win, dijit){
  38992. // module:
  38993. // dijit/_editor/selection
  38994. // summary:
  38995. // Text selection API
  38996. lang.getObject("_editor.selection", true, dijit);
  38997. // FIXME:
  38998. // all of these methods branch internally for IE. This is probably
  38999. // sub-optimal in terms of runtime performance. We should investigate the
  39000. // size difference for differentiating at definition time.
  39001. lang.mixin(dijit._editor.selection, {
  39002. getType: function(){
  39003. // summary:
  39004. // Get the selection type (like win.doc.select.type in IE).
  39005. if(has("ie") < 9){
  39006. return win.doc.selection.type.toLowerCase();
  39007. }else{
  39008. var stype = "text";
  39009. // Check if the actual selection is a CONTROL (IMG, TABLE, HR, etc...).
  39010. var oSel;
  39011. try{
  39012. oSel = win.global.getSelection();
  39013. }catch(e){ /*squelch*/ }
  39014. if(oSel && oSel.rangeCount == 1){
  39015. var oRange = oSel.getRangeAt(0);
  39016. if( (oRange.startContainer == oRange.endContainer) &&
  39017. ((oRange.endOffset - oRange.startOffset) == 1) &&
  39018. (oRange.startContainer.nodeType != 3 /* text node*/)
  39019. ){
  39020. stype = "control";
  39021. }
  39022. }
  39023. return stype; //String
  39024. }
  39025. },
  39026. getSelectedText: function(){
  39027. // summary:
  39028. // Return the text (no html tags) included in the current selection or null if no text is selected
  39029. if(has("ie") < 9){
  39030. if(dijit._editor.selection.getType() == 'control'){
  39031. return null;
  39032. }
  39033. return win.doc.selection.createRange().text;
  39034. }else{
  39035. var selection = win.global.getSelection();
  39036. if(selection){
  39037. return selection.toString(); //String
  39038. }
  39039. }
  39040. return '';
  39041. },
  39042. getSelectedHtml: function(){
  39043. // summary:
  39044. // Return the html text of the current selection or null if unavailable
  39045. if(has("ie") < 9){
  39046. if(dijit._editor.selection.getType() == 'control'){
  39047. return null;
  39048. }
  39049. return win.doc.selection.createRange().htmlText;
  39050. }else{
  39051. var selection = win.global.getSelection();
  39052. if(selection && selection.rangeCount){
  39053. var i;
  39054. var html = "";
  39055. for(i = 0; i < selection.rangeCount; i++){
  39056. //Handle selections spanning ranges, such as Opera
  39057. var frag = selection.getRangeAt(i).cloneContents();
  39058. var div = win.doc.createElement("div");
  39059. div.appendChild(frag);
  39060. html += div.innerHTML;
  39061. }
  39062. return html; //String
  39063. }
  39064. return null;
  39065. }
  39066. },
  39067. getSelectedElement: function(){
  39068. // summary:
  39069. // Retrieves the selected element (if any), just in the case that
  39070. // a single element (object like and image or a table) is
  39071. // selected.
  39072. if(dijit._editor.selection.getType() == "control"){
  39073. if(has("ie") < 9){
  39074. var range = win.doc.selection.createRange();
  39075. if(range && range.item){
  39076. return win.doc.selection.createRange().item(0);
  39077. }
  39078. }else{
  39079. var selection = win.global.getSelection();
  39080. return selection.anchorNode.childNodes[ selection.anchorOffset ];
  39081. }
  39082. }
  39083. return null;
  39084. },
  39085. getParentElement: function(){
  39086. // summary:
  39087. // Get the parent element of the current selection
  39088. if(dijit._editor.selection.getType() == "control"){
  39089. var p = this.getSelectedElement();
  39090. if(p){ return p.parentNode; }
  39091. }else{
  39092. if(has("ie") < 9){
  39093. var r = win.doc.selection.createRange();
  39094. r.collapse(true);
  39095. return r.parentElement();
  39096. }else{
  39097. var selection = win.global.getSelection();
  39098. if(selection){
  39099. var node = selection.anchorNode;
  39100. while(node && (node.nodeType != 1)){ // not an element
  39101. node = node.parentNode;
  39102. }
  39103. return node;
  39104. }
  39105. }
  39106. }
  39107. return null;
  39108. },
  39109. hasAncestorElement: function(/*String*/tagName /* ... */){
  39110. // summary:
  39111. // Check whether current selection has a parent element which is
  39112. // of type tagName (or one of the other specified tagName)
  39113. // tagName: String
  39114. // The tag name to determine if it has an ancestor of.
  39115. return this.getAncestorElement.apply(this, arguments) != null; //Boolean
  39116. },
  39117. getAncestorElement: function(/*String*/tagName /* ... */){
  39118. // summary:
  39119. // Return the parent element of the current selection which is of
  39120. // type tagName (or one of the other specified tagName)
  39121. // tagName: String
  39122. // The tag name to determine if it has an ancestor of.
  39123. var node = this.getSelectedElement() || this.getParentElement();
  39124. return this.getParentOfType(node, arguments); //DOMNode
  39125. },
  39126. isTag: function(/*DomNode*/ node, /*String[]*/ tags){
  39127. // summary:
  39128. // Function to determine if a node is one of an array of tags.
  39129. // node:
  39130. // The node to inspect.
  39131. // tags:
  39132. // An array of tag name strings to check to see if the node matches.
  39133. if(node && node.tagName){
  39134. var _nlc = node.tagName.toLowerCase();
  39135. for(var i=0; i<tags.length; i++){
  39136. var _tlc = String(tags[i]).toLowerCase();
  39137. if(_nlc == _tlc){
  39138. return _tlc; // String
  39139. }
  39140. }
  39141. }
  39142. return "";
  39143. },
  39144. getParentOfType: function(/*DomNode*/ node, /*String[]*/ tags){
  39145. // summary:
  39146. // Function to locate a parent node that matches one of a set of tags
  39147. // node:
  39148. // The node to inspect.
  39149. // tags:
  39150. // An array of tag name strings to check to see if the node matches.
  39151. while(node){
  39152. if(this.isTag(node, tags).length){
  39153. return node; // DOMNode
  39154. }
  39155. node = node.parentNode;
  39156. }
  39157. return null;
  39158. },
  39159. collapse: function(/*Boolean*/beginning){
  39160. // summary:
  39161. // Function to collapse (clear), the current selection
  39162. // beginning: Boolean
  39163. // Boolean to indicate whether to collapse the cursor to the beginning of the selection or end.
  39164. if(window.getSelection){
  39165. var selection = win.global.getSelection();
  39166. if(selection.removeAllRanges){ // Mozilla
  39167. if(beginning){
  39168. selection.collapseToStart();
  39169. }else{
  39170. selection.collapseToEnd();
  39171. }
  39172. }else{ // Safari
  39173. // pulled from WebCore/ecma/kjs_window.cpp, line 2536
  39174. selection.collapse(beginning);
  39175. }
  39176. }else if(has("ie")){ // IE
  39177. var range = win.doc.selection.createRange();
  39178. range.collapse(beginning);
  39179. range.select();
  39180. }
  39181. },
  39182. remove: function(){
  39183. // summary:
  39184. // Function to delete the currently selected content from the document.
  39185. var sel = win.doc.selection;
  39186. if(has("ie") < 9){
  39187. if(sel.type.toLowerCase() != "none"){
  39188. sel.clear();
  39189. }
  39190. return sel; //Selection
  39191. }else{
  39192. sel = win.global.getSelection();
  39193. sel.deleteFromDocument();
  39194. return sel; //Selection
  39195. }
  39196. },
  39197. selectElementChildren: function(/*DomNode*/element,/*Boolean?*/nochangefocus){
  39198. // summary:
  39199. // clear previous selection and select the content of the node
  39200. // (excluding the node itself)
  39201. // element: DOMNode
  39202. // The element you wish to select the children content of.
  39203. // nochangefocus: Boolean
  39204. // Boolean to indicate if the foxus should change or not.
  39205. var global = win.global;
  39206. var doc = win.doc;
  39207. var range;
  39208. element = dom.byId(element);
  39209. if(doc.selection && has("ie") < 9 && win.body().createTextRange){ // IE
  39210. range = element.ownerDocument.body.createTextRange();
  39211. range.moveToElementText(element);
  39212. if(!nochangefocus){
  39213. try{
  39214. range.select(); // IE throws an exception here if the widget is hidden. See #5439
  39215. }catch(e){ /* squelch */}
  39216. }
  39217. }else if(global.getSelection){
  39218. var selection = win.global.getSelection();
  39219. if(has("opera")){
  39220. //Opera's selectAllChildren doesn't seem to work right
  39221. //against <body> nodes and possibly others ... so
  39222. //we use the W3C range API
  39223. if(selection.rangeCount){
  39224. range = selection.getRangeAt(0);
  39225. }else{
  39226. range = doc.createRange();
  39227. }
  39228. range.setStart(element, 0);
  39229. range.setEnd(element,(element.nodeType == 3)?element.length:element.childNodes.length);
  39230. selection.addRange(range);
  39231. }else{
  39232. selection.selectAllChildren(element);
  39233. }
  39234. }
  39235. },
  39236. selectElement: function(/*DomNode*/element,/*Boolean?*/nochangefocus){
  39237. // summary:
  39238. // clear previous selection and select element (including all its children)
  39239. // element: DOMNode
  39240. // The element to select.
  39241. // nochangefocus: Boolean
  39242. // Boolean indicating if the focus should be changed. IE only.
  39243. var range;
  39244. var doc = win.doc;
  39245. var global = win.global;
  39246. element = dom.byId(element);
  39247. if(has("ie") < 9 && win.body().createTextRange){
  39248. try{
  39249. var tg = element.tagName ? element.tagName.toLowerCase() : "";
  39250. if(tg === "img" || tg === "table"){
  39251. range = win.body().createControlRange();
  39252. }else{
  39253. range = win.body().createRange();
  39254. }
  39255. range.addElement(element);
  39256. if(!nochangefocus){
  39257. range.select();
  39258. }
  39259. }catch(e){
  39260. this.selectElementChildren(element,nochangefocus);
  39261. }
  39262. }else if(global.getSelection){
  39263. var selection = global.getSelection();
  39264. range = doc.createRange();
  39265. if(selection.removeAllRanges){ // Mozilla
  39266. // FIXME: does this work on Safari?
  39267. if(has("opera")){
  39268. //Opera works if you use the current range on
  39269. //the selection if present.
  39270. if(selection.getRangeAt(0)){
  39271. range = selection.getRangeAt(0);
  39272. }
  39273. }
  39274. range.selectNode(element);
  39275. selection.removeAllRanges();
  39276. selection.addRange(range);
  39277. }
  39278. }
  39279. },
  39280. inSelection: function(node){
  39281. // summary:
  39282. // This function determines if 'node' is
  39283. // in the current selection.
  39284. // tags:
  39285. // public
  39286. if(node){
  39287. var newRange;
  39288. var doc = win.doc;
  39289. var range;
  39290. if(win.global.getSelection){
  39291. //WC3
  39292. var sel = win.global.getSelection();
  39293. if(sel && sel.rangeCount > 0){
  39294. range = sel.getRangeAt(0);
  39295. }
  39296. if(range && range.compareBoundaryPoints && doc.createRange){
  39297. try{
  39298. newRange = doc.createRange();
  39299. newRange.setStart(node, 0);
  39300. if(range.compareBoundaryPoints(range.START_TO_END, newRange) === 1){
  39301. return true;
  39302. }
  39303. }catch(e){ /* squelch */}
  39304. }
  39305. }else if(doc.selection){
  39306. // Probably IE, so we can't use the range object as the pseudo
  39307. // range doesn't implement the boundry checking, we have to
  39308. // use IE specific crud.
  39309. range = doc.selection.createRange();
  39310. try{
  39311. newRange = node.ownerDocument.body.createControlRange();
  39312. if(newRange){
  39313. newRange.addElement(node);
  39314. }
  39315. }catch(e1){
  39316. try{
  39317. newRange = node.ownerDocument.body.createTextRange();
  39318. newRange.moveToElementText(node);
  39319. }catch(e2){/* squelch */}
  39320. }
  39321. if(range && newRange){
  39322. // We can finally compare similar to W3C
  39323. if(range.compareEndPoints("EndToStart", newRange) === 1){
  39324. return true;
  39325. }
  39326. }
  39327. }
  39328. }
  39329. return false; // boolean
  39330. }
  39331. });
  39332. return dijit._editor.selection;
  39333. });
  39334. },
  39335. 'dojo/fx':function(){
  39336. define("dojo/fx", [
  39337. "./_base/lang",
  39338. "./Evented",
  39339. "./_base/kernel",
  39340. "./_base/array",
  39341. "./_base/connect",
  39342. "./_base/fx",
  39343. "./dom",
  39344. "./dom-style",
  39345. "./dom-geometry",
  39346. "./ready",
  39347. "require" // for context sensitive loading of Toggler
  39348. ], function(lang, Evented, dojo, arrayUtil, connect, baseFx, dom, domStyle, geom, ready, require) {
  39349. // module:
  39350. // dojo/fx
  39351. // summary:
  39352. // TODOC
  39353. /*=====
  39354. dojo.fx = {
  39355. // summary: Effects library on top of Base animations
  39356. };
  39357. var coreFx = dojo.fx;
  39358. =====*/
  39359. // For back-compat, remove in 2.0.
  39360. if(!dojo.isAsync){
  39361. ready(0, function(){
  39362. var requires = ["./fx/Toggler"];
  39363. require(requires); // use indirection so modules not rolled into a build
  39364. });
  39365. }
  39366. var coreFx = dojo.fx = {};
  39367. var _baseObj = {
  39368. _fire: function(evt, args){
  39369. if(this[evt]){
  39370. this[evt].apply(this, args||[]);
  39371. }
  39372. return this;
  39373. }
  39374. };
  39375. var _chain = function(animations){
  39376. this._index = -1;
  39377. this._animations = animations||[];
  39378. this._current = this._onAnimateCtx = this._onEndCtx = null;
  39379. this.duration = 0;
  39380. arrayUtil.forEach(this._animations, function(a){
  39381. this.duration += a.duration;
  39382. if(a.delay){ this.duration += a.delay; }
  39383. }, this);
  39384. };
  39385. _chain.prototype = new Evented();
  39386. lang.extend(_chain, {
  39387. _onAnimate: function(){
  39388. this._fire("onAnimate", arguments);
  39389. },
  39390. _onEnd: function(){
  39391. connect.disconnect(this._onAnimateCtx);
  39392. connect.disconnect(this._onEndCtx);
  39393. this._onAnimateCtx = this._onEndCtx = null;
  39394. if(this._index + 1 == this._animations.length){
  39395. this._fire("onEnd");
  39396. }else{
  39397. // switch animations
  39398. this._current = this._animations[++this._index];
  39399. this._onAnimateCtx = connect.connect(this._current, "onAnimate", this, "_onAnimate");
  39400. this._onEndCtx = connect.connect(this._current, "onEnd", this, "_onEnd");
  39401. this._current.play(0, true);
  39402. }
  39403. },
  39404. play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
  39405. if(!this._current){ this._current = this._animations[this._index = 0]; }
  39406. if(!gotoStart && this._current.status() == "playing"){ return this; }
  39407. var beforeBegin = connect.connect(this._current, "beforeBegin", this, function(){
  39408. this._fire("beforeBegin");
  39409. }),
  39410. onBegin = connect.connect(this._current, "onBegin", this, function(arg){
  39411. this._fire("onBegin", arguments);
  39412. }),
  39413. onPlay = connect.connect(this._current, "onPlay", this, function(arg){
  39414. this._fire("onPlay", arguments);
  39415. connect.disconnect(beforeBegin);
  39416. connect.disconnect(onBegin);
  39417. connect.disconnect(onPlay);
  39418. });
  39419. if(this._onAnimateCtx){
  39420. connect.disconnect(this._onAnimateCtx);
  39421. }
  39422. this._onAnimateCtx = connect.connect(this._current, "onAnimate", this, "_onAnimate");
  39423. if(this._onEndCtx){
  39424. connect.disconnect(this._onEndCtx);
  39425. }
  39426. this._onEndCtx = connect.connect(this._current, "onEnd", this, "_onEnd");
  39427. this._current.play.apply(this._current, arguments);
  39428. return this;
  39429. },
  39430. pause: function(){
  39431. if(this._current){
  39432. var e = connect.connect(this._current, "onPause", this, function(arg){
  39433. this._fire("onPause", arguments);
  39434. connect.disconnect(e);
  39435. });
  39436. this._current.pause();
  39437. }
  39438. return this;
  39439. },
  39440. gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
  39441. this.pause();
  39442. var offset = this.duration * percent;
  39443. this._current = null;
  39444. arrayUtil.some(this._animations, function(a){
  39445. if(a.duration <= offset){
  39446. this._current = a;
  39447. return true;
  39448. }
  39449. offset -= a.duration;
  39450. return false;
  39451. });
  39452. if(this._current){
  39453. this._current.gotoPercent(offset / this._current.duration, andPlay);
  39454. }
  39455. return this;
  39456. },
  39457. stop: function(/*boolean?*/ gotoEnd){
  39458. if(this._current){
  39459. if(gotoEnd){
  39460. for(; this._index + 1 < this._animations.length; ++this._index){
  39461. this._animations[this._index].stop(true);
  39462. }
  39463. this._current = this._animations[this._index];
  39464. }
  39465. var e = connect.connect(this._current, "onStop", this, function(arg){
  39466. this._fire("onStop", arguments);
  39467. connect.disconnect(e);
  39468. });
  39469. this._current.stop();
  39470. }
  39471. return this;
  39472. },
  39473. status: function(){
  39474. return this._current ? this._current.status() : "stopped";
  39475. },
  39476. destroy: function(){
  39477. if(this._onAnimateCtx){ connect.disconnect(this._onAnimateCtx); }
  39478. if(this._onEndCtx){ connect.disconnect(this._onEndCtx); }
  39479. }
  39480. });
  39481. lang.extend(_chain, _baseObj);
  39482. coreFx.chain = /*===== dojo.fx.chain = =====*/ function(/*dojo.Animation[]*/ animations){
  39483. // summary:
  39484. // Chain a list of `dojo.Animation`s to run in sequence
  39485. //
  39486. // description:
  39487. // Return a `dojo.Animation` which will play all passed
  39488. // `dojo.Animation` instances in sequence, firing its own
  39489. // synthesized events simulating a single animation. (eg:
  39490. // onEnd of this animation means the end of the chain,
  39491. // not the individual animations within)
  39492. //
  39493. // example:
  39494. // Once `node` is faded out, fade in `otherNode`
  39495. // | dojo.fx.chain([
  39496. // | dojo.fadeIn({ node:node }),
  39497. // | dojo.fadeOut({ node:otherNode })
  39498. // | ]).play();
  39499. //
  39500. return new _chain(animations); // dojo.Animation
  39501. };
  39502. var _combine = function(animations){
  39503. this._animations = animations||[];
  39504. this._connects = [];
  39505. this._finished = 0;
  39506. this.duration = 0;
  39507. arrayUtil.forEach(animations, function(a){
  39508. var duration = a.duration;
  39509. if(a.delay){ duration += a.delay; }
  39510. if(this.duration < duration){ this.duration = duration; }
  39511. this._connects.push(connect.connect(a, "onEnd", this, "_onEnd"));
  39512. }, this);
  39513. this._pseudoAnimation = new baseFx.Animation({curve: [0, 1], duration: this.duration});
  39514. var self = this;
  39515. arrayUtil.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"],
  39516. function(evt){
  39517. self._connects.push(connect.connect(self._pseudoAnimation, evt,
  39518. function(){ self._fire(evt, arguments); }
  39519. ));
  39520. }
  39521. );
  39522. };
  39523. lang.extend(_combine, {
  39524. _doAction: function(action, args){
  39525. arrayUtil.forEach(this._animations, function(a){
  39526. a[action].apply(a, args);
  39527. });
  39528. return this;
  39529. },
  39530. _onEnd: function(){
  39531. if(++this._finished > this._animations.length){
  39532. this._fire("onEnd");
  39533. }
  39534. },
  39535. _call: function(action, args){
  39536. var t = this._pseudoAnimation;
  39537. t[action].apply(t, args);
  39538. },
  39539. play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
  39540. this._finished = 0;
  39541. this._doAction("play", arguments);
  39542. this._call("play", arguments);
  39543. return this;
  39544. },
  39545. pause: function(){
  39546. this._doAction("pause", arguments);
  39547. this._call("pause", arguments);
  39548. return this;
  39549. },
  39550. gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
  39551. var ms = this.duration * percent;
  39552. arrayUtil.forEach(this._animations, function(a){
  39553. a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay);
  39554. });
  39555. this._call("gotoPercent", arguments);
  39556. return this;
  39557. },
  39558. stop: function(/*boolean?*/ gotoEnd){
  39559. this._doAction("stop", arguments);
  39560. this._call("stop", arguments);
  39561. return this;
  39562. },
  39563. status: function(){
  39564. return this._pseudoAnimation.status();
  39565. },
  39566. destroy: function(){
  39567. arrayUtil.forEach(this._connects, connect.disconnect);
  39568. }
  39569. });
  39570. lang.extend(_combine, _baseObj);
  39571. coreFx.combine = /*===== dojo.fx.combine = =====*/ function(/*dojo.Animation[]*/ animations){
  39572. // summary:
  39573. // Combine a list of `dojo.Animation`s to run in parallel
  39574. //
  39575. // description:
  39576. // Combine an array of `dojo.Animation`s to run in parallel,
  39577. // providing a new `dojo.Animation` instance encompasing each
  39578. // animation, firing standard animation events.
  39579. //
  39580. // example:
  39581. // Fade out `node` while fading in `otherNode` simultaneously
  39582. // | dojo.fx.combine([
  39583. // | dojo.fadeIn({ node:node }),
  39584. // | dojo.fadeOut({ node:otherNode })
  39585. // | ]).play();
  39586. //
  39587. // example:
  39588. // When the longest animation ends, execute a function:
  39589. // | var anim = dojo.fx.combine([
  39590. // | dojo.fadeIn({ node: n, duration:700 }),
  39591. // | dojo.fadeOut({ node: otherNode, duration: 300 })
  39592. // | ]);
  39593. // | dojo.connect(anim, "onEnd", function(){
  39594. // | // overall animation is done.
  39595. // | });
  39596. // | anim.play(); // play the animation
  39597. //
  39598. return new _combine(animations); // dojo.Animation
  39599. };
  39600. coreFx.wipeIn = /*===== dojo.fx.wipeIn = =====*/ function(/*Object*/ args){
  39601. // summary:
  39602. // Expand a node to it's natural height.
  39603. //
  39604. // description:
  39605. // Returns an animation that will expand the
  39606. // node defined in 'args' object from it's current height to
  39607. // it's natural height (with no scrollbar).
  39608. // Node must have no margin/border/padding.
  39609. //
  39610. // args: Object
  39611. // A hash-map of standard `dojo.Animation` constructor properties
  39612. // (such as easing: node: duration: and so on)
  39613. //
  39614. // example:
  39615. // | dojo.fx.wipeIn({
  39616. // | node:"someId"
  39617. // | }).play()
  39618. var node = args.node = dom.byId(args.node), s = node.style, o;
  39619. var anim = baseFx.animateProperty(lang.mixin({
  39620. properties: {
  39621. height: {
  39622. // wrapped in functions so we wait till the last second to query (in case value has changed)
  39623. start: function(){
  39624. // start at current [computed] height, but use 1px rather than 0
  39625. // because 0 causes IE to display the whole panel
  39626. o = s.overflow;
  39627. s.overflow = "hidden";
  39628. if(s.visibility == "hidden" || s.display == "none"){
  39629. s.height = "1px";
  39630. s.display = "";
  39631. s.visibility = "";
  39632. return 1;
  39633. }else{
  39634. var height = domStyle.get(node, "height");
  39635. return Math.max(height, 1);
  39636. }
  39637. },
  39638. end: function(){
  39639. return node.scrollHeight;
  39640. }
  39641. }
  39642. }
  39643. }, args));
  39644. var fini = function(){
  39645. s.height = "auto";
  39646. s.overflow = o;
  39647. };
  39648. connect.connect(anim, "onStop", fini);
  39649. connect.connect(anim, "onEnd", fini);
  39650. return anim; // dojo.Animation
  39651. };
  39652. coreFx.wipeOut = /*===== dojo.fx.wipeOut = =====*/ function(/*Object*/ args){
  39653. // summary:
  39654. // Shrink a node to nothing and hide it.
  39655. //
  39656. // description:
  39657. // Returns an animation that will shrink node defined in "args"
  39658. // from it's current height to 1px, and then hide it.
  39659. //
  39660. // args: Object
  39661. // A hash-map of standard `dojo.Animation` constructor properties
  39662. // (such as easing: node: duration: and so on)
  39663. //
  39664. // example:
  39665. // | dojo.fx.wipeOut({ node:"someId" }).play()
  39666. var node = args.node = dom.byId(args.node), s = node.style, o;
  39667. var anim = baseFx.animateProperty(lang.mixin({
  39668. properties: {
  39669. height: {
  39670. end: 1 // 0 causes IE to display the whole panel
  39671. }
  39672. }
  39673. }, args));
  39674. connect.connect(anim, "beforeBegin", function(){
  39675. o = s.overflow;
  39676. s.overflow = "hidden";
  39677. s.display = "";
  39678. });
  39679. var fini = function(){
  39680. s.overflow = o;
  39681. s.height = "auto";
  39682. s.display = "none";
  39683. };
  39684. connect.connect(anim, "onStop", fini);
  39685. connect.connect(anim, "onEnd", fini);
  39686. return anim; // dojo.Animation
  39687. };
  39688. coreFx.slideTo = /*===== dojo.fx.slideTo = =====*/ function(/*Object*/ args){
  39689. // summary:
  39690. // Slide a node to a new top/left position
  39691. //
  39692. // description:
  39693. // Returns an animation that will slide "node"
  39694. // defined in args Object from its current position to
  39695. // the position defined by (args.left, args.top).
  39696. //
  39697. // args: Object
  39698. // A hash-map of standard `dojo.Animation` constructor properties
  39699. // (such as easing: node: duration: and so on). Special args members
  39700. // are `top` and `left`, which indicate the new position to slide to.
  39701. //
  39702. // example:
  39703. // | .slideTo({ node: node, left:"40", top:"50", units:"px" }).play()
  39704. var node = args.node = dom.byId(args.node),
  39705. top = null, left = null;
  39706. var init = (function(n){
  39707. return function(){
  39708. var cs = domStyle.getComputedStyle(n);
  39709. var pos = cs.position;
  39710. top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0);
  39711. left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0);
  39712. if(pos != 'absolute' && pos != 'relative'){
  39713. var ret = geom.position(n, true);
  39714. top = ret.y;
  39715. left = ret.x;
  39716. n.style.position="absolute";
  39717. n.style.top=top+"px";
  39718. n.style.left=left+"px";
  39719. }
  39720. };
  39721. })(node);
  39722. init();
  39723. var anim = baseFx.animateProperty(lang.mixin({
  39724. properties: {
  39725. top: args.top || 0,
  39726. left: args.left || 0
  39727. }
  39728. }, args));
  39729. connect.connect(anim, "beforeBegin", anim, init);
  39730. return anim; // dojo.Animation
  39731. };
  39732. return coreFx;
  39733. });
  39734. },
  39735. 'dojox/form/uploader/Base':function(){
  39736. define("dojox/form/uploader/Base", [
  39737. "dojo/dom-form",
  39738. "dojo/dom-style",
  39739. "dojo/dom-construct",
  39740. "dojo/dom-attr",
  39741. "dojo/has",
  39742. "dojo/_base/declare",
  39743. "dojo/_base/event",
  39744. "dijit/_Widget",
  39745. "dijit/_TemplatedMixin",
  39746. "dijit/_WidgetsInTemplateMixin"
  39747. ],function(domForm, domStyle, domConstruct, domAttr, has, declare, event, Widget, TemplatedMixin, WidgetsInTemplateMixin){
  39748. has.add('FormData', function(){return !!window.FormData;});
  39749. has.add("xhr-sendAsBinary", function(){var xhr=window.XMLHttpRequest && new window.XMLHttpRequest(); return xhr && !!xhr.sendAsBinary;});
  39750. has.add("file-multiple", function(){return !!({'true':1,'false':1}[domAttr.get(document.createElement('input',{type:"file"}), 'multiple')]);});
  39751. /*=====
  39752. Widget = dijit._Widget;
  39753. TemplatedMixin = dijit._TemplatedMixin;
  39754. WidgetsInTemplateMixin = dijit._WidgetsInTemplateMixin;
  39755. =====*/
  39756. return declare("dojox.form.uploader.Base", [Widget, TemplatedMixin, WidgetsInTemplateMixin], {
  39757. //
  39758. // Version: 1.6
  39759. //
  39760. // summary:
  39761. // The Base class used for dojox.form.Uploader and dojox.form.uploader.FileList.
  39762. //
  39763. // description:
  39764. // Should not be used as a standalone. To be mixed in with other classes.
  39765. //
  39766. getForm: function(){
  39767. // summary:
  39768. // Finds the parent form of the Uploader, if it exists.
  39769. //
  39770. if(!this.form){
  39771. var n = this.domNode;
  39772. while(n && n.tagName && n !== document.body){
  39773. if(n.tagName.toLowerCase() == "form"){
  39774. this.form = n;
  39775. break;
  39776. }
  39777. n = n.parentNode;
  39778. }
  39779. }
  39780. return this.form // Node;
  39781. },
  39782. getUrl: function(){
  39783. // summary:
  39784. // Finds the URL to upload to, whether it be the action in the parent form, this.url or
  39785. // this.uploadUrl
  39786. //
  39787. if(this.uploadUrl) this.url = this.uploadUrl;
  39788. if(this.url) return this.url;
  39789. if(this.getForm()) this.url = this.form.action;
  39790. return this.url; // String
  39791. },
  39792. connectForm: function(){
  39793. // summary:
  39794. // Internal. Connects to form if there is one.
  39795. //
  39796. this.url = this.getUrl();
  39797. if(!this._fcon && !!this.getForm()){
  39798. this._fcon = true;
  39799. this.connect(this.form, "onsubmit", function(evt){
  39800. event.stop(evt);
  39801. this.submit(this.form);
  39802. });
  39803. }
  39804. },
  39805. supports: function(what){
  39806. // summary:
  39807. // Does feature testing for uploader capabilities. (No browser sniffing - yay)
  39808. //
  39809. switch(what){
  39810. case "multiple":
  39811. if(this.force == "flash" || this.force == "iframe") return false;
  39812. return has("file-multiple");
  39813. case "FormData":
  39814. return has(what);
  39815. case "sendAsBinary":
  39816. return has("xhr-sendAsBinary");
  39817. }
  39818. return false; // Boolean
  39819. },
  39820. getMimeType: function(){
  39821. // summary:
  39822. // Returns the mime type that should be used in an HTML5 upload form. Return result
  39823. // may change as the current use is very generic.
  39824. //
  39825. return "application/octet-stream"; //image/gif
  39826. },
  39827. getFileType: function(/* String */name){
  39828. // summary:
  39829. // Gets the extension of a file
  39830. return name.substring(name.lastIndexOf(".")+1).toUpperCase(); // String
  39831. },
  39832. convertBytes: function(bytes){
  39833. // summary:
  39834. // Converts bytes. Returns an object with all conversions. The "value" property is
  39835. // considered the most likely desired result.
  39836. //
  39837. var kb = Math.round(bytes/1024*100000)/100000;
  39838. var mb = Math.round(bytes/1048576*100000)/100000;
  39839. var gb = Math.round(bytes/1073741824*100000)/100000;
  39840. var value = bytes;
  39841. if(kb>1) value = kb.toFixed(1)+" kb";
  39842. if(mb>1) value = mb.toFixed(1)+" mb";
  39843. if(gb>1) value = gb.toFixed(1)+" gb";
  39844. return {
  39845. kb:kb,
  39846. mb:mb,
  39847. gb:gb,
  39848. bytes:bytes,
  39849. value: value
  39850. }; // Object
  39851. }
  39852. });
  39853. });
  39854. },
  39855. 'dojox/grid/_SelectionPreserver':function(){
  39856. define("dojox/grid/_SelectionPreserver", [
  39857. "dojo/_base/declare",
  39858. "dojo/_base/connect",
  39859. "dojo/_base/lang",
  39860. "dojo/_base/array"
  39861. ], function(declare, connect, lang, array){
  39862. return declare("dojox.grid._SelectionPreserver", null, {
  39863. // summary:
  39864. // Preserve selections across various user actions.
  39865. //
  39866. // description:
  39867. // When this feature is turned on, Grid will try to preserve selections across actions, e.g. sorting, filtering etc.
  39868. //
  39869. // Precondition - Identifier(id) is required for store since id is the only way for differentiating row items.
  39870. // Known issue - The preserved selections might be inaccurate if some unloaded rows are previously selected by range(e.g.SHIFT + click)
  39871. //
  39872. // example:
  39873. // | //To turn on this - please set 'keepSelection' attribute to true
  39874. // | <div dojoType="dojox.grid.DataGrid" keepSelection = true .../>
  39875. // | <div dojoType="dojox.grid.TreeGrid" keepSelection = true .../>
  39876. // | <div dojoType="dojox.grid.LazyTreeGrid" keepSelection = true .../>
  39877. constructor: function(selection){
  39878. this.selection = selection;
  39879. var grid = this.grid = selection.grid;
  39880. this.reset();
  39881. this._connects = [
  39882. connect.connect(grid, '_setStore', this, 'reset'),
  39883. connect.connect(grid, '_addItem', this, '_reSelectById'),
  39884. connect.connect(selection, 'addToSelection', lang.hitch(this, '_selectById', true)),
  39885. connect.connect(selection, 'deselect', lang.hitch(this, '_selectById', false)),
  39886. connect.connect(selection, 'deselectAll', this, 'reset')
  39887. ];
  39888. },
  39889. destroy: function(){
  39890. this.reset();
  39891. array.forEach(this._connects, connect.disconnect);
  39892. delete this._connects;
  39893. },
  39894. reset: function(){
  39895. this._selectedById = {};
  39896. },
  39897. _reSelectById: function(item, index){
  39898. // summary:
  39899. // When some rows is fetched, determine whether it should be selected.
  39900. if(item && this.grid._hasIdentity){
  39901. this.selection.selected[index] = this._selectedById[this.grid.store.getIdentity(item)];
  39902. }
  39903. },
  39904. _selectById: function(toSelect, inItemOrIndex){
  39905. // summary:
  39906. // Record selected rows by ID.
  39907. if(this.selection.mode == 'none' || !this.grid._hasIdentity){ return; }
  39908. var item = inItemOrIndex, g = this.grid;
  39909. if(typeof inItemOrIndex == "number" || typeof inItemOrIndex == "string"){
  39910. var entry = g._by_idx[inItemOrIndex];
  39911. item = entry && entry.item;
  39912. }
  39913. if(item){
  39914. this._selectedById[g.store.getIdentity(item)] = !!toSelect;
  39915. }
  39916. return item;
  39917. }
  39918. });
  39919. });
  39920. },
  39921. 'url:dojox/form/resources/Uploader.html':"<span class=\"dijit dijitReset dijitInline\"\r\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\r\n\t\tdojoAttachEvent=\"ondijitclick:_onClick\"\r\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\r\n\t\t\tdojoAttachPoint=\"titleNode,focusNode\"\r\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\r\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\"></span\r\n\t\t\t><span class=\"dijitReset dijitToggleButtonIconChar\">&#x25CF;</span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\r\n\t\t\t\tid=\"${id}_label\"\r\n\t\t\t\tdojoAttachPoint=\"containerNode\"\r\n\t\t\t></span\r\n\t\t></span\r\n\t></span\r\n\t><!--no need to have this for Uploader \r\n\t<input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\" tabIndex=\"-1\"\r\n\t\tdojoAttachPoint=\"valueNode\"\r\n/--></span>\r\n",
  39922. 'dijit/form/HorizontalSlider':function(){
  39923. require({cache:{
  39924. '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\"\r\n\trole=\"presentation\"\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t\t><td data-dojo-attach-point=\"topDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationT dijitSliderDecorationH\"></td\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\r\n\t\t\t><div class=\"dijitSliderDecrementIconH\" style=\"display:none\" data-dojo-attach-point=\"decrementButton\"><span class=\"dijitSliderButtonInner\">-</span></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderLeftBumper\" data-dojo-attach-event=\"press:_onClkDecBumper\"></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><input data-dojo-attach-point=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\r\n\t\t\t/><div class=\"dijitReset dijitSliderBarContainerH\" role=\"presentation\" data-dojo-attach-point=\"sliderBarContainer\"\r\n\t\t\t\t><div role=\"presentation\" data-dojo-attach-point=\"progressBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderProgressBar dijitSliderProgressBarH\" data-dojo-attach-event=\"press:_onBarClick\"\r\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableH\"\r\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\r\n\t\t\t\t\t></div\r\n\t\t\t\t></div\r\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\r\n\t\t\t></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderRightBumper\" data-dojo-attach-event=\"press:_onClkIncBumper\"></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\r\n\t\t\t><div class=\"dijitSliderIncrementIconH\" style=\"display:none\" data-dojo-attach-point=\"incrementButton\"><span class=\"dijitSliderButtonInner\">+</span></div\r\n\t\t></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t\t><td data-dojo-attach-point=\"containerNode,bottomDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationB dijitSliderDecorationH\"></td\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t></tr\r\n></table>\r\n"}});
  39925. define("dijit/form/HorizontalSlider", [
  39926. "dojo/_base/array", // array.forEach
  39927. "dojo/_base/declare", // declare
  39928. "dojo/dnd/move",
  39929. "dojo/_base/event", // event.stop
  39930. "dojo/_base/fx", // fx.animateProperty
  39931. "dojo/dom-geometry", // domGeometry.position
  39932. "dojo/dom-style", // domStyle.getComputedStyle
  39933. "dojo/keys", // keys.DOWN_ARROW keys.END keys.HOME keys.LEFT_ARROW keys.PAGE_DOWN keys.PAGE_UP keys.RIGHT_ARROW keys.UP_ARROW
  39934. "dojo/_base/lang", // lang.hitch
  39935. "dojo/_base/sniff", // has("ie") has("mozilla")
  39936. "dojo/dnd/Moveable", // Moveable
  39937. "dojo/dnd/Mover", // Mover Mover.prototype.destroy.apply
  39938. "dojo/query", // query
  39939. "../registry", // registry.findWidgets
  39940. "../focus", // focus.focus()
  39941. "../typematic",
  39942. "./Button",
  39943. "./_FormValueWidget",
  39944. "../_Container",
  39945. "dojo/text!./templates/HorizontalSlider.html"
  39946. ], function(array, declare, move, event, fx, domGeometry, domStyle, keys, lang, has, Moveable, Mover, query,
  39947. registry, focus, typematic, Button, _FormValueWidget, _Container, template){
  39948. /*=====
  39949. var Button = dijit.form.Button;
  39950. var _FormValueWidget = dijit.form._FormValueWidget;
  39951. var _Container = dijit._Container;
  39952. =====*/
  39953. // module:
  39954. // dijit/form/HorizontalSlider
  39955. // summary:
  39956. // A form widget that allows one to select a value with a horizontally draggable handle
  39957. var _SliderMover = declare("dijit.form._SliderMover", Mover, {
  39958. onMouseMove: function(e){
  39959. var widget = this.widget;
  39960. var abspos = widget._abspos;
  39961. if(!abspos){
  39962. abspos = widget._abspos = domGeometry.position(widget.sliderBarContainer, true);
  39963. widget._setPixelValue_ = lang.hitch(widget, "_setPixelValue");
  39964. widget._isReversed_ = widget._isReversed();
  39965. }
  39966. var pixelValue = e[widget._mousePixelCoord] - abspos[widget._startingPixelCoord];
  39967. widget._setPixelValue_(widget._isReversed_ ? (abspos[widget._pixelCount]-pixelValue) : pixelValue, abspos[widget._pixelCount], false);
  39968. },
  39969. destroy: function(e){
  39970. Mover.prototype.destroy.apply(this, arguments);
  39971. var widget = this.widget;
  39972. widget._abspos = null;
  39973. widget._setValueAttr(widget.value, true);
  39974. }
  39975. });
  39976. var HorizontalSlider = declare("dijit.form.HorizontalSlider", [_FormValueWidget, _Container], {
  39977. // summary:
  39978. // A form widget that allows one to select a value with a horizontally draggable handle
  39979. templateString: template,
  39980. // Overrides FormValueWidget.value to indicate numeric value
  39981. value: 0,
  39982. // showButtons: [const] Boolean
  39983. // Show increment/decrement buttons at the ends of the slider?
  39984. showButtons: true,
  39985. // minimum:: [const] Integer
  39986. // The minimum value the slider can be set to.
  39987. minimum: 0,
  39988. // maximum: [const] Integer
  39989. // The maximum value the slider can be set to.
  39990. maximum: 100,
  39991. // discreteValues: Integer
  39992. // If specified, indicates that the slider handle has only 'discreteValues' possible positions,
  39993. // and that after dragging the handle, it will snap to the nearest possible position.
  39994. // Thus, the slider has only 'discreteValues' possible values.
  39995. //
  39996. // For example, if minimum=10, maxiumum=30, and discreteValues=3, then the slider handle has
  39997. // three possible positions, representing values 10, 20, or 30.
  39998. //
  39999. // If discreteValues is not specified or if it's value is higher than the number of pixels
  40000. // in the slider bar, then the slider handle can be moved freely, and the slider's value will be
  40001. // computed/reported based on pixel position (in this case it will likely be fractional,
  40002. // such as 123.456789).
  40003. discreteValues: Infinity,
  40004. // pageIncrement: Integer
  40005. // If discreteValues is also specified, this indicates the amount of clicks (ie, snap positions)
  40006. // that the slider handle is moved via pageup/pagedown keys.
  40007. // If discreteValues is not specified, it indicates the number of pixels.
  40008. pageIncrement: 2,
  40009. // clickSelect: Boolean
  40010. // If clicking the slider bar changes the value or not
  40011. clickSelect: true,
  40012. // slideDuration: Number
  40013. // The time in ms to take to animate the slider handle from 0% to 100%,
  40014. // when clicking the slider bar to make the handle move.
  40015. slideDuration: registry.defaultDuration,
  40016. // Map widget attributes to DOMNode attributes.
  40017. _setIdAttr: "", // Override _FormWidget which sends id to focusNode
  40018. baseClass: "dijitSlider",
  40019. // Apply CSS classes to up/down arrows and handle per mouse state
  40020. cssStateNodes: {
  40021. incrementButton: "dijitSliderIncrementButton",
  40022. decrementButton: "dijitSliderDecrementButton",
  40023. focusNode: "dijitSliderThumb"
  40024. },
  40025. _mousePixelCoord: "pageX",
  40026. _pixelCount: "w",
  40027. _startingPixelCoord: "x",
  40028. _handleOffsetCoord: "left",
  40029. _progressPixelSize: "width",
  40030. _onKeyUp: function(/*Event*/ e){
  40031. if(this.disabled || this.readOnly || e.altKey || e.ctrlKey || e.metaKey){ return; }
  40032. this._setValueAttr(this.value, true);
  40033. },
  40034. _onKeyPress: function(/*Event*/ e){
  40035. if(this.disabled || this.readOnly || e.altKey || e.ctrlKey || e.metaKey){ return; }
  40036. switch(e.charOrCode){
  40037. case keys.HOME:
  40038. this._setValueAttr(this.minimum, false);
  40039. break;
  40040. case keys.END:
  40041. this._setValueAttr(this.maximum, false);
  40042. break;
  40043. // this._descending === false: if ascending vertical (min on top)
  40044. // (this._descending || this.isLeftToRight()): if left-to-right horizontal or descending vertical
  40045. case ((this._descending || this.isLeftToRight()) ? keys.RIGHT_ARROW : keys.LEFT_ARROW):
  40046. case (this._descending === false ? keys.DOWN_ARROW : keys.UP_ARROW):
  40047. case (this._descending === false ? keys.PAGE_DOWN : keys.PAGE_UP):
  40048. this.increment(e);
  40049. break;
  40050. case ((this._descending || this.isLeftToRight()) ? keys.LEFT_ARROW : keys.RIGHT_ARROW):
  40051. case (this._descending === false ? keys.UP_ARROW : keys.DOWN_ARROW):
  40052. case (this._descending === false ? keys.PAGE_UP : keys.PAGE_DOWN):
  40053. this.decrement(e);
  40054. break;
  40055. default:
  40056. return;
  40057. }
  40058. event.stop(e);
  40059. },
  40060. _onHandleClick: function(e){
  40061. if(this.disabled || this.readOnly){ return; }
  40062. if(!has("ie")){
  40063. // make sure you get focus when dragging the handle
  40064. // (but don't do on IE because it causes a flicker on mouse up (due to blur then focus)
  40065. focus.focus(this.sliderHandle);
  40066. }
  40067. event.stop(e);
  40068. },
  40069. _isReversed: function(){
  40070. // summary:
  40071. // Returns true if direction is from right to left
  40072. // tags:
  40073. // protected extension
  40074. return !this.isLeftToRight();
  40075. },
  40076. _onBarClick: function(e){
  40077. if(this.disabled || this.readOnly || !this.clickSelect){ return; }
  40078. focus.focus(this.sliderHandle);
  40079. event.stop(e);
  40080. var abspos = domGeometry.position(this.sliderBarContainer, true);
  40081. var pixelValue = e[this._mousePixelCoord] - abspos[this._startingPixelCoord];
  40082. this._setPixelValue(this._isReversed() ? (abspos[this._pixelCount] - pixelValue) : pixelValue, abspos[this._pixelCount], true);
  40083. this._movable.onMouseDown(e);
  40084. },
  40085. _setPixelValue: function(/*Number*/ pixelValue, /*Number*/ maxPixels, /*Boolean?*/ priorityChange){
  40086. if(this.disabled || this.readOnly){ return; }
  40087. var count = this.discreteValues;
  40088. if(count <= 1 || count == Infinity){ count = maxPixels; }
  40089. count--;
  40090. var pixelsPerValue = maxPixels / count;
  40091. var wholeIncrements = Math.round(pixelValue / pixelsPerValue);
  40092. this._setValueAttr(Math.max(Math.min((this.maximum-this.minimum)*wholeIncrements/count + this.minimum, this.maximum), this.minimum), priorityChange);
  40093. },
  40094. _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange){
  40095. // summary:
  40096. // Hook so set('value', value) works.
  40097. this._set("value", value);
  40098. this.valueNode.value = value;
  40099. this.focusNode.setAttribute("aria-valuenow", value);
  40100. this.inherited(arguments);
  40101. var percent = (value - this.minimum) / (this.maximum - this.minimum);
  40102. var progressBar = (this._descending === false) ? this.remainingBar : this.progressBar;
  40103. var remainingBar = (this._descending === false) ? this.progressBar : this.remainingBar;
  40104. if(this._inProgressAnim && this._inProgressAnim.status != "stopped"){
  40105. this._inProgressAnim.stop(true);
  40106. }
  40107. if(priorityChange && this.slideDuration > 0 && progressBar.style[this._progressPixelSize]){
  40108. // animate the slider
  40109. var _this = this;
  40110. var props = {};
  40111. var start = parseFloat(progressBar.style[this._progressPixelSize]);
  40112. var duration = this.slideDuration * (percent-start/100);
  40113. if(duration == 0){ return; }
  40114. if(duration < 0){ duration = 0 - duration; }
  40115. props[this._progressPixelSize] = { start: start, end: percent*100, units:"%" };
  40116. this._inProgressAnim = fx.animateProperty({ node: progressBar, duration: duration,
  40117. onAnimate: function(v){
  40118. remainingBar.style[_this._progressPixelSize] = (100 - parseFloat(v[_this._progressPixelSize])) + "%";
  40119. },
  40120. onEnd: function(){
  40121. delete _this._inProgressAnim;
  40122. },
  40123. properties: props
  40124. });
  40125. this._inProgressAnim.play();
  40126. }else{
  40127. progressBar.style[this._progressPixelSize] = (percent*100) + "%";
  40128. remainingBar.style[this._progressPixelSize] = ((1-percent)*100) + "%";
  40129. }
  40130. },
  40131. _bumpValue: function(signedChange, /*Boolean?*/ priorityChange){
  40132. if(this.disabled || this.readOnly){ return; }
  40133. var s = domStyle.getComputedStyle(this.sliderBarContainer);
  40134. var c = domGeometry.getContentBox(this.sliderBarContainer, s);
  40135. var count = this.discreteValues;
  40136. if(count <= 1 || count == Infinity){ count = c[this._pixelCount]; }
  40137. count--;
  40138. var value = (this.value - this.minimum) * count / (this.maximum - this.minimum) + signedChange;
  40139. if(value < 0){ value = 0; }
  40140. if(value > count){ value = count; }
  40141. value = value * (this.maximum - this.minimum) / count + this.minimum;
  40142. this._setValueAttr(value, priorityChange);
  40143. },
  40144. _onClkBumper: function(val){
  40145. if(this.disabled || this.readOnly || !this.clickSelect){ return; }
  40146. this._setValueAttr(val, true);
  40147. },
  40148. _onClkIncBumper: function(){
  40149. this._onClkBumper(this._descending === false ? this.minimum : this.maximum);
  40150. },
  40151. _onClkDecBumper: function(){
  40152. this._onClkBumper(this._descending === false ? this.maximum : this.minimum);
  40153. },
  40154. decrement: function(/*Event*/ e){
  40155. // summary:
  40156. // Decrement slider
  40157. // tags:
  40158. // private
  40159. this._bumpValue(e.charOrCode == keys.PAGE_DOWN ? -this.pageIncrement : -1);
  40160. },
  40161. increment: function(/*Event*/ e){
  40162. // summary:
  40163. // Increment slider
  40164. // tags:
  40165. // private
  40166. this._bumpValue(e.charOrCode == keys.PAGE_UP ? this.pageIncrement : 1);
  40167. },
  40168. _mouseWheeled: function(/*Event*/ evt){
  40169. // summary:
  40170. // Event handler for mousewheel where supported
  40171. event.stop(evt);
  40172. var janky = !has("mozilla");
  40173. var scroll = evt[(janky ? "wheelDelta" : "detail")] * (janky ? 1 : -1);
  40174. this._bumpValue(scroll < 0 ? -1 : 1, true); // negative scroll acts like a decrement
  40175. },
  40176. startup: function(){
  40177. if(this._started){ return; }
  40178. array.forEach(this.getChildren(), function(child){
  40179. if(this[child.container] != this.containerNode){
  40180. this[child.container].appendChild(child.domNode);
  40181. }
  40182. }, this);
  40183. this.inherited(arguments);
  40184. },
  40185. _typematicCallback: function(/*Number*/ count, /*Object*/ button, /*Event*/ e){
  40186. if(count == -1){
  40187. this._setValueAttr(this.value, true);
  40188. }else{
  40189. this[(button == (this._descending? this.incrementButton : this.decrementButton)) ? "decrement" : "increment"](e);
  40190. }
  40191. },
  40192. buildRendering: function(){
  40193. this.inherited(arguments);
  40194. if(this.showButtons){
  40195. this.incrementButton.style.display="";
  40196. this.decrementButton.style.display="";
  40197. }
  40198. // find any associated label element and add to slider focusnode.
  40199. var label = query('label[for="'+this.id+'"]');
  40200. if(label.length){
  40201. label[0].id = (this.id+"_label");
  40202. this.focusNode.setAttribute("aria-labelledby", label[0].id);
  40203. }
  40204. this.focusNode.setAttribute("aria-valuemin", this.minimum);
  40205. this.focusNode.setAttribute("aria-valuemax", this.maximum);
  40206. },
  40207. postCreate: function(){
  40208. this.inherited(arguments);
  40209. if(this.showButtons){
  40210. this._connects.push(typematic.addMouseListener(
  40211. this.decrementButton, this, "_typematicCallback", 25, 500));
  40212. this._connects.push(typematic.addMouseListener(
  40213. this.incrementButton, this, "_typematicCallback", 25, 500));
  40214. }
  40215. this.connect(this.domNode, !has("mozilla") ? "onmousewheel" : "DOMMouseScroll", "_mouseWheeled");
  40216. // define a custom constructor for a SliderMover that points back to me
  40217. var mover = declare(_SliderMover, {
  40218. widget: this
  40219. });
  40220. this._movable = new Moveable(this.sliderHandle, {mover: mover});
  40221. this._layoutHackIE7();
  40222. },
  40223. destroy: function(){
  40224. this._movable.destroy();
  40225. if(this._inProgressAnim && this._inProgressAnim.status != "stopped"){
  40226. this._inProgressAnim.stop(true);
  40227. }
  40228. this._supportingWidgets = registry.findWidgets(this.domNode); // tells destroy about pseudo-child widgets (ruler/labels)
  40229. this.inherited(arguments);
  40230. }
  40231. });
  40232. HorizontalSlider._Mover = _SliderMover; // for monkey patching
  40233. return HorizontalSlider;
  40234. });
  40235. },
  40236. 'dijit/form/_FormValueWidget':function(){
  40237. define("dijit/form/_FormValueWidget", [
  40238. "dojo/_base/declare", // declare
  40239. "dojo/_base/sniff", // has("ie")
  40240. "./_FormWidget",
  40241. "./_FormValueMixin"
  40242. ], function(declare, has, _FormWidget, _FormValueMixin){
  40243. /*=====
  40244. var _FormWidget = dijit.form._FormWidget;
  40245. var _FormValueMixin = dijit.form._FormValueMixin;
  40246. =====*/
  40247. // module:
  40248. // dijit/form/_FormValueWidget
  40249. // summary:
  40250. // FormValueWidget
  40251. return declare("dijit.form._FormValueWidget", [_FormWidget, _FormValueMixin],
  40252. {
  40253. // summary:
  40254. // Base class for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values.
  40255. // description:
  40256. // Each _FormValueWidget represents a single input value, and has a (possibly hidden) <input> element,
  40257. // to which it serializes it's input value, so that form submission (either normal submission or via FormBind?)
  40258. // works as expected.
  40259. // Don't attempt to mixin the 'type', 'name' attributes here programatically -- they must be declared
  40260. // directly in the template as read by the parser in order to function. IE is known to specifically
  40261. // require the 'name' attribute at element creation time. See #8484, #8660.
  40262. _layoutHackIE7: function(){
  40263. // summary:
  40264. // Work around table sizing bugs on IE7 by forcing redraw
  40265. if(has("ie") == 7){ // fix IE7 layout bug when the widget is scrolled out of sight
  40266. var domNode = this.domNode;
  40267. var parent = domNode.parentNode;
  40268. var pingNode = domNode.firstChild || domNode; // target node most unlikely to have a custom filter
  40269. var origFilter = pingNode.style.filter; // save custom filter, most likely nothing
  40270. var _this = this;
  40271. while(parent && parent.clientHeight == 0){ // search for parents that haven't rendered yet
  40272. (function ping(){
  40273. var disconnectHandle = _this.connect(parent, "onscroll",
  40274. function(){
  40275. _this.disconnect(disconnectHandle); // only call once
  40276. pingNode.style.filter = (new Date()).getMilliseconds(); // set to anything that's unique
  40277. setTimeout(function(){ pingNode.style.filter = origFilter }, 0); // restore custom filter, if any
  40278. }
  40279. );
  40280. })();
  40281. parent = parent.parentNode;
  40282. }
  40283. }
  40284. }
  40285. });
  40286. });
  40287. },
  40288. '*now':function(r){r(['dojo/i18n!*preload*dojo/nls/pddojo*["ar","ca","cs","da","de-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"]']);}
  40289. }});
  40290. define("dojo/pddojo", [], 1);