UNPKG

@maxgraph/core

Version:

maxGraph is a fully client side JavaScript diagramming library that uses SVG and HTML for rendering.

144 lines (140 loc) 5.52 kB
"use strict"; /* Copyright 2023-present The maxGraph project Contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ChildChangeCodec = void 0; const ObjectCodec_js_1 = __importDefault(require("../ObjectCodec.js")); const ChildChange_js_1 = __importDefault(require("../../view/undoable_changes/ChildChange.js")); const utils_js_1 = require("../../internal/utils.js"); /** * Codec for {@link ChildChange}s. * * This class is created and registered dynamically at load time and used implicitly via {@link Codec} and the {@link CodecRegistry}. * * Transient Fields: * * - model * - previous * - previousIndex * - child * * Reference Fields: * * - parent * * @category Serialization with Codecs */ class ChildChangeCodec extends ObjectCodec_js_1.default { constructor() { const __dummy = undefined; super(new ChildChange_js_1.default(__dummy, __dummy, __dummy), ['model', 'child', 'previousIndex'], ['parent', 'previous']); } /** * 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. */ isReference(obj, attr, value, isWrite) { if (attr === 'child' && (!isWrite || obj.model.contains(obj.previous))) { return true; } return super.isReference(obj, attr, value, isWrite); } /** * Excludes references to parent or previous if not in the model. */ isExcluded(obj, attr, value, write) { return (super.isExcluded(obj, attr, value, write) || (write && value != null && (attr === 'previous' || attr === 'parent') && !obj.model.contains(value))); } /** * Encodes the child recursively and adds the result to the given node. */ afterEncode(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; } /** * Decodes any child nodes as using the respective codec from the registry. */ beforeDecode(dec, _node, obj) { if ((0, utils_js_1.isElement)(_node.firstChild)) { // Makes sure the original node isn't modified const node = _node.cloneNode(true); let tmp = node.firstChild; obj.child = dec.decodeCell(tmp, false); let tmp2 = tmp.nextSibling; tmp.parentNode.removeChild(tmp); tmp = tmp2; while (tmp) { tmp2 = tmp.nextSibling; if ((0, utils_js_1.isElement)(tmp)) { // 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 (i.e. a parent // change without a call to parentForCellChanged). const id = tmp.getAttribute('id'); if (dec.lookup(id) == null) { dec.decodeCell(tmp); } } tmp.parentNode?.removeChild(tmp); tmp = tmp2; } return node; } else { const childRef = _node.getAttribute('child'); obj.child = dec.getObject(childRef); return _node; } } /** * Restores object state in the child change. */ afterDecode(dec, node, obj) { // Cells are decoded 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; } } exports.ChildChangeCodec = ChildChangeCodec;