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