169 lines
4.1 KiB
JavaScript
169 lines
4.1 KiB
JavaScript
/**
|
|
* 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 implicitly 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' && (!isWrite || obj.model.contains(obj.previous)))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return mxUtils.indexOf(this.idrefs, attr) >= 0;
|
|
};
|
|
|
|
/**
|
|
* Function: isExcluded
|
|
*
|
|
* Excludes references to parent or previous if not in the model.
|
|
*/
|
|
codec.isExcluded = function(obj, attr, value, write)
|
|
{
|
|
return mxObjectCodec.prototype.isExcluded.apply(this, arguments) ||
|
|
(write && value != null && (attr == 'previous' ||
|
|
attr == 'parent') && !obj.model.contains(value));
|
|
};
|
|
|
|
/**
|
|
* 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 decoded 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;
|
|
|
|
}());
|