diff options
Diffstat (limited to 'ext/js/language')
| -rw-r--r-- | ext/js/language/translator.js | 104 | 
1 files changed, 102 insertions, 2 deletions
| diff --git a/ext/js/language/translator.js b/ext/js/language/translator.js index d416d405..bf2c7322 100644 --- a/ext/js/language/translator.js +++ b/ext/js/language/translator.js @@ -85,13 +85,14 @@ class Translator {       *         priority: (number),       *         allowSecondarySearches: (boolean)       *       } -     *     ]) +     *     ]), +     *     excludeDictionaryDefinitions: (Set of (string) or null)       *   }       * ```       * @returns An object of the structure `{dictionaryEntries, originalTextLength}`.       */      async findTerms(mode, text, options) { -        const {enabledDictionaryMap} = options; +        const {enabledDictionaryMap, excludeDictionaryDefinitions} = options;          let {dictionaryEntries, originalTextLength} = await this._findTermsInternal(text, enabledDictionaryMap, options);          switch (mode) { @@ -103,6 +104,10 @@ class Translator {                  break;          } +        if (excludeDictionaryDefinitions !== null) { +            this._removeExcludedDefinitions(dictionaryEntries, excludeDictionaryDefinitions); +        } +          if (dictionaryEntries.length > 1) {              this._sortTermDictionaryEntries(dictionaryEntries);          } @@ -492,6 +497,101 @@ class Translator {          return newDictionaryEntries;      } +    _removeExcludedDefinitions(dictionaryEntries, excludeDictionaryDefinitions) { +        for (let i = dictionaryEntries.length - 1; i >= 0; --i) { +            const dictionaryEntry = dictionaryEntries[i]; +            const {definitions, pronunciations, frequencies, headwords} = dictionaryEntry; +            const definitionsChanged = this._removeArrayItemsWithDictionary(definitions, excludeDictionaryDefinitions); +            this._removeArrayItemsWithDictionary(pronunciations, excludeDictionaryDefinitions); +            this._removeArrayItemsWithDictionary(frequencies, excludeDictionaryDefinitions); +            this._removeTagGroupsWithDictionary(definitions, excludeDictionaryDefinitions); +            this._removeTagGroupsWithDictionary(headwords, excludeDictionaryDefinitions); + +            if (!definitionsChanged) { continue; } + +            if (definitions.length === 0) { +                dictionaryEntries.splice(i, 1); +            } else { +                this._removeUnusedHeadwords(dictionaryEntry); +            } +        } +    } + +    _removeUnusedHeadwords(dictionaryEntry) { +        const {definitions, pronunciations, frequencies, headwords} = dictionaryEntry; +        const removeHeadwordIndices = new Set(); +        for (let i = 0, ii = headwords.length; i < ii; ++i) { +            removeHeadwordIndices.add(i); +        } +        for (const {headwordIndices} of definitions) { +            for (const headwordIndex of headwordIndices) { +                removeHeadwordIndices.delete(headwordIndex); +            } +        } + +        if (removeHeadwordIndices.size === 0) { return; } + +        const indexRemap = new Map(); +        let oldIndex = 0; +        for (let i = 0, ii = headwords.length; i < ii; ++i) { +            if (removeHeadwordIndices.has(i)) { +                headwords.splice(i, 1); +                --i; +                --ii; +            } else { +                indexRemap.set(oldIndex, indexRemap.size); +            } +            ++oldIndex; +        } + +        this._updateDefinitionHeadwordIndices(definitions, indexRemap); +        this._updateArrayItemsHeadwordIndex(pronunciations, indexRemap); +        this._updateArrayItemsHeadwordIndex(frequencies, indexRemap); +    } + +    _updateDefinitionHeadwordIndices(definitions, indexRemap) { +        for (const {headwordIndices} of definitions) { +            for (let i = headwordIndices.length - 1; i >= 0; --i) { +                const newHeadwordIndex = indexRemap.get(headwordIndices[i]); +                if (typeof newHeadwordIndex === 'undefined') { +                    headwordIndices.splice(i, 1); +                } else { +                    headwordIndices[i] = newHeadwordIndex; +                } +            } +        } +    } + +    _updateArrayItemsHeadwordIndex(array, indexRemap) { +        for (let i = array.length - 1; i >= 0; --i) { +            const item = array[i]; +            const {headwordIndex} = item; +            const newHeadwordIndex = indexRemap.get(headwordIndex); +            if (typeof newHeadwordIndex === 'undefined') { +                array.splice(i, 1); +            } else { +                item.headwordIndex = newHeadwordIndex; +            } +        } +    } + +    _removeArrayItemsWithDictionary(array, excludeDictionaryDefinitions) { +        let changed = false; +        for (let j = array.length - 1; j >= 0; --j) { +            const {dictionary} = array[j]; +            if (!excludeDictionaryDefinitions.has(dictionary)) { continue; } +            array.splice(j, 1); +            changed = true; +        } +        return changed; +    } + +    _removeTagGroupsWithDictionary(array, excludeDictionaryDefinitions) { +        for (const {tags} of array) { +            this._removeArrayItemsWithDictionary(tags, excludeDictionaryDefinitions); +        } +    } +      // Tags      _getTermTagTargets(dictionaryEntries) { |