define([ "dojo/_base/array", // array.forEach "dojo/dom", // dom.isDescendant "dojo/_base/lang", // lang.isArray "dojo/topic", // publish "dojo/_base/window", // win.doc win.doc.selection win.global win.global.getSelection win.withGlobal "../focus", "../selection", "../main" // for exporting symbols to dijit ], function(array, dom, lang, topic, win, focus, selection, dijit){ // module: // dijit/_base/focus var exports = { // summary: // Deprecated module to monitor currently focused node and stack of currently focused widgets. // New code should access dijit/focus directly. // _curFocus: DomNode // Currently focused item on screen _curFocus: null, // _prevFocus: DomNode // Previously focused item on screen _prevFocus: null, isCollapsed: function(){ // summary: // Returns true if there is no text selected return dijit.getBookmark().isCollapsed; }, getBookmark: function(){ // summary: // Retrieves a bookmark that can be used with moveToBookmark to return to the same range var sel = win.global == window ? selection : new selection.SelectionManager(win.global); return sel.getBookmark(); }, moveToBookmark: function(/*Object*/ bookmark){ // summary: // Moves current selection to a bookmark // bookmark: // This should be a returned object from dijit.getBookmark() var sel = win.global == window ? selection : new selection.SelectionManager(win.global); return sel.moveToBookmark(bookmark); }, getFocus: function(/*Widget?*/ menu, /*Window?*/ openedForWindow){ // summary: // Called as getFocus(), this returns an Object showing the current focus // and selected text. // // Called as getFocus(widget), where widget is a (widget representing) a button // that was just pressed, it returns where focus was before that button // was pressed. (Pressing the button may have either shifted focus to the button, // or removed focus altogether.) In this case the selected text is not returned, // since it can't be accurately determined. // // menu: dijit/_WidgetBase|{domNode: DomNode} structure // The button that was just pressed. If focus has disappeared or moved // to this button, returns the previous focus. In this case the bookmark // information is already lost, and null is returned. // // openedForWindow: // iframe in which menu was opened // // returns: // A handle to restore focus/selection, to be passed to `dijit.focus` var node = !focus.curNode || (menu && dom.isDescendant(focus.curNode, menu.domNode)) ? dijit._prevFocus : focus.curNode; return { node: node, bookmark: node && (node == focus.curNode) && win.withGlobal(openedForWindow || win.global, dijit.getBookmark), openedForWindow: openedForWindow }; // Object }, // _activeStack: dijit/_WidgetBase[] // List of currently active widgets (focused widget and it's ancestors) _activeStack: [], registerIframe: function(/*DomNode*/ iframe){ // summary: // Registers listeners on the specified iframe so that any click // or focus event on that iframe (or anything in it) is reported // as a focus/click event on the `<iframe>` itself. // description: // Currently only used by editor. // returns: // Handle to pass to unregisterIframe() return focus.registerIframe(iframe); }, unregisterIframe: function(/*Object*/ handle){ // summary: // Unregisters listeners on the specified iframe created by registerIframe. // After calling be sure to delete or null out the handle itself. // handle: // Handle returned by registerIframe() handle && handle.remove(); }, registerWin: function(/*Window?*/targetWindow, /*DomNode?*/ effectiveNode){ // summary: // Registers listeners on the specified window (either the main // window or an iframe's window) to detect when the user has clicked somewhere // or focused somewhere. // description: // Users should call registerIframe() instead of this method. // targetWindow: // If specified this is the window associated with the iframe, // i.e. iframe.contentWindow. // effectiveNode: // If specified, report any focus events inside targetWindow as // an event on effectiveNode, rather than on evt.target. // returns: // Handle to pass to unregisterWin() return focus.registerWin(targetWindow, effectiveNode); }, unregisterWin: function(/*Handle*/ handle){ // summary: // Unregisters listeners on the specified window (either the main // window or an iframe's window) according to handle returned from registerWin(). // After calling be sure to delete or null out the handle itself. handle && handle.remove(); } }; // Override focus singleton's focus function so that dijit.focus() // has backwards compatible behavior of restoring selection (although // probably no one is using that). focus.focus = function(/*Object|DomNode */ handle){ // summary: // Sets the focused node and the selection according to argument. // To set focus to an iframe's content, pass in the iframe itself. // handle: // object returned by get(), or a DomNode if(!handle){ return; } var node = "node" in handle ? handle.node : handle, // because handle is either DomNode or a composite object bookmark = handle.bookmark, openedForWindow = handle.openedForWindow, collapsed = bookmark ? bookmark.isCollapsed : false; // Set the focus // Note that for iframe's we need to use the <iframe> to follow the parentNode chain, // but we need to set focus to iframe.contentWindow if(node){ var focusNode = (node.tagName.toLowerCase() == "iframe") ? node.contentWindow : node; if(focusNode && focusNode.focus){ try{ // Gecko throws sometimes if setting focus is impossible, // node not displayed or something like that focusNode.focus(); }catch(e){/*quiet*/} } focus._onFocusNode(node); } // set the selection // do not need to restore if current selection is not empty // (use keyboard to select a menu item) or if previous selection was collapsed // as it may cause focus shift (Esp in IE). if(bookmark && win.withGlobal(openedForWindow || win.global, dijit.isCollapsed) && !collapsed){ if(openedForWindow){ openedForWindow.focus(); } try{ win.withGlobal(openedForWindow || win.global, dijit.moveToBookmark, null, [bookmark]); }catch(e2){ /*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */ } } }; // For back compatibility, monitor changes to focused node and active widget stack, // publishing events and copying changes from focus manager variables into dijit (top level) variables focus.watch("curNode", function(name, oldVal, newVal){ dijit._curFocus = newVal; dijit._prevFocus = oldVal; if(newVal){ topic.publish("focusNode", newVal); // publish } }); focus.watch("activeStack", function(name, oldVal, newVal){ dijit._activeStack = newVal; }); focus.on("widget-blur", function(widget, by){ topic.publish("widgetBlur", widget, by); // publish }); focus.on("widget-focus", function(widget, by){ topic.publish("widgetFocus", widget, by); // publish }); lang.mixin(dijit, exports); /*===== return exports; =====*/ return dijit; // for back compat :-( });