/** * 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 * , the configuration is applied to the context and * the resulting menu items are added to the menu dynamically. See * 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 * each time the menu is displayed. * * Codec: * * This class uses the 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 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 to add items to the * given menu based on . 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) * * * * (end) * * To add a new item for a custom function: * * (code) * * * * (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 * instance, the instance under the mouse, and the * native mouse event. * * Custom Conditions: * * To add a new condition for popupmenu items: * * (code) * * (end) * * The new condition can then be used in any item as follows: * * (code) * * (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 instance. * menu - that is used for adding items and separators. * cell - Optional 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 instance. * menu - that is used for adding items and separators. * cell - Optional 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 - that is used for adding items and separators. * editor - Enclosing 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 , the under the mouse and the * mouse event that triggered the call. * cell - Optional 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