]> git.wh0rd.org - tt-rss.git/blob - lib/dijit/_base/focus.js.uncompressed.js
make precache_headlines_idle() start slower
[tt-rss.git] / lib / dijit / _base / focus.js.uncompressed.js
1 define("dijit/_base/focus", [
2 "dojo/_base/array", // array.forEach
3 "dojo/dom", // dom.isDescendant
4 "dojo/_base/lang", // lang.isArray
5 "dojo/topic", // publish
6 "dojo/_base/window", // win.doc win.doc.selection win.global win.global.getSelection win.withGlobal
7 "../focus",
8 ".." // for exporting symbols to dijit
9 ], function(array, dom, lang, topic, win, focus, dijit){
10
11 // module:
12 // dijit/_base/focus
13 // summary:
14 // Deprecated module to monitor currently focused node and stack of currently focused widgets.
15 // New code should access dijit/focus directly.
16
17 lang.mixin(dijit, {
18 // _curFocus: DomNode
19 // Currently focused item on screen
20 _curFocus: null,
21
22 // _prevFocus: DomNode
23 // Previously focused item on screen
24 _prevFocus: null,
25
26 isCollapsed: function(){
27 // summary:
28 // Returns true if there is no text selected
29 return dijit.getBookmark().isCollapsed;
30 },
31
32 getBookmark: function(){
33 // summary:
34 // Retrieves a bookmark that can be used with moveToBookmark to return to the same range
35 var bm, rg, tg, sel = win.doc.selection, cf = focus.curNode;
36
37 if(win.global.getSelection){
38 //W3C Range API for selections.
39 sel = win.global.getSelection();
40 if(sel){
41 if(sel.isCollapsed){
42 tg = cf? cf.tagName : "";
43 if(tg){
44 //Create a fake rangelike item to restore selections.
45 tg = tg.toLowerCase();
46 if(tg == "textarea" ||
47 (tg == "input" && (!cf.type || cf.type.toLowerCase() == "text"))){
48 sel = {
49 start: cf.selectionStart,
50 end: cf.selectionEnd,
51 node: cf,
52 pRange: true
53 };
54 return {isCollapsed: (sel.end <= sel.start), mark: sel}; //Object.
55 }
56 }
57 bm = {isCollapsed:true};
58 if(sel.rangeCount){
59 bm.mark = sel.getRangeAt(0).cloneRange();
60 }
61 }else{
62 rg = sel.getRangeAt(0);
63 bm = {isCollapsed: false, mark: rg.cloneRange()};
64 }
65 }
66 }else if(sel){
67 // If the current focus was a input of some sort and no selection, don't bother saving
68 // a native bookmark. This is because it causes issues with dialog/page selection restore.
69 // So, we need to create psuedo bookmarks to work with.
70 tg = cf ? cf.tagName : "";
71 tg = tg.toLowerCase();
72 if(cf && tg && (tg == "button" || tg == "textarea" || tg == "input")){
73 if(sel.type && sel.type.toLowerCase() == "none"){
74 return {
75 isCollapsed: true,
76 mark: null
77 }
78 }else{
79 rg = sel.createRange();
80 return {
81 isCollapsed: rg.text && rg.text.length?false:true,
82 mark: {
83 range: rg,
84 pRange: true
85 }
86 };
87 }
88 }
89 bm = {};
90
91 //'IE' way for selections.
92 try{
93 // createRange() throws exception when dojo in iframe
94 //and nothing selected, see #9632
95 rg = sel.createRange();
96 bm.isCollapsed = !(sel.type == 'Text' ? rg.htmlText.length : rg.length);
97 }catch(e){
98 bm.isCollapsed = true;
99 return bm;
100 }
101 if(sel.type.toUpperCase() == 'CONTROL'){
102 if(rg.length){
103 bm.mark=[];
104 var i=0,len=rg.length;
105 while(i<len){
106 bm.mark.push(rg.item(i++));
107 }
108 }else{
109 bm.isCollapsed = true;
110 bm.mark = null;
111 }
112 }else{
113 bm.mark = rg.getBookmark();
114 }
115 }else{
116 console.warn("No idea how to store the current selection for this browser!");
117 }
118 return bm; // Object
119 },
120
121 moveToBookmark: function(/*Object*/ bookmark){
122 // summary:
123 // Moves current selection to a bookmark
124 // bookmark:
125 // This should be a returned object from dijit.getBookmark()
126
127 var _doc = win.doc,
128 mark = bookmark.mark;
129 if(mark){
130 if(win.global.getSelection){
131 //W3C Rangi API (FF, WebKit, Opera, etc)
132 var sel = win.global.getSelection();
133 if(sel && sel.removeAllRanges){
134 if(mark.pRange){
135 var n = mark.node;
136 n.selectionStart = mark.start;
137 n.selectionEnd = mark.end;
138 }else{
139 sel.removeAllRanges();
140 sel.addRange(mark);
141 }
142 }else{
143 console.warn("No idea how to restore selection for this browser!");
144 }
145 }else if(_doc.selection && mark){
146 //'IE' way.
147 var rg;
148 if(mark.pRange){
149 rg = mark.range;
150 }else if(lang.isArray(mark)){
151 rg = _doc.body.createControlRange();
152 //rg.addElement does not have call/apply method, so can not call it directly
153 //rg is not available in "range.addElement(item)", so can't use that either
154 array.forEach(mark, function(n){
155 rg.addElement(n);
156 });
157 }else{
158 rg = _doc.body.createTextRange();
159 rg.moveToBookmark(mark);
160 }
161 rg.select();
162 }
163 }
164 },
165
166 getFocus: function(/*Widget?*/ menu, /*Window?*/ openedForWindow){
167 // summary:
168 // Called as getFocus(), this returns an Object showing the current focus
169 // and selected text.
170 //
171 // Called as getFocus(widget), where widget is a (widget representing) a button
172 // that was just pressed, it returns where focus was before that button
173 // was pressed. (Pressing the button may have either shifted focus to the button,
174 // or removed focus altogether.) In this case the selected text is not returned,
175 // since it can't be accurately determined.
176 //
177 // menu: dijit._Widget or {domNode: DomNode} structure
178 // The button that was just pressed. If focus has disappeared or moved
179 // to this button, returns the previous focus. In this case the bookmark
180 // information is already lost, and null is returned.
181 //
182 // openedForWindow:
183 // iframe in which menu was opened
184 //
185 // returns:
186 // A handle to restore focus/selection, to be passed to `dijit.focus`
187 var node = !focus.curNode || (menu && dom.isDescendant(focus.curNode, menu.domNode)) ? dijit._prevFocus : focus.curNode;
188 return {
189 node: node,
190 bookmark: node && (node == focus.curNode) && win.withGlobal(openedForWindow || win.global, dijit.getBookmark),
191 openedForWindow: openedForWindow
192 }; // Object
193 },
194
195 // _activeStack: dijit._Widget[]
196 // List of currently active widgets (focused widget and it's ancestors)
197 _activeStack: [],
198
199 registerIframe: function(/*DomNode*/ iframe){
200 // summary:
201 // Registers listeners on the specified iframe so that any click
202 // or focus event on that iframe (or anything in it) is reported
203 // as a focus/click event on the <iframe> itself.
204 // description:
205 // Currently only used by editor.
206 // returns:
207 // Handle to pass to unregisterIframe()
208 return focus.registerIframe(iframe);
209 },
210
211 unregisterIframe: function(/*Object*/ handle){
212 // summary:
213 // Unregisters listeners on the specified iframe created by registerIframe.
214 // After calling be sure to delete or null out the handle itself.
215 // handle:
216 // Handle returned by registerIframe()
217
218 handle && handle.remove();
219 },
220
221 registerWin: function(/*Window?*/targetWindow, /*DomNode?*/ effectiveNode){
222 // summary:
223 // Registers listeners on the specified window (either the main
224 // window or an iframe's window) to detect when the user has clicked somewhere
225 // or focused somewhere.
226 // description:
227 // Users should call registerIframe() instead of this method.
228 // targetWindow:
229 // If specified this is the window associated with the iframe,
230 // i.e. iframe.contentWindow.
231 // effectiveNode:
232 // If specified, report any focus events inside targetWindow as
233 // an event on effectiveNode, rather than on evt.target.
234 // returns:
235 // Handle to pass to unregisterWin()
236
237 return focus.registerWin(targetWindow, effectiveNode);
238 },
239
240 unregisterWin: function(/*Handle*/ handle){
241 // summary:
242 // Unregisters listeners on the specified window (either the main
243 // window or an iframe's window) according to handle returned from registerWin().
244 // After calling be sure to delete or null out the handle itself.
245
246 handle && handle.remove();
247 }
248 });
249
250 // Override focus singleton's focus function so that dijit.focus()
251 // has backwards compatible behavior of restoring selection (although
252 // probably no one is using that).
253 focus.focus = function(/*Object || DomNode */ handle){
254 // summary:
255 // Sets the focused node and the selection according to argument.
256 // To set focus to an iframe's content, pass in the iframe itself.
257 // handle:
258 // object returned by get(), or a DomNode
259
260 if(!handle){ return; }
261
262 var node = "node" in handle ? handle.node : handle, // because handle is either DomNode or a composite object
263 bookmark = handle.bookmark,
264 openedForWindow = handle.openedForWindow,
265 collapsed = bookmark ? bookmark.isCollapsed : false;
266
267 // Set the focus
268 // Note that for iframe's we need to use the <iframe> to follow the parentNode chain,
269 // but we need to set focus to iframe.contentWindow
270 if(node){
271 var focusNode = (node.tagName.toLowerCase() == "iframe") ? node.contentWindow : node;
272 if(focusNode && focusNode.focus){
273 try{
274 // Gecko throws sometimes if setting focus is impossible,
275 // node not displayed or something like that
276 focusNode.focus();
277 }catch(e){/*quiet*/}
278 }
279 focus._onFocusNode(node);
280 }
281
282 // set the selection
283 // do not need to restore if current selection is not empty
284 // (use keyboard to select a menu item) or if previous selection was collapsed
285 // as it may cause focus shift (Esp in IE).
286 if(bookmark && win.withGlobal(openedForWindow || win.global, dijit.isCollapsed) && !collapsed){
287 if(openedForWindow){
288 openedForWindow.focus();
289 }
290 try{
291 win.withGlobal(openedForWindow || win.global, dijit.moveToBookmark, null, [bookmark]);
292 }catch(e2){
293 /*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */
294 }
295 }
296 };
297
298 // For back compatibility, monitor changes to focused node and active widget stack,
299 // publishing events and copying changes from focus manager variables into dijit (top level) variables
300 focus.watch("curNode", function(name, oldVal, newVal){
301 dijit._curFocus = newVal;
302 dijit._prevFocus = oldVal;
303 if(newVal){
304 topic.publish("focusNode", newVal); // publish
305 }
306 });
307 focus.watch("activeStack", function(name, oldVal, newVal){
308 dijit._activeStack = newVal;
309 });
310
311 focus.on("widget-blur", function(widget, by){
312 topic.publish("widgetBlur", widget, by); // publish
313 });
314 focus.on("widget-focus", function(widget, by){
315 topic.publish("widgetFocus", widget, by); // publish
316 });
317
318 return dijit;
319 });