Files
chatpapers/src/modules/ui/multiChatDialog.ts
T

213 lines
5.9 KiB
TypeScript

import { config } from "../../../package.json";
import { getString } from "../../utils/locale";
import { normalizeLibraryItems } from "../pdf/multiContext";
import { MultiChatView } from "./multiChatView";
let activeDialog: any = null;
let activeView: MultiChatView | null = null;
let onDialogResize: (() => void) | null = null;
function ensureDialogStyles(doc: Document) {
const id = "chatpapers-styles";
if (doc.getElementById(id)) return;
const link = doc.createElement("link");
link.id = id;
link.rel = "stylesheet";
link.type = "text/css";
link.href = `chrome://${config.addonRef}/content/chatpapers.css`;
doc.documentElement?.appendChild(link);
}
/** Prefer a large window that still fits the current screen. */
function getPreferredDialogSize(): { width: number; height: number } {
try {
const win = Zotero.getMainWindow?.() as Window | undefined;
const screen = win?.screen;
const aw = screen?.availWidth || win?.outerWidth || 1280;
const ah = screen?.availHeight || win?.outerHeight || 800;
return {
width: Math.max(880, Math.min(Math.round(aw * 0.9), aw - 48)),
height: Math.max(640, Math.min(Math.round(ah * 0.88), ah - 48)),
};
} catch {
return { width: 1100, height: 780 };
}
}
function hideDialogButtonBox(doc: Document) {
const selectors = [
"#dialog-button-box",
".dialog-button-box",
"dialog > vbox.dialog-button-box",
"[anonid='buttons']",
];
for (const sel of selectors) {
const nodes = Array.from(doc.querySelectorAll(sel));
for (const node of nodes) {
(node as HTMLElement).style.display = "none";
}
}
}
/** Keep chat root filling the window so composer stays pinned to the bottom. */
function fitMultiChatRoot(win: Window) {
const doc = win.document;
hideDialogButtonBox(doc);
const root = doc.getElementById(
"chatpapers-multi-root",
) as HTMLElement | null;
if (!root) return;
const html = doc.documentElement as HTMLElement | null;
const body = doc.body as HTMLElement | null;
if (html) {
html.style.height = "100%";
html.style.margin = "0";
html.style.padding = "0";
html.style.overflow = "hidden";
html.style.setProperty("scrollbar-width", "thin");
}
if (body) {
body.style.height = "100%";
body.style.margin = "0";
body.style.padding = "0";
body.style.overflow = "hidden";
body.style.display = "flex";
body.style.flexDirection = "column";
body.style.setProperty("scrollbar-width", "thin");
}
// Shrink leftover dialog grid padding around our cell
for (const node of Array.from(doc.querySelectorAll("hbox, vbox, dialog"))) {
const el = node as HTMLElement;
if (
el.id === "dialog-button-box" ||
el.classList?.contains("dialog-button-box")
) {
el.style.display = "none";
continue;
}
if (el.tagName?.toLowerCase() === "dialog") {
el.style.padding = "0";
el.style.margin = "0";
el.style.height = "100%";
el.style.setProperty("scrollbar-width", "thin");
}
}
const pad = 4;
const h = Math.max(360, (win.innerHeight || 600) - pad);
root.style.width = "100%";
root.style.height = `${h}px`;
root.style.maxHeight = `${h}px`;
root.style.minHeight = "0";
root.style.flex = "1 1 auto";
root.style.overflow = "hidden";
}
export function openMultiChatDialog(items: Zotero.Item[]) {
const selected = normalizeLibraryItems(items);
if (!selected.length) {
new ztoolkit.ProgressWindow("ChatPapers")
.createLine({
text: getString("multi-no-items"),
type: "fail",
})
.show();
return;
}
if (selected.length > 8) {
new ztoolkit.ProgressWindow("ChatPapers")
.createLine({
text: getString("multi-too-many", {
args: { count: selected.length },
}),
type: "default",
})
.show();
}
// Close previous dialog if any
try {
if (activeDialog?.window && onDialogResize) {
activeDialog.window.removeEventListener("resize", onDialogResize);
}
activeView?.destroy();
activeDialog?.window?.close?.();
} catch {
// ignore
}
activeView = null;
activeDialog = null;
onDialogResize = null;
const size = getPreferredDialogSize();
const dialogHelper = new ztoolkit.Dialog(1, 1)
.addCell(0, 0, {
tag: "div",
namespace: "html",
id: "chatpapers-multi-root",
styles: {
width: "100%",
height: "100%",
minWidth: "640px",
minHeight: "0",
overflow: "hidden",
boxSizing: "border-box",
display: "flex",
flexDirection: "column",
},
})
.setDialogData({
loadCallback: () => {
try {
const win = dialogHelper.window;
const doc = win.document;
ensureDialogStyles(doc);
hideDialogButtonBox(doc);
fitMultiChatRoot(win);
onDialogResize = () => fitMultiChatRoot(win);
win.addEventListener("resize", onDialogResize);
const root = doc.getElementById(
"chatpapers-multi-root",
) as HTMLElement | null;
if (!root) return;
activeView = new MultiChatView(doc, root, selected.slice(0, 8));
void activeView.mount().then(() => fitMultiChatRoot(win));
} catch (e) {
ztoolkit.log("openMultiChatDialog load failed", e);
}
},
unloadCallback: () => {
try {
if (activeDialog?.window && onDialogResize) {
activeDialog.window.removeEventListener("resize", onDialogResize);
}
} catch {
// ignore
}
onDialogResize = null;
activeView?.destroy();
activeView = null;
activeDialog = null;
},
});
activeDialog = dialogHelper;
dialogHelper.open(
`ChatPapers · ${Math.min(selected.length, 8)} papers`,
{
centerscreen: true,
resizable: true,
noDialogMode: true,
fitContent: false,
width: size.width,
height: size.height,
},
);
}