Subversion Repositories Applications.papyrus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2150 mathias 1
if(!dojo._hasResource["dijit._base.focus"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2
dojo._hasResource["dijit._base.focus"] = true;
3
dojo.provide("dijit._base.focus");
4
 
5
// summary:
6
//		These functions are used to query or set the focus and selection.
7
//
8
//		Also, they trace when widgets become actived/deactivated,
9
//		so that the widget can fire _onFocus/_onBlur events.
10
//		"Active" here means something similar to "focused", but
11
//		"focus" isn't quite the right word because we keep track of
12
//		a whole stack of "active" widgets.  Example:  Combobutton --> Menu -->
13
//		MenuItem.   The onBlur event for Combobutton doesn't fire due to focusing
14
//		on the Menu or a MenuItem, since they are considered part of the
15
//		Combobutton widget.  It only happens when focus is shifted
16
//		somewhere completely different.
17
 
18
dojo.mixin(dijit,
19
{
20
	// _curFocus: DomNode
21
	//		Currently focused item on screen
22
	_curFocus: null,
23
 
24
	// _prevFocus: DomNode
25
	//		Previously focused item on screen
26
	_prevFocus: null,
27
 
28
	isCollapsed: function(){
29
		// summary: tests whether the current selection is empty
30
		var _window = dojo.global;
31
		var _document = dojo.doc;
32
		if(_document.selection){ // IE
33
			return !_document.selection.createRange().text; // Boolean
34
		}else if(_window.getSelection){
35
			var selection = _window.getSelection();
36
			if(dojo.isString(selection)){ // Safari
37
				return !selection; // Boolean
38
			}else{ // Mozilla/W3
39
				return selection.isCollapsed || !selection.toString(); // Boolean
40
			}
41
		}
42
	},
43
 
44
	getBookmark: function(){
45
		// summary: Retrieves a bookmark that can be used with moveToBookmark to return to the same range
46
		var bookmark, selection = dojo.doc.selection;
47
		if(selection){ // IE
48
			var range = selection.createRange();
49
			if(selection.type.toUpperCase()=='CONTROL'){
50
				bookmark = range.length ? dojo._toArray(range) : null;
51
			}else{
52
				bookmark = range.getBookmark();
53
			}
54
		}else{
55
			if(dojo.global.getSelection){
56
				selection = dojo.global.getSelection();
57
				if(selection){
58
					var range = selection.getRangeAt(0);
59
					bookmark = range.cloneRange();
60
				}
61
			}else{
62
				console.debug("No idea how to store the current selection for this browser!");
63
			}
64
		}
65
		return bookmark; // Array
66
	},
67
 
68
	moveToBookmark: function(/*Object*/bookmark){
69
		// summary: Moves current selection to a bookmark
70
		// bookmark: this should be a returned object from dojo.html.selection.getBookmark()
71
		var _document = dojo.doc;
72
		if(_document.selection){ // IE
73
			var range;
74
			if(dojo.isArray(bookmark)){
75
				range = _document.body.createControlRange();
76
				dojo.forEach(bookmark, range.addElement);
77
			}else{
78
				range = _document.selection.createRange();
79
				range.moveToBookmark(bookmark);
80
			}
81
			range.select();
82
		}else{ //Moz/W3C
83
			var selection = dojo.global.getSelection && dojo.global.getSelection();
84
			if(selection && selection.removeAllRanges){
85
				selection.removeAllRanges();
86
				selection.addRange(bookmark);
87
			}else{
88
				console.debug("No idea how to restore selection for this browser!");
89
			}
90
		}
91
	},
92
 
93
	getFocus: function(/*Widget*/menu, /*Window*/ openedForWindow){
94
		// summary:
95
		//	Returns the current focus and selection.
96
		//	Called when a popup appears (either a top level menu or a dialog),
97
		//	or when a toolbar/menubar receives focus
98
		//
99
		// menu:
100
		//	the menu that's being opened
101
		//
102
		// openedForWindow:
103
		//	iframe in which menu was opened
104
		//
105
		// returns:
106
		//	a handle to restore focus/selection
107
 
108
		return {
109
			// Node to return focus to
110
			node: menu && dojo.isDescendant(dijit._curFocus, menu.domNode) ? dijit._prevFocus : dijit._curFocus,
111
 
112
			// Previously selected text
113
			bookmark:
114
				!dojo.withGlobal(openedForWindow||dojo.global, dijit.isCollapsed) ?
115
				dojo.withGlobal(openedForWindow||dojo.global, dijit.getBookmark) :
116
				null,
117
 
118
			openedForWindow: openedForWindow
119
		}; // Object
120
	},
121
 
122
	focus: function(/*Object || DomNode */ handle){
123
		// summary:
124
		//		Sets the focused node and the selection according to argument.
125
		//		To set focus to an iframe's content, pass in the iframe itself.
126
		// handle:
127
		//		object returned by get(), or a DomNode
128
 
129
		if(!handle){ return; }
130
 
131
		var node = "node" in handle ? handle.node : handle,		// because handle is either DomNode or a composite object
132
			bookmark = handle.bookmark,
133
			openedForWindow = handle.openedForWindow;
134
 
135
		// Set the focus
136
		// Note that for iframe's we need to use the <iframe> to follow the parentNode chain,
137
		// but we need to set focus to iframe.contentWindow
138
		if(node){
139
			var focusNode = (node.tagName.toLowerCase()=="iframe") ? node.contentWindow : node;
140
			if(focusNode && focusNode.focus){
141
				try{
142
					// Gecko throws sometimes if setting focus is impossible,
143
					// node not displayed or something like that
144
					focusNode.focus();
145
				}catch(e){/*quiet*/}
146
			}
147
			dijit._onFocusNode(node);
148
		}
149
 
150
		// set the selection
151
		// do not need to restore if current selection is not empty
152
		// (use keyboard to select a menu item)
153
		if(bookmark && dojo.withGlobal(openedForWindow||dojo.global, dijit.isCollapsed)){
154
			if(openedForWindow){
155
				openedForWindow.focus();
156
			}
157
			try{
158
				dojo.withGlobal(openedForWindow||dojo.global, moveToBookmark, null, [bookmark]);
159
			}catch(e){
160
				/*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */
161
			}
162
		}
163
	},
164
 
165
	// List of currently active widgets (focused widget and it's ancestors)
166
	_activeStack: [],
167
 
168
	registerWin: function(/*Window?*/targetWindow){
169
		// summary:
170
		//		Registers listeners on the specified window (either the main
171
		//		window or an iframe) to detect when the user has clicked somewhere.
172
		//		Anyone that creates an iframe should call this function.
173
 
174
		if(!targetWindow){
175
			targetWindow = window;
176
		}
177
 
178
		dojo.connect(targetWindow.document, "onmousedown", null, function(evt){
179
			dijit._justMouseDowned = true;
180
			setTimeout(function(){ dijit._justMouseDowned = false; }, 0);
181
			dijit._onTouchNode(evt.target||evt.srcElement);
182
		});
183
		//dojo.connect(targetWindow, "onscroll", ???);
184
 
185
		// Listen for blur and focus events on targetWindow's body
186
		var body = targetWindow.document.body || targetWindow.document.getElementsByTagName("body")[0];
187
		if(body){
188
			if(dojo.isIE){
189
				body.attachEvent('onactivate', function(evt){
190
					if(evt.srcElement.tagName.toLowerCase() != "body"){
191
						dijit._onFocusNode(evt.srcElement);
192
					}
193
				});
194
				body.attachEvent('ondeactivate', function(evt){ dijit._onBlurNode(evt.srcElement); });
195
			}else{
196
				body.addEventListener('focus', function(evt){ dijit._onFocusNode(evt.target); }, true);
197
				body.addEventListener('blur', function(evt){ dijit._onBlurNode(evt.target); }, true);
198
			}
199
		}
200
		body = null;	// prevent memory leak (apparent circular reference via closure)
201
	},
202
 
203
	_onBlurNode: function(/*DomNode*/ node){
204
		// summary:
205
		// 		Called when focus leaves a node.
206
		//		Usually ignored, _unless_ it *isn't* follwed by touching another node,
207
		//		which indicates that we tabbed off the last field on the page,
208
		//		in which case every widget is marked inactive
209
		dijit._prevFocus = dijit._curFocus;
210
		dijit._curFocus = null;
211
 
212
		var w = dijit.getEnclosingWidget(node);
213
		if (w && w._setStateClass){
214
			w._focused = false;
215
			w._setStateClass();
216
		}
217
		if(dijit._justMouseDowned){
218
			// the mouse down caused a new widget to be marked as active; this blur event
219
			// is coming late, so ignore it.
220
			return;
221
		}
222
 
223
		// if the blur event isn't followed by a focus event then mark all widgets as inactive.
224
		if(dijit._clearActiveWidgetsTimer){
225
			clearTimeout(dijit._clearActiveWidgetsTimer);
226
		}
227
		dijit._clearActiveWidgetsTimer = setTimeout(function(){
228
			delete dijit._clearActiveWidgetsTimer; dijit._setStack([]); }, 100);
229
	},
230
 
231
	_onTouchNode: function(/*DomNode*/ node){
232
		// summary
233
		//		Callback when node is focused or mouse-downed
234
 
235
		// ignore the recent blurNode event
236
		if(dijit._clearActiveWidgetsTimer){
237
			clearTimeout(dijit._clearActiveWidgetsTimer);
238
			delete dijit._clearActiveWidgetsTimer;
239
		}
240
 
241
		// compute stack of active widgets (ex: ComboButton --> Menu --> MenuItem)
242
		var newStack=[];
243
		try{
244
			while(node){
245
				if(node.dijitPopupParent){
246
					node=dijit.byId(node.dijitPopupParent).domNode;
247
				}else if(node.tagName && node.tagName.toLowerCase()=="body"){
248
					// is this the root of the document or just the root of an iframe?
249
					if(node===dojo.body()){
250
						// node is the root of the main document
251
						break;
252
					}
253
					// otherwise, find the iframe this node refers to (can't access it via parentNode,
254
					// need to do this trick instead) and continue tracing up the document
255
					node=dojo.query("iframe").filter(function(iframe){ return iframe.contentDocument.body===node; })[0];
256
				}else{
257
					var id = node.getAttribute && node.getAttribute("widgetId");
258
					if(id){
259
						newStack.unshift(id);
260
					}
261
					node=node.parentNode;
262
				}
263
			}
264
		}catch(e){ /* squelch */ }
265
 
266
		dijit._setStack(newStack);
267
	},
268
 
269
	_onFocusNode: function(/*DomNode*/ node){
270
		// summary
271
		//		Callback when node is focused
272
		if(node && node.tagName && node.tagName.toLowerCase() == "body"){
273
			return;
274
		}
275
		dijit._onTouchNode(node);
276
		if(node==dijit._curFocus){ return; }
277
		dijit._prevFocus = dijit._curFocus;
278
		dijit._curFocus = node;
279
		dojo.publish("focusNode", [node]);
280
 
281
		// handle focus/blur styling
282
		var w = dijit.getEnclosingWidget(node);
283
		if (w && w._setStateClass){
284
			w._focused = true;
285
			w._setStateClass();
286
		}
287
	},
288
 
289
	_setStack: function(newStack){
290
		// summary
291
		//	The stack of active widgets has changed.  Send out appropriate events and record new stack
292
 
293
		var oldStack = dijit._activeStack;
294
		dijit._activeStack = newStack;
295
 
296
		// compare old stack to new stack to see how many elements they have in common
297
		for(var nCommon=0; nCommon<Math.min(oldStack.length, newStack.length); nCommon++){
298
			if(oldStack[nCommon] != newStack[nCommon]){
299
				break;
300
			}
301
		}
302
 
303
		// for all elements that have gone out of focus, send blur event
304
		for(var i=oldStack.length-1; i>=nCommon; i--){
305
			var widget = dijit.byId(oldStack[i]);
306
			if(widget){
307
				dojo.publish("widgetBlur", [widget]);
308
				if(widget._onBlur){
309
					widget._onBlur();
310
				}
311
			}
312
		}
313
 
314
		// for all element that have come into focus, send focus event
315
		for(var i=nCommon; i<newStack.length; i++){
316
			var widget = dijit.byId(newStack[i]);
317
			if(widget){
318
				dojo.publish("widgetFocus", [widget]);
319
				if(widget._onFocus){
320
					widget._onFocus();
321
				}
322
			}
323
		}
324
	}
325
});
326
 
327
// register top window and all the iframes it contains
328
dojo.addOnLoad(dijit.registerWin);
329
 
330
}