aboutsummaryrefslogtreecommitdiff
path: root/includes/js/dijit/Menu.js
diff options
context:
space:
mode:
Diffstat (limited to 'includes/js/dijit/Menu.js')
-rw-r--r--includes/js/dijit/Menu.js487
1 files changed, 487 insertions, 0 deletions
diff --git a/includes/js/dijit/Menu.js b/includes/js/dijit/Menu.js
new file mode 100644
index 0000000..049c827
--- /dev/null
+++ b/includes/js/dijit/Menu.js
@@ -0,0 +1,487 @@
+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],
+ {
+ // summary
+ // A context menu you can assign to multiple elements
+
+ constructor: function(){
+ this._bindings = [];
+ },
+
+ templateString:
+ '<table class="dijit dijitMenu dijitReset dijitMenuTable" waiRole="menu" dojoAttachEvent="onkeypress:_onKeyPress">' +
+ '<tbody class="dijitReset" dojoAttachPoint="containerNode"></tbody>'+
+ '</table>',
+
+ // 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,
+
+ // leftClickToOpen: Boolean
+ // If true, menu will open on left click instead of right click, similiar to a file menu.
+ leftClickToOpen: 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(){
+ if(this._started){ return; }
+
+ dojo.forEach(this.getChildren(), function(child){ child.startup(); });
+ this.startupKeyNavChildren();
+
+ this.inherited(arguments);
+ },
+
+ 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){
+ // summary: Called when cursor is over a MenuItem
+ 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){
+ // summary: Close all popups that are open and descendants of this menu
+ dijit.popup.close(item.popup);
+ item._blur();
+ this._stopPopupTimer();
+ },
+
+ onItemUnhover: function(/*MenuItem*/ item){
+ // summary: Callback fires when mouse exits a MenuItem
+ },
+
+ _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, /*Event*/ evt){
+ // summary: user defined function to handle clicks on an item
+ 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(evt);
+ }
+ },
+
+ // 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 && dojo.doc.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 && dojo.doc.frames[iframe_el.name] && dojo.doc.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, (this.leftClickToOpen)?"onclick":"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);
+ if(node){
+ 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
+
+ if(this.leftClickToOpen&&e.button>0){
+ return;
+ }
+ 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(){
+ this.inherited('_onBlur', arguments);
+ // 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();
+ }
+ },
+
+ uninitialize: function(){
+ dojo.forEach(this.targetNodeIds, this.unBindDomNode, this);
+ this.inherited(arguments);
+ }
+}
+);
+
+dojo.declare("dijit.MenuItem",
+ [dijit._Widget, dijit._Templated, dijit._Contained],
+ {
+ // summary: A line item in a Menu Widget
+
+ // Make 3 columns
+ // icon, label, and expand arrow (BiDi-dependent) indicating sub-menu
+ templateString:
+ '<tr class="dijitReset dijitMenuItem" '
+ +'dojoAttachEvent="onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick">'
+ +'<td class="dijitReset"><div class="dijitMenuItemIcon ${iconClass}" dojoAttachPoint="iconNode"></div></td>'
+ +'<td tabIndex="-1" class="dijitReset dijitMenuItemLabel" dojoAttachPoint="containerNode,focusNode" waiRole="menuitem"></td>'
+ +'<td class="dijitReset" dojoAttachPoint="arrowCell">'
+ +'<div class="dijitMenuExpand" dojoAttachPoint="expand" style="display:none">'
+ +'<span class="dijitInline dijitArrowNode dijitMenuExpandInner">+</span>'
+ +'</div>'
+ +'</td>'
+ +'</tr>',
+
+ // 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.setLabel(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, evt);
+ dojo.stopEvent(evt);
+ },
+
+ onClick: function(/*Event*/ evt){
+ // 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');
+ },
+
+ setLabel: function(/*String*/ value){
+ this.containerNode.innerHTML=this.label=value;
+ },
+
+ 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(){
+ // summary: The innerHTML contains both the menu item text and a popup widget
+ // description: the first part holds the menu item text and the second part is the popup
+ // example:
+ // | <div dojoType="dijit.PopupMenuItem">
+ // | <span>pick me</span>
+ // | <popup> ... </popup>
+ // | </div>
+ 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(){
+ if(this._started){ return; }
+ this.inherited(arguments);
+
+ // we didn't copy the dropdown widget from the this.srcNodeRef, so it's in no-man's
+ // land now. move it to dojo.doc.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");
+ },
+
+ destroyDescendants: function(){
+ if(this.popup){
+ this.popup.destroyRecursive();
+ delete this.popup;
+ }
+ this.inherited(arguments);
+ }
+});
+
+dojo.declare("dijit.MenuSeparator",
+ [dijit._Widget, dijit._Templated, dijit._Contained],
+ {
+ // summary: A line between two menu items
+
+ templateString: '<tr class="dijitMenuSeparator"><td colspan=3>'
+ +'<div class="dijitMenuSeparatorTop"></div>'
+ +'<div class="dijitMenuSeparatorBottom"></div>'
+ +'</td></tr>',
+
+ postCreate: function(){
+ dojo.setSelectable(this.domNode, false);
+ },
+
+ isFocusable: function(){
+ // summary: over ride to always return false
+ return false; // Boolean
+ }
+});
+
+}