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) {
|
||||
navigator.clipboard.writeText(getEditLink(fileID));
|
||||
function copyEditLink(path) {
|
||||
navigator.clipboard.writeText(getEditLink(path));
|
||||
}
|
||||
function copyImageLink(fileID) {
|
||||
navigator.clipboard.writeText(``);
|
||||
function copyImageLink(path) {
|
||||
navigator.clipboard.writeText(`})`);
|
||||
}
|
||||
|
||||
function refreshPage() {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
function addButton(document, fileID) {
|
||||
function addButton(document, path) {
|
||||
|
||||
// Add floating button
|
||||
const floatingButton = document.createElement('button');
|
||||
|
@ -22,8 +22,8 @@ function addButton(document, fileID) {
|
|||
popupMenu.id = 'popupMenu';
|
||||
popupMenu.innerHTML = `
|
||||
<button onclick="refreshPage()">Refresh</button>
|
||||
<button onclick="copyEditLink('${fileID}')">Copy Direct Edit Link</button>
|
||||
<button onclick="copyImageLink('${fileID}')">Copy Image Link</button>
|
||||
<button onclick="copyEditLink('${path}')">Copy Direct Edit Link</button>
|
||||
<button onclick="copyImageLink('${path}')">Copy Image Link</button>
|
||||
`;
|
||||
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) {
|
||||
return FALLBACK;
|
||||
}
|
||||
|
@ -37,10 +37,10 @@ async function getSVG(fileID) {
|
|||
|
||||
}
|
||||
|
||||
function getEditLink(fileID) {
|
||||
function getEditLink(path) {
|
||||
const data = encodeURIComponent(
|
||||
JSON.stringify({
|
||||
id: fileID
|
||||
path: path,
|
||||
})
|
||||
)
|
||||
return `siyuan://plugins/siyuan-jsdraw-pluginwhiteboard/?icon=iconDraw&title=Drawing&data=${data}`;
|
||||
|
|
|
@ -5,18 +5,22 @@
|
|||
<script src="button.js"></script>
|
||||
<script>
|
||||
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 () => {
|
||||
const editLink = document.createElement('a');
|
||||
editLink.href = getEditLink(fileID);
|
||||
editLink.href = getEditLink(path);
|
||||
document.body.appendChild(editLink);
|
||||
|
||||
const htmlContainer = document.createElement('div');
|
||||
htmlContainer.innerHTML = await getSVG(fileID);
|
||||
htmlContainer.innerHTML = await getSVG(path);
|
||||
editLink.appendChild(htmlContainer);
|
||||
|
||||
addButton(document, fileID);
|
||||
addButton(document, path);
|
||||
});
|
||||
</script>
|
||||
<link rel="stylesheet" href="index.css">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
export const SVG_MIME = "image/svg+xml";
|
||||
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 TOOLBAR_PATH = STORAGE_PATH + "/toolbar.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 {idToPath} from "@/helper";
|
||||
|
||||
export function openEditorTab(p: Plugin, fileID: string) {
|
||||
export function openEditorTab(p: Plugin, path: string) {
|
||||
openTab({
|
||||
app: p.app,
|
||||
custom: {
|
||||
title: 'Drawing',
|
||||
icon: 'iconDraw',
|
||||
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();
|
||||
try {
|
||||
saveFile(idToPath(fileID), SVG_MIME, svgElem.outerHTML);
|
||||
saveFile(path, SVG_MIME, svgElem.outerHTML);
|
||||
saveButton.setDisabled(true);
|
||||
setTimeout(() => { // @todo improve save button feedback
|
||||
saveButton.setDisabled(false);
|
||||
|
@ -36,11 +36,15 @@ async function saveCallback(editor: Editor, fileID: string, saveButton: BaseWidg
|
|||
|
||||
export function createEditor(i: ITabModel) {
|
||||
|
||||
const fileID = i.data.id;
|
||||
if(fileID == null) {
|
||||
alert("File ID missing - couldn't open file.")
|
||||
let path = i.data.path;
|
||||
if(path == null) {
|
||||
const fileID = i.data.id; // legacy compatibility
|
||||
if (fileID == null) {
|
||||
alert("File ID and path missing - couldn't open file.")
|
||||
return;
|
||||
}
|
||||
path = idToPath(fileID);
|
||||
}
|
||||
|
||||
const editor = new Editor(i.element, {
|
||||
iconProvider: new MaterialIconProvider(),
|
||||
|
@ -55,14 +59,14 @@ export function createEditor(i: ITabModel) {
|
|||
}
|
||||
});
|
||||
// restore drawing
|
||||
getFile(idToPath(fileID)).then(svg => {
|
||||
getFile(path).then(svg => {
|
||||
if(svg != null) {
|
||||
editor.loadFromSVG(svg);
|
||||
}
|
||||
});
|
||||
|
||||
// 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!)
|
||||
editor.notifier.on(EditorEventType.ToolUpdated, () => {
|
||||
|
|
|
@ -45,14 +45,14 @@ export function generateSiyuanId() {
|
|||
}
|
||||
|
||||
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}"})
|
||||
// 
|
||||
export function getPreviewHTML(id: string): string {
|
||||
export function getPreviewHTML(path: string): string {
|
||||
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 {
|
||||
// Base case: if current element is an image
|
||||
if (element.tagName === 'IMG') {
|
||||
const fullSrc = (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;
|
||||
return (element as HTMLImageElement).src;
|
||||
}
|
||||
|
||||
// Recursively check children
|
||||
|
@ -79,12 +74,15 @@ export function findImgSrc(element: HTMLElement): string | null {
|
|||
return null;
|
||||
}
|
||||
|
||||
export function extractFileID(imgSrc: string | null): string | null {
|
||||
export function imgSrcToAbsolutePath(imgSrc: string | null): string | null {
|
||||
if (!imgSrc) return null;
|
||||
|
||||
const [pathPart] = imgSrc.split('?');
|
||||
// Match pattern: assets/{fileID}.svg
|
||||
const match = pathPart.match(/^assets\/([^\/]+)\.svg$/i);
|
||||
const url = new URL(imgSrc);
|
||||
imgSrc = decodeURIComponent(url.pathname);
|
||||
|
||||
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 {getPreviewHTML, loadIcons, getMenuHTML, generateSiyuanId, findImgSrc, extractFileID} from "@/helper";
|
||||
import {
|
||||
getPreviewHTML,
|
||||
loadIcons,
|
||||
getMenuHTML,
|
||||
generateSiyuanId,
|
||||
findImgSrc,
|
||||
imgSrcToAbsolutePath
|
||||
} from "@/helper";
|
||||
import {createEditor, openEditorTab} from "@/editorTab";
|
||||
import {DATA_PATH} from "@/const";
|
||||
|
||||
export default class DrawJSPlugin extends Plugin {
|
||||
onload() {
|
||||
|
@ -18,23 +26,22 @@ export default class DrawJSPlugin extends Plugin {
|
|||
filter: ["Insert Drawing", "Add drawing", "whiteboard", "freehand", "graphics", "jsdraw"],
|
||||
html: getMenuHTML("iconDraw", this.i18n.insertDrawing),
|
||||
callback: (protyle: Protyle) => {
|
||||
const uid = generateSiyuanId();
|
||||
protyle.insert(getPreviewHTML(uid), true, false);
|
||||
openEditorTab(this, uid);
|
||||
const path = DATA_PATH + generateSiyuanId() + ".svg";
|
||||
protyle.insert(getPreviewHTML(path), true, false);
|
||||
openEditorTab(this, path);
|
||||
}
|
||||
}];
|
||||
|
||||
this.eventBus.on("open-menu-image", (e: any) => {
|
||||
const fileID = extractFileID(findImgSrc(e.detail.element));
|
||||
if(fileID === null) {
|
||||
const path = imgSrcToAbsolutePath(findImgSrc(e.detail.element));
|
||||
if(path === null) {
|
||||
return;
|
||||
}
|
||||
console.log("got ID" + fileID);
|
||||
e.detail.menu.addItem({
|
||||
icon: "iconDraw",
|
||||
label: "Edit with js-draw",
|
||||
click: () => {
|
||||
openEditorTab(this, fileID);
|
||||
openEditorTab(this, path);
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue