From 1e8447cda3c7d1de5bb62f156d614ffd40ba71e2 Mon Sep 17 00:00:00 2001 From: wareya Date: Wed, 7 Feb 2018 07:35:10 -0500 Subject: [PATCH] start implementing import-based epwing lookups --- background-script.js | 165 +++++++++++++++++++++++++++---------------- options.html | 1 + options.js | 40 ++++++++++- texthook.js | 36 +++++++++- 4 files changed, 178 insertions(+), 64 deletions(-) diff --git a/background-script.js b/background-script.js index ed0f6d5..9ec875f 100644 --- a/background-script.js +++ b/background-script.js @@ -8,12 +8,26 @@ // We have to send an HTTP request and store the result in a string before parsing it into an object. // Seriously. -let epwing = [ -// Fill this out with some testing data from a json file generated by zero-epwing so that it looks something like this screenshot: https://i.imgur.com/waTYH1i.png -]; +let epwing = []; let lookup_epwing_kan = new Map(); let lookup_epwing_kana = new Map(); +async function refresh_epwing() +{ + epwing = (await browser.storage.local.get("epwing"))["epwing"]; + lookup_epwing_kan = new Map(); + lookup_epwing_kana = new Map(); + for (let i = 1; i < epwing.length; i++) + { + if(typeof epwing[i] === 'string' || epwing[i] instanceof String) + continue; + add_epwing_id(epwing[i]["r"], i); + for(let spelling of epwing[i]["s"]) + add_epwing_id(spelling, i); + } +} +refresh_epwing(); + function string_is_kana(str) { for(let i = 0; i < str.length; i++) @@ -22,10 +36,13 @@ function string_is_kana(str) if(!(codepoint >= 0x3040 && codepoint <= 0x30FF)) return false; } + return true; } function add_epwing_id(id, i) { + if(id === "") + return; if(string_is_kana(id)) { if (!lookup_epwing_kana.has(id)) @@ -42,45 +59,6 @@ function add_epwing_id(id, i) } } -// FIXME: this is almost certainly only the format of the kenkyuusha epwing dictionary. others might be completely different. -for (let i = 0; i < epwing.length; i++) -{ - let heading = epwing[i]["heading"]; - let text = epwing[i]["text"]; - if(heading.startsWith("¶")) - { - let id = heading.match(/¶([^<]*)/)[1].trim(); - // there's stuff inside the brackets but it doesn't represent this dictionary entry, just another one where it appears - add_epwing_id(id, i); - } - else if(heading.includes("<") && heading.includes("【")) - { - let useful = heading.match(/<(.*)>/)[1].trim(); - let kana = useful.match(/([^【]*)/)[1].trim(); - let kanji = useful.match(/【([^】]*)/)[1].trim(); - add_epwing_id(kanji, i); - add_epwing_id(kana, i); - } - else if(heading.includes("<") && !heading.includes("【")) - { - let kana = heading.match(/([^<]*)/)[1].trim(); - let kanji = heading.match(/<(.*)>/)[1].trim(); - add_epwing_id(kanji, i); - add_epwing_id(kana, i); - } - else if(text.split(/\\n/)[0].includes("【")) - { - let useful = text.match(/([^】]*】)/)[1].trim(); - let kana = useful.match(/([^【]*)/)[1].trim(); - let kanji = useful.match(/【([^】]*)/)[1].trim(); - add_epwing_id(kanji, i); - add_epwing_id(kana, i); - } - else - { - console.log(`Unknown kind of entry at index ${i} in epwing dictionary`); - } -} let dict = []; let lookup_kan = new Map(); @@ -851,14 +829,15 @@ function add_epwing_info(lookups) for(let entry of lookup.result) { // look for an epwing entry that matches this lookup and jmdict entry - let epwing_data = ""; + let epwing_data = undefined; let foundtext = undefined; if(entry.orig_found.keb) foundtext = entry.orig_found.keb; else foundtext = entry.orig_found.reb; - let exact = false; + let exact = 0; + // TODO: figure out which of these .includes() calls should be equality tests instead. definitely some of them, definitely not all of them. if(entry.k_ele) { for(let spelling of entry.k_ele) @@ -866,48 +845,104 @@ function add_epwing_info(lookups) let text = spelling.keb; if (lookup_epwing_kan.has(text)) { + console.log("looking for epwing possibilities"); let possibilities = lookup_epwing_kan.get(text); + // FIXME we want to try epwing matches in the order they match the epwing entry's spellings/readings instead of the order they're in in the map.get() return list for(let wing of possibilities) { - if(epwing[wing] && epwing[wing]["text"]) + console.log("checking an epwing possibility"); + if(epwing[wing] && epwing[wing]["l"]) { - if(epwing_data == "") + if(epwing_data == undefined) { - epwing_data = epwing[wing]["text"]; - // FIXME: using .includes() is too loose. just simpler than adding real arrays of spellings/readings to the epwing data on load. - exact = (epwing[wing]["heading"].includes(foundtext) || epwing[wing]["text"].includes(foundtext)); + epwing_data = epwing[wing]; + exact = epwing[wing]["r"].includes(foundtext); + for(let spelling of epwing[wing]["s"]) + exact |= spelling.includes(foundtext); + // FIXME duplicated + if(exact) + { + for(let reading of entry.r_ele) + { + let text = reading.reb; + if(epwing[wing]["r"].includes(text)) + exact = 2; + } + } } - else if(!exact && (epwing[wing]["heading"].includes(foundtext) || epwing[wing]["text"].includes(foundtext))) + else if(exact == 0) { - epwing_data = epwing[wing]["text"]; - exact = true; + exact |= epwing[wing]["r"].includes(foundtext); + for(let spelling of epwing[wing]["s"]) + exact |= spelling.includes(foundtext); + if(exact) + { + for(let reading of entry.r_ele) + { + let text = reading.reb; + if(epwing[wing]["r"].includes(text)) + exact = 2; + } + epwing_data = epwing[wing]; + } + } + else if(exact == 1) + { + let maybe_more_exact = epwing[wing]["r"].includes(foundtext); + for(let spelling of epwing[wing]["s"]) + maybe_more_exact |= spelling.includes(foundtext); + if(maybe_more_exact) + { + for(let reading of entry.r_ele) + { + let text = reading.reb; + if(epwing[wing]["r"].includes(text)) + { + exact = 2; + epwing_data = epwing[wing]; + } + } + } } } } } } } - if(epwing_data == "" && entry.r_ele) + if(epwing_data == undefined && entry.r_ele) { - for(let spelling of entry.r_ele) + for(let reading of entry.r_ele) { - let text = spelling.reb; + let text = reading.reb; + + console.log(`checking if lookup ${text} in structure`); if (lookup_epwing_kana.has(text)) { + console.log("looking for epwing possibilities"); let possibilities = lookup_epwing_kana.get(text); for(let wing of possibilities) { - if(epwing[wing] && epwing[wing]["text"]) + console.log("checking an epwing possibility"); + if(epwing[wing] && epwing[wing]["l"]) { - if(epwing_data == "") + if(epwing_data == undefined) { - epwing_data = epwing[wing]["text"]; - exact = (epwing[wing]["heading"].includes(foundtext) || epwing[wing]["text"].includes(foundtext)); + epwing_data = epwing[wing]; + exact = epwing[wing]["r"].includes(foundtext); } - else if(!exact && (epwing[wing]["heading"].includes(foundtext) || epwing[wing]["text"].includes(foundtext))) + else if(exact == 0) { - epwing_data = epwing[wing]["text"]; - exact = true; + exact |= epwing[wing]["r"].includes(foundtext); + if(exact) + epwing_data = epwing[wing]; + } + else if(exact == 1) + { + if(epwing[wing]["s"].length == 1 && epwing[wing]["s"][0] === "" && epwing[wing]["r"].includes(foundtext)) + { + exact = 2; + epwing_data = epwing[wing]; + } } } } @@ -915,6 +950,8 @@ function add_epwing_info(lookups) } } entry.epwing = epwing_data; + if(entry.epwing && (typeof epwing[0] === 'string' || epwing[0] instanceof String)) + entry.epwing["z"] = epwing[0]; } } return lookups; @@ -1522,6 +1559,10 @@ browser.runtime.onMessage.addListener((req, sender, sendResponse) => { clipboard_hook(sender.tab); } + else if (req.type == "refreshepwing") + { + refresh_epwing(); + } else { return; diff --git a/options.html b/options.html index f28e04a..475cc4e 100644 --- a/options.html +++ b/options.html @@ -17,6 +17,7 @@
+

