mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-09-22 17:16:19 -07:00
feat(dictionary): add Hachidori backend support
- Add backend selection, setup gating, Anki integration, and external host support - Add launcher flags, documentation, packaging, and focused tests - Open on-demand overlay modals on the first attempt
This commit is contained in:
+71
@@ -0,0 +1,71 @@
|
||||
// SubMiner's popup contract is shared with its default Yomitan backend.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
(function () {
|
||||
"use strict";
|
||||
const emit = (name) => window.dispatchEvent(new CustomEvent(name));
|
||||
globalThis.SubMinerHachidori = {
|
||||
prioritizeCharacterResults(results, { primaryReading = "" } = {}, presentation = []) {
|
||||
const prefix = "SubMiner Character Dictionary";
|
||||
const aliases = new Map(presentation.map(entry => [entry.title, entry.displayName]));
|
||||
const character = glossary => glossary?.dictionary?.startsWith(prefix)
|
||||
|| aliases.get(glossary?.dictionary)?.startsWith(prefix) || false;
|
||||
// Keep the native linguistic ranking ahead of the character preference,
|
||||
// matching Yomitan's boost before frequency and user dictionary order.
|
||||
const ranked = results.map(result => ({ ...result, term: { ...result.term,
|
||||
glossaries: [...result.term.glossaries].sort((a, b) => Number(character(b)) - Number(character(a))),
|
||||
} }));
|
||||
return ranked.sort((a, b) =>
|
||||
(primaryReading ? Number(b.term.reading === primaryReading) - Number(a.term.reading === primaryReading) : 0)
|
||||
|| (b.matched || b.term.expression).length - (a.matched || a.term.expression).length
|
||||
|| (a.preprocessorSteps ?? 0) - (b.preprocessorSteps ?? 0)
|
||||
|| (a.trace?.length ?? 0) - (b.trace?.length ?? 0)
|
||||
|| Number(b.term.expression === b.deinflected) - Number(a.term.expression === a.deinflected)
|
||||
|| Number(character(b.term.glossaries[0])) - Number(character(a.term.glossaries[0])));
|
||||
},
|
||||
markHost(host, visible) {
|
||||
host?.setAttribute("data-subminer-yomitan-popup-host", "true");
|
||||
host?.setAttribute("data-subminer-yomitan-popup-visible", String(visible));
|
||||
},
|
||||
attention(host, visible) {
|
||||
this.markHost(host, visible);
|
||||
emit(visible ? "yomitan-popup-shown" : "yomitan-popup-hidden");
|
||||
},
|
||||
lookup() { emit("subminer-yomitan-lookup"); },
|
||||
popup(popup) {
|
||||
popup.addEventListener("mouseenter", () => emit("yomitan-popup-mouse-enter"));
|
||||
popup.addEventListener("mouseleave", () => emit("yomitan-popup-mouse-leave"));
|
||||
},
|
||||
connect({ hide, clear, action, keydown, scroll, cycleAudio }) {
|
||||
const listener = (event) => {
|
||||
const detail = event.detail;
|
||||
if (!detail || typeof detail !== "object") return;
|
||||
switch (detail.type) {
|
||||
case "setVisible": if (detail.visible === false) hide(); break;
|
||||
case "clearActiveTextSource": clear(); break;
|
||||
case "mineSelected": action("addNote"); break;
|
||||
case "scanSelectedText": action("scanSelectedText"); break;
|
||||
case "playCurrentAudio": action("playAudio"); break;
|
||||
case "cycleAudioSource": cycleAudio(detail.direction === -1 ? -1 : 1); break;
|
||||
case "scrollBy":
|
||||
scroll(Number.isFinite(detail.deltaX) ? detail.deltaX : 0,
|
||||
Number.isFinite(detail.deltaY) ? detail.deltaY : 0);
|
||||
break;
|
||||
case "simulateHotkey":
|
||||
case "forwardKeyDown": {
|
||||
if (typeof detail.key !== "string" || !Array.isArray(detail.modifiers)) return;
|
||||
const modifiers = detail.modifiers;
|
||||
keydown(new KeyboardEvent("keydown", {
|
||||
key: detail.key, code: typeof detail.code === "string" ? detail.code : "",
|
||||
repeat: detail.repeat === true, cancelable: true,
|
||||
altKey: modifiers.includes("alt"), ctrlKey: modifiers.includes("ctrl"),
|
||||
metaKey: modifiers.includes("meta"), shiftKey: modifiers.includes("shift"),
|
||||
}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
window.addEventListener("subminer-yomitan-popup-command", listener);
|
||||
return () => window.removeEventListener("subminer-yomitan-popup-command", listener);
|
||||
},
|
||||
};
|
||||
}());
|
||||
Reference in New Issue
Block a user