Issue #447: apply review comments

This commit is contained in:
Julian Descottes 2016-05-22 14:37:58 +02:00
parent 58d491cb53
commit aa9c1659fc
3 changed files with 40 additions and 87 deletions

View File

@ -7,7 +7,7 @@
this.deserializer = deserializer || pskl.utils.serialization.Deserializer; this.deserializer = deserializer || pskl.utils.serialization.Deserializer;
this.stateQueue = []; this.stateQueue = [];
this.currentUUID = false; this.currentIndex = -1;
this.lastLoadState = -1; this.lastLoadState = -1;
}; };
@ -40,89 +40,52 @@
}; };
ns.HistoryService.prototype.saveState = function (action) { ns.HistoryService.prototype.saveState = function (action) {
this.stateQueue = this.stateQueue.slice(0, this.currentIndex + 1);
this.currentIndex = this.currentIndex + 1;
var state = { var state = {
action : action, action : action,
frameIndex : action.state ? action.state.frameIndex : this.piskelController.currentFrameIndex, frameIndex : action.state ? action.state.frameIndex : this.piskelController.currentFrameIndex,
layerIndex : action.state ? action.state.layerIndex : this.piskelController.currentLayerIndex, layerIndex : action.state ? action.state.layerIndex : this.piskelController.currentLayerIndex,
previousIndex: false, uuid: pskl.utils.Uuid.generate()
nextIndex: false
}; };
var isSnapshot = action.type === ns.HistoryService.SNAPSHOT; var isSnapshot = action.type === ns.HistoryService.SNAPSHOT;
var isAtAutoSnapshotInterval = (this.stateQueue.length - 1) % ns.HistoryService.SNAPSHOT_PERIOD === 0; var isAtAutoSnapshotInterval = this.currentIndex % ns.HistoryService.SNAPSHOT_PERIOD === 0;
if (isSnapshot || isAtAutoSnapshotInterval) { if (isSnapshot || isAtAutoSnapshotInterval) {
state.piskel = this.piskelController.serialize(true); state.piskel = this.piskelController.serialize(true);
} }
this.pushNewState_(state); this.stateQueue.push(state);
$.publish(Events.HISTORY_STATE_SAVED); $.publish(Events.HISTORY_STATE_SAVED);
}; };
ns.HistoryService.prototype.getCurrentStateIndex = function() { ns.HistoryService.prototype.getCurrentStateId = function () {
return this.currentUUID; var state = this.stateQueue[this.currentIndex];
}; if (!state) {
ns.HistoryService.prototype.getCurrentState = function() {
if (this.currentUUID) {
return this.stateQueue[this.currentUUID];
} else {
return false; return false;
} }
};
ns.HistoryService.prototype.pushNewState_ = function(state) { return state.uuid;
// Generate a random UUID (~1e28 combinations)
var uuid = 'xxxxxx'.replace(/x/g, function() {
return (Math.random() * 36 << 0).toString(36);
});
var currentState = this.getCurrentState();
if (currentState) {
// Clear unlinked states
if (currentState.nextIndex) {
this.clearBranchingQueue_(currentState.nextIndex);
}
currentState.nextIndex = uuid;
}
state.previousIndex = this.currentUUID;
this.stateQueue[uuid] = state;
this.currentUUID = uuid;
};
ns.HistoryService.prototype.clearBranchingQueue_ = function(index) {
while (this.stateQueue[index]) {
var next = this.stateQueue[index].nextIndex;
delete(this.stateQueue[index]);
index = next;
}
}; };
ns.HistoryService.prototype.undo = function () { ns.HistoryService.prototype.undo = function () {
var currentState = this.getCurrentState(); this.loadState(this.currentIndex - 1);
if (currentState.previousIndex) {
this.loadState(currentState.previousIndex);
}
}; };
ns.HistoryService.prototype.redo = function () { ns.HistoryService.prototype.redo = function () {
var currentState = this.getCurrentState(); this.loadState(this.currentIndex + 1);
if (currentState.nextIndex) {
this.loadState(currentState.nextIndex);
}
}; };
ns.HistoryService.prototype.isLoadStateAllowed_ = function (index) { ns.HistoryService.prototype.isLoadStateAllowed_ = function (index) {
var timeOk = (Date.now() - this.lastLoadState) > ns.HistoryService.LOAD_STATE_INTERVAL; var timeOk = (Date.now() - this.lastLoadState) > ns.HistoryService.LOAD_STATE_INTERVAL;
var indexInRange = index && this.stateQueue[index]; var indexInRange = index >= 0 && index < this.stateQueue.length;
return timeOk && indexInRange; return timeOk && indexInRange;
}; };
ns.HistoryService.prototype.getPreviousSnapshotIndex_ = function (index) { ns.HistoryService.prototype.getPreviousSnapshotIndex_ = function (index) {
while (this.stateQueue[index] && !this.stateQueue[index].piskel) { while (this.stateQueue[index] && !this.stateQueue[index].piskel) {
index = this.stateQueue[index].previousIndex; index = index - 1;
} }
return index; return index;
}; };
@ -133,7 +96,7 @@
this.lastLoadState = Date.now(); this.lastLoadState = Date.now();
var snapshotIndex = this.getPreviousSnapshotIndex_(index); var snapshotIndex = this.getPreviousSnapshotIndex_(index);
if (!snapshotIndex) { if (snapshotIndex < 0) {
throw 'Could not find previous SNAPSHOT saved in history stateQueue'; throw 'Could not find previous SNAPSHOT saved in history stateQueue';
} }
var serializedPiskel = this.getSnapshotFromState_(snapshotIndex); var serializedPiskel = this.getSnapshotFromState_(snapshotIndex);
@ -144,7 +107,7 @@
console.error('[CRITICAL ERROR] : Unable to load a history state.'); console.error('[CRITICAL ERROR] : Unable to load a history state.');
this.logError_(error); this.logError_(error);
this.stateQueue = []; this.stateQueue = [];
this.currentUUID = false; this.currentIndex = -1;
} }
}; };
@ -179,23 +142,19 @@
piskel.savePath = this.piskelController.piskel.savePath; piskel.savePath = this.piskelController.piskel.savePath;
this.piskelController.setPiskel(piskel); this.piskelController.setPiskel(piskel);
var walkingIndex = snapshotIndex; for (var i = snapshotIndex + 1 ; i <= index ; i++) {
while (walkingIndex && walkingIndex != index) { var state = this.stateQueue[i];
walkingIndex = this.stateQueue[walkingIndex].nextIndex;
if (walkingIndex) {
var state = this.stateQueue[walkingIndex];
this.setupState(state); this.setupState(state);
this.replayState(state); this.replayState(state);
} }
}
// Should only do this when going backwards // Should only do this when going backwards
var next = this.stateQueue[index].nextIndex; var lastState = this.stateQueue[index + 1];
if (next) { if (lastState) {
this.setupState(this.stateQueue[next]); this.setupState(lastState);
} }
this.currentUUID = index; this.currentIndex = index;
$.publish(Events.PISKEL_RESET); $.publish(Events.PISKEL_RESET);
$.publish(Events.HISTORY_STATE_LOADED); $.publish(Events.HISTORY_STATE_LOADED);
if (originalSize !== this.getPiskelSize_()) { if (originalSize !== this.getPiskelSize_()) {

View File

@ -5,33 +5,27 @@
this.piskelController = piskelController; this.piskelController = piskelController;
this.historyService = historyService; this.historyService = historyService;
this.lastSavedStateIndex = ''; this.lastSavedStateIndex = '';
this.publishStatusUpdateEvent_ = this.publishStatusUpdateEvent_.bind(this);
}; };
ns.SavedStatusService.prototype.init = function () { ns.SavedStatusService.prototype.init = function () {
$.subscribe(Events.TOOL_RELEASED, this.onToolReleased.bind(this)); $.subscribe(Events.TOOL_RELEASED, this.publishStatusUpdateEvent_);
$.subscribe(Events.PISKEL_RESET, this.onPiskelReset.bind(this)); $.subscribe(Events.PISKEL_RESET, this.publishStatusUpdateEvent_);
$.subscribe(Events.PISKEL_SAVED, this.onPiskelSaved.bind(this)); $.subscribe(Events.PISKEL_SAVED, this.onPiskelSaved.bind(this));
this.lastSavedStateIndex = this.historyService.getCurrentStateIndex(); this.lastSavedStateIndex = this.historyService.getCurrentStateId();
};
ns.SavedStatusService.prototype.onToolReleased = function () {
this.updateDirtyStatus();
};
ns.SavedStatusService.prototype.onPiskelReset = function () {
this.updateDirtyStatus();
}; };
ns.SavedStatusService.prototype.onPiskelSaved = function () { ns.SavedStatusService.prototype.onPiskelSaved = function () {
this.lastSavedStateIndex = this.historyService.getCurrentStateIndex(); this.lastSavedStateIndex = this.historyService.getCurrentStateId();
$.publish(Events.PISKEL_SAVED_STATUS_UPDATE); this.publishStatusUpdateEvent_();
}; };
ns.SavedStatusService.prototype.updateDirtyStatus = function () { ns.SavedStatusService.prototype.publishStatusUpdateEvent_ = function () {
$.publish(Events.PISKEL_SAVED_STATUS_UPDATE); $.publish(Events.PISKEL_SAVED_STATUS_UPDATE);
}; };
ns.SavedStatusService.prototype.isDirty = function () { ns.SavedStatusService.prototype.isDirty = function () {
return (this.lastSavedStateIndex != this.historyService.getCurrentStateIndex()); return (this.lastSavedStateIndex != this.historyService.getCurrentStateId());
}; };
})(); })();

