dijit.js.uncompressed.js 113 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784
  1. /*
  2. * Copyright (c) 2004-2007, The Dojo Foundation All Rights Reserved.
  3. *
  4. * Licensed under the Academic Free License version 2.1 or above OR the modified
  5. * BSD license. For more information on Dojo licensing, see:
  6. *
  7. * http://dojotoolkit.org/book/dojo-book-0-9/introduction/licensing
  8. */
  9. /*
  10. * This is a compiled version of Dojo, built for deployment and not for
  11. * development. To get an editable version, please visit:
  12. *
  13. * http://dojotoolkit.org
  14. *
  15. * for documentation and information on getting the source.
  16. */
  17. if (!dojo._hasResource["dijit._base.focus"]) { // _hasResource checks added by
  18. // build. Do not use
  19. // _hasResource directly in your
  20. // code.
  21. dojo._hasResource["dijit._base.focus"] = true;
  22. dojo.provide("dijit._base.focus");
  23. // summary:
  24. // These functions are used to query or set the focus and selection.
  25. //
  26. // Also, they trace when widgets become actived/deactivated,
  27. // so that the widget can fire _onFocus/_onBlur events.
  28. // "Active" here means something similar to "focused", but
  29. // "focus" isn't quite the right word because we keep track of
  30. // a whole stack of "active" widgets. Example: Combobutton --> Menu -->
  31. // MenuItem. The onBlur event for Combobutton doesn't fire due to focusing
  32. // on the Menu or a MenuItem, since they are considered part of the
  33. // Combobutton widget. It only happens when focus is shifted
  34. // somewhere completely different.
  35. dojo.mixin(dijit, {
  36. // _curFocus: DomNode
  37. // Currently focused item on screen
  38. _curFocus : null,
  39. // _prevFocus: DomNode
  40. // Previously focused item on screen
  41. _prevFocus : null,
  42. isCollapsed : function() {
  43. // summary: tests whether the current selection is empty
  44. var _window = dojo.global;
  45. var _document = dojo.doc;
  46. if (_document.selection) { // IE
  47. return !_document.selection.createRange().text; // Boolean
  48. } else if (_window.getSelection) {
  49. var selection = _window.getSelection();
  50. if (dojo.isString(selection)) { // Safari
  51. return !selection; // Boolean
  52. } else { // Mozilla/W3
  53. return selection.isCollapsed || !selection.toString(); // Boolean
  54. }
  55. }
  56. },
  57. getBookmark : function() {
  58. // summary: Retrieves a bookmark that can be used with
  59. // moveToBookmark to return to the same range
  60. var bookmark, selection = dojo.doc.selection;
  61. if (selection) { // IE
  62. var range = selection.createRange();
  63. if (selection.type.toUpperCase() == 'CONTROL') {
  64. bookmark = range.length ? dojo._toArray(range) : null;
  65. } else {
  66. bookmark = range.getBookmark();
  67. }
  68. } else {
  69. if (dojo.global.getSelection) {
  70. selection = dojo.global.getSelection();
  71. if (selection) {
  72. var range = selection.getRangeAt(0);
  73. bookmark = range.cloneRange();
  74. }
  75. } else {
  76. console
  77. .debug("No idea how to store the current selection for this browser!");
  78. }
  79. }
  80. return bookmark; // Array
  81. },
  82. moveToBookmark : function(/* Object */bookmark) {
  83. // summary: Moves current selection to a bookmark
  84. // bookmark: this should be a returned object from
  85. // dojo.html.selection.getBookmark()
  86. var _document = dojo.doc;
  87. if (_document.selection) { // IE
  88. var range;
  89. if (dojo.isArray(bookmark)) {
  90. range = _document.body.createControlRange();
  91. dojo.forEach(bookmark, range.addElement);
  92. } else {
  93. range = _document.selection.createRange();
  94. range.moveToBookmark(bookmark);
  95. }
  96. range.select();
  97. } else { // Moz/W3C
  98. var selection = dojo.global.getSelection
  99. && dojo.global.getSelection();
  100. if (selection && selection.removeAllRanges) {
  101. selection.removeAllRanges();
  102. selection.addRange(bookmark);
  103. } else {
  104. console
  105. .debug("No idea how to restore selection for this browser!");
  106. }
  107. }
  108. },
  109. getFocus : function(/* Widget */menu, /* Window */openedForWindow) {
  110. // summary:
  111. // Returns the current focus and selection.
  112. // Called when a popup appears (either a top level menu or a
  113. // dialog),
  114. // or when a toolbar/menubar receives focus
  115. //
  116. // menu:
  117. // the menu that's being opened
  118. //
  119. // openedForWindow:
  120. // iframe in which menu was opened
  121. //
  122. // returns:
  123. // a handle to restore focus/selection
  124. return {
  125. // Node to return focus to
  126. node : menu && dojo.isDescendant(dijit._curFocus, menu.domNode)
  127. ? dijit._prevFocus
  128. : dijit._curFocus,
  129. // Previously selected text
  130. bookmark : !dojo.withGlobal(openedForWindow || dojo.global,
  131. dijit.isCollapsed) ? dojo.withGlobal(openedForWindow
  132. || dojo.global, dijit.getBookmark) : null,
  133. openedForWindow : openedForWindow
  134. }; // Object
  135. },
  136. focus : function(/* Object || DomNode */handle) {
  137. // summary:
  138. // Sets the focused node and the selection according to argument.
  139. // To set focus to an iframe's content, pass in the iframe itself.
  140. // handle:
  141. // object returned by get(), or a DomNode
  142. if (!handle) {
  143. return;
  144. }
  145. var node = "node" in handle ? handle.node : handle, // because
  146. // handle is
  147. // either
  148. // DomNode or a
  149. // composite
  150. // object
  151. bookmark = handle.bookmark, openedForWindow = handle.openedForWindow;
  152. // Set the focus
  153. // Note that for iframe's we need to use the <iframe> to follow the
  154. // parentNode chain,
  155. // but we need to set focus to iframe.contentWindow
  156. if (node) {
  157. var focusNode = (node.tagName.toLowerCase() == "iframe")
  158. ? node.contentWindow
  159. : node;
  160. if (focusNode && focusNode.focus) {
  161. try {
  162. // Gecko throws sometimes if setting focus is
  163. // impossible,
  164. // node not displayed or something like that
  165. focusNode.focus();
  166. } catch (e) {/* quiet */
  167. }
  168. }
  169. dijit._onFocusNode(node);
  170. }
  171. // set the selection
  172. // do not need to restore if current selection is not empty
  173. // (use keyboard to select a menu item)
  174. if (bookmark
  175. && dojo.withGlobal(openedForWindow || dojo.global,
  176. dijit.isCollapsed)) {
  177. if (openedForWindow) {
  178. openedForWindow.focus();
  179. }
  180. try {
  181. dojo.withGlobal(openedForWindow || dojo.global,
  182. moveToBookmark, null, [bookmark]);
  183. } catch (e) {
  184. /*
  185. * squelch IE internal error, see
  186. * http://trac.dojotoolkit.org/ticket/1984
  187. */
  188. }
  189. }
  190. },
  191. // List of currently active widgets (focused widget and it's ancestors)
  192. _activeStack : [],
  193. registerWin : function(/* Window? */targetWindow) {
  194. // summary:
  195. // Registers listeners on the specified window (either the main
  196. // window or an iframe) to detect when the user has clicked
  197. // somewhere.
  198. // Anyone that creates an iframe should call this function.
  199. if (!targetWindow) {
  200. targetWindow = window;
  201. }
  202. dojo.connect(targetWindow.document, "onmousedown", null, function(
  203. evt) {
  204. dijit._justMouseDowned = true;
  205. setTimeout(function() {
  206. dijit._justMouseDowned = false;
  207. }, 0);
  208. dijit._onTouchNode(evt.target || evt.srcElement);
  209. });
  210. // dojo.connect(targetWindow, "onscroll", ???);
  211. // Listen for blur and focus events on targetWindow's body
  212. var body = targetWindow.document.body
  213. || targetWindow.document.getElementsByTagName("body")[0];
  214. if (body) {
  215. if (dojo.isIE) {
  216. body.attachEvent('onactivate', function(evt) {
  217. if (evt.srcElement.tagName.toLowerCase() != "body") {
  218. dijit._onFocusNode(evt.srcElement);
  219. }
  220. });
  221. body.attachEvent('ondeactivate', function(evt) {
  222. dijit._onBlurNode(evt.srcElement);
  223. });
  224. } else {
  225. body.addEventListener('focus', function(evt) {
  226. dijit._onFocusNode(evt.target);
  227. }, true);
  228. body.addEventListener('blur', function(evt) {
  229. dijit._onBlurNode(evt.target);
  230. }, true);
  231. }
  232. }
  233. body = null; // prevent memory leak (apparent circular reference
  234. // via closure)
  235. },
  236. _onBlurNode : function(/* DomNode */node) {
  237. // summary:
  238. // Called when focus leaves a node.
  239. // Usually ignored, _unless_ it *isn't* follwed by touching another
  240. // node,
  241. // which indicates that we tabbed off the last field on the page,
  242. // in which case every widget is marked inactive
  243. dijit._prevFocus = dijit._curFocus;
  244. dijit._curFocus = null;
  245. var w = dijit.getEnclosingWidget(node);
  246. if (w && w._setStateClass) {
  247. w._focused = false;
  248. w._setStateClass();
  249. }
  250. if (dijit._justMouseDowned) {
  251. // the mouse down caused a new widget to be marked as active;
  252. // this blur event
  253. // is coming late, so ignore it.
  254. return;
  255. }
  256. // if the blur event isn't followed by a focus event then mark all
  257. // widgets as inactive.
  258. if (dijit._clearActiveWidgetsTimer) {
  259. clearTimeout(dijit._clearActiveWidgetsTimer);
  260. }
  261. dijit._clearActiveWidgetsTimer = setTimeout(function() {
  262. delete dijit._clearActiveWidgetsTimer;
  263. dijit._setStack([]);
  264. }, 100);
  265. },
  266. _onTouchNode : function(/* DomNode */node) {
  267. // summary
  268. // Callback when node is focused or mouse-downed
  269. // ignore the recent blurNode event
  270. if (dijit._clearActiveWidgetsTimer) {
  271. clearTimeout(dijit._clearActiveWidgetsTimer);
  272. delete dijit._clearActiveWidgetsTimer;
  273. }
  274. // compute stack of active widgets (ex: ComboButton --> Menu -->
  275. // MenuItem)
  276. var newStack = [];
  277. try {
  278. while (node) {
  279. if (node.dijitPopupParent) {
  280. node = dijit.byId(node.dijitPopupParent).domNode;
  281. } else if (node.tagName
  282. && node.tagName.toLowerCase() == "body") {
  283. // is this the root of the document or just the root of
  284. // an iframe?
  285. if (node === dojo.body()) {
  286. // node is the root of the main document
  287. break;
  288. }
  289. // otherwise, find the iframe this node refers to (can't
  290. // access it via parentNode,
  291. // need to do this trick instead) and continue tracing
  292. // up the document
  293. node = dojo.query("iframe").filter(function(iframe) {
  294. return iframe.contentDocument.body === node;
  295. })[0];
  296. } else {
  297. var id = node.getAttribute
  298. && node.getAttribute("widgetId");
  299. if (id) {
  300. newStack.unshift(id);
  301. }
  302. node = node.parentNode;
  303. }
  304. }
  305. } catch (e) { /* squelch */
  306. }
  307. dijit._setStack(newStack);
  308. },
  309. _onFocusNode : function(/* DomNode */node) {
  310. // summary
  311. // Callback when node is focused
  312. if (node && node.tagName && node.tagName.toLowerCase() == "body") {
  313. return;
  314. }
  315. dijit._onTouchNode(node);
  316. if (node == dijit._curFocus) {
  317. return;
  318. }
  319. dijit._prevFocus = dijit._curFocus;
  320. dijit._curFocus = node;
  321. dojo.publish("focusNode", [node]);
  322. // handle focus/blur styling
  323. var w = dijit.getEnclosingWidget(node);
  324. if (w && w._setStateClass) {
  325. w._focused = true;
  326. w._setStateClass();
  327. }
  328. },
  329. _setStack : function(newStack) {
  330. // summary
  331. // The stack of active widgets has changed. Send out appropriate
  332. // events and record new stack
  333. var oldStack = dijit._activeStack;
  334. dijit._activeStack = newStack;
  335. // compare old stack to new stack to see how many elements they have
  336. // in common
  337. for (var nCommon = 0; nCommon < Math.min(oldStack.length,
  338. newStack.length); nCommon++) {
  339. if (oldStack[nCommon] != newStack[nCommon]) {
  340. break;
  341. }
  342. }
  343. // for all elements that have gone out of focus, send blur event
  344. for (var i = oldStack.length - 1; i >= nCommon; i--) {
  345. var widget = dijit.byId(oldStack[i]);
  346. if (widget) {
  347. dojo.publish("widgetBlur", [widget]);
  348. if (widget._onBlur) {
  349. widget._onBlur();
  350. }
  351. }
  352. }
  353. // for all element that have come into focus, send focus event
  354. for (var i = nCommon; i < newStack.length; i++) {
  355. var widget = dijit.byId(newStack[i]);
  356. if (widget) {
  357. dojo.publish("widgetFocus", [widget]);
  358. if (widget._onFocus) {
  359. widget._onFocus();
  360. }
  361. }
  362. }
  363. }
  364. });
  365. // register top window and all the iframes it contains
  366. dojo.addOnLoad(dijit.registerWin);
  367. }
  368. if (!dojo._hasResource["dijit._base.manager"]) { // _hasResource checks added
  369. // by build. Do not use
  370. // _hasResource directly in
  371. // your code.
  372. dojo._hasResource["dijit._base.manager"] = true;
  373. dojo.provide("dijit._base.manager");
  374. dojo.declare("dijit.WidgetSet", null, {
  375. constructor : function() {
  376. // summary:
  377. // A set of widgets indexed by id
  378. this._hash = {};
  379. },
  380. add : function(/* Widget */widget) {
  381. if (this._hash[widget.id]) {
  382. throw new Error("Tried to register widget with id=="
  383. + widget.id
  384. + " but that id is already registered");
  385. }
  386. this._hash[widget.id] = widget;
  387. },
  388. remove : function(/* String */id) {
  389. delete this._hash[id];
  390. },
  391. forEach : function(/* Function */func) {
  392. for (var id in this._hash) {
  393. func(this._hash[id]);
  394. }
  395. },
  396. filter : function(/* Function */filter) {
  397. var res = new dijit.WidgetSet();
  398. this.forEach(function(widget) {
  399. if (filter(widget)) {
  400. res.add(widget);
  401. }
  402. });
  403. return res; // dijit.WidgetSet
  404. },
  405. byId : function(/* String */id) {
  406. return this._hash[id];
  407. },
  408. byClass : function(/* String */cls) {
  409. return this.filter(function(widget) {
  410. return widget.declaredClass == cls;
  411. }); // dijit.WidgetSet
  412. }
  413. });
  414. // registry: list of all widgets on page
  415. dijit.registry = new dijit.WidgetSet();
  416. dijit._widgetTypeCtr = {};
  417. dijit.getUniqueId = function(/* String */widgetType) {
  418. // summary
  419. // Generates a unique id for a given widgetType
  420. var id;
  421. do {
  422. id = widgetType
  423. + "_"
  424. + (dijit._widgetTypeCtr[widgetType] !== undefined
  425. ? ++dijit._widgetTypeCtr[widgetType]
  426. : dijit._widgetTypeCtr[widgetType] = 0);
  427. } while (dijit.byId(id));
  428. return id; // String
  429. };
  430. if (dojo.isIE) {
  431. // Only run this for IE because we think it's only necessary in that
  432. // case,
  433. // and because it causes problems on FF. See bug #3531 for details.
  434. dojo.addOnUnload(function() {
  435. dijit.registry.forEach(function(widget) {
  436. widget.destroy();
  437. });
  438. });
  439. }
  440. dijit.byId = function(/* String|Widget */id) {
  441. // summary:
  442. // Returns a widget by its id, or if passed a widget, no-op (like
  443. // dojo.byId())
  444. return (dojo.isString(id)) ? dijit.registry.byId(id) : id; // Widget
  445. };
  446. dijit.byNode = function(/* DOMNode */node) {
  447. // summary:
  448. // Returns the widget as referenced by node
  449. return dijit.registry.byId(node.getAttribute("widgetId")); // Widget
  450. };
  451. dijit.getEnclosingWidget = function(/* DOMNode */node) {
  452. // summary:
  453. // Returns the widget whose dom tree contains node or null if
  454. // the node is not contained within the dom tree of any widget
  455. while (node) {
  456. if (node.getAttribute && node.getAttribute("widgetId")) {
  457. return dijit.registry.byId(node.getAttribute("widgetId"));
  458. }
  459. node = node.parentNode;
  460. }
  461. return null;
  462. };
  463. }
  464. if (!dojo._hasResource["dijit._base.place"]) { // _hasResource checks added by
  465. // build. Do not use
  466. // _hasResource directly in your
  467. // code.
  468. dojo._hasResource["dijit._base.place"] = true;
  469. dojo.provide("dijit._base.place");
  470. // ported from dojo.html.util
  471. dijit.getViewport = function() {
  472. // summary
  473. // Returns the dimensions and scroll position of the viewable area of a
  474. // browser window
  475. var _window = dojo.global;
  476. var _document = dojo.doc;
  477. // get viewport size
  478. var w = 0, h = 0;
  479. if (dojo.isMozilla) {
  480. // mozilla
  481. // _window.innerHeight includes the height taken by the scroll bar
  482. // clientHeight is ideal but has DTD issues:
  483. // #4539: FF reverses the roles of body.clientHeight/Width and
  484. // documentElement.clientHeight/Width based on the DTD!
  485. // check DTD to see whether body or documentElement returns the
  486. // viewport dimensions using this algorithm:
  487. var minw, minh, maxw, maxh;
  488. if (_document.body.clientWidth > _document.documentElement.clientWidth) {
  489. minw = _document.documentElement.clientWidth;
  490. maxw = _document.body.clientWidth;
  491. } else {
  492. maxw = _document.documentElement.clientWidth;
  493. minw = _document.body.clientWidth;
  494. }
  495. if (_document.body.clientHeight > _document.documentElement.clientHeight) {
  496. minh = _document.documentElement.clientHeight;
  497. maxh = _document.body.clientHeight;
  498. } else {
  499. maxh = _document.documentElement.clientHeight;
  500. minh = _document.body.clientHeight;
  501. }
  502. w = (maxw > _window.innerWidth) ? minw : maxw;
  503. h = (maxh > _window.innerHeight) ? minh : maxh;
  504. } else if (!dojo.isOpera && _window.innerWidth) {
  505. // in opera9, dojo.body().clientWidth should be used, instead
  506. // of window.innerWidth/document.documentElement.clientWidth
  507. // so we have to check whether it is opera
  508. w = _window.innerWidth;
  509. h = _window.innerHeight;
  510. } else if (dojo.isIE && _document.documentElement
  511. && _document.documentElement.clientHeight) {
  512. w = _document.documentElement.clientWidth;
  513. h = _document.documentElement.clientHeight;
  514. } else if (dojo.body().clientWidth) {
  515. // IE5, Opera
  516. w = dojo.body().clientWidth;
  517. h = dojo.body().clientHeight;
  518. }
  519. // get scroll position
  520. var scroll = dojo._docScroll();
  521. return {
  522. w : w,
  523. h : h,
  524. l : scroll.x,
  525. t : scroll.y
  526. }; // object
  527. };
  528. dijit.placeOnScreen = function(
  529. /* DomNode */node,
  530. /* Object */pos,
  531. /* Object */corners,
  532. /* boolean? */tryOnly) {
  533. // summary:
  534. // Keeps 'node' in the visible area of the screen while trying to
  535. // place closest to pos.x, pos.y. The input coordinates are
  536. // expected to be the desired document position.
  537. //
  538. // Set which corner(s) you want to bind to, such as
  539. //
  540. // placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"])
  541. //
  542. // The desired x/y will be treated as the topleft(TL)/topright(TR) or
  543. // BottomLeft(BL)/BottomRight(BR) corner of the node. Each corner is
  544. // tested
  545. // and if a perfect match is found, it will be used. Otherwise, it goes
  546. // through
  547. // all of the specified corners, and choose the most appropriate one.
  548. //
  549. // NOTE: node is assumed to be absolutely or relatively positioned.
  550. var choices = dojo.map(corners, function(corner) {
  551. return {
  552. corner : corner,
  553. pos : pos
  554. };
  555. });
  556. return dijit._place(node, choices);
  557. }
  558. dijit._place = function(/* DomNode */node, /* Array */choices, /* Function */
  559. layoutNode) {
  560. // summary:
  561. // Given a list of spots to put node, put it at the first spot where it
  562. // fits,
  563. // of if it doesn't fit anywhere then the place with the least overflow
  564. // choices: Array
  565. // Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} }
  566. // Above example says to put the top-left corner of the node at (10,20)
  567. // layoutNode: Function(node, orient)
  568. // for things like tooltip, they are displayed differently (and have
  569. // different dimensions)
  570. // based on their orientation relative to the parent. This adjusts the
  571. // popup based on orientation.
  572. // get {x: 10, y: 10, w: 100, h:100} type obj representing position of
  573. // viewport over document
  574. var view = dijit.getViewport();
  575. // This won't work if the node is inside a <div style="position:
  576. // relative">,
  577. // so reattach it to document.body. (Otherwise, the positioning will be
  578. // wrong
  579. // and also it might get cutoff)
  580. if (!node.parentNode
  581. || String(node.parentNode.tagName).toLowerCase() != "body") {
  582. dojo.body().appendChild(node);
  583. }
  584. var best = null;
  585. for (var i = 0; i < choices.length; i++) {
  586. var corner = choices[i].corner;
  587. var pos = choices[i].pos;
  588. // configure node to be displayed in given position relative to
  589. // button
  590. // (need to do this in order to get an accurate size for the node,
  591. // because
  592. // a tooltips size changes based on position, due to triangle)
  593. if (layoutNode) {
  594. layoutNode(corner);
  595. }
  596. // get node's size
  597. var oldDisplay = node.style.display;
  598. var oldVis = node.style.visibility;
  599. node.style.visibility = "hidden";
  600. node.style.display = "";
  601. var mb = dojo.marginBox(node);
  602. node.style.display = oldDisplay;
  603. node.style.visibility = oldVis;
  604. // coordinates and size of node with specified corner placed at pos,
  605. // and clipped by viewport
  606. var startX = (corner.charAt(1) == 'L' ? pos.x : Math.max(view.l,
  607. pos.x - mb.w)), startY = (corner.charAt(0) == 'T'
  608. ? pos.y
  609. : Math.max(view.t, pos.y - mb.h)), endX = (corner.charAt(1) == 'L'
  610. ? Math.min(view.l + view.w, startX + mb.w)
  611. : pos.x), endY = (corner.charAt(0) == 'T' ? Math.min(view.t
  612. + view.h, startY + mb.h) : pos.y), width = endX
  613. - startX, height = endY - startY, overflow = (mb.w - width)
  614. + (mb.h - height);
  615. if (best == null || overflow < best.overflow) {
  616. best = {
  617. corner : corner,
  618. aroundCorner : choices[i].aroundCorner,
  619. x : startX,
  620. y : startY,
  621. w : width,
  622. h : height,
  623. overflow : overflow
  624. };
  625. }
  626. if (overflow == 0) {
  627. break;
  628. }
  629. }
  630. node.style.left = best.x + "px";
  631. node.style.top = best.y + "px";
  632. return best;
  633. }
  634. dijit.placeOnScreenAroundElement = function(
  635. /* DomNode */node,
  636. /* DomNode */aroundNode,
  637. /* Object */aroundCorners,
  638. /* Function */layoutNode) {
  639. // summary
  640. // Like placeOnScreen, except it accepts aroundNode instead of x,y
  641. // and attempts to place node around it. Uses margin box dimensions.
  642. //
  643. // aroundCorners
  644. // specify Which corner of aroundNode should be
  645. // used to place the node => which corner(s) of node to use (see the
  646. // corners parameter in dijit.placeOnScreen)
  647. // e.g. {'TL': 'BL', 'BL': 'TL'}
  648. //
  649. // layoutNode: Function(node, orient)
  650. // for things like tooltip, they are displayed differently (and have
  651. // different dimensions)
  652. // based on their orientation relative to the parent. This adjusts the
  653. // popup based on orientation.
  654. // get coordinates of aroundNode
  655. aroundNode = dojo.byId(aroundNode);
  656. var oldDisplay = aroundNode.style.display;
  657. aroundNode.style.display = "";
  658. // #3172: use the slightly tighter border box instead of marginBox
  659. var aroundNodeW = aroundNode.offsetWidth; // mb.w;
  660. var aroundNodeH = aroundNode.offsetHeight; // mb.h;
  661. var aroundNodePos = dojo.coords(aroundNode, true);
  662. aroundNode.style.display = oldDisplay;
  663. // Generate list of possible positions for node
  664. var choices = [];
  665. for (var nodeCorner in aroundCorners) {
  666. choices.push({
  667. aroundCorner : nodeCorner,
  668. corner : aroundCorners[nodeCorner],
  669. pos : {
  670. x : aroundNodePos.x
  671. + (nodeCorner.charAt(1) == 'L'
  672. ? 0
  673. : aroundNodeW),
  674. y : aroundNodePos.y
  675. + (nodeCorner.charAt(0) == 'T'
  676. ? 0
  677. : aroundNodeH)
  678. }
  679. });
  680. }
  681. return dijit._place(node, choices, layoutNode);
  682. }
  683. }
  684. if (!dojo._hasResource["dijit._base.window"]) { // _hasResource checks added by
  685. // build. Do not use
  686. // _hasResource directly in your
  687. // code.
  688. dojo._hasResource["dijit._base.window"] = true;
  689. dojo.provide("dijit._base.window");
  690. dijit.getDocumentWindow = function(doc) {
  691. // summary
  692. // Get window object associated with document doc
  693. // With Safari, there is not way to retrieve the window from the
  694. // document, so we must fix it.
  695. if (dojo.isSafari && !doc._parentWindow) {
  696. /*
  697. * This is a Safari specific function that fix the reference to the
  698. * parent window from the document object.
  699. */
  700. var fix = function(win) {
  701. win.document._parentWindow = win;
  702. for (var i = 0; i < win.frames.length; i++) {
  703. fix(win.frames[i]);
  704. }
  705. }
  706. fix(window.top);
  707. }
  708. // In some IE versions (at least 6.0), document.parentWindow does not
  709. // return a
  710. // reference to the real window object (maybe a copy), so we must fix it
  711. // as well
  712. // We use IE specific execScript to attach the real window reference to
  713. // document._parentWindow for later use
  714. if (dojo.isIE && window !== document.parentWindow && !doc._parentWindow) {
  715. /*
  716. * In IE 6, only the variable "window" can be used to connect events
  717. * (others may be only copies).
  718. */
  719. doc.parentWindow.execScript("document._parentWindow = window;",
  720. "Javascript");
  721. // to prevent memory leak, unset it after use
  722. // another possibility is to add an onUnload handler which seems
  723. // overkill to me (liucougar)
  724. var win = doc._parentWindow;
  725. doc._parentWindow = null;
  726. return win; // Window
  727. }
  728. return doc._parentWindow || doc.parentWindow || doc.defaultView; // Window
  729. }
  730. }
  731. if (!dojo._hasResource["dijit._base.popup"]) { // _hasResource checks added by
  732. // build. Do not use
  733. // _hasResource directly in your
  734. // code.
  735. dojo._hasResource["dijit._base.popup"] = true;
  736. dojo.provide("dijit._base.popup");
  737. dijit.popup = new function() {
  738. // summary:
  739. // This class is used to show/hide widgets as popups.
  740. //
  741. var stack = [], beginZIndex = 1000, idGen = 1;
  742. this.open = function(/* Object */args) {
  743. // summary:
  744. // Popup the widget at the specified position
  745. //
  746. // args: Object
  747. // popup: Widget
  748. // widget to display,
  749. // parent: Widget
  750. // the button etc. that is displaying this popup
  751. // around: DomNode
  752. // DOM node (typically a button); place popup relative to this node
  753. // orient: Object
  754. // structure specifying possible positions of popup relative to
  755. // "around" node
  756. // onCancel: Function
  757. // callback when user has canceled the popup by
  758. // 1. hitting ESC or
  759. // 2. by using the popup widget's proprietary cancel mechanism (like
  760. // a cancel button in a dialog);
  761. // ie: whenever popupWidget.onCancel() is called, args.onCancel is
  762. // called
  763. // onClose: Function
  764. // callback whenever this popup is closed
  765. // onExecute: Function
  766. // callback when user "executed" on the popup/sub-popup by selecting
  767. // a menu choice, etc. (top menu only)
  768. //
  769. // examples:
  770. // 1. opening at the mouse position
  771. // dijit.popup.open({popup: menuWidget, x: evt.pageX, y:
  772. // evt.pageY});
  773. // 2. opening the widget as a dropdown
  774. // dijit.popup.open({parent: this, popup: menuWidget, around:
  775. // this.domNode, onClose: function(){...} });
  776. //
  777. // Note that whatever widget called dijit.popup.open() should also
  778. // listen to it's own _onBlur callback
  779. // (fired from _base/focus.js) to know that focus has moved
  780. // somewhere else and thus the popup should be closed.
  781. var widget = args.popup, orient = args.orient || {
  782. 'BL' : 'TL',
  783. 'TL' : 'BL'
  784. }, around = args.around, id = (args.around && args.around.id)
  785. ? (args.around.id + "_dropdown")
  786. : ("popup_" + idGen++);
  787. // make wrapper div to hold widget and possibly hold iframe behind
  788. // it.
  789. // we can't attach the iframe as a child of the widget.domNode
  790. // because
  791. // widget.domNode might be a <table>, <ul>, etc.
  792. var wrapper = dojo.doc.createElement("div");
  793. wrapper.id = id;
  794. wrapper.className = "dijitPopup";
  795. wrapper.style.zIndex = beginZIndex + stack.length;
  796. wrapper.style.visibility = "hidden";
  797. if (args.parent) {
  798. wrapper.dijitPopupParent = args.parent.id;
  799. }
  800. dojo.body().appendChild(wrapper);
  801. widget.domNode.style.display = "";
  802. wrapper.appendChild(widget.domNode);
  803. var iframe = new dijit.BackgroundIframe(wrapper);
  804. // position the wrapper node
  805. var best = around ? dijit.placeOnScreenAroundElement(wrapper,
  806. around, orient, widget.orient ? dojo
  807. .hitch(widget, "orient") : null) : dijit
  808. .placeOnScreen(wrapper, args, orient == 'R' ? ['TR', 'BR',
  809. 'TL', 'BL'] : ['TL', 'BL', 'TR', 'BR']);
  810. wrapper.style.visibility = "visible";
  811. // TODO: use effects to fade in wrapper
  812. var handlers = [];
  813. // Compute the closest ancestor popup that's *not* a child of
  814. // another popup.
  815. // Ex: For a TooltipDialog with a button that spawns a tree of
  816. // menus, find the popup of the button.
  817. function getTopPopup() {
  818. for (var pi = stack.length - 1; pi > 0
  819. && stack[pi].parent === stack[pi - 1].widget; pi--);
  820. return stack[pi];
  821. }
  822. // provide default escape and tab key handling
  823. // (this will work for any widget, not just menu)
  824. handlers.push(dojo.connect(wrapper, "onkeypress", this, function(
  825. evt) {
  826. if (evt.keyCode == dojo.keys.ESCAPE && args.onCancel) {
  827. args.onCancel();
  828. } else if (evt.keyCode == dojo.keys.TAB) {
  829. dojo.stopEvent(evt);
  830. var topPopup = getTopPopup();
  831. if (topPopup && topPopup.onCancel) {
  832. topPopup.onCancel();
  833. }
  834. }
  835. }));
  836. // watch for cancel/execute events on the popup and notify the
  837. // caller
  838. // (for a menu, "execute" means clicking an item)
  839. if (widget.onCancel) {
  840. handlers.push(dojo.connect(widget, "onCancel", null,
  841. args.onCancel));
  842. }
  843. handlers.push(dojo.connect(widget, widget.onExecute
  844. ? "onExecute"
  845. : "onChange", null, function() {
  846. var topPopup = getTopPopup();
  847. if (topPopup && topPopup.onExecute) {
  848. topPopup.onExecute();
  849. }
  850. }));
  851. stack.push({
  852. wrapper : wrapper,
  853. iframe : iframe,
  854. widget : widget,
  855. parent : args.parent,
  856. onExecute : args.onExecute,
  857. onCancel : args.onCancel,
  858. onClose : args.onClose,
  859. handlers : handlers
  860. });
  861. if (widget.onOpen) {
  862. widget.onOpen(best);
  863. }
  864. return best;
  865. };
  866. this.close = function(/* Widget */popup) {
  867. // summary:
  868. // Close specified popup and any popups that it parented
  869. while (dojo.some(stack, function(elem) {
  870. return elem.widget == popup;
  871. })) {
  872. var top = stack.pop(), wrapper = top.wrapper, iframe = top.iframe, widget = top.widget, onClose = top.onClose;
  873. if (widget.onClose) {
  874. widget.onClose();
  875. }
  876. dojo.forEach(top.handlers, dojo.disconnect);
  877. // #2685: check if the widget still has a domNode so ContentPane
  878. // can change its URL without getting an error
  879. if (!widget || !widget.domNode) {
  880. return;
  881. }
  882. dojo.style(widget.domNode, "display", "none");
  883. dojo.body().appendChild(widget.domNode);
  884. iframe.destroy();
  885. dojo._destroyElement(wrapper);
  886. if (onClose) {
  887. onClose();
  888. }
  889. }
  890. };
  891. }();
  892. dijit._frames = new function() {
  893. // summary: cache of iframes
  894. var queue = [];
  895. this.pop = function() {
  896. var iframe;
  897. if (queue.length) {
  898. iframe = queue.pop();
  899. iframe.style.display = "";
  900. } else {
  901. if (dojo.isIE) {
  902. var html = "<iframe src='javascript:\"\"'"
  903. + " style='position: absolute; left: 0px; top: 0px;"
  904. + "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
  905. iframe = dojo.doc.createElement(html);
  906. } else {
  907. var iframe = dojo.doc.createElement("iframe");
  908. iframe.src = 'javascript:""';
  909. iframe.className = "dijitBackgroundIframe";
  910. }
  911. iframe.tabIndex = -1; // Magic to prevent iframe from getting
  912. // focus on tab keypress - as style
  913. // didnt work.
  914. dojo.body().appendChild(iframe);
  915. }
  916. return iframe;
  917. };
  918. this.push = function(iframe) {
  919. iframe.style.display = "";
  920. if (dojo.isIE) {
  921. iframe.style.removeExpression("width");
  922. iframe.style.removeExpression("height");
  923. }
  924. queue.push(iframe);
  925. }
  926. }();
  927. // fill the queue
  928. if (dojo.isIE && dojo.isIE < 7) {
  929. dojo.addOnLoad(function() {
  930. var f = dijit._frames;
  931. dojo.forEach([f.pop()], f.push);
  932. });
  933. }
  934. dijit.BackgroundIframe = function(/* DomNode */node) {
  935. // summary:
  936. // For IE z-index schenanigans. id attribute is required.
  937. //
  938. // description:
  939. // new dijit.BackgroundIframe(node)
  940. // Makes a background iframe as a child of node, that fills
  941. // area (and position) of node
  942. if (!node.id) {
  943. throw new Error("no id");
  944. }
  945. if ((dojo.isIE && dojo.isIE < 7)
  946. || (dojo.isFF && dojo.isFF < 3 && dojo.hasClass(dojo.body(),
  947. "dijit_a11y"))) {
  948. var iframe = dijit._frames.pop();
  949. node.appendChild(iframe);
  950. if (dojo.isIE) {
  951. iframe.style.setExpression("width", "document.getElementById('"
  952. + node.id + "').offsetWidth");
  953. iframe.style.setExpression("height",
  954. "document.getElementById('" + node.id
  955. + "').offsetHeight");
  956. }
  957. this.iframe = iframe;
  958. }
  959. };
  960. dojo.extend(dijit.BackgroundIframe, {
  961. destroy : function() {
  962. // summary: destroy the iframe
  963. if (this.iframe) {
  964. dijit._frames.push(this.iframe);
  965. delete this.iframe;
  966. }
  967. }
  968. });
  969. }
  970. if (!dojo._hasResource["dijit._base.scroll"]) { // _hasResource checks added by
  971. // build. Do not use
  972. // _hasResource directly in your
  973. // code.
  974. dojo._hasResource["dijit._base.scroll"] = true;
  975. dojo.provide("dijit._base.scroll");
  976. dijit.scrollIntoView = function(/* DomNode */node) {
  977. // summary
  978. // Scroll the passed node into view, if it is not.
  979. // don't rely on that node.scrollIntoView works just because the
  980. // function is there
  981. // it doesnt work in Konqueror or Opera even though the function is
  982. // there and probably
  983. // not safari either
  984. // dont like browser sniffs implementations but sometimes you have to
  985. // use it
  986. if (dojo.isIE) {
  987. // only call scrollIntoView if there is a scrollbar for this menu,
  988. // otherwise, scrollIntoView will scroll the window scrollbar
  989. if (dojo.marginBox(node.parentNode).h <= node.parentNode.scrollHeight) { // PORT
  990. // was
  991. // getBorderBox
  992. node.scrollIntoView(false);
  993. }
  994. } else if (dojo.isMozilla) {
  995. node.scrollIntoView(false);
  996. } else {
  997. var parent = node.parentNode;
  998. var parentBottom = parent.scrollTop + dojo.marginBox(parent).h; // PORT
  999. // was
  1000. // getBorderBox
  1001. var nodeBottom = node.offsetTop + dojo.marginBox(node).h;
  1002. if (parentBottom < nodeBottom) {
  1003. parent.scrollTop += (nodeBottom - parentBottom);
  1004. } else if (parent.scrollTop > node.offsetTop) {
  1005. parent.scrollTop -= (parent.scrollTop - node.offsetTop);
  1006. }
  1007. }
  1008. };
  1009. }
  1010. if (!dojo._hasResource["dijit._base.sniff"]) { // _hasResource checks added by
  1011. // build. Do not use
  1012. // _hasResource directly in your
  1013. // code.
  1014. dojo._hasResource["dijit._base.sniff"] = true;
  1015. dojo.provide("dijit._base.sniff");
  1016. // ported from dojo.html.applyBrowserClass (style.js)
  1017. // summary:
  1018. // Applies pre-set class names based on browser & version to the
  1019. // top-level HTML node. Simply doing a require on this module will
  1020. // establish this CSS. Modified version of Morris' CSS hack.
  1021. (function() {
  1022. var d = dojo;
  1023. var ie = d.isIE;
  1024. var opera = d.isOpera;
  1025. var maj = Math.floor;
  1026. var classes = {
  1027. dj_ie : ie,
  1028. // dj_ie55: ie == 5.5,
  1029. dj_ie6 : maj(ie) == 6,
  1030. dj_ie7 : maj(ie) == 7,
  1031. dj_iequirks : ie && d.isQuirks,
  1032. // NOTE: Opera not supported by dijit
  1033. dj_opera : opera,
  1034. dj_opera8 : maj(opera) == 8,
  1035. dj_opera9 : maj(opera) == 9,
  1036. dj_khtml : d.isKhtml,
  1037. dj_safari : d.isSafari,
  1038. dj_gecko : d.isMozilla
  1039. }; // no dojo unsupported browsers
  1040. for (var p in classes) {
  1041. if (classes[p]) {
  1042. var html = dojo.doc.documentElement; // TODO browser-specific
  1043. // DOM magic needed?
  1044. if (html.className) {
  1045. html.className += " " + p;
  1046. } else {
  1047. html.className = p;
  1048. }
  1049. }
  1050. }
  1051. })();
  1052. }
  1053. if (!dojo._hasResource["dijit._base.bidi"]) { // _hasResource checks added by
  1054. // build. Do not use
  1055. // _hasResource directly in your
  1056. // code.
  1057. dojo._hasResource["dijit._base.bidi"] = true;
  1058. dojo.provide("dijit._base.bidi");
  1059. // summary: applies a class to the top of the document for right-to-left
  1060. // stylesheet rules
  1061. dojo.addOnLoad(function() {
  1062. if (!dojo._isBodyLtr()) {
  1063. dojo.addClass(dojo.body(), "dijitRtl");
  1064. }
  1065. });
  1066. }
  1067. if (!dojo._hasResource["dijit._base.typematic"]) { // _hasResource checks added
  1068. // by build. Do not use
  1069. // _hasResource directly in
  1070. // your code.
  1071. dojo._hasResource["dijit._base.typematic"] = true;
  1072. dojo.provide("dijit._base.typematic");
  1073. dijit.typematic = {
  1074. // summary:
  1075. // These functions are used to repetitively call a user specified
  1076. // callback
  1077. // method when a specific key or mouse click over a specific DOM node is
  1078. // held down for a specific amount of time.
  1079. // Only 1 such event is allowed to occur on the browser page at 1 time.
  1080. _fireEventAndReload : function() {
  1081. this._timer = null;
  1082. this._callback(++this._count, this._node, this._evt);
  1083. this._currentTimeout = (this._currentTimeout < 0)
  1084. ? this._initialDelay
  1085. : ((this._subsequentDelay > 1)
  1086. ? this._subsequentDelay
  1087. : Math.round(this._currentTimeout
  1088. * this._subsequentDelay));
  1089. this._timer = setTimeout(dojo.hitch(this, "_fireEventAndReload"),
  1090. this._currentTimeout);
  1091. },
  1092. trigger : function(/* Event */evt, /* Object */_this, /* DOMNode */node, /* Function */
  1093. callback, /* Object */obj, /* Number */subsequentDelay, /* Number */
  1094. initialDelay) {
  1095. // summary:
  1096. // Start a timed, repeating callback sequence.
  1097. // If already started, the function call is ignored.
  1098. // This method is not normally called by the user but can be
  1099. // when the normal listener code is insufficient.
  1100. // Parameters:
  1101. // evt: key or mouse event object to pass to the user callback
  1102. // _this: pointer to the user's widget space.
  1103. // node: the DOM node object to pass the the callback function
  1104. // callback: function to call until the sequence is stopped called
  1105. // with 3 parameters:
  1106. // count: integer representing number of repeated calls (0..n) with
  1107. // -1 indicating the iteration has stopped
  1108. // node: the DOM node object passed in
  1109. // evt: key or mouse event object
  1110. // obj: user space object used to uniquely identify each typematic
  1111. // sequence
  1112. // subsequentDelay: if > 1, the number of milliseconds until the
  1113. // 3->n events occur
  1114. // or else the fractional time multiplier for the next event's
  1115. // delay, default=0.9
  1116. // initialDelay: the number of milliseconds until the 2nd event
  1117. // occurs, default=500ms
  1118. if (obj != this._obj) {
  1119. this.stop();
  1120. this._initialDelay = initialDelay || 500;
  1121. this._subsequentDelay = subsequentDelay || 0.90;
  1122. this._obj = obj;
  1123. this._evt = evt;
  1124. this._node = node;
  1125. this._currentTimeout = -1;
  1126. this._count = -1;
  1127. this._callback = dojo.hitch(_this, callback);
  1128. this._fireEventAndReload();
  1129. }
  1130. },
  1131. stop : function() {
  1132. // summary:
  1133. // Stop an ongoing timed, repeating callback sequence.
  1134. if (this._timer) {
  1135. clearTimeout(this._timer);
  1136. this._timer = null;
  1137. }
  1138. if (this._obj) {
  1139. this._callback(-1, this._node, this._evt);
  1140. this._obj = null;
  1141. }
  1142. },
  1143. addKeyListener : function(/* DOMNode */node, /* Object */keyObject, /* Object */
  1144. _this, /* Function */callback, /* Number */subsequentDelay, /* Number */
  1145. initialDelay) {
  1146. // summary: Start listening for a specific typematic key.
  1147. // keyObject: an object defining the key to listen for.
  1148. // key: (mandatory) the keyCode (number) or character (string) to
  1149. // listen for.
  1150. // ctrlKey: desired ctrl key state to initiate the calback sequence:
  1151. // pressed (true)
  1152. // released (false)
  1153. // either (unspecified)
  1154. // altKey: same as ctrlKey but for the alt key
  1155. // shiftKey: same as ctrlKey but for the shift key
  1156. // See the trigger method for other parameters.
  1157. // Returns an array of dojo.connect handles
  1158. return [dojo.connect(node, "onkeypress", this, function(evt) {
  1159. if (evt.keyCode == keyObject.keyCode
  1160. && (!keyObject.charCode || keyObject.charCode == evt.charCode)
  1161. && (keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey)
  1162. && (keyObject.altKey === undefined || keyObject.altKey == evt.ctrlKey)
  1163. && (keyObject.shiftKey === undefined || keyObject.shiftKey == evt.ctrlKey)) {
  1164. dojo.stopEvent(evt);
  1165. dijit.typematic.trigger(keyObject, _this, node, callback,
  1166. keyObject, subsequentDelay, initialDelay);
  1167. } else if (dijit.typematic._obj == keyObject) {
  1168. dijit.typematic.stop();
  1169. }
  1170. }), dojo.connect(node, "onkeyup", this, function(evt) {
  1171. if (dijit.typematic._obj == keyObject) {
  1172. dijit.typematic.stop();
  1173. }
  1174. })];
  1175. },
  1176. addMouseListener : function(/* DOMNode */node, /* Object */_this, /* Function */
  1177. callback, /* Number */subsequentDelay, /* Number */initialDelay) {
  1178. // summary: Start listening for a typematic mouse click.
  1179. // See the trigger method for other parameters.
  1180. // Returns an array of dojo.connect handles
  1181. var dc = dojo.connect;
  1182. return [dc(node, "mousedown", this, function(evt) {
  1183. dojo.stopEvent(evt);
  1184. dijit.typematic.trigger(evt, _this, node, callback,
  1185. node, subsequentDelay, initialDelay);
  1186. }), dc(node, "mouseup", this, function(evt) {
  1187. dojo.stopEvent(evt);
  1188. dijit.typematic.stop();
  1189. }), dc(node, "mouseout", this, function(evt) {
  1190. dojo.stopEvent(evt);
  1191. dijit.typematic.stop();
  1192. }), dc(node, "mousemove", this, function(evt) {
  1193. dojo.stopEvent(evt);
  1194. }), dc(node, "dblclick", this, function(evt) {
  1195. dojo.stopEvent(evt);
  1196. if (dojo.isIE) {
  1197. dijit.typematic.trigger(evt, _this, node, callback,
  1198. node, subsequentDelay, initialDelay);
  1199. setTimeout(dijit.typematic.stop, 50);
  1200. }
  1201. })];
  1202. },
  1203. addListener : function(/* Node */mouseNode, /* Node */keyNode, /* Object */
  1204. keyObject, /* Object */_this, /* Function */callback, /* Number */
  1205. subsequentDelay, /* Number */initialDelay) {
  1206. // summary: Start listening for a specific typematic key and
  1207. // mouseclick.
  1208. // This is a thin wrapper to addKeyListener and addMouseListener.
  1209. // mouseNode: the DOM node object to listen on for mouse events.
  1210. // keyNode: the DOM node object to listen on for key events.
  1211. // See the addMouseListener and addKeyListener methods for other
  1212. // parameters.
  1213. // Returns an array of dojo.connect handles
  1214. return this.addKeyListener(keyNode, keyObject, _this, callback,
  1215. subsequentDelay, initialDelay).concat(this
  1216. .addMouseListener(mouseNode, _this, callback,
  1217. subsequentDelay, initialDelay));
  1218. }
  1219. };
  1220. }
  1221. if (!dojo._hasResource["dijit._base.wai"]) { // _hasResource checks added by
  1222. // build. Do not use
  1223. // _hasResource directly in your
  1224. // code.
  1225. dojo._hasResource["dijit._base.wai"] = true;
  1226. dojo.provide("dijit._base.wai");
  1227. dijit.wai = {
  1228. onload : function() {
  1229. // summary:
  1230. // Function that detects if we are in high-contrast mode or not,
  1231. // and sets up a timer to periodically confirm the value.
  1232. // figure out the background-image style property
  1233. // and apply that to the image.src property.
  1234. // description:
  1235. // This must be a named function and not an anonymous
  1236. // function, so that the widget parsing code can make sure it
  1237. // registers its onload function after this function.
  1238. // DO NOT USE "this" within this function.
  1239. // create div for testing if high contrast mode is on or images are
  1240. // turned off
  1241. var div = document.createElement("div");
  1242. div.id = "a11yTestNode";
  1243. div.style.cssText = 'border: 1px solid;'
  1244. + 'border-color:red green;' + 'position: absolute;'
  1245. + 'height: 5px;' + 'top: -999px;'
  1246. + 'background-image: url("'
  1247. + dojo.moduleUrl("dijit", "form/templates/blank.gif")
  1248. + '");';
  1249. dojo.body().appendChild(div);
  1250. // test it
  1251. function check() {
  1252. var cs = dojo.getComputedStyle(div);
  1253. if (cs) {
  1254. var bkImg = cs.backgroundImage;
  1255. var needsA11y = (cs.borderTopColor == cs.borderRightColor)
  1256. || (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)"));
  1257. dojo[needsA11y ? "addClass" : "removeClass"](dojo.body(),
  1258. "dijit_a11y");
  1259. }
  1260. }
  1261. check();
  1262. if (dojo.isIE) {
  1263. setInterval(check, 4000);
  1264. }
  1265. }
  1266. };
  1267. // Test if computer is in high contrast mode.
  1268. // Make sure the a11y test runs first, before widgets are instantiated.
  1269. if (dojo.isIE || dojo.isMoz) { // NOTE: checking in Safari messes things up
  1270. dojo._loaders.unshift(dijit.wai.onload);
  1271. }
  1272. dojo.mixin(dijit, {
  1273. hasWaiRole : function(/* Element */elem) {
  1274. // Summary: Return true if elem has a role attribute and false if
  1275. // not.
  1276. if (elem.hasAttribute) {
  1277. return elem.hasAttribute("role");
  1278. } else {
  1279. return elem.getAttribute("role") ? true : false;
  1280. }
  1281. },
  1282. getWaiRole : function(/* Element */elem) {
  1283. // Summary: Return the role of elem or an empty string if
  1284. // elem does not have a role.
  1285. var value = elem.getAttribute("role");
  1286. if (value) {
  1287. var prefixEnd = value.indexOf(":");
  1288. return prefixEnd == -1 ? value : value.substring(prefixEnd + 1);
  1289. } else {
  1290. return "";
  1291. }
  1292. },
  1293. setWaiRole : function(/* Element */elem, /* String */role) {
  1294. // Summary: Set the role on elem. On Firefox 2 and below, "wairole:"
  1295. // is
  1296. // prepended to the provided role value.
  1297. if (dojo.isFF && dojo.isFF < 3) {
  1298. elem.setAttribute("role", "wairole:" + role);
  1299. } else {
  1300. elem.setAttribute("role", role);
  1301. }
  1302. },
  1303. removeWaiRole : function(/* Element */elem) {
  1304. // Summary: Removes the role attribute from elem.
  1305. elem.removeAttribute("role");
  1306. },
  1307. hasWaiState : function(/* Element */elem, /* String */state) {
  1308. // Summary: Return true if elem has a value for the given state and
  1309. // false if it does not.
  1310. // On Firefox 2 and below, we check for an attribute in namespace
  1311. // "http://www.w3.org/2005/07/aaa" with a name of the given state.
  1312. // On all other browsers, we check for an attribute called
  1313. // "aria-"+state.
  1314. if (dojo.isFF && dojo.isFF < 3) {
  1315. return elem.hasAttributeNS("http://www.w3.org/2005/07/aaa",
  1316. state);
  1317. } else {
  1318. if (elem.hasAttribute) {
  1319. return elem.hasAttribute("aria-" + state);
  1320. } else {
  1321. return elem.getAttribute("aria-" + state) ? true : false;
  1322. }
  1323. }
  1324. },
  1325. getWaiState : function(/* Element */elem, /* String */state) {
  1326. // Summary: Return the value of the requested state on elem
  1327. // or an empty string if elem has no value for state.
  1328. // On Firefox 2 and below, we check for an attribute in namespace
  1329. // "http://www.w3.org/2005/07/aaa" with a name of the given state.
  1330. // On all other browsers, we check for an attribute called
  1331. // "aria-"+state.
  1332. if (dojo.isFF && dojo.isFF < 3) {
  1333. return elem.getAttributeNS("http://www.w3.org/2005/07/aaa",
  1334. state);
  1335. } else {
  1336. var value = elem.getAttribute("aria-" + state);
  1337. return value ? value : "";
  1338. }
  1339. },
  1340. setWaiState : function(/* Element */elem, /* String */state, /* String */
  1341. value) {
  1342. // Summary: Set state on elem to value.
  1343. // On Firefox 2 and below, we set an attribute in namespace
  1344. // "http://www.w3.org/2005/07/aaa" with a name of the given state.
  1345. // On all other browsers, we set an attribute called
  1346. // "aria-"+state.
  1347. if (dojo.isFF && dojo.isFF < 3) {
  1348. elem.setAttributeNS("http://www.w3.org/2005/07/aaa", "aaa:"
  1349. + state, value);
  1350. } else {
  1351. elem.setAttribute("aria-" + state, value);
  1352. }
  1353. },
  1354. removeWaiState : function(/* Element */elem, /* String */state) {
  1355. // Summary: Removes the given state from elem.
  1356. // On Firefox 2 and below, we remove the attribute in namespace
  1357. // "http://www.w3.org/2005/07/aaa" with a name of the given state.
  1358. // On all other browsers, we remove the attribute called
  1359. // "aria-"+state.
  1360. if (dojo.isFF && dojo.isFF < 3) {
  1361. elem.removeAttributeNS("http://www.w3.org/2005/07/aaa", state);
  1362. } else {
  1363. elem.removeAttribute("aria-" + state);
  1364. }
  1365. }
  1366. });
  1367. }
  1368. if (!dojo._hasResource["dijit._base"]) { // _hasResource checks added by
  1369. // build. Do not use _hasResource
  1370. // directly in your code.
  1371. dojo._hasResource["dijit._base"] = true;
  1372. dojo.provide("dijit._base");
  1373. }
  1374. if (!dojo._hasResource["dojo.date.stamp"]) { // _hasResource checks added by
  1375. // build. Do not use
  1376. // _hasResource directly in your
  1377. // code.
  1378. dojo._hasResource["dojo.date.stamp"] = true;
  1379. dojo.provide("dojo.date.stamp");
  1380. // Methods to convert dates to or from a wire (string) format using
  1381. // well-known conventions
  1382. dojo.date.stamp.fromISOString = function(/* String */formattedString, /* Number? */
  1383. defaultTime) {
  1384. // summary:
  1385. // Returns a Date object given a string formatted according to a subset
  1386. // of the ISO-8601 standard.
  1387. //
  1388. // description:
  1389. // Accepts a string formatted according to a profile of ISO8601 as
  1390. // defined by
  1391. // RFC3339 (http://www.ietf.org/rfc/rfc3339.txt), except that partial
  1392. // input is allowed.
  1393. // Can also process dates as specified by
  1394. // http://www.w3.org/TR/NOTE-datetime
  1395. // The following combinations are valid:
  1396. // * dates only
  1397. // yyyy
  1398. // yyyy-MM
  1399. // yyyy-MM-dd
  1400. // * times only, with an optional time zone appended
  1401. // THH:mm
  1402. // THH:mm:ss
  1403. // THH:mm:ss.SSS
  1404. // * and "datetimes" which could be any combination of the above
  1405. // timezones may be specified as Z (for UTC) or +/- followed by a time
  1406. // expression HH:mm
  1407. // Assumes the local time zone if not specified. Does not validate.
  1408. // Improperly formatted
  1409. // input may return null. Arguments which are out of bounds will be
  1410. // handled
  1411. // by the Date constructor (e.g. January 32nd typically gets resolved to
  1412. // February 1st)
  1413. //
  1414. // formattedString:
  1415. // A string such as 2005-06-30T08:05:00-07:00 or 2005-06-30 or T08:05:00
  1416. //
  1417. // defaultTime:
  1418. // Used for defaults for fields omitted in the formattedString.
  1419. // Uses 1970-01-01T00:00:00.0Z by default.
  1420. if (!dojo.date.stamp._isoRegExp) {
  1421. dojo.date.stamp._isoRegExp =
  1422. // TODO: could be more restrictive and check for 00-59, etc.
  1423. /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/;
  1424. }
  1425. var match = dojo.date.stamp._isoRegExp.exec(formattedString);
  1426. var result = null;
  1427. if (match) {
  1428. match.shift();
  1429. match[1] && match[1]--; // Javascript Date months are 0-based
  1430. match[6] && (match[6] *= 1000); // Javascript Date expects
  1431. // fractional seconds as
  1432. // milliseconds
  1433. if (defaultTime) {
  1434. // mix in defaultTime. Relatively expensive, so use || operators
  1435. // for the fast path of defaultTime === 0
  1436. defaultTime = new Date(defaultTime);
  1437. dojo.map(
  1438. ["FullYear", "Month", "Date", "Hours", "Minutes",
  1439. "Seconds", "Milliseconds"], function(prop) {
  1440. return defaultTime["get" + prop]();
  1441. }).forEach(function(value, index) {
  1442. if (match[index] === undefined) {
  1443. match[index] = value;
  1444. }
  1445. });
  1446. }
  1447. result = new Date(match[0] || 1970, match[1] || 0, match[2] || 0,
  1448. match[3] || 0, match[4] || 0, match[5] || 0, match[6] || 0);
  1449. var offset = 0;
  1450. var zoneSign = match[7] && match[7].charAt(0);
  1451. if (zoneSign != 'Z') {
  1452. offset = ((match[8] || 0) * 60) + (Number(match[9]) || 0);
  1453. if (zoneSign != '-') {
  1454. offset *= -1;
  1455. }
  1456. }
  1457. if (zoneSign) {
  1458. offset -= result.getTimezoneOffset();
  1459. }
  1460. if (offset) {
  1461. result.setTime(result.getTime() + offset * 60000);
  1462. }
  1463. }
  1464. return result; // Date or null
  1465. }
  1466. dojo.date.stamp.toISOString = function(/* Date */dateObject, /* Object? */
  1467. options) {
  1468. // summary:
  1469. // Format a Date object as a string according a subset of the ISO-8601
  1470. // standard
  1471. //
  1472. // description:
  1473. // When options.selector is omitted, output follows RFC3339
  1474. // (http://www.ietf.org/rfc/rfc3339.txt)
  1475. // The local time zone is included as an offset from GMT, except when
  1476. // selector=='time' (time without a date)
  1477. // Does not check bounds.
  1478. //
  1479. // dateObject:
  1480. // A Date object
  1481. //
  1482. // object {selector: string, zulu: boolean, milliseconds: boolean}
  1483. // selector- "date" or "time" for partial formatting of the Date object.
  1484. // Both date and time will be formatted by default.
  1485. // zulu- if true, UTC/GMT is used for a timezone
  1486. // milliseconds- if true, output milliseconds
  1487. var _ = function(n) {
  1488. return (n < 10) ? "0" + n : n;
  1489. }
  1490. options = options || {};
  1491. var formattedDate = [];
  1492. var getter = options.zulu ? "getUTC" : "get";
  1493. var date = "";
  1494. if (options.selector != "time") {
  1495. date = [dateObject[getter + "FullYear"](),
  1496. _(dateObject[getter + "Month"]() + 1),
  1497. _(dateObject[getter + "Date"]())].join('-');
  1498. }
  1499. formattedDate.push(date);
  1500. if (options.selector != "date") {
  1501. var time = [_(dateObject[getter + "Hours"]()),
  1502. _(dateObject[getter + "Minutes"]()),
  1503. _(dateObject[getter + "Seconds"]())].join(':');
  1504. var millis = dateObject[getter + "Milliseconds"]();
  1505. if (options.milliseconds) {
  1506. time += "." + (millis < 100 ? "0" : "") + _(millis);
  1507. }
  1508. if (options.zulu) {
  1509. time += "Z";
  1510. } else if (options.selector != "time") {
  1511. var timezoneOffset = dateObject.getTimezoneOffset();
  1512. var absOffset = Math.abs(timezoneOffset);
  1513. time += (timezoneOffset > 0 ? "-" : "+")
  1514. + _(Math.floor(absOffset / 60)) + ":"
  1515. + _(absOffset % 60);
  1516. }
  1517. formattedDate.push(time);
  1518. }
  1519. return formattedDate.join('T'); // String
  1520. }
  1521. }
  1522. if (!dojo._hasResource["dojo.parser"]) { // _hasResource checks added by
  1523. // build. Do not use _hasResource
  1524. // directly in your code.
  1525. dojo._hasResource["dojo.parser"] = true;
  1526. dojo.provide("dojo.parser");
  1527. dojo.parser = new function() {
  1528. var d = dojo;
  1529. function val2type(/* Object */value) {
  1530. // summary:
  1531. // Returns name of type of given value.
  1532. if (d.isString(value)) {
  1533. return "string";
  1534. }
  1535. if (typeof value == "number") {
  1536. return "number";
  1537. }
  1538. if (typeof value == "boolean") {
  1539. return "boolean";
  1540. }
  1541. if (d.isFunction(value)) {
  1542. return "function";
  1543. }
  1544. if (d.isArray(value)) {
  1545. return "array";
  1546. } // typeof [] == "object"
  1547. if (value instanceof Date) {
  1548. return "date";
  1549. } // assume timestamp
  1550. if (value instanceof d._Url) {
  1551. return "url";
  1552. }
  1553. return "object";
  1554. }
  1555. function str2obj(/* String */value, /* String */type) {
  1556. // summary:
  1557. // Convert given string value to given type
  1558. switch (type) {
  1559. case "string" :
  1560. return value;
  1561. case "number" :
  1562. return value.length ? Number(value) : NaN;
  1563. case "boolean" :
  1564. // for checked/disabled value might be "" or "checked".
  1565. // interpret as true.
  1566. return typeof value == "boolean" ? value : !(value
  1567. .toLowerCase() == "false");
  1568. case "function" :
  1569. if (d.isFunction(value)) {
  1570. // IE gives us a function, even when we say something
  1571. // like onClick="foo"
  1572. // (in which case it gives us an invalid function
  1573. // "function(){ foo }").
  1574. // Therefore, convert to string
  1575. value = value.toString();
  1576. value = d.trim(value.substring(value.indexOf('{') + 1,
  1577. value.length - 1));
  1578. }
  1579. try {
  1580. if (value.search(/[^\w\.]+/i) != -1) {
  1581. // TODO: "this" here won't work
  1582. value = d.parser._nameAnonFunc(new Function(value),
  1583. this);
  1584. }
  1585. return d.getObject(value, false);
  1586. } catch (e) {
  1587. return new Function();
  1588. }
  1589. case "array" :
  1590. return value.split(/\s*,\s*/);
  1591. case "date" :
  1592. switch (value) {
  1593. case "" :
  1594. return new Date(""); // the NaN of dates
  1595. case "now" :
  1596. return allGetServerTime(); // current date
  1597. default :
  1598. return d.date.stamp.fromISOString(value);
  1599. }
  1600. case "url" :
  1601. return d.baseUrl + value;
  1602. default :
  1603. return d.fromJson(value);
  1604. }
  1605. }
  1606. var instanceClasses = {
  1607. // map from fully qualified name (like "dijit.Button") to structure like
  1608. // { cls: dijit.Button, params: {label: "string", disabled: "boolean"} }
  1609. };
  1610. function getClassInfo(/* String */className) {
  1611. // className:
  1612. // fully qualified name (like "dijit.Button")
  1613. // returns:
  1614. // structure like
  1615. // {
  1616. // cls: dijit.Button,
  1617. // params: { label: "string", disabled: "boolean"}
  1618. // }
  1619. if (!instanceClasses[className]) {
  1620. // get pointer to widget class
  1621. var cls = d.getObject(className);
  1622. if (!d.isFunction(cls)) {
  1623. throw new Error("Could not load class '"
  1624. + className
  1625. + "'. Did you spell the name correctly and use a full path, like 'dijit.form.Button'?");
  1626. }
  1627. var proto = cls.prototype;
  1628. // get table of parameter names & types
  1629. var params = {};
  1630. for (var name in proto) {
  1631. if (name.charAt(0) == "_") {
  1632. continue;
  1633. } // skip internal properties
  1634. var defVal = proto[name];
  1635. params[name] = val2type(defVal);
  1636. }
  1637. instanceClasses[className] = {
  1638. cls : cls,
  1639. params : params
  1640. };
  1641. }
  1642. return instanceClasses[className];
  1643. }
  1644. this._functionFromScript = function(script) {
  1645. var preamble = "";
  1646. var suffix = "";
  1647. var argsStr = script.getAttribute("args");
  1648. if (argsStr) {
  1649. d.forEach(argsStr.split(/\s*,\s*/), function(part, idx) {
  1650. preamble += "var " + part + " = arguments[" + idx
  1651. + "]; ";
  1652. });
  1653. }
  1654. var withStr = script.getAttribute("with");
  1655. if (withStr && withStr.length) {
  1656. d.forEach(withStr.split(/\s*,\s*/), function(part) {
  1657. preamble += "with(" + part + "){";
  1658. suffix += "}";
  1659. });
  1660. }
  1661. return new Function(preamble + script.innerHTML + suffix);
  1662. }
  1663. this.instantiate = function(/* Array */nodes) {
  1664. // summary:
  1665. // Takes array of nodes, and turns them into class instances and
  1666. // potentially calls a layout method to allow them to connect with
  1667. // any children
  1668. var thelist = [];
  1669. d.forEach(nodes, function(node) {
  1670. if (!node) {
  1671. return;
  1672. }
  1673. var type = node.getAttribute("dojoType");
  1674. if ((!type) || (!type.length)) {
  1675. return;
  1676. }
  1677. var clsInfo = getClassInfo(type);
  1678. var clazz = clsInfo.cls;
  1679. var ps = clazz._noScript || clazz.prototype._noScript;
  1680. // read parameters (ie, attributes).
  1681. // clsInfo.params lists expected params like {"checked":
  1682. // "boolean", "n": "number"}
  1683. var params = {};
  1684. var attributes = node.attributes;
  1685. for (var name in clsInfo.params) {
  1686. var item = attributes.getNamedItem(name);
  1687. if (!item
  1688. || (!item.specified && (!dojo.isIE || name
  1689. .toLowerCase() != "value"))) {
  1690. continue;
  1691. }
  1692. var value = item.value;
  1693. // Deal with IE quirks for 'class' and 'style'
  1694. switch (name) {
  1695. case "class" :
  1696. value = node.className;
  1697. break;
  1698. case "style" :
  1699. value = node.style && node.style.cssText; // FIXME:
  1700. // Opera?
  1701. }
  1702. var _type = clsInfo.params[name];
  1703. params[name] = str2obj(value, _type);
  1704. }
  1705. // Process <script type="dojo/*"> script tags
  1706. // <script type="dojo/method" event="foo"> tags are added to
  1707. // params, and passed to
  1708. // the widget on instantiation.
  1709. // <script type="dojo/method"> tags (with no event) are executed
  1710. // after instantiation
  1711. // <script type="dojo/connect" event="foo"> tags are
  1712. // dojo.connected after instantiation
  1713. if (!ps) {
  1714. var connects = [], // functions to connect after
  1715. // instantiation
  1716. calls = []; // functions to call after instantiation
  1717. d.query("> script[type^='dojo/']", node).orphan().forEach(
  1718. function(script) {
  1719. var event = script.getAttribute("event"), type = script
  1720. .getAttribute("type"), nf = d.parser
  1721. ._functionFromScript(script);
  1722. if (event) {
  1723. if (type == "dojo/connect") {
  1724. connects.push({
  1725. event : event,
  1726. func : nf
  1727. });
  1728. } else {
  1729. params[event] = nf;
  1730. }
  1731. } else {
  1732. calls.push(nf);
  1733. }
  1734. });
  1735. }
  1736. var markupFactory = clazz["markupFactory"];
  1737. if (!markupFactory && clazz["prototype"]) {
  1738. markupFactory = clazz.prototype["markupFactory"];
  1739. }
  1740. // create the instance
  1741. var instance = markupFactory ? markupFactory(params, node,
  1742. clazz) : new clazz(params, node);
  1743. thelist.push(instance);
  1744. // map it to the JS namespace if that makes sense
  1745. var jsname = node.getAttribute("jsId");
  1746. if (jsname) {
  1747. d.setObject(jsname, instance);
  1748. }
  1749. // process connections and startup functions
  1750. if (!ps) {
  1751. dojo.forEach(connects, function(connect) {
  1752. dojo.connect(instance, connect.event, null,
  1753. connect.func);
  1754. });
  1755. dojo.forEach(calls, function(func) {
  1756. func.call(instance);
  1757. });
  1758. }
  1759. });
  1760. // Call startup on each top level instance if it makes sense (as for
  1761. // widgets). Parent widgets will recursively call startup on their
  1762. // (non-top level) children
  1763. d.forEach(thelist, function(instance) {
  1764. if (instance
  1765. && (instance.startup)
  1766. && ((!instance.getParent) || (!instance
  1767. .getParent()))) {
  1768. instance.startup();
  1769. }
  1770. });
  1771. return thelist;
  1772. };
  1773. this.parse = function(/* DomNode? */rootNode) {
  1774. // summary:
  1775. // Search specified node (or root node) recursively for class
  1776. // instances,
  1777. // and instantiate them Searches for
  1778. // dojoType="qualified.class.name"
  1779. var list = d.query('[dojoType]', rootNode);
  1780. // go build the object instances
  1781. var instances = this.instantiate(list);
  1782. return instances;
  1783. };
  1784. }();
  1785. // Register the parser callback. It should be the first callback
  1786. // after the a11y test.
  1787. (function() {
  1788. var parseRunner = function() {
  1789. if (djConfig["parseOnLoad"] == true) {
  1790. dojo.parser.parse();
  1791. }
  1792. };
  1793. // FIXME: need to clobber cross-dependency!!
  1794. if (dojo.exists("dijit.wai.onload")
  1795. && (dijit.wai.onload === dojo._loaders[0])) {
  1796. dojo._loaders.splice(1, 0, parseRunner);
  1797. } else {
  1798. dojo._loaders.unshift(parseRunner);
  1799. }
  1800. })();
  1801. // TODO: ported from 0.4.x Dojo. Can we reduce this?
  1802. dojo.parser._anonCtr = 0;
  1803. dojo.parser._anon = {}; // why is this property required?
  1804. dojo.parser._nameAnonFunc = function(/* Function */anonFuncPtr, /* Object */
  1805. thisObj) {
  1806. // summary:
  1807. // Creates a reference to anonFuncPtr in thisObj with a completely
  1808. // unique name. The new name is returned as a String.
  1809. var jpn = "$joinpoint";
  1810. var nso = (thisObj || dojo.parser._anon);
  1811. if (dojo.isIE) {
  1812. var cn = anonFuncPtr["__dojoNameCache"];
  1813. if (cn && nso[cn] === anonFuncPtr) {
  1814. return anonFuncPtr["__dojoNameCache"];
  1815. }
  1816. }
  1817. var ret = "__" + dojo.parser._anonCtr++;
  1818. while (typeof nso[ret] != "undefined") {
  1819. ret = "__" + dojo.parser._anonCtr++;
  1820. }
  1821. nso[ret] = anonFuncPtr;
  1822. return ret; // String
  1823. }
  1824. }
  1825. if (!dojo._hasResource["dijit._Widget"]) { // _hasResource checks added by
  1826. // build. Do not use _hasResource
  1827. // directly in your code.
  1828. dojo._hasResource["dijit._Widget"] = true;
  1829. dojo.provide("dijit._Widget");
  1830. dojo.declare("dijit._Widget", null, {
  1831. // summary:
  1832. // The foundation of dijit widgets.
  1833. //
  1834. // id: String
  1835. // a unique, opaque ID string that can be assigned by users or by the
  1836. // system. If the developer passes an ID which is known not to be
  1837. // unique, the specified ID is ignored and the system-generated ID is
  1838. // used instead.
  1839. id : "",
  1840. // lang: String
  1841. // Language to display this widget in (like en-us).
  1842. // Defaults to brower's specified preferred language (typically the
  1843. // language of the OS)
  1844. lang : "",
  1845. // dir: String
  1846. // Bi-directional support, as defined by the HTML DIR attribute. Either
  1847. // left-to-right "ltr" or right-to-left "rtl".
  1848. dir : "",
  1849. // class: String
  1850. // HTML class attribute
  1851. "class" : "",
  1852. // style: String
  1853. // HTML style attribute
  1854. style : "",
  1855. // title: String
  1856. // HTML title attribute
  1857. title : "",
  1858. // srcNodeRef: DomNode
  1859. // pointer to original dom node
  1860. srcNodeRef : null,
  1861. // domNode: DomNode
  1862. // this is our visible representation of the widget! Other DOM
  1863. // Nodes may by assigned to other properties, usually through the
  1864. // template system's dojoAttachPonit syntax, but the domNode
  1865. // property is the canonical "top level" node in widget UI.
  1866. domNode : null,
  1867. // attributeMap: Object
  1868. // A map of attributes and attachpoints -- typically standard HTML
  1869. // attributes -- to set
  1870. // on the widget's dom, at the "domNode" attach point, by default.
  1871. // Other node references can be specified as properties of 'this'
  1872. attributeMap : {
  1873. id : "",
  1874. dir : "",
  1875. lang : "",
  1876. "class" : "",
  1877. style : "",
  1878. title : ""
  1879. }, // TODO: add on* handlers?
  1880. // ////////// INITIALIZATION METHODS
  1881. // ///////////////////////////////////////
  1882. postscript : function(params, srcNodeRef) {
  1883. this.create(params, srcNodeRef);
  1884. },
  1885. create : function(params, srcNodeRef) {
  1886. // summary:
  1887. // To understand the process by which widgets are instantiated, it
  1888. // is critical to understand what other methods create calls and
  1889. // which of them you'll want to override. Of course, adventurous
  1890. // developers could override create entirely, but this should
  1891. // only be done as a last resort.
  1892. //
  1893. // Below is a list of the methods that are called, in the order
  1894. // they are fired, along with notes about what they do and if/when
  1895. // you should over-ride them in your widget:
  1896. //
  1897. // postMixInProperties:
  1898. // a stub function that you can over-ride to modify
  1899. // variables that may have been naively assigned by
  1900. // mixInProperties
  1901. // # widget is added to manager object here
  1902. // buildRendering
  1903. // Subclasses use this method to handle all UI initialization
  1904. // Sets this.domNode. Templated widgets do this automatically
  1905. // and otherwise it just uses the source dom node.
  1906. // postCreate
  1907. // a stub function that you can over-ride to modify take
  1908. // actions once the widget has been placed in the UI
  1909. // store pointer to original dom tree
  1910. this.srcNodeRef = dojo.byId(srcNodeRef);
  1911. // For garbage collection. An array of handles returned by
  1912. // Widget.connect()
  1913. // Each handle returned from Widget.connect() is an array of handles
  1914. // from dojo.connect()
  1915. this._connects = [];
  1916. // _attaches: String[]
  1917. // names of all our dojoAttachPoint variables
  1918. this._attaches = [];
  1919. // mixin our passed parameters
  1920. if (this.srcNodeRef && (typeof this.srcNodeRef.id == "string")) {
  1921. this.id = this.srcNodeRef.id;
  1922. }
  1923. if (params) {
  1924. dojo.mixin(this, params);
  1925. }
  1926. this.postMixInProperties();
  1927. // generate an id for the widget if one wasn't specified
  1928. // (be sure to do this before buildRendering() because that function
  1929. // might
  1930. // expect the id to be there.
  1931. if (!this.id) {
  1932. this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,
  1933. "_"));
  1934. }
  1935. dijit.registry.add(this);
  1936. this.buildRendering();
  1937. // Copy attributes listed in attributeMap into the [newly created]
  1938. // DOM for the widget.
  1939. // The placement of these attributes is according to the property
  1940. // mapping in attributeMap.
  1941. // Note special handling for 'style' and 'class' attributes which
  1942. // are lists and can
  1943. // have elements from both old and new structures, and some
  1944. // attributes like "type"
  1945. // cannot be processed this way as they are not mutable.
  1946. if (this.domNode) {
  1947. for (var attr in this.attributeMap) {
  1948. var mapNode = this[this.attributeMap[attr] || "domNode"];
  1949. var value = this[attr];
  1950. if (typeof value != "object"
  1951. && (value !== "" || (params && params[attr]))) {
  1952. switch (attr) {
  1953. case "class" :
  1954. dojo.addClass(mapNode, value);
  1955. break;
  1956. case "style" :
  1957. if (mapNode.style.cssText) {
  1958. mapNode.style.cssText += "; " + value;// FIXME:
  1959. // Opera
  1960. } else {
  1961. mapNode.style.cssText = value;
  1962. }
  1963. break;
  1964. default :
  1965. mapNode.setAttribute(attr, value);
  1966. }
  1967. }
  1968. }
  1969. }
  1970. if (this.domNode) {
  1971. this.domNode.setAttribute("widgetId", this.id);
  1972. }
  1973. this.postCreate();
  1974. // If srcNodeRef has been processed and removed from the DOM (e.g.
  1975. // TemplatedWidget) then delete it to allow GC.
  1976. if (this.srcNodeRef && !this.srcNodeRef.parentNode) {
  1977. delete this.srcNodeRef;
  1978. }
  1979. },
  1980. postMixInProperties : function() {
  1981. // summary
  1982. // Called after the parameters to the widget have been read-in,
  1983. // but before the widget template is instantiated.
  1984. // Especially useful to set properties that are referenced in the
  1985. // widget template.
  1986. },
  1987. buildRendering : function() {
  1988. // summary:
  1989. // Construct the UI for this widget, setting this.domNode.
  1990. // Most widgets will mixin TemplatedWidget, which overrides this
  1991. // method.
  1992. this.domNode = this.srcNodeRef || dojo.doc.createElement('div');
  1993. },
  1994. postCreate : function() {
  1995. // summary:
  1996. // Called after a widget's dom has been setup
  1997. },
  1998. startup : function() {
  1999. // summary:
  2000. // Called after a widget's children, and other widgets on the page,
  2001. // have been created.
  2002. // Provides an opportunity to manipulate any children before they
  2003. // are displayed
  2004. // This is useful for composite widgets that need to control or
  2005. // layout sub-widgets
  2006. // Many layout widgets can use this as a wiring phase
  2007. },
  2008. // ////////// DESTROY FUNCTIONS ////////////////////////////////
  2009. destroyRecursive : function(/* Boolean */finalize) {
  2010. // summary:
  2011. // Destroy this widget and it's descendants. This is the generic
  2012. // "destructor" function that all widget users should call to
  2013. // cleanly discard with a widget. Once a widget is destroyed, it's
  2014. // removed from the manager object.
  2015. // finalize: Boolean
  2016. // is this function being called part of global environment
  2017. // tear-down?
  2018. this.destroyDescendants();
  2019. this.destroy();
  2020. },
  2021. destroy : function(/* Boolean */finalize) {
  2022. // summary:
  2023. // Destroy this widget, but not its descendants
  2024. // finalize: Boolean
  2025. // is this function being called part of global environment
  2026. // tear-down?
  2027. this.uninitialize();
  2028. dojo.forEach(this._connects, function(array) {
  2029. dojo.forEach(array, dojo.disconnect);
  2030. });
  2031. this.destroyRendering(finalize);
  2032. dijit.registry.remove(this.id);
  2033. },
  2034. destroyRendering : function(/* Boolean */finalize) {
  2035. // summary:
  2036. // Destroys the DOM nodes associated with this widget
  2037. // finalize: Boolean
  2038. // is this function being called part of global environment
  2039. // tear-down?
  2040. if (this.bgIframe) {
  2041. this.bgIframe.destroy();
  2042. delete this.bgIframe;
  2043. }
  2044. if (this.domNode) {
  2045. dojo._destroyElement(this.domNode);
  2046. delete this.domNode;
  2047. }
  2048. if (this.srcNodeRef) {
  2049. dojo._destroyElement(this.srcNodeRef);
  2050. delete this.srcNodeRef;
  2051. }
  2052. },
  2053. destroyDescendants : function() {
  2054. // summary:
  2055. // Recursively destroy the children of this widget and their
  2056. // descendants.
  2057. // TODO: should I destroy in the reverse order, to go bottom up?
  2058. dojo.forEach(this.getDescendants(), function(widget) {
  2059. widget.destroy();
  2060. });
  2061. },
  2062. uninitialize : function() {
  2063. // summary:
  2064. // stub function. Over-ride to implement custom widget tear-down
  2065. // behavior.
  2066. return false;
  2067. },
  2068. // //////////////// MISCELLANEOUS METHODS ///////////////////
  2069. toString : function() {
  2070. // summary:
  2071. // returns a string that represents the widget. When a widget is
  2072. // cast to a string, this method will be used to generate the
  2073. // output. Currently, it does not implement any sort of reversable
  2074. // serialization.
  2075. return '[Widget ' + this.declaredClass + ', '
  2076. + (this.id || 'NO ID') + ']'; // String
  2077. },
  2078. getDescendants : function() {
  2079. // summary:
  2080. // return all the descendant widgets
  2081. var list = dojo.query('[widgetId]', this.domNode);
  2082. return list.map(dijit.byNode); // Array
  2083. },
  2084. nodesWithKeyClick : ["input", "button"],
  2085. connect : function(
  2086. /* Object|null */obj,
  2087. /* String */event,
  2088. /* String|Function */method) {
  2089. // summary:
  2090. // Connects specified obj/event to specified method of this object
  2091. // and registers for disconnect() on widget destroy.
  2092. // Special event: "ondijitclick" triggers on a click or enter-down
  2093. // or space-up
  2094. // Similar to dojo.connect() but takes three arguments rather than
  2095. // four.
  2096. var handles = [];
  2097. if (event == "ondijitclick") {
  2098. var w = this;
  2099. // add key based click activation for unsupported nodes.
  2100. if (!this.nodesWithKeyClick[obj.nodeName]) {
  2101. handles.push(dojo.connect(obj, "onkeydown", this, function(
  2102. e) {
  2103. if (e.keyCode == dojo.keys.ENTER) {
  2104. return (dojo.isString(method))
  2105. ? w[method](e)
  2106. : method.call(w, e);
  2107. } else if (e.keyCode == dojo.keys.SPACE) {
  2108. // stop space down as it causes IE to scroll
  2109. // the browser window
  2110. dojo.stopEvent(e);
  2111. }
  2112. }));
  2113. handles.push(dojo.connect(obj, "onkeyup", this,
  2114. function(e) {
  2115. if (e.keyCode == dojo.keys.SPACE) {
  2116. return dojo.isString(method)
  2117. ? w[method](e)
  2118. : method.call(w, e);
  2119. }
  2120. }));
  2121. }
  2122. event = "onclick";
  2123. }
  2124. handles.push(dojo.connect(obj, event, this, method));
  2125. // return handles for FormElement and ComboBox
  2126. this._connects.push(handles);
  2127. return handles;
  2128. },
  2129. disconnect : function(/* Object */handles) {
  2130. // summary:
  2131. // Disconnects handle created by this.connect.
  2132. // Also removes handle from this widget's list of connects
  2133. for (var i = 0; i < this._connects.length; i++) {
  2134. if (this._connects[i] == handles) {
  2135. dojo.forEach(handles, dojo.disconnect);
  2136. this._connects.splice(i, 1);
  2137. return;
  2138. }
  2139. }
  2140. },
  2141. isLeftToRight : function() {
  2142. // summary:
  2143. // Checks the DOM to for the text direction for bi-directional
  2144. // support
  2145. // description:
  2146. // This method cannot be used during widget construction because the
  2147. // widget
  2148. // must first be connected to the DOM tree. Parent nodes are
  2149. // searched for the
  2150. // 'dir' attribute until one is found, otherwise left to right mode
  2151. // is assumed.
  2152. // See HTML spec, DIR attribute for more information.
  2153. if (typeof this._ltr == "undefined") {
  2154. this._ltr = dojo.getComputedStyle(this.domNode).direction != "rtl";
  2155. }
  2156. return this._ltr; // Boolean
  2157. },
  2158. isFocusable : function() {
  2159. // summary:
  2160. // Return true if this widget can currently be focused
  2161. // and false if not
  2162. return this.focus
  2163. && (dojo.style(this.domNode, "display") != "none");
  2164. }
  2165. });
  2166. }
  2167. if (!dojo._hasResource["dojo.string"]) { // _hasResource checks added by
  2168. // build. Do not use _hasResource
  2169. // directly in your code.
  2170. dojo._hasResource["dojo.string"] = true;
  2171. dojo.provide("dojo.string");
  2172. dojo.string.pad = function(/* String */text, /* int */size, /* String? */ch, /* boolean? */
  2173. end) {
  2174. // summary:
  2175. // Pad a string to guarantee that it is at least 'size' length by
  2176. // filling with the character 'c' at either the start or end of the
  2177. // string. Pads at the start, by default.
  2178. // text: the string to pad
  2179. // size: length to provide padding
  2180. // ch: character to pad, defaults to '0'
  2181. // end: adds padding at the end if true, otherwise pads at start
  2182. var out = String(text);
  2183. if (!ch) {
  2184. ch = '0';
  2185. }
  2186. while (out.length < size) {
  2187. if (end) {
  2188. out += ch;
  2189. } else {
  2190. out = ch + out;
  2191. }
  2192. }
  2193. return out; // String
  2194. };
  2195. dojo.string.substitute = function( /* String */template,
  2196. /* Object or Array */map,
  2197. /* Function? */transform,
  2198. /* Object? */thisObject) {
  2199. // summary:
  2200. // Performs parameterized substitutions on a string. Throws an
  2201. // exception if any parameter is unmatched.
  2202. // description:
  2203. // For example,
  2204. // | dojo.string.substitute("File '${0}' is not found in directory
  2205. // '${1}'.",["foo.html","/temp"]);
  2206. // | dojo.string.substitute("File '${name}' is not found in directory
  2207. // '${info.dir}'.",{name: "foo.html", info: {dir: "/temp"}});
  2208. // both return
  2209. // "File 'foo.html' is not found in directory '/temp'."
  2210. // template:
  2211. // a string with expressions in the form ${key} to be replaced or
  2212. // ${key:format} which specifies a format function. NOTE syntax has
  2213. // changed from %{key}
  2214. // map: where to look for substitutions
  2215. // transform:
  2216. // a function to process all parameters before substitution takes
  2217. // place, e.g. dojo.string.encodeXML
  2218. // thisObject:
  2219. // where to look for optional format function; default to the global
  2220. // namespace
  2221. return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,
  2222. function(match, key, format) {
  2223. var value = dojo.getObject(key, false, map);
  2224. if (format) {
  2225. value = dojo.getObject(format, false, thisObject)(value);
  2226. }
  2227. if (transform) {
  2228. value = transform(value, key);
  2229. }
  2230. return value.toString();
  2231. }); // string
  2232. };
  2233. dojo.string.trim = function(/* String */str) {
  2234. // summary: trims whitespaces from both sides of the string
  2235. // description:
  2236. // This version of trim() was taken from Steven Levithan's blog:
  2237. // http://blog.stevenlevithan.com/archives/faster-trim-javascript.
  2238. // The short yet good-performing version of this function is
  2239. // dojo.trim(), which is part of the base.
  2240. str = str.replace(/^\s+/, '');
  2241. for (var i = str.length - 1; i > 0; i--) {
  2242. if (/\S/.test(str.charAt(i))) {
  2243. str = str.substring(0, i + 1);
  2244. break;
  2245. }
  2246. }
  2247. return str; // String
  2248. };
  2249. }
  2250. if (!dojo._hasResource["dijit._Templated"]) { // _hasResource checks added by
  2251. // build. Do not use
  2252. // _hasResource directly in your
  2253. // code.
  2254. dojo._hasResource["dijit._Templated"] = true;
  2255. dojo.provide("dijit._Templated");
  2256. dojo.declare("dijit._Templated", null, {
  2257. // summary:
  2258. // mixin for widgets that are instantiated from a template
  2259. // templateNode: DomNode
  2260. // a node that represents the widget template. Pre-empts both
  2261. // templateString and templatePath.
  2262. templateNode : null,
  2263. // templateString String:
  2264. // a string that represents the widget template. Pre-empts the
  2265. // templatePath. In builds that have their strings "interned", the
  2266. // templatePath is converted to an inline templateString, thereby
  2267. // preventing a synchronous network call.
  2268. templateString : null,
  2269. // templatePath: String
  2270. // Path to template (HTML file) for this widget
  2271. templatePath : null,
  2272. // widgetsInTemplate Boolean:
  2273. // should we parse the template to find widgets that might be
  2274. // declared in markup inside it? false by default.
  2275. widgetsInTemplate : false,
  2276. // containerNode DomNode:
  2277. // holds child elements. "containerNode" is generally set via a
  2278. // dojoAttachPoint assignment and it designates where children of
  2279. // the src dom node will be placed
  2280. containerNode : null,
  2281. // skipNodeCache Boolean:
  2282. // if using a cached widget template node poses issues for a
  2283. // particular widget class, it can set this property to ensure
  2284. // that its template is always re-built from a string
  2285. _skipNodeCache : false,
  2286. // method over-ride
  2287. buildRendering : function() {
  2288. // summary:
  2289. // Construct the UI for this widget from a template, setting
  2290. // this.domNode.
  2291. // Lookup cached version of template, and download to cache if it
  2292. // isn't there already. Returns either a DomNode or a string,
  2293. // depending on
  2294. // whether or not the template contains ${foo} replacement
  2295. // parameters.
  2296. var cached = dijit._Templated.getCachedTemplate(this.templatePath,
  2297. this.templateString, this._skipNodeCache);
  2298. var node;
  2299. if (dojo.isString(cached)) {
  2300. var className = this.declaredClass, _this = this;
  2301. // Cache contains a string because we need to do property
  2302. // replacement
  2303. // do the property replacement
  2304. var tstr = dojo.string.substitute(cached, this, function(value,
  2305. key) {
  2306. if (key.charAt(0) == '!') {
  2307. value = _this[key.substr(1)];
  2308. }
  2309. if (typeof value == "undefined") {
  2310. throw new Error(className + " template:" + key);
  2311. } // a debugging aide
  2312. if (!value) {
  2313. return "";
  2314. }
  2315. // Substitution keys beginning with ! will skip the
  2316. // transform step,
  2317. // in case a user wishes to insert unescaped markup,
  2318. // e.g. ${!foo}
  2319. return key.charAt(0) == "!" ? value :
  2320. // Safer substitution, see heading
  2321. // "Attribute values" in
  2322. // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
  2323. value.toString().replace(/"/g, "&quot;"); // TODO:
  2324. // add
  2325. // &amp?
  2326. // use
  2327. // encodeXML
  2328. // method?
  2329. }, this);
  2330. node = dijit._Templated._createNodesFromText(tstr)[0];
  2331. } else {
  2332. // if it's a node, all we have to do is clone it
  2333. node = cached.cloneNode(true);
  2334. }
  2335. // recurse through the node, looking for, and attaching to, our
  2336. // attachment points which should be defined on the template node.
  2337. this._attachTemplateNodes(node);
  2338. var source = this.srcNodeRef;
  2339. if (source && source.parentNode) {
  2340. source.parentNode.replaceChild(node, source);
  2341. }
  2342. this.domNode = node;
  2343. if (this.widgetsInTemplate) {
  2344. var childWidgets = dojo.parser.parse(node);
  2345. this._attachTemplateNodes(childWidgets, function(n, p) {
  2346. return n[p];
  2347. });
  2348. }
  2349. this._fillContent(source);
  2350. },
  2351. _fillContent : function(/* DomNode */source) {
  2352. // summary:
  2353. // relocate source contents to templated container node
  2354. // this.containerNode must be able to receive children, or
  2355. // exceptions will be thrown
  2356. var dest = this.containerNode;
  2357. if (source && dest) {
  2358. while (source.hasChildNodes()) {
  2359. dest.appendChild(source.firstChild);
  2360. }
  2361. }
  2362. },
  2363. _attachTemplateNodes : function(rootNode, getAttrFunc) {
  2364. // summary:
  2365. // map widget properties and functions to the handlers specified in
  2366. // the dom node and it's descendants. This function iterates over
  2367. // all
  2368. // nodes and looks for these properties:
  2369. // * dojoAttachPoint
  2370. // * dojoAttachEvent
  2371. // * waiRole
  2372. // * waiState
  2373. // rootNode: DomNode|Array[Widgets]
  2374. // the node to search for properties. All children will be searched.
  2375. // getAttrFunc: function?
  2376. // a function which will be used to obtain property for a given
  2377. // DomNode/Widget
  2378. getAttrFunc = getAttrFunc || function(n, p) {
  2379. return n.getAttribute(p);
  2380. };
  2381. var nodes = dojo.isArray(rootNode)
  2382. ? rootNode
  2383. : (rootNode.all || rootNode.getElementsByTagName("*"));
  2384. var x = dojo.isArray(rootNode) ? 0 : -1;
  2385. for (; x < nodes.length; x++) {
  2386. var baseNode = (x == -1) ? rootNode : nodes[x];
  2387. if (this.widgetsInTemplate && getAttrFunc(baseNode, 'dojoType')) {
  2388. continue;
  2389. }
  2390. // Process dojoAttachPoint
  2391. var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint");
  2392. if (attachPoint) {
  2393. var point, points = attachPoint.split(/\s*,\s*/);
  2394. while (point = points.shift()) {
  2395. if (dojo.isArray(this[point])) {
  2396. this[point].push(baseNode);
  2397. } else {
  2398. this[point] = baseNode;
  2399. }
  2400. }
  2401. }
  2402. // Process dojoAttachEvent
  2403. var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent");
  2404. if (attachEvent) {
  2405. // NOTE: we want to support attributes that have the form
  2406. // "domEvent: nativeEvent; ..."
  2407. var event, events = attachEvent.split(/\s*,\s*/);
  2408. var trim = dojo.trim;
  2409. while (event = events.shift()) {
  2410. if (event) {
  2411. var thisFunc = null;
  2412. if (event.indexOf(":") != -1) {
  2413. // oh, if only JS had tuple assignment
  2414. var funcNameArr = event.split(":");
  2415. event = trim(funcNameArr[0]);
  2416. thisFunc = trim(funcNameArr[1]);
  2417. } else {
  2418. event = trim(event);
  2419. }
  2420. if (!thisFunc) {
  2421. thisFunc = event;
  2422. }
  2423. this.connect(baseNode, event, thisFunc);
  2424. }
  2425. }
  2426. }
  2427. // waiRole, waiState
  2428. var role = getAttrFunc(baseNode, "waiRole");
  2429. if (role) {
  2430. dijit.setWaiRole(baseNode, role);
  2431. }
  2432. var values = getAttrFunc(baseNode, "waiState");
  2433. if (values) {
  2434. dojo.forEach(values.split(/\s*,\s*/), function(stateValue) {
  2435. if (stateValue.indexOf('-') != -1) {
  2436. var pair = stateValue.split('-');
  2437. dijit.setWaiState(baseNode, pair[0],
  2438. pair[1]);
  2439. }
  2440. });
  2441. }
  2442. }
  2443. }
  2444. });
  2445. // key is either templatePath or templateString; object is either string or
  2446. // DOM tree
  2447. dijit._Templated._templateCache = {};
  2448. dijit._Templated.getCachedTemplate = function(templatePath, templateString,
  2449. alwaysUseString) {
  2450. // summary:
  2451. // static method to get a template based on the templatePath or
  2452. // templateString key
  2453. // templatePath: String
  2454. // the URL to get the template from. dojo.uri.Uri is often passed as
  2455. // well.
  2456. // templateString: String?
  2457. // a string to use in lieu of fetching the template from a URL
  2458. // Returns:
  2459. // Either string (if there are ${} variables that need to be replaced)
  2460. // or just
  2461. // a DOM tree (if the node can be cloned directly)
  2462. // is it already cached?
  2463. var tmplts = dijit._Templated._templateCache;
  2464. var key = templateString || templatePath;
  2465. var cached = tmplts[key];
  2466. if (cached) {
  2467. return cached;
  2468. }
  2469. // If necessary, load template string from template path
  2470. if (!templateString) {
  2471. templateString = dijit._Templated._sanitizeTemplateString(dojo
  2472. ._getText(templatePath));
  2473. }
  2474. templateString = dojo.string.trim(templateString);
  2475. if (templateString.match(/\$\{([^\}]+)\}/g) || alwaysUseString) {
  2476. // there are variables in the template so all we can do is cache the
  2477. // string
  2478. return (tmplts[key] = templateString); // String
  2479. } else {
  2480. // there are no variables in the template so we can cache the DOM
  2481. // tree
  2482. return (tmplts[key] = dijit._Templated
  2483. ._createNodesFromText(templateString)[0]); // Node
  2484. }
  2485. };
  2486. dijit._Templated._sanitizeTemplateString = function(/* String */tString) {
  2487. // summary:
  2488. // Strips <?xml ...?> declarations so that external SVG and XML
  2489. // documents can be added to a document without worry. Also, if the
  2490. // string
  2491. // is an HTML document, only the part inside the body tag is returned.
  2492. if (tString) {
  2493. tString = tString.replace(
  2494. /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,
  2495. "");
  2496. var matches = tString.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
  2497. if (matches) {
  2498. tString = matches[1];
  2499. }
  2500. } else {
  2501. tString = "";
  2502. }
  2503. return tString; // String
  2504. };
  2505. if (dojo.isIE) {
  2506. dojo.addOnUnload(function() {
  2507. var cache = dijit._Templated._templateCache;
  2508. for (var key in cache) {
  2509. var value = cache[key];
  2510. if (!isNaN(value.nodeType)) { // isNode equivalent
  2511. dojo._destroyElement(value);
  2512. }
  2513. delete cache[key];
  2514. }
  2515. });
  2516. }
  2517. (function() {
  2518. var tagMap = {
  2519. cell : {
  2520. re : /^<t[dh][\s\r\n>]/i,
  2521. pre : "<table><tbody><tr>",
  2522. post : "</tr></tbody></table>"
  2523. },
  2524. row : {
  2525. re : /^<tr[\s\r\n>]/i,
  2526. pre : "<table><tbody>",
  2527. post : "</tbody></table>"
  2528. },
  2529. section : {
  2530. re : /^<(thead|tbody|tfoot)[\s\r\n>]/i,
  2531. pre : "<table>",
  2532. post : "</table>"
  2533. }
  2534. };
  2535. // dummy container node used temporarily to hold nodes being created
  2536. var tn;
  2537. dijit._Templated._createNodesFromText = function(/* String */text) {
  2538. // summary:
  2539. // Attempts to create a set of nodes based on the structure of the
  2540. // passed text.
  2541. if (!tn) {
  2542. tn = dojo.doc.createElement("div");
  2543. tn.style.display = "none";
  2544. dojo.body().appendChild(tn);
  2545. }
  2546. var tableType = "none";
  2547. var rtext = text.replace(/^\s+/, "");
  2548. for (var type in tagMap) {
  2549. var map = tagMap[type];
  2550. if (map.re.test(rtext)) {
  2551. tableType = type;
  2552. text = map.pre + text + map.post;
  2553. break;
  2554. }
  2555. }
  2556. tn.innerHTML = text;
  2557. if (tn.normalize) {
  2558. tn.normalize();
  2559. }
  2560. var tag = {
  2561. cell : "tr",
  2562. row : "tbody",
  2563. section : "table"
  2564. }[tableType];
  2565. var _parent = (typeof tag != "undefined") ? tn
  2566. .getElementsByTagName(tag)[0] : tn;
  2567. var nodes = [];
  2568. while (_parent.firstChild) {
  2569. nodes.push(_parent.removeChild(_parent.firstChild));
  2570. }
  2571. tn.innerHTML = "";
  2572. return nodes; // Array
  2573. }
  2574. })();
  2575. // These arguments can be specified for widgets which are used in templates.
  2576. // Since any widget can be specified as sub widgets in template, mix it
  2577. // into the base widget class. (This is a hack, but it's effective.)
  2578. dojo.extend(dijit._Widget, {
  2579. dojoAttachEvent : "",
  2580. dojoAttachPoint : "",
  2581. waiRole : "",
  2582. waiState : ""
  2583. })
  2584. }
  2585. if (!dojo._hasResource["dijit._Container"]) { // _hasResource checks added by
  2586. // build. Do not use
  2587. // _hasResource directly in your
  2588. // code.
  2589. dojo._hasResource["dijit._Container"] = true;
  2590. dojo.provide("dijit._Container");
  2591. dojo.declare("dijit._Contained", null, {
  2592. // summary
  2593. // Mixin for widgets that are children of a container widget
  2594. getParent : function() {
  2595. // summary:
  2596. // returns the parent widget of this widget, assuming the
  2597. // parent
  2598. // implements dijit._Container
  2599. for (var p = this.domNode.parentNode; p; p = p.parentNode) {
  2600. var id = p.getAttribute && p.getAttribute("widgetId");
  2601. if (id) {
  2602. var parent = dijit.byId(id);
  2603. return parent.isContainer ? parent : null;
  2604. }
  2605. }
  2606. return null;
  2607. },
  2608. _getSibling : function(which) {
  2609. var node = this.domNode;
  2610. do {
  2611. node = node[which + "Sibling"];
  2612. } while (node && node.nodeType != 1);
  2613. if (!node) {
  2614. return null;
  2615. } // null
  2616. var id = node.getAttribute("widgetId");
  2617. return dijit.byId(id);
  2618. },
  2619. getPreviousSibling : function() {
  2620. // summary:
  2621. // returns null if this is the first child of the parent,
  2622. // otherwise returns the next element sibling to the "left".
  2623. return this._getSibling("previous");
  2624. },
  2625. getNextSibling : function() {
  2626. // summary:
  2627. // returns null if this is the last child of the parent,
  2628. // otherwise returns the next element sibling to the
  2629. // "right".
  2630. return this._getSibling("next");
  2631. }
  2632. });
  2633. dojo.declare("dijit._Container", null, {
  2634. // summary
  2635. // Mixin for widgets that contain a list of children like
  2636. // SplitContainer
  2637. isContainer : true,
  2638. addChild : function(/* Widget */widget, /* int? */insertIndex) {
  2639. // summary:
  2640. // Process the given child widget, inserting it's dom node
  2641. // as
  2642. // a child of our dom node
  2643. if (insertIndex === undefined) {
  2644. insertIndex = "last";
  2645. }
  2646. var refNode = this.containerNode || this.domNode;
  2647. if (insertIndex && typeof insertIndex == "number") {
  2648. var children = dojo.query("> [widgetid]", refNode);
  2649. if (children && children.length >= insertIndex) {
  2650. refNode = children[insertIndex - 1];
  2651. insertIndex = "after";
  2652. }
  2653. }
  2654. dojo.place(widget.domNode, refNode, insertIndex);
  2655. // If I've been started but the child widget hasn't been
  2656. // started,
  2657. // start it now. Make sure to do this after widget has been
  2658. // inserted into the DOM tree, so it can see that it's being
  2659. // controlled by me,
  2660. // so it doesn't try to size itself.
  2661. if (this._started && !widget._started) {
  2662. widget.startup();
  2663. }
  2664. },
  2665. removeChild : function(/* Widget */widget) {
  2666. // summary:
  2667. // removes the passed widget instance from this widget but
  2668. // does
  2669. // not destroy it
  2670. var node = widget.domNode;
  2671. node.parentNode.removeChild(node); // detach but don't
  2672. // destroy
  2673. },
  2674. _nextElement : function(node) {
  2675. do {
  2676. node = node.nextSibling;
  2677. } while (node && node.nodeType != 1);
  2678. return node;
  2679. },
  2680. _firstElement : function(node) {
  2681. node = node.firstChild;
  2682. if (node && node.nodeType != 1) {
  2683. node = this._nextElement(node);
  2684. }
  2685. return node;
  2686. },
  2687. getChildren : function() {
  2688. // summary:
  2689. // Returns array of children widgets
  2690. return dojo.query("> [widgetId]",
  2691. this.containerNode || this.domNode)
  2692. .map(dijit.byNode); // Array
  2693. },
  2694. hasChildren : function() {
  2695. // summary:
  2696. // Returns true if widget has children
  2697. var cn = this.containerNode || this.domNode;
  2698. return !!this._firstElement(cn); // Boolean
  2699. },
  2700. _getSiblingOfChild : function(/* Widget */child, /* int */dir) {
  2701. // summary:
  2702. // get the next or previous widget sibling of child
  2703. // dir:
  2704. // if 1, get the next sibling
  2705. // if -1, get the previous sibling
  2706. var node = child.domNode;
  2707. var which = (dir > 0 ? "nextSibling" : "previousSibling");
  2708. do {
  2709. node = node[which];
  2710. } while (node
  2711. && (node.nodeType != 1 || !dijit.byNode(node)));
  2712. return node ? dijit.byNode(node) : null;
  2713. }
  2714. });
  2715. dojo.declare("dijit._KeyNavContainer", [dijit._Container], {
  2716. // summary:
  2717. // A _Container with keyboard navigation of its children.
  2718. // To use this mixin, call connectKeyNavHandlers() in
  2719. // postCreate() and call startupKeyNavChildren() in startup().
  2720. /*
  2721. * ===== // focusedChild: Widget // The currently focused child
  2722. * widget, or null if there isn't one focusedChild: null, =====
  2723. */
  2724. _keyNavCodes : {},
  2725. connectKeyNavHandlers : function(/* Array */prevKeyCodes, /* Array */
  2726. nextKeyCodes) {
  2727. // summary:
  2728. // Call in postCreate() to attach the keyboard handlers
  2729. // to the container.
  2730. // preKeyCodes: Array
  2731. // Key codes for navigating to the previous child.
  2732. // nextKeyCodes: Array
  2733. // Key codes for navigating to the next child.
  2734. var keyCodes = this._keyNavCodes = {};
  2735. var prev = dojo.hitch(this, this.focusPrev);
  2736. var next = dojo.hitch(this, this.focusNext);
  2737. dojo.forEach(prevKeyCodes, function(code) {
  2738. keyCodes[code] = prev
  2739. });
  2740. dojo.forEach(nextKeyCodes, function(code) {
  2741. keyCodes[code] = next
  2742. });
  2743. this.connect(this.domNode, "onkeypress",
  2744. "_onContainerKeypress");
  2745. if (dojo.isIE) {
  2746. this.connect(this.domNode, "onactivate",
  2747. "_onContainerFocus");
  2748. this.connect(this.domNode, "ondeactivate",
  2749. "_onContainerBlur");
  2750. } else {
  2751. this.connect(this.domNode, "onfocus",
  2752. "_onContainerFocus");
  2753. this
  2754. .connect(this.domNode, "onblur",
  2755. "_onContainerBlur");
  2756. }
  2757. },
  2758. startupKeyNavChildren : function() {
  2759. // summary:
  2760. // Call in startup() to set child tabindexes to -1
  2761. dojo.forEach(this.getChildren(), dojo.hitch(this,
  2762. "_setTabIndexMinusOne"));
  2763. },
  2764. addChild : function(/* Widget */widget, /* int? */insertIndex) {
  2765. // summary: Add a child to our _Container
  2766. dijit._KeyNavContainer.superclass.addChild.apply(this,
  2767. arguments);
  2768. this._setTabIndexMinusOne(widget);
  2769. },
  2770. focus : function() {
  2771. // summary: Default focus() implementation: focus the first
  2772. // child.
  2773. this.focusFirstChild();
  2774. },
  2775. focusFirstChild : function() {
  2776. // summary: Focus the first focusable child in the
  2777. // container.
  2778. this.focusChild(this._getFirstFocusableChild());
  2779. },
  2780. focusNext : function() {
  2781. // summary: Focus the next widget or focal node (for widgets
  2782. // with multiple focal nodes) within this container.
  2783. if (this.focusedChild && this.focusedChild.hasNextFocalNode
  2784. && this.focusedChild.hasNextFocalNode()) {
  2785. this.focusedChild.focusNext();
  2786. return;
  2787. }
  2788. var child = this._getNextFocusableChild(this.focusedChild,
  2789. 1);
  2790. if (child.getFocalNodes) {
  2791. this.focusChild(child, child.getFocalNodes()[0]);
  2792. } else {
  2793. this.focusChild(child);
  2794. }
  2795. },
  2796. focusPrev : function() {
  2797. // summary: Focus the previous widget or focal node (for
  2798. // widgets
  2799. // with multiple focal nodes) within this container.
  2800. if (this.focusedChild && this.focusedChild.hasPrevFocalNode
  2801. && this.focusedChild.hasPrevFocalNode()) {
  2802. this.focusedChild.focusPrev();
  2803. return;
  2804. }
  2805. var child = this._getNextFocusableChild(this.focusedChild,
  2806. -1);
  2807. if (child.getFocalNodes) {
  2808. var nodes = child.getFocalNodes();
  2809. this.focusChild(child, nodes[nodes.length - 1]);
  2810. } else {
  2811. this.focusChild(child);
  2812. }
  2813. },
  2814. focusChild : function(/* Widget */widget, /* Node? */node) {
  2815. // summary: Focus widget. Optionally focus 'node' within
  2816. // widget.
  2817. if (widget) {
  2818. if (this.focusedChild && widget !== this.focusedChild) {
  2819. this._onChildBlur(this.focusedChild);
  2820. }
  2821. this.focusedChild = widget;
  2822. if (node && widget.focusFocalNode) {
  2823. widget.focusFocalNode(node);
  2824. } else {
  2825. widget.focus();
  2826. }
  2827. }
  2828. },
  2829. _setTabIndexMinusOne : function(/* Widget */widget) {
  2830. if (widget.getFocalNodes) {
  2831. dojo.forEach(widget.getFocalNodes(), function(node) {
  2832. node.setAttribute("tabIndex", -1);
  2833. });
  2834. } else {
  2835. (widget.focusNode || widget.domNode).setAttribute(
  2836. "tabIndex", -1);
  2837. }
  2838. },
  2839. _onContainerFocus : function(evt) {
  2840. this.domNode.setAttribute("tabIndex", -1);
  2841. if (evt.target === this.domNode) {
  2842. this.focusFirstChild();
  2843. } else {
  2844. var widget = dijit.getEnclosingWidget(evt.target);
  2845. if (widget && widget.isFocusable()) {
  2846. this.focusedChild = widget;
  2847. }
  2848. }
  2849. },
  2850. _onContainerBlur : function(evt) {
  2851. if (this.tabIndex) {
  2852. this.domNode.setAttribute("tabIndex", this.tabIndex);
  2853. }
  2854. },
  2855. _onContainerKeypress : function(evt) {
  2856. if (evt.ctrlKey || evt.altKey) {
  2857. return;
  2858. }
  2859. var func = this._keyNavCodes[evt.keyCode];
  2860. if (func) {
  2861. func();
  2862. dojo.stopEvent(evt);
  2863. }
  2864. },
  2865. _onChildBlur : function(/* Widget */widget) {
  2866. // summary:
  2867. // Called when focus leaves a child widget to go
  2868. // to a sibling widget.
  2869. },
  2870. _getFirstFocusableChild : function() {
  2871. return this._getNextFocusableChild(null, 1);
  2872. },
  2873. _getNextFocusableChild : function(child, dir) {
  2874. if (child) {
  2875. child = this._getSiblingOfChild(child, dir);
  2876. }
  2877. var children = this.getChildren();
  2878. for (var i = 0; i < children.length; i++) {
  2879. if (!child) {
  2880. child = children[(dir > 0)
  2881. ? 0
  2882. : (children.length - 1)];
  2883. }
  2884. if (child.isFocusable()) {
  2885. return child;
  2886. }
  2887. child = this._getSiblingOfChild(child, dir);
  2888. }
  2889. }
  2890. });
  2891. }
  2892. if (!dojo._hasResource["dijit.layout._LayoutWidget"]) { // _hasResource checks
  2893. // added by build. Do
  2894. // not use _hasResource
  2895. // directly in your
  2896. // code.
  2897. dojo._hasResource["dijit.layout._LayoutWidget"] = true;
  2898. dojo.provide("dijit.layout._LayoutWidget");
  2899. dojo.declare("dijit.layout._LayoutWidget", [dijit._Widget,
  2900. dijit._Container, dijit._Contained], {
  2901. // summary
  2902. // Mixin for widgets that contain a list of children like
  2903. // SplitContainer.
  2904. // Widgets which mixin this code must define layout() to lay out
  2905. // the children
  2906. isLayoutContainer : true,
  2907. postCreate : function() {
  2908. dojo.addClass(this.domNode, "dijitContainer");
  2909. },
  2910. startup : function() {
  2911. // summary:
  2912. // Called after all the widgets have been instantiated and
  2913. // their
  2914. // dom nodes have been inserted somewhere under
  2915. // document.body.
  2916. //
  2917. // Widgets should override this method to do any
  2918. // initialization
  2919. // dependent on other widgets existing, and then call
  2920. // this superclass method to finish things off.
  2921. //
  2922. // startup() in subclasses shouldn't do anything
  2923. // size related because the size of the widget hasn't been
  2924. // set yet.
  2925. if (this._started) {
  2926. return;
  2927. }
  2928. this._started = true;
  2929. if (this.getChildren) {
  2930. dojo.forEach(this.getChildren(), function(child) {
  2931. child.startup();
  2932. });
  2933. }
  2934. // If I am a top level widget
  2935. if (!this.getParent || !this.getParent()) {
  2936. // Do recursive sizing and layout of all my descendants
  2937. // (passing in no argument to resize means that it has
  2938. // to glean the size itself)
  2939. this.resize();
  2940. // since my parent isn't a layout container, and my
  2941. // style is width=height=100% (or something similar),
  2942. // then I need to watch when the window resizes, and
  2943. // size myself accordingly
  2944. // (passing in no argument to resize means that it has
  2945. // to glean the size itself)
  2946. this.connect(window, 'onresize', function() {
  2947. this.resize();
  2948. });
  2949. }
  2950. },
  2951. resize : function(args) {
  2952. // summary:
  2953. // Explicitly set this widget's size (in pixels),
  2954. // and then call layout() to resize contents (and maybe
  2955. // adjust child widgets)
  2956. //
  2957. // args: Object?
  2958. // {w: int, h: int, l: int, t: int}
  2959. var node = this.domNode;
  2960. // set margin box size, unless it wasn't specified, in which
  2961. // case use current size
  2962. if (args) {
  2963. dojo.marginBox(node, args);
  2964. // set offset of the node
  2965. if (args.t) {
  2966. node.style.top = args.t + "px";
  2967. }
  2968. if (args.l) {
  2969. node.style.left = args.l + "px";
  2970. }
  2971. }
  2972. // If either height or width wasn't specified by the user,
  2973. // then query node for it.
  2974. // But note that setting the margin box and then immediately
  2975. // querying dimensions may return
  2976. // inaccurate results, so try not to depend on it.
  2977. var mb = dojo.mixin(dojo.marginBox(node), args || {});
  2978. // Save the size of my content box.
  2979. this._contentBox = dijit.layout.marginBox2contentBox(node,
  2980. mb);
  2981. // Callback for widget to adjust size of it's children
  2982. this.layout();
  2983. },
  2984. layout : function() {
  2985. // summary
  2986. // Widgets override this method to size & position their
  2987. // contents/children.
  2988. // When this is called this._contentBox is guaranteed to be
  2989. // set (see resize()).
  2990. //
  2991. // This is called after startup(), and also when the
  2992. // widget's size has been
  2993. // changed.
  2994. }
  2995. });
  2996. dijit.layout.marginBox2contentBox = function(/* DomNode */node, /* Object */
  2997. mb) {
  2998. // summary:
  2999. // Given the margin-box size of a node, return it's content box size.
  3000. // Functions like dojo.contentBox() but is more reliable since it
  3001. // doesn't have
  3002. // to wait for the browser to compute sizes.
  3003. var cs = dojo.getComputedStyle(node);
  3004. var me = dojo._getMarginExtents(node, cs);
  3005. var pb = dojo._getPadBorderExtents(node, cs);
  3006. return {
  3007. l : dojo._toPixelValue(node, cs.paddingLeft),
  3008. t : dojo._toPixelValue(node, cs.paddingTop),
  3009. w : mb.w - (me.w + pb.w),
  3010. h : mb.h - (me.h + pb.h)
  3011. };
  3012. };
  3013. (function() {
  3014. var capitalize = function(word) {
  3015. return word.substring(0, 1).toUpperCase() + word.substring(1);
  3016. };
  3017. var size = function(widget, dim) {
  3018. // size the child
  3019. widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode,
  3020. dim);
  3021. // record child's size, but favor our own numbers when we have them.
  3022. // the browser lies sometimes
  3023. dojo.mixin(widget, dojo.marginBox(widget.domNode));
  3024. dojo.mixin(widget, dim);
  3025. };
  3026. dijit.layout.layoutChildren = function(/* DomNode */container, /* Object */
  3027. dim, /* Object[] */children) {
  3028. /**
  3029. * summary Layout a bunch of child dom nodes within a parent dom
  3030. * node container: parent node dim: {l, t, w, h} object specifying
  3031. * dimensions of container into which to place children children: an
  3032. * array like [ {domNode: foo, layoutAlign: "bottom" }, {domNode:
  3033. * bar, layoutAlign: "client"} ]
  3034. */
  3035. // copy dim because we are going to modify it
  3036. dim = dojo.mixin({}, dim);
  3037. dojo.addClass(container, "dijitLayoutContainer");
  3038. // Move "client" elements to the end of the array for layout. a11y
  3039. // dictates that the author
  3040. // needs to be able to put them in the document in tab-order, but
  3041. // this algorithm requires that
  3042. // client be last.
  3043. children = dojo.filter(children, function(item) {
  3044. return item.layoutAlign != "client";
  3045. }).concat(dojo.filter(children, function(item) {
  3046. return item.layoutAlign == "client";
  3047. }));
  3048. // set positions/sizes
  3049. dojo.forEach(children, function(child) {
  3050. var elm = child.domNode, pos = child.layoutAlign;
  3051. // set elem to upper left corner of unused space; may
  3052. // move it later
  3053. var elmStyle = elm.style;
  3054. elmStyle.left = dim.l + "px";
  3055. elmStyle.top = dim.t + "px";
  3056. elmStyle.bottom = elmStyle.right = "auto";
  3057. dojo.addClass(elm, "dijitAlign" + capitalize(pos));
  3058. // set size && adjust record of remaining space.
  3059. // note that setting the width of a <div> may affect
  3060. // it's height.
  3061. if (pos == "top" || pos == "bottom") {
  3062. size(child, {
  3063. w : dim.w
  3064. });
  3065. dim.h -= child.h;
  3066. if (pos == "top") {
  3067. dim.t += child.h;
  3068. } else {
  3069. elmStyle.top = dim.t + dim.h + "px";
  3070. }
  3071. } else if (pos == "left" || pos == "right") {
  3072. size(child, {
  3073. h : dim.h
  3074. });
  3075. dim.w -= child.w;
  3076. if (pos == "left") {
  3077. dim.l += child.w;
  3078. } else {
  3079. elmStyle.left = dim.l + dim.w + "px";
  3080. }
  3081. } else if (pos == "client") {
  3082. size(child, dim);
  3083. }
  3084. });
  3085. };
  3086. })();
  3087. }
  3088. if (!dojo._hasResource["dijit.form._FormWidget"]) { // _hasResource checks added
  3089. // by build. Do not use
  3090. // _hasResource directly in
  3091. // your code.
  3092. dojo._hasResource["dijit.form._FormWidget"] = true;
  3093. dojo.provide("dijit.form._FormWidget");
  3094. dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated], {
  3095. /*
  3096. * Summary: FormElement widgets correspond to native HTML elements such
  3097. * as <input> or <button> or <select>. Each FormElement represents a
  3098. * single input value, and has a (possibly hidden) <input> element, to
  3099. * which it serializes its input value, so that form submission (either
  3100. * normal submission or via FormBind?) works as expected.
  3101. *
  3102. * All these widgets should have these attributes just like native HTML
  3103. * input elements. You can set them during widget construction, but
  3104. * after that they are read only.
  3105. *
  3106. * They also share some common methods.
  3107. */
  3108. // baseClass: String
  3109. // Root CSS class of the widget (ex: dijitTextBox), used to add CSS
  3110. // classes of widget
  3111. // (ex: "dijitTextBox dijitTextBoxInvalid dijitTextBoxFocused
  3112. // dijitTextBoxInvalidFocused")
  3113. // See _setStateClass().
  3114. baseClass : "",
  3115. // value: String
  3116. // Corresponds to the native HTML <input> element's attribute.
  3117. value : "",
  3118. // name: String
  3119. // Name used when submitting form; same as "name" attribute or plain
  3120. // HTML elements
  3121. name : "",
  3122. // id: String
  3123. // Corresponds to the native HTML <input> element's attribute.
  3124. // Also becomes the id for the widget.
  3125. id : "",
  3126. // alt: String
  3127. // Corresponds to the native HTML <input> element's attribute.
  3128. alt : "",
  3129. // type: String
  3130. // Corresponds to the native HTML <input> element's attribute.
  3131. type : "text",
  3132. // tabIndex: Integer
  3133. // Order fields are traversed when user hits the tab key
  3134. tabIndex : "0",
  3135. // disabled: Boolean
  3136. // Should this widget respond to user input?
  3137. // In markup, this is specified as "disabled='disabled'", or just
  3138. // "disabled".
  3139. disabled : false,
  3140. // intermediateChanges: Boolean
  3141. // Fires onChange for each value change or only on demand
  3142. intermediateChanges : false,
  3143. // These mixins assume that the focus node is an INPUT, as many but not
  3144. // all _FormWidgets are.
  3145. // Don't attempt to mixin the 'type', 'name' attributes here
  3146. // programatically -- they must be declared
  3147. // directly in the template as read by the parser in order to function.
  3148. // IE is known to specifically
  3149. // require the 'name' attribute at element creation time.
  3150. attributeMap : dojo.mixin(dojo
  3151. .clone(dijit._Widget.prototype.attributeMap), {
  3152. id : "focusNode",
  3153. tabIndex : "focusNode",
  3154. alt : "focusNode"
  3155. }),
  3156. setDisabled : function(/* Boolean */disabled) {
  3157. // summary:
  3158. // Set disabled state of widget.
  3159. this.domNode.disabled = this.disabled = disabled;
  3160. if (this.focusNode) {
  3161. this.focusNode.disabled = disabled;
  3162. }
  3163. if (disabled) {
  3164. // reset those, because after the domNode is disabled, we can no
  3165. // longer receive
  3166. // mouse related events, see #4200
  3167. this._hovering = false;
  3168. this._active = false;
  3169. }
  3170. dijit.setWaiState(this.focusNode || this.domNode, "disabled",
  3171. disabled);
  3172. this._setStateClass();
  3173. },
  3174. _onMouse : function(/* Event */event) {
  3175. // summary:
  3176. // Sets _hovering, _active, and stateModifier properties depending
  3177. // on mouse state,
  3178. // then calls setStateClass() to set appropriate CSS classes for
  3179. // this.domNode.
  3180. //
  3181. // To get a different CSS class for hover, send onmouseover and
  3182. // onmouseout events to this method.
  3183. // To get a different CSS class while mouse button is depressed,
  3184. // send onmousedown to this method.
  3185. var mouseNode = event.target;
  3186. if (mouseNode && mouseNode.getAttribute) {
  3187. this.stateModifier = mouseNode.getAttribute("stateModifier")
  3188. || "";
  3189. }
  3190. if (!this.disabled) {
  3191. switch (event.type) {
  3192. case "mouseenter" :
  3193. case "mouseover" :
  3194. this._hovering = true;
  3195. break;
  3196. case "mouseout" :
  3197. case "mouseleave" :
  3198. this._hovering = false;
  3199. break;
  3200. case "mousedown" :
  3201. this._active = true;
  3202. // set a global event to handle mouseup, so it fires
  3203. // properly
  3204. // even if the cursor leaves the button
  3205. var self = this;
  3206. // #2685: use this.connect and disconnect so destroy
  3207. // works properly
  3208. var mouseUpConnector = this.connect(dojo.body(),
  3209. "onmouseup", function() {
  3210. self._active = false;
  3211. self._setStateClass();
  3212. self.disconnect(mouseUpConnector);
  3213. });
  3214. break;
  3215. }
  3216. this._setStateClass();
  3217. }
  3218. },
  3219. isFocusable : function() {
  3220. return !this.disabled
  3221. && (dojo.style(this.domNode, "display") != "none");
  3222. },
  3223. focus : function() {
  3224. dijit.focus(this.focusNode);
  3225. },
  3226. _setStateClass : function() {
  3227. // summary
  3228. // Update the visual state of the widget by setting the css classes
  3229. // on this.domNode
  3230. // (or this.stateNode if defined) by combining this.baseClass with
  3231. // various suffixes that represent the current widget state(s).
  3232. //
  3233. // In the case where a widget has multiple
  3234. // states, it sets the class based on all possible
  3235. // combinations. For example, an invalid form widget that is being
  3236. // hovered
  3237. // will be "dijitInput dijitInputInvalid dijitInputHover
  3238. // dijitInputInvalidHover".
  3239. //
  3240. // For complex widgets with multiple regions, there can be various
  3241. // hover/active states,
  3242. // such as "Hover" or "CloseButtonHover" (for tab buttons).
  3243. // This is controlled by a stateModifier="CloseButton" attribute on
  3244. // the close button node.
  3245. //
  3246. // The widget may have one or more of the following states,
  3247. // determined
  3248. // by this.state, this.checked, this.valid, and this.selected:
  3249. // Error - ValidationTextBox sets this.state to "Error" if the
  3250. // current input value is invalid
  3251. // Checked - ex: a checkmark or a ToggleButton in a checked state,
  3252. // will have this.checked==true
  3253. // Selected - ex: currently selected tab will have
  3254. // this.selected==true
  3255. //
  3256. // In addition, it may have at most one of the following states,
  3257. // based on this.disabled and flags set in _onMouse (this._active,
  3258. // this._hovering, this._focused):
  3259. // Disabled - if the widget is disabled
  3260. // Active - if the mouse (or space/enter key?) is being pressed down
  3261. // Focused - if the widget has focus
  3262. // Hover - if the mouse is over the widget
  3263. //
  3264. // (even if multiple af the above conditions are true we only pick
  3265. // the first matching one)
  3266. // Get original (non state related, non baseClass related) class
  3267. // specified in template
  3268. if (!("staticClass" in this)) {
  3269. this.staticClass = (this.stateNode || this.domNode).className;
  3270. }
  3271. // Compute new set of classes
  3272. var classes = [this.baseClass];
  3273. function multiply(modifier) {
  3274. classes = classes.concat(dojo.map(classes, function(c) {
  3275. return c + modifier;
  3276. }));
  3277. }
  3278. if (this.checked) {
  3279. multiply("Checked");
  3280. }
  3281. if (this.state) {
  3282. multiply(this.state);
  3283. }
  3284. if (this.selected) {
  3285. multiply("Selected");
  3286. }
  3287. // Only one of these four can be applied.
  3288. // Active trumps Focused, Focused trumps Hover, and Disabled trumps
  3289. // all.
  3290. if (this.disabled) {
  3291. multiply("Disabled");
  3292. } else if (this._active) {
  3293. multiply(this.stateModifier + "Active");
  3294. } else {
  3295. if (this._focused) {
  3296. multiply("Focused");
  3297. }
  3298. if ((this.stateModifier || !this._focused) && this._hovering) {
  3299. multiply(this.stateModifier + "Hover");
  3300. }
  3301. }
  3302. (this.stateNode || this.domNode).className = this.staticClass + " "
  3303. + classes.join(" ");
  3304. },
  3305. onChange : function(newValue) {
  3306. // summary: callback when value is changed
  3307. },
  3308. postCreate : function() {
  3309. this.setValue(this.value, null); // null reserved for initial
  3310. // value
  3311. this.setDisabled(this.disabled);
  3312. this._setStateClass();
  3313. },
  3314. setValue : function(/* anything */newValue, /* Boolean, optional */
  3315. priorityChange) {
  3316. // summary: set the value of the widget.
  3317. this._lastValue = newValue;
  3318. dijit.setWaiState(this.focusNode || this.domNode, "valuenow", this
  3319. .forWaiValuenow());
  3320. if (priorityChange === undefined) {
  3321. priorityChange = true;
  3322. } // setValue with value only should fire onChange
  3323. if (this._lastValueReported == undefined && priorityChange === null) { // don't
  3324. // report
  3325. // the
  3326. // initial
  3327. // value
  3328. this._lastValueReported = newValue;
  3329. }
  3330. if ((this.intermediateChanges || priorityChange)
  3331. && ((newValue && newValue.toString)
  3332. ? newValue.toString()
  3333. : newValue) !== ((this._lastValueReported && this._lastValueReported.toString)
  3334. ? this._lastValueReported.toString()
  3335. : this._lastValueReported)) {
  3336. this._lastValueReported = newValue;
  3337. this.onChange(newValue);
  3338. }
  3339. },
  3340. getValue : function() {
  3341. // summary: get the value of the widget.
  3342. return this._lastValue;
  3343. },
  3344. undo : function() {
  3345. // summary: restore the value to the last value passed to onChange
  3346. this.setValue(this._lastValueReported, false);
  3347. },
  3348. _onKeyPress : function(e) {
  3349. if (e.keyCode == dojo.keys.ESCAPE && !e.shiftKey && !e.ctrlKey
  3350. && !e.altKey) {
  3351. var v = this.getValue();
  3352. var lv = this._lastValueReported;
  3353. // Equality comparison of objects such as dates are done by
  3354. // reference so
  3355. // two distinct objects are != even if they have the same data.
  3356. // So use
  3357. // toStrings in case the values are objects.
  3358. if ((typeof lv != "undefined")
  3359. && ((v !== null && v.toString) ? v.toString() : null) !== lv
  3360. .toString()) {
  3361. this.undo();
  3362. dojo.stopEvent(e);
  3363. return false;
  3364. }
  3365. }
  3366. return true;
  3367. },
  3368. forWaiValuenow : function() {
  3369. // summary: returns a value, reflecting the current state of the
  3370. // widget,
  3371. // to be used for the ARIA valuenow.
  3372. // This method may be overridden by subclasses that want
  3373. // to use something other than this.getValue() for valuenow
  3374. return this.getValue();
  3375. }
  3376. });
  3377. }
  3378. if (!dojo._hasResource["dijit.dijit"]) { // _hasResource checks added by
  3379. // build. Do not use _hasResource
  3380. // directly in your code.
  3381. dojo._hasResource["dijit.dijit"] = true;
  3382. dojo.provide("dijit.dijit");
  3383. // All the stuff in _base (these are the function that are guaranteed
  3384. // available without an explicit dojo.require)
  3385. // And some other stuff that we tend to pull in all the time anyway
  3386. }