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, }, ); }