[483] | 1 | define([ |
---|
| 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 | "../selection", |
---|
| 9 | "../main" // for exporting symbols to dijit |
---|
| 10 | ], function(array, dom, lang, topic, win, focus, selection, dijit){ |
---|
| 11 | |
---|
| 12 | // module: |
---|
| 13 | // dijit/_base/focus |
---|
| 14 | |
---|
| 15 | var exports = { |
---|
| 16 | // summary: |
---|
| 17 | // Deprecated module to monitor currently focused node and stack of currently focused widgets. |
---|
| 18 | // New code should access dijit/focus directly. |
---|
| 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: |
---|
| 30 | // Returns true if there is no text selected |
---|
| 31 | return dijit.getBookmark().isCollapsed; |
---|
| 32 | }, |
---|
| 33 | |
---|
| 34 | getBookmark: function(){ |
---|
| 35 | // summary: |
---|
| 36 | // Retrieves a bookmark that can be used with moveToBookmark to return to the same range |
---|
| 37 | var sel = win.global == window ? selection : new selection.SelectionManager(win.global); |
---|
| 38 | return sel.getBookmark(); |
---|
| 39 | }, |
---|
| 40 | |
---|
| 41 | moveToBookmark: function(/*Object*/ bookmark){ |
---|
| 42 | // summary: |
---|
| 43 | // Moves current selection to a bookmark |
---|
| 44 | // bookmark: |
---|
| 45 | // This should be a returned object from dijit.getBookmark() |
---|
| 46 | |
---|
| 47 | var sel = win.global == window ? selection : new selection.SelectionManager(win.global); |
---|
| 48 | return sel.moveToBookmark(bookmark); |
---|
| 49 | }, |
---|
| 50 | |
---|
| 51 | getFocus: function(/*Widget?*/ menu, /*Window?*/ openedForWindow){ |
---|
| 52 | // summary: |
---|
| 53 | // Called as getFocus(), this returns an Object showing the current focus |
---|
| 54 | // and selected text. |
---|
| 55 | // |
---|
| 56 | // Called as getFocus(widget), where widget is a (widget representing) a button |
---|
| 57 | // that was just pressed, it returns where focus was before that button |
---|
| 58 | // was pressed. (Pressing the button may have either shifted focus to the button, |
---|
| 59 | // or removed focus altogether.) In this case the selected text is not returned, |
---|
| 60 | // since it can't be accurately determined. |
---|
| 61 | // |
---|
| 62 | // menu: dijit/_WidgetBase|{domNode: DomNode} structure |
---|
| 63 | // The button that was just pressed. If focus has disappeared or moved |
---|
| 64 | // to this button, returns the previous focus. In this case the bookmark |
---|
| 65 | // information is already lost, and null is returned. |
---|
| 66 | // |
---|
| 67 | // openedForWindow: |
---|
| 68 | // iframe in which menu was opened |
---|
| 69 | // |
---|
| 70 | // returns: |
---|
| 71 | // A handle to restore focus/selection, to be passed to `dijit.focus` |
---|
| 72 | var node = !focus.curNode || (menu && dom.isDescendant(focus.curNode, menu.domNode)) ? dijit._prevFocus : focus.curNode; |
---|
| 73 | return { |
---|
| 74 | node: node, |
---|
| 75 | bookmark: node && (node == focus.curNode) && win.withGlobal(openedForWindow || win.global, dijit.getBookmark), |
---|
| 76 | openedForWindow: openedForWindow |
---|
| 77 | }; // Object |
---|
| 78 | }, |
---|
| 79 | |
---|
| 80 | // _activeStack: dijit/_WidgetBase[] |
---|
| 81 | // List of currently active widgets (focused widget and it's ancestors) |
---|
| 82 | _activeStack: [], |
---|
| 83 | |
---|
| 84 | registerIframe: function(/*DomNode*/ iframe){ |
---|
| 85 | // summary: |
---|
| 86 | // Registers listeners on the specified iframe so that any click |
---|
| 87 | // or focus event on that iframe (or anything in it) is reported |
---|
| 88 | // as a focus/click event on the `<iframe>` itself. |
---|
| 89 | // description: |
---|
| 90 | // Currently only used by editor. |
---|
| 91 | // returns: |
---|
| 92 | // Handle to pass to unregisterIframe() |
---|
| 93 | return focus.registerIframe(iframe); |
---|
| 94 | }, |
---|
| 95 | |
---|
| 96 | unregisterIframe: function(/*Object*/ handle){ |
---|
| 97 | // summary: |
---|
| 98 | // Unregisters listeners on the specified iframe created by registerIframe. |
---|
| 99 | // After calling be sure to delete or null out the handle itself. |
---|
| 100 | // handle: |
---|
| 101 | // Handle returned by registerIframe() |
---|
| 102 | |
---|
| 103 | handle && handle.remove(); |
---|
| 104 | }, |
---|
| 105 | |
---|
| 106 | registerWin: function(/*Window?*/targetWindow, /*DomNode?*/ effectiveNode){ |
---|
| 107 | // summary: |
---|
| 108 | // Registers listeners on the specified window (either the main |
---|
| 109 | // window or an iframe's window) to detect when the user has clicked somewhere |
---|
| 110 | // or focused somewhere. |
---|
| 111 | // description: |
---|
| 112 | // Users should call registerIframe() instead of this method. |
---|
| 113 | // targetWindow: |
---|
| 114 | // If specified this is the window associated with the iframe, |
---|
| 115 | // i.e. iframe.contentWindow. |
---|
| 116 | // effectiveNode: |
---|
| 117 | // If specified, report any focus events inside targetWindow as |
---|
| 118 | // an event on effectiveNode, rather than on evt.target. |
---|
| 119 | // returns: |
---|
| 120 | // Handle to pass to unregisterWin() |
---|
| 121 | |
---|
| 122 | return focus.registerWin(targetWindow, effectiveNode); |
---|
| 123 | }, |
---|
| 124 | |
---|
| 125 | unregisterWin: function(/*Handle*/ handle){ |
---|
| 126 | // summary: |
---|
| 127 | // Unregisters listeners on the specified window (either the main |
---|
| 128 | // window or an iframe's window) according to handle returned from registerWin(). |
---|
| 129 | // After calling be sure to delete or null out the handle itself. |
---|
| 130 | |
---|
| 131 | handle && handle.remove(); |
---|
| 132 | } |
---|
| 133 | }; |
---|
| 134 | |
---|
| 135 | // Override focus singleton's focus function so that dijit.focus() |
---|
| 136 | // has backwards compatible behavior of restoring selection (although |
---|
| 137 | // probably no one is using that). |
---|
| 138 | focus.focus = function(/*Object|DomNode */ handle){ |
---|
| 139 | // summary: |
---|
| 140 | // Sets the focused node and the selection according to argument. |
---|
| 141 | // To set focus to an iframe's content, pass in the iframe itself. |
---|
| 142 | // handle: |
---|
| 143 | // object returned by get(), or a DomNode |
---|
| 144 | |
---|
| 145 | if(!handle){ return; } |
---|
| 146 | |
---|
| 147 | var node = "node" in handle ? handle.node : handle, // because handle is either DomNode or a composite object |
---|
| 148 | bookmark = handle.bookmark, |
---|
| 149 | openedForWindow = handle.openedForWindow, |
---|
| 150 | collapsed = bookmark ? bookmark.isCollapsed : false; |
---|
| 151 | |
---|
| 152 | // Set the focus |
---|
| 153 | // Note that for iframe's we need to use the <iframe> to follow the parentNode chain, |
---|
| 154 | // but we need to set focus to iframe.contentWindow |
---|
| 155 | if(node){ |
---|
| 156 | var focusNode = (node.tagName.toLowerCase() == "iframe") ? node.contentWindow : node; |
---|
| 157 | if(focusNode && focusNode.focus){ |
---|
| 158 | try{ |
---|
| 159 | // Gecko throws sometimes if setting focus is impossible, |
---|
| 160 | // node not displayed or something like that |
---|
| 161 | focusNode.focus(); |
---|
| 162 | }catch(e){/*quiet*/} |
---|
| 163 | } |
---|
| 164 | focus._onFocusNode(node); |
---|
| 165 | } |
---|
| 166 | |
---|
| 167 | // set the selection |
---|
| 168 | // do not need to restore if current selection is not empty |
---|
| 169 | // (use keyboard to select a menu item) or if previous selection was collapsed |
---|
| 170 | // as it may cause focus shift (Esp in IE). |
---|
| 171 | if(bookmark && win.withGlobal(openedForWindow || win.global, dijit.isCollapsed) && !collapsed){ |
---|
| 172 | if(openedForWindow){ |
---|
| 173 | openedForWindow.focus(); |
---|
| 174 | } |
---|
| 175 | try{ |
---|
| 176 | win.withGlobal(openedForWindow || win.global, dijit.moveToBookmark, null, [bookmark]); |
---|
| 177 | }catch(e2){ |
---|
| 178 | /*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */ |
---|
| 179 | } |
---|
| 180 | } |
---|
| 181 | }; |
---|
| 182 | |
---|
| 183 | // For back compatibility, monitor changes to focused node and active widget stack, |
---|
| 184 | // publishing events and copying changes from focus manager variables into dijit (top level) variables |
---|
| 185 | focus.watch("curNode", function(name, oldVal, newVal){ |
---|
| 186 | dijit._curFocus = newVal; |
---|
| 187 | dijit._prevFocus = oldVal; |
---|
| 188 | if(newVal){ |
---|
| 189 | topic.publish("focusNode", newVal); // publish |
---|
| 190 | } |
---|
| 191 | }); |
---|
| 192 | focus.watch("activeStack", function(name, oldVal, newVal){ |
---|
| 193 | dijit._activeStack = newVal; |
---|
| 194 | }); |
---|
| 195 | |
---|
| 196 | focus.on("widget-blur", function(widget, by){ |
---|
| 197 | topic.publish("widgetBlur", widget, by); // publish |
---|
| 198 | }); |
---|
| 199 | focus.on("widget-focus", function(widget, by){ |
---|
| 200 | topic.publish("widgetFocus", widget, by); // publish |
---|
| 201 | }); |
---|
| 202 | |
---|
| 203 | lang.mixin(dijit, exports); |
---|
| 204 | |
---|
| 205 | /*===== return exports; =====*/ |
---|
| 206 | return dijit; // for back compat :-( |
---|
| 207 | }); |
---|