mxChildChangeCodec.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /**
  2. * Copyright (c) 2006-2015, JGraph Ltd
  3. * Copyright (c) 2006-2015, Gaudenz Alder
  4. */
  5. mxCodecRegistry.register(function()
  6. {
  7. /**
  8. * Class: mxChildChangeCodec
  9. *
  10. * Codec for <mxChildChange>s. This class is created and registered
  11. * dynamically at load time and used implicitly via <mxCodec> and
  12. * the <mxCodecRegistry>.
  13. *
  14. * Transient Fields:
  15. *
  16. * - model
  17. * - previous
  18. * - previousIndex
  19. * - child
  20. *
  21. * Reference Fields:
  22. *
  23. * - parent
  24. */
  25. var codec = new mxObjectCodec(new mxChildChange(),
  26. ['model', 'child', 'previousIndex'],
  27. ['parent', 'previous']);
  28. /**
  29. * Function: isReference
  30. *
  31. * Returns true for the child attribute if the child
  32. * cell had a previous parent or if we're reading the
  33. * child as an attribute rather than a child node, in
  34. * which case it's always a reference.
  35. */
  36. codec.isReference = function(obj, attr, value, isWrite)
  37. {
  38. if (attr == 'child' && (!isWrite || obj.model.contains(obj.previous)))
  39. {
  40. return true;
  41. }
  42. return mxUtils.indexOf(this.idrefs, attr) >= 0;
  43. };
  44. /**
  45. * Function: isExcluded
  46. *
  47. * Excludes references to parent or previous if not in the model.
  48. */
  49. codec.isExcluded = function(obj, attr, value, write)
  50. {
  51. return mxObjectCodec.prototype.isExcluded.apply(this, arguments) ||
  52. (write && value != null && (attr == 'previous' ||
  53. attr == 'parent') && !obj.model.contains(value));
  54. };
  55. /**
  56. * Function: afterEncode
  57. *
  58. * Encodes the child recusively and adds the result
  59. * to the given node.
  60. */
  61. codec.afterEncode = function(enc, obj, node)
  62. {
  63. if (this.isReference(obj, 'child', obj.child, true))
  64. {
  65. // Encodes as reference (id)
  66. node.setAttribute('child', enc.getId(obj.child));
  67. }
  68. else
  69. {
  70. // At this point, the encoder is no longer able to know which cells
  71. // are new, so we have to encode the complete cell hierarchy and
  72. // ignore the ones that are already there at decoding time. Note:
  73. // This can only be resolved by moving the notify event into the
  74. // execute of the edit.
  75. enc.encodeCell(obj.child, node);
  76. }
  77. return node;
  78. };
  79. /**
  80. * Function: beforeDecode
  81. *
  82. * Decodes the any child nodes as using the respective
  83. * codec from the registry.
  84. */
  85. codec.beforeDecode = function(dec, node, obj)
  86. {
  87. if (node.firstChild != null &&
  88. node.firstChild.nodeType == mxConstants.NODETYPE_ELEMENT)
  89. {
  90. // Makes sure the original node isn't modified
  91. node = node.cloneNode(true);
  92. var tmp = node.firstChild;
  93. obj.child = dec.decodeCell(tmp, false);
  94. var tmp2 = tmp.nextSibling;
  95. tmp.parentNode.removeChild(tmp);
  96. tmp = tmp2;
  97. while (tmp != null)
  98. {
  99. tmp2 = tmp.nextSibling;
  100. if (tmp.nodeType == mxConstants.NODETYPE_ELEMENT)
  101. {
  102. // Ignores all existing cells because those do not need to
  103. // be re-inserted into the model. Since the encoded version
  104. // of these cells contains the new parent, this would leave
  105. // to an inconsistent state on the model (ie. a parent
  106. // change without a call to parentForCellChanged).
  107. var id = tmp.getAttribute('id');
  108. if (dec.lookup(id) == null)
  109. {
  110. dec.decodeCell(tmp);
  111. }
  112. }
  113. tmp.parentNode.removeChild(tmp);
  114. tmp = tmp2;
  115. }
  116. }
  117. else
  118. {
  119. var childRef = node.getAttribute('child');
  120. obj.child = dec.getObject(childRef);
  121. }
  122. return node;
  123. };
  124. /**
  125. * Function: afterDecode
  126. *
  127. * Restores object state in the child change.
  128. */
  129. codec.afterDecode = function(dec, node, obj)
  130. {
  131. // Cells are decoded here after a complete transaction so the previous
  132. // parent must be restored on the cell for the case where the cell was
  133. // added. This is needed for the local model to identify the cell as a
  134. // new cell and register the ID.
  135. if (obj.child != null)
  136. {
  137. if (obj.child.parent != null && obj.previous != null &&
  138. obj.child.parent != obj.previous)
  139. {
  140. obj.previous = obj.child.parent;
  141. }
  142. obj.child.parent = obj.previous;
  143. obj.previous = obj.parent;
  144. obj.previousIndex = obj.index;
  145. }
  146. return obj;
  147. };
  148. // Returns the codec into the registry
  149. return codec;
  150. }());
  151. __mxOutput.mxChildChangeCodec = typeof mxChildChangeCodec !== 'undefined' ? mxChildChangeCodec : undefined;