blob: 5edc5ec13648cb4e2e72e9b9b53959b55d01de80 [file] [log] [blame]
(() => {
let initialized = false;
let globalNodeMap = new EditingHistory.GlobalNodeMap();
let topLevelUpdates = [];
let currentChildUpdates = [];
let isProcessingTopLevelUpdate = false;
let lastKnownSelectionState = null;
let mutationObserver = new MutationObserver(records => appendDOMUpdatesFromRecords(records));
function beginProcessingTopLevelUpdate() {
isProcessingTopLevelUpdate = true;
}
function endProcessingTopLevelUpdate(topLevelUpdate) {
topLevelUpdates.push(topLevelUpdate);
currentChildUpdates = [];
isProcessingTopLevelUpdate = false;
}
function appendDOMUpdatesFromRecords(records) {
if (!records.length)
return;
let newUpdates = EditingHistory.DOMUpdate.fromRecords(records, globalNodeMap);
if (isProcessingTopLevelUpdate)
currentChildUpdates = currentChildUpdates.concat(newUpdates);
else
topLevelUpdates = topLevelUpdates.concat(newUpdates);
}
function appendSelectionUpdateIfNecessary() {
let newSelectionState = EditingHistory.SelectionState.fromSelection(getSelection(), globalNodeMap);
if (newSelectionState.isEqual(lastKnownSelectionState))
return;
let update = new EditingHistory.SelectionUpdate(globalNodeMap, newSelectionState);
if (isProcessingTopLevelUpdate)
currentChildUpdates.push(update);
else
topLevelUpdates.push(update);
lastKnownSelectionState = newSelectionState;
}
document.body.setAttribute("contenteditable", true);
document.body.addEventListener("focus", () => {
if (initialized)
return;
initialized = true;
EditingHistory.getEditingHistoryAsJSONString = (formatted) => {
let record = {};
record.updates = topLevelUpdates.map(update => update.toObject());
record.globalNodeMap = globalNodeMap.toObject();
return formatted ? JSON.stringify(record, null, 4) : JSON.stringify(record);
};
document.addEventListener("selectionchange", () => {
appendSelectionUpdateIfNecessary();
});
document.addEventListener("beforeinput", event => {
appendDOMUpdatesFromRecords(mutationObserver.takeRecords());
beginProcessingTopLevelUpdate();
});
document.addEventListener("input", event => {
appendDOMUpdatesFromRecords(mutationObserver.takeRecords());
let eventData = event.dataTransfer ? event.dataTransfer.getData("text/html") : event.data;
lastKnownSelectionState = null;
endProcessingTopLevelUpdate(new EditingHistory.InputEventUpdate(globalNodeMap, currentChildUpdates, event.inputType, eventData, event.timeStamp));
});
document.addEventListener("keydown", event => {
if (event.key !== "s" || !event.metaKey)
return;
let fakeLink = document.createElement("a");
fakeLink.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(EditingHistory.getEditingHistoryAsJSONString()));
fakeLink.setAttribute("download", "record.json");
fakeLink.click();
event.preventDefault();
});
mutationObserver.observe(document, {
childList: true,
attributes: true,
characterData: true,
subtree: true,
attributeOldValue: true,
characterDataOldValue: true,
});
});
})();