text: /**
   * 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;
  };
  