summaryrefslogtreecommitdiff
path: root/lib/dijit/_base
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dijit/_base')
-rw-r--r--lib/dijit/_base/focus.js803
-rw-r--r--lib/dijit/_base/manager.js718
-rw-r--r--lib/dijit/_base/place.js449
-rw-r--r--lib/dijit/_base/popup.js533
-rw-r--r--lib/dijit/_base/scroll.js17
-rw-r--r--lib/dijit/_base/sniff.js15
-rw-r--r--lib/dijit/_base/typematic.js262
-rw-r--r--lib/dijit/_base/wai.js191
-rw-r--r--lib/dijit/_base/window.js13
9 files changed, 2098 insertions, 903 deletions
diff --git a/lib/dijit/_base/focus.js b/lib/dijit/_base/focus.js
index 32be06aa7..55c5b682d 100644
--- a/lib/dijit/_base/focus.js
+++ b/lib/dijit/_base/focus.js
@@ -1,299 +1,530 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
-if(!dojo._hasResource["dijit._base.focus"]){
-dojo._hasResource["dijit._base.focus"]=true;
+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");
dojo.require("dojo.window");
dojo.require("dijit._base.manager");
-dojo.mixin(dijit,{_curFocus:null,_prevFocus:null,isCollapsed:function(){
-return dijit.getBookmark().isCollapsed;
-},getBookmark:function(){
-var bm,rg,tg,_1=dojo.doc.selection,cf=dijit._curFocus;
-if(dojo.global.getSelection){
-_1=dojo.global.getSelection();
-if(_1){
-if(_1.isCollapsed){
-tg=cf?cf.tagName:"";
-if(tg){
-tg=tg.toLowerCase();
-if(tg=="textarea"||(tg=="input"&&(!cf.type||cf.type.toLowerCase()=="text"))){
-_1={start:cf.selectionStart,end:cf.selectionEnd,node:cf,pRange:true};
-return {isCollapsed:(_1.end<=_1.start),mark:_1};
-}
-}
-bm={isCollapsed:true};
-}else{
-rg=_1.getRangeAt(0);
-bm={isCollapsed:false,mark:rg.cloneRange()};
-}
-}
-}else{
-if(_1){
-tg=cf?cf.tagName:"";
-tg=tg.toLowerCase();
-if(cf&&tg&&(tg=="button"||tg=="textarea"||tg=="input")){
-if(_1.type&&_1.type.toLowerCase()=="none"){
-return {isCollapsed:true,mark:null};
-}else{
-rg=_1.createRange();
-return {isCollapsed:rg.text&&rg.text.length?false:true,mark:{range:rg,pRange:true}};
-}
-}
-bm={};
-try{
-rg=_1.createRange();
-bm.isCollapsed=!(_1.type=="Text"?rg.htmlText.length:rg.length);
-}
-catch(e){
-bm.isCollapsed=true;
-return bm;
-}
-if(_1.type.toUpperCase()=="CONTROL"){
-if(rg.length){
-bm.mark=[];
-var i=0,_2=rg.length;
-while(i<_2){
-bm.mark.push(rg.item(i++));
-}
-}else{
-bm.isCollapsed=true;
-bm.mark=null;
-}
-}else{
-bm.mark=rg.getBookmark();
-}
-}else{
-console.warn("No idea how to store the current selection for this browser!");
-}
-}
-return bm;
-},moveToBookmark:function(_3){
-var _4=dojo.doc,_5=_3.mark;
-if(_5){
-if(dojo.global.getSelection){
-var _6=dojo.global.getSelection();
-if(_6&&_6.removeAllRanges){
-if(_5.pRange){
-var r=_5;
-var n=r.node;
-n.selectionStart=r.start;
-n.selectionEnd=r.end;
-}else{
-_6.removeAllRanges();
-_6.addRange(_5);
-}
-}else{
-console.warn("No idea how to restore selection for this browser!");
-}
-}else{
-if(_4.selection&&_5){
-var rg;
-if(_5.pRange){
-rg=_5.range;
-}else{
-if(dojo.isArray(_5)){
-rg=_4.body.createControlRange();
-dojo.forEach(_5,function(n){
-rg.addElement(n);
+
+
+// summary:
+// These functions are used to query or set the focus and selection.
+//
+// Also, they trace when widgets become activated/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:
+ // Returns true if there is no text selected
+ return dijit.getBookmark().isCollapsed;
+ },
+
+ getBookmark: function(){
+ // summary:
+ // Retrieves a bookmark that can be used with moveToBookmark to return to the same range
+ var bm, rg, tg, sel = dojo.doc.selection, cf = dijit._curFocus;
+
+ if(dojo.global.getSelection){
+ //W3C Range API for selections.
+ sel = dojo.global.getSelection();
+ if(sel){
+ if(sel.isCollapsed){
+ tg = cf? cf.tagName : "";
+ if(tg){
+ //Create a fake rangelike item to restore selections.
+ tg = tg.toLowerCase();
+ if(tg == "textarea" ||
+ (tg == "input" && (!cf.type || cf.type.toLowerCase() == "text"))){
+ sel = {
+ start: cf.selectionStart,
+ end: cf.selectionEnd,
+ node: cf,
+ pRange: true
+ };
+ return {isCollapsed: (sel.end <= sel.start), mark: sel}; //Object.
+ }
+ }
+ bm = {isCollapsed:true};
+ if(sel.rangeCount){
+ bm.mark = sel.getRangeAt(0).cloneRange();
+ }
+ }else{
+ rg = sel.getRangeAt(0);
+ bm = {isCollapsed: false, mark: rg.cloneRange()};
+ }
+ }
+ }else if(sel){
+ // If the current focus was a input of some sort and no selection, don't bother saving
+ // a native bookmark. This is because it causes issues with dialog/page selection restore.
+ // So, we need to create psuedo bookmarks to work with.
+ tg = cf ? cf.tagName : "";
+ tg = tg.toLowerCase();
+ if(cf && tg && (tg == "button" || tg == "textarea" || tg == "input")){
+ if(sel.type && sel.type.toLowerCase() == "none"){
+ return {
+ isCollapsed: true,
+ mark: null
+ }
+ }else{
+ rg = sel.createRange();
+ return {
+ isCollapsed: rg.text && rg.text.length?false:true,
+ mark: {
+ range: rg,
+ pRange: true
+ }
+ };
+ }
+ }
+ bm = {};
+
+ //'IE' way for selections.
+ try{
+ // createRange() throws exception when dojo in iframe
+ //and nothing selected, see #9632
+ rg = sel.createRange();
+ bm.isCollapsed = !(sel.type == 'Text' ? rg.htmlText.length : rg.length);
+ }catch(e){
+ bm.isCollapsed = true;
+ return bm;
+ }
+ if(sel.type.toUpperCase() == 'CONTROL'){
+ if(rg.length){
+ bm.mark=[];
+ var i=0,len=rg.length;
+ while(i<len){
+ bm.mark.push(rg.item(i++));
+ }
+ }else{
+ bm.isCollapsed = true;
+ bm.mark = null;
+ }
+ }else{
+ bm.mark = rg.getBookmark();
+ }
+ }else{
+ console.warn("No idea how to store the current selection for this browser!");
+ }
+ return bm; // Object
+ },
+
+ moveToBookmark: function(/*Object*/bookmark){
+ // summary:
+ // Moves current selection to a bookmark
+ // bookmark:
+ // This should be a returned object from dijit.getBookmark()
+
+ var _doc = dojo.doc,
+ mark = bookmark.mark;
+ if(mark){
+ if(dojo.global.getSelection){
+ //W3C Rangi API (FF, WebKit, Opera, etc)
+ var sel = dojo.global.getSelection();
+ if(sel && sel.removeAllRanges){
+ if(mark.pRange){
+ var r = mark;
+ var n = r.node;
+ n.selectionStart = r.start;
+ n.selectionEnd = r.end;
+ }else{
+ sel.removeAllRanges();
+ sel.addRange(mark);
+ }
+ }else{
+ console.warn("No idea how to restore selection for this browser!");
+ }
+ }else if(_doc.selection && mark){
+ //'IE' way.
+ var rg;
+ if(mark.pRange){
+ rg = mark.range;
+ }else if(dojo.isArray(mark)){
+ rg = _doc.body.createControlRange();
+ //rg.addElement does not have call/apply method, so can not call it directly
+ //rg is not available in "range.addElement(item)", so can't use that either
+ dojo.forEach(mark, function(n){
+ rg.addElement(n);
+ });
+ }else{
+ rg = _doc.body.createTextRange();
+ rg.moveToBookmark(mark);
+ }
+ rg.select();
+ }
+ }
+ },
+
+ getFocus: function(/*Widget?*/ menu, /*Window?*/ openedForWindow){
+ // summary:
+ // Called as getFocus(), this returns an Object showing the current focus
+ // and selected text.
+ //
+ // Called as getFocus(widget), where widget is a (widget representing) a button
+ // that was just pressed, it returns where focus was before that button
+ // was pressed. (Pressing the button may have either shifted focus to the button,
+ // or removed focus altogether.) In this case the selected text is not returned,
+ // since it can't be accurately determined.
+ //
+ // menu: dijit._Widget or {domNode: DomNode} structure
+ // The button that was just pressed. If focus has disappeared or moved
+ // to this button, returns the previous focus. In this case the bookmark
+ // information is already lost, and null is returned.
+ //
+ // openedForWindow:
+ // iframe in which menu was opened
+ //
+ // returns:
+ // A handle to restore focus/selection, to be passed to `dijit.focus`
+ var node = !dijit._curFocus || (menu && dojo.isDescendant(dijit._curFocus, menu.domNode)) ? dijit._prevFocus : dijit._curFocus;
+ return {
+ node: node,
+ bookmark: (node == dijit._curFocus) && dojo.withGlobal(openedForWindow || dojo.global, dijit.getBookmark),
+ 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,
+ collapsed = bookmark ? bookmark.isCollapsed : false;
+
+ // 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) or if previous selection was collapsed
+ // as it may cause focus shift (Esp in IE).
+ if(bookmark && dojo.withGlobal(openedForWindow || dojo.global, dijit.isCollapsed) && !collapsed){
+ if(openedForWindow){
+ openedForWindow.focus();
+ }
+ try{
+ dojo.withGlobal(openedForWindow || dojo.global, dijit.moveToBookmark, null, [bookmark]);
+ }catch(e2){
+ /*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */
+ }
+ }
+ },
+
+ // _activeStack: dijit._Widget[]
+ // List of currently active widgets (focused widget and it's ancestors)
+ _activeStack: [],
+
+ registerIframe: function(/*DomNode*/ iframe){
+ // summary:
+ // Registers listeners on the specified iframe so that any click
+ // or focus event on that iframe (or anything in it) is reported
+ // as a focus/click event on the <iframe> itself.
+ // description:
+ // Currently only used by editor.
+ // returns:
+ // Handle to pass to unregisterIframe()
+ return dijit.registerWin(iframe.contentWindow, iframe);
+ },
+
+ unregisterIframe: function(/*Object*/ handle){
+ // summary:
+ // Unregisters listeners on the specified iframe created by registerIframe.
+ // After calling be sure to delete or null out the handle itself.
+ // handle:
+ // Handle returned by registerIframe()
+
+ dijit.unregisterWin(handle);
+ },
+
+ registerWin: function(/*Window?*/targetWindow, /*DomNode?*/ effectiveNode){
+ // summary:
+ // Registers listeners on the specified window (either the main
+ // window or an iframe's window) to detect when the user has clicked somewhere
+ // or focused somewhere.
+ // description:
+ // Users should call registerIframe() instead of this method.
+ // targetWindow:
+ // If specified this is the window associated with the iframe,
+ // i.e. iframe.contentWindow.
+ // effectiveNode:
+ // If specified, report any focus events inside targetWindow as
+ // an event on effectiveNode, rather than on evt.target.
+ // returns:
+ // Handle to pass to unregisterWin()
+
+ // TODO: make this function private in 2.0; Editor/users should call registerIframe(),
+
+ var mousedownListener = function(evt){
+ dijit._justMouseDowned = true;
+ setTimeout(function(){ dijit._justMouseDowned = false; }, 0);
+
+ // workaround weird IE bug where the click is on an orphaned node
+ // (first time clicking a Select/DropDownButton inside a TooltipDialog)
+ if(dojo.isIE && evt && evt.srcElement && evt.srcElement.parentNode == null){
+ return;
+ }
+
+ dijit._onTouchNode(effectiveNode || evt.target || evt.srcElement, "mouse");
+ };
+ //dojo.connect(targetWindow, "onscroll", ???);
+
+ // Listen for blur and focus events on targetWindow's document.
+ // IIRC, I'm using attachEvent() rather than dojo.connect() because focus/blur events don't bubble
+ // through dojo.connect(), and also maybe to catch the focus events early, before onfocus handlers
+ // fire.
+ // Connect to <html> (rather than document) on IE to avoid memory leaks, but document on other browsers because
+ // (at least for FF) the focus event doesn't fire on <html> or <body>.
+ var doc = dojo.isIE ? targetWindow.document.documentElement : targetWindow.document;
+ if(doc){
+ if(dojo.isIE){
+ targetWindow.document.body.attachEvent('onmousedown', mousedownListener);
+ var activateListener = function(evt){
+ // IE reports that nodes like <body> have gotten focus, even though they have tabIndex=-1,
+ // Should consider those more like a mouse-click than a focus....
+ if(evt.srcElement.tagName.toLowerCase() != "#document" &&
+ dijit.isTabNavigable(evt.srcElement)){
+ dijit._onFocusNode(effectiveNode || evt.srcElement);
+ }else{
+ dijit._onTouchNode(effectiveNode || evt.srcElement);
+ }
+ };
+ doc.attachEvent('onactivate', activateListener);
+ var deactivateListener = function(evt){
+ dijit._onBlurNode(effectiveNode || evt.srcElement);
+ };
+ doc.attachEvent('ondeactivate', deactivateListener);
+
+ return function(){
+ targetWindow.document.detachEvent('onmousedown', mousedownListener);
+ doc.detachEvent('onactivate', activateListener);
+ doc.detachEvent('ondeactivate', deactivateListener);
+ doc = null; // prevent memory leak (apparent circular reference via closure)
+ };
+ }else{
+ doc.body.addEventListener('mousedown', mousedownListener, true);
+ var focusListener = function(evt){
+ dijit._onFocusNode(effectiveNode || evt.target);
+ };
+ doc.addEventListener('focus', focusListener, true);
+ var blurListener = function(evt){
+ dijit._onBlurNode(effectiveNode || evt.target);
+ };
+ doc.addEventListener('blur', blurListener, true);
+
+ return function(){
+ doc.body.removeEventListener('mousedown', mousedownListener, true);
+ doc.removeEventListener('focus', focusListener, true);
+ doc.removeEventListener('blur', blurListener, true);
+ doc = null; // prevent memory leak (apparent circular reference via closure)
+ };
+ }
+ }
+ },
+
+ unregisterWin: function(/*Handle*/ handle){
+ // summary:
+ // Unregisters listeners on the specified window (either the main
+ // window or an iframe's window) according to handle returned from registerWin().
+ // After calling be sure to delete or null out the handle itself.
+
+ // Currently our handle is actually a function
+ handle && handle();
+ },
+
+ _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;
+
+ 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([]);
+ dijit._prevFocus = null;
+ }, 100);
+ },
+
+ _onTouchNode: function(/*DomNode*/ node, /*String*/ by){
+ // summary:
+ // Callback when node is focused or mouse-downed
+ // node:
+ // The node that was touched.
+ // by:
+ // "mouse" if the focus/touch was caused by a mouse down event
+
+ // 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){
+ var popupParent = dojo.attr(node, "dijitPopupParent");
+ if(popupParent){
+ node=dijit.byId(popupParent).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). window.frameElement is supported in IE/FF/Webkit
+ node=dojo.window.get(node.ownerDocument).frameElement;
+ }else{
+ // if this node is the root node of a widget, then add widget id to stack,
+ // except ignore clicks on disabled widgets (actually focusing a disabled widget still works,
+ // to support MenuItem)
+ var id = node.getAttribute && node.getAttribute("widgetId"),
+ widget = id && dijit.byId(id);
+ if(widget && !(by == "mouse" && widget.get("disabled"))){
+ newStack.unshift(id);
+ }
+ node=node.parentNode;
+ }
+ }
+ }catch(e){ /* squelch */ }
+
+ dijit._setStack(newStack, by);
+ },
+
+ _onFocusNode: function(/*DomNode*/ node){
+ // summary:
+ // Callback when node is focused
+
+ if(!node){
+ return;
+ }
+
+ if(node.nodeType == 9){
+ // Ignore focus events on the document itself. This is here so that
+ // (for example) clicking the up/down arrows of a spinner
+ // (which don't get focus) won't cause that widget to blur. (FF issue)
+ return;
+ }
+
+ dijit._onTouchNode(node);
+
+ if(node == dijit._curFocus){ return; }
+ if(dijit._curFocus){
+ dijit._prevFocus = dijit._curFocus;
+ }
+ dijit._curFocus = node;
+ dojo.publish("focusNode", [node]);
+ },
+
+ _setStack: function(/*String[]*/ newStack, /*String*/ by){
+ // summary:
+ // The stack of active widgets has changed. Send out appropriate events and records new stack.
+ // newStack:
+ // array of widget id's, starting from the top (outermost) widget
+ // by:
+ // "mouse" if the focus/touch was caused by a mouse down event
+
+ 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;
+ }
+ }
+
+ var widget;
+ // for all elements that have gone out of focus, send blur event
+ for(var i=oldStack.length-1; i>=nCommon; i--){
+ widget = dijit.byId(oldStack[i]);
+ if(widget){
+ widget._focused = false;
+ widget.set("focused", false);
+ widget._hasBeenBlurred = true;
+ if(widget._onBlur){
+ widget._onBlur(by);
+ }
+ dojo.publish("widgetBlur", [widget, by]);
+ }
+ }
+
+ // for all element that have come into focus, send focus event
+ for(i=nCommon; i<newStack.length; i++){
+ widget = dijit.byId(newStack[i]);
+ if(widget){
+ widget._focused = true;
+ widget.set("focused", true);
+ if(widget._onFocus){
+ widget._onFocus(by);
+ }
+ dojo.publish("widgetFocus", [widget, by]);
+ }
+ }
+ }
});
-}else{
-rg=_4.body.createTextRange();
-rg.moveToBookmark(_5);
-}
-}
-rg.select();
-}
-}
-}
-},getFocus:function(_7,_8){
-var _9=!dijit._curFocus||(_7&&dojo.isDescendant(dijit._curFocus,_7.domNode))?dijit._prevFocus:dijit._curFocus;
-return {node:_9,bookmark:(_9==dijit._curFocus)&&dojo.withGlobal(_8||dojo.global,dijit.getBookmark),openedForWindow:_8};
-},focus:function(_a){
-if(!_a){
-return;
-}
-var _b="node" in _a?_a.node:_a,_c=_a.bookmark,_d=_a.openedForWindow,_e=_c?_c.isCollapsed:false;
-if(_b){
-var _f=(_b.tagName.toLowerCase()=="iframe")?_b.contentWindow:_b;
-if(_f&&_f.focus){
-try{
-_f.focus();
-}
-catch(e){
-}
-}
-dijit._onFocusNode(_b);
-}
-if(_c&&dojo.withGlobal(_d||dojo.global,dijit.isCollapsed)&&!_e){
-if(_d){
-_d.focus();
-}
-try{
-dojo.withGlobal(_d||dojo.global,dijit.moveToBookmark,null,[_c]);
-}
-catch(e2){
-}
-}
-},_activeStack:[],registerIframe:function(_10){
-return dijit.registerWin(_10.contentWindow,_10);
-},unregisterIframe:function(_11){
-dijit.unregisterWin(_11);
-},registerWin:function(_12,_13){
-var _14=function(evt){
-dijit._justMouseDowned=true;
-setTimeout(function(){
-dijit._justMouseDowned=false;
-},0);
-if(dojo.isIE&&evt&&evt.srcElement&&evt.srcElement.parentNode==null){
-return;
-}
-dijit._onTouchNode(_13||evt.target||evt.srcElement,"mouse");
-};
-var doc=dojo.isIE?_12.document.documentElement:_12.document;
-if(doc){
-if(dojo.isIE){
-doc.attachEvent("onmousedown",_14);
-var _15=function(evt){
-if(evt.srcElement.tagName.toLowerCase()!="#document"&&dijit.isTabNavigable(evt.srcElement)){
-dijit._onFocusNode(_13||evt.srcElement);
-}else{
-dijit._onTouchNode(_13||evt.srcElement);
-}
-};
-doc.attachEvent("onactivate",_15);
-var _16=function(evt){
-dijit._onBlurNode(_13||evt.srcElement);
-};
-doc.attachEvent("ondeactivate",_16);
-return function(){
-doc.detachEvent("onmousedown",_14);
-doc.detachEvent("onactivate",_15);
-doc.detachEvent("ondeactivate",_16);
-doc=null;
-};
-}else{
-doc.addEventListener("mousedown",_14,true);
-var _17=function(evt){
-dijit._onFocusNode(_13||evt.target);
-};
-doc.addEventListener("focus",_17,true);
-var _18=function(evt){
-dijit._onBlurNode(_13||evt.target);
-};
-doc.addEventListener("blur",_18,true);
-return function(){
-doc.removeEventListener("mousedown",_14,true);
-doc.removeEventListener("focus",_17,true);
-doc.removeEventListener("blur",_18,true);
-doc=null;
-};
-}
-}
-},unregisterWin:function(_19){
-_19&&_19();
-},_onBlurNode:function(_1a){
-dijit._prevFocus=dijit._curFocus;
-dijit._curFocus=null;
-if(dijit._justMouseDowned){
-return;
-}
-if(dijit._clearActiveWidgetsTimer){
-clearTimeout(dijit._clearActiveWidgetsTimer);
-}
-dijit._clearActiveWidgetsTimer=setTimeout(function(){
-delete dijit._clearActiveWidgetsTimer;
-dijit._setStack([]);
-dijit._prevFocus=null;
-},100);
-},_onTouchNode:function(_1b,by){
-if(dijit._clearActiveWidgetsTimer){
-clearTimeout(dijit._clearActiveWidgetsTimer);
-delete dijit._clearActiveWidgetsTimer;
-}
-var _1c=[];
-try{
-while(_1b){
-var _1d=dojo.attr(_1b,"dijitPopupParent");
-if(_1d){
-_1b=dijit.byId(_1d).domNode;
-}else{
-if(_1b.tagName&&_1b.tagName.toLowerCase()=="body"){
-if(_1b===dojo.body()){
-break;
-}
-_1b=dojo.window.get(_1b.ownerDocument).frameElement;
-}else{
-var id=_1b.getAttribute&&_1b.getAttribute("widgetId"),_1e=id&&dijit.byId(id);
-if(_1e&&!(by=="mouse"&&_1e.get("disabled"))){
-_1c.unshift(id);
-}
-_1b=_1b.parentNode;
-}
-}
-}
-}
-catch(e){
-}
-dijit._setStack(_1c,by);
-},_onFocusNode:function(_1f){
-if(!_1f){
-return;
-}
-if(_1f.nodeType==9){
-return;
-}
-dijit._onTouchNode(_1f);
-if(_1f==dijit._curFocus){
-return;
-}
-if(dijit._curFocus){
-dijit._prevFocus=dijit._curFocus;
-}
-dijit._curFocus=_1f;
-dojo.publish("focusNode",[_1f]);
-},_setStack:function(_20,by){
-var _21=dijit._activeStack;
-dijit._activeStack=_20;
-for(var _22=0;_22<Math.min(_21.length,_20.length);_22++){
-if(_21[_22]!=_20[_22]){
-break;
-}
-}
-var _23;
-for(var i=_21.length-1;i>=_22;i--){
-_23=dijit.byId(_21[i]);
-if(_23){
-_23._focused=false;
-_23._hasBeenBlurred=true;
-if(_23._onBlur){
-_23._onBlur(by);
-}
-dojo.publish("widgetBlur",[_23,by]);
-}
-}
-for(i=_22;i<_20.length;i++){
-_23=dijit.byId(_20[i]);
-if(_23){
-_23._focused=true;
-if(_23._onFocus){
-_23._onFocus(by);
-}
-dojo.publish("widgetFocus",[_23,by]);
-}
-}
-}});
+
+// register top window and all the iframes it contains
dojo.addOnLoad(function(){
-var _24=dijit.registerWin(window);
-if(dojo.isIE){
-dojo.addOnWindowUnload(function(){
-dijit.unregisterWin(_24);
-_24=null;
-});
-}
+ var handle = dijit.registerWin(window);
+ if(dojo.isIE){
+ dojo.addOnWindowUnload(function(){
+ dijit.unregisterWin(handle);
+ handle = null;
+ })
+ }
});
+
}
diff --git a/lib/dijit/_base/manager.js b/lib/dijit/_base/manager.js
index d8d1cf6d5..e5f745622 100644
--- a/lib/dijit/_base/manager.js
+++ b/lib/dijit/_base/manager.js
@@ -1,245 +1,493 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
-if(!dojo._hasResource["dijit._base.manager"]){
-dojo._hasResource["dijit._base.manager"]=true;
+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(){
-this._hash={};
-this.length=0;
-},add:function(_1){
-if(this._hash[_1.id]){
-throw new Error("Tried to register widget with id=="+_1.id+" but that id is already registered");
-}
-this._hash[_1.id]=_1;
-this.length++;
-},remove:function(id){
-if(this._hash[id]){
-delete this._hash[id];
-this.length--;
-}
-},forEach:function(_2,_3){
-_3=_3||dojo.global;
-var i=0,id;
-for(id in this._hash){
-_2.call(_3,this._hash[id],i++,this._hash);
-}
-return this;
-},filter:function(_4,_5){
-_5=_5||dojo.global;
-var _6=new dijit.WidgetSet(),i=0,id;
-for(id in this._hash){
-var w=this._hash[id];
-if(_4.call(_5,w,i++,this._hash)){
-_6.add(w);
-}
-}
-return _6;
-},byId:function(id){
-return this._hash[id];
-},byClass:function(_7){
-var _8=new dijit.WidgetSet(),id,_9;
-for(id in this._hash){
-_9=this._hash[id];
-if(_9.declaredClass==_7){
-_8.add(_9);
-}
-}
-return _8;
-},toArray:function(){
-var ar=[];
-for(var id in this._hash){
-ar.push(this._hash[id]);
-}
-return ar;
-},map:function(_a,_b){
-return dojo.map(this.toArray(),_a,_b);
-},every:function(_c,_d){
-_d=_d||dojo.global;
-var x=0,i;
-for(i in this._hash){
-if(!_c.call(_d,this._hash[i],x++,this._hash)){
-return false;
-}
-}
-return true;
-},some:function(_e,_f){
-_f=_f||dojo.global;
-var x=0,i;
-for(i in this._hash){
-if(_e.call(_f,this._hash[i],x++,this._hash)){
-return true;
-}
-}
-return false;
-}});
-(function(){
-dijit.registry=new dijit.WidgetSet();
-var _10=dijit.registry._hash,_11=dojo.attr,_12=dojo.hasAttr,_13=dojo.style;
-dijit.byId=function(id){
-return typeof id=="string"?_10[id]:id;
-};
-var _14={};
-dijit.getUniqueId=function(_15){
-var id;
-do{
-id=_15+"_"+(_15 in _14?++_14[_15]:_14[_15]=0);
-}while(_10[id]);
-return dijit._scopeName=="dijit"?id:dijit._scopeName+"_"+id;
-};
-dijit.findWidgets=function(_16){
-var _17=[];
-function _18(_19){
-for(var _1a=_19.firstChild;_1a;_1a=_1a.nextSibling){
-if(_1a.nodeType==1){
-var _1b=_1a.getAttribute("widgetId");
-if(_1b){
-_17.push(_10[_1b]);
-}else{
-_18(_1a);
-}
-}
-}
-};
-_18(_16);
-return _17;
-};
-dijit._destroyAll=function(){
-dijit._curFocus=null;
-dijit._prevFocus=null;
-dijit._activeStack=[];
-dojo.forEach(dijit.findWidgets(dojo.body()),function(_1c){
-if(!_1c._destroyed){
-if(_1c.destroyRecursive){
-_1c.destroyRecursive();
-}else{
-if(_1c.destroy){
-_1c.destroy();
-}
-}
-}
-});
-};
-if(dojo.isIE){
-dojo.addOnWindowUnload(function(){
-dijit._destroyAll();
-});
-}
-dijit.byNode=function(_1d){
-return _10[_1d.getAttribute("widgetId")];
-};
-dijit.getEnclosingWidget=function(_1e){
-while(_1e){
-var id=_1e.getAttribute&&_1e.getAttribute("widgetId");
-if(id){
-return _10[id];
-}
-_1e=_1e.parentNode;
-}
-return null;
-};
-var _1f=(dijit._isElementShown=function(_20){
-var s=_13(_20);
-return (s.visibility!="hidden")&&(s.visibility!="collapsed")&&(s.display!="none")&&(_11(_20,"type")!="hidden");
-});
-dijit.hasDefaultTabStop=function(_21){
-switch(_21.nodeName.toLowerCase()){
-case "a":
-return _12(_21,"href");
-case "area":
-case "button":
-case "input":
-case "object":
-case "select":
-case "textarea":
-return true;
-case "iframe":
-if(dojo.isMoz){
-try{
-return _21.contentDocument.designMode=="on";
-}
-catch(err){
-return false;
-}
-}else{
-if(dojo.isWebKit){
-var doc=_21.contentDocument,_22=doc&&doc.body;
-return _22&&_22.contentEditable=="true";
-}else{
-try{
-doc=_21.contentWindow.document;
-_22=doc&&doc.body;
-return _22&&_22.firstChild&&_22.firstChild.contentEditable=="true";
-}
-catch(e){
-return false;
-}
-}
-}
-default:
-return _21.contentEditable=="true";
-}
-};
-var _23=(dijit.isTabNavigable=function(_24){
-if(_11(_24,"disabled")){
-return false;
-}else{
-if(_12(_24,"tabIndex")){
-return _11(_24,"tabIndex")>=0;
-}else{
-return dijit.hasDefaultTabStop(_24);
-}
-}
-});
-dijit._getTabNavigable=function(_25){
-var _26,_27,_28,_29,_2a,_2b;
-var _2c=function(_2d){
-dojo.query("> *",_2d).forEach(function(_2e){
-if((dojo.isIE&&_2e.scopeName!=="HTML")||!_1f(_2e)){
-return;
-}
-if(_23(_2e)){
-var _2f=_11(_2e,"tabIndex");
-if(!_12(_2e,"tabIndex")||_2f==0){
-if(!_26){
-_26=_2e;
-}
-_27=_2e;
-}else{
-if(_2f>0){
-if(!_28||_2f<_29){
-_29=_2f;
-_28=_2e;
-}
-if(!_2a||_2f>=_2b){
-_2b=_2f;
-_2a=_2e;
-}
-}
-}
-}
-if(_2e.nodeName.toUpperCase()!="SELECT"){
-_2c(_2e);
-}
+
+
+dojo.declare("dijit.WidgetSet", null, {
+ // summary:
+ // A set of widgets indexed by id. A default instance of this class is
+ // available as `dijit.registry`
+ //
+ // example:
+ // Create a small list of widgets:
+ // | var ws = new dijit.WidgetSet();
+ // | ws.add(dijit.byId("one"));
+ // | ws.add(dijit.byId("two"));
+ // | // destroy both:
+ // | ws.forEach(function(w){ w.destroy(); });
+ //
+ // example:
+ // Using dijit.registry:
+ // | dijit.registry.forEach(function(w){ /* do something */ });
+
+ constructor: function(){
+ this._hash = {};
+ this.length = 0;
+ },
+
+ add: function(/*dijit._Widget*/ widget){
+ // summary:
+ // Add a widget to this list. If a duplicate ID is detected, a error is thrown.
+ //
+ // widget: dijit._Widget
+ // Any dijit._Widget subclass.
+ 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;
+ this.length++;
+ },
+
+ remove: function(/*String*/ id){
+ // summary:
+ // Remove a widget from this WidgetSet. Does not destroy the widget; simply
+ // removes the reference.
+ if(this._hash[id]){
+ delete this._hash[id];
+ this.length--;
+ }
+ },
+
+ forEach: function(/*Function*/ func, /* Object? */thisObj){
+ // summary:
+ // Call specified function for each widget in this set.
+ //
+ // func:
+ // A callback function to run for each item. Is passed the widget, the index
+ // in the iteration, and the full hash, similar to `dojo.forEach`.
+ //
+ // thisObj:
+ // An optional scope parameter
+ //
+ // example:
+ // Using the default `dijit.registry` instance:
+ // | dijit.registry.forEach(function(widget){
+ // | console.log(widget.declaredClass);
+ // | });
+ //
+ // returns:
+ // Returns self, in order to allow for further chaining.
+
+ thisObj = thisObj || dojo.global;
+ var i = 0, id;
+ for(id in this._hash){
+ func.call(thisObj, this._hash[id], i++, this._hash);
+ }
+ return this; // dijit.WidgetSet
+ },
+
+ filter: function(/*Function*/ filter, /* Object? */thisObj){
+ // summary:
+ // Filter down this WidgetSet to a smaller new WidgetSet
+ // Works the same as `dojo.filter` and `dojo.NodeList.filter`
+ //
+ // filter:
+ // Callback function to test truthiness. Is passed the widget
+ // reference and the pseudo-index in the object.
+ //
+ // thisObj: Object?
+ // Option scope to use for the filter function.
+ //
+ // example:
+ // Arbitrary: select the odd widgets in this list
+ // | dijit.registry.filter(function(w, i){
+ // | return i % 2 == 0;
+ // | }).forEach(function(w){ /* odd ones */ });
+
+ thisObj = thisObj || dojo.global;
+ var res = new dijit.WidgetSet(), i = 0, id;
+ for(id in this._hash){
+ var w = this._hash[id];
+ if(filter.call(thisObj, w, i++, this._hash)){
+ res.add(w);
+ }
+ }
+ return res; // dijit.WidgetSet
+ },
+
+ byId: function(/*String*/ id){
+ // summary:
+ // Find a widget in this list by it's id.
+ // example:
+ // Test if an id is in a particular WidgetSet
+ // | var ws = new dijit.WidgetSet();
+ // | ws.add(dijit.byId("bar"));
+ // | var t = ws.byId("bar") // returns a widget
+ // | var x = ws.byId("foo"); // returns undefined
+
+ return this._hash[id]; // dijit._Widget
+ },
+
+ byClass: function(/*String*/ cls){
+ // summary:
+ // Reduce this widgetset to a new WidgetSet of a particular `declaredClass`
+ //
+ // cls: String
+ // The Class to scan for. Full dot-notated string.
+ //
+ // example:
+ // Find all `dijit.TitlePane`s in a page:
+ // | dijit.registry.byClass("dijit.TitlePane").forEach(function(tp){ tp.close(); });
+
+ var res = new dijit.WidgetSet(), id, widget;
+ for(id in this._hash){
+ widget = this._hash[id];
+ if(widget.declaredClass == cls){
+ res.add(widget);
+ }
+ }
+ return res; // dijit.WidgetSet
+},
+
+ toArray: function(){
+ // summary:
+ // Convert this WidgetSet into a true Array
+ //
+ // example:
+ // Work with the widget .domNodes in a real Array
+ // | dojo.map(dijit.registry.toArray(), function(w){ return w.domNode; });
+
+ var ar = [];
+ for(var id in this._hash){
+ ar.push(this._hash[id]);
+ }
+ return ar; // dijit._Widget[]
+},
+
+ map: function(/* Function */func, /* Object? */thisObj){
+ // summary:
+ // Create a new Array from this WidgetSet, following the same rules as `dojo.map`
+ // example:
+ // | var nodes = dijit.registry.map(function(w){ return w.domNode; });
+ //
+ // returns:
+ // A new array of the returned values.
+ return dojo.map(this.toArray(), func, thisObj); // Array
+ },
+
+ every: function(func, thisObj){
+ // summary:
+ // A synthetic clone of `dojo.every` acting explicitly on this WidgetSet
+ //
+ // func: Function
+ // A callback function run for every widget in this list. Exits loop
+ // when the first false return is encountered.
+ //
+ // thisObj: Object?
+ // Optional scope parameter to use for the callback
+
+ thisObj = thisObj || dojo.global;
+ var x = 0, i;
+ for(i in this._hash){
+ if(!func.call(thisObj, this._hash[i], x++, this._hash)){
+ return false; // Boolean
+ }
+ }
+ return true; // Boolean
+ },
+
+ some: function(func, thisObj){
+ // summary:
+ // A synthetic clone of `dojo.some` acting explictly on this WidgetSet
+ //
+ // func: Function
+ // A callback function run for every widget in this list. Exits loop
+ // when the first true return is encountered.
+ //
+ // thisObj: Object?
+ // Optional scope parameter to use for the callback
+
+ thisObj = thisObj || dojo.global;
+ var x = 0, i;
+ for(i in this._hash){
+ if(func.call(thisObj, this._hash[i], x++, this._hash)){
+ return true; // Boolean
+ }
+ }
+ return false; // Boolean
+ }
+
});
-};
-if(_1f(_25)){
-_2c(_25);
-}
-return {first:_26,last:_27,lowest:_28,highest:_2a};
-};
-dijit.getFirstInTabbingOrder=function(_30){
-var _31=dijit._getTabNavigable(dojo.byId(_30));
-return _31.lowest?_31.lowest:_31.first;
-};
-dijit.getLastInTabbingOrder=function(_32){
-var _33=dijit._getTabNavigable(dojo.byId(_32));
-return _33.last?_33.last:_33.highest;
-};
-dijit.defaultDuration=dojo.config["defaultDuration"]||200;
+
+(function(){
+
+ /*=====
+ dijit.registry = {
+ // summary:
+ // A list of widgets on a page.
+ // description:
+ // Is an instance of `dijit.WidgetSet`
+ };
+ =====*/
+ dijit.registry = new dijit.WidgetSet();
+
+ var hash = dijit.registry._hash,
+ attr = dojo.attr,
+ hasAttr = dojo.hasAttr,
+ style = dojo.style;
+
+ dijit.byId = function(/*String|dijit._Widget*/ id){
+ // summary:
+ // Returns a widget by it's id, or if passed a widget, no-op (like dojo.byId())
+ return typeof id == "string" ? hash[id] : id; // dijit._Widget
+ };
+
+ var _widgetTypeCtr = {};
+ dijit.getUniqueId = function(/*String*/widgetType){
+ // summary:
+ // Generates a unique id for a given widgetType
+
+ var id;
+ do{
+ id = widgetType + "_" +
+ (widgetType in _widgetTypeCtr ?
+ ++_widgetTypeCtr[widgetType] : _widgetTypeCtr[widgetType] = 0);
+ }while(hash[id]);
+ return dijit._scopeName == "dijit" ? id : dijit._scopeName + "_" + id; // String
+ };
+
+ dijit.findWidgets = function(/*DomNode*/ root){
+ // summary:
+ // Search subtree under root returning widgets found.
+ // Doesn't search for nested widgets (ie, widgets inside other widgets).
+
+ var outAry = [];
+
+ function getChildrenHelper(root){
+ for(var node = root.firstChild; node; node = node.nextSibling){
+ if(node.nodeType == 1){
+ var widgetId = node.getAttribute("widgetId");
+ if(widgetId){
+ var widget = hash[widgetId];
+ if(widget){ // may be null on page w/multiple dojo's loaded
+ outAry.push(widget);
+ }
+ }else{
+ getChildrenHelper(node);
+ }
+ }
+ }
+ }
+
+ getChildrenHelper(root);
+ return outAry;
+ };
+
+ dijit._destroyAll = function(){
+ // summary:
+ // Code to destroy all widgets and do other cleanup on page unload
+
+ // Clean up focus manager lingering references to widgets and nodes
+ dijit._curFocus = null;
+ dijit._prevFocus = null;
+ dijit._activeStack = [];
+
+ // Destroy all the widgets, top down
+ dojo.forEach(dijit.findWidgets(dojo.body()), function(widget){
+ // Avoid double destroy of widgets like Menu that are attached to <body>
+ // even though they are logically children of other widgets.
+ if(!widget._destroyed){
+ if(widget.destroyRecursive){
+ widget.destroyRecursive();
+ }else if(widget.destroy){
+ widget.destroy();
+ }
+ }
+ });
+ };
+
+ if(dojo.isIE){
+ // Only run _destroyAll() 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.addOnWindowUnload(function(){
+ dijit._destroyAll();
+ });
+ }
+
+ dijit.byNode = function(/*DOMNode*/ node){
+ // summary:
+ // Returns the widget corresponding to the given DOMNode
+ return hash[node.getAttribute("widgetId")]; // dijit._Widget
+ };
+
+ dijit.getEnclosingWidget = function(/*DOMNode*/ node){
+ // summary:
+ // Returns the widget whose DOM tree contains the specified DOMNode, or null if
+ // the node is not contained within the DOM tree of any widget
+ while(node){
+ var id = node.getAttribute && node.getAttribute("widgetId");
+ if(id){
+ return hash[id];
+ }
+ node = node.parentNode;
+ }
+ return null;
+ };
+
+ var shown = (dijit._isElementShown = function(/*Element*/ elem){
+ var s = style(elem);
+ return (s.visibility != "hidden")
+ && (s.visibility != "collapsed")
+ && (s.display != "none")
+ && (attr(elem, "type") != "hidden");
+ });
+
+ dijit.hasDefaultTabStop = function(/*Element*/ elem){
+ // summary:
+ // Tests if element is tab-navigable even without an explicit tabIndex setting
+
+ // No explicit tabIndex setting, need to investigate node type
+ switch(elem.nodeName.toLowerCase()){
+ case "a":
+ // An <a> w/out a tabindex is only navigable if it has an href
+ return hasAttr(elem, "href");
+ case "area":
+ case "button":
+ case "input":
+ case "object":
+ case "select":
+ case "textarea":
+ // These are navigable by default
+ return true;
+ case "iframe":
+ // If it's an editor <iframe> then it's tab navigable.
+ var body;
+ try{
+ // non-IE
+ var contentDocument = elem.contentDocument;
+ if("designMode" in contentDocument && contentDocument.designMode == "on"){
+ return true;
+ }
+ body = contentDocument.body;
+ }catch(e1){
+ // contentWindow.document isn't accessible within IE7/8
+ // if the iframe.src points to a foreign url and this
+ // page contains an element, that could get focus
+ try{
+ body = elem.contentWindow.document.body;
+ }catch(e2){
+ return false;
+ }
+ }
+ return body.contentEditable == 'true' || (body.firstChild && body.firstChild.contentEditable == 'true');
+ default:
+ return elem.contentEditable == 'true';
+ }
+ };
+
+ var isTabNavigable = (dijit.isTabNavigable = function(/*Element*/ elem){
+ // summary:
+ // Tests if an element is tab-navigable
+
+ // TODO: convert (and rename method) to return effective tabIndex; will save time in _getTabNavigable()
+ if(attr(elem, "disabled")){
+ return false;
+ }else if(hasAttr(elem, "tabIndex")){
+ // Explicit tab index setting
+ return attr(elem, "tabIndex") >= 0; // boolean
+ }else{
+ // No explicit tabIndex setting, so depends on node type
+ return dijit.hasDefaultTabStop(elem);
+ }
+ });
+
+ dijit._getTabNavigable = function(/*DOMNode*/ root){
+ // summary:
+ // Finds descendants of the specified root node.
+ //
+ // description:
+ // Finds the following descendants of the specified root node:
+ // * the first tab-navigable element in document order
+ // without a tabIndex or with tabIndex="0"
+ // * the last tab-navigable element in document order
+ // without a tabIndex or with tabIndex="0"
+ // * the first element in document order with the lowest
+ // positive tabIndex value
+ // * the last element in document order with the highest
+ // positive tabIndex value
+ var first, last, lowest, lowestTabindex, highest, highestTabindex, radioSelected = {};
+ function radioName(node) {
+ // If this element is part of a radio button group, return the name for that group.
+ return node && node.tagName.toLowerCase() == "input" &&
+ node.type && node.type.toLowerCase() == "radio" &&
+ node.name && node.name.toLowerCase();
+ }
+ var walkTree = function(/*DOMNode*/parent){
+ dojo.query("> *", parent).forEach(function(child){
+ // Skip hidden elements, and also non-HTML elements (those in custom namespaces) in IE,
+ // since show() invokes getAttribute("type"), which crash on VML nodes in IE.
+ if((dojo.isIE && child.scopeName!=="HTML") || !shown(child)){
+ return;
+ }
+
+ if(isTabNavigable(child)){
+ var tabindex = attr(child, "tabIndex");
+ if(!hasAttr(child, "tabIndex") || tabindex == 0){
+ if(!first){ first = child; }
+ last = child;
+ }else if(tabindex > 0){
+ if(!lowest || tabindex < lowestTabindex){
+ lowestTabindex = tabindex;
+ lowest = child;
+ }
+ if(!highest || tabindex >= highestTabindex){
+ highestTabindex = tabindex;
+ highest = child;
+ }
+ }
+ var rn = radioName(child);
+ if(dojo.attr(child, "checked") && rn) {
+ radioSelected[rn] = child;
+ }
+ }
+ if(child.nodeName.toUpperCase() != 'SELECT'){
+ walkTree(child);
+ }
+ });
+ };
+ if(shown(root)){ walkTree(root) }
+ function rs(node) {
+ // substitute checked radio button for unchecked one, if there is a checked one with the same name.
+ return radioSelected[radioName(node)] || node;
+ }
+ return { first: rs(first), last: rs(last), lowest: rs(lowest), highest: rs(highest) };
+ }
+ dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/ root){
+ // summary:
+ // Finds the descendant of the specified root node
+ // that is first in the tabbing order
+ var elems = dijit._getTabNavigable(dojo.byId(root));
+ return elems.lowest ? elems.lowest : elems.first; // DomNode
+ };
+
+ dijit.getLastInTabbingOrder = function(/*String|DOMNode*/ root){
+ // summary:
+ // Finds the descendant of the specified root node
+ // that is last in the tabbing order
+ var elems = dijit._getTabNavigable(dojo.byId(root));
+ return elems.last ? elems.last : elems.highest; // DomNode
+ };
+
+ /*=====
+ dojo.mixin(dijit, {
+ // defaultDuration: Integer
+ // The default animation speed (in ms) to use for all Dijit
+ // transitional animations, unless otherwise specified
+ // on a per-instance basis. Defaults to 200, overrided by
+ // `djConfig.defaultDuration`
+ defaultDuration: 200
+ });
+ =====*/
+
+ dijit.defaultDuration = dojo.config["defaultDuration"] || 200;
+
})();
+
}
diff --git a/lib/dijit/_base/place.js b/lib/dijit/_base/place.js
index ddc38fd08..a098f2fa4 100644
--- a/lib/dijit/_base/place.js
+++ b/lib/dijit/_base/place.js
@@ -1,111 +1,376 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
-if(!dojo._hasResource["dijit._base.place"]){
-dojo._hasResource["dijit._base.place"]=true;
+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");
dojo.require("dojo.window");
dojo.require("dojo.AdapterRegistry");
-dijit.getViewport=function(){
-return dojo.window.getBox();
-};
-dijit.placeOnScreen=function(_1,_2,_3,_4){
-var _5=dojo.map(_3,function(_6){
-var c={corner:_6,pos:{x:_2.x,y:_2.y}};
-if(_4){
-c.pos.x+=_6.charAt(1)=="L"?_4.x:-_4.x;
-c.pos.y+=_6.charAt(0)=="T"?_4.y:-_4.y;
-}
-return c;
-});
-return dijit._place(_1,_5);
+
+
+dijit.getViewport = function(){
+ // summary:
+ // Returns the dimensions and scroll position of the viewable area of a browser window
+
+ return dojo.window.getBox();
};
-dijit._place=function(_7,_8,_9){
-var _a=dojo.window.getBox();
-if(!_7.parentNode||String(_7.parentNode.tagName).toLowerCase()!="body"){
-dojo.body().appendChild(_7);
-}
-var _b=null;
-dojo.some(_8,function(_c){
-var _d=_c.corner;
-var _e=_c.pos;
-if(_9){
-_9(_7,_c.aroundCorner,_d);
+
+/*=====
+dijit.__Position = function(){
+ // x: Integer
+ // horizontal coordinate in pixels, relative to document body
+ // y: Integer
+ // vertical coordinate in pixels, relative to document body
+
+ thix.x = x;
+ this.y = y;
}
-var _f=_7.style;
-var _10=_f.display;
-var _11=_f.visibility;
-_f.visibility="hidden";
-_f.display="";
-var mb=dojo.marginBox(_7);
-_f.display=_10;
-_f.visibility=_11;
-var _12=Math.max(_a.l,_d.charAt(1)=="L"?_e.x:(_e.x-mb.w)),_13=Math.max(_a.t,_d.charAt(0)=="T"?_e.y:(_e.y-mb.h)),_14=Math.min(_a.l+_a.w,_d.charAt(1)=="L"?(_12+mb.w):_e.x),_15=Math.min(_a.t+_a.h,_d.charAt(0)=="T"?(_13+mb.h):_e.y),_16=_14-_12,_17=_15-_13,_18=(mb.w-_16)+(mb.h-_17);
-if(_b==null||_18<_b.overflow){
-_b={corner:_d,aroundCorner:_c.aroundCorner,x:_12,y:_13,w:_16,h:_17,overflow:_18};
+=====*/
+
+
+dijit.placeOnScreen = function(
+ /* DomNode */ node,
+ /* dijit.__Position */ pos,
+ /* String[] */ corners,
+ /* dijit.__Position? */ padding){
+ // summary:
+ // Positions one of the node's corners at specified position
+ // such that node is fully visible in viewport.
+ // description:
+ // NOTE: node is assumed to be absolutely or relatively positioned.
+ // pos:
+ // Object like {x: 10, y: 20}
+ // corners:
+ // Array of Strings representing order to try corners in, like ["TR", "BL"].
+ // Possible values are:
+ // * "BL" - bottom left
+ // * "BR" - bottom right
+ // * "TL" - top left
+ // * "TR" - top right
+ // padding:
+ // set padding to put some buffer around the element you want to position.
+ // example:
+ // Try to place node's top right corner at (10,20).
+ // If that makes node go (partially) off screen, then try placing
+ // bottom left corner at (10,20).
+ // | placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"])
+
+ var choices = dojo.map(corners, function(corner){
+ var c = { corner: corner, pos: {x:pos.x,y:pos.y} };
+ if(padding){
+ c.pos.x += corner.charAt(1) == 'L' ? padding.x : -padding.x;
+ c.pos.y += corner.charAt(0) == 'T' ? padding.y : -padding.y;
+ }
+ return c;
+ });
+
+ return dijit._place(node, choices);
}
-return !_18;
-});
-_7.style.left=_b.x+"px";
-_7.style.top=_b.y+"px";
-if(_b.overflow&&_9){
-_9(_7,_b.aroundCorner,_b.corner);
+
+dijit._place = function(/*DomNode*/ node, choices, layoutNode, /*Object*/ aroundNodeCoords){
+ // 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, aroundNodeCorner, nodeCorner, size)
+ // 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.
+ // It also passes in the available size for the popup, which is useful for tooltips to
+ // tell them that their width is limited to a certain amount. layoutNode() may return a value expressing
+ // how much the popup had to be modified to fit into the available space. This is used to determine
+ // what the best placement is.
+ // aroundNodeCoords: Object
+ // Size of aroundNode, ex: {w: 200, h: 50}
+
+ // get {x: 10, y: 10, w: 100, h:100} type obj representing position of
+ // viewport over document
+ var view = dojo.window.getBox();
+
+ // This won't work if the node is inside a <div style="position: relative">,
+ // so reattach it to dojo.doc.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;
+ dojo.some(choices, function(choice){
+ var corner = choice.corner;
+ var pos = choice.pos;
+ var overflow = 0;
+
+ // calculate amount of space available given specified position of node
+ var spaceAvailable = {
+ w: corner.charAt(1) == 'L' ? (view.l + view.w) - pos.x : pos.x - view.l,
+ h: corner.charAt(1) == 'T' ? (view.t + view.h) - pos.y : pos.y - view.t
+ };
+
+ // 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 tooltip's size changes based on position, due to triangle)
+ if(layoutNode){
+ var res = layoutNode(node, choice.aroundCorner, corner, spaceAvailable, aroundNodeCoords);
+ overflow = typeof res == "undefined" ? 0 : res;
+ }
+
+ // get node's size
+ var style = node.style;
+ var oldDisplay = style.display;
+ var oldVis = style.visibility;
+ style.visibility = "hidden";
+ style.display = "";
+ var mb = dojo.marginBox(node);
+ style.display = oldDisplay;
+ style.visibility = oldVis;
+
+ // coordinates and size of node with specified corner placed at pos,
+ // and clipped by viewport
+ var startX = Math.max(view.l, corner.charAt(1) == 'L' ? pos.x : (pos.x - mb.w)),
+ startY = Math.max(view.t, corner.charAt(0) == 'T' ? pos.y : (pos.y - mb.h)),
+ endX = Math.min(view.l + view.w, corner.charAt(1) == 'L' ? (startX + mb.w) : pos.x),
+ endY = Math.min(view.t + view.h, corner.charAt(0) == 'T' ? (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: choice.aroundCorner,
+ x: startX,
+ y: startY,
+ w: width,
+ h: height,
+ overflow: overflow,
+ spaceAvailable: spaceAvailable
+ };
+ }
+
+ return !overflow;
+ });
+
+ // In case the best position is not the last one we checked, need to call
+ // layoutNode() again.
+ if(best.overflow && layoutNode){
+ layoutNode(node, best.aroundCorner, best.corner, best.spaceAvailable, aroundNodeCoords);
+ }
+
+ // And then position the node. Do this last, after the layoutNode() above
+ // has sized the node, due to browser quirks when the viewport is scrolled
+ // (specifically that a Tooltip will shrink to fit as though the window was
+ // scrolled to the left).
+ //
+ // In RTL mode, set style.right rather than style.left so in the common case,
+ // window resizes move the popup along with the aroundNode.
+ var l = dojo._isBodyLtr(),
+ s = node.style;
+ s.top = best.y + "px";
+ s[l ? "left" : "right"] = (l ? best.x : view.w - best.x - best.w) + "px";
+
+ return best;
}
-return _b;
-};
-dijit.placeOnScreenAroundNode=function(_19,_1a,_1b,_1c){
-_1a=dojo.byId(_1a);
-var _1d=_1a.style.display;
-_1a.style.display="";
-var _1e=dojo.position(_1a,true);
-_1a.style.display=_1d;
-return dijit._placeOnScreenAroundRect(_19,_1e.x,_1e.y,_1e.w,_1e.h,_1b,_1c);
-};
-dijit.placeOnScreenAroundRectangle=function(_1f,_20,_21,_22){
-return dijit._placeOnScreenAroundRect(_1f,_20.x,_20.y,_20.width,_20.height,_21,_22);
+
+dijit.placeOnScreenAroundNode = function(
+ /* DomNode */ node,
+ /* DomNode */ aroundNode,
+ /* Object */ aroundCorners,
+ /* Function? */ layoutNode){
+
+ // summary:
+ // Position node adjacent or kitty-corner to aroundNode
+ // such that it's fully visible in viewport.
+ //
+ // description:
+ // Place node such that corner of node touches a corner of
+ // aroundNode, and that node is fully visible.
+ //
+ // aroundCorners:
+ // Ordered list of pairs of corners to try matching up.
+ // Each pair of corners is represented as a key/value in the hash,
+ // where the key corresponds to the aroundNode's corner, and
+ // the value corresponds to the node's corner:
+ //
+ // | { aroundNodeCorner1: nodeCorner1, aroundNodeCorner2: nodeCorner2, ...}
+ //
+ // The following strings are used to represent the four corners:
+ // * "BL" - bottom left
+ // * "BR" - bottom right
+ // * "TL" - top left
+ // * "TR" - top right
+ //
+ // layoutNode: Function(node, aroundNodeCorner, nodeCorner)
+ // 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.
+ //
+ // example:
+ // | dijit.placeOnScreenAroundNode(node, aroundNode, {'BL':'TL', 'TR':'BR'});
+ // This will try to position node such that node's top-left corner is at the same position
+ // as the bottom left corner of the aroundNode (ie, put node below
+ // aroundNode, with left edges aligned). If that fails it will try to put
+ // the bottom-right corner of node where the top right corner of aroundNode is
+ // (ie, put node above aroundNode, with right edges aligned)
+ //
+
+ // get coordinates of aroundNode
+ aroundNode = dojo.byId(aroundNode);
+ var aroundNodePos = dojo.position(aroundNode, true);
+
+ // place the node around the calculated rectangle
+ return dijit._placeOnScreenAroundRect(node,
+ aroundNodePos.x, aroundNodePos.y, aroundNodePos.w, aroundNodePos.h, // rectangle
+ aroundCorners, layoutNode);
};
-dijit._placeOnScreenAroundRect=function(_23,x,y,_24,_25,_26,_27){
-var _28=[];
-for(var _29 in _26){
-_28.push({aroundCorner:_29,corner:_26[_29],pos:{x:x+(_29.charAt(1)=="L"?0:_24),y:y+(_29.charAt(0)=="T"?0:_25)}});
+
+/*=====
+dijit.__Rectangle = function(){
+ // x: Integer
+ // horizontal offset in pixels, relative to document body
+ // y: Integer
+ // vertical offset in pixels, relative to document body
+ // width: Integer
+ // width in pixels
+ // height: Integer
+ // height in pixels
+
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
}
-return dijit._place(_23,_28,_27);
+=====*/
+
+
+dijit.placeOnScreenAroundRectangle = function(
+ /* DomNode */ node,
+ /* dijit.__Rectangle */ aroundRect,
+ /* Object */ aroundCorners,
+ /* Function */ layoutNode){
+
+ // summary:
+ // Like dijit.placeOnScreenAroundNode(), except that the "around"
+ // parameter is an arbitrary rectangle on the screen (x, y, width, height)
+ // instead of a dom node.
+
+ return dijit._placeOnScreenAroundRect(node,
+ aroundRect.x, aroundRect.y, aroundRect.width, aroundRect.height, // rectangle
+ aroundCorners, layoutNode);
+};
+
+dijit._placeOnScreenAroundRect = function(
+ /* DomNode */ node,
+ /* Number */ x,
+ /* Number */ y,
+ /* Number */ width,
+ /* Number */ height,
+ /* Object */ aroundCorners,
+ /* Function */ layoutNode){
+
+ // summary:
+ // Like dijit.placeOnScreenAroundNode(), except it accepts coordinates
+ // of a rectangle to place node adjacent to.
+
+ // TODO: combine with placeOnScreenAroundRectangle()
+
+ // Generate list of possible positions for node
+ var choices = [];
+ for(var nodeCorner in aroundCorners){
+ choices.push( {
+ aroundCorner: nodeCorner,
+ corner: aroundCorners[nodeCorner],
+ pos: {
+ x: x + (nodeCorner.charAt(1) == 'L' ? 0 : width),
+ y: y + (nodeCorner.charAt(0) == 'T' ? 0 : height)
+ }
+ });
+ }
+
+ return dijit._place(node, choices, layoutNode, {w: width, h: height});
};
-dijit.placementRegistry=new dojo.AdapterRegistry();
-dijit.placementRegistry.register("node",function(n,x){
-return typeof x=="object"&&typeof x.offsetWidth!="undefined"&&typeof x.offsetHeight!="undefined";
-},dijit.placeOnScreenAroundNode);
-dijit.placementRegistry.register("rect",function(n,x){
-return typeof x=="object"&&"x" in x&&"y" in x&&"width" in x&&"height" in x;
-},dijit.placeOnScreenAroundRectangle);
-dijit.placeOnScreenAroundElement=function(_2a,_2b,_2c,_2d){
-return dijit.placementRegistry.match.apply(dijit.placementRegistry,arguments);
+
+dijit.placementRegistry= new dojo.AdapterRegistry();
+dijit.placementRegistry.register("node",
+ function(n, x){
+ return typeof x == "object" &&
+ typeof x.offsetWidth != "undefined" && typeof x.offsetHeight != "undefined";
+ },
+ dijit.placeOnScreenAroundNode);
+dijit.placementRegistry.register("rect",
+ function(n, x){
+ return typeof x == "object" &&
+ "x" in x && "y" in x && "width" in x && "height" in x;
+ },
+ dijit.placeOnScreenAroundRectangle);
+
+dijit.placeOnScreenAroundElement = function(
+ /* DomNode */ node,
+ /* Object */ aroundElement,
+ /* Object */ aroundCorners,
+ /* Function */ layoutNode){
+
+ // summary:
+ // Like dijit.placeOnScreenAroundNode(), except it accepts an arbitrary object
+ // for the "around" argument and finds a proper processor to place a node.
+
+ return dijit.placementRegistry.match.apply(dijit.placementRegistry, arguments);
};
-dijit.getPopupAroundAlignment=function(_2e,_2f){
-var _30={};
-dojo.forEach(_2e,function(pos){
-switch(pos){
-case "after":
-_30[_2f?"BR":"BL"]=_2f?"BL":"BR";
-break;
-case "before":
-_30[_2f?"BL":"BR"]=_2f?"BR":"BL";
-break;
-case "below":
-_30[_2f?"BL":"BR"]=_2f?"TL":"TR";
-_30[_2f?"BR":"BL"]=_2f?"TR":"TL";
-break;
-case "above":
-default:
-_30[_2f?"TL":"TR"]=_2f?"BL":"BR";
-_30[_2f?"TR":"TL"]=_2f?"BR":"BL";
-break;
-}
-});
-return _30;
+
+dijit.getPopupAroundAlignment = function(/*Array*/ position, /*Boolean*/ leftToRight){
+ // summary:
+ // Transforms the passed array of preferred positions into a format suitable for passing as the aroundCorners argument to dijit.placeOnScreenAroundElement.
+ //
+ // position: String[]
+ // This variable controls the position of the drop down.
+ // It's an array of strings with the following values:
+ //
+ // * before: places drop down to the left of the target node/widget, or to the right in
+ // the case of RTL scripts like Hebrew and Arabic
+ // * after: places drop down to the right of the target node/widget, or to the left in
+ // the case of RTL scripts like Hebrew and Arabic
+ // * above: drop down goes above target node
+ // * below: drop down goes below target node
+ //
+ // The list is positions is tried, in order, until a position is found where the drop down fits
+ // within the viewport.
+ //
+ // leftToRight: Boolean
+ // Whether the popup will be displaying in leftToRight mode.
+ //
+ var align = {};
+ dojo.forEach(position, function(pos){
+ switch(pos){
+ case "after":
+ align[leftToRight ? "BR" : "BL"] = leftToRight ? "BL" : "BR";
+ break;
+ case "before":
+ align[leftToRight ? "BL" : "BR"] = leftToRight ? "BR" : "BL";
+ break;
+ case "below-alt":
+ leftToRight = !leftToRight;
+ // fall through
+ case "below":
+ // first try to align left borders, next try to align right borders (or reverse for RTL mode)
+ align[leftToRight ? "BL" : "BR"] = leftToRight ? "TL" : "TR";
+ align[leftToRight ? "BR" : "BL"] = leftToRight ? "TR" : "TL";
+ break;
+ case "above-alt":
+ leftToRight = !leftToRight;
+ // fall through
+ case "above":
+ default:
+ // first try to align left borders, next try to align right borders (or reverse for RTL mode)
+ align[leftToRight ? "TL" : "TR"] = leftToRight ? "BL" : "BR";
+ align[leftToRight ? "TR" : "TL"] = leftToRight ? "BR" : "BL";
+ break;
+ }
+ });
+ return align;
};
+
}
diff --git a/lib/dijit/_base/popup.js b/lib/dijit/_base/popup.js
index aed046489..e6fa6a5ed 100644
--- a/lib/dijit/_base/popup.js
+++ b/lib/dijit/_base/popup.js
@@ -1,158 +1,405 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
-if(!dojo._hasResource["dijit._base.popup"]){
-dojo._hasResource["dijit._base.popup"]=true;
+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");
dojo.require("dijit._base.focus");
dojo.require("dijit._base.place");
dojo.require("dijit._base.window");
-dijit.popup={_stack:[],_beginZIndex:1000,_idGen:1,moveOffScreen:function(_1){
-var _2=_1.parentNode;
-if(!_2||!dojo.hasClass(_2,"dijitPopup")){
-_2=dojo.create("div",{"class":"dijitPopup",style:{visibility:"hidden",top:"-9999px"}},dojo.body());
-dijit.setWaiRole(_2,"presentation");
-_2.appendChild(_1);
-}
-var s=_1.style;
-s.display="";
-s.visibility="";
-s.position="";
-s.top="0px";
-dojo.style(_2,{visibility:"hidden",top:"-9999px"});
-},getTopPopup:function(){
-var _3=this._stack;
-for(var pi=_3.length-1;pi>0&&_3[pi].parent===_3[pi-1].widget;pi--){
-}
-return _3[pi];
-},open:function(_4){
-var _5=this._stack,_6=_4.popup,_7=_4.orient||((_4.parent?_4.parent.isLeftToRight():dojo._isBodyLtr())?{"BL":"TL","BR":"TR","TL":"BL","TR":"BR"}:{"BR":"TR","BL":"TL","TR":"BR","TL":"BL"}),_8=_4.around,id=(_4.around&&_4.around.id)?(_4.around.id+"_dropdown"):("popup_"+this._idGen++);
-var _9=_6.domNode.parentNode;
-if(!_9||!dojo.hasClass(_9,"dijitPopup")){
-this.moveOffScreen(_6.domNode);
-_9=_6.domNode.parentNode;
-}
-dojo.attr(_9,{id:id,style:{zIndex:this._beginZIndex+_5.length},"class":"dijitPopup "+(_6.baseClass||_6["class"]||"").split(" ")[0]+"Popup",dijitPopupParent:_4.parent?_4.parent.id:""});
-if(dojo.isIE||dojo.isMoz){
-var _a=_9.childNodes[1];
-if(!_a){
-_a=new dijit.BackgroundIframe(_9);
-}
-}
-var _b=_8?dijit.placeOnScreenAroundElement(_9,_8,_7,_6.orient?dojo.hitch(_6,"orient"):null):dijit.placeOnScreen(_9,_4,_7=="R"?["TR","BR","TL","BL"]:["TL","BL","TR","BR"],_4.padding);
-_9.style.visibility="visible";
-_6.domNode.style.visibility="visible";
-var _c=[];
-_c.push(dojo.connect(_9,"onkeypress",this,function(_d){
-if(_d.charOrCode==dojo.keys.ESCAPE&&_4.onCancel){
-dojo.stopEvent(_d);
-_4.onCancel();
-}else{
-if(_d.charOrCode===dojo.keys.TAB){
-dojo.stopEvent(_d);
-var _e=this.getTopPopup();
-if(_e&&_e.onCancel){
-_e.onCancel();
-}
-}
-}
-}));
-if(_6.onCancel){
-_c.push(dojo.connect(_6,"onCancel",_4.onCancel));
-}
-_c.push(dojo.connect(_6,_6.onExecute?"onExecute":"onChange",this,function(){
-var _f=this.getTopPopup();
-if(_f&&_f.onExecute){
-_f.onExecute();
-}
-}));
-_5.push({wrapper:_9,iframe:_a,widget:_6,parent:_4.parent,onExecute:_4.onExecute,onCancel:_4.onCancel,onClose:_4.onClose,handlers:_c});
-if(_6.onOpen){
-_6.onOpen(_b);
-}
-return _b;
-},close:function(_10){
-var _11=this._stack;
-while(dojo.some(_11,function(_12){
-return _12.widget==_10;
-})){
-var top=_11.pop(),_13=top.wrapper,_14=top.iframe,_15=top.widget,_16=top.onClose;
-if(_15.onClose){
-_15.onClose();
-}
-dojo.forEach(top.handlers,dojo.disconnect);
-if(_15&&_15.domNode){
-this.moveOffScreen(_15.domNode);
-}else{
-dojo.destroy(_13);
-}
-if(_16){
-_16();
-}
-}
-}};
-dijit._frames=new function(){
-var _17=[];
-this.pop=function(){
-var _18;
-if(_17.length){
-_18=_17.pop();
-_18.style.display="";
-}else{
-if(dojo.isIE){
-var _19=dojo.config["dojoBlankHtmlUrl"]||(dojo.moduleUrl("dojo","resources/blank.html")+"")||"javascript:\"\"";
-var _1a="<iframe src='"+_19+"'"+" style='position: absolute; left: 0px; top: 0px;"+"z-index: -1; filter:Alpha(Opacity=\"0\");'>";
-_18=dojo.doc.createElement(_1a);
-}else{
-_18=dojo.create("iframe");
-_18.src="javascript:\"\"";
-_18.className="dijitBackgroundIframe";
-dojo.style(_18,"opacity",0.1);
-}
-_18.tabIndex=-1;
-dijit.setWaiRole(_18,"presentation");
+
+
+/*=====
+dijit.popup.__OpenArgs = function(){
+ // 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. (Specify this *or* "x" and "y" parameters.)
+ // x: Integer
+ // Absolute horizontal position (in pixels) to place node at. (Specify this *or* "around" parameter.)
+ // y: Integer
+ // Absolute vertical position (in pixels) to place node at. (Specify this *or* "around" parameter.)
+ // orient: Object|String
+ // When the around parameter is specified, orient should be an
+ // ordered list of tuples of the form (around-node-corner, popup-node-corner).
+ // dijit.popup.open() tries to position the popup according to each tuple in the list, in order,
+ // until the popup appears fully within the viewport.
+ //
+ // The default value is {BL:'TL', TL:'BL'}, which represents a list of two tuples:
+ // 1. (BL, TL)
+ // 2. (TL, BL)
+ // where BL means "bottom left" and "TL" means "top left".
+ // So by default, it first tries putting the popup below the around node, left-aligning them,
+ // and then tries to put it above the around node, still left-aligning them. Note that the
+ // default is horizontally reversed when in RTL mode.
+ //
+ // When an (x,y) position is specified rather than an around node, orient is either
+ // "R" or "L". R (for right) means that it tries to put the popup to the right of the mouse,
+ // specifically positioning the popup's top-right corner at the mouse position, and if that doesn't
+ // fit in the viewport, then it tries, in order, the bottom-right corner, the top left corner,
+ // and the top-right corner.
+ // 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);
+ // i.e. 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)
+ // padding: dijit.__Position
+ // adding a buffer around the opening position. This is only useful when around is not set.
+ this.popup = popup;
+ this.parent = parent;
+ this.around = around;
+ this.x = x;
+ this.y = y;
+ this.orient = orient;
+ this.onCancel = onCancel;
+ this.onClose = onClose;
+ this.onExecute = onExecute;
+ this.padding = padding;
}
-return _18;
-};
-this.push=function(_1b){
-_1b.style.display="none";
-_17.push(_1b);
+=====*/
+
+dijit.popup = {
+ // summary:
+ // This singleton is used to show/hide widgets as popups.
+
+ // _stack: dijit._Widget[]
+ // Stack of currently popped up widgets.
+ // (someone opened _stack[0], and then it opened _stack[1], etc.)
+ _stack: [],
+
+ // _beginZIndex: Number
+ // Z-index of the first popup. (If first popup opens other
+ // popups they get a higher z-index.)
+ _beginZIndex: 1000,
+
+ _idGen: 1,
+
+ _createWrapper: function(/*Widget || DomNode*/ widget){
+ // summary:
+ // Initialization for widgets that will be used as popups.
+ // Puts widget inside a wrapper DIV (if not already in one),
+ // and returns pointer to that wrapper DIV.
+
+ var wrapper = widget.declaredClass ? widget._popupWrapper : (widget.parentNode && dojo.hasClass(widget.parentNode, "dijitPopup")),
+ node = widget.domNode || widget;
+
+ if(!wrapper){
+ // Create wrapper <div> for when this widget [in the future] will be used as a popup.
+ // This is done early because of IE bugs where creating/moving DOM nodes causes focus
+ // to go wonky, see tests/robot/Toolbar.html to reproduce
+ wrapper = dojo.create("div",{
+ "class":"dijitPopup",
+ style:{ display: "none"},
+ role: "presentation"
+ }, dojo.body());
+ wrapper.appendChild(node);
+
+ var s = node.style;
+ s.display = "";
+ s.visibility = "";
+ s.position = "";
+ s.top = "0px";
+
+ if(widget.declaredClass){ // TODO: in 2.0 change signature to always take widget, then remove if()
+ widget._popupWrapper = wrapper;
+ dojo.connect(widget, "destroy", function(){
+ dojo.destroy(wrapper);
+ delete widget._popupWrapper;
+ });
+ }
+ }
+
+ return wrapper;
+ },
+
+ moveOffScreen: function(/*Widget || DomNode*/ widget){
+ // summary:
+ // Moves the popup widget off-screen.
+ // Do not use this method to hide popups when not in use, because
+ // that will create an accessibility issue: the offscreen popup is
+ // still in the tabbing order.
+
+ // Create wrapper if not already there
+ var wrapper = this._createWrapper(widget);
+
+ dojo.style(wrapper, {
+ visibility: "hidden",
+ top: "-9999px", // prevent transient scrollbar causing misalign (#5776), and initial flash in upper left (#10111)
+ display: ""
+ });
+ },
+
+ hide: function(/*dijit._Widget*/ widget){
+ // summary:
+ // Hide this popup widget (until it is ready to be shown).
+ // Initialization for widgets that will be used as popups
+ //
+ // Also puts widget inside a wrapper DIV (if not already in one)
+ //
+ // If popup widget needs to layout it should
+ // do so when it is made visible, and popup._onShow() is called.
+
+ // Create wrapper if not already there
+ var wrapper = this._createWrapper(widget);
+
+ dojo.style(wrapper, "display", "none");
+ },
+
+ getTopPopup: function(){
+ // summary:
+ // 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.
+ var stack = this._stack;
+ for(var pi=stack.length-1; pi > 0 && stack[pi].parent === stack[pi-1].widget; pi--){
+ /* do nothing, just trying to get right value for pi */
+ }
+ return stack[pi];
+ },
+
+ open: function(/*dijit.popup.__OpenArgs*/ args){
+ // summary:
+ // Popup the widget at the specified position
+ //
+ // example:
+ // opening at the mouse position
+ // | dijit.popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY});
+ //
+ // example:
+ // 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 its own _onBlur callback
+ // (fired from _base/focus.js) to know that focus has moved somewhere else and thus the popup should be closed.
+
+ var stack = this._stack,
+ widget = args.popup,
+ orient = args.orient || (
+ (args.parent ? args.parent.isLeftToRight() : dojo._isBodyLtr()) ?
+ {'BL':'TL', 'BR':'TR', 'TL':'BL', 'TR':'BR'} :
+ {'BR':'TR', 'BL':'TL', 'TR':'BR', 'TL':'BL'}
+ ),
+ around = args.around,
+ id = (args.around && args.around.id) ? (args.around.id+"_dropdown") : ("popup_"+this._idGen++);
+
+ // If we are opening a new popup that isn't a child of a currently opened popup, then
+ // close currently opened popup(s). This should happen automatically when the old popups
+ // gets the _onBlur() event, except that the _onBlur() event isn't reliable on IE, see [22198].
+ while(stack.length && (!args.parent || !dojo.isDescendant(args.parent.domNode, stack[stack.length-1].widget.domNode))){
+ dijit.popup.close(stack[stack.length-1].widget);
+ }
+
+ // Get pointer to popup wrapper, and create wrapper if it doesn't exist
+ var wrapper = this._createWrapper(widget);
+
+
+ dojo.attr(wrapper, {
+ id: id,
+ style: {
+ zIndex: this._beginZIndex + stack.length
+ },
+ "class": "dijitPopup " + (widget.baseClass || widget["class"] || "").split(" ")[0] +"Popup",
+ dijitPopupParent: args.parent ? args.parent.id : ""
+ });
+
+ if(dojo.isIE || dojo.isMoz){
+ if(!widget.bgIframe){
+ // setting widget.bgIframe triggers cleanup in _Widget.destroy()
+ widget.bgIframe = new dijit.BackgroundIframe(wrapper);
+ }
+ }
+
+ // position the wrapper node and make it visible
+ 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'], args.padding);
+
+ wrapper.style.display = "";
+ wrapper.style.visibility = "visible";
+ widget.domNode.style.visibility = "visible"; // counteract effects from _HasDropDown
+
+ var handlers = [];
+
+ // 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.charOrCode == dojo.keys.ESCAPE && args.onCancel){
+ dojo.stopEvent(evt);
+ args.onCancel();
+ }else if(evt.charOrCode === dojo.keys.TAB){
+ dojo.stopEvent(evt);
+ var topPopup = this.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", args.onCancel));
+ }
+
+ handlers.push(dojo.connect(widget, widget.onExecute ? "onExecute" : "onChange", this, function(){
+ var topPopup = this.getTopPopup();
+ if(topPopup && topPopup.onExecute){
+ topPopup.onExecute();
+ }
+ }));
+
+ stack.push({
+ widget: widget,
+ parent: args.parent,
+ onExecute: args.onExecute,
+ onCancel: args.onCancel,
+ onClose: args.onClose,
+ handlers: handlers
+ });
+
+ if(widget.onOpen){
+ // TODO: in 2.0 standardize onShow() (used by StackContainer) and onOpen() (used here)
+ widget.onOpen(best);
+ }
+
+ return best;
+ },
+
+ close: function(/*dijit._Widget?*/ popup){
+ // summary:
+ // Close specified popup and any popups that it parented.
+ // If no popup is specified, closes all popups.
+
+ var stack = this._stack;
+
+ // Basically work backwards from the top of the stack closing popups
+ // until we hit the specified popup, but IIRC there was some issue where closing
+ // a popup would cause others to close too. Thus if we are trying to close B in [A,B,C]
+ // closing C might close B indirectly and then the while() condition will run where stack==[A]...
+ // so the while condition is constructed defensively.
+ while((popup && dojo.some(stack, function(elem){return elem.widget == popup;})) ||
+ (!popup && stack.length)){
+ var top = stack.pop(),
+ widget = top.widget,
+ onClose = top.onClose;
+
+ if(widget.onClose){
+ // TODO: in 2.0 standardize onHide() (used by StackContainer) and onClose() (used here)
+ widget.onClose();
+ }
+ dojo.forEach(top.handlers, dojo.disconnect);
+
+ // Hide the widget and it's wrapper unless it has already been destroyed in above onClose() etc.
+ if(widget && widget.domNode){
+ this.hide(widget);
+ }
+
+ if(onClose){
+ onClose();
+ }
+ }
+ }
};
+
+// TODO: remove dijit._frames, it isn't being used much, since popups never release their
+// iframes (see [22236])
+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 < 9){
+ var burl = dojo.config["dojoBlankHtmlUrl"] || (dojo.moduleUrl("dojo", "resources/blank.html")+"") || "javascript:\"\"";
+ var html="<iframe src='" + burl + "'"
+ + " style='position: absolute; left: 0px; top: 0px;"
+ + "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
+ iframe = dojo.doc.createElement(html);
+ }else{
+ iframe = dojo.create("iframe");
+ iframe.src = 'javascript:""';
+ iframe.className = "dijitBackgroundIframe";
+ dojo.style(iframe, "opacity", 0.1);
+ }
+ iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didn't work.
+ dijit.setWaiRole(iframe,"presentation");
+ }
+ return iframe;
+ };
+
+ this.push = function(iframe){
+ iframe.style.display="none";
+ queue.push(iframe);
+ }
}();
-dijit.BackgroundIframe=function(_1c){
-if(!_1c.id){
-throw new Error("no id");
-}
-if(dojo.isIE||dojo.isMoz){
-var _1d=dijit._frames.pop();
-_1c.appendChild(_1d);
-if(dojo.isIE<7){
-this.resize(_1c);
-this._conn=dojo.connect(_1c,"onresize",this,function(){
-this.resize(_1c);
-});
-}else{
-dojo.style(_1d,{width:"100%",height:"100%"});
-}
-this.iframe=_1d;
-}
+
+
+dijit.BackgroundIframe = function(/*DomNode*/ node){
+ // summary:
+ // For IE/FF 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.isMoz){
+ var iframe = (this.iframe = dijit._frames.pop());
+ node.appendChild(iframe);
+ if(dojo.isIE<7 || dojo.isQuirks){
+ this.resize(node);
+ this._conn = dojo.connect(node, 'onresize', this, function(){
+ this.resize(node);
+ });
+ }else{
+ dojo.style(iframe, {
+ width: '100%',
+ height: '100%'
+ });
+ }
+ }
};
-dojo.extend(dijit.BackgroundIframe,{resize:function(_1e){
-if(this.iframe&&dojo.isIE<7){
-dojo.style(this.iframe,{width:_1e.offsetWidth+"px",height:_1e.offsetHeight+"px"});
-}
-},destroy:function(){
-if(this._conn){
-dojo.disconnect(this._conn);
-this._conn=null;
-}
-if(this.iframe){
-dijit._frames.push(this.iframe);
-delete this.iframe;
-}
-}});
+
+dojo.extend(dijit.BackgroundIframe, {
+ resize: function(node){
+ // summary:
+ // Resize the iframe so it's the same size as node.
+ // Needed on IE6 and IE/quirks because height:100% doesn't work right.
+ if(this.iframe){
+ dojo.style(this.iframe, {
+ width: node.offsetWidth + 'px',
+ height: node.offsetHeight + 'px'
+ });
+ }
+ },
+ destroy: function(){
+ // summary:
+ // destroy the iframe
+ if(this._conn){
+ dojo.disconnect(this._conn);
+ this._conn = null;
+ }
+ if(this.iframe){
+ dijit._frames.push(this.iframe);
+ delete this.iframe;
+ }
+ }
+});
+
}
diff --git a/lib/dijit/_base/scroll.js b/lib/dijit/_base/scroll.js
index 623cea392..1010a4fca 100644
--- a/lib/dijit/_base/scroll.js
+++ b/lib/dijit/_base/scroll.js
@@ -1,15 +1,22 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
-if(!dojo._hasResource["dijit._base.scroll"]){
-dojo._hasResource["dijit._base.scroll"]=true;
+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");
dojo.require("dojo.window");
-dijit.scrollIntoView=function(_1,_2){
-dojo.window.scrollIntoView(_1,_2);
+
+
+dijit.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
+ // summary:
+ // Scroll the passed node into view, if it is not already.
+ // Deprecated, use `dojo.window.scrollIntoView` instead.
+
+ dojo.window.scrollIntoView(node, pos);
};
+
}
diff --git a/lib/dijit/_base/sniff.js b/lib/dijit/_base/sniff.js
index bf5386cfb..c7c6b94d8 100644
--- a/lib/dijit/_base/sniff.js
+++ b/lib/dijit/_base/sniff.js
@@ -1,12 +1,21 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
-if(!dojo._hasResource["dijit._base.sniff"]){
-dojo._hasResource["dijit._base.sniff"]=true;
+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");
dojo.require("dojo.uacss");
+
+
+// summary:
+// Applies pre-set CSS classes to the top-level HTML node, see
+// `dojo.uacss` for details.
+//
+// Simply doing a require on this module will
+// establish this CSS. Modified version of Morris' CSS hack.
+
}
diff --git a/lib/dijit/_base/typematic.js b/lib/dijit/_base/typematic.js
index 460e9db1a..f424b71d5 100644
--- a/lib/dijit/_base/typematic.js
+++ b/lib/dijit/_base/typematic.js
@@ -1,87 +1,191 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
-if(!dojo._hasResource["dijit._base.typematic"]){
-dojo._hasResource["dijit._base.typematic"]=true;
+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={_fireEventAndReload:function(){
-this._timer=null;
-this._callback(++this._count,this._node,this._evt);
-this._currentTimeout=Math.max(this._currentTimeout<0?this._initialDelay:(this._subsequentDelay>1?this._subsequentDelay:Math.round(this._currentTimeout*this._subsequentDelay)),this._minDelay);
-this._timer=setTimeout(dojo.hitch(this,"_fireEventAndReload"),this._currentTimeout);
-},trigger:function(_1,_2,_3,_4,_5,_6,_7,_8){
-if(_5!=this._obj){
-this.stop();
-this._initialDelay=_7||500;
-this._subsequentDelay=_6||0.9;
-this._minDelay=_8||10;
-this._obj=_5;
-this._evt=_1;
-this._node=_3;
-this._currentTimeout=-1;
-this._count=-1;
-this._callback=dojo.hitch(_2,_4);
-this._fireEventAndReload();
-this._evt=dojo.mixin({faux:true},_1);
-}
-},stop:function(){
-if(this._timer){
-clearTimeout(this._timer);
-this._timer=null;
-}
-if(this._obj){
-this._callback(-1,this._node,this._evt);
-this._obj=null;
-}
-},addKeyListener:function(_9,_a,_b,_c,_d,_e,_f){
-if(_a.keyCode){
-_a.charOrCode=_a.keyCode;
-dojo.deprecated("keyCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.","","2.0");
-}else{
-if(_a.charCode){
-_a.charOrCode=String.fromCharCode(_a.charCode);
-dojo.deprecated("charCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.","","2.0");
-}
-}
-return [dojo.connect(_9,"onkeypress",this,function(evt){
-if(evt.charOrCode==_a.charOrCode&&(_a.ctrlKey===undefined||_a.ctrlKey==evt.ctrlKey)&&(_a.altKey===undefined||_a.altKey==evt.altKey)&&(_a.metaKey===undefined||_a.metaKey==(evt.metaKey||false))&&(_a.shiftKey===undefined||_a.shiftKey==evt.shiftKey)){
-dojo.stopEvent(evt);
-dijit.typematic.trigger(evt,_b,_9,_c,_a,_d,_e,_f);
-}else{
-if(dijit.typematic._obj==_a){
-dijit.typematic.stop();
-}
-}
-}),dojo.connect(_9,"onkeyup",this,function(evt){
-if(dijit.typematic._obj==_a){
-dijit.typematic.stop();
-}
-})];
-},addMouseListener:function(_10,_11,_12,_13,_14,_15){
-var dc=dojo.connect;
-return [dc(_10,"mousedown",this,function(evt){
-dojo.stopEvent(evt);
-dijit.typematic.trigger(evt,_11,_10,_12,_10,_13,_14,_15);
-}),dc(_10,"mouseup",this,function(evt){
-dojo.stopEvent(evt);
-dijit.typematic.stop();
-}),dc(_10,"mouseout",this,function(evt){
-dojo.stopEvent(evt);
-dijit.typematic.stop();
-}),dc(_10,"mousemove",this,function(evt){
-evt.preventDefault();
-}),dc(_10,"dblclick",this,function(evt){
-dojo.stopEvent(evt);
-if(dojo.isIE){
-dijit.typematic.trigger(evt,_11,_10,_12,_10,_13,_14,_15);
-setTimeout(dojo.hitch(this,dijit.typematic.stop),50);
-}
-})];
-},addListener:function(_16,_17,_18,_19,_1a,_1b,_1c,_1d){
-return this.addKeyListener(_17,_18,_19,_1a,_1b,_1c,_1d).concat(this.addMouseListener(_16,_19,_1a,_1b,_1c,_1d));
-}};
+
+
+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);
+
+ // Schedule next event, timer is at most minDelay (default 10ms) to avoid
+ // browser overload (particularly avoiding starving DOH robot so it never gets to send a mouseup)
+ this._currentTimeout = Math.max(
+ this._currentTimeout < 0 ? this._initialDelay :
+ (this._subsequentDelay > 1 ? this._subsequentDelay : Math.round(this._currentTimeout * this._subsequentDelay)),
+ this._minDelay);
+ 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, /*Number?*/ minDelay){
+ // 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.
+ // 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 (optional):
+ // 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 (optional):
+ // the number of milliseconds until the 2nd event occurs, default=500ms
+ // minDelay (optional):
+ // the maximum delay in milliseconds for event to fire, default=10ms
+ if(obj != this._obj){
+ this.stop();
+ this._initialDelay = initialDelay || 500;
+ this._subsequentDelay = subsequentDelay || 0.90;
+ this._minDelay = minDelay || 10;
+ this._obj = obj;
+ this._evt = evt;
+ this._node = node;
+ this._currentTimeout = -1;
+ this._count = -1;
+ this._callback = dojo.hitch(_this, callback);
+ this._fireEventAndReload();
+ this._evt = dojo.mixin({faux: true}, evt);
+ }
+ },
+
+ 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, /*Number?*/ minDelay){
+ // summary:
+ // Start listening for a specific typematic key.
+ // See also the trigger method for other parameters.
+ // keyObject:
+ // an object defining the key to listen for:
+ // charOrCode:
+ // the printable character (string) or keyCode (number) to listen for.
+ // keyCode:
+ // (deprecated - use charOrCode) the keyCode (number) to listen for (implies charCode = 0).
+ // charCode:
+ // (deprecated - use charOrCode) the charCode (number) to listen for.
+ // ctrlKey:
+ // desired ctrl key state to initiate the callback 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
+ // returns:
+ // an array of dojo.connect handles
+ if(keyObject.keyCode){
+ keyObject.charOrCode = keyObject.keyCode;
+ dojo.deprecated("keyCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
+ }else if(keyObject.charCode){
+ keyObject.charOrCode = String.fromCharCode(keyObject.charCode);
+ dojo.deprecated("charCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
+ }
+ return [
+ dojo.connect(node, "onkeypress", this, function(evt){
+ if(evt.charOrCode == keyObject.charOrCode &&
+ (keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey) &&
+ (keyObject.altKey === undefined || keyObject.altKey == evt.altKey) &&
+ (keyObject.metaKey === undefined || keyObject.metaKey == (evt.metaKey || false)) && // IE doesn't even set metaKey
+ (keyObject.shiftKey === undefined || keyObject.shiftKey == evt.shiftKey)){
+ dojo.stopEvent(evt);
+ dijit.typematic.trigger(evt, _this, node, callback, keyObject, subsequentDelay, initialDelay, minDelay);
+ }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, /*Number?*/ minDelay){
+ // 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, minDelay);
+ }),
+ 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){
+ evt.preventDefault();
+ }),
+ dc(node, "dblclick", this, function(evt){
+ dojo.stopEvent(evt);
+ if(dojo.isIE){
+ dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay);
+ setTimeout(dojo.hitch(this, dijit.typematic.stop), 50);
+ }
+ })
+ ];
+ },
+
+ addListener: function(/*Node*/ mouseNode, /*Node*/ keyNode, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
+ // summary:
+ // Start listening for a specific typematic key and mouseclick.
+ // This is a thin wrapper to addKeyListener and addMouseListener.
+ // See the addMouseListener and addKeyListener methods for other parameters.
+ // mouseNode:
+ // the DOM node object to listen on for mouse events.
+ // keyNode:
+ // the DOM node object to listen on for key events.
+ // returns:
+ // an array of dojo.connect handles
+ return this.addKeyListener(keyNode, keyObject, _this, callback, subsequentDelay, initialDelay, minDelay).concat(
+ this.addMouseListener(mouseNode, _this, callback, subsequentDelay, initialDelay, minDelay));
+ }
+};
+
}
diff --git a/lib/dijit/_base/wai.js b/lib/dijit/_base/wai.js
index de67ad17a..58c9cdb8f 100644
--- a/lib/dijit/_base/wai.js
+++ b/lib/dijit/_base/wai.js
@@ -1,64 +1,145 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
-if(!dojo._hasResource["dijit._base.wai"]){
-dojo._hasResource["dijit._base.wai"]=true;
+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(){
-var _1=dojo.create("div",{id:"a11yTestNode",style:{cssText:"border: 1px solid;"+"border-color:red green;"+"position: absolute;"+"height: 5px;"+"top: -999px;"+"background-image: url(\""+(dojo.config.blankGif||dojo.moduleUrl("dojo","resources/blank.gif"))+"\");"}},dojo.body());
-var cs=dojo.getComputedStyle(_1);
-if(cs){
-var _2=cs.backgroundImage;
-var _3=(cs.borderTopColor==cs.borderRightColor)||(_2!=null&&(_2=="none"||_2=="url(invalid-url:)"));
-dojo[_3?"addClass":"removeClass"](dojo.body(),"dijit_a11y");
-if(dojo.isIE){
-_1.outerHTML="";
-}else{
-dojo.body().removeChild(_1);
-}
-}
-}};
-if(dojo.isIE||dojo.isMoz){
-dojo._loaders.unshift(dijit.wai.onload);
-}
-dojo.mixin(dijit,{_XhtmlRoles:/banner|contentinfo|definition|main|navigation|search|note|secondary|seealso/,hasWaiRole:function(_4,_5){
-var _6=this.getWaiRole(_4);
-return _5?(_6.indexOf(_5)>-1):(_6.length>0);
-},getWaiRole:function(_7){
-return dojo.trim((dojo.attr(_7,"role")||"").replace(this._XhtmlRoles,"").replace("wairole:",""));
-},setWaiRole:function(_8,_9){
-var _a=dojo.attr(_8,"role")||"";
-if(!this._XhtmlRoles.test(_a)){
-dojo.attr(_8,"role",_9);
-}else{
-if((" "+_a+" ").indexOf(" "+_9+" ")<0){
-var _b=dojo.trim(_a.replace(this._XhtmlRoles,""));
-var _c=dojo.trim(_a.replace(_b,""));
-dojo.attr(_8,"role",_c+(_c?" ":"")+_9);
-}
-}
-},removeWaiRole:function(_d,_e){
-var _f=dojo.attr(_d,"role");
-if(!_f){
-return;
-}
-if(_e){
-var t=dojo.trim((" "+_f+" ").replace(" "+_e+" "," "));
-dojo.attr(_d,"role",t);
-}else{
-_d.removeAttribute("role");
+
+
+dijit.wai = {
+ onload: function(){
+ // summary:
+ // Detects if we are in high-contrast mode or not
+
+ // 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 = dojo.create("div",{
+ id: "a11yTestNode",
+ style:{
+ cssText:'border: 1px solid;'
+ + 'border-color:red green;'
+ + 'position: absolute;'
+ + 'height: 5px;'
+ + 'top: -999px;'
+ + 'background-image: url("' + (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")) + '");'
+ }
+ }, dojo.body());
+
+ // test it
+ 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");
+ if(dojo.isIE){
+ div.outerHTML = ""; // prevent mixed-content warning, see http://support.microsoft.com/kb/925014
+ }else{
+ dojo.body().removeChild(div);
+ }
+ }
+ }
+};
+
+// 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);
}
-},hasWaiState:function(_10,_11){
-return _10.hasAttribute?_10.hasAttribute("aria-"+_11):!!_10.getAttribute("aria-"+_11);
-},getWaiState:function(_12,_13){
-return _12.getAttribute("aria-"+_13)||"";
-},setWaiState:function(_14,_15,_16){
-_14.setAttribute("aria-"+_15,_16);
-},removeWaiState:function(_17,_18){
-_17.removeAttribute("aria-"+_18);
-}});
+
+dojo.mixin(dijit, {
+ hasWaiRole: function(/*Element*/ elem, /*String?*/ role){
+ // summary:
+ // Determines if an element has a particular role.
+ // returns:
+ // True if elem has the specific role attribute and false if not.
+ // For backwards compatibility if role parameter not provided,
+ // returns true if has a role
+ var waiRole = this.getWaiRole(elem);
+ return role ? (waiRole.indexOf(role) > -1) : (waiRole.length > 0);
+ },
+
+ getWaiRole: function(/*Element*/ elem){
+ // summary:
+ // Gets the role for an element (which should be a wai role).
+ // returns:
+ // The role of elem or an empty string if elem
+ // does not have a role.
+ return dojo.trim((dojo.attr(elem, "role") || "").replace("wairole:",""));
+ },
+
+ setWaiRole: function(/*Element*/ elem, /*String*/ role){
+ // summary:
+ // Sets the role on an element.
+ // description:
+ // Replace existing role attribute with new role.
+
+ dojo.attr(elem, "role", role);
+ },
+
+ removeWaiRole: function(/*Element*/ elem, /*String*/ role){
+ // summary:
+ // Removes the specified role from an element.
+ // Removes role attribute if no specific role provided (for backwards compat.)
+
+ var roleValue = dojo.attr(elem, "role");
+ if(!roleValue){ return; }
+ if(role){
+ var t = dojo.trim((" " + roleValue + " ").replace(" " + role + " ", " "));
+ dojo.attr(elem, "role", t);
+ }else{
+ elem.removeAttribute("role");
+ }
+ },
+
+ hasWaiState: function(/*Element*/ elem, /*String*/ state){
+ // summary:
+ // Determines if an element has a given state.
+ // description:
+ // Checks for an attribute called "aria-"+state.
+ // returns:
+ // true if elem has a value for the given state and
+ // false if it does not.
+
+ return elem.hasAttribute ? elem.hasAttribute("aria-"+state) : !!elem.getAttribute("aria-"+state);
+ },
+
+ getWaiState: function(/*Element*/ elem, /*String*/ state){
+ // summary:
+ // Gets the value of a state on an element.
+ // description:
+ // Checks for an attribute called "aria-"+state.
+ // returns:
+ // The value of the requested state on elem
+ // or an empty string if elem has no value for state.
+
+ return elem.getAttribute("aria-"+state) || "";
+ },
+
+ setWaiState: function(/*Element*/ elem, /*String*/ state, /*String*/ value){
+ // summary:
+ // Sets a state on an element.
+ // description:
+ // Sets an attribute called "aria-"+state.
+
+ elem.setAttribute("aria-"+state, value);
+ },
+
+ removeWaiState: function(/*Element*/ elem, /*String*/ state){
+ // summary:
+ // Removes a state from an element.
+ // description:
+ // Sets an attribute called "aria-"+state.
+
+ elem.removeAttribute("aria-"+state);
+ }
+});
+
}
diff --git a/lib/dijit/_base/window.js b/lib/dijit/_base/window.js
index 57a691436..713455b90 100644
--- a/lib/dijit/_base/window.js
+++ b/lib/dijit/_base/window.js
@@ -1,15 +1,18 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
-if(!dojo._hasResource["dijit._base.window"]){
-dojo._hasResource["dijit._base.window"]=true;
+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");
dojo.require("dojo.window");
-dijit.getDocumentWindow=function(_1){
-return dojo.window.get(_1);
+
+
+dijit.getDocumentWindow = function(doc){
+ return dojo.window.get(doc);
};
+
}