mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-05-08 08:41:50 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab6ff01f1a | ||
|
|
c836953fa9 | ||
|
|
e69371ff24 | ||
|
|
d324add086 | ||
|
|
0caf330f39 | ||
|
|
3a147ca427 | ||
|
|
8266cfba40 | ||
|
|
d5a95d43dd | ||
|
|
7da930a8bb | ||
|
|
a632b79726 |
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "obsidian-livesync",
|
"id": "obsidian-livesync",
|
||||||
"name": "Self-hosted LiveSync",
|
"name": "Self-hosted LiveSync",
|
||||||
"version": "0.12.2",
|
"version": "0.12.3",
|
||||||
"minAppVersion": "0.9.12",
|
"minAppVersion": "0.9.12",
|
||||||
"description": "Community implementation of self-hosted livesync. Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.",
|
"description": "Community implementation of self-hosted livesync. Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.",
|
||||||
"author": "vorotamoroz",
|
"author": "vorotamoroz",
|
||||||
|
|||||||
64
package-lock.json
generated
64
package-lock.json
generated
@@ -1,19 +1,19 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.12.2",
|
"version": "0.12.3",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.12.2",
|
"version": "0.12.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"diff-match-patch": "^1.0.5",
|
"diff-match-patch": "^1.0.5",
|
||||||
"esbuild": "0.13.12",
|
"esbuild": "0.13.12",
|
||||||
"esbuild-svelte": "^0.6.0",
|
"esbuild-svelte": "^0.7.0",
|
||||||
"idb": "^7.0.1",
|
"idb": "^7.0.2",
|
||||||
"svelte-preprocess": "^4.10.2",
|
"svelte-preprocess": "^4.10.5",
|
||||||
"xxhash-wasm": "^0.4.2"
|
"xxhash-wasm": "^0.4.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -27,13 +27,13 @@
|
|||||||
"@typescript-eslint/parser": "^5.0.0",
|
"@typescript-eslint/parser": "^5.0.0",
|
||||||
"builtin-modules": "^3.2.0",
|
"builtin-modules": "^3.2.0",
|
||||||
"esbuild": "0.13.12",
|
"esbuild": "0.13.12",
|
||||||
"esbuild-svelte": "^0.6.0",
|
"esbuild-svelte": "^0.7.0",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-airbnb-base": "^14.2.1",
|
"eslint-config-airbnb-base": "^14.2.1",
|
||||||
"eslint-plugin-import": "^2.25.2",
|
"eslint-plugin-import": "^2.25.2",
|
||||||
"obsidian": "^0.15.4",
|
"obsidian": "^0.15.4",
|
||||||
"rollup": "^2.32.1",
|
"rollup": "^2.32.1",
|
||||||
"svelte-preprocess": "^4.10.2",
|
"svelte-preprocess": "^4.10.5",
|
||||||
"tslib": "^2.2.0",
|
"tslib": "^2.2.0",
|
||||||
"typescript": "^4.2.4"
|
"typescript": "^4.2.4"
|
||||||
}
|
}
|
||||||
@@ -1416,18 +1416,16 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/esbuild-svelte": {
|
"node_modules/esbuild-svelte": {
|
||||||
"version": "0.6.2",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild-svelte/-/esbuild-svelte-0.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild-svelte/-/esbuild-svelte-0.7.0.tgz",
|
||||||
"integrity": "sha512-FRHcyaQqIm4ncFsbk97b+80fHAI0VA15Ty56zOai9zpOPOQ1kgqWJt7JYn0jNGm+1VSvJNaGUj8QB85H/P43jA==",
|
"integrity": "sha512-hfiauhEXtGocUf7oVcxTrLhhF57ajBbvNCCClsS3KntEeITddKU+1WFhmsCt9SO0dQJlCFzJtpPu2dI7dRkXBw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
|
||||||
"svelte": "^3.46.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"esbuild": ">=0.9.6"
|
"esbuild": ">=0.9.6",
|
||||||
|
"svelte": ">=3.43.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/esbuild-windows-32": {
|
"node_modules/esbuild-windows-32": {
|
||||||
@@ -2109,9 +2107,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/idb": {
|
"node_modules/idb": {
|
||||||
"version": "7.0.1",
|
"version": "7.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/idb/-/idb-7.0.2.tgz",
|
||||||
"integrity": "sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg=="
|
"integrity": "sha512-jjKrT1EnyZewQ/gCBb/eyiYrhGzws2FeY92Yx8qT9S9GeQAmo4JFVIiWRIfKW/6Ob9A+UDAOW9j9jn58fy2HIg=="
|
||||||
},
|
},
|
||||||
"node_modules/ignore": {
|
"node_modules/ignore": {
|
||||||
"version": "5.1.9",
|
"version": "5.1.9",
|
||||||
@@ -3189,14 +3187,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.46.4.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.46.4.tgz",
|
||||||
"integrity": "sha512-qKJzw6DpA33CIa+C/rGp4AUdSfii0DOTCzj/2YpSKKayw5WGSS624Et9L1nU1k2OVRS9vaENQXp2CVZNU+xvIg==",
|
"integrity": "sha512-qKJzw6DpA33CIa+C/rGp4AUdSfii0DOTCzj/2YpSKKayw5WGSS624Et9L1nU1k2OVRS9vaENQXp2CVZNU+xvIg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/svelte-preprocess": {
|
"node_modules/svelte-preprocess": {
|
||||||
"version": "4.10.3",
|
"version": "4.10.5",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.3.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.5.tgz",
|
||||||
"integrity": "sha512-ttw17lJfb/dx2ZJT9sesaXT5l7mPQ9Apx1H496Kli3Hkk7orIRGpOw6rCPkRNzr6ueVPqb4vzodS5x7sBFhKHw==",
|
"integrity": "sha512-VKXPRScCzAZqeBZOGq4LLwtNrAu++mVn7XvQox3eFDV7Ciq0Lg70Q8QWjH9iXF7J+pMlXhPsSFwpCb2E+hoeyA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -4526,13 +4525,11 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"esbuild-svelte": {
|
"esbuild-svelte": {
|
||||||
"version": "0.6.2",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild-svelte/-/esbuild-svelte-0.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild-svelte/-/esbuild-svelte-0.7.0.tgz",
|
||||||
"integrity": "sha512-FRHcyaQqIm4ncFsbk97b+80fHAI0VA15Ty56zOai9zpOPOQ1kgqWJt7JYn0jNGm+1VSvJNaGUj8QB85H/P43jA==",
|
"integrity": "sha512-hfiauhEXtGocUf7oVcxTrLhhF57ajBbvNCCClsS3KntEeITddKU+1WFhmsCt9SO0dQJlCFzJtpPu2dI7dRkXBw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {}
|
||||||
"svelte": "^3.46.2"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"esbuild-windows-32": {
|
"esbuild-windows-32": {
|
||||||
"version": "0.13.12",
|
"version": "0.13.12",
|
||||||
@@ -5052,9 +5049,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"idb": {
|
"idb": {
|
||||||
"version": "7.0.1",
|
"version": "7.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/idb/-/idb-7.0.2.tgz",
|
||||||
"integrity": "sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg=="
|
"integrity": "sha512-jjKrT1EnyZewQ/gCBb/eyiYrhGzws2FeY92Yx8qT9S9GeQAmo4JFVIiWRIfKW/6Ob9A+UDAOW9j9jn58fy2HIg=="
|
||||||
},
|
},
|
||||||
"ignore": {
|
"ignore": {
|
||||||
"version": "5.1.9",
|
"version": "5.1.9",
|
||||||
@@ -5827,12 +5824,13 @@
|
|||||||
"version": "3.46.4",
|
"version": "3.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.46.4.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.46.4.tgz",
|
||||||
"integrity": "sha512-qKJzw6DpA33CIa+C/rGp4AUdSfii0DOTCzj/2YpSKKayw5WGSS624Et9L1nU1k2OVRS9vaENQXp2CVZNU+xvIg==",
|
"integrity": "sha512-qKJzw6DpA33CIa+C/rGp4AUdSfii0DOTCzj/2YpSKKayw5WGSS624Et9L1nU1k2OVRS9vaENQXp2CVZNU+xvIg==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"svelte-preprocess": {
|
"svelte-preprocess": {
|
||||||
"version": "4.10.3",
|
"version": "4.10.5",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.3.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.5.tgz",
|
||||||
"integrity": "sha512-ttw17lJfb/dx2ZJT9sesaXT5l7mPQ9Apx1H496Kli3Hkk7orIRGpOw6rCPkRNzr6ueVPqb4vzodS5x7sBFhKHw==",
|
"integrity": "sha512-VKXPRScCzAZqeBZOGq4LLwtNrAu++mVn7XvQox3eFDV7Ciq0Lg70Q8QWjH9iXF7J+pMlXhPsSFwpCb2E+hoeyA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/pug": "^2.0.4",
|
"@types/pug": "^2.0.4",
|
||||||
|
|||||||
12
package.json
12
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.12.2",
|
"version": "0.12.3",
|
||||||
"description": "Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.",
|
"description": "Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -23,22 +23,22 @@
|
|||||||
"@typescript-eslint/parser": "^5.0.0",
|
"@typescript-eslint/parser": "^5.0.0",
|
||||||
"builtin-modules": "^3.2.0",
|
"builtin-modules": "^3.2.0",
|
||||||
"esbuild": "0.13.12",
|
"esbuild": "0.13.12",
|
||||||
"esbuild-svelte": "^0.6.0",
|
"esbuild-svelte": "^0.7.0",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-airbnb-base": "^14.2.1",
|
"eslint-config-airbnb-base": "^14.2.1",
|
||||||
"eslint-plugin-import": "^2.25.2",
|
"eslint-plugin-import": "^2.25.2",
|
||||||
"obsidian": "^0.15.4",
|
"obsidian": "^0.15.4",
|
||||||
"rollup": "^2.32.1",
|
"rollup": "^2.32.1",
|
||||||
"svelte-preprocess": "^4.10.2",
|
"svelte-preprocess": "^4.10.5",
|
||||||
"tslib": "^2.2.0",
|
"tslib": "^2.2.0",
|
||||||
"typescript": "^4.2.4"
|
"typescript": "^4.2.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"diff-match-patch": "^1.0.5",
|
"diff-match-patch": "^1.0.5",
|
||||||
"esbuild": "0.13.12",
|
"esbuild": "0.13.12",
|
||||||
"esbuild-svelte": "^0.6.0",
|
"esbuild-svelte": "^0.7.0",
|
||||||
"idb": "^7.0.1",
|
"svelte-preprocess": "^4.10.5",
|
||||||
"svelte-preprocess": "^4.10.2",
|
"idb": "^7.0.2",
|
||||||
"xxhash-wasm": "^0.4.2"
|
"xxhash-wasm": "^0.4.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { TFile, Modal, App } from "obsidian";
|
import { TFile, Modal, App } from "obsidian";
|
||||||
import { path2id } from "./utils";
|
import { path2id } from "./utils";
|
||||||
import { escapeStringToHTML } from "./lib/src/utils";
|
import { base64ToArrayBuffer, base64ToString, escapeStringToHTML, isValidPath } from "./lib/src/utils";
|
||||||
import ObsidianLiveSyncPlugin from "./main";
|
import ObsidianLiveSyncPlugin from "./main";
|
||||||
import { DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "diff-match-patch";
|
import { DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "diff-match-patch";
|
||||||
import { LOG_LEVEL } from "./lib/src/types";
|
import { LoadedEntry, LOG_LEVEL } from "./lib/src/types";
|
||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
|
|
||||||
export class DocumentHistoryModal extends Modal {
|
export class DocumentHistoryModal extends Modal {
|
||||||
@@ -17,12 +17,13 @@ export class DocumentHistoryModal extends Modal {
|
|||||||
file: string;
|
file: string;
|
||||||
|
|
||||||
revs_info: PouchDB.Core.RevisionInfo[] = [];
|
revs_info: PouchDB.Core.RevisionInfo[] = [];
|
||||||
|
currentDoc: LoadedEntry;
|
||||||
currentText = "";
|
currentText = "";
|
||||||
|
|
||||||
constructor(app: App, plugin: ObsidianLiveSyncPlugin, file: TFile) {
|
constructor(app: App, plugin: ObsidianLiveSyncPlugin, file: TFile | string) {
|
||||||
super(app);
|
super(app);
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.file = file.path;
|
this.file = (file instanceof TFile) ? file.path : file;
|
||||||
if (localStorage.getItem("ols-history-highlightdiff") == "1") {
|
if (localStorage.getItem("ols-history-highlightdiff") == "1") {
|
||||||
this.showDiff = true;
|
this.showDiff = true;
|
||||||
}
|
}
|
||||||
@@ -47,9 +48,12 @@ export class DocumentHistoryModal extends Modal {
|
|||||||
this.info.innerHTML = "";
|
this.info.innerHTML = "";
|
||||||
this.contentView.innerHTML = `Could not read this revision<br>(${rev.rev})`;
|
this.contentView.innerHTML = `Could not read this revision<br>(${rev.rev})`;
|
||||||
} else {
|
} else {
|
||||||
|
this.currentDoc = w;
|
||||||
this.info.innerHTML = `Modified:${new Date(w.mtime).toLocaleString()}`;
|
this.info.innerHTML = `Modified:${new Date(w.mtime).toLocaleString()}`;
|
||||||
let result = "";
|
let result = "";
|
||||||
this.currentText = w.data;
|
const w1data = w.datatype == "plain" ? w.data : base64ToString(w.data);
|
||||||
|
|
||||||
|
this.currentText = w1data;
|
||||||
if (this.showDiff) {
|
if (this.showDiff) {
|
||||||
const prevRevIdx = this.revs_info.length - 1 - ((this.range.value as any) / 1 - 1);
|
const prevRevIdx = this.revs_info.length - 1 - ((this.range.value as any) / 1 - 1);
|
||||||
if (prevRevIdx >= 0 && prevRevIdx < this.revs_info.length) {
|
if (prevRevIdx >= 0 && prevRevIdx < this.revs_info.length) {
|
||||||
@@ -57,7 +61,8 @@ export class DocumentHistoryModal extends Modal {
|
|||||||
const w2 = await db.getDBEntry(path2id(this.file), { rev: oldRev }, false, false);
|
const w2 = await db.getDBEntry(path2id(this.file), { rev: oldRev }, false, false);
|
||||||
if (w2 != false) {
|
if (w2 != false) {
|
||||||
const dmp = new diff_match_patch();
|
const dmp = new diff_match_patch();
|
||||||
const diff = dmp.diff_main(w2.data, w.data);
|
const w2data = w2.datatype == "plain" ? w2.data : base64ToString(w2.data);
|
||||||
|
const diff = dmp.diff_main(w2data, w1data);
|
||||||
dmp.diff_cleanupSemantic(diff);
|
dmp.diff_cleanupSemantic(diff);
|
||||||
for (const v of diff) {
|
for (const v of diff) {
|
||||||
const x1 = v[0];
|
const x1 = v[0];
|
||||||
@@ -73,13 +78,13 @@ export class DocumentHistoryModal extends Modal {
|
|||||||
|
|
||||||
result = result.replace(/\n/g, "<br>");
|
result = result.replace(/\n/g, "<br>");
|
||||||
} else {
|
} else {
|
||||||
result = escapeStringToHTML(w.data);
|
result = escapeStringToHTML(w1data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = escapeStringToHTML(w.data);
|
result = escapeStringToHTML(w1data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = escapeStringToHTML(w.data);
|
result = escapeStringToHTML(w1data);
|
||||||
}
|
}
|
||||||
this.contentView.innerHTML = result;
|
this.contentView.innerHTML = result;
|
||||||
}
|
}
|
||||||
@@ -138,6 +143,25 @@ export class DocumentHistoryModal extends Modal {
|
|||||||
Logger(`Old content copied to clipboard`, LOG_LEVEL.NOTICE);
|
Logger(`Old content copied to clipboard`, LOG_LEVEL.NOTICE);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
buttons.createEl("button", { text: "Back to this revision" }, (e) => {
|
||||||
|
e.addClass("mod-cta");
|
||||||
|
e.addEventListener("click", async () => {
|
||||||
|
const pathToWrite = this.file.startsWith("i:") ? this.file.substring("i:".length) : this.file;
|
||||||
|
if (!isValidPath(pathToWrite)) {
|
||||||
|
Logger("Path is not vaild to write content.", LOG_LEVEL.INFO);
|
||||||
|
}
|
||||||
|
if (this.currentDoc?.datatype == "plain") {
|
||||||
|
await this.app.vault.adapter.write(pathToWrite, this.currentDoc.data);
|
||||||
|
this.close();
|
||||||
|
} else if (this.currentDoc?.datatype == "newnote") {
|
||||||
|
await this.app.vault.adapter.writeBinary(pathToWrite, base64ToArrayBuffer(this.currentDoc.data));
|
||||||
|
this.close();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Logger(`Could not parse entry`, LOG_LEVEL.NOTICE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
onClose() {
|
onClose() {
|
||||||
const { contentEl } = this;
|
const { contentEl } = this;
|
||||||
|
|||||||
87
src/main.ts
87
src/main.ts
@@ -29,12 +29,14 @@ import { DocumentHistoryModal } from "./DocumentHistoryModal";
|
|||||||
|
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
import PluginPane from "./PluginPane.svelte";
|
import PluginPane from "./PluginPane.svelte";
|
||||||
|
|
||||||
import { clearAllPeriodic, clearAllTriggers, disposeMemoObject, id2path, memoIfNotExist, memoObject, path2id, retriveMemoObject, setTrigger } from "./utils";
|
import { clearAllPeriodic, clearAllTriggers, disposeMemoObject, id2path, memoIfNotExist, memoObject, path2id, retriveMemoObject, setTrigger } from "./utils";
|
||||||
import { decrypt, encrypt } from "./lib/src/e2ee_v2";
|
import { decrypt, encrypt } from "./lib/src/e2ee_v2";
|
||||||
|
|
||||||
const isDebug = false;
|
const isDebug = false;
|
||||||
|
|
||||||
setNoticeClass(Notice);
|
setNoticeClass(Notice);
|
||||||
|
|
||||||
class PluginDialogModal extends Modal {
|
class PluginDialogModal extends Modal {
|
||||||
plugin: ObsidianLiveSyncPlugin;
|
plugin: ObsidianLiveSyncPlugin;
|
||||||
logEl: HTMLDivElement;
|
logEl: HTMLDivElement;
|
||||||
@@ -118,19 +120,24 @@ class InputStringDialog extends Modal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class PopoverYesNo extends FuzzySuggestModal<string> {
|
class PopoverSelectString extends FuzzySuggestModal<string> {
|
||||||
app: App;
|
app: App;
|
||||||
callback: (e: string) => void = () => { };
|
callback: (e: string) => void = () => { };
|
||||||
|
getItemsFun: () => string[] = () => {
|
||||||
|
return ["yes", "no"];
|
||||||
|
|
||||||
constructor(app: App, note: string, callback: (e: string) => void) {
|
}
|
||||||
|
|
||||||
|
constructor(app: App, note: string, placeholder: string | null, getItemsFun: () => string[], callback: (e: string) => void) {
|
||||||
super(app);
|
super(app);
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.setPlaceholder("y/n) " + note);
|
this.setPlaceholder(placeholder ?? "y/n) " + note);
|
||||||
|
if (getItemsFun) this.getItemsFun = getItemsFun;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
getItems(): string[] {
|
getItems(): string[] {
|
||||||
return ["yes", "no"];
|
return this.getItemsFun();
|
||||||
}
|
}
|
||||||
|
|
||||||
getItemText(item: string): string {
|
getItemText(item: string): string {
|
||||||
@@ -153,11 +160,20 @@ class PopoverYesNo extends FuzzySuggestModal<string> {
|
|||||||
|
|
||||||
const askYesNo = (app: App, message: string): Promise<"yes" | "no"> => {
|
const askYesNo = (app: App, message: string): Promise<"yes" | "no"> => {
|
||||||
return new Promise((res) => {
|
return new Promise((res) => {
|
||||||
const popover = new PopoverYesNo(app, message, (result) => res(result as "yes" | "no"));
|
const popover = new PopoverSelectString(app, message, null, null, (result) => res(result as "yes" | "no"));
|
||||||
popover.open();
|
popover.open();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const askSelectString = (app: App, message: string, items: string[]): Promise<string> => {
|
||||||
|
const getItemsFun = () => items;
|
||||||
|
return new Promise((res) => {
|
||||||
|
const popover = new PopoverSelectString(app, message, "Select file)", getItemsFun, (result) => res(result));
|
||||||
|
popover.open();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const askString = (app: App, title: string, key: string, placeholder: string): Promise<string | false> => {
|
const askString = (app: App, title: string, key: string, placeholder: string): Promise<string | false> => {
|
||||||
return new Promise((res) => {
|
return new Promise((res) => {
|
||||||
const dialog = new InputStringDialog(app, title, key, placeholder, (result) => res(result));
|
const dialog = new InputStringDialog(app, title, key, placeholder, (result) => res(result));
|
||||||
@@ -207,7 +223,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
showHistory(file: TFile) {
|
showHistory(file: TFile | string) {
|
||||||
if (!this.settings.useHistory) {
|
if (!this.settings.useHistory) {
|
||||||
Logger("You have to enable Use History in misc.", LOG_LEVEL.NOTICE);
|
Logger("You have to enable Use History in misc.", LOG_LEVEL.NOTICE);
|
||||||
} else {
|
} else {
|
||||||
@@ -215,6 +231,29 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fileHistory() {
|
||||||
|
const pageLimit = 2500;
|
||||||
|
let nextKey = "";
|
||||||
|
const notes = [];
|
||||||
|
do {
|
||||||
|
const docs = await this.localDatabase.localDatabase.allDocs({ limit: pageLimit, startkey: nextKey, include_docs: true });
|
||||||
|
nextKey = "";
|
||||||
|
for (const row of docs.rows) {
|
||||||
|
const doc = row.doc;
|
||||||
|
nextKey = `${row.id}\u{10ffff}`;
|
||||||
|
if (!("type" in doc)) continue;
|
||||||
|
if (doc.type == "newnote" || doc.type == "plain") {
|
||||||
|
// const docId = doc._id.startsWith("i:") ? doc._id.substring("i:".length) : doc._id;
|
||||||
|
notes.push(id2path(doc._id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (nextKey != "");
|
||||||
|
const target = await askSelectString(this.app, "File to view History", notes);
|
||||||
|
if (target) {
|
||||||
|
this.showHistory(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async onload() {
|
async onload() {
|
||||||
setLogger(this.addLog.bind(this)); // Logger moved to global.
|
setLogger(this.addLog.bind(this)); // Logger moved to global.
|
||||||
Logger("loading plugin");
|
Logger("loading plugin");
|
||||||
@@ -499,6 +538,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
this.showHistory(view.file);
|
this.showHistory(view.file);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.triggerRealizeSettingSyncMode = debounce(this.triggerRealizeSettingSyncMode.bind(this), 1000);
|
this.triggerRealizeSettingSyncMode = debounce(this.triggerRealizeSettingSyncMode.bind(this), 1000);
|
||||||
this.triggerCheckPluginUpdate = debounce(this.triggerCheckPluginUpdate.bind(this), 3000);
|
this.triggerCheckPluginUpdate = debounce(this.triggerCheckPluginUpdate.bind(this), 3000);
|
||||||
setLockNotifier(() => {
|
setLockNotifier(() => {
|
||||||
@@ -519,6 +559,14 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
this.syncInternalFilesAndDatabase("safe", true);
|
this.syncInternalFilesAndDatabase("safe", true);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
this.addCommand({
|
||||||
|
id: "livesync-filehistory",
|
||||||
|
name: "Pick file to show history",
|
||||||
|
callback: () => {
|
||||||
|
this.fileHistory();
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pluginDialog: PluginDialogModal = null;
|
pluginDialog: PluginDialogModal = null;
|
||||||
@@ -1511,7 +1559,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
Logger("Updating database by new files");
|
Logger("Updating database by new files");
|
||||||
this.setStatusBarText(`UPDATE DATABASE`);
|
this.setStatusBarText(`UPDATE DATABASE`);
|
||||||
|
|
||||||
const runAll = async <T>(procedurename: string, objects: T[], callback: (arg: T) => Promise<void>) => {
|
const runAll = async<T>(procedurename: string, objects: T[], callback: (arg: T) => Promise<void>) => {
|
||||||
const count = objects.length;
|
const count = objects.length;
|
||||||
Logger(procedurename);
|
Logger(procedurename);
|
||||||
let i = 0;
|
let i = 0;
|
||||||
@@ -1547,6 +1595,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
await p.all();
|
await p.all();
|
||||||
Logger(`${procedurename} done.`);
|
Logger(`${procedurename} done.`);
|
||||||
};
|
};
|
||||||
|
|
||||||
await runAll("UPDATE DATABASE", onlyInStorage, async (e) => {
|
await runAll("UPDATE DATABASE", onlyInStorage, async (e) => {
|
||||||
Logger(`Update into ${e.path}`);
|
Logger(`Update into ${e.path}`);
|
||||||
|
|
||||||
@@ -1575,7 +1624,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.setStatusBarText(`NOW TRACKING!`);
|
this.setStatusBarText(`NOW TRACKING!`);
|
||||||
Logger("Initialized,NOW TRACKING!");
|
Logger("Initialized, NOW TRACKING!");
|
||||||
if (!isInitialized) {
|
if (!isInitialized) {
|
||||||
await (this.localDatabase.kvDB.set("initialized", true))
|
await (this.localDatabase.kvDB.set("initialized", true))
|
||||||
}
|
}
|
||||||
@@ -2157,30 +2206,39 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
async getFiles(
|
async getFiles(
|
||||||
path: string,
|
path: string,
|
||||||
ignoreList: string[],
|
ignoreList: string[],
|
||||||
filter: RegExp[]
|
filter: RegExp[],
|
||||||
|
ignoreFilter: RegExp[],
|
||||||
) {
|
) {
|
||||||
|
|
||||||
const w = await this.app.vault.adapter.list(path);
|
const w = await this.app.vault.adapter.list(path);
|
||||||
let files = [
|
let files = [
|
||||||
...w.files
|
...w.files
|
||||||
.filter((e) => !ignoreList.some((ee) => e.endsWith(ee)))
|
.filter((e) => !ignoreList.some((ee) => e.endsWith(ee)))
|
||||||
.filter((e) => !filter || filter.some((ee) => e.match(ee))),
|
.filter((e) => !filter || filter.some((ee) => e.match(ee)))
|
||||||
|
.filter((e) => !ignoreFilter || ignoreFilter.every((ee) => !e.match(ee))),
|
||||||
];
|
];
|
||||||
|
|
||||||
L1: for (const v of w.folders) {
|
L1: for (const v of w.folders) {
|
||||||
for (const ignore of ignoreList) {
|
for (const ignore of ignoreList) {
|
||||||
if (v.endsWith(ignore)) {
|
if (v.endsWith(ignore)) {
|
||||||
continue L1;
|
continue L1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
files = files.concat(await this.getFiles(v, ignoreList, filter));
|
if (ignoreFilter && ignoreFilter.some(e => v.match(e))) {
|
||||||
|
continue L1;
|
||||||
|
}
|
||||||
|
files = files.concat(await this.getFiles(v, ignoreList, filter, ignoreFilter));
|
||||||
}
|
}
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
async scanInternalFiles(): Promise<InternalFileInfo[]> {
|
async scanInternalFiles(): Promise<InternalFileInfo[]> {
|
||||||
const ignoreFiles = ["node_modules", ".git", "obsidian-pouch"];
|
const ignoreFilter = this.settings.syncInternalFilesIgnorePatterns.toLocaleLowerCase()
|
||||||
|
.replace(/\n| /g, "")
|
||||||
|
.split(",").filter(e => e).map(e => new RegExp(e));
|
||||||
const root = this.app.vault.getRoot();
|
const root = this.app.vault.getRoot();
|
||||||
const findRoot = root.path;
|
const findRoot = root.path;
|
||||||
const filenames = (await this.getFiles(findRoot, ignoreFiles, null)).filter(e => e.startsWith(".")).filter(e => !e.startsWith(".trash"));
|
const filenames = (await this.getFiles(findRoot, [], null, ignoreFilter)).filter(e => e.startsWith(".")).filter(e => !e.startsWith(".trash"));
|
||||||
const files = filenames.map(async e => {
|
const files = filenames.map(async e => {
|
||||||
return {
|
return {
|
||||||
path: e,
|
path: e,
|
||||||
@@ -2344,10 +2402,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
const ignorePatterns = this.settings.syncInternalFilesIgnorePatterns.toLocaleLowerCase()
|
const ignorePatterns = this.settings.syncInternalFilesIgnorePatterns.toLocaleLowerCase()
|
||||||
.replace(/\n| /g, "")
|
.replace(/\n| /g, "")
|
||||||
.split(",").filter(e => e).map(e => new RegExp(e));
|
.split(",").filter(e => e).map(e => new RegExp(e));
|
||||||
// const files = await this.scanInternalFiles();
|
|
||||||
return files.filter(file => !ignorePatterns.some(e => file.path.match(e))).filter(file => !targetFiles || (targetFiles && targetFiles.indexOf(file.path) !== -1))
|
return files.filter(file => !ignorePatterns.some(e => file.path.match(e))).filter(file => !targetFiles || (targetFiles && targetFiles.indexOf(file.path) !== -1))
|
||||||
//if (ignorePatterns.some(e => filename.match(e))) continue;
|
|
||||||
//if (targetFiles !== false && targetFiles.indexOf(filename) == -1) continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async applyMTimeToFile(file: InternalFileInfo) {
|
async applyMTimeToFile(file: InternalFileInfo) {
|
||||||
|
|||||||
Reference in New Issue
Block a user