Files
chatpapers/src/modules/ui/readerPane.ts
T
2026-09-01 08:38:36 +08:00

125 lines
3.8 KiB
TypeScript

import { config } from "../../../package.json";
import { getLocaleID, getString } from "../../utils/locale";
import { ChatView } from "./chatView";
import {
applyAdaptiveHeight,
applyItemPaneSectionButtonIcons,
applyItemPaneSectionHeadLabel,
buildItemPaneSectionButtons,
clearSectionSummary,
onItemPaneSectionToggle,
prepareItemPaneBody,
refreshSectionOpenHeight,
} from "./itemPaneSection";
const views = new WeakMap<HTMLElement, ChatView>();
function iconURL(file: string) {
return `chrome://${config.addonRef}/content/icons/${file}`;
}
export function registerChatPane() {
Zotero.ItemPaneManager.registerSection({
paneID: "chatpapers-chat",
pluginID: config.addonID,
header: {
l10nID: getLocaleID("item-section-chat-head"),
icon: iconURL("chat.svg"),
},
sidenav: {
l10nID: getLocaleID("item-section-chat-sidenav"),
icon: iconURL("chat.svg"),
},
sectionButtons: buildItemPaneSectionButtons("chat"),
onInit: ({ body }) => {
const doc = body.ownerDocument;
if (doc) ensureStyles(doc);
prepareItemPaneBody(body);
applyAdaptiveHeight(body, "chat");
applyItemPaneSectionHeadLabel(body, "chat");
},
onDestroy: ({ body }) => {
views.get(body)?.destroy();
views.delete(body);
},
onItemChange: ({ item, setEnabled, tabType }) => {
// Enable in reader and library item pane when there is an item
setEnabled(Boolean(item));
void tabType;
return true;
},
onRender: ({ body, setSectionSummary }) => {
body.replaceChildren();
const doc = body.ownerDocument;
if (!doc) return;
applyItemPaneSectionHeadLabel(body, "chat");
clearSectionSummary(body, setSectionSummary);
applyItemPaneSectionButtonIcons(body);
const loading = doc.createElement("div");
loading.className = "chatpapers-loading";
loading.textContent = getString("chat-loading");
body.append(loading);
},
onAsyncRender: async ({ body, item, setSectionSummary }) => {
if (!item) return;
const doc = body.ownerDocument;
if (!doc) return;
views.get(body)?.destroy();
const view = new ChatView(doc, body, item);
views.set(body, view);
await view.mount();
applyItemPaneSectionHeadLabel(body, "chat");
clearSectionSummary(body, setSectionSummary);
applyAdaptiveHeight(body, "chat");
applyItemPaneSectionButtonIcons(body);
const section = body.closest("collapsible-section");
if (section?.hasAttribute("open")) {
refreshSectionOpenHeight(body);
} else if (section) {
onItemPaneSectionToggle({ body });
}
},
onToggle: ({ body, event }) => {
applyItemPaneSectionButtonIcons(body);
onItemPaneSectionToggle({ body, event });
},
});
}
export function registerPrefs() {
Zotero.PreferencePanes.register({
pluginID: config.addonID,
src: rootURI + "content/preferences.xhtml",
label: getString("prefs-title"),
image: `chrome://${config.addonRef}/content/icons/favicon.png`,
});
}
export function ensureChatPapersStyles(doc: Document): void {
const id = "chatpapers-styles";
const base = `chrome://${config.addonRef}/content/chatpapers.css`;
const href =
typeof __env__ !== "undefined" && __env__ === "development"
? `${base}?v=${Date.now()}`
: base;
const existing = doc.getElementById(id) as HTMLLinkElement | null;
if (existing) {
if (typeof __env__ !== "undefined" && __env__ === "development") {
existing.href = href;
}
return;
}
const link = doc.createElement("link");
link.id = id;
link.rel = "stylesheet";
link.type = "text/css";
link.href = href;
doc.documentElement?.appendChild(link);
}
function ensureStyles(doc: Document) {
ensureChatPapersStyles(doc);
}