| /** |
| * 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; |
| |
| }()); |