View File

@ -18,7 +18,7 @@ describe("History Service suite", function() {
var historyService = null; var historyService = null;
var getLastState = function () { var getLastState = function () {
return historyService.getCurrentState(); return historyService.stateQueue[historyService.currentIndex];
}; };
var createMockHistoryService = function () { var createMockHistoryService = function () {
@ -34,15 +34,15 @@ describe("History Service suite", function() {
return new pskl.service.HistoryService(mockPiskelController, mockShortcutService); return new pskl.service.HistoryService(mockPiskelController, mockShortcutService);
}; };
it("starts empty", function() { it("starts at -1", function() {
historyService = createMockHistoryService(); historyService = createMockHistoryService();
expect(historyService.stateQueue.length).toBe(0); expect(historyService.currentIndex).toBe(-1);
}); });
it("has 1 item after init", function() { it("is at 0 after init", function() {
historyService = createMockHistoryService(); historyService = createMockHistoryService();
historyService.init(); historyService.init();
expect(historyService.stateQueue.length).toBe(1); expect(historyService.currentIndex).toBe(0);
}); });
var sendSaveEvents = function (type) { var sendSaveEvents = function (type) {
@ -65,7 +65,7 @@ describe("History Service suite", function() {
sendSaveEvents(pskl.service.HistoryService.REPLAY).times(5); sendSaveEvents(pskl.service.HistoryService.REPLAY).times(5);
expect(historyService.stateQueue.length).toBe(5); expect(historyService.currentIndex).toBe(5);
expect(getLastState().piskel).toBe(SERIALIZED_PISKEL); expect(getLastState().piskel).toBe(SERIALIZED_PISKEL);