Actualización

This commit is contained in:
Xes
2025-04-10 12:49:05 +02:00
parent 4aff98e77b
commit 1cdd00920f
9151 changed files with 1800913 additions and 0 deletions

View File

@@ -0,0 +1,189 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
mxCodecRegistry.register(function()
{
/**
* Class: mxCellCodec
*
* Codec for <mxCell>s. This class is created and registered
* dynamically at load time and used implicitely via <mxCodec>
* and the <mxCodecRegistry>.
*
* Transient Fields:
*
* - children
* - edges
* - overlays
* - mxTransient
*
* Reference Fields:
*
* - parent
* - source
* - target
*
* Transient fields can be added using the following code:
*
* mxCodecRegistry.getCodec(mxCell).exclude.push('name_of_field');
*
* To subclass <mxCell>, replace the template and add an alias as
* follows.
*
* (code)
* function CustomCell(value, geometry, style)
* {
* mxCell.apply(this, arguments);
* }
*
* mxUtils.extend(CustomCell, mxCell);
*
* mxCodecRegistry.getCodec(mxCell).template = new CustomCell();
* mxCodecRegistry.addAlias('CustomCell', 'mxCell');
* (end)
*/
var codec = new mxObjectCodec(new mxCell(),
['children', 'edges', 'overlays', 'mxTransient'],
['parent', 'source', 'target']);
/**
* Function: isCellCodec
*
* Returns true since this is a cell codec.
*/
codec.isCellCodec = function()
{
return true;
};
/**
* Overidden to disable conversion of value to number.
*/
codec.isNumericAttribute = function(dec, attr, obj)
{
return attr.nodeName !== 'value' && mxObjectCodec.prototype.isNumericAttribute.apply(this, arguments);
};
/**
* Function: isExcluded
*
* Excludes user objects that are XML nodes.
*/
codec.isExcluded = function(obj, attr, value, isWrite)
{
return mxObjectCodec.prototype.isExcluded.apply(this, arguments) ||
(isWrite && attr == 'value' &&
value.nodeType == mxConstants.NODETYPE_ELEMENT);
};
/**
* Function: afterEncode
*
* Encodes an <mxCell> and wraps the XML up inside the
* XML of the user object (inversion).
*/
codec.afterEncode = function(enc, obj, node)
{
if (obj.value != null && obj.value.nodeType == mxConstants.NODETYPE_ELEMENT)
{
// Wraps the graphical annotation up in the user object (inversion)
// by putting the result of the default encoding into a clone of the
// user object (node type 1) and returning this cloned user object.
var tmp = node;
node = mxUtils.importNode(enc.document, obj.value, true);
node.appendChild(tmp);
// Moves the id attribute to the outermost XML node, namely the
// node which denotes the object boundaries in the file.
var id = tmp.getAttribute('id');
node.setAttribute('id', id);
tmp.removeAttribute('id');
}
return node;
};
/**
* Function: beforeDecode
*
* Decodes an <mxCell> and uses the enclosing XML node as
* the user object for the cell (inversion).
*/
codec.beforeDecode = function(dec, node, obj)
{
var inner = node.cloneNode(true);
var classname = this.getName();
if (node.nodeName != classname)
{
// Passes the inner graphical annotation node to the
// object codec for further processing of the cell.
var tmp = node.getElementsByTagName(classname)[0];
if (tmp != null && tmp.parentNode == node)
{
mxUtils.removeWhitespace(tmp, true);
mxUtils.removeWhitespace(tmp, false);
tmp.parentNode.removeChild(tmp);
inner = tmp;
}
else
{
inner = null;
}
// Creates the user object out of the XML node
obj.value = node.cloneNode(true);
var id = obj.value.getAttribute('id');
if (id != null)
{
obj.setId(id);
obj.value.removeAttribute('id');
}
}
else
{
// Uses ID from XML file as ID for cell in model
obj.setId(node.getAttribute('id'));
}
// Preprocesses and removes all Id-references in order to use the
// correct encoder (this) for the known references to cells (all).
if (inner != null)
{
for (var i = 0; i < this.idrefs.length; i++)
{
var attr = this.idrefs[i];
var ref = inner.getAttribute(attr);
if (ref != null)
{
inner.removeAttribute(attr);
var object = dec.objects[ref] || dec.lookup(ref);
if (object == null)
{
// Needs to decode forward reference
var element = dec.getElementById(ref);
if (element != null)
{
var decoder = mxCodecRegistry.codecs[element.nodeName] || this;
object = decoder.decode(dec, element);
}
}
obj[attr] = object;
}
}
}
return inner;
};
// Returns the codec into the registry
return codec;
}());

View File

@@ -0,0 +1,157 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
mxCodecRegistry.register(function()
{
/**
* Class: mxChildChangeCodec
*
* Codec for <mxChildChange>s. This class is created and registered
* dynamically at load time and used implicitely via <mxCodec> and
* the <mxCodecRegistry>.
*
* Transient Fields:
*
* - model
* - previous
* - previousIndex
* - child
*
* Reference Fields:
*
* - parent
*/
var codec = new mxObjectCodec(new mxChildChange(),
['model', 'child', 'previousIndex'],
['parent', 'previous']);
/**
* Function: isReference
*
* Returns true for the child attribute if the child
* cell had a previous parent or if we're reading the
* child as an attribute rather than a child node, in
* which case it's always a reference.
*/
codec.isReference = function(obj, attr, value, isWrite)
{
if (attr == 'child' && (obj.previous != null || !isWrite))
{
return true;
}
return mxUtils.indexOf(this.idrefs, attr) >= 0;
};
/**
* Function: afterEncode
*
* Encodes the child recusively and adds the result
* to the given node.
*/
codec.afterEncode = function(enc, obj, node)
{
if (this.isReference(obj, 'child', obj.child, true))
{
// Encodes as reference (id)
node.setAttribute('child', enc.getId(obj.child));
}
else
{
// At this point, the encoder is no longer able to know which cells
// are new, so we have to encode the complete cell hierarchy and
// ignore the ones that are already there at decoding time. Note:
// This can only be resolved by moving the notify event into the
// execute of the edit.
enc.encodeCell(obj.child, node);
}
return node;
};
/**
* Function: beforeDecode
*
* Decodes the any child nodes as using the respective
* codec from the registry.
*/
codec.beforeDecode = function(dec, node, obj)
{
if (node.firstChild != null &&
node.firstChild.nodeType == mxConstants.NODETYPE_ELEMENT)
{
// Makes sure the original node isn't modified
node = node.cloneNode(true);
var tmp = node.firstChild;
obj.child = dec.decodeCell(tmp, false);
var tmp2 = tmp.nextSibling;
tmp.parentNode.removeChild(tmp);
tmp = tmp2;
while (tmp != null)
{
tmp2 = tmp.nextSibling;
if (tmp.nodeType == mxConstants.NODETYPE_ELEMENT)
{
// Ignores all existing cells because those do not need to
// be re-inserted into the model. Since the encoded version
// of these cells contains the new parent, this would leave
// to an inconsistent state on the model (ie. a parent
// change without a call to parentForCellChanged).
var id = tmp.getAttribute('id');
if (dec.lookup(id) == null)
{
dec.decodeCell(tmp);
}
}
tmp.parentNode.removeChild(tmp);
tmp = tmp2;
}
}
else
{
var childRef = node.getAttribute('child');
obj.child = dec.getObject(childRef);
}
return node;
};
/**
* Function: afterDecode
*
* Restores object state in the child change.
*/
codec.afterDecode = function(dec, node, obj)
{
// Cells are encoded here after a complete transaction so the previous
// parent must be restored on the cell for the case where the cell was
// added. This is needed for the local model to identify the cell as a
// new cell and register the ID.
if (obj.child != null)
{
if (obj.child.parent != null && obj.previous != null &&
obj.child.parent != obj.previous)
{
obj.previous = obj.child.parent;
}
obj.child.parent = obj.previous;
obj.previous = obj.parent;
obj.previousIndex = obj.index;
}
return obj;
};
// Returns the codec into the registry
return codec;
}());

