aboutsummaryrefslogtreecommitdiff
path: root/includes/js/dijit/_base/focus.js
diff options
context:
space:
mode:
Diffstat (limited to 'includes/js/dijit/_base/focus.js')
-rw-r--r--includes/js/dijit/_base/focus.js342
1 files changed, 342 insertions, 0 deletions
diff --git a/includes/js/dijit/_base/focus.js b/includes/js/dijit/_base/focus.js
new file mode 100644
index 0000000..46230b5
--- /dev/null
+++ b/includes/js/dijit/_base/focus.js
@@ -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);
+
+}