About

This extension uses JMdict, which is Copyright © 2017 The Electronic Dictionary Research and Development Group and licensed under the CC BY-SA 3.0 license.

This extension is otherwise licensed under the Apache License, version 2.0.

Meanings of abbreviations follow. From JMdict. Some may be unused. Unsorted.

diff --git a/options.js b/options.js index 0749c7b..5ae1e11 100644 --- a/options.js +++ b/options.js @@ -164,6 +164,12 @@ function defaults() default: "", label: "Font override (highlighted text only) (without trailing comma)" }); + + // other (added procedurally) + settings.push({ + kind: "dummy", + label: "Other" + }); } defaults(); @@ -258,7 +264,6 @@ function buildpage() let label = document.createElement("label"); label.for = option.id; - label.className = "panel-formElements-item"; let labelText = document.createTextNode(option.label); if(option.kind == "checkbox") @@ -281,6 +286,39 @@ function buildpage() container.style.marginBottom = "8px"; optionsection.appendChild(container); } + let file = document.createElement("input"); + file.type = "file"; + file.id = "file"; + file.addEventListener("change", () => + { + let fname = document.querySelector("#file").files[0]; + let fr = new FileReader(); + fr.onload = (e) => + { + try + { + document.querySelector("#import_label").textContent = "Importing..."; + browser.storage.local.set({"epwing":JSON.parse(e.target.result)}); + browser.runtime.sendMessage({type:"refreshepwing"}); + document.querySelector("#import_label").textContent = "Imported. Might take a few seconds to apply."; + } + catch(e) + { + console.log(e); + } + }; + fr.readAsText(fname); + }); + let label = document.createElement("label"); + label.for = file.id; + label.id = "import_label"; + label.textContent = "Import thin dictionary"; + label.style.display = "block"; + + optionsection.appendChild(file); + optionsection.appendChild(label); + + optionsection.appendChild(document.createElement("hr")); } async function restoreOptions() diff --git a/texthook.js b/texthook.js index 03ae8d0..687ce6a 100644 --- a/texthook.js +++ b/texthook.js @@ -278,6 +278,8 @@ function build_div_inner (text, result) `.nazeka_main_keb{font-family: ${font}IPAGothic,TakaoGothic,Noto Sans CJK JP Regular,Meiryo,sans-serif;font-size:18px;color:${settings.hlcolor}}\ .nazeka_main_reb{font-family: ${font}IPAGothic,TakaoGothic,Noto Sans CJK JP Regular,Meiryo,sans-serif;font-size:18px;color:${settings.hlcolor}}\ .nazeka_original{float: right; margin-right: 2px; margin-left:4px; opacity:0.7;}\ +.epwing_head{margin: 6px 8px 4px;} +.epwing_definition{margin: 0 8px;}\ `; temp.appendChild(style); @@ -593,7 +595,39 @@ function build_div_inner (text, result) if(term.epwing) { definition.appendChild(document.createElement("br")); - definition.appendChild(document.createTextNode(term.epwing)); + let epwing_head = document.createElement("div"); + epwing_head.appendChild(document.createTextNode("―"+term.epwing["z"]+"―")); + epwing_head.appendChild(document.createElement("br")); + let epwing_head_text = term.epwing["r"]; + if(term.epwing["s"] && term.epwing["s"][0] != "") + { + let isfirst = true; + epwing_head_text += "【"; + for(let spelling of term.epwing["s"]) + { + if(!isfirst) + epwing_head_text += "・"; + epwing_head_text += spelling; + isfirst = false; + } + epwing_head_text += "】"; + } + epwing_head.appendChild(document.createTextNode(epwing_head_text)); + let epwing_definition = document.createElement("div"); + let isfirst = true; + for(let line of term.epwing["l"]) + { + if(!isfirst) + epwing_definition.appendChild(document.createElement("br")); + let def_line = document.createElement("span"); + def_line.textContent = line; + epwing_definition.appendChild(def_line); + isfirst = false; + } + epwing_head.className = "epwing_head"; + epwing_definition.className = "epwing_definition"; + definition.appendChild(epwing_head); + definition.appendChild(epwing_definition); } container.appendChild(definition); if(settings.corner == 2 || settings.corner == 3)