|
|
@@ -1105,13 +1105,15 @@ class History {
|
|
|
};
|
|
|
}
|
|
|
|
|
|
- _exec(op, setState) {
|
|
|
- // update mapping to point to op
|
|
|
+ _update_head(op) {
|
|
|
for (const [key, {value}] of op.detail.entries()) {
|
|
|
- this.heads.set(key, op); // update HEAD ptr
|
|
|
- if (setState) {
|
|
|
- this.setState(key, value);
|
|
|
- }
|
|
|
+ this.heads.set(key, op);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ _update_state(op) {
|
|
|
+ for (const [key, {value}] of op.detail.entries()) {
|
|
|
+ this.setState(key, value);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1132,7 +1134,7 @@ class History {
|
|
|
|
|
|
// To be called when a new user operation has happened locally.
|
|
|
// The new operation advances HEADs.
|
|
|
- new(v, setState=true) {
|
|
|
+ new(v, updateState=true) {
|
|
|
const newId = uuidv4();
|
|
|
const detail = new Map(Object.entries(v).map(([key,value]) => {
|
|
|
const {op: parent, depth} = this._getHead(key);
|
|
|
@@ -1146,7 +1148,10 @@ class History {
|
|
|
for (const [key, {parent}] of detail.entries()) {
|
|
|
this._setChild(parent, key, newOp);
|
|
|
}
|
|
|
- this._exec(newOp, setState);
|
|
|
+ this._update_head(newOp);
|
|
|
+ if (updateState) {
|
|
|
+ this._update_state(newOp);
|
|
|
+ }
|
|
|
|
|
|
this.context.ops.set(newId, Promise.resolve(newOp));
|
|
|
this.ops.set(newId, newOp);
|
|
|
@@ -1216,7 +1221,8 @@ class History {
|
|
|
}
|
|
|
|
|
|
if (exec) {
|
|
|
- this._exec(op, true);
|
|
|
+ this._update_head(op);
|
|
|
+ this._update_state(op);
|
|
|
}
|
|
|
|
|
|
this.ops.set(op.id, op);
|
|
|
@@ -1514,31 +1520,45 @@ Draw.loadPlugin(async function(ui) {
|
|
|
model.setStyle(cell, style);
|
|
|
},
|
|
|
parent: () => {
|
|
|
- const cellId = value;
|
|
|
- const parent = model.cells[cellId];
|
|
|
- // The following appears to create a mxChildChange object, indicating that it is this the correct way to set the parent...
|
|
|
- if (parent) {
|
|
|
- model.add(parent, cell, null);
|
|
|
- } else {
|
|
|
+ const {parentId} = value;
|
|
|
+ if (parentId === null) {
|
|
|
+ // Creates a mxChildChange object
|
|
|
model.remove(cell);
|
|
|
}
|
|
|
+ else {
|
|
|
+ let parent = getCell(parentId);
|
|
|
+ if (parent === undefined) {
|
|
|
+ console.log("creating non-existing parent");
|
|
|
+ const {isVertex, isEdge} = value;
|
|
|
+ parent = createCell(parentId, isVertex, isEdge);
|
|
|
+ }
|
|
|
+ // Creates a mxChildChange object
|
|
|
+ model.add(parent, cell, null);
|
|
|
+ }
|
|
|
},
|
|
|
value: () => {
|
|
|
let v;
|
|
|
if (typeof value === 'object') {
|
|
|
const {xmlEncoded} = value;
|
|
|
- v = xmlParser.parseFromString(xmlEncoded, 'text/xml');
|
|
|
+ v = xmlParser.parseFromString(xmlEncoded, 'text/xml').documentElement;
|
|
|
} else {
|
|
|
v = value;
|
|
|
}
|
|
|
- model.setValue(cell, v.documentElement);
|
|
|
+ model.setValue(cell, v);
|
|
|
},
|
|
|
source: () => {
|
|
|
const sourceId = value;
|
|
|
if (sourceId === null) {
|
|
|
model.setTerminal(cell, null, true);
|
|
|
} else {
|
|
|
- const source = getCell(sourceId);
|
|
|
+ const source = getCell(sourceId)
|
|
|
+ // if in the same user operation, a vertex is created and an edge
|
|
|
+ // is connected to that vertex, it is possible that the connection
|
|
|
+ // is made before the vertex is created (operations within a single user
|
|
|
+ // operation are currently unordered)
|
|
|
+ || createCell(sourceId,
|
|
|
+ /* isVertex */ true,
|
|
|
+ /* isEdge */ false);
|
|
|
if (source === undefined) {
|
|
|
throw new Error("NO SUCH CELL:", cellId);
|
|
|
}
|
|
|
@@ -1550,7 +1570,10 @@ Draw.loadPlugin(async function(ui) {
|
|
|
if (targetId === null) {
|
|
|
model.setTerminal(cell, null, false);
|
|
|
} else {
|
|
|
- const target = getCell(targetId);
|
|
|
+ const target = getCell(targetId)
|
|
|
+ || createCell(targetId,
|
|
|
+ /* isVertex */ true,
|
|
|
+ /* isEdge */ false);
|
|
|
if (target === undefined) {
|
|
|
throw new Error("NO SUCH CELL:", cellId);
|
|
|
}
|
|
|
@@ -1751,7 +1774,11 @@ Draw.loadPlugin(async function(ui) {
|
|
|
deltaObj[prefix + 'style'] = cell.style;
|
|
|
}
|
|
|
if (cell.parent) {
|
|
|
- deltaObj[prefix + 'parent'] = cell.parent.id;
|
|
|
+ deltaObj[prefix + 'parent'] = {
|
|
|
+ parentId: cell.parent.id,
|
|
|
+ isVertex: cell.parent.isVertex(),
|
|
|
+ isEdge: cell.parent.isEdge(),
|
|
|
+ };
|
|
|
}
|
|
|
if (cell.value) {
|
|
|
// For some reason, 'value' can be an HTML string (when only a label is defined, or it can be a DOM object
|
|
|
@@ -1793,6 +1820,7 @@ Draw.loadPlugin(async function(ui) {
|
|
|
}
|
|
|
else {
|
|
|
if (change.constructor === mxGeometryChange) {
|
|
|
+ console.log(change.cell.id, 'change geometry')
|
|
|
deltaObj[keyPrefix(change.cell) + 'geometry'] = change.geometry ?
|
|
|
xmlSerializer.serializeToString(
|
|
|
codec.encode(change.geometry)) : null;
|
|
|
@@ -1801,14 +1829,29 @@ Draw.loadPlugin(async function(ui) {
|
|
|
deltaObj[keyPrefix(change.cell) + 'style'] = change.style;
|
|
|
}
|
|
|
else if (change.constructor === mxChildChange) {
|
|
|
+ console.log(change.child.id, 'change parent')
|
|
|
if (change.previous && model.contains(change.previous)) {
|
|
|
// cell had a previous parent
|
|
|
console.log("previous parent");
|
|
|
- deltaObj[keyPrefix(change.child) + 'parent'] = change.parent ? change.parent.id: null;
|
|
|
+ deltaObj[keyPrefix(change.child) + 'parent'] = change.parent ? {
|
|
|
+ parentId: change.parent.id,
|
|
|
+ isVertex: change.parent.isVertex(),
|
|
|
+ isEdge: change.parent.isEdge(),
|
|
|
+ } : {
|
|
|
+ parentId: null,
|
|
|
+ };
|
|
|
} else {
|
|
|
// no previous parent -> cell was created:
|
|
|
console.log("no previous parent");
|
|
|
- encodeCompleteCellState(change.child, deltaObj);
|
|
|
+ function recursivelyEncode(cell) {
|
|
|
+ encodeCompleteCellState(cell, deltaObj);
|
|
|
+ if (cell.children !== null) {
|
|
|
+ for (const child of cell.children) {
|
|
|
+ recursivelyEncode(child);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ recursivelyEncode(change.child);
|
|
|
}
|
|
|
}
|
|
|
else if (change.constructor === mxValueChange) {
|
|
|
@@ -1861,18 +1904,18 @@ Draw.loadPlugin(async function(ui) {
|
|
|
// UI stuff
|
|
|
uiState.install(ui);
|
|
|
|
|
|
- // document.addEventListener('keydown', e => {
|
|
|
+ document.addEventListener('keydown', e => {
|
|
|
// console.log(e);
|
|
|
- // if (e.code === 'KeyC') {
|
|
|
- // console.log("KeyC pressed: Clear model and reset history");
|
|
|
- // resetHistory();
|
|
|
- // model.clear();
|
|
|
- // }
|
|
|
+ if (e.code === 'KeyC') {
|
|
|
+ console.log("KeyC pressed: Clear model and reset history");
|
|
|
+ resetHistory();
|
|
|
+ model.clear();
|
|
|
+ }
|
|
|
|
|
|
- // if (e.code === 'KeyH') {
|
|
|
- // const seq = history.getOpsSequence();
|
|
|
- // console.log(seq.map(op => op.serialize()));
|
|
|
- // }
|
|
|
+ if (e.code === 'KeyH') {
|
|
|
+ const seq = history.getOpsSequence();
|
|
|
+ console.log(seq.map(op => op.serialize()));
|
|
|
+ }
|
|
|
|
|
|
// if (e.code === 'KeyU') {
|
|
|
// const u = window.prompt("Choose a user name:", myName);
|
|
|
@@ -1880,6 +1923,6 @@ Draw.loadPlugin(async function(ui) {
|
|
|
// myName = u;
|
|
|
// }
|
|
|
// }
|
|
|
- // })
|
|
|
+ });
|
|
|
});
|
|
|
},{"../../../../../lib/versioning/DragHandler.js":16,"../../../../../lib/versioning/GhostOverlays.js":17,"../../../../../lib/versioning/History.js":18,"../../../../../lib/versioning/UserColors.js":19}]},{},[20]);
|