diff options
Diffstat (limited to 'src/js/editor/mxDefaultPopupMenu.js')
-rw-r--r-- | src/js/editor/mxDefaultPopupMenu.js | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/src/js/editor/mxDefaultPopupMenu.js b/src/js/editor/mxDefaultPopupMenu.js new file mode 100644 index 0000000..01c65b5 --- /dev/null +++ b/src/js/editor/mxDefaultPopupMenu.js @@ -0,0 +1,300 @@ +/** + * $Id: mxDefaultPopupMenu.js,v 1.29 2012-07-03 06:30:25 gaudenz Exp $ + * Copyright (c) 2006-2010, JGraph Ltd + */ +/** + * Class: mxDefaultPopupMenu + * + * Creates popupmenus for mouse events. This object holds an XML node + * which is a description of the popup menu to be created. In + * <createMenu>, the configuration is applied to the context and + * the resulting menu items are added to the menu dynamically. See + * <createMenu> for a description of the configuration format. + * + * This class does not create the DOM nodes required for the popup menu, it + * only parses an XML description to invoke the respective methods on an + * <mxPopupMenu> each time the menu is displayed. + * + * Codec: + * + * This class uses the <mxDefaultPopupMenuCodec> to read configuration + * data into an existing instance, however, the actual parsing is done + * by this class during program execution, so the format is described + * below. + * + * Constructor: mxDefaultPopupMenu + * + * Constructs a new popupmenu-factory based on given configuration. + * + * Paramaters: + * + * config - XML node that contains the configuration data. + */ +function mxDefaultPopupMenu(config) +{ + this.config = config; +}; + +/** + * Variable: imageBasePath + * + * Base path for all icon attributes in the config. Default is null. + */ +mxDefaultPopupMenu.prototype.imageBasePath = null; + +/** + * Variable: config + * + * XML node used as the description of new menu items. This node is + * used in <createMenu> to dynamically create the menu items if their + * respective conditions evaluate to true for the given arguments. + */ +mxDefaultPopupMenu.prototype.config = null; + +/** + * Function: createMenu + * + * This function is called from <mxEditor> to add items to the + * given menu based on <config>. The config is a sequence of + * the following nodes and attributes. + * + * Child Nodes: + * + * add - Adds a new menu item. See below for attributes. + * separator - Adds a separator. No attributes. + * condition - Adds a custom condition. Name attribute. + * + * The add-node may have a child node that defines a function to be invoked + * before the action is executed (or instead of an action to be executed). + * + * Attributes: + * + * as - Resource key for the label (needs entry in property file). + * action - Name of the action to execute in enclosing editor. + * icon - Optional icon (relative/absolute URL). + * iconCls - Optional CSS class for the icon. + * if - Optional name of condition that must be true(see below). + * name - Name of custom condition. Only for condition nodes. + * + * Conditions: + * + * nocell - No cell under the mouse. + * ncells - More than one cell selected. + * notRoot - Drilling position is other than home. + * cell - Cell under the mouse. + * notEmpty - Exactly one cell with children under mouse. + * expandable - Exactly one expandable cell under mouse. + * collapsable - Exactly one collapsable cell under mouse. + * validRoot - Exactly one cell which is a possible root under mouse. + * swimlane - Exactly one cell which is a swimlane under mouse. + * + * Example: + * + * To add a new item for a given action to the popupmenu: + * + * (code) + * <mxDefaultPopupMenu as="popupHandler"> + * <add as="delete" action="delete" icon="images/delete.gif" if="cell"/> + * </mxDefaultPopupMenu> + * (end) + * + * To add a new item for a custom function: + * + * (code) + * <mxDefaultPopupMenu as="popupHandler"> + * <add as="action1"><![CDATA[ + * function (editor, cell, evt) + * { + * editor.execute('action1', cell, 'myArg'); + * } + * ]]></add> + * </mxDefaultPopupMenu> + * (end) + * + * The above example invokes action1 with an additional third argument via + * the editor instance. The third argument is passed to the function that + * defines action1. If the add-node has no action-attribute, then only the + * function defined in the text content is executed, otherwise first the + * function and then the action defined in the action-attribute is + * executed. The function in the text content has 3 arguments, namely the + * <mxEditor> instance, the <mxCell> instance under the mouse, and the + * native mouse event. + * + * Custom Conditions: + * + * To add a new condition for popupmenu items: + * + * (code) + * <condition name="condition1"><![CDATA[ + * function (editor, cell, evt) + * { + * return cell != null; + * } + * ]]></condition> + * (end) + * + * The new condition can then be used in any item as follows: + * + * (code) + * <add as="action1" action="action1" icon="action1.gif" if="condition1"/> + * (end) + * + * The order in which the items and conditions appear is not significant as + * all connditions are evaluated before any items are created. + * + * Parameters: + * + * editor - Enclosing <mxEditor> instance. + * menu - <mxPopupMenu> that is used for adding items and separators. + * cell - Optional <mxCell> which is under the mousepointer. + * evt - Optional mouse event which triggered the menu. + */ +mxDefaultPopupMenu.prototype.createMenu = function(editor, menu, cell, evt) +{ + if (this.config != null) + { + var conditions = this.createConditions(editor, cell, evt); + var item = this.config.firstChild; + + this.addItems(editor, menu, cell, evt, conditions, item, null); + } +}; + +/** + * Function: addItems + * + * Recursively adds the given items and all of its children into the given menu. + * + * Parameters: + * + * editor - Enclosing <mxEditor> instance. + * menu - <mxPopupMenu> that is used for adding items and separators. + * cell - Optional <mxCell> which is under the mousepointer. + * evt - Optional mouse event which triggered the menu. + * conditions - Array of names boolean conditions. + * item - XML node that represents the current menu item. + * parent - DOM node that represents the parent menu item. + */ +mxDefaultPopupMenu.prototype.addItems = function(editor, menu, cell, evt, conditions, item, parent) +{ + var addSeparator = false; + + while (item != null) + { + if (item.nodeName == 'add') + { + var condition = item.getAttribute('if'); + + if (condition == null || conditions[condition]) + { + var as = item.getAttribute('as'); + as = mxResources.get(as) || as; + var funct = mxUtils.eval(mxUtils.getTextContent(item)); + var action = item.getAttribute('action'); + var icon = item.getAttribute('icon'); + var iconCls = item.getAttribute('iconCls'); + + if (addSeparator) + { + menu.addSeparator(parent); + addSeparator = false; + } + + if (icon != null && this.imageBasePath) + { + icon = this.imageBasePath + icon; + } + + var row = this.addAction(menu, editor, as, icon, funct, action, cell, parent, iconCls); + this.addItems(editor, menu, cell, evt, conditions, item.firstChild, row); + } + } + else if (item.nodeName == 'separator') + { + addSeparator = true; + } + + item = item.nextSibling; + } +}; + +/** + * Function: addAction + * + * Helper method to bind an action to a new menu item. + * + * Parameters: + * + * menu - <mxPopupMenu> that is used for adding items and separators. + * editor - Enclosing <mxEditor> instance. + * lab - String that represents the label of the menu item. + * icon - Optional URL that represents the icon of the menu item. + * action - Optional name of the action to execute in the given editor. + * funct - Optional function to execute before the optional action. The + * function takes an <mxEditor>, the <mxCell> under the mouse and the + * mouse event that triggered the call. + * cell - Optional <mxCell> to use as an argument for the action. + * parent - DOM node that represents the parent menu item. + * iconCls - Optional CSS class for the menu icon. + */ +mxDefaultPopupMenu.prototype.addAction = function(menu, editor, lab, icon, funct, action, cell, parent, iconCls) +{ + var clickHandler = function(evt) + { + if (typeof(funct) == 'function') + { + funct.call(editor, editor, cell, evt); + } + + if (action != null) + { + editor.execute(action, cell, evt); + } + }; + + return menu.addItem(lab, icon, clickHandler, parent, iconCls); +}; + +/** + * Function: createConditions + * + * Evaluates the default conditions for the given context. + */ +mxDefaultPopupMenu.prototype.createConditions = function(editor, cell, evt) +{ + // Creates array with conditions + var model = editor.graph.getModel(); + var childCount = model.getChildCount(cell); + + // Adds some frequently used conditions + var conditions = []; + conditions['nocell'] = cell == null; + conditions['ncells'] = editor.graph.getSelectionCount() > 1; + conditions['notRoot'] = model.getRoot() != + model.getParent(editor.graph.getDefaultParent()); + conditions['cell'] = cell != null; + + var isCell = cell != null && editor.graph.getSelectionCount() == 1; + conditions['nonEmpty'] = isCell && childCount > 0; + conditions['expandable'] = isCell && editor.graph.isCellFoldable(cell, false); + conditions['collapsable'] = isCell && editor.graph.isCellFoldable(cell, true); + conditions['validRoot'] = isCell && editor.graph.isValidRoot(cell); + conditions['emptyValidRoot'] = conditions['validRoot'] && childCount == 0; + conditions['swimlane'] = isCell && editor.graph.isSwimlane(cell); + + // Evaluates dynamic conditions from config file + var condNodes = this.config.getElementsByTagName('condition'); + + for (var i=0; i<condNodes.length; i++) + { + var funct = mxUtils.eval(mxUtils.getTextContent(condNodes[i])); + var name = condNodes[i].getAttribute('name'); + + if (name != null && typeof(funct) == 'function') + { + conditions[name] = funct(editor, cell, evt); + } + } + + return conditions; +}; |