View File

@@ -0,0 +1,596 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxCodec
*
* XML codec for JavaScript object graphs. See <mxObjectCodec> for a
* description of the general encoding/decoding scheme. This class uses the
* codecs registered in <mxCodecRegistry> for encoding/decoding each object.
*
* References:
*
* In order to resolve references, especially forward references, the mxCodec
* constructor must be given the document that contains the referenced
* elements.
*
* Examples:
*
* The following code is used to encode a graph model.
*
* (code)
* var encoder = new mxCodec();
* var result = encoder.encode(graph.getModel());
* var xml = mxUtils.getXml(result);
* (end)
*
* Example:
*
* Using the code below, an XML document is decoded into an existing model. The
* document may be obtained using one of the functions in mxUtils for loading
* an XML file, eg. <mxUtils.get>, or using <mxUtils.parseXml> for parsing an
* XML string.
*
* (code)
* var doc = mxUtils.parseXml(xmlString);
* var codec = new mxCodec(doc);
* codec.decode(doc.documentElement, graph.getModel());
* (end)
*
* Example:
*
* This example demonstrates parsing a list of isolated cells into an existing
* graph model. Note that the cells do not have a parent reference so they can
* be added anywhere in the cell hierarchy after parsing.
*
* (code)
* var xml = '<root><mxCell id="2" value="Hello," vertex="1"><mxGeometry x="20" y="20" width="80" height="30" as="geometry"/></mxCell><mxCell id="3" value="World!" vertex="1"><mxGeometry x="200" y="150" width="80" height="30" as="geometry"/></mxCell><mxCell id="4" value="" edge="1" source="2" target="3"><mxGeometry relative="1" as="geometry"/></mxCell></root>';
* var doc = mxUtils.parseXml(xml);
* var codec = new mxCodec(doc);
* var elt = doc.documentElement.firstChild;
* var cells = [];
*
* while (elt != null)
* {
* cells.push(codec.decode(elt));
* elt = elt.nextSibling;
* }
*
* graph.addCells(cells);
* (end)
*
* Example:
*
* Using the following code, the selection cells of a graph are encoded and the
* output is displayed in a dialog box.
*
* (code)
* var enc = new mxCodec();
* var cells = graph.getSelectionCells();
* mxUtils.alert(mxUtils.getPrettyXml(enc.encode(cells)));
* (end)
*
* Newlines in the XML can be converted to <br>, in which case a '<br>' argument
* must be passed to <mxUtils.getXml> as the second argument.
*
* Debugging:
*
* For debugging I/O you can use the following code to get the sequence of
* encoded objects:
*
* (code)
* var oldEncode = mxCodec.prototype.encode;
* mxCodec.prototype.encode = function(obj)
* {
* mxLog.show();
* mxLog.debug('mxCodec.encode: obj='+mxUtils.getFunctionName(obj.constructor));
*
* return oldEncode.apply(this, arguments);
* };
* (end)
*
* Note that the I/O system adds object codecs for new object automatically. For
* decoding those objects, the constructor should be written as follows:
*
* (code)
* var MyObj = function(name)
* {
* // ...
* };
* (end)
*
* Constructor: mxCodec
*
* Constructs an XML encoder/decoder for the specified
* owner document.
*
* Parameters:
*
* document - Optional XML document that contains the data.
* If no document is specified then a new document is created
* using <mxUtils.createXmlDocument>.
*/
function mxCodec(document)
{
this.document = document || mxUtils.createXmlDocument();
this.objects = [];
};
/**
* Variable: document
*
* The owner document of the codec.
*/
mxCodec.prototype.document = null;
/**
* Variable: objects
*
* Maps from IDs to objects.
*/
mxCodec.prototype.objects = null;
/**
* Variable: elements
*
* Lookup table for resolving IDs to elements.
*/
mxCodec.prototype.elements = null;
/**
* Variable: encodeDefaults
*
* Specifies if default values should be encoded. Default is false.
*/
mxCodec.prototype.encodeDefaults = false;
/**
* Function: putObject
*
* Assoiates the given object with the given ID and returns the given object.
*
* Parameters
*
* id - ID for the object to be associated with.
* obj - Object to be associated with the ID.
*/
mxCodec.prototype.putObject = function(id, obj)
{
this.objects[id] = obj;
return obj;
};
/**
* Function: getObject
*
* Returns the decoded object for the element with the specified ID in
* <document>. If the object is not known then <lookup> is used to find an
* object. If no object is found, then the element with the respective ID
* from the document is parsed using <decode>.
*/
mxCodec.prototype.getObject = function(id)
{
var obj = null;
if (id != null)
{
obj = this.objects[id];
if (obj == null)
{
obj = this.lookup(id);
if (obj == null)
{
var node = this.getElementById(id);
if (node != null)
{
obj = this.decode(node);
}
}
}
}
return obj;
};
/**
* Function: lookup
*
* Hook for subclassers to implement a custom lookup mechanism for cell IDs.
* This implementation always returns null.
*
* Example:
*
* (code)
* var codec = new mxCodec();
* codec.lookup = function(id)
* {
* return model.getCell(id);
* };
* (end)
*
* Parameters:
*
* id - ID of the object to be returned.
*/
mxCodec.prototype.lookup = function(id)
{
return null;
};
/**
* Function: getElementById
*
* Returns the element with the given ID from <document>.
*
* Parameters:
*
* id - String that contains the ID.
*/
mxCodec.prototype.getElementById = function(id)
{
if (this.elements == null)
{
// Throws custom error for cases where a reference should be resolved
// in an empty document. This happens if an XML node is decoded without
// passing the owner document to the codec constructor.
if (this.document.documentElement == null)
{
throw new Error('mxCodec constructor needs document parameter');
}
this.elements = new Object();
this.addElement(this.document.documentElement);
}
return this.elements[id];
};
/**
* Function: addElement
*
* Adds the given element to <elements> if it has an ID.
*/
mxCodec.prototype.addElement = function(node)
{
if (node.nodeType == mxConstants.NODETYPE_ELEMENT)
{
var id = node.getAttribute('id');
if (id != null && this.elements[id] == null)
{
this.elements[id] = node;
}
}
node = node.firstChild;
while (node != null)
{
this.addElement(node);
node = node.nextSibling;
}
};
/**
* Function: getId
*
* Returns the ID of the specified object. This implementation
* calls <reference> first and if that returns null handles
* the object as an <mxCell> by returning their IDs using
* <mxCell.getId>. If no ID exists for the given cell, then
* an on-the-fly ID is generated using <mxCellPath.create>.
*
* Parameters:
*
* obj - Object to return the ID for.
*/
mxCodec.prototype.getId = function(obj)
{
var id = null;
if (obj != null)
{
id = this.reference(obj);
if (id == null && obj instanceof mxCell)
{
id = obj.getId();
if (id == null)
{
// Uses an on-the-fly Id
id = mxCellPath.create(obj);
if (id.length == 0)
{
id = 'root';
}
}
}
}
return id;
};
/**
* Function: reference
*
* Hook for subclassers to implement a custom method
* for retrieving IDs from objects. This implementation
* always returns null.
*
* Example:
*
* (code)
* var codec = new mxCodec();
* codec.reference = function(obj)
* {
* return obj.getCustomId();
* };
* (end)
*
* Parameters:
*
* obj - Object whose ID should be returned.
*/
mxCodec.prototype.reference = function(obj)
{
return null;
};
/**
* Function: encode
*
* Encodes the specified object and returns the resulting
* XML node.
*
* Parameters:
*
* obj - Object to be encoded.
*/
mxCodec.prototype.encode = function(obj)
{
var node = null;
if (obj != null && obj.constructor != null)
{
var enc = mxCodecRegistry.getCodec(obj.constructor);
if (enc != null)
{
node = enc.encode(this, obj);
}
else
{
if (mxUtils.isNode(obj))
{
node = mxUtils.importNode(this.document, obj, true);
}
else
{
mxLog.warn('mxCodec.encode: No codec for ' + mxUtils.getFunctionName(obj.constructor));
}
}
}
return node;
};
/**
* Function: decode
*
* Decodes the given XML node. The optional "into"
* argument specifies an existing object to be
* used. If no object is given, then a new instance
* is created using the constructor from the codec.
*
* The function returns the passed in object or
* the new instance if no object was given.
*
* Parameters:
*
* node - XML node to be decoded.
* into - Optional object to be decodec into.
*/
mxCodec.prototype.decode = function(node, into)
{
var obj = null;
if (node != null && node.nodeType == mxConstants.NODETYPE_ELEMENT)
{
var ctor = null;
try
{
ctor = window[node.nodeName];
}
catch (err)
{
// ignore
}
var dec = mxCodecRegistry.getCodec(ctor);
if (dec != null)
{
obj = dec.decode(this, node, into);
}
else
{
obj = node.cloneNode(true);
obj.removeAttribute('as');
}
}
return obj;
};
/**
* Function: encodeCell
*
* Encoding of cell hierarchies is built-into the core, but
* is a higher-level function that needs to be explicitely
* used by the respective object encoders (eg. <mxModelCodec>,
* <mxChildChangeCodec> and <mxRootChangeCodec>). This
* implementation writes the given cell and its children as a
* (flat) sequence into the given node. The children are not
* encoded if the optional includeChildren is false. The
* function is in charge of adding the result into the
* given node and has no return value.
*
* Parameters:
*
* cell - <mxCell> to be encoded.
* node - Parent XML node to add the encoded cell into.
* includeChildren - Optional boolean indicating if the
* function should include all descendents. Default is true.
*/
mxCodec.prototype.encodeCell = function(cell, node, includeChildren)
{
node.appendChild(this.encode(cell));
if (includeChildren == null || includeChildren)
{
var childCount = cell.getChildCount();
for (var i = 0; i < childCount; i++)
{
this.encodeCell(cell.getChildAt(i), node);
}
}
};
/**
* Function: isCellCodec
*
* Returns true if the given codec is a cell codec. This uses
* <mxCellCodec.isCellCodec> to check if the codec is of the
* given type.
*/
mxCodec.prototype.isCellCodec = function(codec)
{
if (codec != null && typeof(codec.isCellCodec) == 'function')
{
return codec.isCellCodec();
}
return false;
};
/**
* Function: decodeCell
*
* Decodes cells that have been encoded using inversion, ie.
* where the user object is the enclosing node in the XML,
* and restores the group and graph structure in the cells.
* Returns a new <mxCell> instance that represents the
* given node.
*
* Parameters:
*
* node - XML node that contains the cell data.
* restoreStructures - Optional boolean indicating whether
* the graph structure should be restored by calling insert
* and insertEdge on the parent and terminals, respectively.
* Default is true.
*/
mxCodec.prototype.decodeCell = function(node, restoreStructures)
{
restoreStructures = (restoreStructures != null) ? restoreStructures : true;
var cell = null;
if (node != null && node.nodeType == mxConstants.NODETYPE_ELEMENT)
{
// Tries to find a codec for the given node name. If that does
// not return a codec then the node is the user object (an XML node
// that contains the mxCell, aka inversion).
var decoder = mxCodecRegistry.getCodec(node.nodeName);
// Tries to find the codec for the cell inside the user object.
// This assumes all node names inside the user object are either
// not registered or they correspond to a class for cells.
if (!this.isCellCodec(decoder))
{
var child = node.firstChild;
while (child != null && !this.isCellCodec(decoder))
{
decoder = mxCodecRegistry.getCodec(child.nodeName);
child = child.nextSibling;
}
}
if (!this.isCellCodec(decoder))
{
decoder = mxCodecRegistry.getCodec(mxCell);
}
cell = decoder.decode(this, node);
if (restoreStructures)
{
this.insertIntoGraph(cell);
}
}
return cell;
};
/**
* Function: insertIntoGraph
*
* Inserts the given cell into its parent and terminal cells.
*/
mxCodec.prototype.insertIntoGraph = function(cell)
{
var parent = cell.parent;
var source = cell.getTerminal(true);
var target = cell.getTerminal(false);
// Fixes possible inconsistencies during insert into graph
cell.setTerminal(null, false);
cell.setTerminal(null, true);
cell.parent = null;
if (parent != null)
{
parent.insert(cell);
}
if (source != null)
{
source.insertEdge(cell, true);
}
if (target != null)
{
target.insertEdge(cell, false);
}
};
/**
* Function: setAttribute
*
* Sets the attribute on the specified node to value. This is a
* helper method that makes sure the attribute and value arguments
* are not null.
*
* Parameters:
*
* node - XML node to set the attribute for.
* attributes - Attributename to be set.
* value - New value of the attribute.
*/
mxCodec.prototype.setAttribute = function(node, attribute, value)
{
if (attribute != null && value != null)
{
node.setAttribute(attribute, value);
}
};

