UNPKG

wed

Version:

Wed is a schema-aware editor for XML documents.

254 lines 9.87 kB
var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; define(["require", "exports", "./domutil", "./undo"], function (require, exports, domutil_1, undo) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); undo = __importStar(undo); function getOuterHTML(node) { return (node == null) ? "undefined" : node.outerHTML; } /** * Undo operation for [["wed/tree-updater".InsertNodeAtEvent]]. * * The parameters after ``tree_updater`` are the same as the properties on the * event corresponding to this class. * * @private */ class InsertNodeAtUndo extends undo.Undo { /** * @param treeUpdater The tree updater to use to perform undo or redo * operations. * * @param parent * @param index */ constructor(treeUpdater, parent, index) { super("InsertNodeAtUndo"); this.treeUpdater = treeUpdater; this.index = index; this.parentPath = treeUpdater.nodeToPath(parent); // We do not take a node parameter and save it here because further // manipulations could take the node out of the tree. So we cannot rely in a // reference to a node. What we do instead is keep a path to the parent and // the index. The ``node`` property will be filled as needed when // undoing/redoing. } performUndo() { if (this.node !== undefined) { throw new Error("undo called twice in a row"); } const parent = this.treeUpdater.pathToNode(this.parentPath); this.node = parent.childNodes[this.index].cloneNode(true); this.treeUpdater.deleteNode(parent.childNodes[this.index]); } performRedo() { if (this.node === undefined) { throw new Error("redo called twice in a row"); } const parent = this.treeUpdater.pathToNode(this.parentPath); this.treeUpdater.insertNodeAt(parent, this.index, this.node); this.node = undefined; } toString() { return [this.desc, "\n", " Parent path: ", this.parentPath, "\n", " Index: ", this.index, "\n", " Node: ", getOuterHTML(this.node), "\n"].join(""); } } /** * Undo operation for [["wed/tree-updater".SetTextNodeValueEvent]]. * * @private */ class SetTextNodeValueUndo extends undo.Undo { /** * @param treeUpdater The tree updater to use to perform undo or redo * operations. */ constructor(treeUpdater, node, value, oldValue) { super("SetTextNodeValueUndo"); this.treeUpdater = treeUpdater; this.value = value; this.oldValue = oldValue; this.nodePath = treeUpdater.nodeToPath(node); } performUndo() { // The node is necessarily a text node. const node = this.treeUpdater.pathToNode(this.nodePath); this.treeUpdater.setTextNodeValue(node, this.oldValue); } performRedo() { // The node is necessarily a text node. const node = this.treeUpdater.pathToNode(this.nodePath); this.treeUpdater.setTextNodeValue(node, this.value); } toString() { return [this.desc, "\n", " Node path: ", this.nodePath, "\n", " Value: ", this.value, "\n", " Old value: ", this.oldValue, "\n"].join(""); } } /** * Undo operation for [["wed/tree-updater".BeforeDeleteNodeEvent]]. * * @private */ class DeleteNodeUndo extends undo.Undo { /** * @param treeUpdater The tree updater to use to perform undo or redo * operations. */ constructor(treeUpdater, node) { super("DeleteNodeUndo"); this.treeUpdater = treeUpdater; const parent = node.parentNode; this.parentPath = treeUpdater.nodeToPath(parent); this.index = domutil_1.indexOf(parent.childNodes, node); this.node = node.cloneNode(true); } performUndo() { if (this.node === undefined) { throw new Error("undo called twice in a row"); } const parent = this.treeUpdater.pathToNode(this.parentPath); this.treeUpdater.insertNodeAt(parent, this.index, this.node); this.node = undefined; } performRedo() { if (this.node !== undefined) { throw new Error("redo called twice in a row"); } const parent = this.treeUpdater.pathToNode(this.parentPath); this.node = parent.childNodes[this.index].cloneNode(true); this.treeUpdater.deleteNode(parent.childNodes[this.index]); } toString() { return [this.desc, "\n", " Parent path: ", this.parentPath, "\n", " Index: ", this.index, "\n", " Node: ", getOuterHTML(this.node), "\n"].join(""); } } /** * Undo operation for [["wed/tree-updater".SetAttributeNSEvent]]. * * @private */ class SetAttributeNSUndo extends undo.Undo { /** * @param treeUpdater The tree updater to use to perform undo or redo * operations. */ constructor(treeUpdater, node, ns, attribute, oldValue, newValue) { super("SetAttributeNSUndo"); this.treeUpdater = treeUpdater; this.ns = ns; this.attribute = attribute; this.oldValue = oldValue; this.newValue = newValue; this.nodePath = treeUpdater.nodeToPath(node); } performUndo() { const node = this.treeUpdater.pathToNode(this.nodePath); this.treeUpdater.setAttributeNS(node, this.ns, this.attribute, this.oldValue); } performRedo() { const node = this.treeUpdater.pathToNode(this.nodePath); this.treeUpdater.setAttributeNS(node, this.ns, this.attribute, this.newValue); } toString() { return [this.desc, "\n", " Node path: ", this.nodePath, "\n", " Namespace: ", this.ns, "\n", " Attribute Name: ", this.attribute, "\n", " New value: ", this.newValue, "\n", " Old value: ", this.oldValue, "\n"].join(""); } } /** * Records undo operations. */ class UndoRecorder { /** * @param editor The editor for which this recorder is created. * * @param treeUpdater The tree updater on which to listen for modifications. */ constructor(editor, treeUpdater) { this.editor = editor; this.treeUpdater = treeUpdater; this.suppress = false; treeUpdater.events.subscribe((ev) => { switch (ev.name) { case "InsertNodeAt": this.insertNodeAtHandler(ev); break; case "SetTextNodeValue": this.setTextNodeValueHandler(ev); break; case "BeforeDeleteNode": this.beforeDeleteNodeHandler(ev); break; case "SetAttributeNS": this.setAttributeNSHandler(ev); break; default: // Do nothing... } }); } /** * Sets the suppression state. When suppression is on, the recorder does not * record anything. When off, the recorder records. The recorder's suppression * state is initially off. * * @param suppress Whether to suppress or not. * * @throws {Error} If the call does not change the suppression state. */ suppressRecording(suppress) { if (suppress === this.suppress) { throw new Error("spurious call to suppressRecording"); } this.suppress = suppress; } insertNodeAtHandler(ev) { if (this.suppress) { return; } this.editor.recordUndo(new InsertNodeAtUndo(this.treeUpdater, ev.parent, ev.index)); } setTextNodeValueHandler(ev) { if (this.suppress) { return; } this.editor.recordUndo(new SetTextNodeValueUndo(this.treeUpdater, ev.node, ev.value, ev.oldValue)); } beforeDeleteNodeHandler(ev) { if (this.suppress) { return; } this.editor.recordUndo(new DeleteNodeUndo(this.treeUpdater, ev.node)); } setAttributeNSHandler(ev) { if (this.suppress) { return; } this.editor.recordUndo(new SetAttributeNSUndo(this.treeUpdater, ev.node, ev.ns, ev.attribute, ev.oldValue, ev.newValue)); } } exports.UndoRecorder = UndoRecorder; }); // LocalWords: domutil insertNodeAt setTextNodeValue deleteNode ev param MPL // LocalWords: InsertNodeAtUndo SetTextNodeValueUndo DeleteNodeUndo Dubeau // LocalWords: pathToNode nodeToPath Mangalam SetAttributeNSUndo // LocalWords: BeforeDeleteNode SetAttributeNS suppressRecording //# sourceMappingURL=undo-recorder.js.map