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
//
// 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;
}
});
}