View File

@@ -0,0 +1,137 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
var mxCodecRegistry =
{
/**
* Class: mxCodecRegistry
*
* Singleton class that acts as a global registry for codecs.
*
* Adding an <mxCodec>:
*
* 1. Define a default codec with a new instance of the
* object to be handled.
*
* (code)
* var codec = new mxObjectCodec(new mxGraphModel());
* (end)
*
* 2. Define the functions required for encoding and decoding
* objects.
*
* (code)
* codec.encode = function(enc, obj) { ... }
* codec.decode = function(dec, node, into) { ... }
* (end)
*
* 3. Register the codec in the <mxCodecRegistry>.
*
* (code)
* mxCodecRegistry.register(codec);
* (end)
*
* <mxObjectCodec.decode> may be used to either create a new
* instance of an object or to configure an existing instance,
* in which case the into argument points to the existing
* object. In this case, we say the codec "configures" the
* object.
*
* Variable: codecs
*
* Maps from constructor names to codecs.
*/
codecs: [],
/**
* Variable: aliases
*
* Maps from classnames to codecnames.
*/
aliases: [],
/**
* Function: register
*
* Registers a new codec and associates the name of the template
* constructor in the codec with the codec object.
*
* Parameters:
*
* codec - <mxObjectCodec> to be registered.
*/
register: function(codec)
{
if (codec != null)
{
var name = codec.getName();
mxCodecRegistry.codecs[name] = codec;
var classname = mxUtils.getFunctionName(codec.template.constructor);
if (classname != name)
{
mxCodecRegistry.addAlias(classname, name);
}
}
return codec;
},
/**
* Function: addAlias
*
* Adds an alias for mapping a classname to a codecname.
*/
addAlias: function(classname, codecname)
{
mxCodecRegistry.aliases[classname] = codecname;
},
/**
* Function: getCodec
*
* Returns a codec that handles objects that are constructed
* using the given constructor.
*
* Parameters:
*
* ctor - JavaScript constructor function.
*/
getCodec: function(ctor)
{
var codec = null;
if (ctor != null)
{
var name = mxUtils.getFunctionName(ctor);
var tmp = mxCodecRegistry.aliases[name];
if (tmp != null)
{
name = tmp;
}
codec = mxCodecRegistry.codecs[name];
// Registers a new default codec for the given constructor
// if no codec has been previously defined.
if (codec == null)
{
try
{
codec = new mxObjectCodec(new ctor());
mxCodecRegistry.register(codec);
}
catch (e)
{
// ignore
}
}
}
return codec;
}
};

