This commit is contained in:
Christopher Chedeau 2020-01-04 16:59:59 -08:00 committed by GitHub
parent 4ca8f65887
commit 9e5c5daf64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -20,6 +20,34 @@ const LOCAL_STORAGE_KEY_STATE = "excalidraw-state";
const elements = Array.of<ExcalidrawElement>();
let skipHistory = false;
const stateHistory: string[] = [];
function generateHistoryCurrentEntry() {
return JSON.stringify(
elements.map(element => ({ ...element, isSelected: false }))
);
}
function pushHistoryEntry(newEntry: string) {
if (
stateHistory.length > 0 &&
stateHistory[stateHistory.length - 1] === newEntry
) {
// If the last entry is the same as this one, ignore it
return;
}
stateHistory.push(newEntry);
}
function restoreHistoryEntry(entry: string) {
const newElements = JSON.parse(entry);
elements.splice(0, elements.length);
newElements.forEach((newElement: ExcalidrawElement) => {
generateDraw(newElement);
elements.push(newElement);
});
// When restoring, we shouldn't add an history entry otherwise we'll be stuck with it and can't go back
skipHistory = true;
}
// https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript/47593316#47593316
const LCG = (seed: number) => () =>
((2 ** 31 - 1) & (seed = Math.imul(48271, seed))) / 2 ** 31;
@ -901,6 +929,17 @@ class App extends React.Component<{}, AppState> {
event.preventDefault();
} else if (shapesShortcutKeys.includes(event.key.toLowerCase())) {
this.setState({ elementType: findElementByKey(event.key) });
} else if (event.metaKey && event.code === "KeyZ") {
let lastEntry = stateHistory.pop();
// If nothing was changed since last, take the previous one
if (generateHistoryCurrentEntry() === lastEntry) {
lastEntry = stateHistory.pop();
}
if (lastEntry !== undefined) {
restoreHistoryEntry(lastEntry);
}
this.forceUpdate();
event.preventDefault();
}
};
@ -1301,6 +1340,8 @@ class App extends React.Component<{}, AppState> {
});
lastX = x;
lastY = y;
// We don't want to save history when resizing an element
skipHistory = true;
this.forceUpdate();
return;
}
@ -1319,6 +1360,8 @@ class App extends React.Component<{}, AppState> {
});
lastX = x;
lastY = y;
// We don't want to save history when dragging an element to initially size it
skipHistory = true;
this.forceUpdate();
return;
}
@ -1347,6 +1390,8 @@ class App extends React.Component<{}, AppState> {
if (this.state.elementType === "selection") {
setSelection(draggingElement);
}
// We don't want to save history when moving an element
skipHistory = true;
this.forceUpdate();
};
@ -1384,6 +1429,8 @@ class App extends React.Component<{}, AppState> {
window.addEventListener("mousemove", onMouseMove);
window.addEventListener("mouseup", onMouseUp);
// We don't want to save history on mouseDown, only on mouseUp when it's fully configured
skipHistory = true;
this.forceUpdate();
}}
/>
@ -1407,6 +1454,10 @@ class App extends React.Component<{}, AppState> {
viewBackgroundColor: this.state.viewBackgroundColor
});
save(this.state);
if (!skipHistory) {
pushHistoryEntry(generateHistoryCurrentEntry());
}
skipHistory = false;
}
}