增加pdf中划句或段ai伴读功能
This commit is contained in:
@@ -1,10 +1,104 @@
|
||||
/** Helpers for Zotero ItemPane collapsible sections. */
|
||||
|
||||
import { getLocaleID, getString } from "../../utils/locale";
|
||||
import { getPref, setPref } from "../../utils/prefs";
|
||||
import { openChatPaneWindow, openLecturePaneWindow } from "./itemPaneWindow";
|
||||
|
||||
export type ItemPaneKind = "chat" | "lecture";
|
||||
|
||||
const ADAPTIVE_PREF: Record<ItemPaneKind, keyof _ZoteroTypes.Prefs["PluginPrefsMap"]> =
|
||||
{
|
||||
chat: "chatPaneAdaptiveHeight",
|
||||
lecture: "lecturePaneAdaptiveHeight",
|
||||
};
|
||||
|
||||
const FIXED_HEIGHT: Record<ItemPaneKind, number> = {
|
||||
chat: 360,
|
||||
lecture: 420,
|
||||
};
|
||||
|
||||
const OPEN_WINDOW_ICON = "chrome://zotero/skin/16/universal/open.svg";
|
||||
const ADAPTIVE_ICON = "chrome://zotero/skin/16/universal/expand-all.svg";
|
||||
const ADAPTIVE_ICON_OFF = "chrome://zotero/skin/16/universal/collapse-all.svg";
|
||||
|
||||
export function prepareItemPaneBody(body: HTMLElement): void {
|
||||
body.classList.add("chatpapers-pane-body");
|
||||
body.style.minHeight = "0";
|
||||
}
|
||||
|
||||
export function isAdaptiveHeight(kind: ItemPaneKind): boolean {
|
||||
const val = getPref(ADAPTIVE_PREF[kind]);
|
||||
return val !== false;
|
||||
}
|
||||
|
||||
export function applyAdaptiveHeight(
|
||||
body: HTMLElement,
|
||||
kind: ItemPaneKind,
|
||||
adaptive = isAdaptiveHeight(kind),
|
||||
): void {
|
||||
body.classList.toggle("chatpapers-pane-adaptive", adaptive);
|
||||
body.classList.toggle("chatpapers-pane-fixed", !adaptive);
|
||||
body.dataset.chatpapersPaneKind = kind;
|
||||
|
||||
const section = resolveCollapsibleSection(body);
|
||||
section?.classList.toggle("chatpapers-adaptive-height", adaptive);
|
||||
section?.classList.toggle("chatpapers-fixed-height", !adaptive);
|
||||
updateAdaptiveButtonState(body, adaptive);
|
||||
}
|
||||
|
||||
export function toggleAdaptiveHeight(
|
||||
body: HTMLElement,
|
||||
kind: ItemPaneKind,
|
||||
): boolean {
|
||||
const next = !isAdaptiveHeight(kind);
|
||||
setPref(ADAPTIVE_PREF[kind], next);
|
||||
applyAdaptiveHeight(body, kind, next);
|
||||
refreshSectionOpenHeight(body);
|
||||
return next;
|
||||
}
|
||||
|
||||
export function refreshSectionOpenHeight(body: HTMLElement): void {
|
||||
const section = resolveCollapsibleSection(body);
|
||||
if (!section?.hasAttribute("open")) return;
|
||||
|
||||
if (section.classList.contains("chatpapers-adaptive-height")) {
|
||||
section.style.setProperty("--open-height", "auto");
|
||||
body.style.removeProperty("max-height");
|
||||
body.style.removeProperty("overflow");
|
||||
return;
|
||||
}
|
||||
|
||||
const kind = (body.dataset.chatpapersPaneKind || "chat") as ItemPaneKind;
|
||||
const maxH = FIXED_HEIGHT[kind] ?? 360;
|
||||
body.style.maxHeight = `${maxH}px`;
|
||||
body.style.overflowY = "auto";
|
||||
section.style.setProperty("--open-height", `${maxH}px`);
|
||||
}
|
||||
|
||||
export function updateAdaptiveButtonState(
|
||||
body: HTMLElement,
|
||||
adaptive: boolean,
|
||||
): void {
|
||||
const section = resolveCollapsibleSection(body);
|
||||
const btn = section?.querySelector(
|
||||
".adaptive-height.section-custom-button",
|
||||
) as HTMLElement | null;
|
||||
if (!btn) return;
|
||||
btn.setAttribute("aria-pressed", adaptive ? "true" : "false");
|
||||
btn.classList.toggle("chatpapers-adaptive-active", adaptive);
|
||||
btn.style.setProperty(
|
||||
"--custom-button-icon-light",
|
||||
`url('${adaptive ? ADAPTIVE_ICON : ADAPTIVE_ICON_OFF}')`,
|
||||
);
|
||||
btn.style.setProperty(
|
||||
"--custom-button-icon-dark",
|
||||
`url('${adaptive ? ADAPTIVE_ICON : ADAPTIVE_ICON_OFF}')`,
|
||||
);
|
||||
btn.title = getString(
|
||||
adaptive ? "item-pane-adaptive-height-on" : "item-pane-adaptive-height-off",
|
||||
);
|
||||
}
|
||||
|
||||
export function onItemPaneSectionToggle(options: {
|
||||
body: HTMLElement;
|
||||
event?: Event;
|
||||
@@ -13,28 +107,57 @@ export function onItemPaneSectionToggle(options: {
|
||||
if (!section) return;
|
||||
|
||||
const open = section.hasAttribute("open");
|
||||
const adaptive = section.classList.contains("chatpapers-adaptive-height");
|
||||
|
||||
if (open) {
|
||||
options.body.style.removeProperty("height");
|
||||
options.body.style.removeProperty("overflow");
|
||||
options.body.style.minHeight = "0";
|
||||
const raf = options.body.ownerDocument?.defaultView?.requestAnimationFrame;
|
||||
const updateHeight = () => {
|
||||
const h = options.body.scrollHeight;
|
||||
if (h > 0) {
|
||||
section.style.setProperty("--open-height", `${h}px`);
|
||||
}
|
||||
};
|
||||
if (raf) raf(updateHeight);
|
||||
else updateHeight();
|
||||
|
||||
if (adaptive) {
|
||||
options.body.style.removeProperty("overflow");
|
||||
options.body.style.removeProperty("max-height");
|
||||
section.style.setProperty("--open-height", "auto");
|
||||
return;
|
||||
}
|
||||
|
||||
options.body.style.overflowY = "auto";
|
||||
const kind = (options.body.dataset.chatpapersPaneKind || "chat") as ItemPaneKind;
|
||||
const maxH = FIXED_HEIGHT[kind] ?? 360;
|
||||
options.body.style.maxHeight = `${maxH}px`;
|
||||
section.style.setProperty("--open-height", `${maxH}px`);
|
||||
return;
|
||||
}
|
||||
|
||||
options.body.style.minHeight = "0";
|
||||
options.body.style.height = "0";
|
||||
options.body.style.overflow = "hidden";
|
||||
options.body.style.removeProperty("max-height");
|
||||
section.style.setProperty("--open-height", "0px");
|
||||
}
|
||||
|
||||
export function buildItemPaneSectionButtons(kind: ItemPaneKind) {
|
||||
return [
|
||||
{
|
||||
type: "open-in-window",
|
||||
icon: OPEN_WINDOW_ICON,
|
||||
l10nID: getLocaleID("item-pane-open-window"),
|
||||
onClick: ({ item }: { item?: Zotero.Item }) => {
|
||||
if (!item) return;
|
||||
if (kind === "chat") openChatPaneWindow(item);
|
||||
else openLecturePaneWindow(item);
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "adaptive-height",
|
||||
icon: ADAPTIVE_ICON,
|
||||
l10nID: getLocaleID("item-pane-adaptive-height"),
|
||||
onClick: ({ body }: { body: HTMLElement }) => {
|
||||
toggleAdaptiveHeight(body, kind);
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function resolveCollapsibleSection(
|
||||
body: HTMLElement,
|
||||
event?: Event,
|
||||
|
||||
Reference in New Issue
Block a user