View File

@@ -0,0 +1,88 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
mxCodecRegistry.register(function()
{
/**
* Class: mxDefaultKeyHandlerCodec
*
* Custom codec for configuring <mxDefaultKeyHandler>s. This class is created
* and registered dynamically at load time and used implicitely via
* <mxCodec> and the <mxCodecRegistry>. This codec only reads configuration
* data for existing key handlers, it does not encode or create key handlers.
*/
var codec = new mxObjectCodec(new mxDefaultKeyHandler());
/**
* Function: encode
*
* Returns null.
*/
codec.encode = function(enc, obj)
{
return null;
};
/**
* Function: decode
*
* Reads a sequence of the following child nodes
* and attributes:
*
* Child Nodes:
*
* add - Binds a keystroke to an actionname.
*
* Attributes:
*
* as - Keycode.
* action - Actionname to execute in editor.
* control - Optional boolean indicating if
* the control key must be pressed.
*
* Example:
*
* (code)
* <mxDefaultKeyHandler as="keyHandler">
* <add as="88" control="true" action="cut"/>
* <add as="67" control="true" action="copy"/>
* <add as="86" control="true" action="paste"/>
* </mxDefaultKeyHandler>
* (end)
*
* The keycodes are for the x, c and v keys.
*
* See also: <mxDefaultKeyHandler.bindAction>,
* http://www.js-examples.com/page/tutorials__key_codes.html
*/
codec.decode = function(dec, node, into)
{
if (into != null)
{
var editor = into.editor;
node = node.firstChild;
while (node != null)
{
if (!this.processInclude(dec, node, into) &&
node.nodeName == 'add')
{
var as = node.getAttribute('as');
var action = node.getAttribute('action');
var control = node.getAttribute('control');
into.bindAction(as, action, control);
}
node = node.nextSibling;
}
}
return into;
};
// Returns the codec into the registry
return codec;
}());

View File

@@ -0,0 +1,54 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
mxCodecRegistry.register(function()
{
/**
* Class: mxDefaultPopupMenuCodec
*
* Custom codec for configuring <mxDefaultPopupMenu>s. This class is created
* and registered dynamically at load time and used implicitely via
* <mxCodec> and the <mxCodecRegistry>. This codec only reads configuration
* data for existing popup menus, it does not encode or create menus. Note
* that this codec only passes the configuration node to the popup menu,
* which uses the config to dynamically create menus. See
* <mxDefaultPopupMenu.createMenu>.
*/
var codec = new mxObjectCodec(new mxDefaultPopupMenu());
/**
* Function: encode
*
* Returns null.
*/
codec.encode = function(enc, obj)
{
return null;
};
/**
* Function: decode
*
* Uses the given node as the config for <mxDefaultPopupMenu>.
*/
codec.decode = function(dec, node, into)
{
var inc = node.getElementsByTagName('include')[0];
if (inc != null)
{
this.processInclude(dec, inc, into);
}
else if (into != null)
{
into.config = node;
}
return into;
};
// Returns the codec into the registry
return codec;
}());

View File

