1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784 |
- /*
- * Copyright (c) 2004-2007, The Dojo Foundation All Rights Reserved.
- *
- * Licensed under the Academic Free License version 2.1 or above OR the modified
- * BSD license. For more information on Dojo licensing, see:
- *
- * http://dojotoolkit.org/book/dojo-book-0-9/introduction/licensing
- */
- /*
- * This is a compiled version of Dojo, built for deployment and not for
- * development. To get an editable version, please visit:
- *
- * http://dojotoolkit.org
- *
- * for documentation and information on getting the source.
- */
- if (!dojo._hasResource["dijit._base.focus"]) { // _hasResource checks added by
- // build. Do not use
- // _hasResource directly in your
- // code.
- dojo._hasResource["dijit._base.focus"] = true;
- dojo.provide("dijit._base.focus");
- // summary:
- // These functions are used to query or set the focus and selection.
- //
- // Also, they trace when widgets become actived/deactivated,
- // so that the widget can fire _onFocus/_onBlur events.
- // "Active" here means something similar to "focused", but
- // "focus" isn't quite the right word because we keep track of
- // a whole stack of "active" widgets. Example: Combobutton --> Menu -->
- // MenuItem. The onBlur event for Combobutton doesn't fire due to focusing
- // on the Menu or a MenuItem, since they are considered part of the
- // Combobutton widget. It only happens when focus is shifted
- // somewhere completely different.
- dojo.mixin(dijit, {
- // _curFocus: DomNode
- // Currently focused item on screen
- _curFocus : null,
- // _prevFocus: DomNode
- // Previously focused item on screen
- _prevFocus : null,
- isCollapsed : function() {
- // summary: tests whether the current selection is empty
- var _window = dojo.global;
- var _document = dojo.doc;
- if (_document.selection) { // IE
- return !_document.selection.createRange().text; // Boolean
- } else if (_window.getSelection) {
- var selection = _window.getSelection();
- if (dojo.isString(selection)) { // Safari
- return !selection; // Boolean
- } else { // Mozilla/W3
- return selection.isCollapsed || !selection.toString(); // Boolean
- }
- }
- },
- getBookmark : function() {
- // summary: Retrieves a bookmark that can be used with
- // moveToBookmark to return to the same range
- var bookmark, selection = dojo.doc.selection;
- if (selection) { // IE
- var range = selection.createRange();
- if (selection.type.toUpperCase() == 'CONTROL') {
- bookmark = range.length ? dojo._toArray(range) : null;
- } else {
- bookmark = range.getBookmark();
- }
- } else {
- if (dojo.global.getSelection) {
- selection = dojo.global.getSelection();
- if (selection) {
- var range = selection.getRangeAt(0);
- bookmark = range.cloneRange();
- }
- } else {
- console
- .debug("No idea how to store the current selection for this browser!");
- }
- }
- return bookmark; // Array
- },
- moveToBookmark : function(/* Object */bookmark) {
- // summary: Moves current selection to a bookmark
- // bookmark: this should be a returned object from
- // dojo.html.selection.getBookmark()
- var _document = dojo.doc;
- if (_document.selection) { // IE
- var range;
- if (dojo.isArray(bookmark)) {
- range = _document.body.createControlRange();
- dojo.forEach(bookmark, range.addElement);
- } else {
- range = _document.selection.createRange();
- range.moveToBookmark(bookmark);
- }
- range.select();
- } else { // Moz/W3C
- var selection = dojo.global.getSelection
- && dojo.global.getSelection();
- if (selection && selection.removeAllRanges) {
- selection.removeAllRanges();
- selection.addRange(bookmark);
- } else {
- console
- .debug("No idea how to restore selection for this browser!");
- }
- }
- },
- getFocus : function(/* Widget */menu, /* Window */openedForWindow) {
- // summary:
- // Returns the current focus and selection.
- // Called when a popup appears (either a top level menu or a
- // dialog),
- // or when a toolbar/menubar receives focus
- //
- // menu:
- // the menu that's being opened
- //
- // openedForWindow:
- // iframe in which menu was opened
- //
- // returns:
- // a handle to restore focus/selection
- return {
- // Node to return focus to
- node : menu && dojo.isDescendant(dijit._curFocus, menu.domNode)
- ? dijit._prevFocus
- : dijit._curFocus,
- // Previously selected text
- bookmark : !dojo.withGlobal(openedForWindow || dojo.global,
- dijit.isCollapsed) ? dojo.withGlobal(openedForWindow
- || dojo.global, dijit.getBookmark) : null,
- openedForWindow : openedForWindow
- }; // Object
- },
- focus : function(/* Object || DomNode */handle) {
- // summary:
- // Sets the focused node and the selection according to argument.
- // To set focus to an iframe's content, pass in the iframe itself.
- // handle:
- // object returned by get(), or a DomNode
- if (!handle) {
- return;
- }
- var node = "node" in handle ? handle.node : handle, // because
- // handle is
- // either
- // DomNode or a
- // composite
- // object
- bookmark = handle.bookmark, openedForWindow = handle.openedForWindow;
- // Set the focus
- // Note that for iframe's we need to use the <iframe> to follow the
- // parentNode chain,
- // but we need to set focus to iframe.contentWindow
- if (node) {
- var focusNode = (node.tagName.toLowerCase() == "iframe")
- ? node.contentWindow
- : node;
- if (focusNode && focusNode.focus) {
- try {
- // Gecko throws sometimes if setting focus is
- // impossible,
- // node not displayed or something like that
- focusNode.focus();
- } catch (e) {/* quiet */
- }
- }
- dijit._onFocusNode(node);
- }
- // set the selection
- // do not need to restore if current selection is not empty
- // (use keyboard to select a menu item)
- if (bookmark
- && dojo.withGlobal(openedForWindow || dojo.global,
- dijit.isCollapsed)) {
- if (openedForWindow) {
- openedForWindow.focus();
- }
- try {
- dojo.withGlobal(openedForWindow || dojo.global,
- moveToBookmark, null, [bookmark]);
- } catch (e) {
- /*
- * squelch IE internal error, see
- * http://trac.dojotoolkit.org/ticket/1984
- */
- }
- }
- },
- // List of currently active widgets (focused widget and it's ancestors)
- _activeStack : [],
- registerWin : function(/* Window? */targetWindow) {
- // summary:
- // Registers listeners on the specified window (either the main
- // window or an iframe) to detect when the user has clicked
- // somewhere.
- // Anyone that creates an iframe should call this function.
- if (!targetWindow) {
- targetWindow = window;
- }
- dojo.connect(targetWindow.document, "onmousedown", null, function(
- evt) {
- dijit._justMouseDowned = true;
- setTimeout(function() {
- dijit._justMouseDowned = false;
- }, 0);
- dijit._onTouchNode(evt.target || evt.srcElement);
- });
- // dojo.connect(targetWindow, "onscroll", ???);
- // Listen for blur and focus events on targetWindow's body
- var body = targetWindow.document.body
- || targetWindow.document.getElementsByTagName("body")[0];
- if (body) {
- if (dojo.isIE) {
- body.attachEvent('onactivate', function(evt) {
- if (evt.srcElement.tagName.toLowerCase() != "body") {
- dijit._onFocusNode(evt.srcElement);
- }
- });
- body.attachEvent('ondeactivate', function(evt) {
- dijit._onBlurNode(evt.srcElement);
- });
- } else {
- body.addEventListener('focus', function(evt) {
- dijit._onFocusNode(evt.target);
- }, true);
- body.addEventListener('blur', function(evt) {
- dijit._onBlurNode(evt.target);
- }, true);
- }
- }
- body = null; // prevent memory leak (apparent circular reference
- // via closure)
- },
- _onBlurNode : function(/* DomNode */node) {
- // summary:
- // Called when focus leaves a node.
- // Usually ignored, _unless_ it *isn't* follwed by touching another
- // node,
- // which indicates that we tabbed off the last field on the page,
- // in which case every widget is marked inactive
- dijit._prevFocus = dijit._curFocus;
- dijit._curFocus = null;
- var w = dijit.getEnclosingWidget(node);
- if (w && w._setStateClass) {
- w._focused = false;
- w._setStateClass();
- }
- if (dijit._justMouseDowned) {
- // the mouse down caused a new widget to be marked as active;
- // this blur event
- // is coming late, so ignore it.
- return;
- }
- // if the blur event isn't followed by a focus event then mark all
- // widgets as inactive.
- if (dijit._clearActiveWidgetsTimer) {
- clearTimeout(dijit._clearActiveWidgetsTimer);
- }
- dijit._clearActiveWidgetsTimer = setTimeout(function() {
- delete dijit._clearActiveWidgetsTimer;
- dijit._setStack([]);
- }, 100);
- },
- _onTouchNode : function(/* DomNode */node) {
- // summary
- // Callback when node is focused or mouse-downed
- // ignore the recent blurNode event
- if (dijit._clearActiveWidgetsTimer) {
- clearTimeout(dijit._clearActiveWidgetsTimer);
- delete dijit._clearActiveWidgetsTimer;
- }
- // compute stack of active widgets (ex: ComboButton --> Menu -->
- // MenuItem)
- var newStack = [];
- try {
- while (node) {
- if (node.dijitPopupParent) {
- node = dijit.byId(node.dijitPopupParent).domNode;
- } else if (node.tagName
- && node.tagName.toLowerCase() == "body") {
- // is this the root of the document or just the root of
- // an iframe?
- if (node === dojo.body()) {
- // node is the root of the main document
- break;
- }
- // otherwise, find the iframe this node refers to (can't
- // access it via parentNode,
- // need to do this trick instead) and continue tracing
- // up the document
- node = dojo.query("iframe").filter(function(iframe) {
- return iframe.contentDocument.body === node;
- })[0];
- } else {
- var id = node.getAttribute
- && node.getAttribute("widgetId");
- if (id) {
- newStack.unshift(id);
- }
- node = node.parentNode;
- }
- }
- } catch (e) { /* squelch */
- }
- dijit._setStack(newStack);
- },
- _onFocusNode : function(/* DomNode */node) {
- // summary
- // Callback when node is focused
- if (node && node.tagName && node.tagName.toLowerCase() == "body") {
- return;
- }
- dijit._onTouchNode(node);
- if (node == dijit._curFocus) {
- return;
- }
- dijit._prevFocus = dijit._curFocus;
- dijit._curFocus = node;
- dojo.publish("focusNode", [node]);
- // handle focus/blur styling
- var w = dijit.getEnclosingWidget(node);
- if (w && w._setStateClass) {
- w._focused = true;
- w._setStateClass();
- }
- },
- _setStack : function(newStack) {
- // summary
- // The stack of active widgets has changed. Send out appropriate
- // events and record new stack
- var oldStack = dijit._activeStack;
- dijit._activeStack = newStack;
- // compare old stack to new stack to see how many elements they have
- // in common
- for (var nCommon = 0; nCommon < Math.min(oldStack.length,
- newStack.length); nCommon++) {
- if (oldStack[nCommon] != newStack[nCommon]) {
- break;
- }
- }
- // for all elements that have gone out of focus, send blur event
- for (var i = oldStack.length - 1; i >= nCommon; i--) {
- var widget = dijit.byId(oldStack[i]);
- if (widget) {
- dojo.publish("widgetBlur", [widget]);
- if (widget._onBlur) {
- widget._onBlur();
- }
- }
- }
- // for all element that have come into focus, send focus event
- for (var i = nCommon; i < newStack.length; i++) {
- var widget = dijit.byId(newStack[i]);
- if (widget) {
- dojo.publish("widgetFocus", [widget]);
- if (widget._onFocus) {
- widget._onFocus();
- }
- }
- }
- }
- });
- // register top window and all the iframes it contains
- dojo.addOnLoad(dijit.registerWin);
- }
- if (!dojo._hasResource["dijit._base.manager"]) { // _hasResource checks added
- // by build. Do not use
- // _hasResource directly in
- // your code.
- dojo._hasResource["dijit._base.manager"] = true;
- dojo.provide("dijit._base.manager");
- dojo.declare("dijit.WidgetSet", null, {
- constructor : function() {
- // summary:
- // A set of widgets indexed by id
- this._hash = {};
- },
- add : function(/* Widget */widget) {
- if (this._hash[widget.id]) {
- throw new Error("Tried to register widget with id=="
- + widget.id
- + " but that id is already registered");
- }
- this._hash[widget.id] = widget;
- },
- remove : function(/* String */id) {
- delete this._hash[id];
- },
- forEach : function(/* Function */func) {
- for (var id in this._hash) {
- func(this._hash[id]);
- }
- },
- filter : function(/* Function */filter) {
- var res = new dijit.WidgetSet();
- this.forEach(function(widget) {
- if (filter(widget)) {
- res.add(widget);
- }
- });
- return res; // dijit.WidgetSet
- },
- byId : function(/* String */id) {
- return this._hash[id];
- },
- byClass : function(/* String */cls) {
- return this.filter(function(widget) {
- return widget.declaredClass == cls;
- }); // dijit.WidgetSet
- }
- });
- // registry: list of all widgets on page
- dijit.registry = new dijit.WidgetSet();
- dijit._widgetTypeCtr = {};
- dijit.getUniqueId = function(/* String */widgetType) {
- // summary
- // Generates a unique id for a given widgetType
- var id;
- do {
- id = widgetType
- + "_"
- + (dijit._widgetTypeCtr[widgetType] !== undefined
- ? ++dijit._widgetTypeCtr[widgetType]
- : dijit._widgetTypeCtr[widgetType] = 0);
- } while (dijit.byId(id));
- return id; // String
- };
- if (dojo.isIE) {
- // Only run this for IE because we think it's only necessary in that
- // case,
- // and because it causes problems on FF. See bug #3531 for details.
- dojo.addOnUnload(function() {
- dijit.registry.forEach(function(widget) {
- widget.destroy();
- });
- });
- }
- dijit.byId = function(/* String|Widget */id) {
- // summary:
- // Returns a widget by its id, or if passed a widget, no-op (like
- // dojo.byId())
- return (dojo.isString(id)) ? dijit.registry.byId(id) : id; // Widget
- };
- dijit.byNode = function(/* DOMNode */node) {
- // summary:
- // Returns the widget as referenced by node
- return dijit.registry.byId(node.getAttribute("widgetId")); // Widget
- };
- dijit.getEnclosingWidget = function(/* DOMNode */node) {
- // summary:
- // Returns the widget whose dom tree contains node or null if
- // the node is not contained within the dom tree of any widget
- while (node) {
- if (node.getAttribute && node.getAttribute("widgetId")) {
- return dijit.registry.byId(node.getAttribute("widgetId"));
- }
- node = node.parentNode;
- }
- return null;
- };
- }
- if (!dojo._hasResource["dijit._base.place"]) { // _hasResource checks added by
- // build. Do not use
- // _hasResource directly in your
- // code.
- dojo._hasResource["dijit._base.place"] = true;
- dojo.provide("dijit._base.place");
- // ported from dojo.html.util
- dijit.getViewport = function() {
- // summary
- // Returns the dimensions and scroll position of the viewable area of a
- // browser window
- var _window = dojo.global;
- var _document = dojo.doc;
- // get viewport size
- var w = 0, h = 0;
- if (dojo.isMozilla) {
- // mozilla
- // _window.innerHeight includes the height taken by the scroll bar
- // clientHeight is ideal but has DTD issues:
- // #4539: FF reverses the roles of body.clientHeight/Width and
- // documentElement.clientHeight/Width based on the DTD!
- // check DTD to see whether body or documentElement returns the
- // viewport dimensions using this algorithm:
- var minw, minh, maxw, maxh;
- if (_document.body.clientWidth > _document.documentElement.clientWidth) {
- minw = _document.documentElement.clientWidth;
- maxw = _document.body.clientWidth;
- } else {
- maxw = _document.documentElement.clientWidth;
- minw = _document.body.clientWidth;
- }
- if (_document.body.clientHeight > _document.documentElement.clientHeight) {
- minh = _document.documentElement.clientHeight;
- maxh = _document.body.clientHeight;
- } else {
- maxh = _document.documentElement.clientHeight;
- minh = _document.body.clientHeight;
- }
- w = (maxw > _window.innerWidth) ? minw : maxw;
- h = (maxh > _window.innerHeight) ? minh : maxh;
- } else if (!dojo.isOpera && _window.innerWidth) {
- // in opera9, dojo.body().clientWidth should be used, instead
- // of window.innerWidth/document.documentElement.clientWidth
- // so we have to check whether it is opera
- w = _window.innerWidth;
- h = _window.innerHeight;
- } else if (dojo.isIE && _document.documentElement
- && _document.documentElement.clientHeight) {
- w = _document.documentElement.clientWidth;
- h = _document.documentElement.clientHeight;
- } else if (dojo.body().clientWidth) {
- // IE5, Opera
- w = dojo.body().clientWidth;
- h = dojo.body().clientHeight;
- }
- // get scroll position
- var scroll = dojo._docScroll();
- return {
- w : w,
- h : h,
- l : scroll.x,
- t : scroll.y
- }; // object
- };
- dijit.placeOnScreen = function(
- /* DomNode */node,
- /* Object */pos,
- /* Object */corners,
- /* boolean? */tryOnly) {
- // summary:
- // Keeps 'node' in the visible area of the screen while trying to
- // place closest to pos.x, pos.y. The input coordinates are
- // expected to be the desired document position.
- //
- // Set which corner(s) you want to bind to, such as
- //
- // placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"])
- //
- // The desired x/y will be treated as the topleft(TL)/topright(TR) or
- // BottomLeft(BL)/BottomRight(BR) corner of the node. Each corner is
- // tested
- // and if a perfect match is found, it will be used. Otherwise, it goes
- // through
- // all of the specified corners, and choose the most appropriate one.
- //
- // NOTE: node is assumed to be absolutely or relatively positioned.
- var choices = dojo.map(corners, function(corner) {
- return {
- corner : corner,
- pos : pos
- };
- });
- return dijit._place(node, choices);
- }
- dijit._place = function(/* DomNode */node, /* Array */choices, /* Function */
- layoutNode) {
- // summary:
- // Given a list of spots to put node, put it at the first spot where it
- // fits,
- // of if it doesn't fit anywhere then the place with the least overflow
- // choices: Array
- // Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} }
- // Above example says to put the top-left corner of the node at (10,20)
- // layoutNode: Function(node, orient)
- // for things like tooltip, they are displayed differently (and have
- // different dimensions)
- // based on their orientation relative to the parent. This adjusts the
- // popup based on orientation.
- // get {x: 10, y: 10, w: 100, h:100} type obj representing position of
- // viewport over document
- var view = dijit.getViewport();
- // This won't work if the node is inside a <div style="position:
- // relative">,
- // so reattach it to document.body. (Otherwise, the positioning will be
- // wrong
- // and also it might get cutoff)
- if (!node.parentNode
- || String(node.parentNode.tagName).toLowerCase() != "body") {
- dojo.body().appendChild(node);
- }
- var best = null;
- for (var i = 0; i < choices.length; i++) {
- var corner = choices[i].corner;
- var pos = choices[i].pos;
- // configure node to be displayed in given position relative to
- // button
- // (need to do this in order to get an accurate size for the node,
- // because
- // a tooltips size changes based on position, due to triangle)
- if (layoutNode) {
- layoutNode(corner);
- }
- // get node's size
- var oldDisplay = node.style.display;
- var oldVis = node.style.visibility;
- node.style.visibility = "hidden";
- node.style.display = "";
- var mb = dojo.marginBox(node);
- node.style.display = oldDisplay;
- node.style.visibility = oldVis;
- // coordinates and size of node with specified corner placed at pos,
- // and clipped by viewport
- var startX = (corner.charAt(1) == 'L' ? pos.x : Math.max(view.l,
- pos.x - mb.w)), startY = (corner.charAt(0) == 'T'
- ? pos.y
- : Math.max(view.t, pos.y - mb.h)), endX = (corner.charAt(1) == 'L'
- ? Math.min(view.l + view.w, startX + mb.w)
- : pos.x), endY = (corner.charAt(0) == 'T' ? Math.min(view.t
- + view.h, startY + mb.h) : pos.y), width = endX
- - startX, height = endY - startY, overflow = (mb.w - width)
- + (mb.h - height);
- if (best == null || overflow < best.overflow) {
- best = {
- corner : corner,
- aroundCorner : choices[i].aroundCorner,
- x : startX,
- y : startY,
- w : width,
- h : height,
- overflow : overflow
- };
- }
- if (overflow == 0) {
- break;
- }
- }
- node.style.left = best.x + "px";
- node.style.top = best.y + "px";
- return best;
- }
- dijit.placeOnScreenAroundElement = function(
- /* DomNode */node,
- /* DomNode */aroundNode,
- /* Object */aroundCorners,
- /* Function */layoutNode) {
- // summary
- // Like placeOnScreen, except it accepts aroundNode instead of x,y
- // and attempts to place node around it. Uses margin box dimensions.
- //
- // aroundCorners
- // specify Which corner of aroundNode should be
- // used to place the node => which corner(s) of node to use (see the
- // corners parameter in dijit.placeOnScreen)
- // e.g. {'TL': 'BL', 'BL': 'TL'}
- //
- // layoutNode: Function(node, orient)
- // for things like tooltip, they are displayed differently (and have
- // different dimensions)
- // based on their orientation relative to the parent. This adjusts the
- // popup based on orientation.
- // get coordinates of aroundNode
- aroundNode = dojo.byId(aroundNode);
- var oldDisplay = aroundNode.style.display;
- aroundNode.style.display = "";
- // #3172: use the slightly tighter border box instead of marginBox
- var aroundNodeW = aroundNode.offsetWidth; // mb.w;
- var aroundNodeH = aroundNode.offsetHeight; // mb.h;
- var aroundNodePos = dojo.coords(aroundNode, true);
- aroundNode.style.display = oldDisplay;
- // Generate list of possible positions for node
- var choices = [];
- for (var nodeCorner in aroundCorners) {
- choices.push({
- aroundCorner : nodeCorner,
- corner : aroundCorners[nodeCorner],
- pos : {
- x : aroundNodePos.x
- + (nodeCorner.charAt(1) == 'L'
- ? 0
- : aroundNodeW),
- y : aroundNodePos.y
- + (nodeCorner.charAt(0) == 'T'
- ? 0
- : aroundNodeH)
- }
- });
- }
- return dijit._place(node, choices, layoutNode);
- }
- }
- if (!dojo._hasResource["dijit._base.window"]) { // _hasResource checks added by
- // build. Do not use
- // _hasResource directly in your
- // code.
- dojo._hasResource["dijit._base.window"] = true;
- dojo.provide("dijit._base.window");
- dijit.getDocumentWindow = function(doc) {
- // summary
- // Get window object associated with document doc
- // With Safari, there is not way to retrieve the window from the
- // document, so we must fix it.
- if (dojo.isSafari && !doc._parentWindow) {
- /*
- * This is a Safari specific function that fix the reference to the
- * parent window from the document object.
- */
- var fix = function(win) {
- win.document._parentWindow = win;
- for (var i = 0; i < win.frames.length; i++) {
- fix(win.frames[i]);
- }
- }
- fix(window.top);
- }
- // In some IE versions (at least 6.0), document.parentWindow does not
- // return a
- // reference to the real window object (maybe a copy), so we must fix it
- // as well
- // We use IE specific execScript to attach the real window reference to
- // document._parentWindow for later use
- if (dojo.isIE && window !== document.parentWindow && !doc._parentWindow) {
- /*
- * In IE 6, only the variable "window" can be used to connect events
- * (others may be only copies).
- */
- doc.parentWindow.execScript("document._parentWindow = window;",
- "Javascript");
- // to prevent memory leak, unset it after use
- // another possibility is to add an onUnload handler which seems
- // overkill to me (liucougar)
- var win = doc._parentWindow;
- doc._parentWindow = null;
- return win; // Window
- }
- return doc._parentWindow || doc.parentWindow || doc.defaultView; // Window
- }
- }
- if (!dojo._hasResource["dijit._base.popup"]) { // _hasResource checks added by
- // build. Do not use
- // _hasResource directly in your
- // code.
- dojo._hasResource["dijit._base.popup"] = true;
- dojo.provide("dijit._base.popup");
- dijit.popup = new function() {
- // summary:
- // This class is used to show/hide widgets as popups.
- //
- var stack = [], beginZIndex = 1000, idGen = 1;
- this.open = function(/* Object */args) {
- // summary:
- // Popup the widget at the specified position
- //
- // args: Object
- // popup: Widget
- // widget to display,
- // parent: Widget
- // the button etc. that is displaying this popup
- // around: DomNode
- // DOM node (typically a button); place popup relative to this node
- // orient: Object
- // structure specifying possible positions of popup relative to
- // "around" node
- // onCancel: Function
- // callback when user has canceled the popup by
- // 1. hitting ESC or
- // 2. by using the popup widget's proprietary cancel mechanism (like
- // a cancel button in a dialog);
- // ie: whenever popupWidget.onCancel() is called, args.onCancel is
- // called
- // onClose: Function
- // callback whenever this popup is closed
- // onExecute: Function
- // callback when user "executed" on the popup/sub-popup by selecting
- // a menu choice, etc. (top menu only)
- //
- // examples:
- // 1. opening at the mouse position
- // dijit.popup.open({popup: menuWidget, x: evt.pageX, y:
- // evt.pageY});
- // 2. opening the widget as a dropdown
- // dijit.popup.open({parent: this, popup: menuWidget, around:
- // this.domNode, onClose: function(){...} });
- //
- // Note that whatever widget called dijit.popup.open() should also
- // listen to it's own _onBlur callback
- // (fired from _base/focus.js) to know that focus has moved
- // somewhere else and thus the popup should be closed.
- var widget = args.popup, orient = args.orient || {
- 'BL' : 'TL',
- 'TL' : 'BL'
- }, around = args.around, id = (args.around && args.around.id)
- ? (args.around.id + "_dropdown")
- : ("popup_" + idGen++);
- // make wrapper div to hold widget and possibly hold iframe behind
- // it.
- // we can't attach the iframe as a child of the widget.domNode
- // because
- // widget.domNode might be a <table>, <ul>, etc.
- var wrapper = dojo.doc.createElement("div");
- wrapper.id = id;
- wrapper.className = "dijitPopup";
- wrapper.style.zIndex = beginZIndex + stack.length;
- wrapper.style.visibility = "hidden";
- if (args.parent) {
- wrapper.dijitPopupParent = args.parent.id;
- }
- dojo.body().appendChild(wrapper);
- widget.domNode.style.display = "";
- wrapper.appendChild(widget.domNode);
- var iframe = new dijit.BackgroundIframe(wrapper);
- // position the wrapper node
- var best = around ? dijit.placeOnScreenAroundElement(wrapper,
- around, orient, widget.orient ? dojo
- .hitch(widget, "orient") : null) : dijit
- .placeOnScreen(wrapper, args, orient == 'R' ? ['TR', 'BR',
- 'TL', 'BL'] : ['TL', 'BL', 'TR', 'BR']);
- wrapper.style.visibility = "visible";
- // TODO: use effects to fade in wrapper
- var handlers = [];
- // Compute the closest ancestor popup that's *not* a child of
- // another popup.
- // Ex: For a TooltipDialog with a button that spawns a tree of
- // menus, find the popup of the button.
- function getTopPopup() {
- for (var pi = stack.length - 1; pi > 0
- && stack[pi].parent === stack[pi - 1].widget; pi--);
- return stack[pi];
- }
- // provide default escape and tab key handling
- // (this will work for any widget, not just menu)
- handlers.push(dojo.connect(wrapper, "onkeypress", this, function(
- evt) {
- if (evt.keyCode == dojo.keys.ESCAPE && args.onCancel) {
- args.onCancel();
- } else if (evt.keyCode == dojo.keys.TAB) {
- dojo.stopEvent(evt);
- var topPopup = getTopPopup();
- if (topPopup && topPopup.onCancel) {
- topPopup.onCancel();
- }
- }
- }));
- // watch for cancel/execute events on the popup and notify the
- // caller
- // (for a menu, "execute" means clicking an item)
- if (widget.onCancel) {
- handlers.push(dojo.connect(widget, "onCancel", null,
- args.onCancel));
- }
- handlers.push(dojo.connect(widget, widget.onExecute
- ? "onExecute"
- : "onChange", null, function() {
- var topPopup = getTopPopup();
- if (topPopup && topPopup.onExecute) {
- topPopup.onExecute();
- }
- }));
- stack.push({
- wrapper : wrapper,
- iframe : iframe,
- widget : widget,
- parent : args.parent,
- onExecute : args.onExecute,
- onCancel : args.onCancel,
- onClose : args.onClose,
- handlers : handlers
- });
- if (widget.onOpen) {
- widget.onOpen(best);
- }
- return best;
- };
- this.close = function(/* Widget */popup) {
- // summary:
- // Close specified popup and any popups that it parented
- while (dojo.some(stack, function(elem) {
- return elem.widget == popup;
- })) {
- var top = stack.pop(), wrapper = top.wrapper, iframe = top.iframe, widget = top.widget, onClose = top.onClose;
- if (widget.onClose) {
- widget.onClose();
- }
- dojo.forEach(top.handlers, dojo.disconnect);
- // #2685: check if the widget still has a domNode so ContentPane
- // can change its URL without getting an error
- if (!widget || !widget.domNode) {
- return;
- }
- dojo.style(widget.domNode, "display", "none");
- dojo.body().appendChild(widget.domNode);
- iframe.destroy();
- dojo._destroyElement(wrapper);
- if (onClose) {
- onClose();
- }
- }
- };
- }();
- dijit._frames = new function() {
- // summary: cache of iframes
- var queue = [];
- this.pop = function() {
- var iframe;
- if (queue.length) {
- iframe = queue.pop();
- iframe.style.display = "";
- } else {
- if (dojo.isIE) {
- var html = "<iframe src='javascript:\"\"'"
- + " style='position: absolute; left: 0px; top: 0px;"
- + "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
- iframe = dojo.doc.createElement(html);
- } else {
- var iframe = dojo.doc.createElement("iframe");
- iframe.src = 'javascript:""';
- iframe.className = "dijitBackgroundIframe";
- }
- iframe.tabIndex = -1; // Magic to prevent iframe from getting
- // focus on tab keypress - as style
- // didnt work.
- dojo.body().appendChild(iframe);
- }
- return iframe;
- };
- this.push = function(iframe) {
- iframe.style.display = "";
- if (dojo.isIE) {
- iframe.style.removeExpression("width");
- iframe.style.removeExpression("height");
- }
- queue.push(iframe);
- }
- }();
- // fill the queue
- if (dojo.isIE && dojo.isIE < 7) {
- dojo.addOnLoad(function() {
- var f = dijit._frames;
- dojo.forEach([f.pop()], f.push);
- });
- }
- dijit.BackgroundIframe = function(/* DomNode */node) {
- // summary:
- // For IE z-index schenanigans. id attribute is required.
- //
- // description:
- // new dijit.BackgroundIframe(node)
- // Makes a background iframe as a child of node, that fills
- // area (and position) of node
- if (!node.id) {
- throw new Error("no id");
- }
- if ((dojo.isIE && dojo.isIE < 7)
- || (dojo.isFF && dojo.isFF < 3 && dojo.hasClass(dojo.body(),
- "dijit_a11y"))) {
- var iframe = dijit._frames.pop();
- node.appendChild(iframe);
- if (dojo.isIE) {
- iframe.style.setExpression("width", "document.getElementById('"
- + node.id + "').offsetWidth");
- iframe.style.setExpression("height",
- "document.getElementById('" + node.id
- + "').offsetHeight");
- }
- this.iframe = iframe;
- }
- };
- dojo.extend(dijit.BackgroundIframe, {
- destroy : function() {
- // summary: destroy the iframe
- if (this.iframe) {
- dijit._frames.push(this.iframe);
- delete this.iframe;
- }
- }
- });
- }
- if (!dojo._hasResource["dijit._base.scroll"]) { // _hasResource checks added by
- // build. Do not use
- // _hasResource directly in your
- // code.
- dojo._hasResource["dijit._base.scroll"] = true;
- dojo.provide("dijit._base.scroll");
- dijit.scrollIntoView = function(/* DomNode */node) {
- // summary
- // Scroll the passed node into view, if it is not.
- // don't rely on that node.scrollIntoView works just because the
- // function is there
- // it doesnt work in Konqueror or Opera even though the function is
- // there and probably
- // not safari either
- // dont like browser sniffs implementations but sometimes you have to
- // use it
- if (dojo.isIE) {
- // only call scrollIntoView if there is a scrollbar for this menu,
- // otherwise, scrollIntoView will scroll the window scrollbar
- if (dojo.marginBox(node.parentNode).h <= node.parentNode.scrollHeight) { // PORT
- // was
- // getBorderBox
- node.scrollIntoView(false);
- }
- } else if (dojo.isMozilla) {
- node.scrollIntoView(false);
- } else {
- var parent = node.parentNode;
- var parentBottom = parent.scrollTop + dojo.marginBox(parent).h; // PORT
- // was
- // getBorderBox
- var nodeBottom = node.offsetTop + dojo.marginBox(node).h;
- if (parentBottom < nodeBottom) {
- parent.scrollTop += (nodeBottom - parentBottom);
- } else if (parent.scrollTop > node.offsetTop) {
- parent.scrollTop -= (parent.scrollTop - node.offsetTop);
- }
- }
- };
- }
- if (!dojo._hasResource["dijit._base.sniff"]) { // _hasResource checks added by
- // build. Do not use
- // _hasResource directly in your
- // code.
- dojo._hasResource["dijit._base.sniff"] = true;
- dojo.provide("dijit._base.sniff");
- // ported from dojo.html.applyBrowserClass (style.js)
- // summary:
- // Applies pre-set class names based on browser & version to the
- // top-level HTML node. Simply doing a require on this module will
- // establish this CSS. Modified version of Morris' CSS hack.
- (function() {
- var d = dojo;
- var ie = d.isIE;
- var opera = d.isOpera;
- var maj = Math.floor;
- var classes = {
- dj_ie : ie,
- // dj_ie55: ie == 5.5,
- dj_ie6 : maj(ie) == 6,
- dj_ie7 : maj(ie) == 7,
- dj_iequirks : ie && d.isQuirks,
- // NOTE: Opera not supported by dijit
- dj_opera : opera,
- dj_opera8 : maj(opera) == 8,
- dj_opera9 : maj(opera) == 9,
- dj_khtml : d.isKhtml,
- dj_safari : d.isSafari,
- dj_gecko : d.isMozilla
- }; // no dojo unsupported browsers
- for (var p in classes) {
- if (classes[p]) {
- var html = dojo.doc.documentElement; // TODO browser-specific
- // DOM magic needed?
- if (html.className) {
- html.className += " " + p;
- } else {
- html.className = p;
- }
- }
- }
- })();
- }
- if (!dojo._hasResource["dijit._base.bidi"]) { // _hasResource checks added by
- // build. Do not use
- // _hasResource directly in your
- // code.
- dojo._hasResource["dijit._base.bidi"] = true;
- dojo.provide("dijit._base.bidi");
- // summary: applies a class to the top of the document for right-to-left
- // stylesheet rules
- dojo.addOnLoad(function() {
- if (!dojo._isBodyLtr()) {
- dojo.addClass(dojo.body(), "dijitRtl");
- }
- });
- }
- if (!dojo._hasResource["dijit._base.typematic"]) { // _hasResource checks added
- // by build. Do not use
- // _hasResource directly in
- // your code.
- dojo._hasResource["dijit._base.typematic"] = true;
- dojo.provide("dijit._base.typematic");
- dijit.typematic = {
- // summary:
- // These functions are used to repetitively call a user specified
- // callback
- // method when a specific key or mouse click over a specific DOM node is
- // held down for a specific amount of time.
- // Only 1 such event is allowed to occur on the browser page at 1 time.
- _fireEventAndReload : function() {
- this._timer = null;
- this._callback(++this._count, this._node, this._evt);
- this._currentTimeout = (this._currentTimeout < 0)
- ? this._initialDelay
- : ((this._subsequentDelay > 1)
- ? this._subsequentDelay
- : Math.round(this._currentTimeout
- * this._subsequentDelay));
- this._timer = setTimeout(dojo.hitch(this, "_fireEventAndReload"),
- this._currentTimeout);
- },
- trigger : function(/* Event */evt, /* Object */_this, /* DOMNode */node, /* Function */
- callback, /* Object */obj, /* Number */subsequentDelay, /* Number */
- initialDelay) {
- // summary:
- // Start a timed, repeating callback sequence.
- // If already started, the function call is ignored.
- // This method is not normally called by the user but can be
- // when the normal listener code is insufficient.
- // Parameters:
- // evt: key or mouse event object to pass to the user callback
- // _this: pointer to the user's widget space.
- // node: the DOM node object to pass the the callback function
- // callback: function to call until the sequence is stopped called
- // with 3 parameters:
- // count: integer representing number of repeated calls (0..n) with
- // -1 indicating the iteration has stopped
- // node: the DOM node object passed in
- // evt: key or mouse event object
- // obj: user space object used to uniquely identify each typematic
- // sequence
- // subsequentDelay: if > 1, the number of milliseconds until the
- // 3->n events occur
- // or else the fractional time multiplier for the next event's
- // delay, default=0.9
- // initialDelay: the number of milliseconds until the 2nd event
- // occurs, default=500ms
- if (obj != this._obj) {
- this.stop();
- this._initialDelay = initialDelay || 500;
- this._subsequentDelay = subsequentDelay || 0.90;
- this._obj = obj;
- this._evt = evt;
- this._node = node;
- this._currentTimeout = -1;
- this._count = -1;
- this._callback = dojo.hitch(_this, callback);
- this._fireEventAndReload();
- }
- },
- stop : function() {
- // summary:
- // Stop an ongoing timed, repeating callback sequence.
- if (this._timer) {
- clearTimeout(this._timer);
- this._timer = null;
- }
- if (this._obj) {
- this._callback(-1, this._node, this._evt);
- this._obj = null;
- }
- },
- addKeyListener : function(/* DOMNode */node, /* Object */keyObject, /* Object */
- _this, /* Function */callback, /* Number */subsequentDelay, /* Number */
- initialDelay) {
- // summary: Start listening for a specific typematic key.
- // keyObject: an object defining the key to listen for.
- // key: (mandatory) the keyCode (number) or character (string) to
- // listen for.
- // ctrlKey: desired ctrl key state to initiate the calback sequence:
- // pressed (true)
- // released (false)
- // either (unspecified)
- // altKey: same as ctrlKey but for the alt key
- // shiftKey: same as ctrlKey but for the shift key
- // See the trigger method for other parameters.
- // Returns an array of dojo.connect handles
- return [dojo.connect(node, "onkeypress", this, function(evt) {
- if (evt.keyCode == keyObject.keyCode
- && (!keyObject.charCode || keyObject.charCode == evt.charCode)
- && (keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey)
- && (keyObject.altKey === undefined || keyObject.altKey == evt.ctrlKey)
- && (keyObject.shiftKey === undefined || keyObject.shiftKey == evt.ctrlKey)) {
- dojo.stopEvent(evt);
- dijit.typematic.trigger(keyObject, _this, node, callback,
- keyObject, subsequentDelay, initialDelay);
- } else if (dijit.typematic._obj == keyObject) {
- dijit.typematic.stop();
- }
- }), dojo.connect(node, "onkeyup", this, function(evt) {
- if (dijit.typematic._obj == keyObject) {
- dijit.typematic.stop();
- }
- })];
- },
- addMouseListener : function(/* DOMNode */node, /* Object */_this, /* Function */
- callback, /* Number */subsequentDelay, /* Number */initialDelay) {
- // summary: Start listening for a typematic mouse click.
- // See the trigger method for other parameters.
- // Returns an array of dojo.connect handles
- var dc = dojo.connect;
- return [dc(node, "mousedown", this, function(evt) {
- dojo.stopEvent(evt);
- dijit.typematic.trigger(evt, _this, node, callback,
- node, subsequentDelay, initialDelay);
- }), dc(node, "mouseup", this, function(evt) {
- dojo.stopEvent(evt);
- dijit.typematic.stop();
- }), dc(node, "mouseout", this, function(evt) {
- dojo.stopEvent(evt);
- dijit.typematic.stop();
- }), dc(node, "mousemove", this, function(evt) {
- dojo.stopEvent(evt);
- }), dc(node, "dblclick", this, function(evt) {
- dojo.stopEvent(evt);
- if (dojo.isIE) {
- dijit.typematic.trigger(evt, _this, node, callback,
- node, subsequentDelay, initialDelay);
- setTimeout(dijit.typematic.stop, 50);
- }
- })];
- },
- addListener : function(/* Node */mouseNode, /* Node */keyNode, /* Object */
- keyObject, /* Object */_this, /* Function */callback, /* Number */
- subsequentDelay, /* Number */initialDelay) {
- // summary: Start listening for a specific typematic key and
- // mouseclick.
- // This is a thin wrapper to addKeyListener and addMouseListener.
- // mouseNode: the DOM node object to listen on for mouse events.
- // keyNode: the DOM node object to listen on for key events.
- // See the addMouseListener and addKeyListener methods for other
- // parameters.
- // Returns an array of dojo.connect handles
- return this.addKeyListener(keyNode, keyObject, _this, callback,
- subsequentDelay, initialDelay).concat(this
- .addMouseListener(mouseNode, _this, callback,
- subsequentDelay, initialDelay));
- }
- };
- }
- if (!dojo._hasResource["dijit._base.wai"]) { // _hasResource checks added by
- // build. Do not use
- // _hasResource directly in your
- // code.
- dojo._hasResource["dijit._base.wai"] = true;
- dojo.provide("dijit._base.wai");
- dijit.wai = {
- onload : function() {
- // summary:
- // Function that detects if we are in high-contrast mode or not,
- // and sets up a timer to periodically confirm the value.
- // figure out the background-image style property
- // and apply that to the image.src property.
- // description:
- // This must be a named function and not an anonymous
- // function, so that the widget parsing code can make sure it
- // registers its onload function after this function.
- // DO NOT USE "this" within this function.
- // create div for testing if high contrast mode is on or images are
- // turned off
- var div = document.createElement("div");
- div.id = "a11yTestNode";
- div.style.cssText = 'border: 1px solid;'
- + 'border-color:red green;' + 'position: absolute;'
- + 'height: 5px;' + 'top: -999px;'
- + 'background-image: url("'
- + dojo.moduleUrl("dijit", "form/templates/blank.gif")
- + '");';
- dojo.body().appendChild(div);
- // test it
- function check() {
- var cs = dojo.getComputedStyle(div);
- if (cs) {
- var bkImg = cs.backgroundImage;
- var needsA11y = (cs.borderTopColor == cs.borderRightColor)
- || (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)"));
- dojo[needsA11y ? "addClass" : "removeClass"](dojo.body(),
- "dijit_a11y");
- }
- }
- check();
- if (dojo.isIE) {
- setInterval(check, 4000);
- }
- }
- };
- // Test if computer is in high contrast mode.
- // Make sure the a11y test runs first, before widgets are instantiated.
- if (dojo.isIE || dojo.isMoz) { // NOTE: checking in Safari messes things up
- dojo._loaders.unshift(dijit.wai.onload);
- }
- dojo.mixin(dijit, {
- hasWaiRole : function(/* Element */elem) {
- // Summary: Return true if elem has a role attribute and false if
- // not.
- if (elem.hasAttribute) {
- return elem.hasAttribute("role");
- } else {
- return elem.getAttribute("role") ? true : false;
- }
- },
- getWaiRole : function(/* Element */elem) {
- // Summary: Return the role of elem or an empty string if
- // elem does not have a role.
- var value = elem.getAttribute("role");
- if (value) {
- var prefixEnd = value.indexOf(":");
- return prefixEnd == -1 ? value : value.substring(prefixEnd + 1);
- } else {
- return "";
- }
- },
- setWaiRole : function(/* Element */elem, /* String */role) {
- // Summary: Set the role on elem. On Firefox 2 and below, "wairole:"
- // is
- // prepended to the provided role value.
- if (dojo.isFF && dojo.isFF < 3) {
- elem.setAttribute("role", "wairole:" + role);
- } else {
- elem.setAttribute("role", role);
- }
- },
- removeWaiRole : function(/* Element */elem) {
- // Summary: Removes the role attribute from elem.
- elem.removeAttribute("role");
- },
- hasWaiState : function(/* Element */elem, /* String */state) {
- // Summary: Return true if elem has a value for the given state and
- // false if it does not.
- // On Firefox 2 and below, we check for an attribute in namespace
- // "http://www.w3.org/2005/07/aaa" with a name of the given state.
- // On all other browsers, we check for an attribute called
- // "aria-"+state.
- if (dojo.isFF && dojo.isFF < 3) {
- return elem.hasAttributeNS("http://www.w3.org/2005/07/aaa",
- state);
- } else {
- if (elem.hasAttribute) {
- return elem.hasAttribute("aria-" + state);
- } else {
- return elem.getAttribute("aria-" + state) ? true : false;
- }
- }
- },
- getWaiState : function(/* Element */elem, /* String */state) {
- // Summary: Return the value of the requested state on elem
- // or an empty string if elem has no value for state.
- // On Firefox 2 and below, we check for an attribute in namespace
- // "http://www.w3.org/2005/07/aaa" with a name of the given state.
- // On all other browsers, we check for an attribute called
- // "aria-"+state.
- if (dojo.isFF && dojo.isFF < 3) {
- return elem.getAttributeNS("http://www.w3.org/2005/07/aaa",
- state);
- } else {
- var value = elem.getAttribute("aria-" + state);
- return value ? value : "";
- }
- },
- setWaiState : function(/* Element */elem, /* String */state, /* String */
- value) {
- // Summary: Set state on elem to value.
- // On Firefox 2 and below, we set an attribute in namespace
- // "http://www.w3.org/2005/07/aaa" with a name of the given state.
- // On all other browsers, we set an attribute called
- // "aria-"+state.
- if (dojo.isFF && dojo.isFF < 3) {
- elem.setAttributeNS("http://www.w3.org/2005/07/aaa", "aaa:"
- + state, value);
- } else {
- elem.setAttribute("aria-" + state, value);
- }
- },
- removeWaiState : function(/* Element */elem, /* String */state) {
- // Summary: Removes the given state from elem.
- // On Firefox 2 and below, we remove the attribute in namespace
- // "http://www.w3.org/2005/07/aaa" with a name of the given state.
- // On all other browsers, we remove the attribute called
- // "aria-"+state.
- if (dojo.isFF && dojo.isFF < 3) {
- elem.removeAttributeNS("http://www.w3.org/2005/07/aaa", state);
- } else {
- elem.removeAttribute("aria-" + state);
- }
- }
- });
- }
- if (!dojo._hasResource["dijit._base"]) { // _hasResource checks added by
- // build. Do not use _hasResource
- // directly in your code.
- dojo._hasResource["dijit._base"] = true;
- dojo.provide("dijit._base");
- }
- if (!dojo._hasResource["dojo.date.stamp"]) { // _hasResource checks added by
- // build. Do not use
- // _hasResource directly in your
- // code.
- dojo._hasResource["dojo.date.stamp"] = true;
- dojo.provide("dojo.date.stamp");
- // Methods to convert dates to or from a wire (string) format using
- // well-known conventions
- dojo.date.stamp.fromISOString = function(/* String */formattedString, /* Number? */
- defaultTime) {
- // summary:
- // Returns a Date object given a string formatted according to a subset
- // of the ISO-8601 standard.
- //
- // description:
- // Accepts a string formatted according to a profile of ISO8601 as
- // defined by
- // RFC3339 (http://www.ietf.org/rfc/rfc3339.txt), except that partial
- // input is allowed.
- // Can also process dates as specified by
- // http://www.w3.org/TR/NOTE-datetime
- // The following combinations are valid:
- // * dates only
- // yyyy
- // yyyy-MM
- // yyyy-MM-dd
- // * times only, with an optional time zone appended
- // THH:mm
- // THH:mm:ss
- // THH:mm:ss.SSS
- // * and "datetimes" which could be any combination of the above
- // timezones may be specified as Z (for UTC) or +/- followed by a time
- // expression HH:mm
- // Assumes the local time zone if not specified. Does not validate.
- // Improperly formatted
- // input may return null. Arguments which are out of bounds will be
- // handled
- // by the Date constructor (e.g. January 32nd typically gets resolved to
- // February 1st)
- //
- // formattedString:
- // A string such as 2005-06-30T08:05:00-07:00 or 2005-06-30 or T08:05:00
- //
- // defaultTime:
- // Used for defaults for fields omitted in the formattedString.
- // Uses 1970-01-01T00:00:00.0Z by default.
- if (!dojo.date.stamp._isoRegExp) {
- dojo.date.stamp._isoRegExp =
- // TODO: could be more restrictive and check for 00-59, etc.
- /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/;
- }
- var match = dojo.date.stamp._isoRegExp.exec(formattedString);
- var result = null;
- if (match) {
- match.shift();
- match[1] && match[1]--; // Javascript Date months are 0-based
- match[6] && (match[6] *= 1000); // Javascript Date expects
- // fractional seconds as
- // milliseconds
- if (defaultTime) {
- // mix in defaultTime. Relatively expensive, so use || operators
- // for the fast path of defaultTime === 0
- defaultTime = new Date(defaultTime);
- dojo.map(
- ["FullYear", "Month", "Date", "Hours", "Minutes",
- "Seconds", "Milliseconds"], function(prop) {
- return defaultTime["get" + prop]();
- }).forEach(function(value, index) {
- if (match[index] === undefined) {
- match[index] = value;
- }
- });
- }
- result = new Date(match[0] || 1970, match[1] || 0, match[2] || 0,
- match[3] || 0, match[4] || 0, match[5] || 0, match[6] || 0);
- var offset = 0;
- var zoneSign = match[7] && match[7].charAt(0);
- if (zoneSign != 'Z') {
- offset = ((match[8] || 0) * 60) + (Number(match[9]) || 0);
- if (zoneSign != '-') {
- offset *= -1;
- }
- }
- if (zoneSign) {
- offset -= result.getTimezoneOffset();
- }
- if (offset) {
- result.setTime(result.getTime() + offset * 60000);
- }
- }
- return result; // Date or null
- }
- dojo.date.stamp.toISOString = function(/* Date */dateObject, /* Object? */
- options) {
- // summary:
- // Format a Date object as a string according a subset of the ISO-8601
- // standard
- //
- // description:
- // When options.selector is omitted, output follows RFC3339
- // (http://www.ietf.org/rfc/rfc3339.txt)
- // The local time zone is included as an offset from GMT, except when
- // selector=='time' (time without a date)
- // Does not check bounds.
- //
- // dateObject:
- // A Date object
- //
- // object {selector: string, zulu: boolean, milliseconds: boolean}
- // selector- "date" or "time" for partial formatting of the Date object.
- // Both date and time will be formatted by default.
- // zulu- if true, UTC/GMT is used for a timezone
- // milliseconds- if true, output milliseconds
- var _ = function(n) {
- return (n < 10) ? "0" + n : n;
- }
- options = options || {};
- var formattedDate = [];
- var getter = options.zulu ? "getUTC" : "get";
- var date = "";
- if (options.selector != "time") {
- date = [dateObject[getter + "FullYear"](),
- _(dateObject[getter + "Month"]() + 1),
- _(dateObject[getter + "Date"]())].join('-');
- }
- formattedDate.push(date);
- if (options.selector != "date") {
- var time = [_(dateObject[getter + "Hours"]()),
- _(dateObject[getter + "Minutes"]()),
- _(dateObject[getter + "Seconds"]())].join(':');
- var millis = dateObject[getter + "Milliseconds"]();
- if (options.milliseconds) {
- time += "." + (millis < 100 ? "0" : "") + _(millis);
- }
- if (options.zulu) {
- time += "Z";
- } else if (options.selector != "time") {
- var timezoneOffset = dateObject.getTimezoneOffset();
- var absOffset = Math.abs(timezoneOffset);
- time += (timezoneOffset > 0 ? "-" : "+")
- + _(Math.floor(absOffset / 60)) + ":"
- + _(absOffset % 60);
- }
- formattedDate.push(time);
- }
- return formattedDate.join('T'); // String
- }
- }
- if (!dojo._hasResource["dojo.parser"]) { // _hasResource checks added by
- // build. Do not use _hasResource
- // directly in your code.
- dojo._hasResource["dojo.parser"] = true;
- dojo.provide("dojo.parser");
- dojo.parser = new function() {
- var d = dojo;
- function val2type(/* Object */value) {
- // summary:
- // Returns name of type of given value.
- if (d.isString(value)) {
- return "string";
- }
- if (typeof value == "number") {
- return "number";
- }
- if (typeof value == "boolean") {
- return "boolean";
- }
- if (d.isFunction(value)) {
- return "function";
- }
- if (d.isArray(value)) {
- return "array";
- } // typeof [] == "object"
- if (value instanceof Date) {
- return "date";
- } // assume timestamp
- if (value instanceof d._Url) {
- return "url";
- }
- return "object";
- }
- function str2obj(/* String */value, /* String */type) {
- // summary:
- // Convert given string value to given type
- switch (type) {
- case "string" :
- return value;
- case "number" :
- return value.length ? Number(value) : NaN;
- case "boolean" :
- // for checked/disabled value might be "" or "checked".
- // interpret as true.
- return typeof value == "boolean" ? value : !(value
- .toLowerCase() == "false");
- case "function" :
- if (d.isFunction(value)) {
- // IE gives us a function, even when we say something
- // like onClick="foo"
- // (in which case it gives us an invalid function
- // "function(){ foo }").
- // Therefore, convert to string
- value = value.toString();
- value = d.trim(value.substring(value.indexOf('{') + 1,
- value.length - 1));
- }
- try {
- if (value.search(/[^\w\.]+/i) != -1) {
- // TODO: "this" here won't work
- value = d.parser._nameAnonFunc(new Function(value),
- this);
- }
- return d.getObject(value, false);
- } catch (e) {
- return new Function();
- }
- case "array" :
- return value.split(/\s*,\s*/);
- case "date" :
- switch (value) {
- case "" :
- return new Date(""); // the NaN of dates
- case "now" :
- return allGetServerTime(); // current date
- default :
- return d.date.stamp.fromISOString(value);
- }
- case "url" :
- return d.baseUrl + value;
- default :
- return d.fromJson(value);
- }
- }
- var instanceClasses = {
- // map from fully qualified name (like "dijit.Button") to structure like
- // { cls: dijit.Button, params: {label: "string", disabled: "boolean"} }
- };
- function getClassInfo(/* String */className) {
- // className:
- // fully qualified name (like "dijit.Button")
- // returns:
- // structure like
- // {
- // cls: dijit.Button,
- // params: { label: "string", disabled: "boolean"}
- // }
- if (!instanceClasses[className]) {
- // get pointer to widget class
- var cls = d.getObject(className);
- if (!d.isFunction(cls)) {
- throw new Error("Could not load class '"
- + className
- + "'. Did you spell the name correctly and use a full path, like 'dijit.form.Button'?");
- }
- var proto = cls.prototype;
- // get table of parameter names & types
- var params = {};
- for (var name in proto) {
- if (name.charAt(0) == "_") {
- continue;
- } // skip internal properties
- var defVal = proto[name];
- params[name] = val2type(defVal);
- }
- instanceClasses[className] = {
- cls : cls,
- params : params
- };
- }
- return instanceClasses[className];
- }
- this._functionFromScript = function(script) {
- var preamble = "";
- var suffix = "";
- var argsStr = script.getAttribute("args");
- if (argsStr) {
- d.forEach(argsStr.split(/\s*,\s*/), function(part, idx) {
- preamble += "var " + part + " = arguments[" + idx
- + "]; ";
- });
- }
- var withStr = script.getAttribute("with");
- if (withStr && withStr.length) {
- d.forEach(withStr.split(/\s*,\s*/), function(part) {
- preamble += "with(" + part + "){";
- suffix += "}";
- });
- }
- return new Function(preamble + script.innerHTML + suffix);
- }
- this.instantiate = function(/* Array */nodes) {
- // summary:
- // Takes array of nodes, and turns them into class instances and
- // potentially calls a layout method to allow them to connect with
- // any children
- var thelist = [];
- d.forEach(nodes, function(node) {
- if (!node) {
- return;
- }
- var type = node.getAttribute("dojoType");
- if ((!type) || (!type.length)) {
- return;
- }
- var clsInfo = getClassInfo(type);
- var clazz = clsInfo.cls;
- var ps = clazz._noScript || clazz.prototype._noScript;
- // read parameters (ie, attributes).
- // clsInfo.params lists expected params like {"checked":
- // "boolean", "n": "number"}
- var params = {};
- var attributes = node.attributes;
- for (var name in clsInfo.params) {
- var item = attributes.getNamedItem(name);
- if (!item
- || (!item.specified && (!dojo.isIE || name
- .toLowerCase() != "value"))) {
- continue;
- }
- var value = item.value;
- // Deal with IE quirks for 'class' and 'style'
- switch (name) {
- case "class" :
- value = node.className;
- break;
- case "style" :
- value = node.style && node.style.cssText; // FIXME:
- // Opera?
- }
- var _type = clsInfo.params[name];
- params[name] = str2obj(value, _type);
- }
- // Process <script type="dojo/*"> script tags
- // <script type="dojo/method" event="foo"> tags are added to
- // params, and passed to
- // the widget on instantiation.
- // <script type="dojo/method"> tags (with no event) are executed
- // after instantiation
- // <script type="dojo/connect" event="foo"> tags are
- // dojo.connected after instantiation
- if (!ps) {
- var connects = [], // functions to connect after
- // instantiation
- calls = []; // functions to call after instantiation
- d.query("> script[type^='dojo/']", node).orphan().forEach(
- function(script) {
- var event = script.getAttribute("event"), type = script
- .getAttribute("type"), nf = d.parser
- ._functionFromScript(script);
- if (event) {
- if (type == "dojo/connect") {
- connects.push({
- event : event,
- func : nf
- });
- } else {
- params[event] = nf;
- }
- } else {
- calls.push(nf);
- }
- });
- }
- var markupFactory = clazz["markupFactory"];
- if (!markupFactory && clazz["prototype"]) {
- markupFactory = clazz.prototype["markupFactory"];
- }
- // create the instance
- var instance = markupFactory ? markupFactory(params, node,
- clazz) : new clazz(params, node);
- thelist.push(instance);
- // map it to the JS namespace if that makes sense
- var jsname = node.getAttribute("jsId");
- if (jsname) {
- d.setObject(jsname, instance);
- }
- // process connections and startup functions
- if (!ps) {
- dojo.forEach(connects, function(connect) {
- dojo.connect(instance, connect.event, null,
- connect.func);
- });
- dojo.forEach(calls, function(func) {
- func.call(instance);
- });
- }
- });
- // Call startup on each top level instance if it makes sense (as for
- // widgets). Parent widgets will recursively call startup on their
- // (non-top level) children
- d.forEach(thelist, function(instance) {
- if (instance
- && (instance.startup)
- && ((!instance.getParent) || (!instance
- .getParent()))) {
- instance.startup();
- }
- });
- return thelist;
- };
- this.parse = function(/* DomNode? */rootNode) {
- // summary:
- // Search specified node (or root node) recursively for class
- // instances,
- // and instantiate them Searches for
- // dojoType="qualified.class.name"
- var list = d.query('[dojoType]', rootNode);
- // go build the object instances
- var instances = this.instantiate(list);
- return instances;
- };
- }();
- // Register the parser callback. It should be the first callback
- // after the a11y test.
- (function() {
- var parseRunner = function() {
- if (djConfig["parseOnLoad"] == true) {
- dojo.parser.parse();
- }
- };
- // FIXME: need to clobber cross-dependency!!
- if (dojo.exists("dijit.wai.onload")
- && (dijit.wai.onload === dojo._loaders[0])) {
- dojo._loaders.splice(1, 0, parseRunner);
- } else {
- dojo._loaders.unshift(parseRunner);
- }
- })();
- // TODO: ported from 0.4.x Dojo. Can we reduce this?
- dojo.parser._anonCtr = 0;
- dojo.parser._anon = {}; // why is this property required?
- dojo.parser._nameAnonFunc = function(/* Function */anonFuncPtr, /* Object */
- thisObj) {
- // summary:
- // Creates a reference to anonFuncPtr in thisObj with a completely
- // unique name. The new name is returned as a String.
- var jpn = "$joinpoint";
- var nso = (thisObj || dojo.parser._anon);
- if (dojo.isIE) {
- var cn = anonFuncPtr["__dojoNameCache"];
- if (cn && nso[cn] === anonFuncPtr) {
- return anonFuncPtr["__dojoNameCache"];
- }
- }
- var ret = "__" + dojo.parser._anonCtr++;
- while (typeof nso[ret] != "undefined") {
- ret = "__" + dojo.parser._anonCtr++;
- }
- nso[ret] = anonFuncPtr;
- return ret; // String
- }
- }
- if (!dojo._hasResource["dijit._Widget"]) { // _hasResource checks added by
- // build. Do not use _hasResource
- // directly in your code.
- dojo._hasResource["dijit._Widget"] = true;
- dojo.provide("dijit._Widget");
- dojo.declare("dijit._Widget", null, {
- // summary:
- // The foundation of dijit widgets.
- //
- // id: String
- // a unique, opaque ID string that can be assigned by users or by the
- // system. If the developer passes an ID which is known not to be
- // unique, the specified ID is ignored and the system-generated ID is
- // used instead.
- id : "",
- // lang: String
- // Language to display this widget in (like en-us).
- // Defaults to brower's specified preferred language (typically the
- // language of the OS)
- lang : "",
- // dir: String
- // Bi-directional support, as defined by the HTML DIR attribute. Either
- // left-to-right "ltr" or right-to-left "rtl".
- dir : "",
- // class: String
- // HTML class attribute
- "class" : "",
- // style: String
- // HTML style attribute
- style : "",
- // title: String
- // HTML title attribute
- title : "",
- // srcNodeRef: DomNode
- // pointer to original dom node
- srcNodeRef : null,
- // domNode: DomNode
- // this is our visible representation of the widget! Other DOM
- // Nodes may by assigned to other properties, usually through the
- // template system's dojoAttachPonit syntax, but the domNode
- // property is the canonical "top level" node in widget UI.
- domNode : null,
- // attributeMap: Object
- // A map of attributes and attachpoints -- typically standard HTML
- // attributes -- to set
- // on the widget's dom, at the "domNode" attach point, by default.
- // Other node references can be specified as properties of 'this'
- attributeMap : {
- id : "",
- dir : "",
- lang : "",
- "class" : "",
- style : "",
- title : ""
- }, // TODO: add on* handlers?
- // ////////// INITIALIZATION METHODS
- // ///////////////////////////////////////
- postscript : function(params, srcNodeRef) {
- this.create(params, srcNodeRef);
- },
- create : function(params, srcNodeRef) {
- // summary:
- // To understand the process by which widgets are instantiated, it
- // is critical to understand what other methods create calls and
- // which of them you'll want to override. Of course, adventurous
- // developers could override create entirely, but this should
- // only be done as a last resort.
- //
- // Below is a list of the methods that are called, in the order
- // they are fired, along with notes about what they do and if/when
- // you should over-ride them in your widget:
- //
- // postMixInProperties:
- // a stub function that you can over-ride to modify
- // variables that may have been naively assigned by
- // mixInProperties
- // # widget is added to manager object here
- // buildRendering
- // Subclasses use this method to handle all UI initialization
- // Sets this.domNode. Templated widgets do this automatically
- // and otherwise it just uses the source dom node.
- // postCreate
- // a stub function that you can over-ride to modify take
- // actions once the widget has been placed in the UI
- // store pointer to original dom tree
- this.srcNodeRef = dojo.byId(srcNodeRef);
- // For garbage collection. An array of handles returned by
- // Widget.connect()
- // Each handle returned from Widget.connect() is an array of handles
- // from dojo.connect()
- this._connects = [];
- // _attaches: String[]
- // names of all our dojoAttachPoint variables
- this._attaches = [];
- // mixin our passed parameters
- if (this.srcNodeRef && (typeof this.srcNodeRef.id == "string")) {
- this.id = this.srcNodeRef.id;
- }
- if (params) {
- dojo.mixin(this, params);
- }
- this.postMixInProperties();
- // generate an id for the widget if one wasn't specified
- // (be sure to do this before buildRendering() because that function
- // might
- // expect the id to be there.
- if (!this.id) {
- this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,
- "_"));
- }
- dijit.registry.add(this);
- this.buildRendering();
- // Copy attributes listed in attributeMap into the [newly created]
- // DOM for the widget.
- // The placement of these attributes is according to the property
- // mapping in attributeMap.
- // Note special handling for 'style' and 'class' attributes which
- // are lists and can
- // have elements from both old and new structures, and some
- // attributes like "type"
- // cannot be processed this way as they are not mutable.
- if (this.domNode) {
- for (var attr in this.attributeMap) {
- var mapNode = this[this.attributeMap[attr] || "domNode"];
- var value = this[attr];
- if (typeof value != "object"
- && (value !== "" || (params && params[attr]))) {
- switch (attr) {
- case "class" :
- dojo.addClass(mapNode, value);
- break;
- case "style" :
- if (mapNode.style.cssText) {
- mapNode.style.cssText += "; " + value;// FIXME:
- // Opera
- } else {
- mapNode.style.cssText = value;
- }
- break;
- default :
- mapNode.setAttribute(attr, value);
- }
- }
- }
- }
- if (this.domNode) {
- this.domNode.setAttribute("widgetId", this.id);
- }
- this.postCreate();
- // If srcNodeRef has been processed and removed from the DOM (e.g.
- // TemplatedWidget) then delete it to allow GC.
- if (this.srcNodeRef && !this.srcNodeRef.parentNode) {
- delete this.srcNodeRef;
- }
- },
- postMixInProperties : function() {
- // summary
- // Called after the parameters to the widget have been read-in,
- // but before the widget template is instantiated.
- // Especially useful to set properties that are referenced in the
- // widget template.
- },
- buildRendering : function() {
- // summary:
- // Construct the UI for this widget, setting this.domNode.
- // Most widgets will mixin TemplatedWidget, which overrides this
- // method.
- this.domNode = this.srcNodeRef || dojo.doc.createElement('div');
- },
- postCreate : function() {
- // summary:
- // Called after a widget's dom has been setup
- },
- startup : function() {
- // summary:
- // Called after a widget's children, and other widgets on the page,
- // have been created.
- // Provides an opportunity to manipulate any children before they
- // are displayed
- // This is useful for composite widgets that need to control or
- // layout sub-widgets
- // Many layout widgets can use this as a wiring phase
- },
- // ////////// DESTROY FUNCTIONS ////////////////////////////////
- destroyRecursive : function(/* Boolean */finalize) {
- // summary:
- // Destroy this widget and it's descendants. This is the generic
- // "destructor" function that all widget users should call to
- // cleanly discard with a widget. Once a widget is destroyed, it's
- // removed from the manager object.
- // finalize: Boolean
- // is this function being called part of global environment
- // tear-down?
- this.destroyDescendants();
- this.destroy();
- },
- destroy : function(/* Boolean */finalize) {
- // summary:
- // Destroy this widget, but not its descendants
- // finalize: Boolean
- // is this function being called part of global environment
- // tear-down?
- this.uninitialize();
- dojo.forEach(this._connects, function(array) {
- dojo.forEach(array, dojo.disconnect);
- });
- this.destroyRendering(finalize);
- dijit.registry.remove(this.id);
- },
- destroyRendering : function(/* Boolean */finalize) {
- // summary:
- // Destroys the DOM nodes associated with this widget
- // finalize: Boolean
- // is this function being called part of global environment
- // tear-down?
- if (this.bgIframe) {
- this.bgIframe.destroy();
- delete this.bgIframe;
- }
- if (this.domNode) {
- dojo._destroyElement(this.domNode);
- delete this.domNode;
- }
- if (this.srcNodeRef) {
- dojo._destroyElement(this.srcNodeRef);
- delete this.srcNodeRef;
- }
- },
- destroyDescendants : function() {
- // summary:
- // Recursively destroy the children of this widget and their
- // descendants.
- // TODO: should I destroy in the reverse order, to go bottom up?
- dojo.forEach(this.getDescendants(), function(widget) {
- widget.destroy();
- });
- },
- uninitialize : function() {
- // summary:
- // stub function. Over-ride to implement custom widget tear-down
- // behavior.
- return false;
- },
- // //////////////// MISCELLANEOUS METHODS ///////////////////
- toString : function() {
- // summary:
- // returns a string that represents the widget. When a widget is
- // cast to a string, this method will be used to generate the
- // output. Currently, it does not implement any sort of reversable
- // serialization.
- return '[Widget ' + this.declaredClass + ', '
- + (this.id || 'NO ID') + ']'; // String
- },
- getDescendants : function() {
- // summary:
- // return all the descendant widgets
- var list = dojo.query('[widgetId]', this.domNode);
- return list.map(dijit.byNode); // Array
- },
- nodesWithKeyClick : ["input", "button"],
- connect : function(
- /* Object|null */obj,
- /* String */event,
- /* String|Function */method) {
- // summary:
- // Connects specified obj/event to specified method of this object
- // and registers for disconnect() on widget destroy.
- // Special event: "ondijitclick" triggers on a click or enter-down
- // or space-up
- // Similar to dojo.connect() but takes three arguments rather than
- // four.
- var handles = [];
- if (event == "ondijitclick") {
- var w = this;
- // add key based click activation for unsupported nodes.
- if (!this.nodesWithKeyClick[obj.nodeName]) {
- handles.push(dojo.connect(obj, "onkeydown", this, function(
- e) {
- if (e.keyCode == dojo.keys.ENTER) {
- return (dojo.isString(method))
- ? w[method](e)
- : method.call(w, e);
- } else if (e.keyCode == dojo.keys.SPACE) {
- // stop space down as it causes IE to scroll
- // the browser window
- dojo.stopEvent(e);
- }
- }));
- handles.push(dojo.connect(obj, "onkeyup", this,
- function(e) {
- if (e.keyCode == dojo.keys.SPACE) {
- return dojo.isString(method)
- ? w[method](e)
- : method.call(w, e);
- }
- }));
- }
- event = "onclick";
- }
- handles.push(dojo.connect(obj, event, this, method));
- // return handles for FormElement and ComboBox
- this._connects.push(handles);
- return handles;
- },
- disconnect : function(/* Object */handles) {
- // summary:
- // Disconnects handle created by this.connect.
- // Also removes handle from this widget's list of connects
- for (var i = 0; i < this._connects.length; i++) {
- if (this._connects[i] == handles) {
- dojo.forEach(handles, dojo.disconnect);
- this._connects.splice(i, 1);
- return;
- }
- }
- },
- isLeftToRight : function() {
- // summary:
- // Checks the DOM to for the text direction for bi-directional
- // support
- // description:
- // This method cannot be used during widget construction because the
- // widget
- // must first be connected to the DOM tree. Parent nodes are
- // searched for the
- // 'dir' attribute until one is found, otherwise left to right mode
- // is assumed.
- // See HTML spec, DIR attribute for more information.
- if (typeof this._ltr == "undefined") {
- this._ltr = dojo.getComputedStyle(this.domNode).direction != "rtl";
- }
- return this._ltr; // Boolean
- },
- isFocusable : function() {
- // summary:
- // Return true if this widget can currently be focused
- // and false if not
- return this.focus
- && (dojo.style(this.domNode, "display") != "none");
- }
- });
- }
- if (!dojo._hasResource["dojo.string"]) { // _hasResource checks added by
- // build. Do not use _hasResource
- // directly in your code.
- dojo._hasResource["dojo.string"] = true;
- dojo.provide("dojo.string");
- dojo.string.pad = function(/* String */text, /* int */size, /* String? */ch, /* boolean? */
- end) {
- // summary:
- // Pad a string to guarantee that it is at least 'size' length by
- // filling with the character 'c' at either the start or end of the
- // string. Pads at the start, by default.
- // text: the string to pad
- // size: length to provide padding
- // ch: character to pad, defaults to '0'
- // end: adds padding at the end if true, otherwise pads at start
- var out = String(text);
- if (!ch) {
- ch = '0';
- }
- while (out.length < size) {
- if (end) {
- out += ch;
- } else {
- out = ch + out;
- }
- }
- return out; // String
- };
- dojo.string.substitute = function( /* String */template,
- /* Object or Array */map,
- /* Function? */transform,
- /* Object? */thisObject) {
- // summary:
- // Performs parameterized substitutions on a string. Throws an
- // exception if any parameter is unmatched.
- // description:
- // For example,
- // | dojo.string.substitute("File '${0}' is not found in directory
- // '${1}'.",["foo.html","/temp"]);
- // | dojo.string.substitute("File '${name}' is not found in directory
- // '${info.dir}'.",{name: "foo.html", info: {dir: "/temp"}});
- // both return
- // "File 'foo.html' is not found in directory '/temp'."
- // template:
- // a string with expressions in the form ${key} to be replaced or
- // ${key:format} which specifies a format function. NOTE syntax has
- // changed from %{key}
- // map: where to look for substitutions
- // transform:
- // a function to process all parameters before substitution takes
- // place, e.g. dojo.string.encodeXML
- // thisObject:
- // where to look for optional format function; default to the global
- // namespace
- return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,
- function(match, key, format) {
- var value = dojo.getObject(key, false, map);
- if (format) {
- value = dojo.getObject(format, false, thisObject)(value);
- }
- if (transform) {
- value = transform(value, key);
- }
- return value.toString();
- }); // string
- };
- dojo.string.trim = function(/* String */str) {
- // summary: trims whitespaces from both sides of the string
- // description:
- // This version of trim() was taken from Steven Levithan's blog:
- // http://blog.stevenlevithan.com/archives/faster-trim-javascript.
- // The short yet good-performing version of this function is
- // dojo.trim(), which is part of the base.
- str = str.replace(/^\s+/, '');
- for (var i = str.length - 1; i > 0; i--) {
- if (/\S/.test(str.charAt(i))) {
- str = str.substring(0, i + 1);
- break;
- }
- }
- return str; // String
- };
- }
- if (!dojo._hasResource["dijit._Templated"]) { // _hasResource checks added by
- // build. Do not use
- // _hasResource directly in your
- // code.
- dojo._hasResource["dijit._Templated"] = true;
- dojo.provide("dijit._Templated");
- dojo.declare("dijit._Templated", null, {
- // summary:
- // mixin for widgets that are instantiated from a template
- // templateNode: DomNode
- // a node that represents the widget template. Pre-empts both
- // templateString and templatePath.
- templateNode : null,
- // templateString String:
- // a string that represents the widget template. Pre-empts the
- // templatePath. In builds that have their strings "interned", the
- // templatePath is converted to an inline templateString, thereby
- // preventing a synchronous network call.
- templateString : null,
- // templatePath: String
- // Path to template (HTML file) for this widget
- templatePath : null,
- // widgetsInTemplate Boolean:
- // should we parse the template to find widgets that might be
- // declared in markup inside it? false by default.
- widgetsInTemplate : false,
- // containerNode DomNode:
- // holds child elements. "containerNode" is generally set via a
- // dojoAttachPoint assignment and it designates where children of
- // the src dom node will be placed
- containerNode : null,
- // skipNodeCache Boolean:
- // if using a cached widget template node poses issues for a
- // particular widget class, it can set this property to ensure
- // that its template is always re-built from a string
- _skipNodeCache : false,
- // method over-ride
- buildRendering : function() {
- // summary:
- // Construct the UI for this widget from a template, setting
- // this.domNode.
- // Lookup cached version of template, and download to cache if it
- // isn't there already. Returns either a DomNode or a string,
- // depending on
- // whether or not the template contains ${foo} replacement
- // parameters.
- var cached = dijit._Templated.getCachedTemplate(this.templatePath,
- this.templateString, this._skipNodeCache);
- var node;
- if (dojo.isString(cached)) {
- var className = this.declaredClass, _this = this;
- // Cache contains a string because we need to do property
- // replacement
- // do the property replacement
- var tstr = dojo.string.substitute(cached, this, function(value,
- key) {
- if (key.charAt(0) == '!') {
- value = _this[key.substr(1)];
- }
- if (typeof value == "undefined") {
- throw new Error(className + " template:" + key);
- } // a debugging aide
- if (!value) {
- return "";
- }
- // Substitution keys beginning with ! will skip the
- // transform step,
- // in case a user wishes to insert unescaped markup,
- // e.g. ${!foo}
- return key.charAt(0) == "!" ? value :
- // Safer substitution, see heading
- // "Attribute values" in
- // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
- value.toString().replace(/"/g, """); // TODO:
- // add
- // &?
- // use
- // encodeXML
- // method?
- }, this);
- node = dijit._Templated._createNodesFromText(tstr)[0];
- } else {
- // if it's a node, all we have to do is clone it
- node = cached.cloneNode(true);
- }
- // recurse through the node, looking for, and attaching to, our
- // attachment points which should be defined on the template node.
- this._attachTemplateNodes(node);
- var source = this.srcNodeRef;
- if (source && source.parentNode) {
- source.parentNode.replaceChild(node, source);
- }
- this.domNode = node;
- if (this.widgetsInTemplate) {
- var childWidgets = dojo.parser.parse(node);
- this._attachTemplateNodes(childWidgets, function(n, p) {
- return n[p];
- });
- }
- this._fillContent(source);
- },
- _fillContent : function(/* DomNode */source) {
- // summary:
- // relocate source contents to templated container node
- // this.containerNode must be able to receive children, or
- // exceptions will be thrown
- var dest = this.containerNode;
- if (source && dest) {
- while (source.hasChildNodes()) {
- dest.appendChild(source.firstChild);
- }
- }
- },
- _attachTemplateNodes : function(rootNode, getAttrFunc) {
- // summary:
- // map widget properties and functions to the handlers specified in
- // the dom node and it's descendants. This function iterates over
- // all
- // nodes and looks for these properties:
- // * dojoAttachPoint
- // * dojoAttachEvent
- // * waiRole
- // * waiState
- // rootNode: DomNode|Array[Widgets]
- // the node to search for properties. All children will be searched.
- // getAttrFunc: function?
- // a function which will be used to obtain property for a given
- // DomNode/Widget
- getAttrFunc = getAttrFunc || function(n, p) {
- return n.getAttribute(p);
- };
- var nodes = dojo.isArray(rootNode)
- ? rootNode
- : (rootNode.all || rootNode.getElementsByTagName("*"));
- var x = dojo.isArray(rootNode) ? 0 : -1;
- for (; x < nodes.length; x++) {
- var baseNode = (x == -1) ? rootNode : nodes[x];
- if (this.widgetsInTemplate && getAttrFunc(baseNode, 'dojoType')) {
- continue;
- }
- // Process dojoAttachPoint
- var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint");
- if (attachPoint) {
- var point, points = attachPoint.split(/\s*,\s*/);
- while (point = points.shift()) {
- if (dojo.isArray(this[point])) {
- this[point].push(baseNode);
- } else {
- this[point] = baseNode;
- }
- }
- }
- // Process dojoAttachEvent
- var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent");
- if (attachEvent) {
- // NOTE: we want to support attributes that have the form
- // "domEvent: nativeEvent; ..."
- var event, events = attachEvent.split(/\s*,\s*/);
- var trim = dojo.trim;
- while (event = events.shift()) {
- if (event) {
- var thisFunc = null;
- if (event.indexOf(":") != -1) {
- // oh, if only JS had tuple assignment
- var funcNameArr = event.split(":");
- event = trim(funcNameArr[0]);
- thisFunc = trim(funcNameArr[1]);
- } else {
- event = trim(event);
- }
- if (!thisFunc) {
- thisFunc = event;
- }
- this.connect(baseNode, event, thisFunc);
- }
- }
- }
- // waiRole, waiState
- var role = getAttrFunc(baseNode, "waiRole");
- if (role) {
- dijit.setWaiRole(baseNode, role);
- }
- var values = getAttrFunc(baseNode, "waiState");
- if (values) {
- dojo.forEach(values.split(/\s*,\s*/), function(stateValue) {
- if (stateValue.indexOf('-') != -1) {
- var pair = stateValue.split('-');
- dijit.setWaiState(baseNode, pair[0],
- pair[1]);
- }
- });
- }
- }
- }
- });
- // key is either templatePath or templateString; object is either string or
- // DOM tree
- dijit._Templated._templateCache = {};
- dijit._Templated.getCachedTemplate = function(templatePath, templateString,
- alwaysUseString) {
- // summary:
- // static method to get a template based on the templatePath or
- // templateString key
- // templatePath: String
- // the URL to get the template from. dojo.uri.Uri is often passed as
- // well.
- // templateString: String?
- // a string to use in lieu of fetching the template from a URL
- // Returns:
- // Either string (if there are ${} variables that need to be replaced)
- // or just
- // a DOM tree (if the node can be cloned directly)
- // is it already cached?
- var tmplts = dijit._Templated._templateCache;
- var key = templateString || templatePath;
- var cached = tmplts[key];
- if (cached) {
- return cached;
- }
- // If necessary, load template string from template path
- if (!templateString) {
- templateString = dijit._Templated._sanitizeTemplateString(dojo
- ._getText(templatePath));
- }
- templateString = dojo.string.trim(templateString);
- if (templateString.match(/\$\{([^\}]+)\}/g) || alwaysUseString) {
- // there are variables in the template so all we can do is cache the
- // string
- return (tmplts[key] = templateString); // String
- } else {
- // there are no variables in the template so we can cache the DOM
- // tree
- return (tmplts[key] = dijit._Templated
- ._createNodesFromText(templateString)[0]); // Node
- }
- };
- dijit._Templated._sanitizeTemplateString = function(/* String */tString) {
- // summary:
- // Strips <?xml ...?> declarations so that external SVG and XML
- // documents can be added to a document without worry. Also, if the
- // string
- // is an HTML document, only the part inside the body tag is returned.
- if (tString) {
- tString = tString.replace(
- /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,
- "");
- var matches = tString.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
- if (matches) {
- tString = matches[1];
- }
- } else {
- tString = "";
- }
- return tString; // String
- };
- if (dojo.isIE) {
- dojo.addOnUnload(function() {
- var cache = dijit._Templated._templateCache;
- for (var key in cache) {
- var value = cache[key];
- if (!isNaN(value.nodeType)) { // isNode equivalent
- dojo._destroyElement(value);
- }
- delete cache[key];
- }
- });
- }
- (function() {
- var tagMap = {
- cell : {
- re : /^<t[dh][\s\r\n>]/i,
- pre : "<table><tbody><tr>",
- post : "</tr></tbody></table>"
- },
- row : {
- re : /^<tr[\s\r\n>]/i,
- pre : "<table><tbody>",
- post : "</tbody></table>"
- },
- section : {
- re : /^<(thead|tbody|tfoot)[\s\r\n>]/i,
- pre : "<table>",
- post : "</table>"
- }
- };
- // dummy container node used temporarily to hold nodes being created
- var tn;
- dijit._Templated._createNodesFromText = function(/* String */text) {
- // summary:
- // Attempts to create a set of nodes based on the structure of the
- // passed text.
- if (!tn) {
- tn = dojo.doc.createElement("div");
- tn.style.display = "none";
- dojo.body().appendChild(tn);
- }
- var tableType = "none";
- var rtext = text.replace(/^\s+/, "");
- for (var type in tagMap) {
- var map = tagMap[type];
- if (map.re.test(rtext)) {
- tableType = type;
- text = map.pre + text + map.post;
- break;
- }
- }
- tn.innerHTML = text;
- if (tn.normalize) {
- tn.normalize();
- }
- var tag = {
- cell : "tr",
- row : "tbody",
- section : "table"
- }[tableType];
- var _parent = (typeof tag != "undefined") ? tn
- .getElementsByTagName(tag)[0] : tn;
- var nodes = [];
- while (_parent.firstChild) {
- nodes.push(_parent.removeChild(_parent.firstChild));
- }
- tn.innerHTML = "";
- return nodes; // Array
- }
- })();
- // These arguments can be specified for widgets which are used in templates.
- // Since any widget can be specified as sub widgets in template, mix it
- // into the base widget class. (This is a hack, but it's effective.)
- dojo.extend(dijit._Widget, {
- dojoAttachEvent : "",
- dojoAttachPoint : "",
- waiRole : "",
- waiState : ""
- })
- }
- if (!dojo._hasResource["dijit._Container"]) { // _hasResource checks added by
- // build. Do not use
- // _hasResource directly in your
- // code.
- dojo._hasResource["dijit._Container"] = true;
- dojo.provide("dijit._Container");
- dojo.declare("dijit._Contained", null, {
- // summary
- // Mixin for widgets that are children of a container widget
- getParent : function() {
- // summary:
- // returns the parent widget of this widget, assuming the
- // parent
- // implements dijit._Container
- for (var p = this.domNode.parentNode; p; p = p.parentNode) {
- var id = p.getAttribute && p.getAttribute("widgetId");
- if (id) {
- var parent = dijit.byId(id);
- return parent.isContainer ? parent : null;
- }
- }
- return null;
- },
- _getSibling : function(which) {
- var node = this.domNode;
- do {
- node = node[which + "Sibling"];
- } while (node && node.nodeType != 1);
- if (!node) {
- return null;
- } // null
- var id = node.getAttribute("widgetId");
- return dijit.byId(id);
- },
- getPreviousSibling : function() {
- // summary:
- // returns null if this is the first child of the parent,
- // otherwise returns the next element sibling to the "left".
- return this._getSibling("previous");
- },
- getNextSibling : function() {
- // summary:
- // returns null if this is the last child of the parent,
- // otherwise returns the next element sibling to the
- // "right".
- return this._getSibling("next");
- }
- });
- dojo.declare("dijit._Container", null, {
- // summary
- // Mixin for widgets that contain a list of children like
- // SplitContainer
- isContainer : true,
- addChild : function(/* Widget */widget, /* int? */insertIndex) {
- // summary:
- // Process the given child widget, inserting it's dom node
- // as
- // a child of our dom node
- if (insertIndex === undefined) {
- insertIndex = "last";
- }
- var refNode = this.containerNode || this.domNode;
- if (insertIndex && typeof insertIndex == "number") {
- var children = dojo.query("> [widgetid]", refNode);
- if (children && children.length >= insertIndex) {
- refNode = children[insertIndex - 1];
- insertIndex = "after";
- }
- }
- dojo.place(widget.domNode, refNode, insertIndex);
- // If I've been started but the child widget hasn't been
- // started,
- // start it now. Make sure to do this after widget has been
- // inserted into the DOM tree, so it can see that it's being
- // controlled by me,
- // so it doesn't try to size itself.
- if (this._started && !widget._started) {
- widget.startup();
- }
- },
- removeChild : function(/* Widget */widget) {
- // summary:
- // removes the passed widget instance from this widget but
- // does
- // not destroy it
- var node = widget.domNode;
- node.parentNode.removeChild(node); // detach but don't
- // destroy
- },
- _nextElement : function(node) {
- do {
- node = node.nextSibling;
- } while (node && node.nodeType != 1);
- return node;
- },
- _firstElement : function(node) {
- node = node.firstChild;
- if (node && node.nodeType != 1) {
- node = this._nextElement(node);
- }
- return node;
- },
- getChildren : function() {
- // summary:
- // Returns array of children widgets
- return dojo.query("> [widgetId]",
- this.containerNode || this.domNode)
- .map(dijit.byNode); // Array
- },
- hasChildren : function() {
- // summary:
- // Returns true if widget has children
- var cn = this.containerNode || this.domNode;
- return !!this._firstElement(cn); // Boolean
- },
- _getSiblingOfChild : function(/* Widget */child, /* int */dir) {
- // summary:
- // get the next or previous widget sibling of child
- // dir:
- // if 1, get the next sibling
- // if -1, get the previous sibling
- var node = child.domNode;
- var which = (dir > 0 ? "nextSibling" : "previousSibling");
- do {
- node = node[which];
- } while (node
- && (node.nodeType != 1 || !dijit.byNode(node)));
- return node ? dijit.byNode(node) : null;
- }
- });
- dojo.declare("dijit._KeyNavContainer", [dijit._Container], {
- // summary:
- // A _Container with keyboard navigation of its children.
- // To use this mixin, call connectKeyNavHandlers() in
- // postCreate() and call startupKeyNavChildren() in startup().
- /*
- * ===== // focusedChild: Widget // The currently focused child
- * widget, or null if there isn't one focusedChild: null, =====
- */
- _keyNavCodes : {},
- connectKeyNavHandlers : function(/* Array */prevKeyCodes, /* Array */
- nextKeyCodes) {
- // summary:
- // Call in postCreate() to attach the keyboard handlers
- // to the container.
- // preKeyCodes: Array
- // Key codes for navigating to the previous child.
- // nextKeyCodes: Array
- // Key codes for navigating to the next child.
- var keyCodes = this._keyNavCodes = {};
- var prev = dojo.hitch(this, this.focusPrev);
- var next = dojo.hitch(this, this.focusNext);
- dojo.forEach(prevKeyCodes, function(code) {
- keyCodes[code] = prev
- });
- dojo.forEach(nextKeyCodes, function(code) {
- keyCodes[code] = next
- });
- this.connect(this.domNode, "onkeypress",
- "_onContainerKeypress");
- if (dojo.isIE) {
- this.connect(this.domNode, "onactivate",
- "_onContainerFocus");
- this.connect(this.domNode, "ondeactivate",
- "_onContainerBlur");
- } else {
- this.connect(this.domNode, "onfocus",
- "_onContainerFocus");
- this
- .connect(this.domNode, "onblur",
- "_onContainerBlur");
- }
- },
- startupKeyNavChildren : function() {
- // summary:
- // Call in startup() to set child tabindexes to -1
- dojo.forEach(this.getChildren(), dojo.hitch(this,
- "_setTabIndexMinusOne"));
- },
- addChild : function(/* Widget */widget, /* int? */insertIndex) {
- // summary: Add a child to our _Container
- dijit._KeyNavContainer.superclass.addChild.apply(this,
- arguments);
- this._setTabIndexMinusOne(widget);
- },
- focus : function() {
- // summary: Default focus() implementation: focus the first
- // child.
- this.focusFirstChild();
- },
- focusFirstChild : function() {
- // summary: Focus the first focusable child in the
- // container.
- this.focusChild(this._getFirstFocusableChild());
- },
- focusNext : function() {
- // summary: Focus the next widget or focal node (for widgets
- // with multiple focal nodes) within this container.
- if (this.focusedChild && this.focusedChild.hasNextFocalNode
- && this.focusedChild.hasNextFocalNode()) {
- this.focusedChild.focusNext();
- return;
- }
- var child = this._getNextFocusableChild(this.focusedChild,
- 1);
- if (child.getFocalNodes) {
- this.focusChild(child, child.getFocalNodes()[0]);
- } else {
- this.focusChild(child);
- }
- },
- focusPrev : function() {
- // summary: Focus the previous widget or focal node (for
- // widgets
- // with multiple focal nodes) within this container.
- if (this.focusedChild && this.focusedChild.hasPrevFocalNode
- && this.focusedChild.hasPrevFocalNode()) {
- this.focusedChild.focusPrev();
- return;
- }
- var child = this._getNextFocusableChild(this.focusedChild,
- -1);
- if (child.getFocalNodes) {
- var nodes = child.getFocalNodes();
- this.focusChild(child, nodes[nodes.length - 1]);
- } else {
- this.focusChild(child);
- }
- },
- focusChild : function(/* Widget */widget, /* Node? */node) {
- // summary: Focus widget. Optionally focus 'node' within
- // widget.
- if (widget) {
- if (this.focusedChild && widget !== this.focusedChild) {
- this._onChildBlur(this.focusedChild);
- }
- this.focusedChild = widget;
- if (node && widget.focusFocalNode) {
- widget.focusFocalNode(node);
- } else {
- widget.focus();
- }
- }
- },
- _setTabIndexMinusOne : function(/* Widget */widget) {
- if (widget.getFocalNodes) {
- dojo.forEach(widget.getFocalNodes(), function(node) {
- node.setAttribute("tabIndex", -1);
- });
- } else {
- (widget.focusNode || widget.domNode).setAttribute(
- "tabIndex", -1);
- }
- },
- _onContainerFocus : function(evt) {
- this.domNode.setAttribute("tabIndex", -1);
- if (evt.target === this.domNode) {
- this.focusFirstChild();
- } else {
- var widget = dijit.getEnclosingWidget(evt.target);
- if (widget && widget.isFocusable()) {
- this.focusedChild = widget;
- }
- }
- },
- _onContainerBlur : function(evt) {
- if (this.tabIndex) {
- this.domNode.setAttribute("tabIndex", this.tabIndex);
- }
- },
- _onContainerKeypress : function(evt) {
- if (evt.ctrlKey || evt.altKey) {
- return;
- }
- var func = this._keyNavCodes[evt.keyCode];
- if (func) {
- func();
- dojo.stopEvent(evt);
- }
- },
- _onChildBlur : function(/* Widget */widget) {
- // summary:
- // Called when focus leaves a child widget to go
- // to a sibling widget.
- },
- _getFirstFocusableChild : function() {
- return this._getNextFocusableChild(null, 1);
- },
- _getNextFocusableChild : function(child, dir) {
- if (child) {
- child = this._getSiblingOfChild(child, dir);
- }
- var children = this.getChildren();
- for (var i = 0; i < children.length; i++) {
- if (!child) {
- child = children[(dir > 0)
- ? 0
- : (children.length - 1)];
- }
- if (child.isFocusable()) {
- return child;
- }
- child = this._getSiblingOfChild(child, dir);
- }
- }
- });
- }
- if (!dojo._hasResource["dijit.layout._LayoutWidget"]) { // _hasResource checks
- // added by build. Do
- // not use _hasResource
- // directly in your
- // code.
- dojo._hasResource["dijit.layout._LayoutWidget"] = true;
- dojo.provide("dijit.layout._LayoutWidget");
- dojo.declare("dijit.layout._LayoutWidget", [dijit._Widget,
- dijit._Container, dijit._Contained], {
- // summary
- // Mixin for widgets that contain a list of children like
- // SplitContainer.
- // Widgets which mixin this code must define layout() to lay out
- // the children
- isLayoutContainer : true,
- postCreate : function() {
- dojo.addClass(this.domNode, "dijitContainer");
- },
- startup : function() {
- // summary:
- // Called after all the widgets have been instantiated and
- // their
- // dom nodes have been inserted somewhere under
- // document.body.
- //
- // Widgets should override this method to do any
- // initialization
- // dependent on other widgets existing, and then call
- // this superclass method to finish things off.
- //
- // startup() in subclasses shouldn't do anything
- // size related because the size of the widget hasn't been
- // set yet.
- if (this._started) {
- return;
- }
- this._started = true;
- if (this.getChildren) {
- dojo.forEach(this.getChildren(), function(child) {
- child.startup();
- });
- }
- // If I am a top level widget
- if (!this.getParent || !this.getParent()) {
- // Do recursive sizing and layout of all my descendants
- // (passing in no argument to resize means that it has
- // to glean the size itself)
- this.resize();
- // since my parent isn't a layout container, and my
- // style is width=height=100% (or something similar),
- // then I need to watch when the window resizes, and
- // size myself accordingly
- // (passing in no argument to resize means that it has
- // to glean the size itself)
- this.connect(window, 'onresize', function() {
- this.resize();
- });
- }
- },
- resize : function(args) {
- // summary:
- // Explicitly set this widget's size (in pixels),
- // and then call layout() to resize contents (and maybe
- // adjust child widgets)
- //
- // args: Object?
- // {w: int, h: int, l: int, t: int}
- var node = this.domNode;
- // set margin box size, unless it wasn't specified, in which
- // case use current size
- if (args) {
- dojo.marginBox(node, args);
- // set offset of the node
- if (args.t) {
- node.style.top = args.t + "px";
- }
- if (args.l) {
- node.style.left = args.l + "px";
- }
- }
- // If either height or width wasn't specified by the user,
- // then query node for it.
- // But note that setting the margin box and then immediately
- // querying dimensions may return
- // inaccurate results, so try not to depend on it.
- var mb = dojo.mixin(dojo.marginBox(node), args || {});
- // Save the size of my content box.
- this._contentBox = dijit.layout.marginBox2contentBox(node,
- mb);
- // Callback for widget to adjust size of it's children
- this.layout();
- },
- layout : function() {
- // summary
- // Widgets override this method to size & position their
- // contents/children.
- // When this is called this._contentBox is guaranteed to be
- // set (see resize()).
- //
- // This is called after startup(), and also when the
- // widget's size has been
- // changed.
- }
- });
- dijit.layout.marginBox2contentBox = function(/* DomNode */node, /* Object */
- mb) {
- // summary:
- // Given the margin-box size of a node, return it's content box size.
- // Functions like dojo.contentBox() but is more reliable since it
- // doesn't have
- // to wait for the browser to compute sizes.
- var cs = dojo.getComputedStyle(node);
- var me = dojo._getMarginExtents(node, cs);
- var pb = dojo._getPadBorderExtents(node, cs);
- return {
- l : dojo._toPixelValue(node, cs.paddingLeft),
- t : dojo._toPixelValue(node, cs.paddingTop),
- w : mb.w - (me.w + pb.w),
- h : mb.h - (me.h + pb.h)
- };
- };
- (function() {
- var capitalize = function(word) {
- return word.substring(0, 1).toUpperCase() + word.substring(1);
- };
- var size = function(widget, dim) {
- // size the child
- widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode,
- dim);
- // record child's size, but favor our own numbers when we have them.
- // the browser lies sometimes
- dojo.mixin(widget, dojo.marginBox(widget.domNode));
- dojo.mixin(widget, dim);
- };
- dijit.layout.layoutChildren = function(/* DomNode */container, /* Object */
- dim, /* Object[] */children) {
- /**
- * summary Layout a bunch of child dom nodes within a parent dom
- * node container: parent node dim: {l, t, w, h} object specifying
- * dimensions of container into which to place children children: an
- * array like [ {domNode: foo, layoutAlign: "bottom" }, {domNode:
- * bar, layoutAlign: "client"} ]
- */
- // copy dim because we are going to modify it
- dim = dojo.mixin({}, dim);
- dojo.addClass(container, "dijitLayoutContainer");
- // Move "client" elements to the end of the array for layout. a11y
- // dictates that the author
- // needs to be able to put them in the document in tab-order, but
- // this algorithm requires that
- // client be last.
- children = dojo.filter(children, function(item) {
- return item.layoutAlign != "client";
- }).concat(dojo.filter(children, function(item) {
- return item.layoutAlign == "client";
- }));
- // set positions/sizes
- dojo.forEach(children, function(child) {
- var elm = child.domNode, pos = child.layoutAlign;
- // set elem to upper left corner of unused space; may
- // move it later
- var elmStyle = elm.style;
- elmStyle.left = dim.l + "px";
- elmStyle.top = dim.t + "px";
- elmStyle.bottom = elmStyle.right = "auto";
- dojo.addClass(elm, "dijitAlign" + capitalize(pos));
- // set size && adjust record of remaining space.
- // note that setting the width of a <div> may affect
- // it's height.
- if (pos == "top" || pos == "bottom") {
- size(child, {
- w : dim.w
- });
- dim.h -= child.h;
- if (pos == "top") {
- dim.t += child.h;
- } else {
- elmStyle.top = dim.t + dim.h + "px";
- }
- } else if (pos == "left" || pos == "right") {
- size(child, {
- h : dim.h
- });
- dim.w -= child.w;
- if (pos == "left") {
- dim.l += child.w;
- } else {
- elmStyle.left = dim.l + dim.w + "px";
- }
- } else if (pos == "client") {
- size(child, dim);
- }
- });
- };
- })();
- }
- if (!dojo._hasResource["dijit.form._FormWidget"]) { // _hasResource checks added
- // by build. Do not use
- // _hasResource directly in
- // your code.
- dojo._hasResource["dijit.form._FormWidget"] = true;
- dojo.provide("dijit.form._FormWidget");
- dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated], {
- /*
- * Summary: FormElement widgets correspond to native HTML elements such
- * as <input> or <button> or <select>. Each FormElement represents a
- * single input value, and has a (possibly hidden) <input> element, to
- * which it serializes its input value, so that form submission (either
- * normal submission or via FormBind?) works as expected.
- *
- * All these widgets should have these attributes just like native HTML
- * input elements. You can set them during widget construction, but
- * after that they are read only.
- *
- * They also share some common methods.
- */
- // baseClass: String
- // Root CSS class of the widget (ex: dijitTextBox), used to add CSS
- // classes of widget
- // (ex: "dijitTextBox dijitTextBoxInvalid dijitTextBoxFocused
- // dijitTextBoxInvalidFocused")
- // See _setStateClass().
- baseClass : "",
- // value: String
- // Corresponds to the native HTML <input> element's attribute.
- value : "",
- // name: String
- // Name used when submitting form; same as "name" attribute or plain
- // HTML elements
- name : "",
- // id: String
- // Corresponds to the native HTML <input> element's attribute.
- // Also becomes the id for the widget.
- id : "",
- // alt: String
- // Corresponds to the native HTML <input> element's attribute.
- alt : "",
- // type: String
- // Corresponds to the native HTML <input> element's attribute.
- type : "text",
- // tabIndex: Integer
- // Order fields are traversed when user hits the tab key
- tabIndex : "0",
- // disabled: Boolean
- // Should this widget respond to user input?
- // In markup, this is specified as "disabled='disabled'", or just
- // "disabled".
- disabled : false,
- // intermediateChanges: Boolean
- // Fires onChange for each value change or only on demand
- intermediateChanges : false,
- // These mixins assume that the focus node is an INPUT, as many but not
- // all _FormWidgets are.
- // Don't attempt to mixin the 'type', 'name' attributes here
- // programatically -- they must be declared
- // directly in the template as read by the parser in order to function.
- // IE is known to specifically
- // require the 'name' attribute at element creation time.
- attributeMap : dojo.mixin(dojo
- .clone(dijit._Widget.prototype.attributeMap), {
- id : "focusNode",
- tabIndex : "focusNode",
- alt : "focusNode"
- }),
- setDisabled : function(/* Boolean */disabled) {
- // summary:
- // Set disabled state of widget.
- this.domNode.disabled = this.disabled = disabled;
- if (this.focusNode) {
- this.focusNode.disabled = disabled;
- }
- if (disabled) {
- // reset those, because after the domNode is disabled, we can no
- // longer receive
- // mouse related events, see #4200
- this._hovering = false;
- this._active = false;
- }
- dijit.setWaiState(this.focusNode || this.domNode, "disabled",
- disabled);
- this._setStateClass();
- },
- _onMouse : function(/* Event */event) {
- // summary:
- // Sets _hovering, _active, and stateModifier properties depending
- // on mouse state,
- // then calls setStateClass() to set appropriate CSS classes for
- // this.domNode.
- //
- // To get a different CSS class for hover, send onmouseover and
- // onmouseout events to this method.
- // To get a different CSS class while mouse button is depressed,
- // send onmousedown to this method.
- var mouseNode = event.target;
- if (mouseNode && mouseNode.getAttribute) {
- this.stateModifier = mouseNode.getAttribute("stateModifier")
- || "";
- }
- if (!this.disabled) {
- switch (event.type) {
- case "mouseenter" :
- case "mouseover" :
- this._hovering = true;
- break;
- case "mouseout" :
- case "mouseleave" :
- this._hovering = false;
- break;
- case "mousedown" :
- this._active = true;
- // set a global event to handle mouseup, so it fires
- // properly
- // even if the cursor leaves the button
- var self = this;
- // #2685: use this.connect and disconnect so destroy
- // works properly
- var mouseUpConnector = this.connect(dojo.body(),
- "onmouseup", function() {
- self._active = false;
- self._setStateClass();
- self.disconnect(mouseUpConnector);
- });
- break;
- }
- this._setStateClass();
- }
- },
- isFocusable : function() {
- return !this.disabled
- && (dojo.style(this.domNode, "display") != "none");
- },
- focus : function() {
- dijit.focus(this.focusNode);
- },
- _setStateClass : function() {
- // summary
- // Update the visual state of the widget by setting the css classes
- // on this.domNode
- // (or this.stateNode if defined) by combining this.baseClass with
- // various suffixes that represent the current widget state(s).
- //
- // In the case where a widget has multiple
- // states, it sets the class based on all possible
- // combinations. For example, an invalid form widget that is being
- // hovered
- // will be "dijitInput dijitInputInvalid dijitInputHover
- // dijitInputInvalidHover".
- //
- // For complex widgets with multiple regions, there can be various
- // hover/active states,
- // such as "Hover" or "CloseButtonHover" (for tab buttons).
- // This is controlled by a stateModifier="CloseButton" attribute on
- // the close button node.
- //
- // The widget may have one or more of the following states,
- // determined
- // by this.state, this.checked, this.valid, and this.selected:
- // Error - ValidationTextBox sets this.state to "Error" if the
- // current input value is invalid
- // Checked - ex: a checkmark or a ToggleButton in a checked state,
- // will have this.checked==true
- // Selected - ex: currently selected tab will have
- // this.selected==true
- //
- // In addition, it may have at most one of the following states,
- // based on this.disabled and flags set in _onMouse (this._active,
- // this._hovering, this._focused):
- // Disabled - if the widget is disabled
- // Active - if the mouse (or space/enter key?) is being pressed down
- // Focused - if the widget has focus
- // Hover - if the mouse is over the widget
- //
- // (even if multiple af the above conditions are true we only pick
- // the first matching one)
- // Get original (non state related, non baseClass related) class
- // specified in template
- if (!("staticClass" in this)) {
- this.staticClass = (this.stateNode || this.domNode).className;
- }
- // Compute new set of classes
- var classes = [this.baseClass];
- function multiply(modifier) {
- classes = classes.concat(dojo.map(classes, function(c) {
- return c + modifier;
- }));
- }
- if (this.checked) {
- multiply("Checked");
- }
- if (this.state) {
- multiply(this.state);
- }
- if (this.selected) {
- multiply("Selected");
- }
- // Only one of these four can be applied.
- // Active trumps Focused, Focused trumps Hover, and Disabled trumps
- // all.
- if (this.disabled) {
- multiply("Disabled");
- } else if (this._active) {
- multiply(this.stateModifier + "Active");
- } else {
- if (this._focused) {
- multiply("Focused");
- }
- if ((this.stateModifier || !this._focused) && this._hovering) {
- multiply(this.stateModifier + "Hover");
- }
- }
- (this.stateNode || this.domNode).className = this.staticClass + " "
- + classes.join(" ");
- },
- onChange : function(newValue) {
- // summary: callback when value is changed
- },
- postCreate : function() {
- this.setValue(this.value, null); // null reserved for initial
- // value
- this.setDisabled(this.disabled);
- this._setStateClass();
- },
- setValue : function(/* anything */newValue, /* Boolean, optional */
- priorityChange) {
- // summary: set the value of the widget.
- this._lastValue = newValue;
- dijit.setWaiState(this.focusNode || this.domNode, "valuenow", this
- .forWaiValuenow());
- if (priorityChange === undefined) {
- priorityChange = true;
- } // setValue with value only should fire onChange
- if (this._lastValueReported == undefined && priorityChange === null) { // don't
- // report
- // the
- // initial
- // value
- this._lastValueReported = newValue;
- }
- if ((this.intermediateChanges || priorityChange)
- && ((newValue && newValue.toString)
- ? newValue.toString()
- : newValue) !== ((this._lastValueReported && this._lastValueReported.toString)
- ? this._lastValueReported.toString()
- : this._lastValueReported)) {
- this._lastValueReported = newValue;
- this.onChange(newValue);
- }
- },
- getValue : function() {
- // summary: get the value of the widget.
- return this._lastValue;
- },
- undo : function() {
- // summary: restore the value to the last value passed to onChange
- this.setValue(this._lastValueReported, false);
- },
- _onKeyPress : function(e) {
- if (e.keyCode == dojo.keys.ESCAPE && !e.shiftKey && !e.ctrlKey
- && !e.altKey) {
- var v = this.getValue();
- var lv = this._lastValueReported;
- // Equality comparison of objects such as dates are done by
- // reference so
- // two distinct objects are != even if they have the same data.
- // So use
- // toStrings in case the values are objects.
- if ((typeof lv != "undefined")
- && ((v !== null && v.toString) ? v.toString() : null) !== lv
- .toString()) {
- this.undo();
- dojo.stopEvent(e);
- return false;
- }
- }
- return true;
- },
- forWaiValuenow : function() {
- // summary: returns a value, reflecting the current state of the
- // widget,
- // to be used for the ARIA valuenow.
- // This method may be overridden by subclasses that want
- // to use something other than this.getValue() for valuenow
- return this.getValue();
- }
- });
- }
- if (!dojo._hasResource["dijit.dijit"]) { // _hasResource checks added by
- // build. Do not use _hasResource
- // directly in your code.
- dojo._hasResource["dijit.dijit"] = true;
- dojo.provide("dijit.dijit");
- // All the stuff in _base (these are the function that are guaranteed
- // available without an explicit dojo.require)
- // And some other stuff that we tend to pull in all the time anyway
- }
|