Move from file IDs to file paths (with retrocompatibility)
This commit is contained in:
parent
56cf62f1eb
commit
a2503d5def
7 changed files with 62 additions and 49 deletions
|
@ -1,15 +1,15 @@
|
||||||
function copyEditLink(fileID) {
|
function copyEditLink(path) {
|
||||||
navigator.clipboard.writeText(getEditLink(fileID));
|
navigator.clipboard.writeText(getEditLink(path));
|
||||||
}
|
}
|
||||||
function copyImageLink(fileID) {
|
function copyImageLink(path) {
|
||||||
navigator.clipboard.writeText(``);
|
navigator.clipboard.writeText(`})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshPage() {
|
function refreshPage() {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
function addButton(document, fileID) {
|
function addButton(document, path) {
|
||||||
|
|
||||||
// Add floating button
|
// Add floating button
|
||||||
const floatingButton = document.createElement('button');
|
const floatingButton = document.createElement('button');
|
||||||
|
@ -22,8 +22,8 @@ function addButton(document, fileID) {
|
||||||
popupMenu.id = 'popupMenu';
|
popupMenu.id = 'popupMenu';
|
||||||
popupMenu.innerHTML = `
|
popupMenu.innerHTML = `
|
||||||
<button onclick="refreshPage()">Refresh</button>
|
<button onclick="refreshPage()">Refresh</button>
|
||||||
<button onclick="copyEditLink('${fileID}')">Copy Direct Edit Link</button>
|
<button onclick="copyEditLink('${path}')">Copy Direct Edit Link</button>
|
||||||
<button onclick="copyImageLink('${fileID}')">Copy Image Link</button>
|
<button onclick="copyImageLink('${path}')">Copy Image Link</button>
|
||||||
`;
|
`;
|
||||||
document.body.appendChild(popupMenu);
|
document.body.appendChild(popupMenu);
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,9 @@ async function getFile(path) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getSVG(fileID) {
|
async function getSVG(path) {
|
||||||
|
|
||||||
const resp = await getFile("/data/assets/" + fileID + '.svg');
|
const resp = await getFile(path);
|
||||||
if(resp == null) {
|
if(resp == null) {
|
||||||
return FALLBACK;
|
return FALLBACK;
|
||||||
}
|
}
|
||||||
|
@ -37,10 +37,10 @@ async function getSVG(fileID) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEditLink(fileID) {
|
function getEditLink(path) {
|
||||||
const data = encodeURIComponent(
|
const data = encodeURIComponent(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
id: fileID
|
path: path,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
return `siyuan://plugins/siyuan-jsdraw-pluginwhiteboard/?icon=iconDraw&title=Drawing&data=${data}`;
|
return `siyuan://plugins/siyuan-jsdraw-pluginwhiteboard/?icon=iconDraw&title=Drawing&data=${data}`;
|
||||||
|
|
|
@ -5,18 +5,22 @@
|
||||||
<script src="button.js"></script>
|
<script src="button.js"></script>
|
||||||
<script>
|
<script>
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
const fileID = urlParams.get('id');
|
let path = urlParams.get('path');
|
||||||
|
if(path === null) {
|
||||||
|
const fileID = urlParams.get('id'); // legacy support
|
||||||
|
path = "/data/assets/" + fileID + ".svg";
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', async () => {
|
document.addEventListener('DOMContentLoaded', async () => {
|
||||||
const editLink = document.createElement('a');
|
const editLink = document.createElement('a');
|
||||||
editLink.href = getEditLink(fileID);
|
editLink.href = getEditLink(path);
|
||||||
document.body.appendChild(editLink);
|
document.body.appendChild(editLink);
|
||||||
|
|
||||||
const htmlContainer = document.createElement('div');
|
const htmlContainer = document.createElement('div');
|
||||||
htmlContainer.innerHTML = await getSVG(fileID);
|
htmlContainer.innerHTML = await getSVG(path);
|
||||||
editLink.appendChild(htmlContainer);
|
editLink.appendChild(htmlContainer);
|
||||||
|
|
||||||
addButton(document, fileID);
|
addButton(document, path);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<link rel="stylesheet" href="index.css">
|
<link rel="stylesheet" href="index.css">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export const SVG_MIME = "image/svg+xml";
|
export const SVG_MIME = "image/svg+xml";
|
||||||
export const JSON_MIME = "application/json";
|
export const JSON_MIME = "application/json";
|
||||||
export const DATA_PATH = "/data/assets";
|
export const DATA_PATH = "/data/assets/";
|
||||||
export const STORAGE_PATH = "/data/storage/petal/siyuan-jsdraw-plugin";
|
export const STORAGE_PATH = "/data/storage/petal/siyuan-jsdraw-plugin";
|
||||||
export const TOOLBAR_PATH = STORAGE_PATH + "/toolbar.json";
|
export const TOOLBAR_PATH = STORAGE_PATH + "/toolbar.json";
|
||||||
export const CONFIG_PATH = STORAGE_PATH + "/conf.json";
|
export const CONFIG_PATH = STORAGE_PATH + "/conf.json";
|
||||||
export const EMBED_PATH = "/plugins/siyuan-jsdraw-plugin/webapp/?id=";
|
export const EMBED_PATH = "/plugins/siyuan-jsdraw-plugin/webapp/?path=";
|
|
@ -6,22 +6,22 @@ import {getFile, saveFile} from "@/file";
|
||||||
import {JSON_MIME, SVG_MIME, TOOLBAR_PATH} from "@/const";
|
import {JSON_MIME, SVG_MIME, TOOLBAR_PATH} from "@/const";
|
||||||
import {idToPath} from "@/helper";
|
import {idToPath} from "@/helper";
|
||||||
|
|
||||||
export function openEditorTab(p: Plugin, fileID: string) {
|
export function openEditorTab(p: Plugin, path: string) {
|
||||||
openTab({
|
openTab({
|
||||||
app: p.app,
|
app: p.app,
|
||||||
custom: {
|
custom: {
|
||||||
title: 'Drawing',
|
title: 'Drawing',
|
||||||
icon: 'iconDraw',
|
icon: 'iconDraw',
|
||||||
id: "siyuan-jsdraw-pluginwhiteboard",
|
id: "siyuan-jsdraw-pluginwhiteboard",
|
||||||
data: { id: fileID }
|
data: { path: path }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveCallback(editor: Editor, fileID: string, saveButton: BaseWidget) {
|
async function saveCallback(editor: Editor, path: string, saveButton: BaseWidget) {
|
||||||
const svgElem = editor.toSVG();
|
const svgElem = editor.toSVG();
|
||||||
try {
|
try {
|
||||||
saveFile(idToPath(fileID), SVG_MIME, svgElem.outerHTML);
|
saveFile(path, SVG_MIME, svgElem.outerHTML);
|
||||||
saveButton.setDisabled(true);
|
saveButton.setDisabled(true);
|
||||||
setTimeout(() => { // @todo improve save button feedback
|
setTimeout(() => { // @todo improve save button feedback
|
||||||
saveButton.setDisabled(false);
|
saveButton.setDisabled(false);
|
||||||
|
@ -36,10 +36,14 @@ async function saveCallback(editor: Editor, fileID: string, saveButton: BaseWidg
|
||||||
|
|
||||||
export function createEditor(i: ITabModel) {
|
export function createEditor(i: ITabModel) {
|
||||||
|
|
||||||
const fileID = i.data.id;
|
let path = i.data.path;
|
||||||
if(fileID == null) {
|
if(path == null) {
|
||||||
alert("File ID missing - couldn't open file.")
|
const fileID = i.data.id; // legacy compatibility
|
||||||
return;
|
if (fileID == null) {
|
||||||
|
alert("File ID and path missing - couldn't open file.")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
path = idToPath(fileID);
|
||||||
}
|
}
|
||||||
|
|
||||||
const editor = new Editor(i.element, {
|
const editor = new Editor(i.element, {
|
||||||
|
@ -55,14 +59,14 @@ export function createEditor(i: ITabModel) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// restore drawing
|
// restore drawing
|
||||||
getFile(idToPath(fileID)).then(svg => {
|
getFile(path).then(svg => {
|
||||||
if(svg != null) {
|
if(svg != null) {
|
||||||
editor.loadFromSVG(svg);
|
editor.loadFromSVG(svg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// save logic
|
// save logic
|
||||||
const saveButton = toolbar.addSaveButton(() => saveCallback(editor, fileID, saveButton));
|
const saveButton = toolbar.addSaveButton(() => saveCallback(editor, path, saveButton));
|
||||||
|
|
||||||
// save toolbar config on tool change (toolbar state is not saved in SVGs!)
|
// save toolbar config on tool change (toolbar state is not saved in SVGs!)
|
||||||
editor.notifier.on(EditorEventType.ToolUpdated, () => {
|
editor.notifier.on(EditorEventType.ToolUpdated, () => {
|
||||||
|
|
|
@ -45,14 +45,14 @@ export function generateSiyuanId() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function idToPath(id: string) {
|
export function idToPath(id: string) {
|
||||||
return DATA_PATH + '/' + id + '.svg';
|
return DATA_PATH + id + '.svg';
|
||||||
}
|
}
|
||||||
|
|
||||||
// [Edit](siyuan://plugins/siyuan-jsdraw-pluginwhiteboard/?icon=iconDraw&title=Drawing&data={"id":"${id}"})
|
// [Edit](siyuan://plugins/siyuan-jsdraw-pluginwhiteboard/?icon=iconDraw&title=Drawing&data={"id":"${id}"})
|
||||||
// 
|
// 
|
||||||
export function getPreviewHTML(id: string): string {
|
export function getPreviewHTML(path: string): string {
|
||||||
return `
|
return `
|
||||||
<iframe src="${EMBED_PATH + id}&antiCache=0"></iframe>
|
<iframe src="${EMBED_PATH + path}&antiCache=0"></iframe>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,12 +60,7 @@ export function getPreviewHTML(id: string): string {
|
||||||
export function findImgSrc(element: HTMLElement): string | null {
|
export function findImgSrc(element: HTMLElement): string | null {
|
||||||
// Base case: if current element is an image
|
// Base case: if current element is an image
|
||||||
if (element.tagName === 'IMG') {
|
if (element.tagName === 'IMG') {
|
||||||
const fullSrc = (element as HTMLImageElement).src;
|
return (element as HTMLImageElement).src;
|
||||||
// Extract the path after host:port using URL API
|
|
||||||
const url = new URL(fullSrc);
|
|
||||||
return url.pathname.startsWith('/assets/')
|
|
||||||
? url.pathname.substring(1) // Remove leading slash
|
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursively check children
|
// Recursively check children
|
||||||
|
@ -79,12 +74,15 @@ export function findImgSrc(element: HTMLElement): string | null {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractFileID(imgSrc: string | null): string | null {
|
export function imgSrcToAbsolutePath(imgSrc: string | null): string | null {
|
||||||
if (!imgSrc) return null;
|
if (!imgSrc) return null;
|
||||||
|
|
||||||
const [pathPart] = imgSrc.split('?');
|
const url = new URL(imgSrc);
|
||||||
// Match pattern: assets/{fileID}.svg
|
imgSrc = decodeURIComponent(url.pathname);
|
||||||
const match = pathPart.match(/^assets\/([^\/]+)\.svg$/i);
|
|
||||||
|
if(imgSrc.startsWith('/assets/')) {
|
||||||
|
return "/data" + imgSrc;
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
|
||||||
return match?.[1] || null;
|
|
||||||
}
|
}
|
||||||
|
|
23
src/index.ts
23
src/index.ts
|
@ -1,6 +1,14 @@
|
||||||
import {Plugin, Protyle} from 'siyuan';
|
import {Plugin, Protyle} from 'siyuan';
|
||||||
import {getPreviewHTML, loadIcons, getMenuHTML, generateSiyuanId, findImgSrc, extractFileID} from "@/helper";
|
import {
|
||||||
|
getPreviewHTML,
|
||||||
|
loadIcons,
|
||||||
|
getMenuHTML,
|
||||||
|
generateSiyuanId,
|
||||||
|
findImgSrc,
|
||||||
|
imgSrcToAbsolutePath
|
||||||
|
} from "@/helper";
|
||||||
import {createEditor, openEditorTab} from "@/editorTab";
|
import {createEditor, openEditorTab} from "@/editorTab";
|
||||||
|
import {DATA_PATH} from "@/const";
|
||||||
|
|
||||||
export default class DrawJSPlugin extends Plugin {
|
export default class DrawJSPlugin extends Plugin {
|
||||||
onload() {
|
onload() {
|
||||||
|
@ -18,23 +26,22 @@ export default class DrawJSPlugin extends Plugin {
|
||||||
filter: ["Insert Drawing", "Add drawing", "whiteboard", "freehand", "graphics", "jsdraw"],
|
filter: ["Insert Drawing", "Add drawing", "whiteboard", "freehand", "graphics", "jsdraw"],
|
||||||
html: getMenuHTML("iconDraw", this.i18n.insertDrawing),
|
html: getMenuHTML("iconDraw", this.i18n.insertDrawing),
|
||||||
callback: (protyle: Protyle) => {
|
callback: (protyle: Protyle) => {
|
||||||
const uid = generateSiyuanId();
|
const path = DATA_PATH + generateSiyuanId() + ".svg";
|
||||||
protyle.insert(getPreviewHTML(uid), true, false);
|
protyle.insert(getPreviewHTML(path), true, false);
|
||||||
openEditorTab(this, uid);
|
openEditorTab(this, path);
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
this.eventBus.on("open-menu-image", (e: any) => {
|
this.eventBus.on("open-menu-image", (e: any) => {
|
||||||
const fileID = extractFileID(findImgSrc(e.detail.element));
|
const path = imgSrcToAbsolutePath(findImgSrc(e.detail.element));
|
||||||
if(fileID === null) {
|
if(path === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("got ID" + fileID);
|
|
||||||
e.detail.menu.addItem({
|
e.detail.menu.addItem({
|
||||||
icon: "iconDraw",
|
icon: "iconDraw",
|
||||||
label: "Edit with js-draw",
|
label: "Edit with js-draw",
|
||||||
click: () => {
|
click: () => {
|
||||||
openEditorTab(this, fileID);
|
openEditorTab(this, path);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue