From 7dd75082abd31b725d9907a93ab97fe1434bab04 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 16 Jul 2017 12:59:16 -0700 Subject: rename options to settings --- ext/bg/settings.html | 282 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 ext/bg/settings.html (limited to 'ext/bg/settings.html') diff --git a/ext/bg/settings.html b/ext/bg/settings.html new file mode 100644 index 00000000..19dfec22 --- /dev/null +++ b/ext/bg/settings.html @@ -0,0 +1,282 @@ + + + + + Yomichan Options + + + + + +
+
+

General Options

+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+
+
+
+ +
+ + +
+
+ +
+

Scanning Options

+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ +
+
+ +

Dictionaries

+
+ +

+ Yomichan can import and use a variety of dictionary formats. Unneeded dictionaries can be disabled, + or you can simply purge the database to delete everything. +

+

+ Please visit the Yomichan homepage to download free + dictionaries that you can use with this extension. +

+ +
Dictionary data is being purged, please be patient...
+ +
+ Warning: + no dictionaries found; please use the importer below to install packaged dictionaries +
+ +
+ Error: + +
+ +
+ +
+ Dictionary data is being imported, please be patient... +
+
+
+
+ +
+ +
+
+ +
+
+ +

Anki Options

+
+ +

+ Yomichan supports automatic flashcard creation for Anki, a free application + designed to help you remember. This feature requires installation of the + AnkiConnect plugin. +

+ +
+ Error: + +
+ +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+

+ Specify the information you would like included in your flashcards in the field editor below. + As Anki requires the first field in the model to be unique, it is recommended + that you set it to {expression} for term flashcards and {character} for + Kanji flashcards. You can use multiple markers per field by typing them in directly. +

+ + + +
+
+
+
+ + +
+ +
+ + +
+
+ + + + +
FieldValue
+
+ +
+
+
+ + +
+ +
+ + +
+
+ + + + +
FieldValue
+
+
+
+
+ +
+

Support Development

+ +

+ Yomichan is provided to you completely free of charge. Unlike numerous other "free" services, you are not + shown ads, pestered with "offers", or have your browser usage information analyzed and sold to third parties. +

+

+ If you find Yomichan useful, please consider making a small donation as a way to show your appreciation for the + countless hours that I have devoted to this extension. +

+

+ +

+
+ +

