mxChildChangeCodec.js
3.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/**
* 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.
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;
}());