@@ -0,0 +1,312 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxDefaultToolbarCodec
*
* Custom codec for configuring <mxDefaultToolbar>s. This class is created
* and registered dynamically at load time and used implicitely via
* <mxCodec> and the <mxCodecRegistry>. This codec only reads configuration
* data for existing toolbars handlers, it does not encode or create toolbars.
*/
var mxDefaultToolbarCodec = mxCodecRegistry.register(function()
{
var codec = new mxObjectCodec(new mxDefaultToolbar());
/**
* Function: encode
*
* Returns null.
*/
codec.encode = function(enc, obj)
{
return null;
};
/**
* Function: decode
*
* Reads a sequence of the following child nodes
* and attributes:
*
* Child Nodes:
*
* add - Adds a new item to the toolbar. See below for attributes.
* separator - Adds a vertical separator. No attributes.
* hr - Adds a horizontal separator. No attributes.
* br - Adds a linefeed. No attributes.
*
* Attributes:
*
* as - Resource key for the label.
* action - Name of the action to execute in enclosing editor.
* mode - Modename (see below).
* template - Template name for cell insertion.
* style - Optional style to override the template style.
* icon - Icon (relative/absolute URL).
* pressedIcon - Optional icon for pressed state (relative/absolute URL).
* id - Optional ID to be used for the created DOM element.
* toggle - Optional 0 or 1 to disable toggling of the element. Default is
* 1 (true).
*
* The action, mode and template attributes are mutually exclusive. The
* style can only be used with the template attribute. The add node may
* contain another sequence of add nodes with as and action attributes
* to create a combo box in the toolbar. If the icon is specified then
* a list of the child node is expected to have its template attribute
* set and the action is ignored instead.
*
* Nodes with a specified template may define a function to be used for
* inserting the cloned template into the graph. Here is an example of such
* a node:
*
* (code)
* <add as="Swimlane" template="swimlane" icon="images/swimlane.gif"><![CDATA[
* function (editor, cell, evt, targetCell)
* {
* var pt = mxUtils.convertPoint(
* editor.graph.container, mxEvent.getClientX(evt),
* mxEvent.getClientY(evt));
* return editor.addVertex(targetCell, cell, pt.x, pt.y);
* }
* ]]></add>
* (end)
*
* In the above function, editor is the enclosing <mxEditor> instance, cell
* is the clone of the template, evt is the mouse event that represents the
* drop and targetCell is the cell under the mousepointer where the drop
* occurred. The targetCell is retrieved using <mxGraph.getCellAt>.
*
* Futhermore, nodes with the mode attribute may define a function to
* be executed upon selection of the respective toolbar icon. In the
* example below, the default edge style is set when this specific
* connect-mode is activated:
*
* (code)
* <add as="connect" mode="connect"><![CDATA[
* function (editor)
* {
* if (editor.defaultEdge != null)
* {
* editor.defaultEdge.style = 'straightEdge';
* }
* }
* ]]></add>
* (end)
*
* Both functions require <mxDefaultToolbarCodec.allowEval> to be set to true.
*
* Modes:
*
* select - Left mouse button used for rubberband- & cell-selection.
* connect - Allows connecting vertices by inserting new edges.
* pan - Disables selection and switches to panning on the left button.
*
* Example:
*
* To add items to the toolbar:
*
* (code)
* <mxDefaultToolbar as="toolbar">
* <add as="save" action="save" icon="images/save.gif"/>
* <br/><hr/>
* <add as="select" mode="select" icon="images/select.gif"/>
* <add as="connect" mode="connect" icon="images/connect.gif"/>
* </mxDefaultToolbar>
* (end)
*/
codec.decode = function(dec, node, into)
{
if (into != null)
{
var editor = into.editor;
node = node.firstChild;
while (node != null)
{
if (node.nodeType == mxConstants.NODETYPE_ELEMENT)
{
if (!this.processInclude(dec, node, into))
{
if (node.nodeName == 'separator')
{
into.addSeparator();
}
else if (node.nodeName == 'br')
{
into.toolbar.addBreak();
}
else if (node.nodeName == 'hr')
{
into.toolbar.addLine();
}
else if (node.nodeName == 'add')
{
var as = node.getAttribute('as');
as = mxResources.get(as) || as;
var icon = node.getAttribute('icon');
var pressedIcon = node.getAttribute('pressedIcon');
var action = node.getAttribute('action');
var mode = node.getAttribute('mode');
var template = node.getAttribute('template');
var toggle = node.getAttribute('toggle') != '0';
var text = mxUtils.getTextContent(node);
var elt = null;
if (action != null)
{
elt = into.addItem(as, icon, action, pressedIcon);
}
else if (mode != null)
{
var funct = (mxDefaultToolbarCodec.allowEval) ? mxUtils.eval(text) : null;
elt = into.addMode(as, icon, mode, pressedIcon, funct);
}
else if (template != null || (text != null && text.length > 0))
{
var cell = editor.templates[template];
var style = node.getAttribute('style');
if (cell != null && style != null)
{
cell = editor.graph.cloneCells([cell])[0];
cell.setStyle(style);
}
var insertFunction = null;
if (text != null && text.length > 0 && mxDefaultToolbarCodec.allowEval)
{
insertFunction = mxUtils.eval(text);
}
elt = into.addPrototype(as, icon, cell, pressedIcon, insertFunction, toggle);
}
else
{
var children = mxUtils.getChildNodes(node);
if (children.length > 0)
{
if (icon == null)
{
var combo = into.addActionCombo(as);
for (var i=0; i<children.length; i++)
{
var child = children[i];
if (child.nodeName == 'separator')
{
into.addOption(combo, '---');
}
else if (child.nodeName == 'add')
{
var lab = child.getAttribute('as');
var act = child.getAttribute('action');
into.addActionOption(combo, lab, act);
}
}
}
else
{
var select = null;
var create = function()
{
var template = editor.templates[select.value];
if (template != null)
{
var clone = template.clone();
var style = select.options[select.selectedIndex].cellStyle;
if (style != null)
{
clone.setStyle(style);
}
return clone;
}
else
{
mxLog.warn('Template '+template+' not found');
}
return null;
};
var img = into.addPrototype(as, icon, create, null, null, toggle);
select = into.addCombo();
// Selects the toolbar icon if a selection change
// is made in the corresponding combobox.
mxEvent.addListener(select, 'change', function()
{
into.toolbar.selectMode(img, function(evt)
{
var pt = mxUtils.convertPoint(editor.graph.container,
mxEvent.getClientX(evt), mxEvent.getClientY(evt));
return editor.addVertex(null, funct(), pt.x, pt.y);
});
into.toolbar.noReset = false;
});
// Adds the entries to the combobox
for (var i=0; i<children.length; i++)
{
var child = children[i];
if (child.nodeName == 'separator')
{
into.addOption(select, '---');
}
else if (child.nodeName == 'add')
{
var lab = child.getAttribute('as');
var tmp = child.getAttribute('template');
var option = into.addOption(select, lab, tmp || template);
option.cellStyle = child.getAttribute('style');
}
}
}
}
}
// Assigns an ID to the created element to access it later.
if (elt != null)
{
var id = node.getAttribute('id');
if (id != null && id.length > 0)
{
elt.setAttribute('id', id);
}
}
}
}
}
node = node.nextSibling;
}
}
return into;
};
// Returns the codec into the registry
return codec;
}());
/**
* Variable: allowEval
*
* Static global switch that specifies if the use of eval is allowed for
* evaluating text content. Default is true. Set this to false if stylesheets
* may contain user input
*/
mxDefaultToolbarCodec.allowEval = true;

View File

