summaryrefslogtreecommitdiff
path: root/lib/dijit/Menu.js.uncompressed.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dijit/Menu.js.uncompressed.js')
-rw-r--r--lib/dijit/Menu.js.uncompressed.js321
1 files changed, 321 insertions, 0 deletions
diff --git a/lib/dijit/Menu.js.uncompressed.js b/lib/dijit/Menu.js.uncompressed.js
new file mode 100644
index 000000000..d8d78bd76
--- /dev/null
+++ b/lib/dijit/Menu.js.uncompressed.js
@@ -0,0 +1,321 @@
+define("dijit/Menu", [
+ "require",
+ "dojo/_base/array", // array.forEach
+ "dojo/_base/declare", // declare
+ "dojo/_base/event", // event.stop
+ "dojo/dom", // dom.byId dom.isDescendant
+ "dojo/dom-attr", // domAttr.get domAttr.set domAttr.has domAttr.remove
+ "dojo/dom-geometry", // domStyle.getComputedStyle domGeometry.position
+ "dojo/dom-style", // domStyle.getComputedStyle
+ "dojo/_base/kernel",
+ "dojo/keys", // keys.F10
+ "dojo/_base/lang", // lang.hitch
+ "dojo/on",
+ "dojo/_base/sniff", // has("ie"), has("quirks")
+ "dojo/_base/window", // win.body win.doc.documentElement win.doc.frames win.withGlobal
+ "dojo/window", // winUtils.get
+ "./popup",
+ "./DropDownMenu",
+ "dojo/ready"
+], function(require, array, declare, event, dom, domAttr, domGeometry, domStyle, kernel, keys, lang, on,
+ has, win, winUtils, pm, DropDownMenu, ready){
+
+/*=====
+ var DropDownMenu = dijit.DropDownMenu;
+=====*/
+
+// module:
+// dijit/Menu
+// summary:
+// Includes dijit.Menu widget and base class dijit._MenuBase
+
+// Back compat w/1.6, remove for 2.0
+if(!kernel.isAsync){
+ ready(0, function(){
+ var requires = ["dijit/MenuItem", "dijit/PopupMenuItem", "dijit/CheckedMenuItem", "dijit/MenuSeparator"];
+ require(requires); // use indirection so modules not rolled into a build
+ });
+}
+
+return declare("dijit.Menu", DropDownMenu, {
+ // summary:
+ // A context menu you can assign to multiple elements
+
+ constructor: function(){
+ this._bindings = [];
+ },
+
+ // targetNodeIds: [const] 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: [const] Boolean
+ // If true, right clicking anywhere on the window will cause this context menu to open.
+ // If false, must specify targetNodeIds.
+ contextMenuForWindow: false,
+
+ // leftClickToOpen: [const] Boolean
+ // If true, menu will open on left click instead of right click, similar to a file menu.
+ leftClickToOpen: false,
+
+ // refocus: Boolean
+ // When this menu closes, re-focus the element which had focus before it was opened.
+ refocus: true,
+
+ postCreate: function(){
+ if(this.contextMenuForWindow){
+ this.bindDomNode(win.body());
+ }else{
+ // TODO: should have _setTargetNodeIds() method to handle initialization and a possible
+ // later set('targetNodeIds', ...) call. There's also a problem that targetNodeIds[]
+ // gets stale after calls to bindDomNode()/unBindDomNode() as it still is just the original list (see #9610)
+ array.forEach(this.targetNodeIds, this.bindDomNode, this);
+ }
+ this.inherited(arguments);
+ },
+
+ // thanks burstlib!
+ _iframeContentWindow: function(/* HTMLIFrameElement */iframe_el){
+ // summary:
+ // Returns the window reference of the passed iframe
+ // tags:
+ // private
+ return winUtils.get(this._iframeContentDocument(iframe_el)) ||
+ // Moz. TODO: is this available when defaultView isn't?
+ this._iframeContentDocument(iframe_el)['__parent__'] ||
+ (iframe_el.name && win.doc.frames[iframe_el.name]) || null; // Window
+ },
+
+ _iframeContentDocument: function(/* HTMLIFrameElement */iframe_el){
+ // summary:
+ // Returns a reference to the document object inside iframe_el
+ // tags:
+ // protected
+ return iframe_el.contentDocument // W3
+ || (iframe_el.contentWindow && iframe_el.contentWindow.document) // IE
+ || (iframe_el.name && win.doc.frames[iframe_el.name] && win.doc.frames[iframe_el.name].document)
+ || null; // HTMLDocument
+ },
+
+ bindDomNode: function(/*String|DomNode*/ node){
+ // summary:
+ // Attach menu to given node
+ node = dom.byId(node);
+
+ var cn; // Connect node
+
+ // Support context menus on iframes. Rather than binding to the iframe itself we need
+ // to bind to the <body> node inside the iframe.
+ if(node.tagName.toLowerCase() == "iframe"){
+ var iframe = node,
+ window = this._iframeContentWindow(iframe);
+ cn = win.withGlobal(window, win.body);
+ }else{
+
+ // To capture these events at the top level, attach to <html>, not <body>.
+ // Otherwise right-click context menu just doesn't work.
+ cn = (node == win.body() ? win.doc.documentElement : node);
+ }
+
+
+ // "binding" is the object to track our connection to the node (ie, the parameter to bindDomNode())
+ var binding = {
+ node: node,
+ iframe: iframe
+ };
+
+ // Save info about binding in _bindings[], and make node itself record index(+1) into
+ // _bindings[] array. Prefix w/_dijitMenu to avoid setting an attribute that may
+ // start with a number, which fails on FF/safari.
+ domAttr.set(node, "_dijitMenu" + this.id, this._bindings.push(binding));
+
+ // Setup the connections to monitor click etc., unless we are connecting to an iframe which hasn't finished
+ // loading yet, in which case we need to wait for the onload event first, and then connect
+ // On linux Shift-F10 produces the oncontextmenu event, but on Windows it doesn't, so
+ // we need to monitor keyboard events in addition to the oncontextmenu event.
+ var doConnects = lang.hitch(this, function(cn){
+ return [
+ // TODO: when leftClickToOpen is true then shouldn't space/enter key trigger the menu,
+ // rather than shift-F10?
+ on(cn, this.leftClickToOpen ? "click" : "contextmenu", lang.hitch(this, function(evt){
+ // Schedule context menu to be opened unless it's already been scheduled from onkeydown handler
+ event.stop(evt);
+ this._scheduleOpen(evt.target, iframe, {x: evt.pageX, y: evt.pageY});
+ })),
+ on(cn, "keydown", lang.hitch(this, function(evt){
+ if(evt.shiftKey && evt.keyCode == keys.F10){
+ event.stop(evt);
+ this._scheduleOpen(evt.target, iframe); // no coords - open near target node
+ }
+ }))
+ ];
+ });
+ binding.connects = cn ? doConnects(cn) : [];
+
+ if(iframe){
+ // Setup handler to [re]bind to the iframe when the contents are initially loaded,
+ // and every time the contents change.
+ // Need to do this b/c we are actually binding to the iframe's <body> node.
+ // Note: can't use connect.connect(), see #9609.
+
+ binding.onloadHandler = lang.hitch(this, function(){
+ // want to remove old connections, but IE throws exceptions when trying to
+ // access the <body> node because it's already gone, or at least in a state of limbo
+
+ var window = this._iframeContentWindow(iframe);
+ cn = win.withGlobal(window, win.body);
+ binding.connects = doConnects(cn);
+ });
+ if(iframe.addEventListener){
+ iframe.addEventListener("load", binding.onloadHandler, false);
+ }else{
+ iframe.attachEvent("onload", binding.onloadHandler);
+ }
+ }
+ },
+
+ unBindDomNode: function(/*String|DomNode*/ nodeName){
+ // summary:
+ // Detach menu from given node
+
+ var node;
+ try{
+ node = dom.byId(nodeName);
+ }catch(e){
+ // On IE the dom.byId() call will get an exception if the attach point was
+ // the <body> node of an <iframe> that has since been reloaded (and thus the
+ // <body> node is in a limbo state of destruction.
+ return;
+ }
+
+ // node["_dijitMenu" + this.id] contains index(+1) into my _bindings[] array
+ var attrName = "_dijitMenu" + this.id;
+ if(node && domAttr.has(node, attrName)){
+ var bid = domAttr.get(node, attrName)-1, b = this._bindings[bid], h;
+ while(h = b.connects.pop()){
+ h.remove();
+ }
+
+ // Remove listener for iframe onload events
+ var iframe = b.iframe;
+ if(iframe){
+ if(iframe.removeEventListener){
+ iframe.removeEventListener("load", b.onloadHandler, false);
+ }else{
+ iframe.detachEvent("onload", b.onloadHandler);
+ }
+ }
+
+ domAttr.remove(node, attrName);
+ delete this._bindings[bid];
+ }
+ },
+
+ _scheduleOpen: function(/*DomNode?*/ target, /*DomNode?*/ iframe, /*Object?*/ coords){
+ // summary:
+ // Set timer to display myself. Using a timer rather than displaying immediately solves
+ // two problems:
+ //
+ // 1. IE: without the delay, focus work in "open" causes the system
+ // context menu to appear in spite of stopEvent.
+ //
+ // 2. Avoid double-shows on linux, where shift-F10 generates an oncontextmenu event
+ // even after a event.stop(e). (Shift-F10 on windows doesn't generate the
+ // oncontextmenu event.)
+
+ if(!this._openTimer){
+ this._openTimer = setTimeout(lang.hitch(this, function(){
+ delete this._openTimer;
+ this._openMyself({
+ target: target,
+ iframe: iframe,
+ coords: coords
+ });
+ }), 1);
+ }
+ },
+
+ _openMyself: function(args){
+ // summary:
+ // Internal function for opening myself when the user does a right-click or something similar.
+ // args:
+ // This is an Object containing:
+ // * target:
+ // The node that is being clicked
+ // * iframe:
+ // If an <iframe> is being clicked, iframe points to that iframe
+ // * coords:
+ // Put menu at specified x/y position in viewport, or if iframe is
+ // specified, then relative to iframe.
+ //
+ // _openMyself() formerly took the event object, and since various code references
+ // evt.target (after connecting to _openMyself()), using an Object for parameters
+ // (so that old code still works).
+
+ var target = args.target,
+ iframe = args.iframe,
+ coords = args.coords;
+
+ // Get coordinates to open menu, either at specified (mouse) position or (if triggered via keyboard)
+ // then near the node the menu is assigned to.
+ if(coords){
+ if(iframe){
+ // Specified coordinates are on <body> node of an <iframe>, convert to match main document
+ var ifc = domGeometry.position(iframe, true),
+ window = this._iframeContentWindow(iframe),
+ scroll = win.withGlobal(window, "_docScroll", dojo);
+
+ var cs = domStyle.getComputedStyle(iframe),
+ tp = domStyle.toPixelValue,
+ left = (has("ie") && has("quirks") ? 0 : tp(iframe, cs.paddingLeft)) + (has("ie") && has("quirks") ? tp(iframe, cs.borderLeftWidth) : 0),
+ top = (has("ie") && has("quirks") ? 0 : tp(iframe, cs.paddingTop)) + (has("ie") && has("quirks") ? tp(iframe, cs.borderTopWidth) : 0);
+
+ coords.x += ifc.x + left - scroll.x;
+ coords.y += ifc.y + top - scroll.y;
+ }
+ }else{
+ coords = domGeometry.position(target, true);
+ coords.x += 10;
+ coords.y += 10;
+ }
+
+ var self=this;
+ var prevFocusNode = this._focusManager.get("prevNode");
+ var curFocusNode = this._focusManager.get("curNode");
+ var savedFocusNode = !curFocusNode || (dom.isDescendant(curFocusNode, this.domNode)) ? prevFocusNode : curFocusNode;
+
+ function closeAndRestoreFocus(){
+ // user has clicked on a menu or popup
+ if(self.refocus && savedFocusNode){
+ savedFocusNode.focus();
+ }
+ pm.close(self);
+ }
+ pm.open({
+ popup: this,
+ x: coords.x,
+ y: coords.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
+ pm.close(this);
+ // don't try to restore focus; user has clicked another part of the screen
+ // and set focus there
+ };
+ },
+
+ uninitialize: function(){
+ array.forEach(this._bindings, function(b){ if(b){ this.unBindDomNode(b.node); } }, this);
+ this.inherited(arguments);
+ }
+});
+
+});