]> git.wh0rd.org Git - 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 });