if (!dojo._hasResource["dijit.Menu"]) { // _hasResource checks added by build. // Do not use _hasResource directly in // your code. dojo._hasResource["dijit.Menu"] = true; dojo.provide("dijit.Menu"); dojo.require("dijit._Widget"); dojo.require("dijit._Container"); dojo.require("dijit._Templated"); dojo.declare("dijit.Menu", [dijit._Widget, dijit._Templated, dijit._KeyNavContainer], { constructor : function() { this._bindings = []; }, templateString : '' + '' + '
', // targetNodeIds: String[] // Array of dom node ids of nodes to attach to. // Fill this with nodeIds upon widget creation and it becomes // context menu for those nodes. targetNodeIds : [], // contextMenuForWindow: Boolean // if true, right clicking anywhere on the window will cause // this context menu to open; // if false, must specify targetNodeIds contextMenuForWindow : false, // parentMenu: Widget // pointer to menu that displayed me parentMenu : null, // popupDelay: Integer // number of milliseconds before hovering (without clicking) // causes the popup to automatically open popupDelay : 500, // _contextMenuWithMouse: Boolean // used to record mouse and keyboard events to determine if a // context // menu is being opened with the keyboard or the mouse _contextMenuWithMouse : false, postCreate : function() { if (this.contextMenuForWindow) { this.bindDomNode(dojo.body()); } else { dojo .forEach(this.targetNodeIds, this.bindDomNode, this); } this.connectKeyNavHandlers([dojo.keys.UP_ARROW], [dojo.keys.DOWN_ARROW]); }, startup : function() { dojo.forEach(this.getChildren(), function(child) { child.startup(); }); this.startupKeyNavChildren(); }, onExecute : function() { // summary: attach point for notification about when a menu // item has been executed }, onCancel : function(/* Boolean */closeAll) { // summary: attach point for notification about when the // user cancels the current menu }, _moveToPopup : function(/* Event */evt) { if (this.focusedChild && this.focusedChild.popup && !this.focusedChild.disabled) { this.focusedChild._onClick(evt); } }, _onKeyPress : function(/* Event */evt) { // summary // Handle keyboard based menu navigation. if (evt.ctrlKey || evt.altKey) { return; } switch (evt.keyCode) { case dojo.keys.RIGHT_ARROW : this._moveToPopup(evt); dojo.stopEvent(evt); break; case dojo.keys.LEFT_ARROW : if (this.parentMenu) { this.onCancel(false); } else { dojo.stopEvent(evt); } break; } }, onItemHover : function(/* MenuItem */item) { this.focusChild(item); if (this.focusedChild.popup && !this.focusedChild.disabled && !this.hover_timer) { this.hover_timer = setTimeout(dojo.hitch(this, "_openPopup"), this.popupDelay); } }, _onChildBlur : function(item) { // Close all popups that are open and descendants of this // menu dijit.popup.close(item.popup); item._blur(); this._stopPopupTimer(); }, onItemUnhover : function(/* MenuItem */item) { }, _stopPopupTimer : function() { if (this.hover_timer) { clearTimeout(this.hover_timer); this.hover_timer = null; } }, _getTopMenu : function() { for (var top = this; top.parentMenu; top = top.parentMenu); return top; }, onItemClick : function(/* Widget */item) { // summary: user defined function to handle clicks on an // item // summary: internal function for clicks if (item.disabled) { return false; } if (item.popup) { if (!this.is_open) { this._openPopup(); } } else { // before calling user defined handler, close hierarchy // of menus // and restore focus to place it was when menu was // opened this.onExecute(); // user defined handler for click item.onClick(); } }, // thanks burstlib! _iframeContentWindow : function( /* HTMLIFrameElement */iframe_el) { // summary // returns the window reference of the passed iframe var win = dijit.getDocumentWindow(dijit.Menu ._iframeContentDocument(iframe_el)) || // Moz. TODO: is this available when defaultView // isn't? dijit.Menu._iframeContentDocument(iframe_el)['__parent__'] || (iframe_el.name && document.frames[iframe_el.name]) || null; return win; // Window }, _iframeContentDocument : function( /* HTMLIFrameElement */iframe_el) { // summary // returns a reference to the document object inside // iframe_el var doc = iframe_el.contentDocument // W3 || (iframe_el.contentWindow && iframe_el.contentWindow.document) // IE || (iframe_el.name && document.frames[iframe_el.name] && document.frames[iframe_el.name].document) || null; return doc; // HTMLDocument }, bindDomNode : function(/* String|DomNode */node) { // summary: attach menu to given node node = dojo.byId(node); // TODO: this is to support context popups in Editor. Maybe // this shouldn't be in dijit.Menu var win = dijit.getDocumentWindow(node.ownerDocument); if (node.tagName.toLowerCase() == "iframe") { win = this._iframeContentWindow(node); node = dojo.withGlobal(win, dojo.body); } // to capture these events at the top level, // attach to document, not body var cn = (node == dojo.body() ? dojo.doc : node); node[this.id] = this._bindings.push([ dojo.connect(cn, "oncontextmenu", this, "_openMyself"), dojo.connect(cn, "onkeydown", this, "_contextKey"), dojo.connect(cn, "onmousedown", this, "_contextMouse")]); }, unBindDomNode : function(/* String|DomNode */nodeName) { // summary: detach menu from given node var node = dojo.byId(nodeName); var bid = node[this.id] - 1, b = this._bindings[bid]; dojo.forEach(b, dojo.disconnect); delete this._bindings[bid]; }, _contextKey : function(e) { this._contextMenuWithMouse = false; if (e.keyCode == dojo.keys.F10) { dojo.stopEvent(e); if (e.shiftKey && e.type == "keydown") { // FF: copying the wrong property from e will cause // the system // context menu to appear in spite of stopEvent. // Don't know // exactly which properties cause this effect. var _e = { target : e.target, pageX : e.pageX, pageY : e.pageY }; _e.preventDefault = _e.stopPropagation = function() { }; // IE: without the delay, focus work in "open" // causes the system // context menu to appear in spite of stopEvent. window.setTimeout(dojo.hitch(this, function() { this._openMyself(_e); }), 1); } } }, _contextMouse : function(e) { this._contextMenuWithMouse = true; }, _openMyself : function(/* Event */e) { // summary: // Internal function for opening myself when the user // does a right-click or something similar dojo.stopEvent(e); // Get coordinates. // if we are opening the menu with the mouse or on safari // open // the menu at the mouse cursor // (Safari does not have a keyboard command to open the // context menu // and we don't currently have a reliable way to determine // _contextMenuWithMouse on Safari) var x, y; if (dojo.isSafari || this._contextMenuWithMouse) { x = e.pageX; y = e.pageY; } else { // otherwise open near e.target var coords = dojo.coords(e.target, true); x = coords.x + 10; y = coords.y + 10; } var self = this; var savedFocus = dijit.getFocus(this); function closeAndRestoreFocus() { // user has clicked on a menu or popup dijit.focus(savedFocus); dijit.popup.close(self); } dijit.popup.open({ popup : this, x : x, y : y, onExecute : closeAndRestoreFocus, onCancel : closeAndRestoreFocus, orient : this.isLeftToRight() ? 'L' : 'R' }); this.focus(); this._onBlur = function() { // Usually the parent closes the child widget but if // this is a context // menu then there is no parent dijit.popup.close(this); // don't try to restore focus; user has clicked another // part of the screen // and set focus there } }, onOpen : function(/* Event */e) { // summary // Open menu relative to the mouse this.isShowingNow = true; }, onClose : function() { // summary: callback when this menu is closed this._stopPopupTimer(); this.parentMenu = null; this.isShowingNow = false; this.currentPopup = null; if (this.focusedChild) { this._onChildBlur(this.focusedChild); this.focusedChild = null; } }, _openPopup : function() { // summary: open the popup to the side of the current menu // item this._stopPopupTimer(); var from_item = this.focusedChild; var popup = from_item.popup; if (popup.isShowingNow) { return; } popup.parentMenu = this; var self = this; dijit.popup.open({ parent : this, popup : popup, around : from_item.arrowCell, orient : this.isLeftToRight() ? { 'TR' : 'TL', 'TL' : 'TR' } : { 'TL' : 'TR', 'TR' : 'TL' }, onCancel : function() { // called when the child menu is canceled dijit.popup.close(popup); from_item.focus(); // put focus back on my // node self.currentPopup = null; } }); this.currentPopup = popup; if (popup.focus) { popup.focus(); } } }); dojo.declare("dijit.MenuItem", [dijit._Widget, dijit._Templated, dijit._Contained], { // summary // A line item in a Menu2 // Make 3 columns // icon, label, and expand arrow (BiDi-dependent) indicating // sub-menu templateString : '' + '
' + '' + '' + '' + '' + '', // label: String // menu text label : '', // iconClass: String // class to apply to div in button to make it display an icon iconClass : "", // disabled: Boolean // if true, the menu item is disabled // if false, the menu item is enabled disabled : false, postCreate : function() { dojo.setSelectable(this.domNode, false); this.setDisabled(this.disabled); if (this.label) { this.containerNode.innerHTML = this.label; } }, _onHover : function() { // summary: callback when mouse is moved onto menu item this.getParent().onItemHover(this); }, _onUnhover : function() { // summary: callback when mouse is moved off of menu item // if we are unhovering the currently selected item // then unselect it this.getParent().onItemUnhover(this); }, _onClick : function(evt) { this.getParent().onItemClick(this); dojo.stopEvent(evt); }, onClick : function() { // summary // User defined function to handle clicks }, focus : function() { dojo.addClass(this.domNode, 'dijitMenuItemHover'); try { dijit.focus(this.containerNode); } catch (e) { // this throws on IE (at least) in some scenarios } }, _blur : function() { dojo.removeClass(this.domNode, 'dijitMenuItemHover'); }, setDisabled : function(/* Boolean */value) { // summary: enable or disable this menu item this.disabled = value; dojo[value ? "addClass" : "removeClass"](this.domNode, 'dijitMenuItemDisabled'); dijit.setWaiState(this.containerNode, 'disabled', value ? 'true' : 'false'); } }); dojo.declare("dijit.PopupMenuItem", dijit.MenuItem, { _fillContent : function() { // my inner HTML contains both the menu item text and a // popup widget, like //
// pick me // ... //
// the first part holds the menu item text and the second // part is the popup if (this.srcNodeRef) { var nodes = dojo.query("*", this.srcNodeRef); dijit.PopupMenuItem.superclass._fillContent.call(this, nodes[0]); // save pointer to srcNode so we can grab the drop down // widget after it's instantiated this.dropDownContainer = this.srcNodeRef; } }, startup : function() { // we didn't copy the dropdown widget from the // this.srcNodeRef, so it's in no-man's // land now. move it to document.body. if (!this.popup) { var node = dojo.query("[widgetId]", this.dropDownContainer)[0]; this.popup = dijit.byNode(node); } dojo.body().appendChild(this.popup.domNode); this.popup.domNode.style.display = "none"; dojo.addClass(this.expand, "dijitMenuExpandEnabled"); dojo.style(this.expand, "display", ""); dijit.setWaiState(this.containerNode, "haspopup", "true"); } }); dojo.declare("dijit.MenuSeparator", [dijit._Widget, dijit._Templated, dijit._Contained], { // summary // A line between two menu items templateString : '' + '
' + '
' + '', postCreate : function() { dojo.setSelectable(this.domNode, false); }, isFocusable : function() { // summary: // over ride to always return false return false; } }); }