From 736d3c892ecb31b6aa658b0d8b0c5be757258062 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Thu, 30 Jul 2020 20:45:52 -0400 Subject: [PATCH] Dictionary data utility class (#698) * Create utility class for helping format dictionary data * Change format --- ext/bg/search.html | 1 + ext/fg/float.html | 1 + ext/mixed/js/dictionary-data-util.js | 101 +++++++++++++++++++++++++++ ext/mixed/js/display-generator.js | 39 ++--------- 4 files changed, 109 insertions(+), 33 deletions(-) create mode 100644 ext/mixed/js/dictionary-data-util.js diff --git a/ext/bg/search.html b/ext/bg/search.html index dd44b376..653a708f 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -83,6 +83,7 @@ + diff --git a/ext/fg/float.html b/ext/fg/float.html index 9d7fa4b4..427a7e57 100644 --- a/ext/fg/float.html +++ b/ext/fg/float.html @@ -55,6 +55,7 @@ + diff --git a/ext/mixed/js/dictionary-data-util.js b/ext/mixed/js/dictionary-data-util.js new file mode 100644 index 00000000..65ad51a1 --- /dev/null +++ b/ext/mixed/js/dictionary-data-util.js @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2020 Yomichan Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +class DictionaryDataUtil { + static getPitchAccentInfos(definition) { + const results = new Map(); + const allExpressions = new Set(); + const allReadings = new Set(); + const expressions = definition.expressions; + const sources = Array.isArray(expressions) ? expressions : [definition]; + + for (const {pitches: expressionPitches, expression} of sources) { + allExpressions.add(expression); + + for (const {reading, pitches, dictionary} of expressionPitches) { + allReadings.add(reading); + + let dictionaryResults = results.get(dictionary); + if (typeof dictionaryResults === 'undefined') { + dictionaryResults = []; + results.set(dictionary, dictionaryResults); + } + + for (const {position, tags} of pitches) { + let pitchAccentInfo = this._findExistingPitchAccentInfo(reading, position, tags, dictionaryResults); + if (pitchAccentInfo === null) { + pitchAccentInfo = {expressions: new Set(), reading, position, tags}; + dictionaryResults.push(pitchAccentInfo); + } + pitchAccentInfo.expressions.add(expression); + } + } + } + + const multipleReadings = (allReadings.size > 1); + for (const dictionaryResults of results.values()) { + for (const result of dictionaryResults) { + const exclusiveExpressions = []; + const exclusiveReadings = []; + const resultExpressions = result.expressions; + if (!areSetsEqual(resultExpressions, allExpressions)) { + exclusiveExpressions.push(...getSetIntersection(resultExpressions, allExpressions)); + } + if (multipleReadings) { + exclusiveReadings.push(result.reading); + } + result.expressions = [...resultExpressions]; + result.exclusiveExpressions = exclusiveExpressions; + result.exclusiveReadings = exclusiveReadings; + } + } + + const results2 = []; + for (const [dictionary, pitches] of results.entries()) { + results2.push({dictionary, pitches}); + } + return results2; + } + + static _findExistingPitchAccentInfo(reading, position, tags, pitchAccentInfoList) { + for (const pitchInfo of pitchAccentInfoList) { + if ( + pitchInfo.reading === reading && + pitchInfo.position === position && + this._areTagListsEqual(pitchInfo.tags, tags) + ) { + return pitchInfo; + } + } + return null; + } + + static _areTagListsEqual(tagList1, tagList2) { + const ii = tagList1.length; + if (tagList2.length !== ii) { return false; } + + for (let i = 0; i < ii; ++i) { + const tag1 = tagList1[i]; + const tag2 = tagList2[i]; + if (tag1.name !== tag2.name || tag1.dictionary !== tag2.dictionary) { + return false; + } + } + + return true; + } +} diff --git a/ext/mixed/js/display-generator.js b/ext/mixed/js/display-generator.js index 3f3a155e..276b37de 100644 --- a/ext/mixed/js/display-generator.js +++ b/ext/mixed/js/display-generator.js @@ -16,6 +16,7 @@ */ /* global + * DictionaryDataUtil * TemplateHandler * api * jp @@ -46,8 +47,8 @@ class DisplayGenerator { const {termTags, expressions, definitions} = details; - const pitches = this._getPitchInfos(details); - const pitchCount = pitches.reduce((i, v) => i + v[1].length, 0); + const pitches = DictionaryDataUtil.getPitchAccentInfos(details); + const pitchCount = pitches.reduce((i, v) => i + v.pitches.length, 0); const expressionMulti = Array.isArray(expressions); const definitionMulti = Array.isArray(definitions); @@ -363,18 +364,18 @@ class DisplayGenerator { document.head.appendChild(t); } - const [dictionary, dictionaryPitches] = details; + const {dictionary, pitches} = details; const node = this._templateHandler.instantiate('term-pitch-accent-group'); node.dataset.dictionary = dictionary; node.dataset.pitchesMulti = 'true'; - node.dataset.pitchesCount = `${dictionaryPitches.length}`; + node.dataset.pitchesCount = `${pitches.length}`; const tag = this._createTag({notes: '', name: dictionary, category: 'pitch-accent-dictionary'}); node.querySelector('.term-pitch-accent-group-tag-list').appendChild(tag); const n = node.querySelector('.term-pitch-accent-list'); - this._appendMultiple(n, this._createPitch.bind(this), dictionaryPitches); + this._appendMultiple(n, this._createPitch.bind(this), pitches); return node; } @@ -615,32 +616,4 @@ class DisplayGenerator { return [...results.entries()]; } - - _findExistingPitchInfo(reading, position, tags, pitchInfoList) { - for (const pitchInfo of pitchInfoList) { - if ( - pitchInfo.reading === reading && - pitchInfo.position === position && - this._areTagListsEqual(pitchInfo.tags, tags) - ) { - return pitchInfo; - } - } - return null; - } - - _areTagListsEqual(tagList1, tagList2) { - const ii = tagList1.length; - if (tagList2.length !== ii) { return false; } - - for (let i = 0; i < ii; ++i) { - const tag1 = tagList1[i]; - const tag2 = tagList2[i]; - if (tag1.name !== tag2.name || tag1.dictionary !== tag2.dictionary) { - return false; - } - } - - return true; - } }