+            
+ +
+ HomepageLegal +
+
+ + + + + + + + + -- cgit v1.2.3 From 39f1f30dc9e9aaae8cbeac9afe120fbb5c2ecfd3 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 16 Jul 2017 13:14:28 -0700 Subject: refactor bg/js/util.js --- ext/bg/background.html | 1 + ext/bg/js/options.js | 132 +++++++++++++++++++++++++++++++++++++++++++++++++ ext/bg/js/util.js | 119 -------------------------------------------- ext/bg/popup.html | 1 + ext/bg/settings.html | 1 + ext/mixed/js/audio.js | 4 -- 6 files changed, 135 insertions(+), 123 deletions(-) create mode 100644 ext/bg/js/options.js (limited to 'ext/bg/settings.html') diff --git a/ext/bg/background.html b/ext/bg/background.html index 4a2d8c8d..a9071cc7 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -11,6 +11,7 @@ + diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js new file mode 100644 index 00000000..a9345fdd --- /dev/null +++ b/ext/bg/js/options.js @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2016 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 . + */ + + +function optionsSetDefaults(options) { + const defaults = { + general: { + enable: true, + audioSource: 'jpod101', + audioVolume: 100, + groupResults: true, + debugInfo: false, + maxResults: 32, + showAdvanced: false, + popupWidth: 400, + popupHeight: 250, + popupOffset: 10, + showGuide: true + }, + + scanning: { + middleMouse: true, + selectText: true, + alphanumeric: true, + delay: 15, + length: 10, + modifier: 'shift' + }, + + dictionaries: {}, + + anki: { + enable: false, + server: 'http://127.0.0.1:8765', + tags: ['yomichan'], + htmlCards: true, + sentenceExt: 200, + terms: {deck: '', model: '', fields: {}}, + kanji: {deck: '', model: '', fields: {}} + } + }; + + const combine = (target, source) => { + for (const key in source) { + if (!target.hasOwnProperty(key)) { + target[key] = source[key]; + } + } + }; + + combine(options, defaults); + combine(options.general, defaults.general); + combine(options.scanning, defaults.scanning); + combine(options.anki, defaults.anki); + combine(options.anki.terms, defaults.anki.terms); + combine(options.anki.kanji, defaults.anki.kanji); + + return options; +} + +function optionsVersion(options) { + const fixups = [ + () => {}, + () => {}, + () => {}, + () => {}, + () => { + if (options.general.audioPlayback) { + options.general.audioSource = 'jpod101'; + } else { + options.general.audioSource = 'disabled'; + } + }, + () => { + options.general.showGuide = false; + }, + () => { + if (options.scanning.requireShift) { + options.scanning.modifier = 'shift'; + } else { + options.scanning.modifier = 'none'; + } + } + ]; + + optionsSetDefaults(options); + if (!options.hasOwnProperty('version')) { + options.version = fixups.length; + } + + while (options.version < fixups.length) { + fixups[options.version++](); + } + + return options; +} + +function optionsLoad() { + return new Promise((resolve, reject) => { + chrome.storage.local.get(null, store => resolve(store.options)); + }).then(optionsStr => { + return optionsStr ? JSON.parse(optionsStr) : {}; + }).catch(error => { + return {}; + }).then(options => { + return optionsVersion(options); + }); +} + +function optionsSave(options) { + return new Promise((resolve, reject) => { + chrome.storage.local.set({options: JSON.stringify(options)}, resolve); + }).then(() => { + instYomi().optionsSet(options); + fgOptionsSet(options); + }); +} diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js index 4d0aa27e..5d80fdb7 100644 --- a/ext/bg/js/util.js +++ b/ext/bg/js/util.js @@ -91,125 +91,6 @@ function fgOptionsSet(options) { } -/* - * Options - */ - -function optionsSetDefaults(options) { - const defaults = { - general: { - enable: true, - audioSource: 'jpod101', - audioVolume: 100, - groupResults: true, - debugInfo: false, - maxResults: 32, - showAdvanced: false, - popupWidth: 400, - popupHeight: 250, - popupOffset: 10, - showGuide: true - }, - - scanning: { - middleMouse: true, - selectText: true, - alphanumeric: true, - delay: 15, - length: 10, - modifier: 'shift' - }, - - dictionaries: {}, - - anki: { - enable: false, - server: 'http://127.0.0.1:8765', - tags: ['yomichan'], - htmlCards: true, - sentenceExt: 200, - terms: {deck: '', model: '', fields: {}}, - kanji: {deck: '', model: '', fields: {}} - } - }; - - const combine = (target, source) => { - for (const key in source) { - if (!target.hasOwnProperty(key)) { - target[key] = source[key]; - } - } - }; - - combine(options, defaults); - combine(options.general, defaults.general); - combine(options.scanning, defaults.scanning); - combine(options.anki, defaults.anki); - combine(options.anki.terms, defaults.anki.terms); - combine(options.anki.kanji, defaults.anki.kanji); - - return options; -} - -function optionsVersion(options) { - const fixups = [ - () => {}, - () => {}, - () => {}, - () => {}, - () => { - if (options.general.audioPlayback) { - options.general.audioSource = 'jpod101'; - } else { - options.general.audioSource = 'disabled'; - } - }, - () => { - options.general.showGuide = false; - }, - () => { - if (options.scanning.requireShift) { - options.scanning.modifier = 'shift'; - } else { - options.scanning.modifier = 'none'; - } - } - ]; - - optionsSetDefaults(options); - if (!options.hasOwnProperty('version')) { - options.version = fixups.length; - } - - while (options.version < fixups.length) { - fixups[options.version++](); - } - - return options; -} - -function optionsLoad() { - return new Promise((resolve, reject) => { - chrome.storage.local.get(null, store => resolve(store.options)); - }).then(optionsStr => { - return optionsStr ? JSON.parse(optionsStr) : {}; - }).catch(error => { - return {}; - }).then(options => { - return optionsVersion(options); - }); -} - -function optionsSave(options) { - return new Promise((resolve, reject) => { - chrome.storage.local.set({options: JSON.stringify(options)}, resolve); - }).then(() => { - instYomi().optionsSet(options); - fgOptionsSet(options); - }); -} - - /* * Dictionary */ diff --git a/ext/bg/popup.html b/ext/bg/popup.html index dec52795..ab2ee1e0 100644 --- a/ext/bg/popup.html +++ b/ext/bg/popup.html @@ -31,6 +31,7 @@ + diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 19dfec22..ada3299b 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -277,6 +277,7 @@ + diff --git a/ext/mixed/js/audio.js b/ext/mixed/js/audio.js index 451fe1d9..eb8fde94 100644 --- a/ext/mixed/js/audio.js +++ b/ext/mixed/js/audio.js @@ -17,10 +17,6 @@ */ -/* - * Audio - */ - async function audioBuildUrl(definition, mode, cache={}) { if (mode === 'jpod101') { let kana = definition.reading; -- cgit v1.2.3 From 26e1cc517f6100fe665d8d066729a11fde2cdc26 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Tue, 18 Jul 2017 23:07:46 -0700 Subject: refactor --- ext/bg/background.html | 2 + ext/bg/js/dictionary.js | 233 ++++++++++++++++++++++++++++++++++++++++++++++ ext/bg/js/util.js | 237 ----------------------------------------------- ext/bg/popup.html | 2 + ext/bg/search.html | 2 + ext/bg/settings.html | 2 + ext/mixed/js/japanese.js | 31 +++++++ 7 files changed, 272 insertions(+), 237 deletions(-) create mode 100644 ext/bg/js/dictionary.js create mode 100644 ext/mixed/js/japanese.js (limited to 'ext/bg/settings.html') diff --git a/ext/bg/background.html b/ext/bg/background.html index a9071cc7..3cfd894e 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -11,6 +11,8 @@ + + diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js new file mode 100644 index 00000000..6f4ec809 --- /dev/null +++ b/ext/bg/js/dictionary.js @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2016 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 . + */ + + +function dictEnabledSet(options) { + const dictionaries = {}; + for (const title in options.dictionaries) { + const dictionary = options.dictionaries[title]; + if (dictionary.enabled) { + dictionaries[title] = dictionary; + } + } + + return dictionaries; +} + +function dictConfigured(options) { + for (const title in options.dictionaries) { + if (options.dictionaries[title].enabled) { + return true; + } + } + + return false; +} + +function dictRowsSort(rows, options) { + return rows.sort((ra, rb) => { + const pa = (options.dictionaries[ra.title] || {}).priority || 0; + const pb = (options.dictionaries[rb.title] || {}).priority || 0; + if (pa > pb) { + return -1; + } else if (pa < pb) { + return 1; + } else { + return 0; + } + }); +} + +function dictTermsSort(definitions, dictionaries=null) { + return definitions.sort((v1, v2) => { + const sl1 = v1.source.length; + const sl2 = v2.source.length; + if (sl1 > sl2) { + return -1; + } else if (sl1 < sl2) { + return 1; + } + + if (dictionaries !== null) { + const p1 = (dictionaries[v1.dictionary] || {}).priority || 0; + const p2 = (dictionaries[v2.dictionary] || {}).priority || 0; + if (p1 > p2) { + return -1; + } else if (p1 < p2) { + return 1; + } + } + + const s1 = v1.score; + const s2 = v2.score; + if (s1 > s2) { + return -1; + } else if (s1 < s2) { + return 1; + } + + const rl1 = v1.reasons.length; + const rl2 = v2.reasons.length; + if (rl1 < rl2) { + return -1; + } else if (rl1 > rl2) { + return 1; + } + + return v2.expression.localeCompare(v1.expression); + }); +} + +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) { + definitionGroups[definition.id] = definition; + } + } + + const definitionsUnique = []; + for (const key in definitionGroups) { + definitionsUnique.push(definitionGroups[key]); + } + + return definitionsUnique; +} + +function dictTermsGroup(definitions, dictionaries) { + const groups = {}; + for (const definition of definitions) { + const key = [definition.source, definition.expression].concat(definition.reasons); + if (definition.reading) { + key.push(definition.reading); + } + + const group = groups[key]; + if (group) { + group.push(definition); + } else { + groups[key] = [definition]; + } + } + + const results = []; + for (const key in groups) { + const groupDefs = groups[key]; + const firstDef = groupDefs[0]; + dictTermsSort(groupDefs, dictionaries); + results.push({ + definitions: groupDefs, + expression: firstDef.expression, + reading: firstDef.reading, + reasons: firstDef.reasons, + score: groupDefs.reduce((p, v) => v.score > p ? v.score : p, Number.MIN_SAFE_INTEGER), + source: firstDef.source + }); + } + + return dictTermsSort(results); +} + +function dictTagBuildSource(name) { + return dictTagSanitize({name, category: 'dictionary', order: 100}); +} + +function dictTagBuild(name, meta) { + const tag = {name}; + const symbol = name.split(':')[0]; + for (const prop in meta[symbol] || {}) { + tag[prop] = meta[symbol][prop]; + } + + return dictTagSanitize(tag); +} + +function dictTagSanitize(tag) { + tag.name = tag.name || 'untitled'; + tag.category = tag.category || 'default'; + tag.notes = tag.notes || ''; + tag.order = tag.order || 0; + return tag; +} + +function dictTagsSort(tags) { + return tags.sort((v1, v2) => { + const order1 = v1.order; + const order2 = v2.order; + if (order1 < order2) { + return -1; + } else if (order1 > order2) { + return 1; + } + + const name1 = v1.name; + const name2 = v2.name; + if (name1 < name2) { + return -1; + } else if (name1 > name2) { + return 1; + } + + return 0; + }); +} + +function dictFieldSplit(field) { + return field.length === 0 ? [] : field.split(' '); +} + +function dictFieldFormat(field, definition, mode, options) { + const markers = [ + 'audio', + 'character', + 'cloze-body', + 'cloze-prefix', + 'cloze-suffix', + 'dictionary', + 'expression', + 'furigana', + 'glossary', + 'glossary-brief', + 'kunyomi', + 'onyomi', + 'reading', + 'sentence', + 'tags', + 'url' + ]; + + for (const marker of markers) { + const data = { + marker, + definition, + group: options.general.groupResults, + html: options.anki.htmlCards, + modeTermKanji: mode === 'term-kanji', + modeTermKana: mode === 'term-kana', + modeKanji: mode === 'kanji' + }; + + field = field.replace( + `{${marker}}`, + Handlebars.templates['fields.html'](data).trim() + ); + } + + return field; +} diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js index 5d80fdb7..0a4592ea 100644 --- a/ext/bg/js/util.js +++ b/ext/bg/js/util.js @@ -30,24 +30,6 @@ function promiseCallback(promise, callback) { } -/* - * Japanese - */ - -function jpIsKanji(c) { - const code = c.charCodeAt(0); - return code >= 0x4e00 && code < 0x9fb0 || code >= 0x3400 && code < 0x4dc0; -} - -function jpIsKana(c) { - return wanakana.isKana(c); -} - -function jpKatakanaToHiragana(text) { - return wanakana._katakanaToHiragana(text); -} - - /* * Commands */ @@ -91,225 +73,6 @@ function fgOptionsSet(options) { } -/* - * Dictionary - */ - -function dictEnabledSet(options) { - const dictionaries = {}; - for (const title in options.dictionaries) { - const dictionary = options.dictionaries[title]; - if (dictionary.enabled) { - dictionaries[title] = dictionary; - } - } - - return dictionaries; -} - -function dictConfigured(options) { - for (const title in options.dictionaries) { - if (options.dictionaries[title].enabled) { - return true; - } - } - - return false; -} - -function dictRowsSort(rows, options) { - return rows.sort((ra, rb) => { - const pa = (options.dictionaries[ra.title] || {}).priority || 0; - const pb = (options.dictionaries[rb.title] || {}).priority || 0; - if (pa > pb) { - return -1; - } else if (pa < pb) { - return 1; - } else { - return 0; - } - }); -} - -function dictTermsSort(definitions, dictionaries=null) { - return definitions.sort((v1, v2) => { - const sl1 = v1.source.length; - const sl2 = v2.source.length; - if (sl1 > sl2) { - return -1; - } else if (sl1 < sl2) { - return 1; - } - - if (dictionaries !== null) { - const p1 = (dictionaries[v1.dictionary] || {}).priority || 0; - const p2 = (dictionaries[v2.dictionary] || {}).priority || 0; - if (p1 > p2) { - return -1; - } else if (p1 < p2) { - return 1; - } - } - - const s1 = v1.score; - const s2 = v2.score; - if (s1 > s2) { - return -1; - } else if (s1 < s2) { - return 1; - } - - const rl1 = v1.reasons.length; - const rl2 = v2.reasons.length; - if (rl1 < rl2) { - return -1; - } else if (rl1 > rl2) { - return 1; - } - - return v2.expression.localeCompare(v1.expression); - }); -} - -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) { - definitionGroups[definition.id] = definition; - } - } - - const definitionsUnique = []; - for (const key in definitionGroups) { - definitionsUnique.push(definitionGroups[key]); - } - - return definitionsUnique; -} - -function dictTermsGroup(definitions, dictionaries) { - const groups = {}; - for (const definition of definitions) { - const key = [definition.source, definition.expression].concat(definition.reasons); - if (definition.reading) { - key.push(definition.reading); - } - - const group = groups[key]; - if (group) { - group.push(definition); - } else { - groups[key] = [definition]; - } - } - - const results = []; - for (const key in groups) { - const groupDefs = groups[key]; - const firstDef = groupDefs[0]; - dictTermsSort(groupDefs, dictionaries); - results.push({ - definitions: groupDefs, - expression: firstDef.expression, - reading: firstDef.reading, - reasons: firstDef.reasons, - score: groupDefs.reduce((p, v) => v.score > p ? v.score : p, Number.MIN_SAFE_INTEGER), - source: firstDef.source - }); - } - - return dictTermsSort(results); -} - -function dictTagBuildSource(name) { - return dictTagSanitize({name, category: 'dictionary', order: 100}); -} - -function dictTagBuild(name, meta) { - const tag = {name}; - const symbol = name.split(':')[0]; - for (const prop in meta[symbol] || {}) { - tag[prop] = meta[symbol][prop]; - } - - return dictTagSanitize(tag); -} - -function dictTagSanitize(tag) { - tag.name = tag.name || 'untitled'; - tag.category = tag.category || 'default'; - tag.notes = tag.notes || ''; - tag.order = tag.order || 0; - return tag; -} - -function dictTagsSort(tags) { - return tags.sort((v1, v2) => { - const order1 = v1.order; - const order2 = v2.order; - if (order1 < order2) { - return -1; - } else if (order1 > order2) { - return 1; - } - - const name1 = v1.name; - const name2 = v2.name; - if (name1 < name2) { - return -1; - } else if (name1 > name2) { - return 1; - } - - return 0; - }); -} - -function dictFieldSplit(field) { - return field.length === 0 ? [] : field.split(' '); -} - -function dictFieldFormat(field, definition, mode, options) { - const markers = [ - 'audio', - 'character', - 'cloze-body', - 'cloze-prefix', - 'cloze-suffix', - 'dictionary', - 'expression', - 'furigana', - 'glossary', - 'glossary-brief', - 'kunyomi', - 'onyomi', - 'reading', - 'sentence', - 'tags', - 'url' - ]; - - for (const marker of markers) { - const data = { - marker, - definition, - group: options.general.groupResults, - html: options.anki.htmlCards, - modeTermKanji: mode === 'term-kanji', - modeTermKana: mode === 'term-kana', - modeKanji: mode === 'kanji' - }; - - field = field.replace( - `{${marker}}`, - Handlebars.templates['fields.html'](data).trim() - ); - } - - return field; -} - /* * JSON */ diff --git a/ext/bg/popup.html b/ext/bg/popup.html index ab2ee1e0..db9097bd 100644 --- a/ext/bg/popup.html +++ b/ext/bg/popup.html @@ -31,6 +31,8 @@ + + diff --git a/ext/bg/search.html b/ext/bg/search.html index 0fc3caf7..b30b8910 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -34,6 +34,8 @@ + + diff --git a/ext/bg/settings.html b/ext/bg/settings.html index ada3299b..8135ca9a 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -277,6 +277,8 @@ + + diff --git a/ext/mixed/js/japanese.js b/ext/mixed/js/japanese.js new file mode 100644 index 00000000..779e3d35 --- /dev/null +++ b/ext/mixed/js/japanese.js @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016 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 . + */ + + +function jpIsKanji(c) { + const code = c.charCodeAt(0); + return code >= 0x4e00 && code < 0x9fb0 || code >= 0x3400 && code < 0x4dc0; +} + +function jpIsKana(c) { + return wanakana.isKana(c); +} + +function jpKatakanaToHiragana(text) { + return wanakana._katakanaToHiragana(text); +} -- cgit v1.2.3 From 62db3d74b8042dd3185a7a552920a2ce7a4bd4ab Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Wed, 19 Jul 2017 09:24:38 -0700 Subject: factor out handlebars from util --- ext/bg/background.html | 1 + ext/bg/js/handlebars.js | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ ext/bg/js/util.js | 41 ------------------------------------ ext/bg/settings.html | 1 + 4 files changed, 57 insertions(+), 41 deletions(-) create mode 100644 ext/bg/js/handlebars.js (limited to 'ext/bg/settings.html') diff --git a/ext/bg/background.html b/ext/bg/background.html index 3cfd894e..61bc17a0 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -11,6 +11,7 @@ + diff --git a/ext/bg/js/handlebars.js b/ext/bg/js/handlebars.js new file mode 100644 index 00000000..42b36927 --- /dev/null +++ b/ext/bg/js/handlebars.js @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 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 . + */ + + +function handlebarsEscape(text) { + return Handlebars.Utils.escapeExpression(text); +} + +function handlebarsDumpObject(options) { + const dump = JSON.stringify(options.fn(this), null, 4); + return handlebarsEscape(dump); +} + +function handlebarsKanjiLinks(options) { + let result = ''; + for (const c of options.fn(this)) { + if (jpIsKanji(c)) { + result += `${c}`; + } else { + result += c; + } + } + + return result; +} + +function handlebarsMultiLine(options) { + return options.fn(this).split('\n').join('
'); +} + +function handlebarsRegister() { + Handlebars.partials = Handlebars.templates; + Handlebars.registerHelper('dumpObject', handlebarsDumpObject); + Handlebars.registerHelper('kanjiLinks', handlebarsKanjiLinks); + Handlebars.registerHelper('multiLine', handlebarsMultiLine); +} + +function handlebarsRender(template, data) { + return Handlebars.templates[template](data); +} diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js index 0a4592ea..6e86c2a6 100644 --- a/ext/bg/js/util.js +++ b/ext/bg/js/util.js @@ -98,44 +98,3 @@ function jsonRequest(url, action, params) { } }); } - -/* - * Helpers - */ - -function handlebarsEscape(text) { - return Handlebars.Utils.escapeExpression(text); -} - -function handlebarsDumpObject(options) { - const dump = JSON.stringify(options.fn(this), null, 4); - return handlebarsEscape(dump); -} - -function handlebarsKanjiLinks(options) { - let result = ''; - for (const c of options.fn(this)) { - if (jpIsKanji(c)) { - result += `${c}`; - } else { - result += c; - } - } - - return result; -} - -function handlebarsMultiLine(options) { - return options.fn(this).split('\n').join('
'); -} - -function handlebarsRegister() { - Handlebars.partials = Handlebars.templates; - Handlebars.registerHelper('dumpObject', handlebarsDumpObject); - Handlebars.registerHelper('kanjiLinks', handlebarsKanjiLinks); - Handlebars.registerHelper('multiLine', handlebarsMultiLine); -} - -function handlebarsRender(template, data) { - return Handlebars.templates[template](data); -} diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 8135ca9a..9b21b4d8 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -277,6 +277,7 @@ + -- cgit v1.2.3 From fe137e94c92cf0366735936b6ac82dc147b1ad33 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Wed, 19 Jul 2017 21:28:09 -0700 Subject: cleanup --- ext/bg/background.html | 1 + ext/bg/js/anki-connect.js | 2 +- ext/bg/js/translator.js | 2 +- ext/bg/js/util.js | 40 ---------------------------------------- ext/bg/js/yomichan.js | 8 ++++++++ ext/bg/popup.html | 1 + ext/bg/search.html | 1 + ext/bg/settings.html | 1 + ext/mixed/js/request.js | 40 ++++++++++++++++++++++++++++++++++++++++ 9 files changed, 54 insertions(+), 42 deletions(-) create mode 100644 ext/mixed/js/request.js (limited to 'ext/bg/settings.html') diff --git a/ext/bg/background.html b/ext/bg/background.html index 61bc17a0..7d352561 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -14,6 +14,7 @@ + diff --git a/ext/bg/js/anki-connect.js b/ext/bg/js/anki-connect.js index a4d8ba3f..567e8d3f 100644 --- a/ext/bg/js/anki-connect.js +++ b/ext/bg/js/anki-connect.js @@ -64,6 +64,6 @@ class AnkiConnect { } ankiInvoke(action, params) { - return jsonRequest(this.server, 'POST', {action, params, version: this.localVersion}); + return requestJson(this.server, 'POST', {action, params, version: this.localVersion}); } } diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 9232e529..1be485c7 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -31,7 +31,7 @@ class Translator { if (!this.deinflector) { const url = chrome.extension.getURL('/bg/lang/deinflect.json'); - const reasons = await jsonRequest(url, 'GET'); + const reasons = await requestJson(url, 'GET'); this.deinflector = new Deinflector(reasons); } } diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js index 6e86c2a6..c7ebbb0e 100644 --- a/ext/bg/js/util.js +++ b/ext/bg/js/util.js @@ -17,19 +17,6 @@ */ -/* - * Promise - */ - -function promiseCallback(promise, callback) { - return promise.then(result => { - callback({result}); - }).catch(error => { - callback({error}); - }); -} - - /* * Commands */ @@ -71,30 +58,3 @@ function fgBroadcast(action, params) { function fgOptionsSet(options) { fgBroadcast('optionsSet', options); } - - -/* - * JSON - */ - -function jsonRequest(url, action, params) { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest(); - xhr.overrideMimeType('application/json'); - xhr.addEventListener('load', () => resolve(xhr.responseText)); - xhr.addEventListener('error', () => reject('failed to execute network request')); - xhr.open(action, url); - if (params) { - xhr.send(JSON.stringify(params)); - } else { - xhr.send(); - } - }).then(responseText => { - try { - return JSON.parse(responseText); - } - catch (e) { - return Promise.reject('invalid JSON response'); - } - }); -} diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js index acc560ce..eb083396 100644 --- a/ext/bg/js/yomichan.js +++ b/ext/bg/js/yomichan.js @@ -195,6 +195,14 @@ window.yomichan = new class { } onMessage({action, params}, sender, callback) { + const promiseCallback = (promise, callback) => { + return promise.then(result => { + callback({result}); + }).catch(error => { + callback({error}); + }); + }; + const handlers = { optionsGet: ({callback}) => { promiseCallback(optionsLoad(), callback); diff --git a/ext/bg/popup.html b/ext/bg/popup.html index db9097bd..b3d38533 100644 --- a/ext/bg/popup.html +++ b/ext/bg/popup.html @@ -32,6 +32,7 @@ + diff --git a/ext/bg/search.html b/ext/bg/search.html index b30b8910..45603f17 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -35,6 +35,7 @@ + diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 9b21b4d8..4c7198c3 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -280,6 +280,7 @@ + diff --git a/ext/mixed/js/request.js b/ext/mixed/js/request.js new file mode 100644 index 00000000..94fd135a --- /dev/null +++ b/ext/mixed/js/request.js @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017 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 . + */ + + +function requestJson(url, action, params) { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.overrideMimeType('application/json'); + xhr.addEventListener('load', () => resolve(xhr.responseText)); + xhr.addEventListener('error', () => reject('failed to execute network request')); + xhr.open(action, url); + if (params) { + xhr.send(JSON.stringify(params)); + } else { + xhr.send(); + } + }).then(responseText => { + try { + return JSON.parse(responseText); + } + catch (e) { + return Promise.reject('invalid JSON response'); + } + }); +} -- cgit v1.2.3 From ac2e079c98f87acfbafd2105461885a1cb199c76 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Wed, 19 Jul 2017 21:41:30 -0700 Subject: cleanup --- ext/bg/background.html | 2 +- ext/bg/js/instance.js | 30 +++++++++++++++++++++++++ ext/bg/js/options.js | 1 - ext/bg/js/popup.js | 2 ++ ext/bg/js/util.js | 60 -------------------------------------------------- ext/bg/js/yomichan.js | 6 +++++ ext/bg/popup.html | 2 +- ext/bg/search.html | 2 +- ext/bg/settings.html | 2 +- 9 files changed, 42 insertions(+), 65 deletions(-) create mode 100644 ext/bg/js/instance.js delete mode 100644 ext/bg/js/util.js (limited to 'ext/bg/settings.html') diff --git a/ext/bg/background.html b/ext/bg/background.html index 7d352561..de3cbf20 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -10,7 +10,7 @@ - + diff --git a/ext/bg/js/instance.js b/ext/bg/js/instance.js new file mode 100644 index 00000000..0df267cc --- /dev/null +++ b/ext/bg/js/instance.js @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 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 . + */ + + +function instYomi() { + return chrome.extension.getBackgroundPage().yomichan; +} + +function instDb() { + return instYomi().translator.database; +} + +function instAnki() { + return instYomi().anki; +} diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index a9345fdd..d611ae59 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -127,6 +127,5 @@ function optionsSave(options) { chrome.storage.local.set({options: JSON.stringify(options)}, resolve); }).then(() => { instYomi().optionsSet(options); - fgOptionsSet(options); }); } diff --git a/ext/bg/js/popup.js b/ext/bg/js/popup.js index 8577dd96..01994827 100644 --- a/ext/bg/js/popup.js +++ b/ext/bg/js/popup.js @@ -18,6 +18,8 @@ $(document).ready(() => { + const commandExec = command => instYomi().onCommand(command); + $('#open-search').click(() => commandExec('search')); $('#open-options').click(() => commandExec('options')); $('#open-help').click(() => commandExec('help')); diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js deleted file mode 100644 index c7ebbb0e..00000000 --- a/ext/bg/js/util.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2016 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 . - */ - - -/* - * Commands - */ - -function commandExec(command) { - instYomi().onCommand(command); -} - - -/* - * Instance - */ - -function instYomi() { - return chrome.extension.getBackgroundPage().yomichan; -} - -function instDb() { - return instYomi().translator.database; -} - -function instAnki() { - return instYomi().anki; -} - - -/* - * Foreground - */ - -function fgBroadcast(action, params) { - chrome.tabs.query({}, tabs => { - for (const tab of tabs) { - chrome.tabs.sendMessage(tab.id, {action, params}, () => null); - } - }); -} - -function fgOptionsSet(options) { - fgBroadcast('optionsSet', options); -} diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js index eb083396..214bdef3 100644 --- a/ext/bg/js/yomichan.js +++ b/ext/bg/js/yomichan.js @@ -59,6 +59,12 @@ window.yomichan = new class { } else { this.anki = new AnkiNull(); } + + chrome.tabs.query({}, tabs => { + for (const tab of tabs) { + chrome.tabs.sendMessage(tab.id, {action: 'optionsSet', params: options}, () => null); + } + }); } noteFormat(definition, mode) { diff --git a/ext/bg/popup.html b/ext/bg/popup.html index b3d38533..baeb2ffb 100644 --- a/ext/bg/popup.html +++ b/ext/bg/popup.html @@ -30,7 +30,7 @@ - + diff --git a/ext/bg/search.html b/ext/bg/search.html index 45603f17..472907c2 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -33,7 +33,7 @@ - + diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 4c7198c3..9c3995eb 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -276,7 +276,7 @@ - + -- cgit v1.2.3 From 32680c58b895e4c781cfb2f51a97fbff42e111b0 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 23 Jul 2017 22:48:33 -0700 Subject: cleanup --- ext/bg/background.html | 22 +++-- ext/bg/js/api.js | 236 ++++++++++++++++++++++++++++++++++++++++++++ ext/bg/js/backend.js | 223 ++--------------------------------------- ext/bg/js/display-window.js | 20 ---- ext/bg/js/instance.js | 30 ------ ext/bg/js/options.js | 2 +- ext/bg/popup.html | 1 - ext/bg/search.html | 1 - ext/bg/settings.html | 1 - ext/mixed/js/display.js | 34 ++----- 10 files changed, 265 insertions(+), 305 deletions(-) create mode 100644 ext/bg/js/api.js delete mode 100644 ext/bg/js/instance.js (limited to 'ext/bg/settings.html') diff --git a/ext/bg/background.html b/ext/bg/background.html index 27d9bc41..1e9f3809 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -4,23 +4,25 @@ - - + - - - - - - - - + + + + + + + + + + + diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js new file mode 100644 index 00000000..3db0558b --- /dev/null +++ b/ext/bg/js/api.js @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2016 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 . + */ + + +function utilMessageDispatch({action, params}, sender, callback) { + const forward = (promise, callback) => { + return promise.then(result => { + callback({result}); + }).catch(error => { + callback({error}); + }); + }; + + const handlers = { + optionsGet: ({callback}) => { + forward(optionsLoad(), callback); + }, + + kanjiFind: ({text, callback}) => { + forward(apiKanjiFind(text), callback); + }, + + termsFind: ({text, callback}) => { + forward(apiTermsFind(text), callback); + }, + + templateRender: ({template, data, callback}) => { + forward(apiTemplateRender(template, data), callback); + }, + + definitionAdd: ({definition, mode, callback}) => { + forward(apiDefinitionAdd(definition, mode), callback); + }, + + definitionsAddable: ({definitions, modes, callback}) => { + forward(apiDefinitionsAddable(definitions, modes), callback); + }, + + noteView: ({noteId}) => { + forward(apiNoteView(noteId), callback); + } + }; + + const handler = handlers[action]; + if (handler) { + params.callback = callback; + handler(params); + } + + return true; +} + +function utilCommandDispatch(command) { + const handlers = { + search: () => { + chrome.tabs.create({url: chrome.extension.getURL('/bg/search.html')}); + }, + + help: () => { + chrome.tabs.create({url: 'https://foosoft.net/projects/yomichan/'}); + }, + + options: () => { + chrome.runtime.openOptionsPage(); + }, + + toggle: () => { + this.options.general.enable = !this.options.general.enable; + optionsSave(this.options).then(() => this.optionsSet(this.options)); + } + }; + + const handler = handlers[command]; + if (handler) { + handler(); + } +} + +function utilNoteFormat(definition, mode) { + const options = Backend.instance().options; + const note = {fields: {}, tags: options.anki.tags}; + let fields = []; + + if (mode === 'kanji') { + fields = options.anki.kanji.fields; + note.deckName = options.anki.kanji.deck; + note.modelName = options.anki.kanji.model; + } else { + fields = options.anki.terms.fields; + note.deckName = options.anki.terms.deck; + note.modelName = options.anki.terms.model; + + if (definition.audio) { + const audio = { + url: definition.audio.url, + filename: definition.audio.filename, + skipHash: '7e2c2f954ef6051373ba916f000168dc', + fields: [] + }; + + for (const name in fields) { + if (fields[name].includes('{audio}')) { + audio.fields.push(name); + } + } + + if (audio.fields.length > 0) { + note.audio = audio; + } + } + } + + for (const name in fields) { + note.fields[name] = dictFieldFormat(fields[name], definition, mode, options); + } + + return note; +} + +async function apiOptionsSet(options) { + // In Firefox, setting options from the options UI somehow carries references + // to the DOM across to the background page, causing the options object to + // become a "DeadObject" after the options page is closed. The workaround used + // here is to create a deep copy of the options object. + Backend.instance().options = JSON.parse(JSON.stringify(options)); + + if (!options.general.enable) { + chrome.browserAction.setBadgeBackgroundColor({color: '#d9534f'}); + chrome.browserAction.setBadgeText({text: 'off'}); + } else if (!dictConfigured(options)) { + chrome.browserAction.setBadgeBackgroundColor({color: '#f0ad4e'}); + chrome.browserAction.setBadgeText({text: '!'}); + } else { + chrome.browserAction.setBadgeText({text: ''}); + } + + if (options.anki.enable) { + Backend.instance().anki = new AnkiConnect(options.anki.server); + } else { + Backend.instance().anki = new AnkiNull(); + } + + chrome.tabs.query({}, tabs => { + for (const tab of tabs) { + chrome.tabs.sendMessage(tab.id, {action: 'optionsSet', params: options}, () => null); + } + }); +} + +async function apiOptionsGet() { + return Backend.instance().options; +} + +async function apiTermsFind(text) { + const options = Backend.instance().options; + const translator = Backend.instance().translator; + + const searcher = options.general.groupResults ? + translator.findTermsGrouped.bind(translator) : + translator.findTerms.bind(translator); + + const {definitions, length} = await searcher( + text, + dictEnabledSet(options), + options.scanning.alphanumeric + ); + + return { + length, + definitions: definitions.slice(0, options.general.maxResults) + }; +} + +async function apiKanjiFind(text) { + const options = Backend.instance().options; + const definitions = await Backend.instance().translator.findKanji(text, dictEnabledSet(options)); + return definitions.slice(0, options.general.maxResults); +} + +async function apiDefinitionAdd(definition, mode) { + if (mode !== 'kanji') { + const options = Backend.instance().options; + await audioInject( + definition, + options.anki.terms.fields, + options.general.audioSource + ); + } + + return Backend.instance().anki.addNote(utilNoteFormat(definition, mode)); +} + +async function apiDefinitionsAddable(definitions, modes) { + const notes = []; + for (const definition of definitions) { + for (const mode of modes) { + notes.push(utilNoteFormat(definition, mode)); + } + } + + const results = await Backend.instance().anki.canAddNotes(notes); + const states = []; + for (let resultBase = 0; resultBase < results.length; resultBase += modes.length) { + const state = {}; + for (let modeOffset = 0; modeOffset < modes.length; ++modeOffset) { + state[modes[modeOffset]] = results[resultBase + modeOffset]; + } + + states.push(state); + } + + return states; +} + +async function apiNoteView(noteId) { + return Backend.instance().anki.guiBrowse(`nid:${noteId}`); +} + +async function apiTemplateRender(template, data) { + return handlebarsRender(template, data); +} diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index f5415d93..e977735e 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -17,7 +17,7 @@ */ -window.yomichanBackend = new class { +class Backend { constructor() { handlebarsRegister(); @@ -26,225 +26,20 @@ window.yomichanBackend = new class { this.options = null; this.translator.prepare().then(optionsLoad).then(options => { - this.optionsSet(options); + apiOptionsSet(options); - chrome.commands.onCommand.addListener(this.onCommand.bind(this)); - chrome.runtime.onMessage.addListener(this.onMessage.bind(this)); + chrome.commands.onCommand.addListener(utilCommandDispatch); + chrome.runtime.onMessage.addListener(utilMessageDispatch); - if (this.options.general.showGuide) { + if (options.general.showGuide) { chrome.tabs.create({url: chrome.extension.getURL('/bg/guide.html')}); } }); } - optionsSet(options) { - // In Firefox, setting options from the options UI somehow carries references - // to the DOM across to the background page, causing the options object to - // become a "DeadObject" after the options page is closed. The workaround used - // here is to create a deep copy of the options object. - this.options = JSON.parse(JSON.stringify(options)); - - if (!this.options.general.enable) { - chrome.browserAction.setBadgeBackgroundColor({color: '#d9534f'}); - chrome.browserAction.setBadgeText({text: 'off'}); - } else if (!dictConfigured(this.options)) { - chrome.browserAction.setBadgeBackgroundColor({color: '#f0ad4e'}); - chrome.browserAction.setBadgeText({text: '!'}); - } else { - chrome.browserAction.setBadgeText({text: ''}); - } - - if (this.options.anki.enable) { - this.anki = new AnkiConnect(this.options.anki.server); - } else { - this.anki = new AnkiNull(); - } - - chrome.tabs.query({}, tabs => { - for (const tab of tabs) { - chrome.tabs.sendMessage(tab.id, {action: 'optionsSet', params: options}, () => null); - } - }); - } - - noteFormat(definition, mode) { - const note = { - fields: {}, - tags: this.options.anki.tags - }; - - let fields = []; - if (mode === 'kanji') { - fields = this.options.anki.kanji.fields; - note.deckName = this.options.anki.kanji.deck; - note.modelName = this.options.anki.kanji.model; - } else { - fields = this.options.anki.terms.fields; - note.deckName = this.options.anki.terms.deck; - note.modelName = this.options.anki.terms.model; - - if (definition.audio) { - const audio = { - url: definition.audio.url, - filename: definition.audio.filename, - skipHash: '7e2c2f954ef6051373ba916f000168dc', - fields: [] - }; - - for (const name in fields) { - if (fields[name].includes('{audio}')) { - audio.fields.push(name); - } - } - - if (audio.fields.length > 0) { - note.audio = audio; - } - } - } - - for (const name in fields) { - note.fields[name] = dictFieldFormat( - fields[name], - definition, - mode, - this.options - ); - } - - return note; - } - - termsFind(text) { - const searcher = this.options.general.groupResults ? - this.translator.findTermsGrouped.bind(this.translator) : - this.translator.findTerms.bind(this.translator); - - return searcher(text, dictEnabledSet(this.options), this.options.scanning.alphanumeric).then(({definitions, length}) => { - return {length, definitions: definitions.slice(0, this.options.general.maxResults)}; - }); - } - - kanjiFind(text) { - return this.translator.findKanji(text, dictEnabledSet(this.options)).then(definitions => { - return definitions.slice(0, this.options.general.maxResults); - }); - } - - definitionAdd(definition, mode) { - let promise = Promise.resolve(); - if (mode !== 'kanji') { - promise = audioInject(definition, this.options.anki.terms.fields, this.options.general.audioSource); - } - - return promise.then(() => { - const note = this.noteFormat(definition, mode); - return this.anki.addNote(note); - }); - } - - definitionsAddable(definitions, modes) { - const notes = []; - for (const definition of definitions) { - for (const mode of modes) { - notes.push(this.noteFormat(definition, mode)); - } - } - - return this.anki.canAddNotes(notes).then(raw => { - const states = []; - for (let resultBase = 0; resultBase < raw.length; resultBase += modes.length) { - const state = {}; - for (let modeOffset = 0; modeOffset < modes.length; ++modeOffset) { - state[modes[modeOffset]] = raw[resultBase + modeOffset]; - } - - states.push(state); - } - - return states; - }); - } - - noteView(noteId) { - return this.anki.guiBrowse(`nid:${noteId}`); - } - - templateRender(template, data) { - return Promise.resolve(handlebarsRender(template, data)); - } - - onCommand(command) { - const handlers = { - search: () => { - chrome.tabs.create({url: chrome.extension.getURL('/bg/search.html')}); - }, - - help: () => { - chrome.tabs.create({url: 'https://foosoft.net/projects/yomichan/'}); - }, - - options: () => { - chrome.runtime.openOptionsPage(); - }, - - toggle: () => { - this.options.general.enable = !this.options.general.enable; - optionsSave(this.options).then(() => this.optionsSet(this.options)); - } - }; - - const handler = handlers[command]; - if (handler) { - handler(); - } - } - - onMessage({action, params}, sender, callback) { - const promiseCallback = (promise, callback) => { - return promise.then(result => { - callback({result}); - }).catch(error => { - callback({error}); - }); - }; - - const handlers = { - optionsGet: ({callback}) => { - promiseCallback(optionsLoad(), callback); - }, - - kanjiFind: ({text, callback}) => { - promiseCallback(this.kanjiFind(text), callback); - }, - - termsFind: ({text, callback}) => { - promiseCallback(this.termsFind(text), callback); - }, - - templateRender: ({template, data, callback}) => { - promiseCallback(this.templateRender(template, data), callback); - }, - - definitionAdd: ({definition, mode, callback}) => { - promiseCallback(this.definitionAdd(definition, mode), callback); - }, - - definitionsAddable: ({definitions, modes, callback}) => { - promiseCallback(this.definitionsAddable(definitions, modes), callback); - }, - - noteView: ({noteId}) => { - promiseCallback(this.noteView(noteId), callback); - } - }; - - const handler = handlers[action]; - if (handler) { - params.callback = callback; - handler(params); - } - - return true; + static instance() { + return chrome.extension.getBackgroundPage().yomichanBackend; } }; + +window.yomichanBackend = new Backend(); diff --git a/ext/bg/js/display-window.js b/ext/bg/js/display-window.js index 64e56f72..e5357bf9 100644 --- a/ext/bg/js/display-window.js +++ b/ext/bg/js/display-window.js @@ -29,26 +29,6 @@ window.displayWindow = new class extends Display { window.wanakana.bind(query.get(0)); } - definitionAdd(definition, mode) { - return instYomi().definitionAdd(definition, mode); - } - - definitionsAddable(definitions, modes) { - return instYomi().definitionsAddable(definitions, modes).catch(() => []); - } - - noteView(noteId) { - return instYomi().noteView(noteId); - } - - templateRender(template, data) { - return instYomi().templateRender(template, data); - } - - kanjiFind(character) { - return instYomi().kanjiFind(character); - } - handleError(error) { window.alert(`Error: ${error}`); } diff --git a/ext/bg/js/instance.js b/ext/bg/js/instance.js deleted file mode 100644 index bf858fbf..00000000 --- a/ext/bg/js/instance.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2016 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 . - */ - - -function instYomi() { - return chrome.extension.getBackgroundPage().yomichanBackend; -} - -function instDb() { - return instYomi().translator.database; -} - -function instAnki() { - return instYomi().anki; -} diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index d611ae59..ea52d337 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -126,6 +126,6 @@ function optionsSave(options) { return new Promise((resolve, reject) => { chrome.storage.local.set({options: JSON.stringify(options)}, resolve); }).then(() => { - instYomi().optionsSet(options); + apiOptionsSet(options); }); } diff --git a/ext/bg/popup.html b/ext/bg/popup.html index baeb2ffb..26c0f0bb 100644 --- a/ext/bg/popup.html +++ b/ext/bg/popup.html @@ -30,7 +30,6 @@ - diff --git a/ext/bg/search.html b/ext/bg/search.html index 472907c2..7cbae392 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -33,7 +33,6 @@ - diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 9c3995eb..2d0b4b4c 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -276,7 +276,6 @@ - diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index e54bc0f9..f408fb25 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -32,26 +32,6 @@ class Display { $(document).keydown(this.onKeyDown.bind(this)); } - definitionAdd(definition, mode) { - throw 'override me'; - } - - definitionsAddable(definitions, modes) { - throw 'override me'; - } - - noteView(noteId) { - throw 'override me'; - } - - templateRender(template, data) { - throw 'override me'; - } - - kanjiFind(character) { - throw 'override me'; - } - handleError(error) { throw 'override me'; } @@ -87,7 +67,7 @@ class Display { } } - this.templateRender('terms.html', params).then(content => { + apiTemplateRender('terms.html', params).then(content => { this.container.html(content); this.entryScroll(context && context.index || 0); @@ -126,7 +106,7 @@ class Display { } } - this.templateRender('kanji.html', params).then(content => { + apiTemplateRender('kanji.html', params).then(content => { this.container.html(content); this.entryScroll(context && context.index || 0); @@ -138,7 +118,7 @@ class Display { } adderButtonsUpdate(modes, sequence) { - return this.definitionsAddable(this.definitions, modes).then(states => { + return apiDefinitionsAddable(this.definitions, modes).then(states => { if (!states || sequence !== this.sequence) { return; } @@ -198,7 +178,7 @@ class Display { context.url = this.context.url; } - this.kanjiFind(link.text()).then(kanjiDefs => { + apiKanjiFind(link.text()).then(kanjiDefs => { this.showKanjiDefs(kanjiDefs, this.options, context); }).catch(this.handleError.bind(this)); } @@ -220,7 +200,7 @@ class Display { e.preventDefault(); const link = $(e.currentTarget); const index = Display.entryIndexFind(link); - this.noteView(link.data('noteId')); + apiNoteView(link.data('noteId')); } onKeyDown(e) { @@ -234,7 +214,7 @@ class Display { const noteTryView = mode => { const button = Display.viewerButtonFind(this.index); if (button.length !== 0 && !button.hasClass('disabled')) { - this.noteView(button.data('noteId')); + apiNoteView(button.data('noteId')); } }; @@ -351,7 +331,7 @@ class Display { noteAdd(definition, mode) { this.spinner.show(); - return this.definitionAdd(definition, mode).then(noteId => { + return apiDefinitionAdd(definition, mode).then(noteId => { if (noteId) { const index = this.definitions.indexOf(definition); Display.adderButtonFind(index, mode).addClass('disabled'); -- cgit v1.2.3 From adbc7a32cc0cb050b29443e0719e36dd8fafde58 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Thu, 27 Jul 2017 21:42:14 -0700 Subject: cleanup --- ext/bg/js/api.js | 35 ++++++++++++++++++++++------------- ext/bg/js/backend.js | 10 ++-------- ext/bg/js/settings.js | 47 +++++++++++++++++++++++++++++++++++++++++------ ext/bg/settings.html | 9 ++++++--- 4 files changed, 71 insertions(+), 30 deletions(-) (limited to 'ext/bg/settings.html') diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index 3db0558b..6d6ec2ea 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -92,7 +92,8 @@ function utilCommandDispatch(command) { } function utilNoteFormat(definition, mode) { - const options = Backend.instance().options; + const yomichan = chrome.extension.getBackgroundPage().yomichanBackend; + const options = yomichan.options; const note = {fields: {}, tags: options.anki.tags}; let fields = []; @@ -137,7 +138,8 @@ async function apiOptionsSet(options) { // to the DOM across to the background page, causing the options object to // become a "DeadObject" after the options page is closed. The workaround used // here is to create a deep copy of the options object. - Backend.instance().options = JSON.parse(JSON.stringify(options)); + const yomichan = chrome.extension.getBackgroundPage().yomichanBackend; + yomichan.options = JSON.parse(JSON.stringify(options)); if (!options.general.enable) { chrome.browserAction.setBadgeBackgroundColor({color: '#d9534f'}); @@ -150,9 +152,9 @@ async function apiOptionsSet(options) { } if (options.anki.enable) { - Backend.instance().anki = new AnkiConnect(options.anki.server); + yomichan.anki = new AnkiConnect(options.anki.server); } else { - Backend.instance().anki = new AnkiNull(); + yomichan.anki = new AnkiNull(); } chrome.tabs.query({}, tabs => { @@ -163,12 +165,14 @@ async function apiOptionsSet(options) { } async function apiOptionsGet() { - return Backend.instance().options; + const yomichan = chrome.extension.getBackgroundPage().yomichanBackend; + return yomichan.options; } async function apiTermsFind(text) { - const options = Backend.instance().options; - const translator = Backend.instance().translator; + const yomichan = chrome.extension.getBackgroundPage().yomichanBackend; + const options = yomichan.options; + const translator = yomichan.translator; const searcher = options.general.groupResults ? translator.findTermsGrouped.bind(translator) : @@ -187,14 +191,17 @@ async function apiTermsFind(text) { } async function apiKanjiFind(text) { - const options = Backend.instance().options; - const definitions = await Backend.instance().translator.findKanji(text, dictEnabledSet(options)); + const yomichan = chrome.extension.getBackgroundPage().yomichanBackend; + const options = yomichan.options; + const definitions = await yomichan.translator.findKanji(text, dictEnabledSet(options)); return definitions.slice(0, options.general.maxResults); } async function apiDefinitionAdd(definition, mode) { + const yomichan = chrome.extension.getBackgroundPage().yomichanBackend; + if (mode !== 'kanji') { - const options = Backend.instance().options; + const options = yomichan.options; await audioInject( definition, options.anki.terms.fields, @@ -202,7 +209,7 @@ async function apiDefinitionAdd(definition, mode) { ); } - return Backend.instance().anki.addNote(utilNoteFormat(definition, mode)); + return yomichan.anki.addNote(utilNoteFormat(definition, mode)); } async function apiDefinitionsAddable(definitions, modes) { @@ -213,7 +220,8 @@ async function apiDefinitionsAddable(definitions, modes) { } } - const results = await Backend.instance().anki.canAddNotes(notes); + const yomichan = chrome.extension.getBackgroundPage().yomichanBackend; + const results = await yomichan.anki.canAddNotes(notes); const states = []; for (let resultBase = 0; resultBase < results.length; resultBase += modes.length) { const state = {}; @@ -228,7 +236,8 @@ async function apiDefinitionsAddable(definitions, modes) { } async function apiNoteView(noteId) { - return Backend.instance().anki.guiBrowse(`nid:${noteId}`); + const yomichan = chrome.extension.getBackgroundPage().yomichanBackend; + return yomichan.anki.guiBrowse(`nid:${noteId}`); } async function apiTemplateRender(template, data) { diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 0615ffae..4fabe4b2 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -17,7 +17,7 @@ */ -class Backend { +window.yomichanBackend = new class { constructor() { handlebarsRegister(); @@ -36,10 +36,4 @@ class Backend { } }); } - - static instance() { - return chrome.extension.getBackgroundPage().yomichanBackend; - } -} - -window.yomichanBackend = new Backend(); +}; diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index 3cd64fbd..09e92249 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -17,6 +17,41 @@ */ +/* + * Utilities + */ + +function utilAnkiGetModelNames() { + const yomichan = chrome.extension.getBackgroundPage().yomichanBackend; + return yomichan.anki.getModelNames(); +} + +function utilAnkiGetDeckNames() { + const yomichan = chrome.extension.getBackgroundPage().yomichanBackend; + return yomichan.anki.getDeckNames(); +} + +function utilAnkiGetModelFieldNames(modelName) { + const yomichan = chrome.extension.getBackgroundPage().yomichanBackend; + return yomichan.anki.utilAnkiGetModelFieldNames(modelName); +} + +function utilDatabaseGetDictionaries() { + const yomichan = chrome.extension.getBackgroundPage().yomichanBackend; + return yomichan.translator.database.getDictionaries(); +} + +function utilDatabasePurge() { + const yomichan = chrome.extension.getBackgroundPage().yomichanBackend; + return yomichan.translator.database.purge(); +} + +function utilDatabaseImport(data, progress) { + const yomichan = chrome.extension.getBackgroundPage().yomichanBackend; + return yomichan.translator.database.importDictionary(data, progress); +} + + /* * General */ @@ -217,7 +252,7 @@ async function dictionaryGroupsPopulate(options) { const dictGroups = $('#dict-groups').empty(); const dictWarning = $('#dict-warning').hide(); - const dictRows = await instDb().getDictionaries(); + const dictRows = await utilDatabaseGetDictionaries(); if (dictRows.length === 0) { dictWarning.show(); } @@ -253,7 +288,7 @@ async function onDictionaryPurge(e) {(async () => { dictionaryErrorShow(); dictionarySpinnerShow(true); - await instDb().purge(); + await utilDatabasePurge(); const options = await optionsLoad(); options.dictionaries = {}; await optionsSave(options); @@ -283,7 +318,7 @@ function onDictionaryImport(e) {(async () => { setProgress(0.0); const options = await optionsLoad(); - const summary = await instDb().importDictionary(e.target.files[0], updateProgress); + const summary = await utilDatabaseImport(e.target.files[0], updateProgress); options.dictionaries[summary.title] = {enabled: true, priority: 0}; await optionsSave(options); @@ -344,12 +379,12 @@ async function ankiDeckAndModelPopulate(options) { $('#anki-terms-deck').val(options.anki.terms.deck); $('#anki-kanji-deck').val(options.anki.kanji.deck); - const deckNames = await instAnki().getDeckNames(); + const deckNames = await utilAnkiGetDeckNames(); const ankiDeck = $('.anki-deck'); ankiDeck.find('option').remove(); deckNames.sort().forEach(name => ankiDeck.append($('