@@ -0,0 +1,245 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
mxCodecRegistry.register(function()
{
/**
* Class: mxEditorCodec
*
* Codec for <mxEditor>s. This class is created and registered
* dynamically at load time and used implicitely via <mxCodec>
* and the <mxCodecRegistry>.
*
* Transient Fields:
*
* - modified
* - lastSnapshot
* - ignoredChanges
* - undoManager
* - graphContainer
* - toolbarContainer
*/
var codec = new mxObjectCodec(new mxEditor(),
['modified', 'lastSnapshot', 'ignoredChanges',
'undoManager', 'graphContainer', 'toolbarContainer']);
/**
* Function: beforeDecode
*
* Decodes the ui-part of the configuration node by reading
* a sequence of the following child nodes and attributes
* and passes the control to the default decoding mechanism:
*
* Child Nodes:
*
* stylesheet - Adds a CSS stylesheet to the document.
* resource - Adds the basename of a resource bundle.
* add - Creates or configures a known UI element.
*
* These elements may appear in any order given that the
* graph UI element is added before the toolbar element
* (see Known Keys).
*
* Attributes:
*
* as - Key for the UI element (see below).
* element - ID for the element in the document.
* style - CSS style to be used for the element or window.
* x - X coordinate for the new window.
* y - Y coordinate for the new window.
* width - Width for the new window.
* height - Optional height for the new window.
* name - Name of the stylesheet (absolute/relative URL).
* basename - Basename of the resource bundle (see <mxResources>).
*
* The x, y, width and height attributes are used to create a new
* <mxWindow> if the element attribute is not specified in an add
* node. The name and basename are only used in the stylesheet and
* resource nodes, respectively.
*
* Known Keys:
*
* graph - Main graph element (see <mxEditor.setGraphContainer>).
* title - Title element (see <mxEditor.setTitleContainer>).
* toolbar - Toolbar element (see <mxEditor.setToolbarContainer>).
* status - Status bar element (see <mxEditor.setStatusContainer>).
*
* Example:
*
* (code)
* <ui>
* <stylesheet name="css/process.css"/>
* <resource basename="resources/app"/>
* <add as="graph" element="graph"
* style="left:70px;right:20px;top:20px;bottom:40px"/>
* <add as="status" element="status"/>
* <add as="toolbar" x="10" y="20" width="54"/>
* </ui>
* (end)
*/
codec.afterDecode = function(dec, node, obj)
{
// Assigns the specified templates for edges
var defaultEdge = node.getAttribute('defaultEdge');
if (defaultEdge != null)
{
node.removeAttribute('defaultEdge');
obj.defaultEdge = obj.templates[defaultEdge];
}
// Assigns the specified templates for groups
var defaultGroup = node.getAttribute('defaultGroup');
if (defaultGroup != null)
{
node.removeAttribute('defaultGroup');
obj.defaultGroup = obj.templates[defaultGroup];
}
return obj;
};
/**
* Function: decodeChild
*
* Overrides decode child to handle special child nodes.
*/
codec.decodeChild = function(dec, child, obj)
{
if (child.nodeName == 'Array')
{
var role = child.getAttribute('as');
if (role == 'templates')
{
this.decodeTemplates(dec, child, obj);
return;
}
}
else if (child.nodeName == 'ui')
{
this.decodeUi(dec, child, obj);
return;
}
mxObjectCodec.prototype.decodeChild.apply(this, arguments);
};
/**
* Function: decodeTemplates
*
* Decodes the cells from the given node as templates.
*/
codec.decodeUi = function(dec, node, editor)
{
var tmp = node.firstChild;
while (tmp != null)
{
if (tmp.nodeName == 'add')
{
var as = tmp.getAttribute('as');
var elt = tmp.getAttribute('element');
var style = tmp.getAttribute('style');
var element = null;
if (elt != null)
{
element = document.getElementById(elt);
if (element != null && style != null)
{
element.style.cssText += ';' + style;
}
}
else
{
var x = parseInt(tmp.getAttribute('x'));
var y = parseInt(tmp.getAttribute('y'));
var width = tmp.getAttribute('width');
var height = tmp.getAttribute('height');
// Creates a new window around the element
element = document.createElement('div');
element.style.cssText = style;
var wnd = new mxWindow(mxResources.get(as) || as,
element, x, y, width, height, false, true);
wnd.setVisible(true);
}
// TODO: Make more generic
if (as == 'graph')
{
editor.setGraphContainer(element);
}
else if (as == 'toolbar')
{
editor.setToolbarContainer(element);
}
else if (as == 'title')
{
editor.setTitleContainer(element);
}
else if (as == 'status')
{
editor.setStatusContainer(element);
}
else if (as == 'map')
{
editor.setMapContainer(element);
}
}
else if (tmp.nodeName == 'resource')
{
mxResources.add(tmp.getAttribute('basename'));
}
else if (tmp.nodeName == 'stylesheet')
{
mxClient.link('stylesheet', tmp.getAttribute('name'));
}
tmp = tmp.nextSibling;
}
};
/**
* Function: decodeTemplates
*
* Decodes the cells from the given node as templates.
*/
codec.decodeTemplates = function(dec, node, editor)
{
if (editor.templates == null)
{
editor.templates = [];
}
var children = mxUtils.getChildNodes(node);
for (var j=0; j<children.length; j++)
{
var name = children[j].getAttribute('as');
var child = children[j].firstChild;
while (child != null && child.nodeType != 1)
{
child = child.nextSibling;
}
if (child != null)
{
// LATER: Only single cells means you need
// to group multiple cells within another
// cell. This should be changed to support
// arrays of cells, or the wrapper must
// be automatically handled in this class.
editor.templates[name] = dec.decodeCell(child);
}
}
};
// Returns the codec into the registry
return codec;
}());

View File

@@ -0,0 +1,64 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxGenericChangeCodec
*
* Codec for <mxValueChange>s, <mxStyleChange>s, <mxGeometryChange>s,
* <mxCollapseChange>s and <mxVisibleChange>s. This class is created
* and registered dynamically at load time and used implicitely
* via <mxCodec> and the <mxCodecRegistry>.
*
* Transient Fields:
*
* - model
* - previous
*
* Reference Fields:
*
* - cell
*
* Constructor: mxGenericChangeCodec
*
* Factory function that creates a <mxObjectCodec> for
* the specified change and fieldname.
*
* Parameters:
*
* obj - An instance of the change object.
* variable - The fieldname for the change data.
*/
var mxGenericChangeCodec = function(obj, variable)
{
var codec = new mxObjectCodec(obj, ['model', 'previous'], ['cell']);
/**
* Function: afterDecode
*
* Restores the state by assigning the previous value.
*/
codec.afterDecode = function(dec, node, obj)
{
// Allows forward references in sessions. This is a workaround
// for the sequence of edits in mxGraph.moveCells and cellsAdded.
if (mxUtils.isNode(obj.cell))
{
obj.cell = dec.decodeCell(obj.cell, false);
}
obj.previous = obj[variable];
return obj;
};
return codec;
};
// Registers the codecs
mxCodecRegistry.register(mxGenericChangeCodec(new mxValueChange(), 'value'));
mxCodecRegistry.register(mxGenericChangeCodec(new mxStyleChange(), 'style'));
mxCodecRegistry.register(mxGenericChangeCodec(new mxGeometryChange(), 'geometry'));
mxCodecRegistry.register(mxGenericChangeCodec(new mxCollapseChange(), 'collapsed'));
mxCodecRegistry.register(mxGenericChangeCodec(new mxVisibleChange(), 'visible'));
mxCodecRegistry.register(mxGenericChangeCodec(new mxCellAttributeChange(), 'value'));

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
mxCodecRegistry.register(function()
{
/**
* Class: mxGraphCodec
*
* Codec for <mxGraph>s. This class is created and registered
* dynamically at load time and used implicitely via <mxCodec>
* and the <mxCodecRegistry>.
*
* Transient Fields:
*
* - graphListeners
* - eventListeners
* - view
* - container
* - cellRenderer
* - editor
* - selection
*/
return new mxObjectCodec(new mxGraph(),
['graphListeners', 'eventListeners', 'view', 'container',
'cellRenderer', 'editor', 'selection']);
}());

