213 lines
5.9 KiB
TypeScript
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,
|
|
},
|
|
);
|
|
}
|