X-Git-Url: http://git.roojs.org/?a=blobdiff_plain;f=docs%2Fsrc%2FRoo_menu_Menu.js.html;fp=docs%2Fsrc%2FRoo_menu_Menu.js.html;h=970f30cfff1a9ea9ee708947572dd225093f4639;hb=9ff8ded6bbbd258ecd646184ba26020874e2c085;hp=0000000000000000000000000000000000000000;hpb=2542b67d1a0768025056f2f330bfe50b64d1ad38;p=roojs1 diff --git a/docs/src/Roo_menu_Menu.js.html b/docs/src/Roo_menu_Menu.js.html new file mode 100644 index 0000000000..970f30cfff --- /dev/null +++ b/docs/src/Roo_menu_Menu.js.html @@ -0,0 +1,568 @@ +/home/alan/gitlive/roojs1/Roo/menu/Menu.js/* + * Based on: + * Ext JS Library 1.1.1 + * Copyright(c) 2006-2007, Ext JS, LLC. + * + * Originally Released Under LGPL - original licence link has changed is not relivant. + * + * Fork - LGPL + * <script type="text/javascript"> + */ + +/** + * @class Roo.menu.Menu + * @extends Roo.util.Observable + * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class + * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example). + * @constructor + * Creates a new Menu + * @param {Object} config Configuration options + */ +Roo.menu.Menu = function(config){ + Roo.apply(this, config); + this.id = this.id || Roo.id(); + this.addEvents({ + /** + * @event beforeshow + * Fires before this menu is displayed + * @param {Roo.menu.Menu} this + */ + beforeshow : true, + /** + * @event beforehide + * Fires before this menu is hidden + * @param {Roo.menu.Menu} this + */ + beforehide : true, + /** + * @event show + * Fires after this menu is displayed + * @param {Roo.menu.Menu} this + */ + show : true, + /** + * @event hide + * Fires after this menu is hidden + * @param {Roo.menu.Menu} this + */ + hide : true, + /** + * @event click + * Fires when this menu is clicked (or when the enter key is pressed while it is active) + * @param {Roo.menu.Menu} this + * @param {Roo.menu.Item} menuItem The menu item that was clicked + * @param {Roo.EventObject} e + */ + click : true, + /** + * @event mouseover + * Fires when the mouse is hovering over this menu + * @param {Roo.menu.Menu} this + * @param {Roo.EventObject} e + * @param {Roo.menu.Item} menuItem The menu item that was clicked + */ + mouseover : true, + /** + * @event mouseout + * Fires when the mouse exits this menu + * @param {Roo.menu.Menu} this + * @param {Roo.EventObject} e + * @param {Roo.menu.Item} menuItem The menu item that was clicked + */ + mouseout : true, + /** + * @event itemclick + * Fires when a menu item contained in this menu is clicked + * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked + * @param {Roo.EventObject} e + */ + itemclick: true + }); + if (this.registerMenu) { + Roo.menu.MenuMgr.register(this); + } + + var mis = this.items; + this.items = new Roo.util.MixedCollection(); + if(mis){ + this.add.apply(this, mis); + } +}; + +Roo.extend(Roo.menu.Menu, Roo.util.Observable, { + /** + * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120) + */ + minWidth : 120, + /** + * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" + * for bottom-right shadow (defaults to "sides") + */ + shadow : "sides", + /** + * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of + * this menu (defaults to "tl-tr?") + */ + subMenuAlign : "tl-tr?", + /** + * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu + * relative to its element of origin (defaults to "tl-bl?") + */ + defaultAlign : "tl-bl?", + /** + * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false) + */ + allowOtherMenus : false, + /** + * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it. + */ + registerMenu : true, + + hidden:true, + + // private + render : function(){ + if(this.el){ + return; + } + var el = this.el = new Roo.Layer({ + cls: "x-menu", + shadow:this.shadow, + constrain: false, + parentEl: this.parentEl || document.body, + zindex:15000 + }); + + this.keyNav = new Roo.menu.MenuNav(this); + + if(this.plain){ + el.addClass("x-menu-plain"); + } + if(this.cls){ + el.addClass(this.cls); + } + // generic focus element + this.focusEl = el.createChild({ + tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1" + }); + var ul = el.createChild({tag: "ul", cls: "x-menu-list"}); + //disabling touch- as it's causing issues .. + //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this); + ul.on('click' , this.onClick, this); + + + ul.on("mouseover", this.onMouseOver, this); + ul.on("mouseout", this.onMouseOut, this); + this.items.each(function(item){ + if (item.hidden) { + return; + } + + var li = document.createElement("li"); + li.className = "x-menu-list-item"; + ul.dom.appendChild(li); + item.render(li, this); + }, this); + this.ul = ul; + this.autoWidth(); + }, + + // private + autoWidth : function(){ + var el = this.el, ul = this.ul; + if(!el){ + return; + } + var w = this.width; + if(w){ + el.setWidth(w); + }else if(Roo.isIE){ + el.setWidth(this.minWidth); + var t = el.dom.offsetWidth; // force recalc + el.setWidth(ul.getWidth()+el.getFrameWidth("lr")); + } + }, + + // private + delayAutoWidth : function(){ + if(this.rendered){ + if(!this.awTask){ + this.awTask = new Roo.util.DelayedTask(this.autoWidth, this); + } + this.awTask.delay(20); + } + }, + + // private + findTargetItem : function(e){ + var t = e.getTarget(".x-menu-list-item", this.ul, true); + if(t && t.menuItemId){ + return this.items.get(t.menuItemId); + } + }, + + // private + onClick : function(e){ + Roo.log("menu.onClick"); + var t = this.findTargetItem(e); + if(!t){ + return; + } + Roo.log(e); + if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) { + if(t == this.activeItem && t.shouldDeactivate(e)){ + this.activeItem.deactivate(); + delete this.activeItem; + return; + } + if(t.canActivate){ + this.setActiveItem(t, true); + } + return; + + + } + + t.onClick(e); + this.fireEvent("click", this, t, e); + }, + + // private + setActiveItem : function(item, autoExpand){ + if(item != this.activeItem){ + if(this.activeItem){ + this.activeItem.deactivate(); + } + this.activeItem = item; + item.activate(autoExpand); + }else if(autoExpand){ + item.expandMenu(); + } + }, + + // private + tryActivate : function(start, step){ + var items = this.items; + for(var i = start, len = items.length; i >= 0 && i < len; i+= step){ + var item = items.get(i); + if(!item.disabled && item.canActivate){ + this.setActiveItem(item, false); + return item; + } + } + return false; + }, + + // private + onMouseOver : function(e){ + var t; + if(t = this.findTargetItem(e)){ + if(t.canActivate && !t.disabled){ + this.setActiveItem(t, true); + } + } + this.fireEvent("mouseover", this, e, t); + }, + + // private + onMouseOut : function(e){ + var t; + if(t = this.findTargetItem(e)){ + if(t == this.activeItem && t.shouldDeactivate(e)){ + this.activeItem.deactivate(); + delete this.activeItem; + } + } + this.fireEvent("mouseout", this, e, t); + }, + + /** + * Read-only. Returns true if the menu is currently displayed, else false. + * @type Boolean + */ + isVisible : function(){ + return this.el && !this.hidden; + }, + + /** + * Displays this menu relative to another element + * @param {String/HTMLElement/Roo.Element} element The element to align to + * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to + * the element (defaults to this.defaultAlign) + * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined) + */ + show : function(el, pos, parentMenu){ + this.parentMenu = parentMenu; + if(!this.el){ + this.render(); + } + this.fireEvent("beforeshow", this); + this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false); + }, + + /** + * Displays this menu at a specific xy position + * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based) + * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined) + */ + showAt : function(xy, parentMenu, /* private: */_e){ + this.parentMenu = parentMenu; + if(!this.el){ + this.render(); + } + if(_e !== false){ + this.fireEvent("beforeshow", this); + xy = this.el.adjustForConstraints(xy); + } + this.el.setXY(xy); + this.el.show(); + this.hidden = false; + this.focus(); + this.fireEvent("show", this); + }, + + focus : function(){ + if(!this.hidden){ + this.doFocus.defer(50, this); + } + }, + + doFocus : function(){ + if(!this.hidden){ + this.focusEl.focus(); + } + }, + + /** + * Hides this menu and optionally all parent menus + * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false) + */ + hide : function(deep){ + if(this.el && this.isVisible()){ + this.fireEvent("beforehide", this); + if(this.activeItem){ + this.activeItem.deactivate(); + this.activeItem = null; + } + this.el.hide(); + this.hidden = true; + this.fireEvent("hide", this); + } + if(deep === true && this.parentMenu){ + this.parentMenu.hide(true); + } + }, + + /** + * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items. + * Any of the following are valid: + * <ul> + * <li>Any menu item object based on {@link Roo.menu.Item}</li> + * <li>An HTMLElement object which will be converted to a menu item</li> + * <li>A menu item config object that will be created as a new menu item</li> + * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise + * it will be converted into a {@link Roo.menu.TextItem} and added</li> + * </ul> + * Usage: + * <pre><code> +// Create the menu +var menu = new Roo.menu.Menu(); + +// Create a menu item to add by reference +var menuItem = new Roo.menu.Item({ text: 'New Item!' }); + +// Add a bunch of items at once using different methods. +// Only the last item added will be returned. +var item = menu.add( + menuItem, // add existing item by ref + 'Dynamic Item', // new TextItem + '-', // new separator + { text: 'Config Item' } // new item by config +); +</code></pre> + * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items + * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added + */ + add : function(){ + var a = arguments, l = a.length, item; + for(var i = 0; i < l; i++){ + var el = a[i]; + if ((typeof(el) == "object") && el.xtype && el.xns) { + el = Roo.factory(el, Roo.menu); + } + + if(el.render){ // some kind of Item + item = this.addItem(el); + }else if(typeof el == "string"){ // string + if(el == "separator" || el == "-"){ + item = this.addSeparator(); + }else{ + item = this.addText(el); + } + }else if(el.tagName || el.el){ // element + item = this.addElement(el); + }else if(typeof el == "object"){ // must be menu item config? + item = this.addMenuItem(el); + } + } + return item; + }, + + /** + * Returns this menu's underlying {@link Roo.Element} object + * @return {Roo.Element} The element + */ + getEl : function(){ + if(!this.el){ + this.render(); + } + return this.el; + }, + + /** + * Adds a separator bar to the menu + * @return {Roo.menu.Item} The menu item that was added + */ + addSeparator : function(){ + return this.addItem(new Roo.menu.Separator()); + }, + + /** + * Adds an {@link Roo.Element} object to the menu + * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id + * @return {Roo.menu.Item} The menu item that was added + */ + addElement : function(el){ + return this.addItem(new Roo.menu.BaseItem(el)); + }, + + /** + * Adds an existing object based on {@link Roo.menu.Item} to the menu + * @param {Roo.menu.Item} item The menu item to add + * @return {Roo.menu.Item} The menu item that was added + */ + addItem : function(item){ + this.items.add(item); + if(this.ul){ + var li = document.createElement("li"); + li.className = "x-menu-list-item"; + this.ul.dom.appendChild(li); + item.render(li, this); + this.delayAutoWidth(); + } + return item; + }, + + /** + * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu + * @param {Object} config A MenuItem config object + * @return {Roo.menu.Item} The menu item that was added + */ + addMenuItem : function(config){ + if(!(config instanceof Roo.menu.Item)){ + if(typeof config.checked == "boolean"){ // must be check menu item config? + config = new Roo.menu.CheckItem(config); + }else{ + config = new Roo.menu.Item(config); + } + } + return this.addItem(config); + }, + + /** + * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu + * @param {String} text The text to display in the menu item + * @return {Roo.menu.Item} The menu item that was added + */ + addText : function(text){ + return this.addItem(new Roo.menu.TextItem({ text : text })); + }, + + /** + * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index + * @param {Number} index The index in the menu's list of current items where the new item should be inserted + * @param {Roo.menu.Item} item The menu item to add + * @return {Roo.menu.Item} The menu item that was added + */ + insert : function(index, item){ + this.items.insert(index, item); + if(this.ul){ + var li = document.createElement("li"); + li.className = "x-menu-list-item"; + this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]); + item.render(li, this); + this.delayAutoWidth(); + } + return item; + }, + + /** + * Removes an {@link Roo.menu.Item} from the menu and destroys the object + * @param {Roo.menu.Item} item The menu item to remove + */ + remove : function(item){ + this.items.removeKey(item.id); + item.destroy(); + }, + + /** + * Removes and destroys all items in the menu + */ + removeAll : function(){ + var f; + while(f = this.items.first()){ + this.remove(f); + } + } +}); + +// MenuNav is a private utility class used internally by the Menu +Roo.menu.MenuNav = function(menu){ + Roo.menu.MenuNav.superclass.constructor.call(this, menu.el); + this.scope = this.menu = menu; +}; + +Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, { + doRelay : function(e, h){ + var k = e.getKey(); + if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){ + this.menu.tryActivate(0, 1); + return false; + } + return h.call(this.scope || this, e, this.menu); + }, + + up : function(e, m){ + if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){ + m.tryActivate(m.items.length-1, -1); + } + }, + + down : function(e, m){ + if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){ + m.tryActivate(0, 1); + } + }, + + right : function(e, m){ + if(m.activeItem){ + m.activeItem.expandMenu(true); + } + }, + + left : function(e, m){ + m.hide(); + if(m.parentMenu && m.parentMenu.activeItem){ + m.parentMenu.activeItem.activate(); + } + }, + + enter : function(e, m){ + if(m.activeItem){ + e.stopPropagation(); + m.activeItem.onClick(e); + m.fireEvent("click", this, m.activeItem); + return true; + } + } +}); \ No newline at end of file