From 74d808bc84c637c646b6f7df2a3eb3a015521fff Mon Sep 17 00:00:00 2001 From: wareya Date: Sat, 2 Feb 2019 12:31:19 -0500 Subject: [PATCH] minor json dictionary overhaul --- background-script.js | 292 +++++++++++++++++++------------------------ options.js | 17 ++- readme.md | 4 +- texthook.js | 290 +++++++++++++++++++++++++----------------- 4 files changed, 317 insertions(+), 286 deletions(-) diff --git a/background-script.js b/background-script.js index 17c1737..729b1dc 100644 --- a/background-script.js +++ b/background-script.js @@ -64,43 +64,31 @@ async function refresh_epwing() { if(typeof epwing[i] === 'string' || epwing[i] instanceof String) continue; - add_epwing_id(epwing[i]["r"], i); + add_epwing_reading(epwing[i]["r"], i); for(let spelling of epwing[i]["s"]) - add_epwing_id(spelling, i); + add_epwing_spelling(spelling, i); } } } refresh_epwing(); -function string_is_kana(str) +function add_epwing_reading(text, id) { - for(let i = 0; i < str.length; i++) - { - let codepoint = str.codePointAt(i); - if(!(codepoint >= 0x3040 && codepoint <= 0x30FF)) - return false; - } - return true; -} - -function add_epwing_id(id, i) -{ - if(id === "") + if(text === "") return; - if(string_is_kana(id)) - { - if (!lookup_epwing_kana.has(id)) - lookup_epwing_kana.set(id, [i]); - else - lookup_epwing_kana.get(id).push(i); - } + if (!lookup_epwing_kana.has(text)) + lookup_epwing_kana.set(text, [id]); else - { - if (!lookup_epwing_kan.has(id)) - lookup_epwing_kan.set(id, [i]); - else - lookup_epwing_kan.get(id).push(i); - } + lookup_epwing_kana.get(text).push(id); +} +function add_epwing_spelling(text, id) +{ + if(text === "") + return; + if (!lookup_epwing_kan.has(text)) + lookup_epwing_kan.set(text, [id]); + else + lookup_epwing_kan.get(text).push(id); } @@ -670,7 +658,53 @@ function build_lookup_comb(forms) return; } -function add_epwing_info(lookups) +function epwing_lookup_kanji(spelling_list, readings, inexact) +{ + let indexes_set = new Set(); + let indexes = []; + for(let spelling of spelling_list) + { + let possibilities = lookup_epwing_kan.get(spelling); + if(!possibilities) + continue; + for(let id of lookup_epwing_kan.get(spelling)) + { + if(inexact || readings.includes(epwing[id]["r"])) + { + if(!indexes_set.has(id)) + { + indexes_set.add(id); + indexes.push(id); + } + } + } + } + return indexes; +} + +function epwing_lookup_kana_exact(kana) +{ + let possibilities = lookup_epwing_kana.get(kana); + if(!possibilities) + return []; + let actual_possibilities = []; + for(let wing of possibilities) + { + let spellings = epwing[wing]["s"] + if(spellings.length == 1 && spellings[0] === "") + actual_possibilities.push(wing); + } + return actual_possibilities; +} +function epwing_lookup_kana_inexact(kana) +{ + let possibilities = copy_gen(lookup_epwing_kana.get(kana)); + if(!possibilities) + return []; + return possibilities; +} + +function add_epwing_info(lookups, strict_epwing) { for(let lookup of lookups) { @@ -684,139 +718,67 @@ function add_epwing_info(lookups) else foundtext = entry.orig_found.reb; - 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) { + let spellings = []; for(let spelling of entry.k_ele) - { - let text = spelling.keb; - if (lookup_epwing_kan.has(text)) - { - let possibilities = copy_gen(lookup_epwing_kan.get(text)); - - // FIXME this is disgusting - let priority = []; - for(let reading of entry.r_ele) - { - let rtext = reading.reb; - for(let wing of possibilities) - { - if(epwing[wing]["r"] === rtext) - priority.push(wing); - } - } - for(let wing of priority) - { - var index = possibilities.indexOf(wing); - if (index > -1) - possibilities.splice(index, 1); - } - possibilities = priority.concat(possibilities); - priority = []; - - for(let wing of possibilities) - { - let epw = copy(epwing[wing]); - if(epw && epw["l"]) - { - if(epwing_data == undefined) - { - epwing_data = epw; - exact = epw["r"].includes(foundtext); - for(let spelling of epw["s"]) - exact |= spelling.includes(foundtext); - // FIXME duplicated below - if(exact) - { - for(let reading of entry.r_ele) - { - let rtext = reading.reb; - if(epw["r"].includes(rtext)) - exact = 2; - } - } - } - else if(exact == 0) - { - exact |= epw["r"].includes(foundtext); - for(let spelling of epw["s"]) - exact |= spelling.includes(foundtext); - if(exact) - { - for(let reading of entry.r_ele) - { - let rtext = reading.reb; - if(epw["r"].includes(rtext)) - exact = 2; - } - epwing_data = epw; - } - } - else if(exact == 1) - { - let maybe_more_exact = epw["r"].includes(foundtext); - for(let spelling of epw["s"]) - maybe_more_exact |= spelling.includes(foundtext); - if(maybe_more_exact) - { - for(let reading of entry.r_ele) - { - let text = reading.reb; - if(epw["r"].includes(text)) - { - exact = 2; - epwing_data = epw; - } - } - } - } - } - } - } - } - } - if(epwing_data == undefined && entry.r_ele) - { + spellings.push(spelling.keb); + let readings = []; for(let reading of entry.r_ele) + readings.push(reading.reb); + + // try exact matches + // lookup + let possibilities = epwing_lookup_kanji([lookup.text], readings, false); + // main spelling + if(possibilities.length == 0) + possibilities = epwing_lookup_kanji([foundtext], readings, false); + // all possible spellings + if(possibilities.length == 0) + possibilities = epwing_lookup_kanji(spellings, readings, false); + // try inexact matches + if(!strict_epwing) { - let text = reading.reb; - - if (lookup_epwing_kana.has(text)) + if(possibilities.length == 0) + possibilities = epwing_lookup_kanji([lookup.text], readings, true); + if(possibilities.length == 0) + possibilities = epwing_lookup_kanji([foundtext], readings, true); + if(possibilities.length == 0) + possibilities = epwing_lookup_kanji(spellings, readings, true); + } + if(possibilities.length > 0) + epwing_data = copy(epwing[possibilities[0]]); + } + else + { + let possibilities = epwing_lookup_kana_exact(foundtext); + if(!strict_epwing) + { + for(let reading of entry.r_ele) { - let possibilities = copy_gen(lookup_epwing_kana.get(text)); - for(let wing of possibilities) - { - let epw = copy(epwing[wing]); - if(epw && epw["l"]) - { - if(epwing_data == undefined) - { - epwing_data = epw; - exact = epw["r"].includes(foundtext); - } - else if(exact == 0) - { - exact |= epw["r"].includes(foundtext); - if(exact) - epwing_data = epw; - } - else if(exact == 1) - { - if(epw["s"].length == 1 && epw["s"][0] === "" && epw["r"].includes(foundtext)) - { - exact = 2; - epwing_data = epw; - } - } - } - } + if(possibilities.length == 0) + possibilities = epwing_lookup_kana_exact(reading); + } + if(possibilities.length == 0) + possibilities = epwing_lookup_kana_inexact(foundtext); + for(let reading of entry.r_ele) + { + if(possibilities.length == 0) + possibilities = epwing_lookup_kana_inexact(reading); } } + if(possibilities.length > 0) + epwing_data = copy(epwing[possibilities[0]]); + } + + if(epwing_data) + { + // add dictionary title + if(epwing_data && (typeof epwing[0] === 'string' || epwing[0] instanceof String)) + epwing_data["z"] = epwing[0]; + // add to lookup + entry.epwing = epwing_data; } - entry.epwing = epwing_data; - if(entry.epwing && (typeof epwing[0] === 'string' || epwing[0] instanceof String)) - entry.epwing["z"] = epwing[0]; } } return lookups; @@ -1158,7 +1120,7 @@ function restrict_by_text(entry, text) return term; } -function add_extra_info(results) +function add_extra_info(results, strict_epwing) { for(let lookup of results) { @@ -1191,11 +1153,11 @@ function add_extra_info(results) } } } - return add_epwing_info(results); + return add_epwing_info(results, strict_epwing); } // Skip JMdict entries reappearing in alternative lookups (so only the first one is shown) -function skip_rereferenced_entries(results) +function skip_rereferenced_entries(results, strict_epwing) { let newresults = []; let seenseq = new Set(); @@ -1213,12 +1175,12 @@ function skip_rereferenced_entries(results) if(newlookup.length > 0) newresults.push({text:lookup.text, result:newlookup}); } - return add_extra_info(newresults); // add extra information like epwing results and audio data now + return add_extra_info(newresults, strict_epwing); // add extra information like epwing results and audio data now } let last_lookup = ""; let last_time_lookup = Date.now(); -function lookup_indirect(text, time, divexisted, alternatives_mode, strict_alternatives) +function lookup_indirect(text, time, divexisted, alternatives_mode, strict_alternatives, strict_epwing) { if(text == "") return; @@ -1247,7 +1209,7 @@ function lookup_indirect(text, time, divexisted, alternatives_mode, strict_alter { result = sort_results(text, result); if(alternatives_mode == 0 || text.length <= 1) - return skip_rereferenced_entries([{text:text, result:result}]); + return skip_rereferenced_entries([{text:text, result:result}], strict_epwing); else if(alternatives_mode == 1) // second longest too { let len = text.length-1; @@ -1267,10 +1229,10 @@ function lookup_indirect(text, time, divexisted, alternatives_mode, strict_alter if(short_result !== undefined && short_result.length > 0) { short_result = sort_results(short_text, short_result); - return skip_rereferenced_entries([{text:text, result:result}, {text:short_text, result:short_result}]); + return skip_rereferenced_entries([{text:text, result:result}, {text:short_text, result:short_result}], strict_epwing); } else - return skip_rereferenced_entries([{text:text, result:result}]); + return skip_rereferenced_entries([{text:text, result:result}], strict_epwing); } else if(alternatives_mode == 2) // shortest too { @@ -1291,10 +1253,10 @@ function lookup_indirect(text, time, divexisted, alternatives_mode, strict_alter if(short_result !== undefined && short_result.length > 0) { short_result = sort_results(short_text, short_result); - return skip_rereferenced_entries([{text:text, result:result}, {text:short_text, result:short_result}]); + return skip_rereferenced_entries([{text:text, result:result}, {text:short_text, result:short_result}], strict_epwing); } else - return skip_rereferenced_entries([{text:text, result:result}]); + return skip_rereferenced_entries([{text:text, result:result}], strict_epwing); } } } @@ -1320,7 +1282,7 @@ function lookup_indirect(text, time, divexisted, alternatives_mode, strict_alter first = false; } if(results.length > 0) - return skip_rereferenced_entries(results); + return skip_rereferenced_entries(results, strict_epwing); } } @@ -1460,7 +1422,7 @@ browser.runtime.onMessage.addListener((req, sender) => { if (req.type == "search") { - let asdf = lookup_indirect(req.text, req.time, req.divexisted, req.alternatives_mode, req.strict_alternatives); + let asdf = lookup_indirect(req.text, req.time, req.divexisted, req.alternatives_mode, req.strict_alternatives, req.strict_epwing); return Promise.resolve({"response" : asdf}); } else if (req.type == "platform") diff --git a/options.js b/options.js index 058e702..875c2c1 100644 --- a/options.js +++ b/options.js @@ -67,6 +67,19 @@ function defaults() default: true, label: "Strict matching for alternative matches" }); + settings.push({ + id: "definitions_mode", + kind: "combobox", + options: ["From jmdict then json", "From json then jmdict", "From json; otherwise jmdict", "From json dictionary only", "None"], + default: 0, + label: "Where to look for definitions (does not affect jmdict readings)" + }); + settings.push({ + id: "strict_epwing", + kind: "checkbox", + default: true, + label: "Strict matching for json dictionary matches" + }); settings.push({ id: "popup_requires_key", kind: "combobox", @@ -494,7 +507,7 @@ function buildpage() browser.storage.local.set({"deconjugator_rules_json":""}); else browser.storage.local.set({"deconjugator_rules_json":JSON.stringify(JSON.parse())}); - document.querySelector("decon_label").textContent = "Imported. Might take a few seconds to apply."; + document.querySelector("#decon_label").textContent = "Imported. Might take a few seconds to apply."; } catch(except) { @@ -505,7 +518,7 @@ function buildpage() }); let decon_label = document.createElement("label"); decon_label.for = decon_file.id; - decon_label.id = "import_label"; + decon_label.id = "decon_label"; decon_label.textContent = "Import deconjugation ruleset. Overrides default deconjugation ruleset. Importing a blank file will restore the default ruleset."; decon_label.style.display = "block"; diff --git a/readme.md b/readme.md index 6e15519..78184ee 100644 --- a/readme.md +++ b/readme.md @@ -1,8 +1,8 @@ Nazeka is a rikai replacement. -***Nazeka is not ready for general use yet; it does not yet have all the necessary behaviors that rikai variants have.*** +Nazeka was the first nontrivial thing I wrote in Javascript. The code is terrible and a lot of it is bundled into a small number of files. I need help splitting it up into multiple files, or being told how to split it up into multiple first without requiring any build tools. -My code here is terrible, but at least we can all agree that Javascript is a terrible language. +***Nazeka is not ready for general use yet; it does not yet have all the necessary behaviors that rikai variants have.*** # Options diff --git a/texthook.js b/texthook.js index afc3677..9e9e6b7 100644 --- a/texthook.js +++ b/texthook.js @@ -24,6 +24,8 @@ superborder: false, showoriginal: true, alternatives_mode: 0, // 0: longest only; 1: longest and shortest; 2: longest and second longest; 3: all matches strict_alternatives: true, // if true, alternatives looked up in all kana can not return results with kanji glosses that don't have any usually/exclusively kana info +definitions_mode: 0, +strict_epwing: true, scale: 1, width: 600, lookuprate: 8, @@ -400,6 +402,139 @@ function clip(str) return str.substring(1, str.length-1); } +function elementize_jmdict_defs(goodsenses) +{ + let lastpos = []; + let jmdict_defs = document.createElement("div"); + jmdict_defs.className = "jmdict_definitions"; + for(let j = 0; j < goodsenses.length; j++) + { + let sense = goodsenses[j]; + + if(sense.pos == lastpos) + sense.pos = undefined; + else + lastpos = sense.pos; + + if(sense.pos) + { + let part = document.createElement("span"); + part.className = "nazeka_pos"; + let temptext = "("; + let parts = []; + for(let l = 0; l < sense.pos.length; l++) + parts.push(sense.pos[l]); + temptext += parts.join(", "); + temptext += ")"; + part.textContent = temptext; + jmdict_defs.appendChild(part); + if(settings.compact) + jmdict_defs.appendChild(document.createTextNode(" ")); + else + jmdict_defs.appendChild(document.createElement("br")); + + } + if(settings.compact) + { + if(goodsenses.length > 1) + { + let number = document.createElement("span"); + number.className = "nazeka_num"; + number.textContent = "("+(j+1)+")"; + jmdict_defs.appendChild(number); + jmdict_defs.appendChild(document.createTextNode(" ")); + } + } + else + { + let temptag = document.createElement("span"); + temptag.className = "nazeka_num"; + temptag.textContent = ""+(j+1)+"."; + jmdict_defs.appendChild(temptag); + jmdict_defs.appendChild(document.createTextNode(" ")); + } + if(sense.inf) + { + let info = document.createElement("i"); + info.textContent = "("+sense.inf+") "; + jmdict_defs.appendChild(info); + } + if(sense.misc) + { + let temptag = document.createElement("span"); + temptag.className = "nazeka_misc"; + let temptext = "("; + let parts = []; + for(let l = 0; l < sense.misc.length; l++) + parts.push(sense.misc[l].substring(1, sense.misc[l].length-1)); + temptext += parts.join(", "); + temptext += ")"; + temptag.textContent = temptext; + jmdict_defs.appendChild(temptag); + jmdict_defs.appendChild(document.createTextNode(" ")); + } + jmdict_defs.appendChild(document.createTextNode(sense.gloss.join("; "))); + if(settings.compact) + { + if(sense.gloss.length > 1 || j+1 != goodsenses.length) + jmdict_defs.appendChild(document.createTextNode("; ")); + } + else + { + jmdict_defs.appendChild(document.createElement("br")); + } + } + return jmdict_defs; +} +function elementize_epwing_defs(epwing) +{ + if(epwing) + { + let epwing_defs = document.createElement("div"); + epwing_defs.className = "epwing_definitions"; + + let epwing_head = document.createElement("div"); + epwing_head.appendChild(document.createTextNode("―"+epwing["z"]+"―")); + epwing_head.appendChild(document.createElement("br")); + let epwing_head_text = epwing["r"]; + if(epwing["s"] && epwing["s"][0] != "") + { + let isfirst = true; + epwing_head_text += "【"; + for(let spelling of 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 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"; + epwing_defs.appendChild(epwing_head); + epwing_defs.appendChild(epwing_definition); + + return epwing_defs; + } + else + { + return undefined; + } +} + // Here we actually build the content of the lookup popup, based on the text we looked up and the list of lookups from the background script // note that we can get multiple lookups and this function only handles a single lookup function build_div_inner(text, result, moreText, index, first_of_many = false) @@ -514,8 +649,9 @@ function build_div_inner(text, result, moreText, index, first_of_many = false) .nazeka_sub_keb{font-size:${settings.reading_fontsize}px;white-space:nowrap;font-family: ${font}IPAGothic,TakaoGothic,Noto Sans CJK JP Regular,Meiryo,sans-serif} .nazeka_sub_reb{font-size:${settings.reading_fontsize}px;white-space:nowrap;color:${settings.hlcolor2}} .nazeka_original{float: right; margin-right: 2px; margin-left:4px; opacity:0.7;} -.epwing_head{margin: 6px 8px 4px;} -.epwing_definition{margin: 0 8px;} +.epwing_head{margin: 0 4px 6px;} +.jmdict_definitions{margin: 0 4px 6px;} +.epwing_definition{margin: 0 4px 6px;} `; temp.appendChild(style); @@ -684,8 +820,6 @@ function build_div_inner(text, result, moreText, index, first_of_many = false) if(term.deconj) { - console.log(term.deconj); - let deconj = ""; let first = true; for(let form of term.deconj) @@ -733,7 +867,6 @@ function build_div_inner(text, result, moreText, index, first_of_many = false) temptag.appendChild(main_reb); if(term.deconj) { - console.log(term.deconj); let deconj = ""; let first = true; for(let form of term.deconj) @@ -815,125 +948,45 @@ function build_div_inner(text, result, moreText, index, first_of_many = false) container.appendChild(temptag); container.appendChild(document.createElement("br")); - let goodsenses = term.sense; - - let lastpos = []; let definition = document.createElement("div"); definition.className = "nazeka_definitions"; - for(let j = 0; j < goodsenses.length; j++) + + let jmdict_div = elementize_jmdict_defs(term.sense); + let epwing_div = elementize_epwing_defs(term.epwing); + + if (settings.definitions_mode == 0) // normal { - let sense = goodsenses[j]; - - if(sense.pos == lastpos) - sense.pos = undefined; - else - lastpos = sense.pos; - - if(sense.pos) + if(jmdict_div) definition.appendChild(jmdict_div); + if(epwing_div) definition.appendChild(epwing_div); + } + else if (settings.definitions_mode == 1) // epwing first + { + if(epwing_div) definition.appendChild(epwing_div); + if(jmdict_div) { - let part = document.createElement("span"); - part.className = "nazeka_pos"; - let temptext = "("; - let parts = []; - for(let l = 0; l < sense.pos.length; l++) - parts.push(sense.pos[l]); - temptext += parts.join(", "); - temptext += ")"; - part.textContent = temptext; - definition.appendChild(part); - if(settings.compact) - definition.appendChild(document.createTextNode(" ")); - else - definition.appendChild(document.createElement("br")); - - } - if(settings.compact) - { - if(goodsenses.length > 1) - { - let number = document.createElement("span"); - number.className = "nazeka_num"; - number.textContent = "("+(j+1)+")"; - definition.appendChild(number); - definition.appendChild(document.createTextNode(" ")); - } - } - else - { - let temptag = document.createElement("span"); - temptag.className = "nazeka_num"; - temptag.textContent = ""+(j+1)+"."; - definition.appendChild(temptag); - definition.appendChild(document.createTextNode(" ")); - } - if(sense.inf) - { - let info = document.createElement("i"); - info.textContent = "("+sense.inf+") "; - definition.appendChild(info); - } - if(sense.misc) - { - let temptag = document.createElement("span"); - temptag.className = "nazeka_misc"; - let temptext = "("; - let parts = []; - for(let l = 0; l < sense.misc.length; l++) - parts.push(sense.misc[l].substring(1, sense.misc[l].length-1)); - temptext += parts.join(", "); - temptext += ")"; - temptag.textContent = temptext; - definition.appendChild(temptag); - definition.appendChild(document.createTextNode(" ")); - } - definition.appendChild(document.createTextNode(sense.gloss.join("; "))); - if(settings.compact) - { - if(sense.gloss.length > 1 || j+1 != goodsenses.length) - definition.appendChild(document.createTextNode("; ")); - } - else - { - definition.appendChild(document.createElement("br")); + jmdict_div.insertBefore(document.createTextNode("jmdict: "), jmdict_div.firstChild); + definition.appendChild(jmdict_div); } } - if(term.epwing) + else if (settings.definitions_mode == 2) // epwing or else jmdict { - definition.appendChild(document.createElement("br")); - 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); + if(epwing_div) definition.appendChild(epwing_div); + else definition.appendChild(jmdict_div); } + else if (settings.definitions_mode == 3) // epwing only + { + if(epwing_div) definition.appendChild(epwing_div); + } + else if (settings.definitions_mode == 4) // none + { + + } + else // normal (fallback) + { + if(jmdict_div) definition.appendChild(jmdict_div); + if(epwing_div) definition.appendChild(epwing_div); + } + container.appendChild(definition); if(settings.corner == 2 || settings.corner == 3) { @@ -1017,6 +1070,8 @@ async function settings_init() getvar("alternatives_mode", 0); getvar("strict_alternatives", true); + getvar("definitions_mode", 0); + getvar("strict_epwing", true); getvar("corner", 0); getvar("xoffset", 5); @@ -1086,7 +1141,8 @@ async function send_lookup(lookup) time:Date.now(), divexisted:exists_div(), alternatives_mode:settings.alternatives_mode, - strict_alternatives:settings.strict_alternatives + strict_alternatives:settings.strict_alternatives, + strict_epwing:settings.strict_epwing }); if(response) response = response["response"];