View File

@@ -0,0 +1,197 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
mxCodecRegistry.register(function()
{
/**
* Class: mxGraphViewCodec
*
* Custom encoder for <mxGraphView>s. This class is created
* and registered dynamically at load time and used implicitely via
* <mxCodec> and the <mxCodecRegistry>. This codec only writes views
* into a XML format that can be used to create an image for
* the graph, that is, it contains absolute coordinates with
* computed perimeters, edge styles and cell styles.
*/
var codec = new mxObjectCodec(new mxGraphView());
/**
* Function: encode
*
* Encodes the given <mxGraphView> using <encodeCell>
* starting at the model's root. This returns the
* top-level graph node of the recursive encoding.
*/
codec.encode = function(enc, view)
{
return this.encodeCell(enc, view,
view.graph.getModel().getRoot());
};
/**
* Function: encodeCell
*
* Recursively encodes the specifed cell. Uses layer
* as the default nodename. If the cell's parent is
* null, then graph is used for the nodename. If
* <mxGraphModel.isEdge> returns true for the cell,
* then edge is used for the nodename, else if
* <mxGraphModel.isVertex> returns true for the cell,
* then vertex is used for the nodename.
*
* <mxGraph.getLabel> is used to create the label
* attribute for the cell. For graph nodes and vertices
* the bounds are encoded into x, y, width and height.
* For edges the points are encoded into a points
* attribute as a space-separated list of comma-separated
* coordinate pairs (eg. x0,y0 x1,y1 ... xn,yn). All
* values from the cell style are added as attribute
* values to the node.
*/
codec.encodeCell = function(enc, view, cell)
{
var model = view.graph.getModel();
var state = view.getState(cell);
var parent = model.getParent(cell);
if (parent == null || state != null)
{
var childCount = model.getChildCount(cell);
var geo = view.graph.getCellGeometry(cell);
var name = null;
if (parent == model.getRoot())
{
name = 'layer';
}
else if (parent == null)
{
name = 'graph';
}
else if (model.isEdge(cell))
{
name = 'edge';
}
else if (childCount > 0 && geo != null)
{
name = 'group';
}
else if (model.isVertex(cell))
{
name = 'vertex';
}
if (name != null)
{
var node = enc.document.createElement(name);
var lab = view.graph.getLabel(cell);
if (lab != null)
{
node.setAttribute('label', view.graph.getLabel(cell));
if (view.graph.isHtmlLabel(cell))
{
node.setAttribute('html', true);
}
}
if (parent == null)
{
var bounds = view.getGraphBounds();
if (bounds != null)
{
node.setAttribute('x', Math.round(bounds.x));
node.setAttribute('y', Math.round(bounds.y));
node.setAttribute('width', Math.round(bounds.width));
node.setAttribute('height', Math.round(bounds.height));
}
node.setAttribute('scale', view.scale);
}
else if (state != null && geo != null)
{
// Writes each key, value in the style pair to an attribute
for (var i in state.style)
{
var value = state.style[i];
// Tries to turn objects and functions into strings
if (typeof(value) == 'function' &&
typeof(value) == 'object')
{
value = mxStyleRegistry.getName(value);
}
if (value != null &&
typeof(value) != 'function' &&
typeof(value) != 'object')
{
node.setAttribute(i, value);
}
}
var abs = state.absolutePoints;
// Writes the list of points into one attribute
if (abs != null && abs.length > 0)
{
var pts = Math.round(abs[0].x) + ',' + Math.round(abs[0].y);
for (var i=1; i<abs.length; i++)
{
pts += ' ' + Math.round(abs[i].x) + ',' +
Math.round(abs[i].y);
}
node.setAttribute('points', pts);
}
// Writes the bounds into 4 attributes
else
{
node.setAttribute('x', Math.round(state.x));
node.setAttribute('y', Math.round(state.y));
node.setAttribute('width', Math.round(state.width));
node.setAttribute('height', Math.round(state.height));
}
var offset = state.absoluteOffset;
// Writes the offset into 2 attributes
if (offset != null)
{
if (offset.x != 0)
{
node.setAttribute('dx', Math.round(offset.x));
}
if (offset.y != 0)
{
node.setAttribute('dy', Math.round(offset.y));
}
}
}
for (var i=0; i<childCount; i++)
{
var childNode = this.encodeCell(enc,
view, model.getChildAt(cell, i));
if (childNode != null)
{
node.appendChild(childNode);
}
}
}
}
return node;
};
// Returns the codec into the registry
return codec;
}());

View File

@@ -0,0 +1,80 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
mxCodecRegistry.register(function()
{
/**
* Class: mxModelCodec
*
* Codec for <mxGraphModel>s. This class is created and registered
* dynamically at load time and used implicitely via <mxCodec>
* and the <mxCodecRegistry>.
*/
var codec = new mxObjectCodec(new mxGraphModel());
/**
* Function: encodeObject
*
* Encodes the given <mxGraphModel> by writing a (flat) XML sequence of
* cell nodes as produced by the <mxCellCodec>. The sequence is
* wrapped-up in a node with the name root.
*/
codec.encodeObject = function(enc, obj, node)
{
var rootNode = enc.document.createElement('root');
enc.encodeCell(obj.getRoot(), rootNode);
node.appendChild(rootNode);
};
/**
* Function: decodeChild
*
* Overrides decode child to handle special child nodes.
*/
codec.decodeChild = function(dec, child, obj)
{
if (child.nodeName == 'root')
{
this.decodeRoot(dec, child, obj);
}
else
{
mxObjectCodec.prototype.decodeChild.apply(this, arguments);
}
};
/**
* Function: decodeRoot
*
* Reads the cells into the graph model. All cells
* are children of the root element in the node.
*/
codec.decodeRoot = function(dec, root, model)
{
var rootCell = null;
var tmp = root.firstChild;
while (tmp != null)
{
var cell = dec.decodeCell(tmp);
if (cell != null && cell.getParent() == null)
{
rootCell = cell;
}
tmp = tmp.nextSibling;
}
// Sets the root on the model if one has been decoded
if (rootCell != null)
{
model.setRoot(rootCell);
}
};
// Returns the codec into the registry
return codec;
}());

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,83 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
mxCodecRegistry.register(function()
{
/**
* Class: mxRootChangeCodec
*
* Codec for <mxRootChange>s. This class is created and registered
* dynamically at load time and used implicitely via <mxCodec> and
* the <mxCodecRegistry>.
*
* Transient Fields:
*
* - model
* - previous
* - root
*/
var codec = new mxObjectCodec(new mxRootChange(),
['model', 'previous', 'root']);
/**
* Function: onEncode
*
* Encodes the child recursively.
*/
codec.afterEncode = function(enc, obj, node)
{
enc.encodeCell(obj.root, node);
return node;
};
/**
* Function: beforeDecode
*
* Decodes the optional children as cells
* using the respective decoder.
*/
codec.beforeDecode = function(dec, node, obj)
{
if (node.firstChild != null &&
node.firstChild.nodeType == mxConstants.NODETYPE_ELEMENT)
{
// Makes sure the original node isn't modified
node = node.cloneNode(true);
var tmp = node.firstChild;
obj.root = dec.decodeCell(tmp, false);
var tmp2 = tmp.nextSibling;
tmp.parentNode.removeChild(tmp);
tmp = tmp2;
while (tmp != null)
{
tmp2 = tmp.nextSibling;
dec.decodeCell(tmp);
tmp.parentNode.removeChild(tmp);
tmp = tmp2;
}
}
return node;
};
/**
* Function: afterDecode
*
* Restores the state by assigning the previous value.
*/
codec.afterDecode = function(dec, node, obj)
{
obj.previous = obj.root;
return obj;
};
// Returns the codec into the registry
return codec;
}());

View File

@@ -0,0 +1,217 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxStylesheetCodec
*
* Codec for <mxStylesheet>s. This class is created and registered
* dynamically at load time and used implicitely via <mxCodec>
* and the <mxCodecRegistry>.
*/
var mxStylesheetCodec = mxCodecRegistry.register(function()
{
var codec = new mxObjectCodec(new mxStylesheet());
/**
* Function: encode
*
* Encodes a stylesheet. See <decode> for a description of the
* format.
*/
codec.encode = function(enc, obj)
{
var node = enc.document.createElement(this.getName());
for (var i in obj.styles)
{
var style = obj.styles[i];
var styleNode = enc.document.createElement('add');
if (i != null)
{
styleNode.setAttribute('as', i);
for (var j in style)
{
var value = this.getStringValue(j, style[j]);
if (value != null)
{
var entry = enc.document.createElement('add');
entry.setAttribute('value', value);
entry.setAttribute('as', j);
styleNode.appendChild(entry);
}
}
if (styleNode.childNodes.length > 0)
{
node.appendChild(styleNode);
}
}
}
return node;
};
/**
* Function: getStringValue
*
* Returns the string for encoding the given value.
*/
codec.getStringValue = function(key, value)
{
var type = typeof(value);
if (type == 'function')
{
value = mxStyleRegistry.getName(style[j]);
}
else if (type == 'object')
{
value = null;
}
return value;
};
/**
* Function: decode
*
* Reads a sequence of the following child nodes
* and attributes:
*
* Child Nodes:
*
* add - Adds a new style.
*
* Attributes:
*
* as - Name of the style.
* extend - Name of the style to inherit from.
*
* Each node contains another sequence of add and remove nodes with the following
* attributes:
*
* as - Name of the style (see <mxConstants>).
* value - Value for the style.
*
* Instead of the value-attribute, one can put Javascript expressions into
* the node as follows if <mxStylesheetCodec.allowEval> is true:
* <add as="perimeter">mxPerimeter.RectanglePerimeter</add>
*
* A remove node will remove the entry with the name given in the as-attribute
* from the style.
*
* Example:
*
* (code)
* <mxStylesheet as="stylesheet">
* <add as="text">
* <add as="fontSize" value="12"/>
* </add>
* <add as="defaultVertex" extend="text">
* <add as="shape" value="rectangle"/>
* </add>
* </mxStylesheet>
* (end)
*/
codec.decode = function(dec, node, into)
{
var obj = into || new this.template.constructor();
var id = node.getAttribute('id');
if (id != null)
{
dec.objects[id] = obj;
}
node = node.firstChild;
while (node != null)
{
if (!this.processInclude(dec, node, obj) && node.nodeName == 'add')
{
var as = node.getAttribute('as');
if (as != null)
{
var extend = node.getAttribute('extend');
var style = (extend != null) ? mxUtils.clone(obj.styles[extend]) : null;
if (style == null)
{
if (extend != null)
{
mxLog.warn('mxStylesheetCodec.decode: stylesheet ' +
extend + ' not found to extend');
}
style = new Object();
}
var entry = node.firstChild;
while (entry != null)
{
if (entry.nodeType == mxConstants.NODETYPE_ELEMENT)
{
var key = entry.getAttribute('as');
if (entry.nodeName == 'add')
{
var text = mxUtils.getTextContent(entry);
var value = null;
if (text != null && text.length > 0 && mxStylesheetCodec.allowEval)
{
value = mxUtils.eval(text);
}
else
{
value = entry.getAttribute('value');
if (mxUtils.isNumeric(value))
{
value = parseFloat(value);
}
}
if (value != null)
{
style[key] = value;
}
}
else if (entry.nodeName == 'remove')
{
delete style[key];
}
}
entry = entry.nextSibling;
}
obj.putCellStyle(as, style);
}
}
node = node.nextSibling;
}
return obj;
};
// Returns the codec into the registry
return codec;
}());
/**
* Variable: allowEval
*
* Static global switch that specifies if the use of eval is allowed for
* evaluating text content. Default is true. Set this to false if stylesheets
* may contain user input.
*/
mxStylesheetCodec.allowEval = true;

View File

@@ -0,0 +1,42 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
mxCodecRegistry.register(function()
{
/**
* Class: mxTerminalChangeCodec
*
* Codec for <mxTerminalChange>s. This class is created and registered
* dynamically at load time and used implicitely via <mxCodec> and
* the <mxCodecRegistry>.
*
* Transient Fields:
*
* - model
* - previous
*
* Reference Fields:
*
* - cell
* - terminal
*/
var codec = new mxObjectCodec(new mxTerminalChange(),
['model', 'previous'], ['cell', 'terminal']);
/**
* Function: afterDecode
*
* Restores the state by assigning the previous value.
*/
codec.afterDecode = function(dec, node, obj)
{
obj.previous = obj.terminal;
return obj;
};
// Returns the codec into the registry
return codec;
}());