2019-08-09 21:24:01 +08:00

209 lines
5.7 KiB
JavaScript

import Command from './Command';
/**
* 历史记录
* @author dforrer / https://github.com/dforrer
* Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
*/
function History(editor) {
this.editor = editor;
this.undos = [];
this.redos = [];
this.lastCmdTime = new Date();
this.idCounter = 0;
Command.call(this, editor);
};
History.prototype = Object.create(Command.prototype);
Object.assign(History.prototype, {
constructor: History,
execute: function (cmd, optionalName) {
var lastCmd = this.undos[this.undos.length - 1];
var timeDifference = new Date().getTime() - this.lastCmdTime.getTime();
var isUpdatableCmd = lastCmd &&
lastCmd.updatable &&
cmd.updatable &&
lastCmd.object === cmd.object &&
lastCmd.type === cmd.type &&
lastCmd.script === cmd.script &&
lastCmd.attributeName === cmd.attributeName;
if (isUpdatableCmd && cmd.type === "SetScriptValueCommand") {
// When the cmd.type is "SetScriptValueCommand" the timeDifference is ignored
lastCmd.update(cmd);
cmd = lastCmd;
} else if (isUpdatableCmd && timeDifference < 500) {
lastCmd.update(cmd);
cmd = lastCmd;
} else {
// the command is not updatable and is added as a new part of the history
this.undos.push(cmd);
cmd.id = ++this.idCounter;
}
cmd.name = (optionalName !== undefined) ? optionalName : cmd.name;
cmd.execute();
cmd.inMemory = true;
this.lastCmdTime = new Date();
// clearing all the redo-commands
this.redos = [];
app.call('historyChanged', this, cmd);
},
undo: function () {
var cmd = undefined;
if (this.undos.length > 0) {
cmd = this.undos.pop();
if (cmd.inMemory === false) {
cmd.fromJSON(cmd.json);
}
}
if (cmd !== undefined) {
cmd.undo();
this.redos.push(cmd);
app.call('historyChanged', this, cmd);
}
return cmd;
},
redo: function () {
var cmd = undefined;
if (this.redos.length > 0) {
cmd = this.redos.pop();
if (cmd.inMemory === false) {
cmd.fromJSON(cmd.json);
}
}
if (cmd !== undefined) {
cmd.execute();
this.undos.push(cmd);
app.call('historyChanged', this, cmd);
}
return cmd;
},
toJSON: function () {
var history = {};
history.undos = [];
history.redos = [];
// Append Undos to History
for (var i = 0; i < this.undos.length; i++) {
if (this.undos[i].hasOwnProperty("json")) {
history.undos.push(this.undos[i].json);
}
}
// Append Redos to History
for (var i = 0; i < this.redos.length; i++) {
if (this.redos[i].hasOwnProperty("json")) {
history.redos.push(this.redos[i].json);
}
}
return history;
},
fromJSON: function (json) {
if (json === undefined) return;
for (var i = 0; i < json.undos.length; i++) {
var cmdJSON = json.undos[i];
var cmd = new window[cmdJSON.type](); // creates a new object of type "json.type"
cmd.json = cmdJSON;
cmd.id = cmdJSON.id;
cmd.name = cmdJSON.name;
this.undos.push(cmd);
this.idCounter = (cmdJSON.id > this.idCounter) ? cmdJSON.id : this.idCounter; // set last used idCounter
}
for (var i = 0; i < json.redos.length; i++) {
var cmdJSON = json.redos[i];
var cmd = new window[cmdJSON.type](); // creates a new object of type "json.type"
cmd.json = cmdJSON;
cmd.id = cmdJSON.id;
cmd.name = cmdJSON.name;
this.redos.push(cmd);
this.idCounter = (cmdJSON.id > this.idCounter) ? cmdJSON.id : this.idCounter; // set last used idCounter
}
// Select the last executed undo-command
app.call('historyChanged', this, this.undos[this.undos.length - 1]);
},
clear: function () {
this.undos = [];
this.redos = [];
this.idCounter = 0;
app.call('historyChanged', this);
},
goToState: function (id) {
var cmd = this.undos.length > 0 ? this.undos[this.undos.length - 1] : undefined; // next cmd to pop
if (cmd === undefined || id > cmd.id) {
cmd = this.redo();
while (cmd !== undefined && id > cmd.id) {
cmd = this.redo();
}
} else {
while (true) {
cmd = this.undos[this.undos.length - 1]; // next cmd to pop
if (cmd === undefined || id === cmd.id) break;
cmd = this.undo();
}
}
app.call('historyChanged', this, cmd);
},
enableSerialization: function (id) {
/**
* because there might be commands in this.undos and this.redos
* which have not been serialized with .toJSON() we go back
* to the oldest command and redo one command after the other
* while also calling .toJSON() on them.
*/
this.goToState(-1);
var cmd = this.redo();
while (cmd !== undefined) {
if (!cmd.hasOwnProperty("json")) {
cmd.json = cmd.toJSON();
}
cmd = this.redo();
}
this.goToState(id);
}
});
export default History;