zotero-better-notes/src/modules/workspace/link.ts

171 lines
4.8 KiB
TypeScript

import { config } from "../../../package.json";
import { Workspace } from "../../elements/workspace";
export function registerNoteLinkSection(type: "inbound" | "outbound") {
const key = Zotero.ItemPaneManager.registerSection({
paneID: `bn-note-${type}-link`,
pluginID: config.addonID,
header: {
icon: `chrome://${config.addonRef}/content/icons/${type}-link-16.svg`,
l10nID: `${config.addonRef}-note-${type}-header`,
},
sidenav: {
icon: `chrome://${config.addonRef}/content/icons/${type}-link-20.svg`,
l10nID: `${config.addonRef}-note-${type}-sidenav`,
},
sectionButtons: [
{
type: "refreshGraph",
icon: "chrome://zotero/skin/16/universal/sync.svg",
l10nID: `${config.addonRef}-note-${type}-refresh`,
onClick: ({ body, item, setL10nArgs }) => {
renderSection(type, {
body,
item,
setCount: makeSetCount(setL10nArgs),
});
},
},
],
onInit({ body, refresh }) {
const notifierKey = Zotero.Notifier.registerObserver(
{
notify: (event, type, ids, extraData) => {
const item = Zotero.Items.get(body.dataset.itemID || "");
if (
item &&
// @ts-ignore
event === "updateBNRelation" &&
type === "item" &&
(ids as number[]).includes(item.id)
) {
ztoolkit.log(
`relation notify refresh link ${type}`,
ids,
item.id,
);
refresh();
}
},
},
["item"],
);
body.classList.add("bn-link-body");
body.dataset.notifierKey = notifierKey;
},
onDestroy({ body }) {
const notifierKey = body.dataset.notifierKey;
if (notifierKey) {
Zotero.Notifier.unregisterObserver(notifierKey);
}
},
onItemChange: ({ body, item, setEnabled }) => {
if (body.closest("bn-workspace") as HTMLElement | undefined) {
setEnabled(true);
body.dataset.itemID = String(item.id);
return;
}
setEnabled(false);
},
onRender: () => {},
onAsyncRender: async ({ body, item, setL10nArgs }) => {
await renderSection(type, {
body,
item,
setCount: makeSetCount(setL10nArgs),
});
},
});
}
async function renderSection(
type: "inbound" | "outbound",
{
body,
item,
setCount,
}: {
body: HTMLElement;
item: Zotero.Item;
setCount: (count: number) => void;
},
) {
body.replaceChildren();
const doc = body.ownerDocument;
const api = {
inbound: addon.api.relation.getNoteLinkInboundRelation,
outbound: addon.api.relation.getNoteLinkOutboundRelation,
};
const inLinks = await api[type](item.id);
for (const linkData of inLinks) {
const targetItem = (await Zotero.Items.getByLibraryAndKeyAsync(
linkData[
{ inbound: "fromLibID", outbound: "toLibID" }[type] as
| "fromLibID"
| "toLibID"
],
linkData[
{ inbound: "fromKey", outbound: "toKey" }[type] as "fromKey" | "toKey"
],
)) as Zotero.Item;
const linkParams = {
workspaceUID: (body.closest("bn-workspace") as Workspace)?.dataset.uid,
lineIndex: linkData.toLine ?? undefined,
sectionName: linkData.toSection ?? undefined,
};
const row = doc.createElement("div");
row.className = "row";
const icon = ztoolkit
.getGlobal("require")("components/icons")
.getCSSItemTypeIcon("note");
const label = doc.createElement("span");
label.className = "label";
let content = targetItem.getNoteTitle();
if (typeof linkData.toLine === "number") {
content += ` > Line ${linkData.toLine}`;
}
if (typeof linkData.toSection === "string") {
content += `#${linkData.toSection}`;
}
label.append(content);
const box = doc.createElement("div");
box.addEventListener("click", () =>
addon.hooks.onOpenNote(targetItem.id, "preview", linkParams),
);
box.className = "box keyboard-clickable";
box.setAttribute("tabindex", "0");
box.append(icon, label);
row.append(box);
const note = (doc as any).createXULElement("toolbarbutton");
note.addEventListener("command", (event: MouseEvent) => {
const position = event.shiftKey ? "window" : "tab";
addon.hooks.onOpenNote(targetItem.id, position, linkParams);
});
note.className = "zotero-clicky zotero-clicky-open-link";
note.setAttribute("tabindex", "0");
row.append(note);
body.append(row);
}
const count = inLinks.length;
setCount(count);
}
function handleShowItem(id: number) {
ZoteroPane.selectItem(id);
}
function makeSetCount(setL10nArgs: (str: string) => void) {
return (count: number) => {
setL10nArgs(`{"count": "${count}"}`);
};
}