UNPKG

jupyterlab-emrys

Version:

A computational environment for Jupyter. Powered by Emrys

301 lines (300 loc) 9.84 kB
// Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. "use strict"; var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var phosphor_signaling_1 = require('phosphor-signaling'); var observablelist_1 = require('../../common/observablelist'); /** * An observable list that supports undo/redo. */ var ObservableUndoableList = (function (_super) { __extends(ObservableUndoableList, _super); /** * Construct a new undoable observable list. */ function ObservableUndoableList(factory) { _super.call(this); this._inCompound = false; this._isUndoable = true; this._madeCompoundChange = false; this._index = -1; this._stack = []; this._factory = null; this._factory = factory; this.changed.connect(this._onListChanged, this); } Object.defineProperty(ObservableUndoableList.prototype, "canRedo", { /** * Whether the object can redo changes. * * #### Notes * This is a read-only property. */ get: function () { return this._index < this._stack.length - 1; }, enumerable: true, configurable: true }); Object.defineProperty(ObservableUndoableList.prototype, "canUndo", { /** * Whether the object can undo changes. * * #### Notes * This is a read-only property. */ get: function () { return this._index >= 0; }, enumerable: true, configurable: true }); Object.defineProperty(ObservableUndoableList.prototype, "isDisposed", { /** * Get whether the object is disposed. * * #### Notes * This is a read-only property. */ get: function () { return this._stack === null; }, enumerable: true, configurable: true }); /** * Dispose of the resources held by the model. */ ObservableUndoableList.prototype.dispose = function () { // Do nothing if already disposed. if (this.isDisposed) { return; } phosphor_signaling_1.clearSignalData(this); this._factory = null; this._stack = null; }; /** * Begin a compound operation. */ ObservableUndoableList.prototype.beginCompoundOperation = function (isUndoAble) { this._inCompound = true; this._isUndoable = (isUndoAble !== false); this._madeCompoundChange = false; }; /** * End a compound operation. */ ObservableUndoableList.prototype.endCompoundOperation = function () { this._inCompound = false; this._isUndoable = true; if (this._madeCompoundChange) { this._index++; } }; /** * Undo an operation. */ ObservableUndoableList.prototype.undo = function () { if (!this.canUndo) { return; } var changes = this._stack[this._index]; this._isUndoable = false; for (var _i = 0, _a = changes.reverse(); _i < _a.length; _i++) { var change = _a[_i]; this._undoChange(change); } this._isUndoable = true; this._index--; }; /** * Redo an operation. */ ObservableUndoableList.prototype.redo = function () { if (!this.canRedo) { return; } this._index++; var changes = this._stack[this._index]; this._isUndoable = false; for (var _i = 0, changes_1 = changes; _i < changes_1.length; _i++) { var change = changes_1[_i]; this._redoChange(change); } this._isUndoable = true; }; /** * Clear the change stack. */ ObservableUndoableList.prototype.clearUndo = function () { this._index = -1; this._stack = []; }; /** * Handle a change in the list. */ ObservableUndoableList.prototype._onListChanged = function (list, change) { if (!this._isUndoable) { return; } // Clear everything after this position if necessary. if (!this._inCompound || !this._madeCompoundChange) { this._stack = this._stack.slice(0, this._index + 1); } // Copy the change. var evt = this._copyChange(change); // Put the change in the stack. if (this._stack[this._index + 1]) { this._stack[this._index + 1].push(evt); } else { this._stack.push([evt]); } // If not in a compound operation, increase index. if (!this._inCompound) { this._index++; } else { this._madeCompoundChange = true; } }; /** * Undo a change event. */ ObservableUndoableList.prototype._undoChange = function (change) { var value; switch (change.type) { case observablelist_1.ListChangeType.Add: this.removeAt(change.newIndex); break; case observablelist_1.ListChangeType.Set: value = this._createValue(change.oldValue); this.set(change.oldIndex, value); break; case observablelist_1.ListChangeType.Remove: value = this._createValue(change.oldValue); this.insert(change.oldIndex, value); break; case observablelist_1.ListChangeType.Move: this.move(change.newIndex, change.oldIndex); break; case observablelist_1.ListChangeType.Replace: var len = change.newValue.length; var values = this._createValues(change.oldValue); this.replace(change.oldIndex, len, values); break; default: return; } }; /** * Redo a change event. */ ObservableUndoableList.prototype._redoChange = function (change) { var value; switch (change.type) { case observablelist_1.ListChangeType.Add: value = this._createValue(change.newValue); this.insert(change.newIndex, value); break; case observablelist_1.ListChangeType.Set: value = this._createValue(change.newValue); this.set(change.newIndex, value); break; case observablelist_1.ListChangeType.Remove: this.removeAt(change.oldIndex); break; case observablelist_1.ListChangeType.Move: this.move(change.oldIndex, change.newIndex); break; case observablelist_1.ListChangeType.Replace: var len = change.oldValue.length; var cells = this._createValues(change.newValue); this.replace(change.oldIndex, len, cells); break; default: return; } }; /** * Create a value from JSON. */ ObservableUndoableList.prototype._createValue = function (data) { var factory = this._factory; return factory(data); }; /** * Create a list of cell models from JSON. */ ObservableUndoableList.prototype._createValues = function (bundles) { var values = []; for (var _i = 0, bundles_1 = bundles; _i < bundles_1.length; _i++) { var bundle = bundles_1[_i]; values.push(this._createValue(bundle)); } return values; }; /** * Copy a change as JSON. */ ObservableUndoableList.prototype._copyChange = function (change) { if (change.type === observablelist_1.ListChangeType.Replace) { return this._copyReplace(change); } var oldValue = null; var newValue = null; switch (change.type) { case observablelist_1.ListChangeType.Add: case observablelist_1.ListChangeType.Set: case observablelist_1.ListChangeType.Remove: if (change.oldValue) { oldValue = change.oldValue.toJSON(); } if (change.newValue) { newValue = change.newValue.toJSON(); } break; case observablelist_1.ListChangeType.Move: // Only need the indices. break; default: return; } return { type: change.type, oldIndex: change.oldIndex, newIndex: change.newIndex, oldValue: oldValue, newValue: newValue }; }; /** * Copy a replace change as JSON. */ ObservableUndoableList.prototype._copyReplace = function (change) { var oldValue = []; for (var _i = 0, _a = change.oldValue; _i < _a.length; _i++) { var value = _a[_i]; oldValue.push(value.toJSON()); } var newValue = []; for (var _b = 0, _c = change.newValue; _b < _c.length; _b++) { var value = _c[_b]; newValue.push(value.toJSON()); } return { type: observablelist_1.ListChangeType.Replace, oldIndex: change.oldIndex, newIndex: change.newIndex, oldValue: oldValue, newValue: newValue }; }; return ObservableUndoableList; }(observablelist_1.ObservableList)); exports.ObservableUndoableList = ObservableUndoableList;