115 lines
3.6 KiB
TypeScript
115 lines
3.6 KiB
TypeScript
import { config } from "../../../../package.json";
|
|
import { getString } from "../../../utils/locale";
|
|
import { cacheReaderSelection } from "../../pdf/selection";
|
|
import { highlightTextInPdf } from "../../pdf/readerSync";
|
|
import { getRegularItem, resolvePaperAttachment } from "../infrastructure/zotero/adapter";
|
|
import { paperIdFromCacheKey } from "../infrastructure/pdf/fileHash";
|
|
import { explainSelectionLecture } from "../application/explainSelectionLecture";
|
|
import { playSelectionExplainStandalone } from "../application/playSelectionExplain";
|
|
import { lectureEvents } from "../infrastructure/events";
|
|
|
|
function tryString(value: unknown): string {
|
|
if (typeof value === "string") return value.trim();
|
|
if (value == null) return "";
|
|
return String(value).trim();
|
|
}
|
|
|
|
function itemFromReader(reader: any): Zotero.Item | undefined {
|
|
const attachmentId = reader?.itemID ?? reader?._itemID;
|
|
if (!attachmentId) return undefined;
|
|
const attachment = Zotero.Items.get(attachmentId);
|
|
if (!attachment) return undefined;
|
|
return getRegularItem(attachment);
|
|
}
|
|
|
|
function showHeadline(text: string): void {
|
|
try {
|
|
const pw = new Zotero.ProgressWindow({ closeOnClick: true });
|
|
pw.changeHeadline(text);
|
|
pw.show();
|
|
pw.startCloseTimer(4000);
|
|
} catch {
|
|
// ignore
|
|
}
|
|
}
|
|
|
|
export async function runSelectionExplainFromReader(
|
|
reader: any,
|
|
selectedText: string,
|
|
): Promise<void> {
|
|
const text = tryString(selectedText);
|
|
if (!text) return;
|
|
|
|
const item = itemFromReader(reader);
|
|
if (!item) {
|
|
showHeadline(getString("lecture-selection-no-item"));
|
|
return;
|
|
}
|
|
|
|
cacheReaderSelection(text);
|
|
showHeadline(getString("lecture-selection-explaining"));
|
|
|
|
try {
|
|
const ctx = await resolvePaperAttachment(item);
|
|
const result = await explainSelectionLecture({
|
|
item,
|
|
selectedText: text,
|
|
onProgress: (message) => showHeadline(message),
|
|
});
|
|
|
|
await highlightTextInPdf(item, {
|
|
text: result.original,
|
|
page: result.page,
|
|
});
|
|
|
|
lectureEvents.emit("lecture:selection_explain", {
|
|
paperId: paperIdFromCacheKey(ctx.cacheKey),
|
|
cacheKey: ctx.cacheKey,
|
|
itemId: String(getRegularItem(item).id),
|
|
result,
|
|
});
|
|
|
|
await playSelectionExplainStandalone(result);
|
|
showHeadline(getString("lecture-selection-done"));
|
|
} catch (e) {
|
|
const msg = e instanceof Error ? e.message : String(e);
|
|
ztoolkit.log("[ChatPapers:Lecture] selection explain failed", e);
|
|
showHeadline(msg);
|
|
}
|
|
}
|
|
|
|
export function registerSelectionExplainPopup(): void {
|
|
try {
|
|
Zotero.Reader.registerEventListener(
|
|
"renderTextSelectionPopup",
|
|
(event: any) => {
|
|
try {
|
|
const { doc, params, append, reader } = event;
|
|
const text =
|
|
tryString(params?.annotation?.text) || tryString(params?.text);
|
|
if (!text) return;
|
|
cacheReaderSelection(text);
|
|
|
|
const btn = doc.createElement("button");
|
|
btn.type = "button";
|
|
btn.className =
|
|
"toolbar-button wide-button chatpapers-selection-explain-btn";
|
|
btn.textContent = getString("lecture-explain-selection-short");
|
|
btn.title = getString("lecture-explain-selection");
|
|
btn.addEventListener("click", (ev) => {
|
|
ev.preventDefault();
|
|
ev.stopPropagation();
|
|
void runSelectionExplainFromReader(reader, text);
|
|
});
|
|
append(btn);
|
|
} catch (e) {
|
|
ztoolkit.log("[ChatPapers:Lecture] selection popup button failed", e);
|
|
}
|
|
},
|
|
config.addonID,
|
|
);
|
|
} catch (e) {
|
|
ztoolkit.log("[ChatPapers:Lecture] registerSelectionExplainPopup failed", e);
|
|
}
|
|
}
|