diff --git a/app/src/asset/anno.ts b/app/src/asset/anno.ts index 164bc000d..799c56af4 100644 --- a/app/src/asset/anno.ts +++ b/app/src/asset/anno.ts @@ -6,6 +6,8 @@ import {setStorageVal, writeText} from "../protyle/util/compatibility"; import {getAllModels} from "../layout/getAll"; import {focusByRange} from "../protyle/util/selection"; import {Constants} from "../constants"; +import {Dialog} from "../dialog"; +import {showMessage} from "../dialog/message"; export const initAnno = (element: HTMLElement, pdf: any, pdfConfig: any) => { getConfig(pdf); @@ -214,6 +216,13 @@ export const initAnno = (element: HTMLElement, pdf: any, pdfConfig: any) => { event.stopPropagation(); processed = true; break; + } else if (type === "relate") { + setRelation(pdf); + hideToolbar(element); + event.preventDefault(); + event.stopPropagation(); + processed = true; + break; } else if (type === "toggle") { const config = getConfig(pdf); const annoItem = config[rectElement.getAttribute("data-node-id")]; @@ -265,6 +274,81 @@ export const initAnno = (element: HTMLElement, pdf: any, pdfConfig: any) => { return pdf; }; +const getRelationHTML = (ids: string[]) => { + if (!ids) { + return `
  • ${window.siyuan.languages.emptyContent}
  • `; + } + let html = "" + ids.forEach((id: string) => { + html += `
  • + ${id} + + + +
  • `; + }) + return html +} + +const setRelation = (pdf: any) => { + const config = getConfig(pdf); + const configItem = config[rectElement.getAttribute("data-node-id")]; + if (!configItem.ids) { + configItem.ids = []; + } + const dialog = new Dialog({ + title: window.siyuan.languages.relation, + content: `
    +
    + +
    + +
    +
    + +
    `, + width: "520px", + }); + const inputElement = dialog.element.querySelector(".b3-text-field") as HTMLInputElement + inputElement.focus(); + + dialog.element.addEventListener("click", (event) => { + let target = event.target as HTMLElement; + while (target && !target.classList.contains("b3-dialog__content")) { + const type = target.getAttribute("data-type"); + if (type === "add") { + if (/\d{14}-\w{7}/.test(inputElement.value)) { + if (!configItem.ids.includes(inputElement.value)) { + configItem.ids.push(inputElement.value); + updateRelation(pdf, config); + rectElement.dataset.relations = configItem.ids; + dialog.element.querySelector(".b3-list").innerHTML = getRelationHTML(configItem.ids); + } + inputElement.value = ""; + } else { + showMessage("ID " + window.siyuan.languages.invalid); + } + event.preventDefault(); + event.stopPropagation(); + break; + } else if (type === "clear") { + configItem.ids.splice(configItem.ids.indexOf(target.parentElement.textContent.trim()), 1); + updateRelation(pdf, config); + rectElement.dataset.relations = configItem.ids; + dialog.element.querySelector(".b3-list").innerHTML = getRelationHTML(configItem.ids); + } + target = target.parentElement; + } + }); +} + +const updateRelation = (pdf: any, config: any) => { + fetchPost("/api/asset/setFileAnnotation", { + path: pdf.appConfig.file.replace(location.origin, "").substr(1) + ".sya", + data: JSON.stringify(config), + }); +} + const hideToolbar = (element: HTMLElement) => { element.querySelector(".pdf__util").classList.add("fn__none"); }; @@ -540,7 +624,8 @@ export const getHighlight = (element: HTMLElement) => { color: item.color, content: item.content, type: item.type, - mode: item.mode || "" + mode: item.mode || "", + ids: item.ids }, pdfInstance, pdfInstance.annoId === key); } }); @@ -559,7 +644,7 @@ const showHighlight = (selected: IPdfAnno, pdf: any, hl?: boolean) => { textLayerElement.insertAdjacentHTML("beforeend", "
    "); } textLayerElement = textLayerElement.lastElementChild; - let html = `
    `; + let html = `
    `; selected.coords.forEach((rect) => { const bounds = viewport.convertToViewportRectangle(rect); const width = Math.abs(bounds[0] - bounds[2]); @@ -676,11 +761,10 @@ async function getRectImgData(pdfObj: any) { } const setConfig = (pdf: any, id: string, data: IPdfAnno) => { - const urlPath = pdf.appConfig.file.replace(location.origin, "").substr(1); const config = getConfig(pdf); config[id] = data; fetchPost("/api/asset/setFileAnnotation", { - path: urlPath + ".sya", + path: pdf.appConfig.file.replace(location.origin, "").substr(1) + ".sya", data: JSON.stringify(config), }); }; diff --git a/app/src/asset/index.ts b/app/src/asset/index.ts index b6647459a..acdbfffba 100644 --- a/app/src/asset/index.ts +++ b/app/src/asset/index.ts @@ -436,7 +436,7 @@ export class Asset extends Model { ${window.siyuan.languages.copyAnnotation} - diff --git a/app/src/block/popover.ts b/app/src/block/popover.ts index 6fc5fd46f..1cbd16f18 100644 --- a/app/src/block/popover.ts +++ b/app/src/block/popover.ts @@ -278,15 +278,23 @@ export const showPopover = async (app: App, showRef = false) => { // 编辑器中的引用数 targetId = popoverTargetElement.parentElement.parentElement.getAttribute("data-node-id"); } else if (popoverTargetElement.classList.contains("pdf__rect")) { - targetId = popoverTargetElement.getAttribute("data-node-id"); - url = "/api/block/getRefIDsByFileAnnotationID"; + const relationIds = popoverTargetElement.getAttribute("data-relations") + if (relationIds) { + ids = relationIds.split(","); + url = ""; + } else { + targetId = popoverTargetElement.getAttribute("data-node-id"); + url = "/api/block/getRefIDsByFileAnnotationID"; + } } else if (!targetId) { // 文件树中的引用数 targetId = popoverTargetElement.parentElement.getAttribute("data-node-id"); } - const postResponse = await fetchSyncPost(url, {id: targetId}); - ids = postResponse.data.refIDs; - defIds = postResponse.data.defIDs; + if (url) { + const postResponse = await fetchSyncPost(url, {id: targetId}); + ids = postResponse.data.refIDs; + defIds = postResponse.data.defIDs; + } } let hasPin = false; diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index e59f6776f..409069342 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -319,6 +319,7 @@ interface IPdfAnno { mode: string, id?: string, coords?: number[] + ids?: string[] } interface IBackStack {