blob: 92d0c769f7dced93fd9cc32ae3ffa51fbdffcf90 [file] [log] [blame]
/**
* 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.
obj.child.parent = obj.previous;
obj.previous = obj.parent;
obj.previousIndex = obj.index;
return obj;
};
// Returns the codec into the registry
return codec;
}());