]> git.pond.sub.org Git - eow/blobdiff - static/dojo-release-1.1.1/dijit/_base/focus.js
add Dojo 1.1.1
[eow] / static / dojo-release-1.1.1 / dijit / _base / focus.js
diff --git a/static/dojo-release-1.1.1/dijit/_base/focus.js b/static/dojo-release-1.1.1/dijit/_base/focus.js
new file mode 100644 (file)
index 0000000..46230b5
--- /dev/null
@@ -0,0 +1,342 @@
+if(!dojo._hasResource["dijit._base.focus"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.focus"] = true;
+dojo.provide("dijit._base.focus");
+
+// summary:
+//             These functions are used to query or set the focus and selection.
+//
+//             Also, they trace when widgets become actived/deactivated,
+//             so that the widget can fire _onFocus/_onBlur events.
+//             "Active" here means something similar to "focused", but
+//             "focus" isn't quite the right word because we keep track of
+//             a whole stack of "active" widgets.  Example:  Combobutton --> Menu -->
+//             MenuItem.   The onBlur event for Combobutton doesn't fire due to focusing
+//             on the Menu or a MenuItem, since they are considered part of the
+//             Combobutton widget.  It only happens when focus is shifted
+//             somewhere completely different.
+
+dojo.mixin(dijit,
+{
+       // _curFocus: DomNode
+       //              Currently focused item on screen
+       _curFocus: null,
+
+       // _prevFocus: DomNode
+       //              Previously focused item on screen
+       _prevFocus: null,
+
+       isCollapsed: function(){
+               // summary: tests whether the current selection is empty
+               var _window = dojo.global;
+               var _document = dojo.doc;
+               if(_document.selection){ // IE
+                       return !_document.selection.createRange().text; // Boolean
+               }else{
+                       var selection = _window.getSelection();
+                       if(dojo.isString(selection)){ // Safari
+                               return !selection; // Boolean
+                       }else{ // Mozilla/W3
+                               return selection.isCollapsed || !selection.toString(); // Boolean
+                       }
+               }
+       },
+
+       getBookmark: function(){
+               // summary: Retrieves a bookmark that can be used with moveToBookmark to return to the same range
+               var bookmark, selection = dojo.doc.selection;
+               if(selection){ // IE
+                       var range = selection.createRange();
+                       if(selection.type.toUpperCase()=='CONTROL'){
+                               if(range.length){
+                                       bookmark=[];
+                                       var i=0,len=range.length;
+                                       while(i<len){
+                                               bookmark.push(range.item(i++));
+                                       }
+                               }else{
+                                       bookmark=null;
+                               }
+                       }else{
+                               bookmark = range.getBookmark();
+                       }
+               }else{
+                       if(window.getSelection){
+                               selection = dojo.global.getSelection();
+                               if(selection){
+                                       range = selection.getRangeAt(0);
+                                       bookmark = range.cloneRange();
+                               }
+                       }else{
+                               console.warn("No idea how to store the current selection for this browser!");
+                       }
+               }
+               return bookmark; // Array
+       },
+
+       moveToBookmark: function(/*Object*/bookmark){
+               // summary: Moves current selection to a bookmark
+               // bookmark: This should be a returned object from dojo.html.selection.getBookmark()
+               var _document = dojo.doc;
+               if(_document.selection){ // IE
+                       var range;
+                       if(dojo.isArray(bookmark)){
+                               range = _document.body.createControlRange();
+                               dojo.forEach(bookmark, "range.addElement(item)"); //range.addElement does not have call/apply method, so can not call it directly
+                       }else{
+                               range = _document.selection.createRange();
+                               range.moveToBookmark(bookmark);
+                       }
+                       range.select();
+               }else{ //Moz/W3C
+                       var selection = dojo.global.getSelection && dojo.global.getSelection();
+                       if(selection && selection.removeAllRanges){
+                               selection.removeAllRanges();
+                               selection.addRange(bookmark);
+                       }else{
+                               console.warn("No idea how to restore selection for this browser!");
+                       }
+               }
+       },
+
+       getFocus: function(/*Widget?*/menu, /*Window?*/openedForWindow){
+               // summary:
+               //      Returns the current focus and selection.
+               //      Called when a popup appears (either a top level menu or a dialog),
+               //      or when a toolbar/menubar receives focus
+               //
+               // menu:
+               //      The menu that's being opened
+               //
+               // openedForWindow:
+               //      iframe in which menu was opened
+               //
+               // returns:
+               //      A handle to restore focus/selection
+
+               return {
+                       // Node to return focus to
+                       node: menu && dojo.isDescendant(dijit._curFocus, menu.domNode) ? dijit._prevFocus : dijit._curFocus,
+
+                       // Previously selected text
+                       bookmark:
+                               !dojo.withGlobal(openedForWindow||dojo.global, dijit.isCollapsed) ?
+                               dojo.withGlobal(openedForWindow||dojo.global, dijit.getBookmark) :
+                               null,
+
+                       openedForWindow: openedForWindow
+               }; // Object
+       },
+
+       focus: function(/*Object || DomNode */ handle){
+               // summary:
+               //              Sets the focused node and the selection according to argument.
+               //              To set focus to an iframe's content, pass in the iframe itself.
+               // handle:
+               //              object returned by get(), or a DomNode
+
+               if(!handle){ return; }
+
+               var node = "node" in handle ? handle.node : handle,             // because handle is either DomNode or a composite object
+                       bookmark = handle.bookmark,
+                       openedForWindow = handle.openedForWindow;
+
+               // Set the focus
+               // Note that for iframe's we need to use the <iframe> to follow the parentNode chain,
+               // but we need to set focus to iframe.contentWindow
+               if(node){
+                       var focusNode = (node.tagName.toLowerCase()=="iframe") ? node.contentWindow : node;
+                       if(focusNode && focusNode.focus){
+                               try{
+                                       // Gecko throws sometimes if setting focus is impossible,
+                                       // node not displayed or something like that
+                                       focusNode.focus();
+                               }catch(e){/*quiet*/}
+                       }                       
+                       dijit._onFocusNode(node);
+               }
+
+               // set the selection
+               // do not need to restore if current selection is not empty
+               // (use keyboard to select a menu item)
+               if(bookmark && dojo.withGlobal(openedForWindow||dojo.global, dijit.isCollapsed)){
+                       if(openedForWindow){
+                               openedForWindow.focus();
+                       }
+                       try{
+                               dojo.withGlobal(openedForWindow||dojo.global, dijit.moveToBookmark, null, [bookmark]);
+                       }catch(e){
+                               /*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */
+                       }
+               }
+       },
+
+       // _activeStack: Array
+       //              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", function(evt){
+                       dijit._justMouseDowned = true;
+                       setTimeout(function(){ dijit._justMouseDowned = false; }, 0);
+                       dijit._onTouchNode(evt.target||evt.srcElement);
+               });
+               //dojo.connect(targetWindow, "onscroll", ???);
+
+               // Listen for blur and focus events on targetWindow's body
+               var body = targetWindow.document.body || targetWindow.document.getElementsByTagName("body")[0];
+               if(body){
+                       if(dojo.isIE){
+                               body.attachEvent('onactivate', function(evt){
+                                       if(evt.srcElement.tagName.toLowerCase() != "body"){
+                                               dijit._onFocusNode(evt.srcElement);
+                                       }
+                               });
+                               body.attachEvent('ondeactivate', function(evt){ dijit._onBlurNode(evt.srcElement); });
+                       }else{
+                               body.addEventListener('focus', function(evt){ dijit._onFocusNode(evt.target); }, true);
+                               body.addEventListener('blur', function(evt){ dijit._onBlurNode(evt.target); }, true);
+                       }
+               }
+               body = null;    // prevent memory leak (apparent circular reference via closure)
+       },
+
+       _onBlurNode: function(/*DomNode*/ node){
+               // summary:
+               //              Called when focus leaves a node.
+               //              Usually ignored, _unless_ it *isn't* follwed by touching another node,
+               //              which indicates that we tabbed off the last field on the page,
+               //              in which case every widget is marked inactive
+               dijit._prevFocus = dijit._curFocus;
+               dijit._curFocus = null;
+
+               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){
+               // summary:
+               //              Callback when node is focused or mouse-downed
+
+               // ignore the recent blurNode event
+               if(dijit._clearActiveWidgetsTimer){
+                       clearTimeout(dijit._clearActiveWidgetsTimer);
+                       delete dijit._clearActiveWidgetsTimer;
+               }
+
+               // compute stack of active widgets (ex: ComboButton --> Menu --> MenuItem)
+               var newStack=[];
+               try{
+                       while(node){
+                               if(node.dijitPopupParent){
+                                       node=dijit.byId(node.dijitPopupParent).domNode;
+                               }else if(node.tagName && node.tagName.toLowerCase()=="body"){
+                                       // is this the root of the document or just the root of an iframe?
+                                       if(node===dojo.body()){
+                                               // node is the root of the main document
+                                               break;
+                                       }
+                                       // otherwise, find the iframe this node refers to (can't access it via parentNode,
+                                       // need to do this trick instead). window.frameElement is supported in IE/FF/Webkit
+                                       node=dijit.getDocumentWindow(node.ownerDocument).frameElement;
+                               }else{
+                                       var id = node.getAttribute && node.getAttribute("widgetId");
+                                       if(id){
+                                               newStack.unshift(id);
+                                       }
+                                       node=node.parentNode;
+                               }
+                       }
+               }catch(e){ /* squelch */ }
+
+               dijit._setStack(newStack);
+       },
+
+       _onFocusNode: function(/*DomNode*/ node){
+               // summary
+               //              Callback when node is focused
+               if(node && node.tagName && node.tagName.toLowerCase() == "body"){
+                       return;
+               }
+               dijit._onTouchNode(node);
+
+               if(node==dijit._curFocus){ return; }
+               if(dijit._curFocus){
+                       dijit._prevFocus = dijit._curFocus;
+               }
+               dijit._curFocus = node;
+               dojo.publish("focusNode", [node]);
+       },
+
+       _setStack: function(newStack){
+               // summary
+               //      The stack of active widgets has changed.  Send out appropriate events and record new stack
+
+               var oldStack = dijit._activeStack;              
+               dijit._activeStack = newStack;
+
+               // compare old stack to new stack to see how many elements they have in common
+               for(var nCommon=0; nCommon<Math.min(oldStack.length, newStack.length); nCommon++){
+                       if(oldStack[nCommon] != newStack[nCommon]){
+                               break;
+                       }
+               }
+
+               // for all elements that have gone out of focus, send blur event
+               for(var i=oldStack.length-1; i>=nCommon; i--){
+                       var widget = dijit.byId(oldStack[i]);
+                       if(widget){
+                               widget._focused = false;
+                               widget._hasBeenBlurred = true;
+                               if(widget._onBlur){
+                                       widget._onBlur();
+                               }
+                               if (widget._setStateClass){
+                                       widget._setStateClass();
+                               }
+                               dojo.publish("widgetBlur", [widget]);
+                       }
+               }
+
+               // 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;
+                               if(widget._onFocus){
+                                       widget._onFocus();
+                               }
+                               if (widget._setStateClass){
+                                       widget._setStateClass();
+                               }
+                               dojo.publish("widgetFocus", [widget]);
+                       }
+               }
+       }
+});
+
+// register top window and all the iframes it contains
+dojo.addOnLoad(dijit.registerWin);
+
+}