142 lines
4.6 KiB
TypeScript
142 lines
4.6 KiB
TypeScript
import { diffChars } from "diff";
|
|
import { config } from "../../../package.json";
|
|
import { fileExists, formatPath, getItemDataURL } from "../../utils/str";
|
|
import { isWindowAlive } from "../../utils/window";
|
|
import { waitUtilAsync } from "../../utils/wait";
|
|
|
|
export async function showSyncDiff(noteId: number, mdPath: string) {
|
|
const noteItem = Zotero.Items.get(noteId);
|
|
const syncStatus = addon.api.sync.getSyncStatus(noteId);
|
|
const noteStatus = addon.api.sync.getNoteStatus(noteId)!;
|
|
mdPath = formatPath(mdPath);
|
|
if (!noteItem || !noteItem.isNote() || !(await fileExists(mdPath))) {
|
|
return;
|
|
}
|
|
const mdStatus = await addon.api.sync.getMDStatus(mdPath);
|
|
if (!mdStatus.meta) {
|
|
return;
|
|
}
|
|
const mdNoteContent = await addon.api.convert.md2note(mdStatus, noteItem, {
|
|
isImport: true,
|
|
});
|
|
const noteContent = await addon.api.convert.note2noteDiff(noteItem);
|
|
ztoolkit.log(mdNoteContent, noteContent);
|
|
const changes = diffChars(noteContent, mdNoteContent);
|
|
ztoolkit.log("changes", changes);
|
|
|
|
const io = {
|
|
defer: Zotero.Promise.defer(),
|
|
result: "",
|
|
type: "skip",
|
|
};
|
|
|
|
const syncDate = new Date(syncStatus.lastsync);
|
|
if (!(noteStatus.lastmodify > syncDate && mdStatus.lastmodify > syncDate)) {
|
|
// If only one kind of changes, merge automatically
|
|
if (noteStatus.lastmodify >= mdStatus.lastmodify) {
|
|
// refuse all, keep note
|
|
io.result = changes
|
|
.filter((diff) => (!diff.added && !diff.removed) || diff.removed)
|
|
.map((diff) => diff.value)
|
|
.join("");
|
|
} else {
|
|
// accept all, keep md
|
|
io.result = changes
|
|
.filter((diff) => (!diff.added && !diff.removed) || diff.added)
|
|
.map((diff) => diff.value)
|
|
.join("");
|
|
}
|
|
io.type = "finish";
|
|
} else {
|
|
// Otherwise, merge manually
|
|
const imageAttachemnts = Zotero.Items.get(noteItem.getAttachments()).filter(
|
|
(attch) => attch.isEmbeddedImageAttachment(),
|
|
);
|
|
const imageData = {} as Record<string, string>;
|
|
for (const image of imageAttachemnts) {
|
|
try {
|
|
const b64 = await getItemDataURL(image);
|
|
imageData[image.key] = b64;
|
|
} catch (e) {
|
|
ztoolkit.log(e);
|
|
}
|
|
}
|
|
|
|
if (!isWindowAlive(addon.data.sync.diff.window)) {
|
|
addon.data.sync.diff.window = window.open(
|
|
`chrome://${config.addonRef}/content/syncDiff.html`,
|
|
`${config.addonRef}-syncDiff`,
|
|
`chrome,centerscreen,resizable,status,width=900,height=550`,
|
|
)!;
|
|
await waitUtilAsync(
|
|
() => addon.data.sync.diff.window?.document.readyState === "complete",
|
|
);
|
|
}
|
|
const win = addon.data.sync.diff.window as any;
|
|
|
|
win.document.title = `[Better Notes Sycing] Diff Merge of ${noteItem.getNoteTitle()}`;
|
|
win.syncInfo = {
|
|
noteName: noteItem.getNoteTitle(),
|
|
noteModify: noteStatus.lastmodify && noteStatus.lastmodify.toISOString(),
|
|
mdName: mdPath,
|
|
mdModify: mdStatus.lastmodify && mdStatus.lastmodify.toISOString(),
|
|
syncTime: syncDate.toISOString(),
|
|
};
|
|
win.diffData = changes.map((change, id) =>
|
|
Object.assign(change, {
|
|
id: id,
|
|
text: change.value,
|
|
}),
|
|
);
|
|
win.imageData = imageData;
|
|
|
|
win.io = io;
|
|
win.initSyncInfo();
|
|
win.initList();
|
|
win.initDiffViewer();
|
|
win.updateDiffRender([]);
|
|
const abort = () => {
|
|
ztoolkit.log("unloaded");
|
|
io.defer.resolve();
|
|
};
|
|
// If closed by user, abort syncing
|
|
win.addEventListener("beforeunload", abort);
|
|
win.addEventListener("unload", abort);
|
|
win.addEventListener("close", abort);
|
|
win.onclose = abort;
|
|
win.onbeforeunload = abort;
|
|
win.onunload = abort;
|
|
await io.defer.promise;
|
|
win.removeEventListener("beforeunload", abort);
|
|
win.removeEventListener("unload", abort);
|
|
win.removeEventListener("close", abort);
|
|
}
|
|
|
|
switch (io.type) {
|
|
case "skip":
|
|
alert(
|
|
`Syncing of "${noteItem.getNoteTitle()}" is skipped.\nTo sync manually, go to File->Better Notes Sync Manager.`,
|
|
);
|
|
addon.data.sync.diff.window?.closed ||
|
|
addon.data.sync.diff.window?.close();
|
|
break;
|
|
case "unsync":
|
|
ztoolkit.log("remove sync", noteItem.getNote());
|
|
await addon.api.sync.removeSyncNote(noteItem.id);
|
|
break;
|
|
case "finish":
|
|
ztoolkit.log("Diff result:", io.result);
|
|
// return io.result;
|
|
noteItem.setNote(noteStatus.meta + io.result + noteStatus.tail);
|
|
await noteItem.saveTx({
|
|
notifierData: {
|
|
autoSyncDelay: Zotero.Notes.AUTO_SYNC_DELAY,
|
|
},
|
|
});
|
|
await addon.api.$export.syncMDBatch(mdStatus.filedir, [noteItem.id]);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|