From e44a7e37b6c7b5961adaffc62b9042b8d442938e Mon Sep 17 00:00:00 2001 From: mensonge Date: Thu, 13 Nov 2008 09:49:11 +0000 Subject: New feature: basic Ajax suggestion for tags and implementation of Dojo toolkit git-svn-id: https://semanticscuttle.svn.sourceforge.net/svnroot/semanticscuttle/trunk@151 b3834d28-1941-0410-a4f8-b48e95affb8f --- includes/js/dijit/_base/focus.js | 342 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 342 insertions(+) create mode 100644 includes/js/dijit/_base/focus.js (limited to 'includes/js/dijit/_base/focus.js') 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 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=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