summaryrefslogtreecommitdiff
path: root/src/js/io/mxChildChangeCodec.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/io/mxChildChangeCodec.js')
-rw-r--r--src/js/io/mxChildChangeCodec.js149
1 files changed, 149 insertions, 0 deletions
diff --git a/src/js/io/mxChildChangeCodec.js b/src/js/io/mxChildChangeCodec.js
new file mode 100644
index 0000000..deeb57b
--- /dev/null
+++ b/src/js/io/mxChildChangeCodec.js
@@ -0,0 +1,149 @@
+/**
+ * $Id: mxChildChangeCodec.js,v 1.12 2010-09-15 14:38:52 gaudenz Exp $
+ * Copyright (c) 2006-2010, JGraph Ltd
+ */
+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;
+
+}());