Blame | Last modification | View Log | RSS feed
if(!dojo._hasResource["dijit._base.focus"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.dojo._hasResource["dijit._base.focus"] = true;dojo.provide("dijit._base.focus");// summary:// These functions are used to query or set the focus and selection.//// Also, they trace when widgets become actived/deactivated,// so that the widget can fire _onFocus/_onBlur events.// "Active" here means something similar to "focused", but// "focus" isn't quite the right word because we keep track of// a whole stack of "active" widgets. Example: Combobutton --> Menu -->// MenuItem. The onBlur event for Combobutton doesn't fire due to focusing// on the Menu or a MenuItem, since they are considered part of the// Combobutton widget. It only happens when focus is shifted// somewhere completely different.dojo.mixin(dijit,{// _curFocus: DomNode// Currently focused item on screen_curFocus: null,// _prevFocus: DomNode// Previously focused item on screen_prevFocus: null,isCollapsed: function(){// summary: tests whether the current selection is emptyvar _window = dojo.global;var _document = dojo.doc;if(_document.selection){ // IEreturn !_document.selection.createRange().text; // Boolean}else if(_window.getSelection){var selection = _window.getSelection();if(dojo.isString(selection)){ // Safarireturn !selection; // Boolean}else{ // Mozilla/W3return selection.isCollapsed || !selection.toString(); // Boolean}}},getBookmark: function(){// summary: Retrieves a bookmark that can be used with moveToBookmark to return to the same rangevar bookmark, selection = dojo.doc.selection;if(selection){ // IEvar range = selection.createRange();if(selection.type.toUpperCase()=='CONTROL'){bookmark = range.length ? dojo._toArray(range) : null;}else{bookmark = range.getBookmark();}}else{if(dojo.global.getSelection){selection = dojo.global.getSelection();if(selection){var range = selection.getRangeAt(0);bookmark = range.cloneRange();}}else{console.debug("No idea how to store the current selection for this browser!");}}return bookmark; // Array},moveToBookmark: function(/*Object*/bookmark){// summary: Moves current selection to a bookmark// bookmark: this should be a returned object from dojo.html.selection.getBookmark()var _document = dojo.doc;if(_document.selection){ // IEvar range;if(dojo.isArray(bookmark)){range = _document.body.createControlRange();dojo.forEach(bookmark, range.addElement);}else{range = _document.selection.createRange();range.moveToBookmark(bookmark);}range.select();}else{ //Moz/W3Cvar selection = dojo.global.getSelection && dojo.global.getSelection();if(selection && selection.removeAllRanges){selection.removeAllRanges();selection.addRange(bookmark);}else{console.debug("No idea how to restore selection for this browser!");}}},getFocus: function(/*Widget*/menu, /*Window*/ openedForWindow){// summary:// Returns the current focus and selection.// Called when a popup appears (either a top level menu or a dialog),// or when a toolbar/menubar receives focus//// menu:// the menu that's being opened//// openedForWindow:// iframe in which menu was opened//// returns:// a handle to restore focus/selectionreturn {// Node to return focus tonode: menu && dojo.isDescendant(dijit._curFocus, menu.domNode) ? dijit._prevFocus : dijit._curFocus,// Previously selected textbookmark:!dojo.withGlobal(openedForWindow||dojo.global, dijit.isCollapsed) ?dojo.withGlobal(openedForWindow||dojo.global, dijit.getBookmark) :null,openedForWindow: openedForWindow}; // Object},focus: function(/*Object || DomNode */ handle){// summary:// Sets the focused node and the selection according to argument.// To set focus to an iframe's content, pass in the iframe itself.// handle:// object returned by get(), or a DomNodeif(!handle){ return; }var node = "node" in handle ? handle.node : handle, // because handle is either DomNode or a composite objectbookmark = handle.bookmark,openedForWindow = handle.openedForWindow;// Set the focus// Note that for iframe's we need to use the <iframe> to follow the parentNode chain,// but we need to set focus to iframe.contentWindowif(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 thatfocusNode.focus();}catch(e){/*quiet*/}}dijit._onFocusNode(node);}// set the selection// do not need to restore if current selection is not empty// (use keyboard to select a menu item)if(bookmark && dojo.withGlobal(openedForWindow||dojo.global, dijit.isCollapsed)){if(openedForWindow){openedForWindow.focus();}try{dojo.withGlobal(openedForWindow||dojo.global, moveToBookmark, null, [bookmark]);}catch(e){/*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */}}},// List of currently active widgets (focused widget and it's ancestors)_activeStack: [],registerWin: function(/*Window?*/targetWindow){// summary:// Registers listeners on the specified window (either the main// window or an iframe) to detect when the user has clicked somewhere.// Anyone that creates an iframe should call this function.if(!targetWindow){targetWindow = window;}dojo.connect(targetWindow.document, "onmousedown", null, function(evt){dijit._justMouseDowned = true;setTimeout(function(){ dijit._justMouseDowned = false; }, 0);dijit._onTouchNode(evt.target||evt.srcElement);});//dojo.connect(targetWindow, "onscroll", ???);// Listen for blur and focus events on targetWindow's bodyvar body = targetWindow.document.body || targetWindow.document.getElementsByTagName("body")[0];if(body){if(dojo.isIE){body.attachEvent('onactivate', function(evt){if(evt.srcElement.tagName.toLowerCase() != "body"){dijit._onFocusNode(evt.srcElement);}});body.attachEvent('ondeactivate', function(evt){ dijit._onBlurNode(evt.srcElement); });}else{body.addEventListener('focus', function(evt){ dijit._onFocusNode(evt.target); }, true);body.addEventListener('blur', function(evt){ dijit._onBlurNode(evt.target); }, true);}}body = null; // prevent memory leak (apparent circular reference via closure)},_onBlurNode: function(/*DomNode*/ node){// summary:// Called when focus leaves a node.// Usually ignored, _unless_ it *isn't* follwed by touching another node,// which indicates that we tabbed off the last field on the page,// in which case every widget is marked inactivedijit._prevFocus = dijit._curFocus;dijit._curFocus = null;var w = dijit.getEnclosingWidget(node);if (w && w._setStateClass){w._focused = false;w._setStateClass();}if(dijit._justMouseDowned){// the mouse down caused a new widget to be marked as active; this blur event// is coming late, so ignore it.return;}// if the blur event isn't followed by a focus event then mark all widgets as inactive.if(dijit._clearActiveWidgetsTimer){clearTimeout(dijit._clearActiveWidgetsTimer);}dijit._clearActiveWidgetsTimer = setTimeout(function(){delete dijit._clearActiveWidgetsTimer; dijit._setStack([]); }, 100);},_onTouchNode: function(/*DomNode*/ node){// summary// Callback when node is focused or mouse-downed// ignore the recent blurNode eventif(dijit._clearActiveWidgetsTimer){clearTimeout(dijit._clearActiveWidgetsTimer);delete dijit._clearActiveWidgetsTimer;}// compute stack of active widgets (ex: ComboButton --> Menu --> MenuItem)var newStack=[];try{while(node){if(node.dijitPopupParent){node=dijit.byId(node.dijitPopupParent).domNode;}else if(node.tagName && node.tagName.toLowerCase()=="body"){// is this the root of the document or just the root of an iframe?if(node===dojo.body()){// node is the root of the main documentbreak;}// otherwise, find the iframe this node refers to (can't access it via parentNode,// need to do this trick instead) and continue tracing up the documentnode=dojo.query("iframe").filter(function(iframe){ return iframe.contentDocument.body===node; })[0];}else{var id = node.getAttribute && node.getAttribute("widgetId");if(id){newStack.unshift(id);}node=node.parentNode;}}}catch(e){ /* squelch */ }dijit._setStack(newStack);},_onFocusNode: function(/*DomNode*/ node){// summary// Callback when node is focusedif(node && node.tagName && node.tagName.toLowerCase() == "body"){return;}dijit._onTouchNode(node);if(node==dijit._curFocus){ return; }dijit._prevFocus = dijit._curFocus;dijit._curFocus = node;dojo.publish("focusNode", [node]);// handle focus/blur stylingvar w = dijit.getEnclosingWidget(node);if (w && w._setStateClass){w._focused = true;w._setStateClass();}},_setStack: function(newStack){// summary// The stack of active widgets has changed. Send out appropriate events and record new stackvar oldStack = dijit._activeStack;dijit._activeStack = newStack;// compare old stack to new stack to see how many elements they have in commonfor(var nCommon=0; nCommon<Math.min(oldStack.length, newStack.length); nCommon++){if(oldStack[nCommon] != newStack[nCommon]){break;}}// for all elements that have gone out of focus, send blur eventfor(var i=oldStack.length-1; i>=nCommon; i--){var widget = dijit.byId(oldStack[i]);if(widget){dojo.publish("widgetBlur", [widget]);if(widget._onBlur){widget._onBlur();}}}// for all element that have come into focus, send focus eventfor(var i=nCommon; i<newStack.length; i++){var widget = dijit.byId(newStack[i]);if(widget){dojo.publish("widgetFocus", [widget]);if(widget._onFocus){widget._onFocus();}}}}});// register top window and all the iframes it containsdojo.addOnLoad(dijit.registerWin);}