From 41020289ab68ef22a0691a9f268a79d6a706df6b Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sun, 3 Nov 2019 05:08:57 +0200 Subject: add mecab support --- ext/bg/js/mecab.js | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 ext/bg/js/mecab.js (limited to 'ext/bg/js/mecab.js') diff --git a/ext/bg/js/mecab.js b/ext/bg/js/mecab.js new file mode 100644 index 00000000..dc46ded2 --- /dev/null +++ b/ext/bg/js/mecab.js @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019 Alex Yatskov + * Author: Alex Yatskov + * + * 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 Mecab { + constructor() { + this.listeners = {}; + this.sequence = 0; + this.startListener(); + } + + async parseText(text) { + return await this.invoke('parse_text', {text}); + } + + startListener() { + this.port = chrome.runtime.connectNative('mecab'); + this.port.onMessage.addListener((message) => { + const {sequence, data} = message; + const {callback, timer} = this.listeners[sequence] || {}; + if (timer) { + clearTimeout(timer); + delete this.listeners[sequence]; + callback(data); + } + }); + } + + invoke(action, params) { + return new Promise((resolve, reject) => { + const sequence = this.sequence++; + + this.listeners[sequence] = { + callback: (data) => { + resolve(data); + }, + timer: setTimeout(() => { + delete this.listeners[sequence]; + reject(`Mecab invoke timed out in ${Mecab.timeout} ms`); + }, 1000) + } + + this.port.postMessage({action, params, sequence}); + }); + } +} + +Mecab.timeout = 1000; -- cgit v1.2.3 From b0c924d4bdaa0a606a6b559701047283ec0ff1db Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sun, 3 Nov 2019 17:06:02 +0200 Subject: fix mecab variable --- ext/bg/js/mecab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/bg/js/mecab.js') diff --git a/ext/bg/js/mecab.js b/ext/bg/js/mecab.js index dc46ded2..d28d80c0 100644 --- a/ext/bg/js/mecab.js +++ b/ext/bg/js/mecab.js @@ -52,7 +52,7 @@ class Mecab { timer: setTimeout(() => { delete this.listeners[sequence]; reject(`Mecab invoke timed out in ${Mecab.timeout} ms`); - }, 1000) + }, Mecab.timeout) } this.port.postMessage({action, params, sequence}); -- cgit v1.2.3 From 1bf48d24ef4a0a1ed09d8ec6acc74ff5f78dd6c2 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Mon, 4 Nov 2019 01:25:32 +0200 Subject: change mecab path https://github.com/siikamiika/yomichan-mecab-installer --- ext/bg/js/mecab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/bg/js/mecab.js') diff --git a/ext/bg/js/mecab.js b/ext/bg/js/mecab.js index d28d80c0..14f68393 100644 --- a/ext/bg/js/mecab.js +++ b/ext/bg/js/mecab.js @@ -29,7 +29,7 @@ class Mecab { } startListener() { - this.port = chrome.runtime.connectNative('mecab'); + this.port = chrome.runtime.connectNative('yomichan_mecab'); this.port.onMessage.addListener((message) => { const {sequence, data} = message; const {callback, timer} = this.listeners[sequence] || {}; -- cgit v1.2.3 From 955e131f9673e006556bc2c5e0b3551a614ccc48 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Tue, 5 Nov 2019 15:56:45 +0200 Subject: add parser selection options --- ext/bg/js/api.js | 37 +++++++++++++++++++++---------------- ext/bg/js/mecab.js | 2 +- ext/bg/js/options.js | 5 +++++ ext/bg/js/search-query-parser.js | 40 +++++++++++++++++++++++++--------------- ext/bg/js/settings.js | 6 ++++++ ext/bg/settings.html | 29 +++++++++++++++++++++++++++++ 6 files changed, 87 insertions(+), 32 deletions(-) (limited to 'ext/bg/js/mecab.js') diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index 2ab01af3..967bded7 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -109,25 +109,30 @@ async function apiTextParseMecab(text, optionsContext) { const options = await apiOptionsGet(optionsContext); const mecab = utilBackend().mecab; - const results = []; - for (const parsedLine of await mecab.parseText(text)) { - for (const {expression, reading, source} of parsedLine) { - const term = []; - if (expression && reading) { - for (const {text, furigana} of jpDistributeFuriganaInflected( - expression, - jpKatakanaToHiragana(reading), - source - )) { - // can't use 'furigana' in templates - term.push({text, reading: furigana}); + const results = {}; + const rawResults = await mecab.parseText(text); + for (const mecabName in rawResults) { + const result = []; + for (const parsedLine of rawResults[mecabName]) { + for (const {expression, reading, source} of parsedLine) { + const term = []; + if (expression && reading) { + for (const {text, furigana} of jpDistributeFuriganaInflected( + expression, + jpKatakanaToHiragana(reading), + source + )) { + // can't use 'furigana' in templates + term.push({text, reading: furigana}); + } + } else { + term.push({text: source}); } - } else { - term.push({text: source}); + result.push(term); } - results.push(term); + result.push([{text: '\n'}]); } - results.push([{text: '\n'}]); + results[mecabName] = result; } return results; } diff --git a/ext/bg/js/mecab.js b/ext/bg/js/mecab.js index 14f68393..fba9b2eb 100644 --- a/ext/bg/js/mecab.js +++ b/ext/bg/js/mecab.js @@ -60,4 +60,4 @@ class Mecab { } } -Mecab.timeout = 1000; +Mecab.timeout = 5000; diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index be1ccfbb..f1bafaf9 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -311,6 +311,11 @@ function profileOptionsCreateDefaults() { dictionaries: {}, + parsing: { + enableScanningParser: true, + enableMecabParser: false + }, + anki: { enable: false, server: 'http://127.0.0.1:8765', diff --git a/ext/bg/js/search-query-parser.js b/ext/bg/js/search-query-parser.js index 1cf00425..81eb18c3 100644 --- a/ext/bg/js/search-query-parser.js +++ b/ext/bg/js/search-query-parser.js @@ -86,22 +86,32 @@ class QueryParser { this.search.setSpinnerVisible(true); await this.setPreview(text); - // const results = await apiTextParse(text, this.search.getOptionsContext()); - const results = await apiTextParseMecab(text, this.search.getOptionsContext()); - - const content = await apiTemplateRender('query-parser.html', { - terms: results.map((term) => { - return term.filter(part => part.text.trim()).map((part) => { - return { - text: Array.from(part.text), - reading: part.reading, - raw: !part.reading || !part.reading.trim(), - }; - }); - }) - }); + const results = {}; + if (this.search.options.parsing.enableScanningParser) { + results['scan'] = await apiTextParse(text, this.search.getOptionsContext()); + } + if (this.search.options.parsing.enableMecabParser) { + let mecabResults = await apiTextParseMecab(text, this.search.getOptionsContext()); + for (const mecabDictName in mecabResults) { + results[`mecab-${mecabDictName}`] = mecabResults[mecabDictName]; + } + } - this.queryParser.innerHTML = content; + const contents = await Promise.all(Object.values(results).map(async result => { + return await apiTemplateRender('query-parser.html', { + terms: result.map((term) => { + return term.filter(part => part.text.trim()).map((part) => { + return { + text: Array.from(part.text), + reading: part.reading, + raw: !part.reading || !part.reading.trim(), + }; + }); + }) + }); + })); + + this.queryParser.innerHTML = contents.join('
'); this.queryParser.querySelectorAll('.query-parser-char').forEach((charElement) => { this.activateScanning(charElement); diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index e562c54e..f4fe032a 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -64,6 +64,9 @@ async function formRead(options) { options.scanning.modifier = $('#scan-modifier-key').val(); options.scanning.popupNestingMaxDepth = parseInt($('#popup-nesting-max-depth').val(), 10); + options.parsing.enableScanningParser = $('#parsing-scan-enable').prop('checked'); + options.parsing.enableMecabParser = $('#parsing-mecab-enable').prop('checked'); + const optionsAnkiEnableOld = options.anki.enable; options.anki.enable = $('#anki-enable').prop('checked'); options.anki.tags = utilBackgroundIsolate($('#card-tags').val().split(/[,; ]+/)); @@ -126,6 +129,9 @@ async function formWrite(options) { $('#scan-modifier-key').val(options.scanning.modifier); $('#popup-nesting-max-depth').val(options.scanning.popupNestingMaxDepth); + $('#parsing-scan-enable').prop('checked', options.parsing.enableScanningParser); + $('#parsing-mecab-enable').prop('checked', options.parsing.enableMecabParser); + $('#anki-enable').prop('checked', options.anki.enable); $('#card-tags').val(options.anki.tags.join(' ')); $('#sentence-detection-extent').val(options.anki.sentenceExt); diff --git a/ext/bg/settings.html b/ext/bg/settings.html index bdcc11d3..8505567b 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -587,6 +587,35 @@ +
+

Text Parsing Options

+ +

+ Yomichan can attempt to parse entire sentences or longer text blocks on the search page, + adding furigana above words and a small space between words. +

+ +

+ Two types of parsers are supported. The first one, enabled by default, works using the built-in + scanning functionality by automatically advancing in the sentence after a matching word. +

+ +

+ The second type is an external program called MeCab + that uses its own dictionaries and a special parsing algorithm. To get it working, you must first + install it and a native messaging component + that acts as a bridge between the program and Yomichan. +

+ +
+ +
+ +
+ +
+
+
-- cgit v1.2.3 From c1d24208d383e687f443c4e7dfc7bfda81d191bd Mon Sep 17 00:00:00 2001 From: siikamiika Date: Fri, 8 Nov 2019 00:49:20 +0200 Subject: start mecab only after enabling the setting --- ext/bg/js/backend.js | 4 ++++ ext/bg/js/mecab.js | 14 ++++++++++++- ext/bg/js/settings.js | 15 +++++++++++++ ext/bg/settings.html | 58 +++++++++++++++++++++++++-------------------------- 4 files changed, 61 insertions(+), 30 deletions(-) (limited to 'ext/bg/js/mecab.js') diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index e97f32b5..027cc250 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -98,6 +98,10 @@ class Backend { } this.anki = options.anki.enable ? new AnkiConnect(options.anki.server) : new AnkiNull(); + + if (options.parsing.enableMecabParser) { + this.mecab.startListener(); + } } async getFullOptions() { diff --git a/ext/bg/js/mecab.js b/ext/bg/js/mecab.js index fba9b2eb..4c62c2b0 100644 --- a/ext/bg/js/mecab.js +++ b/ext/bg/js/mecab.js @@ -19,16 +19,20 @@ class Mecab { constructor() { + this.port = null; this.listeners = {}; this.sequence = 0; - this.startListener(); } async parseText(text) { + if (this.port === null) { + return {}; + } return await this.invoke('parse_text', {text}); } startListener() { + if (this.port !== null) { return; } this.port = chrome.runtime.connectNative('yomichan_mecab'); this.port.onMessage.addListener((message) => { const {sequence, data} = message; @@ -41,6 +45,14 @@ class Mecab { }); } + stopListener() { + if (this.port === null) { return; } + this.port.disconnect(); + this.port = null; + this.listeners = {}; + this.sequence = 0; + } + invoke(action, params) { return new Promise((resolve, reject) => { const sequence = this.sequence++; diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index f4fe032a..0013291a 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -154,6 +154,7 @@ async function formWrite(options) { function formSetupEventListeners() { $('input, select, textarea').not('.anki-model').not('.ignore-form-changes *').change(utilAsync(onFormOptionsChanged)); + $('#parsing-mecab-enable').change(onParseMecabChanged); $('.anki-model').change(utilAsync(onAnkiModelChanged)); } @@ -440,6 +441,20 @@ function onMessage({action, params}, sender, callback) { } +/* + * Text parsing + */ + +function onParseMecabChanged(e) { + const mecab = utilBackend().mecab; + if (e.target.checked) { + mecab.startListener(); + } else { + mecab.stopListener(); + } +} + + /* * Anki */ diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 8505567b..08b9b6c1 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -410,6 +410,35 @@
+
+

Text Parsing Options

+ +

+ Yomichan can attempt to parse entire sentences or longer text blocks on the search page, + adding furigana above words and a small space between words. +

+ +

+ Two types of parsers are supported. The first one, enabled by default, works using the built-in + scanning functionality by automatically advancing in the sentence after a matching word. +

+ +

+ The second type is an external program called MeCab + that uses its own dictionaries and a special parsing algorithm. To get it working, you must first + install it and a native messaging component + that acts as a bridge between the program and Yomichan. +

+ +
+ +
+ +
+ +
+
+
@@ -587,35 +616,6 @@
-
-

Text Parsing Options

- -

- Yomichan can attempt to parse entire sentences or longer text blocks on the search page, - adding furigana above words and a small space between words. -

- -

- Two types of parsers are supported. The first one, enabled by default, works using the built-in - scanning functionality by automatically advancing in the sentence after a matching word. -

- -

- The second type is an external program called MeCab - that uses its own dictionaries and a special parsing algorithm. To get it working, you must first - install it and a native messaging component - that acts as a bridge between the program and Yomichan. -

- -
- -
- -
- -
-
-
-- cgit v1.2.3 From f97877a2097c8b27b75099e489b93db255cb68be Mon Sep 17 00:00:00 2001 From: siikamiika Date: Mon, 11 Nov 2019 02:28:00 +0200 Subject: promise improvements --- ext/bg/js/mecab.js | 6 ++---- ext/bg/js/search-query-parser.js | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'ext/bg/js/mecab.js') diff --git a/ext/bg/js/mecab.js b/ext/bg/js/mecab.js index 4c62c2b0..b9f2d0b3 100644 --- a/ext/bg/js/mecab.js +++ b/ext/bg/js/mecab.js @@ -58,12 +58,10 @@ class Mecab { const sequence = this.sequence++; this.listeners[sequence] = { - callback: (data) => { - resolve(data); - }, + callback: resolve, timer: setTimeout(() => { delete this.listeners[sequence]; - reject(`Mecab invoke timed out in ${Mecab.timeout} ms`); + reject(new Error(`Mecab invoke timed out in ${Mecab.timeout} ms`)); }, Mecab.timeout) } diff --git a/ext/bg/js/search-query-parser.js b/ext/bg/js/search-query-parser.js index f8e53963..2aee45dd 100644 --- a/ext/bg/js/search-query-parser.js +++ b/ext/bg/js/search-query-parser.js @@ -97,8 +97,8 @@ class QueryParser { } } - const contents = await Promise.all(Object.values(results).map(async result => { - return await apiTemplateRender('query-parser.html', { + const contents = await Promise.all(Object.values(results).map(result => { + return apiTemplateRender('query-parser.html', { terms: result.map((term) => { return term.filter(part => part.text.trim()).map((part) => { return { -- cgit v1.2.3 From 1f2eee449e2c1e0baf20dba038da7eaf3424aefe Mon Sep 17 00:00:00 2001 From: siikamiika Date: Mon, 11 Nov 2019 20:54:23 +0200 Subject: mecab refactoring and bugfix --- ext/bg/js/backend.js | 2 ++ ext/bg/js/mecab.js | 19 ++++++++++--------- ext/bg/js/settings.js | 15 --------------- 3 files changed, 12 insertions(+), 24 deletions(-) (limited to 'ext/bg/js/mecab.js') diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 027cc250..45db9660 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -101,6 +101,8 @@ class Backend { if (options.parsing.enableMecabParser) { this.mecab.startListener(); + } else { + this.mecab.stopListener(); } } diff --git a/ext/bg/js/mecab.js b/ext/bg/js/mecab.js index b9f2d0b3..ada96945 100644 --- a/ext/bg/js/mecab.js +++ b/ext/bg/js/mecab.js @@ -34,15 +34,7 @@ class Mecab { startListener() { if (this.port !== null) { return; } this.port = chrome.runtime.connectNative('yomichan_mecab'); - this.port.onMessage.addListener((message) => { - const {sequence, data} = message; - const {callback, timer} = this.listeners[sequence] || {}; - if (timer) { - clearTimeout(timer); - delete this.listeners[sequence]; - callback(data); - } - }); + this.port.onMessage.addListener(this.onNativeMessage.bind(this)); } stopListener() { @@ -53,6 +45,15 @@ class Mecab { this.sequence = 0; } + onNativeMessage({sequence, data}) { + if (this.listeners.hasOwnProperty(sequence)) { + const {callback, timer} = this.listeners[sequence]; + clearTimeout(timer); + callback(data); + delete this.listeners[sequence]; + } + } + invoke(action, params) { return new Promise((resolve, reject) => { const sequence = this.sequence++; diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index 0013291a..f4fe032a 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -154,7 +154,6 @@ async function formWrite(options) { function formSetupEventListeners() { $('input, select, textarea').not('.anki-model').not('.ignore-form-changes *').change(utilAsync(onFormOptionsChanged)); - $('#parsing-mecab-enable').change(onParseMecabChanged); $('.anki-model').change(utilAsync(onAnkiModelChanged)); } @@ -441,20 +440,6 @@ function onMessage({action, params}, sender, callback) { } -/* - * Text parsing - */ - -function onParseMecabChanged(e) { - const mecab = utilBackend().mecab; - if (e.target.checked) { - mecab.startListener(); - } else { - mecab.stopListener(); - } -} - - /* * Anki */ -- cgit v1.2.3 From 7bf2c8048d82c62dafdfa6a6866ec63e7e95a56b Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 23 Nov 2019 19:18:29 +0200 Subject: add mecab version check --- ext/bg/js/mecab.js | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'ext/bg/js/mecab.js') diff --git a/ext/bg/js/mecab.js b/ext/bg/js/mecab.js index ada96945..a26b7f39 100644 --- a/ext/bg/js/mecab.js +++ b/ext/bg/js/mecab.js @@ -24,10 +24,23 @@ class Mecab { this.sequence = 0; } - async parseText(text) { - if (this.port === null) { - return {}; + onError(error) { + logError(error, true); + } + + async checkVersion() { + try { + const {version} = await this.invoke('get_version', {}); + if (version !== Mecab.version) { + this.stopListener(); + throw new Error(`Unsupported MeCab native messenger version ${version}. Yomichan supports version ${Mecab.version}.`); + } + } catch (error) { + this.onError(error); } + } + + async parseText(text) { return await this.invoke('parse_text', {text}); } @@ -35,6 +48,7 @@ class Mecab { if (this.port !== null) { return; } this.port = chrome.runtime.connectNative('yomichan_mecab'); this.port.onMessage.addListener(this.onNativeMessage.bind(this)); + this.checkVersion(); } stopListener() { @@ -55,6 +69,9 @@ class Mecab { } invoke(action, params) { + if (this.port === null) { + return {}; + } return new Promise((resolve, reject) => { const sequence = this.sequence++; @@ -72,3 +89,4 @@ class Mecab { } Mecab.timeout = 5000; +Mecab.version = 1; -- cgit v1.2.3 From 43fad608fb5833f95c215dd7596bac5a821dbe60 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 23 Nov 2019 19:25:11 +0200 Subject: remove popup from background page Not supported on all browsers --- ext/bg/js/mecab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/bg/js/mecab.js') diff --git a/ext/bg/js/mecab.js b/ext/bg/js/mecab.js index a26b7f39..4983f656 100644 --- a/ext/bg/js/mecab.js +++ b/ext/bg/js/mecab.js @@ -25,7 +25,7 @@ class Mecab { } onError(error) { - logError(error, true); + logError(error, false); } async checkVersion() { -- cgit v1.2.3 From 89c6ef54b0a44685cde530dd4a94405a578ce132 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sun, 24 Nov 2019 02:34:16 +0200 Subject: always return a promise from Mecab.invoke --- ext/bg/js/mecab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/bg/js/mecab.js') diff --git a/ext/bg/js/mecab.js b/ext/bg/js/mecab.js index 4983f656..246f8bba 100644 --- a/ext/bg/js/mecab.js +++ b/ext/bg/js/mecab.js @@ -70,7 +70,7 @@ class Mecab { invoke(action, params) { if (this.port === null) { - return {}; + return Promise.resolve({}); } return new Promise((resolve, reject) => { const sequence = this.sequence++; -- cgit v1.2.3 From 0aed27b66d9c496e4cd57ef95d982c4e634a8666 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Mon, 25 Nov 2019 14:19:18 -0500 Subject: Replace hasOwnProperty with simplified hasOwn function --- ext/bg/js/api.js | 4 ++-- ext/bg/js/audio.js | 6 +++--- ext/bg/js/backend.js | 2 +- ext/bg/js/conditions-ui.js | 20 ++++++++++---------- ext/bg/js/conditions.js | 30 +++++++++++++++--------------- ext/bg/js/database.js | 2 +- ext/bg/js/dictionary.js | 4 ++-- ext/bg/js/mecab.js | 2 +- ext/bg/js/options.js | 2 +- ext/bg/js/search.js | 2 +- ext/bg/js/settings-dictionaries.js | 4 ++-- ext/bg/js/settings-popup-preview.js | 2 +- ext/bg/js/translator.js | 12 ++++++------ ext/fg/js/float.js | 4 ++-- ext/fg/js/frontend-api-receiver.js | 2 +- ext/fg/js/frontend-api-sender.js | 6 +++--- ext/fg/js/frontend.js | 4 ++-- ext/fg/js/popup-proxy-host.js | 4 ++-- ext/mixed/js/audio.js | 2 +- ext/mixed/js/core.js | 4 ++++ ext/mixed/js/display.js | 4 ++-- 21 files changed, 63 insertions(+), 59 deletions(-) (limited to 'ext/bg/js/mecab.js') diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index 766fb0ed..12257e92 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -45,7 +45,7 @@ async function apiOptionsSet(changedOptions, optionsContext, source) { function modifyOption(path, value, options) { let pivot = options; for (const key of path.slice(0, -1)) { - if (!pivot.hasOwnProperty(key)) { + if (!hasOwn(pivot, key)) { return false; } pivot = pivot[key]; @@ -236,7 +236,7 @@ async function apiTemplateRender(template, data, dynamic) { async function apiCommandExec(command, params) { const handlers = apiCommandExec.handlers; - if (handlers.hasOwnProperty(command)) { + if (hasOwn(handlers, command)) { const handler = handlers[command]; handler(params); } diff --git a/ext/bg/js/audio.js b/ext/bg/js/audio.js index cd42a158..9bbbf902 100644 --- a/ext/bg/js/audio.js +++ b/ext/bg/js/audio.js @@ -107,12 +107,12 @@ const audioUrlBuilders = { 'custom': async (definition, optionsContext) => { const options = await apiOptionsGet(optionsContext); const customSourceUrl = options.audio.customSourceUrl; - return customSourceUrl.replace(/\{([^\}]*)\}/g, (m0, m1) => (definition.hasOwnProperty(m1) ? `${definition[m1]}` : m0)); + return customSourceUrl.replace(/\{([^\}]*)\}/g, (m0, m1) => (hasOwn(definition, m1) ? `${definition[m1]}` : m0)); } }; async function audioGetUrl(definition, mode, optionsContext, download) { - if (audioUrlBuilders.hasOwnProperty(mode)) { + if (hasOwn(audioUrlBuilders, mode)) { const handler = audioUrlBuilders[mode]; try { return await handler(definition, optionsContext, download); @@ -171,7 +171,7 @@ async function audioInject(definition, fields, sources, optionsContext) { try { let audioSourceDefinition = definition; - if (definition.hasOwnProperty('expressions')) { + if (hasOwn(definition, 'expressions')) { audioSourceDefinition = definition.expressions[0]; } diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 45db9660..4190116b 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -73,7 +73,7 @@ class Backend { onMessage({action, params}, sender, callback) { const handlers = Backend.messageHandlers; - if (handlers.hasOwnProperty(action)) { + if (hasOwn(handlers, action)) { const handler = handlers[action]; const promise = handler(params, sender); promise.then( diff --git a/ext/bg/js/conditions-ui.js b/ext/bg/js/conditions-ui.js index 43c6dc08..cc9db087 100644 --- a/ext/bg/js/conditions-ui.js +++ b/ext/bg/js/conditions-ui.js @@ -84,7 +84,7 @@ ConditionsUI.Container = class Container { createDefaultCondition(type) { let operator = ''; let value = ''; - if (this.conditionDescriptors.hasOwnProperty(type)) { + if (hasOwn(this.conditionDescriptors, type)) { const conditionDescriptor = this.conditionDescriptors[type]; operator = conditionDescriptor.defaultOperator; ({value} = this.getOperatorDefaultValue(type, operator)); @@ -96,15 +96,15 @@ ConditionsUI.Container = class Container { } getOperatorDefaultValue(type, operator) { - if (this.conditionDescriptors.hasOwnProperty(type)) { + if (hasOwn(this.conditionDescriptors, type)) { const conditionDescriptor = this.conditionDescriptors[type]; - if (conditionDescriptor.operators.hasOwnProperty(operator)) { + if (hasOwn(conditionDescriptor.operators, operator)) { const operatorDescriptor = conditionDescriptor.operators[operator]; - if (operatorDescriptor.hasOwnProperty('defaultValue')) { + if (hasOwn(operatorDescriptor, 'defaultValue')) { return {value: operatorDescriptor.defaultValue, fromOperator: true}; } } - if (conditionDescriptor.hasOwnProperty('defaultValue')) { + if (hasOwn(conditionDescriptor, 'defaultValue')) { return {value: conditionDescriptor.defaultValue, fromOperator: false}; } } @@ -219,7 +219,7 @@ ConditionsUI.Condition = class Condition { optionGroup.empty(); const type = this.condition.type; - if (conditionDescriptors.hasOwnProperty(type)) { + if (hasOwn(conditionDescriptors, type)) { const conditionDescriptor = conditionDescriptors[type]; const operators = conditionDescriptor.operators; for (const operatorName of Object.keys(operators)) { @@ -240,23 +240,23 @@ ConditionsUI.Condition = class Condition { }; const objects = []; - if (conditionDescriptors.hasOwnProperty(type)) { + if (hasOwn(conditionDescriptors, type)) { const conditionDescriptor = conditionDescriptors[type]; objects.push(conditionDescriptor); - if (conditionDescriptor.operators.hasOwnProperty(operator)) { + if (hasOwn(conditionDescriptor.operators, operator)) { const operatorDescriptor = conditionDescriptor.operators[operator]; objects.push(operatorDescriptor); } } for (const object of objects) { - if (object.hasOwnProperty('placeholder')) { + if (hasOwn(object, 'placeholder')) { props.placeholder = object.placeholder; } if (object.type === 'number') { props.type = 'number'; for (const prop of ['step', 'min', 'max']) { - if (object.hasOwnProperty(prop)) { + if (hasOwn(object, prop)) { props[prop] = object[prop]; } } diff --git a/ext/bg/js/conditions.js b/ext/bg/js/conditions.js index ed4b14f5..c0f0f301 100644 --- a/ext/bg/js/conditions.js +++ b/ext/bg/js/conditions.js @@ -18,14 +18,14 @@ function conditionsValidateOptionValue(object, value) { - if (object.hasOwnProperty('validate') && !object.validate(value)) { + if (hasOwn(object, 'validate') && !object.validate(value)) { throw new Error('Invalid value for condition'); } - if (object.hasOwnProperty('transform')) { + if (hasOwn(object, 'transform')) { value = object.transform(value); - if (object.hasOwnProperty('validateTransformed') && !object.validateTransformed(value)) { + if (hasOwn(object, 'validateTransformed') && !object.validateTransformed(value)) { throw new Error('Invalid value for condition'); } } @@ -34,12 +34,12 @@ function conditionsValidateOptionValue(object, value) { } function conditionsNormalizeOptionValue(descriptors, type, operator, optionValue) { - if (!descriptors.hasOwnProperty(type)) { + if (!hasOwn(descriptors, type)) { throw new Error('Invalid type'); } const conditionDescriptor = descriptors[type]; - if (!conditionDescriptor.operators.hasOwnProperty(operator)) { + if (!hasOwn(conditionDescriptor.operators, operator)) { throw new Error('Invalid operator'); } @@ -48,28 +48,28 @@ function conditionsNormalizeOptionValue(descriptors, type, operator, optionValue let transformedValue = conditionsValidateOptionValue(conditionDescriptor, optionValue); transformedValue = conditionsValidateOptionValue(operatorDescriptor, transformedValue); - if (operatorDescriptor.hasOwnProperty('transformReverse')) { + if (hasOwn(operatorDescriptor, 'transformReverse')) { transformedValue = operatorDescriptor.transformReverse(transformedValue); } return transformedValue; } function conditionsTestValueThrowing(descriptors, type, operator, optionValue, value) { - if (!descriptors.hasOwnProperty(type)) { + if (!hasOwn(descriptors, type)) { throw new Error('Invalid type'); } const conditionDescriptor = descriptors[type]; - if (!conditionDescriptor.operators.hasOwnProperty(operator)) { + if (!hasOwn(conditionDescriptor.operators, operator)) { throw new Error('Invalid operator'); } const operatorDescriptor = conditionDescriptor.operators[operator]; - if (operatorDescriptor.hasOwnProperty('transform')) { - if (operatorDescriptor.hasOwnProperty('transformCache')) { + if (hasOwn(operatorDescriptor, 'transform')) { + if (hasOwn(operatorDescriptor, 'transformCache')) { const key = `${optionValue}`; const transformCache = operatorDescriptor.transformCache; - if (transformCache.hasOwnProperty(key)) { + if (hasOwn(transformCache, key)) { optionValue = transformCache[key]; } else { optionValue = operatorDescriptor.transform(optionValue); @@ -93,23 +93,23 @@ function conditionsTestValue(descriptors, type, operator, optionValue, value) { function conditionsClearCaches(descriptors) { for (const type in descriptors) { - if (!descriptors.hasOwnProperty(type)) { + if (!hasOwn(descriptors, type)) { continue; } const conditionDescriptor = descriptors[type]; - if (conditionDescriptor.hasOwnProperty('transformCache')) { + if (hasOwn(conditionDescriptor, 'transformCache')) { conditionDescriptor.transformCache = {}; } const operatorDescriptors = conditionDescriptor.operators; for (const operator in operatorDescriptors) { - if (!operatorDescriptors.hasOwnProperty(operator)) { + if (!hasOwn(operatorDescriptors, operator)) { continue; } const operatorDescriptor = operatorDescriptors[operator]; - if (operatorDescriptor.hasOwnProperty('transformCache')) { + if (hasOwn(operatorDescriptor, 'transformCache')) { operatorDescriptor.transformCache = {}; } } diff --git a/ext/bg/js/database.js b/ext/bg/js/database.js index 9b560f78..c53c9f77 100644 --- a/ext/bg/js/database.js +++ b/ext/bg/js/database.js @@ -137,7 +137,7 @@ class Database { const visited = {}; const results = []; const processRow = (row, index) => { - if (titles.includes(row.dictionary) && !visited.hasOwnProperty(row.id)) { + if (titles.includes(row.dictionary) && !hasOwn(visited, row.id)) { visited[row.id] = true; results.push(Database.createTerm(row, index)); } diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 9aa0af9c..affce9e9 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -81,7 +81,7 @@ function dictTermsUndupe(definitions) { const definitionGroups = {}; for (const definition of definitions) { const definitionExisting = definitionGroups[definition.id]; - if (!definitionGroups.hasOwnProperty(definition.id) || definition.expression.length > definitionExisting.expression.length) { + if (!hasOwn(definitionGroups, definition.id) || definition.expression.length > definitionExisting.expression.length) { definitionGroups[definition.id] = definition; } } @@ -131,7 +131,7 @@ function dictTermsGroup(definitions, dictionaries) { } const keyString = key.toString(); - if (groups.hasOwnProperty(keyString)) { + if (hasOwn(groups, keyString)) { groups[keyString].push(definition); } else { groups[keyString] = [definition]; diff --git a/ext/bg/js/mecab.js b/ext/bg/js/mecab.js index 246f8bba..297432e2 100644 --- a/ext/bg/js/mecab.js +++ b/ext/bg/js/mecab.js @@ -60,7 +60,7 @@ class Mecab { } onNativeMessage({sequence, data}) { - if (this.listeners.hasOwnProperty(sequence)) { + if (hasOwn(this.listeners, sequence)) { const {callback, timer} = this.listeners[sequence]; clearTimeout(timer); callback(data); diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index 63d88789..358a6b45 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -336,7 +336,7 @@ function profileOptionsSetDefaults(options) { const combine = (target, source) => { for (const key in source) { - if (!target.hasOwnProperty(key)) { + if (!hasOwn(target, key)) { target[key] = source[key]; } } diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index 0922d938..16cbfbbd 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -234,7 +234,7 @@ class DisplaySearch extends Display { onRuntimeMessage({action, params}, sender, callback) { const handlers = DisplaySearch.runtimeMessageHandlers; - if (handlers.hasOwnProperty(action)) { + if (hasOwn(handlers, action)) { const handler = handlers[action]; const result = handler(this, params); callback(result); diff --git a/ext/bg/js/settings-dictionaries.js b/ext/bg/js/settings-dictionaries.js index ebd380ac..177379b0 100644 --- a/ext/bg/js/settings-dictionaries.js +++ b/ext/bg/js/settings-dictionaries.js @@ -81,7 +81,7 @@ class SettingsDictionaryListUI { let changed = false; let optionsDictionary; const optionsDictionaries = this.optionsDictionaries; - if (optionsDictionaries.hasOwnProperty(title)) { + if (hasOwn(optionsDictionaries, title)) { optionsDictionary = optionsDictionaries[title]; } else { optionsDictionary = SettingsDictionaryListUI.createDictionaryOptions(); @@ -466,7 +466,7 @@ function dictionaryErrorsShow(errors) { for (let e of errors) { console.error(e); e = dictionaryErrorToString(e); - uniqueErrors[e] = uniqueErrors.hasOwnProperty(e) ? uniqueErrors[e] + 1 : 1; + uniqueErrors[e] = hasOwn(uniqueErrors, e) ? uniqueErrors[e] + 1 : 1; } for (const e in uniqueErrors) { diff --git a/ext/bg/js/settings-popup-preview.js b/ext/bg/js/settings-popup-preview.js index 7d641c46..49409968 100644 --- a/ext/bg/js/settings-popup-preview.js +++ b/ext/bg/js/settings-popup-preview.js @@ -106,7 +106,7 @@ class SettingsPopupPreview { onMessage(e) { const {action, params} = e.data; const handlers = SettingsPopupPreview.messageHandlers; - if (handlers.hasOwnProperty(action)) { + if (hasOwn(handlers, action)) { const handler = handlers[action]; handler(this, params); } diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index e27cbdff..0a0ce663 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -297,7 +297,7 @@ class Translator { for (const deinflection of deinflections) { const term = deinflection.term; let deinflectionArray; - if (uniqueDeinflectionsMap.hasOwnProperty(term)) { + if (hasOwn(uniqueDeinflectionsMap, term)) { deinflectionArray = uniqueDeinflectionsMap[term]; } else { deinflectionArray = []; @@ -355,7 +355,7 @@ class Translator { const kanjiUnique = {}; const kanjiList = []; for (const c of text) { - if (!kanjiUnique.hasOwnProperty(c)) { + if (!hasOwn(kanjiUnique, c)) { kanjiList.push(c); kanjiUnique[c] = true; } @@ -417,7 +417,7 @@ class Translator { const expression = term.expression; term.frequencies = []; - if (termsUniqueMap.hasOwnProperty(expression)) { + if (hasOwn(termsUniqueMap, expression)) { termsUniqueMap[expression].push(term); } else { const termList = [term]; @@ -464,7 +464,7 @@ class Translator { const category = meta.category; const group = ( - stats.hasOwnProperty(category) ? + hasOwn(stats, category) ? stats[category] : (stats[category] = []) ); @@ -484,7 +484,7 @@ class Translator { async getTagMetaList(names, title) { const tagMetaList = []; const cache = ( - this.tagCache.hasOwnProperty(title) ? + hasOwn(this.tagCache, title) ? this.tagCache[title] : (this.tagCache[title] = {}) ); @@ -492,7 +492,7 @@ class Translator { for (const name of names) { const base = Translator.getNameBase(name); - if (cache.hasOwnProperty(base)) { + if (hasOwn(cache, base)) { tagMetaList.push(cache[base]); } else { const tagMeta = await this.database.findTagForTitle(base, title); diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js index 089c9422..ae54be00 100644 --- a/ext/fg/js/float.js +++ b/ext/fg/js/float.js @@ -49,7 +49,7 @@ class DisplayFloat extends Display { onMessage(e) { const {action, params} = e.data; const handlers = DisplayFloat.messageHandlers; - if (handlers.hasOwnProperty(action)) { + if (hasOwn(handlers, action)) { const handler = handlers[action]; handler(this, params); } @@ -58,7 +58,7 @@ class DisplayFloat extends Display { onKeyDown(e) { const key = Display.getKeyFromEvent(e); const handlers = DisplayFloat.onKeyDownHandlers; - if (handlers.hasOwnProperty(key)) { + if (hasOwn(handlers, key)) { const handler = handlers[key]; if (handler(this, e)) { e.preventDefault(); diff --git a/ext/fg/js/frontend-api-receiver.js b/ext/fg/js/frontend-api-receiver.js index fbfb3ab0..bde14646 100644 --- a/ext/fg/js/frontend-api-receiver.js +++ b/ext/fg/js/frontend-api-receiver.js @@ -34,7 +34,7 @@ class FrontendApiReceiver { onMessage(port, {id, action, params, target, senderId}) { if ( target !== this.source || - !this.handlers.hasOwnProperty(action) + !hasOwn(this.handlers, action) ) { return; } diff --git a/ext/fg/js/frontend-api-sender.js b/ext/fg/js/frontend-api-sender.js index c6eeaeb2..af998a8f 100644 --- a/ext/fg/js/frontend-api-sender.js +++ b/ext/fg/js/frontend-api-sender.js @@ -78,7 +78,7 @@ class FrontendApiSender { } onAck(id) { - if (!this.callbacks.hasOwnProperty(id)) { + if (!hasOwn(this.callbacks, id)) { console.warn(`ID ${id} not found for ack`); return; } @@ -95,7 +95,7 @@ class FrontendApiSender { } onResult(id, data) { - if (!this.callbacks.hasOwnProperty(id)) { + if (!hasOwn(this.callbacks, id)) { console.warn(`ID ${id} not found`); return; } @@ -118,7 +118,7 @@ class FrontendApiSender { } onError(id, reason) { - if (!this.callbacks.hasOwnProperty(id)) { return; } + if (!hasOwn(this.callbacks, id)) { return; } const info = this.callbacks[id]; delete this.callbacks[id]; info.timer = null; diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index ee653d78..16302e82 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -237,7 +237,7 @@ class Frontend { onWindowMessage(e) { const action = e.data; const handlers = Frontend.windowMessageHandlers; - if (handlers.hasOwnProperty(action)) { + if (hasOwn(handlers, action)) { const handler = handlers[action]; handler(this); } @@ -245,7 +245,7 @@ class Frontend { onRuntimeMessage({action, params}, sender, callback) { const handlers = Frontend.runtimeMessageHandlers; - if (handlers.hasOwnProperty(action)) { + if (hasOwn(handlers, action)) { const handler = handlers[action]; const result = handler(this, params); callback(result); diff --git a/ext/fg/js/popup-proxy-host.js b/ext/fg/js/popup-proxy-host.js index d8dec4df..b2f18b97 100644 --- a/ext/fg/js/popup-proxy-host.js +++ b/ext/fg/js/popup-proxy-host.js @@ -50,7 +50,7 @@ class PopupProxyHost { } createPopup(parentId, depth) { - const parent = (typeof parentId === 'string' && this.popups.hasOwnProperty(parentId) ? this.popups[parentId] : null); + const parent = (typeof parentId === 'string' && hasOwn(this.popups, parentId) ? this.popups[parentId] : null); const id = `${this.nextId}`; if (parent !== null) { depth = parent.depth + 1; @@ -70,7 +70,7 @@ class PopupProxyHost { } getPopup(id) { - if (!this.popups.hasOwnProperty(id)) { + if (!hasOwn(this.popups, id)) { throw new Error('Invalid popup ID'); } diff --git a/ext/mixed/js/audio.js b/ext/mixed/js/audio.js index 4e9d04fa..7d5ffedd 100644 --- a/ext/mixed/js/audio.js +++ b/ext/mixed/js/audio.js @@ -113,7 +113,7 @@ function audioGetFromUrl(url, willDownload) { async function audioGetFromSources(expression, sources, optionsContext, willDownload, cache=null) { const key = `${expression.expression}:${expression.reading}`; - if (cache !== null && cache.hasOwnProperty(expression)) { + if (cache !== null && hasOwn(cache, expression)) { return cache[key]; } diff --git a/ext/mixed/js/core.js b/ext/mixed/js/core.js index 8a8a2368..d82b9b4b 100644 --- a/ext/mixed/js/core.js +++ b/ext/mixed/js/core.js @@ -94,6 +94,10 @@ function isObject(value) { return typeof value === 'object' && value !== null && !Array.isArray(value); } +function hasOwn(object, property) { + return Object.prototype.hasOwnProperty.call(object, property); +} + // toIterable is required on Edge for cross-window origin objects. function toIterable(value) { if (typeof Symbol !== 'undefined' && typeof value[Symbol.iterator] !== 'undefined') { diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 854418f4..ce43b22c 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -194,7 +194,7 @@ class Display { onKeyDown(e) { const key = Display.getKeyFromEvent(e); const handlers = Display.onKeyDownHandlers; - if (handlers.hasOwnProperty(key)) { + if (hasOwn(handlers, key)) { const handler = handlers[key]; if (handler(this, e)) { e.preventDefault(); @@ -216,7 +216,7 @@ class Display { onRuntimeMessage({action, params}, sender, callback) { const handlers = Display.runtimeMessageHandlers; - if (handlers.hasOwnProperty(action)) { + if (hasOwn(handlers, action)) { const handler = handlers[action]; const result = handler(this, params); callback(result); -- cgit v1.2.3 From 63a775ebcafc8d0477bc267ef39e40c4d3283666 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Tue, 26 Nov 2019 12:50:46 -0500 Subject: Add missing semicolon --- ext/bg/js/mecab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/bg/js/mecab.js') diff --git a/ext/bg/js/mecab.js b/ext/bg/js/mecab.js index 297432e2..62111f73 100644 --- a/ext/bg/js/mecab.js +++ b/ext/bg/js/mecab.js @@ -81,7 +81,7 @@ class Mecab { delete this.listeners[sequence]; reject(new Error(`Mecab invoke timed out in ${Mecab.timeout} ms`)); }, Mecab.timeout) - } + }; this.port.postMessage({action, params, sequence}); }); -- cgit v1.2.3