When inputting kanji with an IME, furigana is automatically added.
当前为
// ==UserScript==
// @name IME2Furigana
// @namespace ime2furigana
// @version 0.2
// @description When inputting kanji with an IME, furigana is automatically added.
// @author Sinyaven
// @match https://community.wanikani.com/*
// @grant none
// ==/UserScript==
(function() {
"use strict";
let furigana = "";
let mode = 0;
let bMode = null;
let tText = null;
let dObserverTarget = document.getElementById("reply-control");
let observer = new MutationObserver(m => m.forEach(handleMutation));
observer.observe(dObserverTarget, {childList: true, subtree: true});
function handleMutation(mutation) {
let addedNodes = Array.from(mutation.addedNodes);
addedNodes.filter(n => n.tagName === "TEXTAREA").forEach(n => {tText = n; n.addEventListener("compositionupdate", update); n.addEventListener("compositionend", addFurigana)});
addedNodes.filter(n => n.classList && n.classList.contains("d-editor-button-bar")).forEach(addButton);
}
function addButton(div) {
bMode = document.createElement("button");
bMode.className = "btn no-text btn-icon ember-view";
bMode.title = "IME2Furigana - off";
bMode.innerText = "F";
bMode.addEventListener("click", toggleActive);
div.appendChild(bMode);
}
function toggleActive() {
mode++;
if (mode === 3) mode = 0;
bMode.style.backgroundColor = mode ? "#00000042" : "";
bMode.style.filter = mode === 2 ? "blur(2px)" : "";
bMode.title = "IME2Furigana - " + (mode ? (mode === 1 ? "on" : "blur") : "off");
if (tText) tText.focus();
}
function update(event) {
if (/^[\u301c\u3041-\u309fnー]+$/.test(event.data)) {
furigana = event.data;
}
}
function addFurigana(event) {
if (!mode || event.data.length === 0) return;
furigana = furigana.replace(/n/g, "ん");
let parts = event.data.split(/([\uff66-\uff9d\u4e00-\u9faf\u3400-\u4dbf]+)/);
if (parts.length === 1) return;
let hiraganaParts = parts.map(p => Array.from(p).map(c => katakanaToHiragana(c)).join(""));
//let regex = new RegExp("^" + parts.map((p, idx) => idx & 1 ? (p ? "(.+)" : "()") : p).join("") + "$");
let regex = new RegExp("^" + hiraganaParts.map((p, idx) => "(" + (idx & 1 ? ".+" : p) + ")").join("") + "$");
let rt = furigana.match(regex);
if (!rt) {
parts = [event.data];
rt = [null, furigana];
}
rt.shift();
let rtStart = "<rp>(</rp><rt>" + (mode === 2 ? "[spoiler]" : "");
let rtEnd = (mode === 2 ? "[/spoiler]" : "") + "</rt><rp>)</rp>";
let ruby = parts.map((p, idx) => idx & 1 ? "<ruby>" + p + rtStart + rt[idx] + rtEnd + "</ruby>" : p).join("");
//if (event.data === furigana) return;
//let ruby = "<ruby>" + event.data + "<rt>" + furigana + "</rt></ruby>";
event.target.setRangeText(ruby, event.target.selectionStart - event.data.length, event.target.selectionStart, "end");
}
function katakanaToHiragana(k) {
return (k + "ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわをんヴヵヶ")["ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピヘベペホボポマミムメモャヤュユョヨラリルレロヮワヲンヴヵヶ".indexOf(k) + 1];
}
})();