123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- /**
- * Copyright (c) 2006-2015, JGraph Ltd
- * Copyright (c) 2006-2015, Gaudenz Alder
- */
- /**
- * 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).
- * enabled-if - Optional name of condition that specifies if the menu item
- * should be enabled.
- * 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');
- var enabledCond = item.getAttribute('enabled-if');
- var enabled = enabledCond == null || conditions[enabledCond];
-
- 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, enabled);
- 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.
- * enabled - Optional boolean that specifies if the menu item is enabled.
- * Default is true.
- */
- mxDefaultPopupMenu.prototype.addAction = function(menu, editor, lab, icon, funct, action, cell, parent, iconCls, enabled)
- {
- 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, enabled);
- };
- /**
- * 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;
- };
|