From 516c7f5381700700dcfdfb06682f11de8205137b Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 16 Jul 2017 12:48:27 -0700 Subject: refactor mixed/js/util.js --- ext/bg/search.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/bg/search.html') diff --git a/ext/bg/search.html b/ext/bg/search.html index 4c07ee61..0fc3caf7 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -34,7 +34,7 @@ - + -- 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/search.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 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/search.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/search.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/search.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 b061cc914210e6c11bc419c38ec850b59d72dd4d Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sat, 29 Jul 2017 09:55:54 -0700 Subject: cleanup --- ext/bg/js/backend.js | 2 - ext/bg/js/dictionary.js | 2 +- ext/bg/js/display-window.js | 14 +++-- ext/bg/js/handlebars.js | 14 ++--- ext/bg/js/settings.js | 2 - ext/bg/js/templates.js | 136 ++++++++++++++++++++++---------------------- ext/bg/search.html | 12 +++- ext/fg/frame.html | 9 +-- 8 files changed, 99 insertions(+), 92 deletions(-) (limited to 'ext/bg/search.html') diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 2763a141..f7823047 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -19,8 +19,6 @@ window.yomichan = new class { constructor() { - handlebarsRegister(); - this.translator = new Translator(); this.anki = new AnkiNull(); this.options = null; diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 6f4ec809..73efe7d1 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -225,7 +225,7 @@ function dictFieldFormat(field, definition, mode, options) { field = field.replace( `{${marker}}`, - Handlebars.templates['fields.html'](data).trim() + handlebarsRender('fields.html', data) ); } diff --git a/ext/bg/js/display-window.js b/ext/bg/js/display-window.js index e5357bf9..1f607510 100644 --- a/ext/bg/js/display-window.js +++ b/ext/bg/js/display-window.js @@ -37,11 +37,15 @@ window.displayWindow = new class extends Display { $('#query').focus().select(); } - onSearch(e) { + async onSearch(e) { e.preventDefault(); - $('#intro').slideUp(); - instYomi().termsFind($('#query').val()).then(({length, definitions}) => { - super.showTermDefs(definitions, instYomi().options); - }).catch(this.handleError.bind(this)); + + try { + $('#intro').slideUp(); + const {length, definitions} = await apiTermsFind($('#query').val()); + super.showTermDefs(definitions, await apiOptionsGet()); + } catch (e) { + this.handleError(e); + } } }; diff --git a/ext/bg/js/handlebars.js b/ext/bg/js/handlebars.js index 42b36927..df98bef1 100644 --- a/ext/bg/js/handlebars.js +++ b/ext/bg/js/handlebars.js @@ -43,13 +43,13 @@ 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) { + if (Handlebars.partials !== Handlebars.templates) { + Handlebars.partials = Handlebars.templates; + Handlebars.registerHelper('dumpObject', handlebarsDumpObject); + Handlebars.registerHelper('kanjiLinks', handlebarsKanjiLinks); + Handlebars.registerHelper('multiLine', handlebarsMultiLine); + } + return Handlebars.templates[template](data); } diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index a0406e0c..fa44c8da 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -158,8 +158,6 @@ async function onFormOptionsChanged(e) {(async () => { })();} function onReady() {(async () => { - handlebarsRegister(); - const options = await optionsLoad(); $('#show-usage-guide').prop('checked', options.general.showGuide); diff --git a/ext/bg/js/templates.js b/ext/bg/js/templates.js index 6fa1dad0..7e05015a 100644 --- a/ext/bg/js/templates.js +++ b/ext/bg/js/templates.js @@ -3,7 +3,7 @@ templates['dictionary.html'] = template({"1":function(container,depth0,helpers,partials,data) { return "checked"; },"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) { - var stack1, helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; + var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return "
(" - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.tags : depth0),{"name":"each","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.tags : depth0),{"name":"each","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + ") "; },"5":function(container,depth0,helpers,partials,data) { - var stack1, helper, alias1=depth0 != null ? depth0 : {}; + var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}); return container.escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(alias1,{"name":"name","hash":{},"data":data}) : helper))) + ((stack1 = helpers.unless.call(alias1,(data && data.last),{"name":"unless","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); @@ -51,12 +51,12 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti var stack1; return "
    " - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(9, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(9, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "
"; },"9":function(container,depth0,helpers,partials,data) { var stack1, helper, options, buffer = "
  • "; - stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},options) : helper)); + stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper)); if (!helpers.multiLine) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)} if (stack1 != null) { buffer += stack1; } return buffer + "
  • "; @@ -65,7 +65,7 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti },"12":function(container,depth0,helpers,partials,data) { var stack1, helper, options, buffer = ""; - stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(13, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},options) : helper)); + stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(13, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper)); if (!helpers.multiLine) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)} if (stack1 != null) { buffer += stack1; } return buffer; @@ -74,29 +74,29 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti return container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["0"] : stack1), depth0)); },"15":function(container,depth0,helpers,partials,data) { - var stack1, alias1=depth0 != null ? depth0 : {}; + var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {}); return ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.brief : depth0),{"name":"unless","hash":{},"fn":container.program(16, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + ((stack1 = helpers["if"].call(alias1,((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(19, data, 0),"inverse":container.program(13, data, 0),"data":data})) != null ? stack1 : ""); },"16":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.tags : depth0),{"name":"if","hash":{},"fn":container.program(17, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.tags : depth0),{"name":"if","hash":{},"fn":container.program(17, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"17":function(container,depth0,helpers,partials,data) { var stack1; return "(" - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.tags : depth0),{"name":"each","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.tags : depth0),{"name":"each","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + ") "; },"19":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"20":function(container,depth0,helpers,partials,data) { var stack1; return container.escapeExpression(container.lambda(depth0, depth0)) - + ((stack1 = helpers.unless.call(depth0 != null ? depth0 : {},(data && data.last),{"name":"unless","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); + + ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.last),{"name":"unless","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"22":function(container,depth0,helpers,partials,data) { return ""; },"24":function(container,depth0,helpers,partials,data) { @@ -110,11 +110,11 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti },"28":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.modeTermKana : depth0),{"name":"if","hash":{},"fn":container.program(29, data, 0),"inverse":container.program(32, data, 0),"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.modeTermKana : depth0),{"name":"if","hash":{},"fn":container.program(29, data, 0),"inverse":container.program(32, data, 0),"data":data})) != null ? stack1 : ""); },"29":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.reading : stack1),{"name":"if","hash":{},"fn":container.program(30, data, 0),"inverse":container.program(32, data, 0),"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.reading : stack1),{"name":"if","hash":{},"fn":container.program(30, data, 0),"inverse":container.program(32, data, 0),"data":data})) != null ? stack1 : ""); },"30":function(container,depth0,helpers,partials,data) { var stack1; @@ -126,11 +126,11 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti },"34":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(35, data, 0),"inverse":container.program(38, data, 0),"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(35, data, 0),"inverse":container.program(38, data, 0),"data":data})) != null ? stack1 : ""); },"35":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.reading : stack1),{"name":"if","hash":{},"fn":container.program(36, data, 0),"inverse":container.program(32, data, 0),"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.reading : stack1),{"name":"if","hash":{},"fn":container.program(36, data, 0),"inverse":container.program(32, data, 0),"data":data})) != null ? stack1 : ""); },"36":function(container,depth0,helpers,partials,data) { var stack1, alias1=container.lambda, alias2=container.escapeExpression; @@ -142,7 +142,7 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti },"38":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.reading : stack1),{"name":"if","hash":{},"fn":container.program(39, data, 0),"inverse":container.program(32, data, 0),"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.reading : stack1),{"name":"if","hash":{},"fn":container.program(39, data, 0),"inverse":container.program(32, data, 0),"data":data})) != null ? stack1 : ""); },"39":function(container,depth0,helpers,partials,data) { var stack1, alias1=container.lambda, alias2=container.escapeExpression; @@ -151,7 +151,7 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti + alias2(alias1(((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.reading : stack1), depth0)) + "]"; },"41":function(container,depth0,helpers,partials,data,blockParams,depths) { - var stack1, alias1=depth0 != null ? depth0 : {}; + var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {}); return ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(42, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.modeKanji : depth0),{"name":"if","hash":{},"fn":container.program(44, data, 0, blockParams, depths),"inverse":container.program(53, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "") @@ -161,16 +161,16 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti },"44":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(45, data, 0),"inverse":container.program(51, data, 0),"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(45, data, 0),"inverse":container.program(51, data, 0),"data":data})) != null ? stack1 : ""); },"45":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(46, data, 0),"inverse":container.program(49, data, 0),"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(46, data, 0),"inverse":container.program(49, data, 0),"data":data})) != null ? stack1 : ""); },"46":function(container,depth0,helpers,partials,data) { var stack1; return "
      " - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1),{"name":"each","hash":{},"fn":container.program(47, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1),{"name":"each","hash":{},"fn":container.program(47, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "
    "; },"47":function(container,depth0,helpers,partials,data) { return "
  • " @@ -179,7 +179,7 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti },"49":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1),{"name":"each","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1),{"name":"each","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"51":function(container,depth0,helpers,partials,data) { var stack1; @@ -187,20 +187,20 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti },"53":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.group : depth0),{"name":"if","hash":{},"fn":container.program(54, data, 0, blockParams, depths),"inverse":container.program(64, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.group : depth0),{"name":"if","hash":{},"fn":container.program(54, data, 0, blockParams, depths),"inverse":container.program(64, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); },"54":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(55, data, 0, blockParams, depths),"inverse":container.program(62, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(55, data, 0, blockParams, depths),"inverse":container.program(62, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); },"55":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(56, data, 0, blockParams, depths),"inverse":container.program(59, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(56, data, 0, blockParams, depths),"inverse":container.program(59, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); },"56":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; return "
      " - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1),{"name":"each","hash":{},"fn":container.program(57, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1),{"name":"each","hash":{},"fn":container.program(57, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "
    "; },"57":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; @@ -211,7 +211,7 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti },"59":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; - return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1),{"name":"each","hash":{},"fn":container.program(60, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1),{"name":"each","hash":{},"fn":container.program(60, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"60":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; @@ -234,19 +234,19 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti },"70":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.kunyomi : stack1),{"name":"each","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.kunyomi : stack1),{"name":"each","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"72":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.onyomi : stack1),{"name":"each","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.onyomi : stack1),{"name":"each","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"74":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.modeTermKana : depth0),{"name":"unless","hash":{},"fn":container.program(30, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.modeTermKana : depth0),{"name":"unless","hash":{},"fn":container.program(30, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"76":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1),{"name":"if","hash":{},"fn":container.program(77, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1),{"name":"if","hash":{},"fn":container.program(77, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"77":function(container,depth0,helpers,partials,data) { var stack1; @@ -254,7 +254,7 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti },"79":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1),{"name":"if","hash":{},"fn":container.program(80, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1),{"name":"if","hash":{},"fn":container.program(80, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"80":function(container,depth0,helpers,partials,data) { var stack1; @@ -262,7 +262,7 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti },"82":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1),{"name":"if","hash":{},"fn":container.program(83, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1),{"name":"if","hash":{},"fn":container.program(83, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"83":function(container,depth0,helpers,partials,data) { var stack1; @@ -270,7 +270,7 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti },"85":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1),{"name":"if","hash":{},"fn":container.program(86, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1),{"name":"if","hash":{},"fn":container.program(86, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"86":function(container,depth0,helpers,partials,data) { var stack1; @@ -278,11 +278,11 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti },"88":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.tags : stack1),{"name":"each","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.tags : stack1),{"name":"each","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"90":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(91, data, 0),"inverse":container.program(93, data, 0),"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(91, data, 0),"inverse":container.program(93, data, 0),"data":data})) != null ? stack1 : ""); },"91":function(container,depth0,helpers,partials,data) { var stack1, alias1=container.lambda, alias2=container.escapeExpression; @@ -299,7 +299,7 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti var stack1; return "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - + ((stack1 = container.invokePartial(helpers.lookup.call(depth0 != null ? depth0 : {},depth0,"marker",{"name":"lookup","hash":{},"data":data}),depth0,{"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : ""); + + ((stack1 = container.invokePartial(helpers.lookup.call(depth0 != null ? depth0 : (container.nullContext || {}),depth0,"marker",{"name":"lookup","hash":{},"data":data}),depth0,{"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : ""); },"main_d": function(fn, props, container, depth0, data, blockParams, depths) { var decorators = container.decorators; @@ -326,7 +326,7 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti ,"useDecorators":true,"usePartial":true,"useData":true,"useDepths":true}); templates['kanji.html'] = template({"1":function(container,depth0,helpers,partials,data) { - var stack1, helper, alias1=depth0 != null ? depth0 : {}; + var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}); return "
    \n
    \n" + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.addable : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") @@ -353,12 +353,12 @@ templates['kanji.html'] = template({"1":function(container,depth0,helpers,partia return " " + container.escapeExpression(container.lambda(depth0, depth0)) - + ((stack1 = helpers.unless.call(depth0 != null ? depth0 : {},(data && data.last),{"name":"unless","hash":{},"fn":container.program(7, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.last),{"name":"unless","hash":{},"fn":container.program(7, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "\n"; },"7":function(container,depth0,helpers,partials,data) { return ", "; },"9":function(container,depth0,helpers,partials,data) { - var helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; + var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return " \n" - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(12, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(12, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + " \n"; },"12":function(container,depth0,helpers,partials,data) { var stack1, helper, options, buffer = "
  • "; - stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(13, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},options) : helper)); + stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(13, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper)); if (!helpers.multiLine) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)} if (stack1 != null) { buffer += stack1; } return buffer + "
  • \n"; @@ -385,7 +385,7 @@ templates['kanji.html'] = template({"1":function(container,depth0,helpers,partia },"15":function(container,depth0,helpers,partials,data) { var stack1, helper, options, buffer = "
    "; - stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(16, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},options) : helper)); + stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(16, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper)); if (!helpers.multiLine) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)} if (stack1 != null) { buffer += stack1; } return buffer + "
    \n"; @@ -396,7 +396,7 @@ templates['kanji.html'] = template({"1":function(container,depth0,helpers,partia },"18":function(container,depth0,helpers,partials,data) { var stack1, helper, options, buffer = "
    ";
    -  stack1 = ((helper = (helper = helpers.dumpObject || (depth0 != null ? depth0.dumpObject : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"dumpObject","hash":{},"fn":container.program(19, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},options) : helper));
    +  stack1 = ((helper = (helper = helpers.dumpObject || (depth0 != null ? depth0.dumpObject : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"dumpObject","hash":{},"fn":container.program(19, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper));
       if (!helpers.dumpObject) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
       if (stack1 != null) { buffer += stack1; }
       return buffer + "
    \n"; @@ -407,11 +407,11 @@ templates['kanji.html'] = template({"1":function(container,depth0,helpers,partia },"21":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; - return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(22, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(22, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"22":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; - return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : {},(data && data.first),{"name":"unless","hash":{},"fn":container.program(23, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.first),{"name":"unless","hash":{},"fn":container.program(23, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "\n" + ((stack1 = container.invokePartial(partials.kanji,depth0,{"name":"kanji","hash":{"root":(depths[1] != null ? depths[1].root : depths[1]),"source":(depths[1] != null ? depths[1].source : depths[1]),"addable":(depths[1] != null ? depths[1].addable : depths[1]),"debug":(depths[1] != null ? depths[1].debug : depths[1])},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : ""); },"23":function(container,depth0,helpers,partials,data) { @@ -422,7 +422,7 @@ templates['kanji.html'] = template({"1":function(container,depth0,helpers,partia var stack1; return "\n" - + ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(21, data, 0, blockParams, depths),"inverse":container.program(25, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); + + ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(21, data, 0, blockParams, depths),"inverse":container.program(25, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); },"main_d": function(fn, props, container, depth0, data, blockParams, depths) { var decorators = container.decorators; @@ -437,7 +437,7 @@ templates['model.html'] = template({"1":function(container,depth0,helpers,partia + container.escapeExpression(container.lambda(depth0, depth0)) + "\n"; },"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) { - var stack1, helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; + var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return "\n " + alias4(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"name","hash":{},"data":data}) : helper))) @@ -450,7 +450,7 @@ templates['model.html'] = template({"1":function(container,depth0,helpers,partia + " \n
    \n \n \n\n"; },"useData":true}); templates['terms.html'] = template({"1":function(container,depth0,helpers,partials,data) { - var stack1, alias1=depth0 != null ? depth0 : {}; + var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {}); return ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.tags : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + ((stack1 = helpers["if"].call(alias1,((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(5, data, 0),"inverse":container.program(9, data, 0),"data":data})) != null ? stack1 : ""); @@ -458,10 +458,10 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia var stack1; return "
    \n" - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.tags : depth0),{"name":"each","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.tags : depth0),{"name":"each","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "
    \n"; },"3":function(container,depth0,helpers,partials,data) { - var helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; + var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return " \n" - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "\n"; },"6":function(container,depth0,helpers,partials,data) { var stack1, helper, options, buffer = "
  • "; - stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(7, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},options) : helper)); + stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(7, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper)); if (!helpers.multiLine) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)} if (stack1 != null) { buffer += stack1; } return buffer + "
  • \n"; @@ -488,7 +488,7 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia },"9":function(container,depth0,helpers,partials,data) { var stack1, helper, options, buffer = "
    "; - stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},options) : helper)); + stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper)); if (!helpers.multiLine) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)} if (stack1 != null) { buffer += stack1; } return buffer + "
    \n"; @@ -497,7 +497,7 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia return container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["0"] : stack1), depth0)); },"12":function(container,depth0,helpers,partials,data) { - var stack1, alias1=depth0 != null ? depth0 : {}; + var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {}); return "
    \n
    \n" + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.addable : depth0),{"name":"if","hash":{},"fn":container.program(13, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") @@ -516,7 +516,7 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia },"15":function(container,depth0,helpers,partials,data) { return " \n"; },"17":function(container,depth0,helpers,partials,data) { - var stack1, helper, options, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", buffer = + var stack1, helper, options, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", buffer = "
    "; stack1 = ((helper = (helper = helpers.kanjiLinks || (depth0 != null ? depth0.kanjiLinks : depth0)) != null ? helper : alias2),(options={"name":"kanjiLinks","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data}),(typeof helper === alias3 ? helper.call(alias1,options) : helper)); if (!helpers.kanjiLinks) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)} @@ -527,11 +527,11 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia },"18":function(container,depth0,helpers,partials,data) { var helper; - return container.escapeExpression(((helper = (helper = helpers.expression || (depth0 != null ? depth0.expression : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},{"name":"expression","hash":{},"data":data}) : helper))); + return container.escapeExpression(((helper = (helper = helpers.expression || (depth0 != null ? depth0.expression : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"expression","hash":{},"data":data}) : helper))); },"20":function(container,depth0,helpers,partials,data) { var stack1, helper, options, buffer = "
    "; - stack1 = ((helper = (helper = helpers.kanjiLinks || (depth0 != null ? depth0.kanjiLinks : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"kanjiLinks","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},options) : helper)); + stack1 = ((helper = (helper = helpers.kanjiLinks || (depth0 != null ? depth0.kanjiLinks : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"kanjiLinks","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper)); if (!helpers.kanjiLinks) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)} if (stack1 != null) { buffer += stack1; } return buffer + "
    \n"; @@ -539,7 +539,7 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia var stack1; return "
    \n" - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.reasons : depth0),{"name":"each","hash":{},"fn":container.program(23, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.reasons : depth0),{"name":"each","hash":{},"fn":container.program(23, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "
    \n"; },"23":function(container,depth0,helpers,partials,data) { var stack1; @@ -547,19 +547,19 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia return " " + container.escapeExpression(container.lambda(depth0, depth0)) + " " - + ((stack1 = helpers.unless.call(depth0 != null ? depth0 : {},(data && data.last),{"name":"unless","hash":{},"fn":container.program(24, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.last),{"name":"unless","hash":{},"fn":container.program(24, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "\n"; },"24":function(container,depth0,helpers,partials,data) { return "«"; },"26":function(container,depth0,helpers,partials,data) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definitions : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(27, data, 0),"inverse":container.program(30, data, 0),"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definitions : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(27, data, 0),"inverse":container.program(30, data, 0),"data":data})) != null ? stack1 : ""); },"27":function(container,depth0,helpers,partials,data) { var stack1; return "
      \n" - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(28, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(28, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "
    \n"; },"28":function(container,depth0,helpers,partials,data) { var stack1; @@ -578,7 +578,7 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia },"34":function(container,depth0,helpers,partials,data) { var stack1, helper, options, buffer = "
    ";
    -  stack1 = ((helper = (helper = helpers.dumpObject || (depth0 != null ? depth0.dumpObject : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"dumpObject","hash":{},"fn":container.program(35, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},options) : helper));
    +  stack1 = ((helper = (helper = helpers.dumpObject || (depth0 != null ? depth0.dumpObject : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"dumpObject","hash":{},"fn":container.program(35, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper));
       if (!helpers.dumpObject) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
       if (stack1 != null) { buffer += stack1; }
       return buffer + "
    \n"; @@ -589,11 +589,11 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia },"37":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; - return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(38, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : ""); + return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(38, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"38":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; - return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : {},(data && data.first),{"name":"unless","hash":{},"fn":container.program(39, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.first),{"name":"unless","hash":{},"fn":container.program(39, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "\n" + ((stack1 = container.invokePartial(partials.term,depth0,{"name":"term","hash":{"playback":(depths[1] != null ? depths[1].playback : depths[1]),"addable":(depths[1] != null ? depths[1].addable : depths[1]),"grouped":(depths[1] != null ? depths[1].grouped : depths[1]),"debug":(depths[1] != null ? depths[1].debug : depths[1])},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : ""); },"39":function(container,depth0,helpers,partials,data) { @@ -604,7 +604,7 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia var stack1; return "\n\n" - + ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(37, data, 0, blockParams, depths),"inverse":container.program(41, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); + + ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(37, data, 0, blockParams, depths),"inverse":container.program(41, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); },"main_d": function(fn, props, container, depth0, data, blockParams, depths) { var decorators = container.decorators; diff --git a/ext/bg/search.html b/ext/bg/search.html index 7cbae392..655d7819 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -32,13 +32,19 @@
    + + + + - - + + - + + + diff --git a/ext/fg/frame.html b/ext/fg/frame.html index 9ff2c585..e0b9eac5 100644 --- a/ext/fg/frame.html +++ b/ext/fg/frame.html @@ -30,12 +30,13 @@
    - - + + - - + + + -- cgit v1.2.3 From aac2a58b5f821c6f90c95bb19f3b0a755d5e1739 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 13 Aug 2017 16:11:51 -0700 Subject: wip --- ext/bg/background.html | 1 + ext/bg/js/display-window.js | 14 +- ext/bg/search.html | 2 +- ext/fg/frame.html | 4 +- ext/fg/js/display-frame.js | 58 +++----- ext/fg/js/frontend.js | 141 +++++++++--------- ext/fg/js/util.js | 2 +- ext/mixed/js/display.js | 344 ++++++++++++++++++++++++-------------------- 8 files changed, 291 insertions(+), 275 deletions(-) (limited to 'ext/bg/search.html') diff --git a/ext/bg/background.html b/ext/bg/background.html index 40f37b11..fd3b7dd1 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -20,6 +20,7 @@ + diff --git a/ext/bg/js/display-window.js b/ext/bg/js/display-window.js index 52c0cafa..cbb96681 100644 --- a/ext/bg/js/display-window.js +++ b/ext/bg/js/display-window.js @@ -17,26 +17,26 @@ */ -window.displayWindow = new class extends Display { +window.yomichan_window = new class extends Display { constructor() { super($('#spinner'), $('#content')); this.search = $('#search').click(this.onSearch.bind(this)); - this.query = $('#query').on('input', this.inputSearch.bind(this)); + this.query = $('#query').on('input', this.onSearchInput.bind(this)); this.intro = $('#intro'); window.wanakana.bind(this.query.get(0)); } - handleError(error) { + onError(error) { window.alert(`Error: ${error}`); } - clearSearch() { + onSearchClear() { this.query.focus().select(); } - inputSearch() { + onSearchInput() { this.search.prop('disabled', this.query.val().length === 0); } @@ -46,9 +46,9 @@ window.displayWindow = new class extends Display { try { this.intro.slideUp(); const {length, definitions} = await apiTermsFind(this.query.val()); - super.showTermDefs(definitions, await apiOptionsGet()); + super.termsShow(definitions, await apiOptionsGet()); } catch (e) { - this.handleError(e); + this.onError(e); } } }; diff --git a/ext/bg/search.html b/ext/bg/search.html index 655d7819..fe44d74e 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -40,10 +40,10 @@ + - diff --git a/ext/fg/frame.html b/ext/fg/frame.html index 3fe42eb2..dda3ef06 100644 --- a/ext/fg/frame.html +++ b/ext/fg/frame.html @@ -18,9 +18,9 @@ -
    +
    -
    +

    Yomichan Updated!

    diff --git a/ext/fg/js/display-frame.js b/ext/fg/js/display-frame.js index 09bd9255..5ea376c2 100644 --- a/ext/fg/js/display-frame.js +++ b/ext/fg/js/display-frame.js @@ -17,65 +17,45 @@ */ -window.displayFrame = new class extends Display { +window.yomichan_frame = new class extends Display { constructor() { super($('#spinner'), $('#content')); $(window).on('message', this.onMessage.bind(this)); } - definitionAdd(definition, mode) { - return apiDefinitionAdd(definition, mode); - } - - definitionsAddable(definitions, modes) { - return apiDefinitionsAddable(definitions, modes); - } - - noteView(noteId) { - return apiNoteView(noteId); - } - - templateRender(template, data) { - return apiTemplateRender(template, data); - } - - kanjiFind(character) { - return apiKanjiFind(character); - } - - handleError(error) { - if (window.yomichanOrphaned) { - this.showOrphaned(); + onError(error) { + if (window.yomichan_orphaned) { + this.onOrphaned(); } else { window.alert(`Error: ${error}`); } } - clearSearch() { - window.parent.postMessage('popupClose', '*'); + onOrphaned() { + $('#definitions').hide(); + $('#error-orphaned').show(); } - selectionCopy() { - window.parent.postMessage('selectionCopy', '*'); + onSearchClear() { + window.parent.postMessage('popupClose', '*'); } - showOrphaned() { - $('#content').hide(); - $('#orphan').show(); + onSelectionCopy() { + window.parent.postMessage('selectionCopy', '*'); } onMessage(e) { const handlers = { - showTermDefs: ({definitions, options, context}) => { - this.showTermDefs(definitions, options, context); + termsShow: ({definitions, options, context}) => { + this.termsShow(definitions, options, context); }, - showKanjiDefs: ({definitions, options, context}) => { - this.showKanjiDefs(definitions, options, context); + kanjiShow: ({definitions, options, context}) => { + this.kanjiShow(definitions, options, context); }, - showOrphaned: () => { - this.showOrphaned(); + orphaned: () => { + this.onOrphaned(); } }; @@ -89,8 +69,8 @@ window.displayFrame = new class extends Display { onKeyDown(e) { const handlers = { 67: /* c */ () => { - if (e.ctrlKey && window.getSelection().toString() === '') { - this.selectionCopy(); + if (e.ctrlKey && !window.getSelection().toString()) { + this.onSelectionCopy(); return true; } } diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index 9974d878..37389766 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -17,7 +17,7 @@ */ -window.yomichanFrontend = new class { +window.yomichan_frontend = new class { constructor() { this.popup = new Popup(); this.popupTimer = null; @@ -27,17 +27,23 @@ window.yomichanFrontend = new class { this.lastTextSource = null; this.pendingLookup = false; this.options = null; + } + + async prepare() { + try { + this.options = await apiOptionsGet(); + } catch (e) { + this.onError(e); + } - apiOptionsGet().then(options => { - this.options = options; - window.addEventListener('mouseover', this.onMouseOver.bind(this)); - window.addEventListener('mousedown', this.onMouseDown.bind(this)); - window.addEventListener('mouseup', this.onMouseUp.bind(this)); - window.addEventListener('mousemove', this.onMouseMove.bind(this)); - window.addEventListener('resize', e => this.searchClear()); - window.addEventListener('message', this.onFrameMessage.bind(this)); - chrome.runtime.onMessage.addListener(this.onBgMessage.bind(this)); - }).catch(this.handleError.bind(this)); + window.addEventListener('message', this.onFrameMessage.bind(this)); + window.addEventListener('mousedown', this.onMouseDown.bind(this)); + window.addEventListener('mousemove', this.onMouseMove.bind(this)); + window.addEventListener('mouseover', this.onMouseOver.bind(this)); + window.addEventListener('mouseup', this.onMouseUp.bind(this)); + window.addEventListener('resize', this.onResize.bind(this)); + + chrome.runtime.onMessage.addListener(this.onBgMessage.bind(this)); } popupTimerSet(callback) { @@ -144,7 +150,11 @@ window.yomichanFrontend = new class { callback(); } - searchAt(point) { + onResize() { + this.onSearchClear(); + } + + async searchAt(point) { if (this.pendingLookup) { return; } @@ -160,70 +170,69 @@ window.yomichanFrontend = new class { } this.pendingLookup = true; - this.searchTerms(textSource).then(found => { - if (!found) { - return this.searchKanji(textSource); + + try { + if (!await this.searchTerms(textSource)) { + await this.searchKanji(textSource); } - }).catch(error => { - this.handleError(error, textSource); - }).then(() => { - docImposterDestroy(); - this.pendingLookup = false; - }); + } catch (e) { + this.onError(e); + } + + docImposterDestroy(); + this.pendingLookup = false; } - searchTerms(textSource) { + async searchTerms(textSource) { textSource.setEndOffset(this.options.scanning.length); - return apiTermsFind(textSource.text()).then(({definitions, length}) => { - if (definitions.length === 0) { - return false; - } else { - textSource.setEndOffset(length); - - const sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt); - const url = window.location.href; - this.popup.showTermDefs( - textSource.getRect(), - definitions, - this.options, - {sentence, url} - ); - - this.lastTextSource = textSource; - if (this.options.scanning.selectText) { - textSource.select(); - } + const {definitions, length} = await apiTermsFind(textSource.text()); + if (definitions.length === 0) { + return false; + } - return true; - } - }); + textSource.setEndOffset(length); + + const sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt); + const url = window.location.href; + this.popup.termsShow( + textSource.getRect(), + definitions, + this.options, + {sentence, url} + ); + + this.lastTextSource = textSource; + if (this.options.scanning.selectText) { + textSource.select(); + } + + return true; } - searchKanji(textSource) { + async searchKanji(textSource) { textSource.setEndOffset(1); - return apiKanjiFind(textSource.text()).then(definitions => { - if (definitions.length === 0) { - return false; - } else { - const sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt); - const url = window.location.href; - this.popup.showKanjiDefs( - textSource.getRect(), - definitions, - this.options, - {sentence, url} - ); - - this.lastTextSource = textSource; - if (this.options.scanning.selectText) { - textSource.select(); - } + const definitions = await apiKanjiFind(textSource.text()); + if (definitions.length === 0) { + return false; + } - return true; - } - }); + const sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt); + const url = window.location.href; + this.popup.showKanji( + textSource.getRect(), + definitions, + this.options, + {sentence, url} + ); + + this.lastTextSource = textSource; + if (this.options.scanning.selectText) { + textSource.select(); + } + + return true; } searchClear() { @@ -238,7 +247,7 @@ window.yomichanFrontend = new class { } handleError(error, textSource) { - if (window.yomichanOrphaned) { + if (window.yomichan_orphaned) { if (textSource && this.options.scanning.modifier !== 'none') { this.popup.showOrphaned(textSource.getRect(), this.options); } diff --git a/ext/fg/js/util.js b/ext/fg/js/util.js index 311fc065..afa895ba 100644 --- a/ext/fg/js/util.js +++ b/ext/fg/js/util.js @@ -28,7 +28,7 @@ function utilInvoke(action, params={}) { } }); } catch (e) { - window.yomichanOrphaned = true; + window.yomichan_orphaned = true; reject(e.message); } }); diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index f408fb25..97dd7d5c 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -32,171 +32,57 @@ class Display { $(document).keydown(this.onKeyDown.bind(this)); } - handleError(error) { + onError(error) { throw 'override me'; } - clearSearch() { + onSearchClear() { throw 'override me'; } - showTermDefs(definitions, options, context) { - window.focus(); - - this.spinner.hide(); - this.definitions = definitions; - this.options = options; - this.context = context; - - const sequence = ++this.sequence; - const params = { - definitions, - addable: options.anki.enable, - grouped: options.general.groupResults, - playback: options.general.audioSource !== 'disabled', - debug: options.general.debugInfo - }; - - if (context) { - for (const definition of definitions) { - if (context.sentence) { - definition.cloze = Display.clozeBuild(context.sentence, definition.source); - } - - definition.url = context.url; - } - } - - apiTemplateRender('terms.html', params).then(content => { - this.container.html(content); - this.entryScroll(context && context.index || 0); - - $('.action-add-note').click(this.onAddNote.bind(this)); - $('.action-view-note').click(this.onViewNote.bind(this)); - $('.action-play-audio').click(this.onPlayAudio.bind(this)); - $('.kanji-link').click(this.onKanjiLookup.bind(this)); - - return this.adderButtonsUpdate(['term-kanji', 'term-kana'], sequence); - }).catch(this.handleError.bind(this)); - } - - showKanjiDefs(definitions, options, context) { - window.focus(); - - this.spinner.hide(); - this.definitions = definitions; - this.options = options; - this.context = context; - - const sequence = ++this.sequence; - const params = { - definitions, - source: context && context.source, - addable: options.anki.enable, - debug: options.general.debugInfo - }; - - if (context) { - for (const definition of definitions) { - if (context.sentence) { - definition.cloze = Display.clozeBuild(context.sentence); - } - - definition.url = context.url; - } - } - - apiTemplateRender('kanji.html', params).then(content => { - this.container.html(content); - this.entryScroll(context && context.index || 0); - - $('.action-add-note').click(this.onAddNote.bind(this)); - $('.source-term').click(this.onSourceTerm.bind(this)); - - return this.adderButtonsUpdate(['kanji'], sequence); - }).catch(this.handleError.bind(this)); - } - - adderButtonsUpdate(modes, sequence) { - return apiDefinitionsAddable(this.definitions, modes).then(states => { - if (!states || sequence !== this.sequence) { - return; - } - - states.forEach((state, index) => { - for (const mode in state) { - const button = Display.adderButtonFind(index, mode); - if (state[mode]) { - button.removeClass('disabled'); - } else { - button.addClass('disabled'); - } - - button.removeClass('pending'); - } - }); - }); - } - - entryScroll(index, smooth) { - index = Math.min(index, this.definitions.length - 1); - index = Math.max(index, 0); - - $('.current').hide().eq(index).show(); - - const container = $('html,body').stop(); - const entry = $('.entry').eq(index); - const target = index === 0 ? 0 : entry.offset().top; - - if (smooth) { - container.animate({scrollTop: target}, 200); - } else { - container.scrollTop(target); - } - - this.index = index; - } - - onSourceTerm(e) { + onSourceTermView(e) { e.preventDefault(); this.sourceBack(); } - onKanjiLookup(e) { - e.preventDefault(); + async onKanjiLookup(e) { + try { + e.preventDefault(); - const link = $(e.target); - const context = { - source: { - definitions: this.definitions, - index: Display.entryIndexFind(link) + const link = $(e.target); + const context = { + source: { + definitions: this.definitions, + index: Display.entryIndexFind(link) + } + }; + + if (this.context) { + context.sentence = this.context.sentence; + context.url = this.context.url; } - }; - if (this.context) { - context.sentence = this.context.sentence; - context.url = this.context.url; + const kanjiDefs = await apiKanjiFind(link.text()); + this.kanjiShow(kanjiDefs, this.options, context); + } catch (e) { + this.onError(e); } - - apiKanjiFind(link.text()).then(kanjiDefs => { - this.showKanjiDefs(kanjiDefs, this.options, context); - }).catch(this.handleError.bind(this)); } - onPlayAudio(e) { + onAudioPlay(e) { e.preventDefault(); const index = Display.entryIndexFind($(e.currentTarget)); this.audioPlay(this.definitions[index]); } - onAddNote(e) { + onNoteAdd(e) { e.preventDefault(); const link = $(e.currentTarget); const index = Display.entryIndexFind(link); this.noteAdd(this.definitions[index], link.data('mode')); } - onViewNote(e) { + onNoteView(e) { e.preventDefault(); const link = $(e.currentTarget); const index = Display.entryIndexFind(link); @@ -220,48 +106,48 @@ class Display { const handlers = { 27: /* escape */ () => { - this.clearSearch(); + this.onSearchClear(); return true; }, 33: /* page up */ () => { if (e.altKey) { - this.entryScroll(this.index - 3, true); + this.entryScrollIntoView(this.index - 3, true); return true; } }, 34: /* page down */ () => { if (e.altKey) { - this.entryScroll(this.index + 3, true); + this.entryScrollIntoView(this.index + 3, true); return true; } }, 35: /* end */ () => { if (e.altKey) { - this.entryScroll(this.definitions.length - 1, true); + this.entryScrollIntoView(this.definitions.length - 1, true); return true; } }, 36: /* home */ () => { if (e.altKey) { - this.entryScroll(0, true); + this.entryScrollIntoView(0, true); return true; } }, 38: /* up */ () => { if (e.altKey) { - this.entryScroll(this.index - 1, true); + this.entryScrollIntoView(this.index - 1, true); return true; } }, 40: /* down */ () => { if (e.altKey) { - this.entryScroll(this.index + 1, true); + this.entryScrollIntoView(this.index + 1, true); return true; } }, @@ -317,6 +203,135 @@ class Display { } } + async termsShow(definitions, options, context) { + try { + window.focus(); + + this.definitions = definitions; + this.options = options; + this.context = context; + + const sequence = ++this.sequence; + const params = { + definitions, + addable: options.anki.enable, + grouped: options.general.groupResults, + playback: options.general.audioSource !== 'disabled', + debug: options.general.debugInfo + }; + + if (context) { + for (const definition of definitions) { + if (context.sentence) { + definition.cloze = Display.clozeBuild(context.sentence, definition.source); + } + + definition.url = context.url; + } + } + + const content = await apiTemplateRender('terms.html', params); + this.container.html(content); + this.entryScrollIntoView(context && context.index || 0); + + $('.action-add-note').click(this.onNoteAdd.bind(this)); + $('.action-view-note').click(this.onNoteView.bind(this)); + $('.action-play-audio').click(this.onAudioPlay.bind(this)); + $('.kanji-link').click(this.onKanjiLookup.bind(this)); + + await this.adderButtonUpdate(['term-kanji', 'term-kana'], sequence); + } catch (e) { + this.onError(e); + } + } + + async kanjiShow(definitions, options, context) { + try { + window.focus(); + + this.definitions = definitions; + this.options = options; + this.context = context; + + const sequence = ++this.sequence; + const params = { + definitions, + source: context && context.source, + addable: options.anki.enable, + debug: options.general.debugInfo + }; + + if (context) { + for (const definition of definitions) { + if (context.sentence) { + definition.cloze = Display.clozeBuild(context.sentence); + } + + definition.url = context.url; + } + } + + const content = await apiTemplateRender('kanji.html', params); + this.container.html(content); + this.entryScrollIntoView(context && context.index || 0); + + $('.action-add-note').click(this.onNoteAdd.bind(this)); + $('.source-term').click(this.onSourceTermView.bind(this)); + + await this.adderButtonUpdate(['kanji'], sequence); + } catch (e) { + this.onError(e); + } + } + + async adderButtonUpdate(modes, sequence) { + try { + this.spinner.show(); + + const states = apiDefinitionsAddable(this.definitions, modes); + if (!states || sequence !== this.sequence) { + return; + } + + for (let i = 0; i < states.length; ++i) { + const state = states[i]; + for (const mode in state) { + const button = Display.adderButtonFind(i, mode); + if (state[mode]) { + button.removeClass('disabled'); + } else { + button.addClass('disabled'); + } + + button.removeClass('pending'); + } + } + } catch (e) { + this.onError(e); + } finally { + this.spinner.hide(); + } + } + + entryScrollIntoView(index, smooth) { + index = Math.min(index, this.definitions.length - 1); + index = Math.max(index, 0); + + $('.current').hide().eq(index).show(); + + const container = $('html,body').stop(); + const entry = $('.entry').eq(index); + const target = index === 0 ? 0 : entry.offset().top; + + if (smooth) { + container.animate({scrollTop: target}, 200); + } else { + container.scrollTop(target); + } + + this.index = index; + } + sourceBack() { if (this.context && this.context.source) { const context = { @@ -325,35 +340,42 @@ class Display { index: this.context.source.index }; - this.showTermDefs(this.context.source.definitions, this.options, context); + this.termsShow(this.context.source.definitions, this.options, context); } } - noteAdd(definition, mode) { - this.spinner.show(); - return apiDefinitionAdd(definition, mode).then(noteId => { + async noteAdd(definition, mode) { + try { + this.spinner.show(); + + const noteId = await apiDefinitionAdd(definition, mode); if (noteId) { const index = this.definitions.indexOf(definition); Display.adderButtonFind(index, mode).addClass('disabled'); Display.viewerButtonFind(index).removeClass('pending disabled').data('noteId', noteId); } else { - this.handleError('note could not be added'); + throw 'note could note be added'; } - }).catch(this.handleError.bind(this)).then(() => this.spinner.hide()); + } catch (e) { + this.onError(e); + } finally { + this.spinner.hide(); + } } - audioPlay(definition) { - this.spinner.show(); - - for (const key in this.audioCache) { - this.audioCache[key].pause(); - } + async audioPlay(definition) { + try { + this.spinner.show(); - audioBuildUrl(definition, this.options.general.audioSource, this.responseCache).then(url => { + let url = await audioBuildUrl(definition, this.options.general.audioSource, this.responseCache); if (!url) { url = '/mixed/mp3/button.mp3'; } + for (const key in this.audioCache) { + this.audioCache[key].pause(); + } + let audio = this.audioCache[url]; if (audio) { audio.currentTime = 0; @@ -371,7 +393,11 @@ class Display { audio.play(); }; } - }).catch(this.handleError.bind(this)).then(() => this.spinner.hide()); + } catch (e) { + this.onError(e); + } finally { + this.spinner.hide(); + } } static clozeBuild(sentence, source) { -- cgit v1.2.3 From 82863cd86156d48b9f18dc10a560bedb82641862 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Mon, 14 Aug 2017 19:55:04 -0700 Subject: renaming files --- ext/bg/context.html | 43 +++++++++++++ ext/bg/js/context.js | 31 ++++++++++ ext/bg/js/display-window.js | 54 ---------------- ext/bg/js/popup.js | 31 ---------- ext/bg/js/search.js | 56 +++++++++++++++++ ext/bg/popup.html | 43 ------------- ext/bg/search.html | 4 +- ext/fg/css/client.css | 2 +- ext/fg/float.html | 43 +++++++++++++ ext/fg/frame.html | 43 ------------- ext/fg/js/display-frame.js | 86 -------------------------- ext/fg/js/float.js | 88 ++++++++++++++++++++++++++ ext/fg/js/popup.js | 4 +- ext/manifest.json | 5 +- ext/mixed/css/display.css | 146 ++++++++++++++++++++++++++++++++++++++++++++ ext/mixed/css/frame.css | 146 -------------------------------------------- 16 files changed, 414 insertions(+), 411 deletions(-) create mode 100644 ext/bg/context.html create mode 100644 ext/bg/js/context.js delete mode 100644 ext/bg/js/display-window.js delete mode 100644 ext/bg/js/popup.js create mode 100644 ext/bg/js/search.js delete mode 100644 ext/bg/popup.html create mode 100644 ext/fg/float.html delete mode 100644 ext/fg/frame.html delete mode 100644 ext/fg/js/display-frame.js create mode 100644 ext/fg/js/float.js create mode 100644 ext/mixed/css/display.css delete mode 100644 ext/mixed/css/frame.css (limited to 'ext/bg/search.html') diff --git a/ext/bg/context.html b/ext/bg/context.html new file mode 100644 index 00000000..3828c9fe --- /dev/null +++ b/ext/bg/context.html @@ -0,0 +1,43 @@ + + + + + + + + + + +

    + +

    +

    +

    + + + +
    +

    + + + + + + + + + + + + + + diff --git a/ext/bg/js/context.js b/ext/bg/js/context.js new file mode 100644 index 00000000..77cb5166 --- /dev/null +++ b/ext/bg/js/context.js @@ -0,0 +1,31 @@ +/* + * 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 . + */ + + +$(document).ready(() => { + $('#open-search').click(() => apiCommandExec('search')); + $('#open-options').click(() => apiCommandExec('options')); + $('#open-help').click(() => apiCommandExec('help')); + + optionsLoad().then(options => { + const toggle = $('#enable-search'); + toggle.prop('checked', options.general.enable).change(); + toggle.bootstrapToggle(); + toggle.change(() => apiCommandExec('toggle')); + }); +}); diff --git a/ext/bg/js/display-window.js b/ext/bg/js/display-window.js deleted file mode 100644 index cbb96681..00000000 --- a/ext/bg/js/display-window.js +++ /dev/null @@ -1,54 +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 . - */ - - -window.yomichan_window = new class extends Display { - constructor() { - super($('#spinner'), $('#content')); - - this.search = $('#search').click(this.onSearch.bind(this)); - this.query = $('#query').on('input', this.onSearchInput.bind(this)); - this.intro = $('#intro'); - - window.wanakana.bind(this.query.get(0)); - } - - onError(error) { - window.alert(`Error: ${error}`); - } - - onSearchClear() { - this.query.focus().select(); - } - - onSearchInput() { - this.search.prop('disabled', this.query.val().length === 0); - } - - async onSearch(e) { - e.preventDefault(); - - try { - this.intro.slideUp(); - const {length, definitions} = await apiTermsFind(this.query.val()); - super.termsShow(definitions, await apiOptionsGet()); - } catch (e) { - this.onError(e); - } - } -}; diff --git a/ext/bg/js/popup.js b/ext/bg/js/popup.js deleted file mode 100644 index 77cb5166..00000000 --- a/ext/bg/js/popup.js +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 . - */ - - -$(document).ready(() => { - $('#open-search').click(() => apiCommandExec('search')); - $('#open-options').click(() => apiCommandExec('options')); - $('#open-help').click(() => apiCommandExec('help')); - - optionsLoad().then(options => { - const toggle = $('#enable-search'); - toggle.prop('checked', options.general.enable).change(); - toggle.bootstrapToggle(); - toggle.change(() => apiCommandExec('toggle')); - }); -}); diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js new file mode 100644 index 00000000..87f50c32 --- /dev/null +++ b/ext/bg/js/search.js @@ -0,0 +1,56 @@ +/* + * 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 . + */ + + +class DisplaySearch extends Display { + constructor() { + super($('#spinner'), $('#content')); + + this.search = $('#search').click(this.onSearch.bind(this)); + this.query = $('#query').on('input', this.onSearchInput.bind(this)); + this.intro = $('#intro'); + + window.wanakana.bind(this.query.get(0)); + } + + onError(error) { + window.alert(`Error: ${error}`); + } + + onSearchClear() { + this.query.focus().select(); + } + + onSearchInput() { + this.search.prop('disabled', this.query.val().length === 0); + } + + async onSearch(e) { + e.preventDefault(); + + try { + this.intro.slideUp(); + const {length, definitions} = await apiTermsFind(this.query.val()); + super.termsShow(definitions, await apiOptionsGet()); + } catch (e) { + this.onError(e); + } + } +} + +window.yomichan_search = new DisplaySearch(); diff --git a/ext/bg/popup.html b/ext/bg/popup.html deleted file mode 100644 index 60253d6f..00000000 --- a/ext/bg/popup.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - -

    - -

    -

    -

    - - - -
    -

    - - - - - - - - - - - - - - diff --git a/ext/bg/search.html b/ext/bg/search.html index fe44d74e..d10530f9 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -5,7 +5,7 @@ Yomichan Search - +
    @@ -45,6 +45,6 @@ - + diff --git a/ext/fg/css/client.css b/ext/fg/css/client.css index 9f566480..b5b1f6bd 100644 --- a/ext/fg/css/client.css +++ b/ext/fg/css/client.css @@ -17,7 +17,7 @@ */ -iframe#yomichan-popup { +iframe#yomichan-float { all: initial; background-color: #fff; border: 1px solid #999; diff --git a/ext/fg/float.html b/ext/fg/float.html new file mode 100644 index 00000000..a3b66c92 --- /dev/null +++ b/ext/fg/float.html @@ -0,0 +1,43 @@ + + + + + + + + + + + +
    + +
    + +
    + +
    +
    +

    Yomichan Updated!

    +

    + The Yomichan extension has been updated to a new version! In order to continue + viewing definitions on this page you must reload this tab or restart your browser. +

    +
    +
    + + + + + + + + + + + + diff --git a/ext/fg/frame.html b/ext/fg/frame.html deleted file mode 100644 index dda3ef06..00000000 --- a/ext/fg/frame.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - -
    - -
    - -
    - -
    -
    -

    Yomichan Updated!

    -

    - The Yomichan extension has been updated to a new version! In order to continue - viewing definitions on this page you must reload this tab or restart your browser. -

    -
    -
    - - - - - - - - - - - - diff --git a/ext/fg/js/display-frame.js b/ext/fg/js/display-frame.js deleted file mode 100644 index e3f3e692..00000000 --- a/ext/fg/js/display-frame.js +++ /dev/null @@ -1,86 +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 . - */ - - -window.yomichan_frame = new class extends Display { - constructor() { - super($('#spinner'), $('#definitions')); - $(window).on('message', this.onMessage.bind(this)); - } - - onError(error) { - if (window.yomichan_orphaned) { - this.onOrphaned(); - } else { - window.alert(`Error: ${error}`); - } - } - - onOrphaned() { - $('#definitions').hide(); - $('#error-orphaned').show(); - } - - onSearchClear() { - window.parent.postMessage('popupClose', '*'); - } - - onSelectionCopy() { - window.parent.postMessage('selectionCopy', '*'); - } - - onMessage(e) { - const handlers = { - termsShow: ({definitions, options, context}) => { - this.termsShow(definitions, options, context); - }, - - kanjiShow: ({definitions, options, context}) => { - this.kanjiShow(definitions, options, context); - }, - - orphaned: () => { - this.onOrphaned(); - } - }; - - const {action, params} = e.originalEvent.data; - const handler = handlers[action]; - if (handler) { - handler(params); - } - } - - onKeyDown(e) { - const handlers = { - 67: /* c */ () => { - if (e.ctrlKey && !window.getSelection().toString()) { - this.onSelectionCopy(); - return true; - } - } - }; - - const handler = handlers[e.keyCode]; - if (handler && handler()) { - e.preventDefault(); - } else { - super.onKeyDown(e); - } - } -}; diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js new file mode 100644 index 00000000..59293239 --- /dev/null +++ b/ext/fg/js/float.js @@ -0,0 +1,88 @@ +/* + * 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 . + */ + + +class DisplayFloat extends Display { + constructor() { + super($('#spinner'), $('#definitions')); + $(window).on('message', e => this.onMessage(e)); + } + + onError(error) { + if (window.yomichan_orphaned) { + this.onOrphaned(); + } else { + window.alert(`Error: ${error}`); + } + } + + onOrphaned() { + $('#definitions').hide(); + $('#error-orphaned').show(); + } + + onSearchClear() { + window.parent.postMessage('popupClose', '*'); + } + + onSelectionCopy() { + window.parent.postMessage('selectionCopy', '*'); + } + + onMessage(e) { + const handlers = { + termsShow: ({definitions, options, context}) => { + this.termsShow(definitions, options, context); + }, + + kanjiShow: ({definitions, options, context}) => { + this.kanjiShow(definitions, options, context); + }, + + orphaned: () => { + this.onOrphaned(); + } + }; + + const {action, params} = e.originalEvent.data; + const handler = handlers[action]; + if (handler) { + handler(params); + } + } + + onKeyDown(e) { + const handlers = { + 67: /* c */ () => { + if (e.ctrlKey && !window.getSelection().toString()) { + this.onSelectionCopy(); + return true; + } + } + }; + + const handler = handlers[e.keyCode]; + if (handler && handler()) { + e.preventDefault(); + } else { + super.onKeyDown(e); + } + } +} + +window.yomichan_display = new DisplayFloat(); diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index ba3289d4..8e61169a 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -20,10 +20,10 @@ class Popup { constructor() { this.container = document.createElement('iframe'); - this.container.id = 'yomichan-popup'; + this.container.id = 'yomichan-float'; this.container.addEventListener('mousedown', e => e.stopPropagation()); this.container.addEventListener('scroll', e => e.stopPropagation()); - this.container.setAttribute('src', chrome.extension.getURL('/fg/frame.html')); + this.container.setAttribute('src', chrome.extension.getURL('/fg/float.html')); this.container.style.width = '0px'; this.container.style.height = '0px'; this.injected = null; diff --git a/ext/manifest.json b/ext/manifest.json index ee3bd2ac..a8b68bfb 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -7,7 +7,7 @@ "icons": {"16": "mixed/img/icon16.png", "48": "mixed/img/icon48.png", "128": "mixed/img/icon128.png"}, "browser_action": { "default_icon": {"19": "mixed/img/icon19.png", "38": "mixed/img/icon38.png"}, - "default_popup": "bg/popup.html" + "default_popup": "bg/context.html" }, "author": "Alex Yatskov", @@ -20,7 +20,6 @@ "fg/js/popup.js", "fg/js/source.js", "fg/js/util.js", - "fg/js/frontend.js" ], "css": ["fg/css/client.css"] @@ -48,7 +47,7 @@ "description": "Open search window" } }, - "web_accessible_resources": ["fg/frame.html"], + "web_accessible_resources": ["fg/float.html"], "applications": { "gecko": { "id": "yomichan-live@foosoft.net", diff --git a/ext/mixed/css/display.css b/ext/mixed/css/display.css new file mode 100644 index 00000000..8b1819bd --- /dev/null +++ b/ext/mixed/css/display.css @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2016 Alex Yatskov + * Author: Alex Yatskov + * + * This program is free software: you can redistribute it and/or modify + * it under the entrys 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 . + */ + + +/* + * Fonts + */ + +@font-face { + font-family: kanji-stroke-orders; + src: url('/mixed/ttf/kanji-stroke-orders.ttf'); +} + +/* + * General + */ + +hr { + padding: 0px; + margin: 0px; +} + +#spinner { + bottom: 5px; + display: none; + position: fixed; + right: 5px; +} + +#error-orphaned { + display: none; +} + + +/* + * Entries + */ + +.entry, .note { + padding-top: 10px; + padding-bottom: 10px; +} + +.tag-default { + background-color: #8a8a91; +} + +.tag-name { + background-color: #5cb85c; +} + +.tag-expression { + background-color: #f0ad4e; +} + +.tag-popular { + background-color: #0275d8; +} + +.tag-frequent { + background-color: #5bc0de; +} + +.tag-archaism { + background-color: #d9534f; +} + +.tag-dictionary { + background-color: #aa66cc; +} + +.actions .disabled { + pointer-events: none; + cursor: default; +} + +.actions .disabled img { + -webkit-filter: grayscale(100%); + opacity: 0.25; +} + +.actions .pending { + visibility: hidden; +} + +.actions { + display: inline-block; + float: right; +} + +.actions:after { + clear: both; + content: ''; + display: block; +} + +.expression { + display: inline-block; + font-size: 24px; +} + +.expression a { + border-bottom: 1px #777 dashed; + color: #333; + text-decoration: none; +} + +.reasons { + color: #777; + display: inline-block; +} + +.glossary ol, .glossary ul { + padding-left: 1.4em; +} + +.glossary li { + color: #777; +} + +.glossary-item { + color: #000; +} + +.glyph { + font-family: kanji-stroke-orders; + font-size: 120px; + line-height: 120px; + padding: 0.01em; + vertical-align: top; +} diff --git a/ext/mixed/css/frame.css b/ext/mixed/css/frame.css deleted file mode 100644 index 8b1819bd..00000000 --- a/ext/mixed/css/frame.css +++ /dev/null @@ -1,146 +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 entrys 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 . - */ - - -/* - * Fonts - */ - -@font-face { - font-family: kanji-stroke-orders; - src: url('/mixed/ttf/kanji-stroke-orders.ttf'); -} - -/* - * General - */ - -hr { - padding: 0px; - margin: 0px; -} - -#spinner { - bottom: 5px; - display: none; - position: fixed; - right: 5px; -} - -#error-orphaned { - display: none; -} - - -/* - * Entries - */ - -.entry, .note { - padding-top: 10px; - padding-bottom: 10px; -} - -.tag-default { - background-color: #8a8a91; -} - -.tag-name { - background-color: #5cb85c; -} - -.tag-expression { - background-color: #f0ad4e; -} - -.tag-popular { - background-color: #0275d8; -} - -.tag-frequent { - background-color: #5bc0de; -} - -.tag-archaism { - background-color: #d9534f; -} - -.tag-dictionary { - background-color: #aa66cc; -} - -.actions .disabled { - pointer-events: none; - cursor: default; -} - -.actions .disabled img { - -webkit-filter: grayscale(100%); - opacity: 0.25; -} - -.actions .pending { - visibility: hidden; -} - -.actions { - display: inline-block; - float: right; -} - -.actions:after { - clear: both; - content: ''; - display: block; -} - -.expression { - display: inline-block; - font-size: 24px; -} - -.expression a { - border-bottom: 1px #777 dashed; - color: #333; - text-decoration: none; -} - -.reasons { - color: #777; - display: inline-block; -} - -.glossary ol, .glossary ul { - padding-left: 1.4em; -} - -.glossary li { - color: #777; -} - -.glossary-item { - color: #000; -} - -.glyph { - font-family: kanji-stroke-orders; - font-size: 120px; - line-height: 120px; - padding: 0.01em; - vertical-align: top; -} -- cgit v1.2.3 From 8ed3ca6fd44d24aff9ea41c65821c6e094024d4e Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Tue, 15 Aug 2017 21:40:41 -0700 Subject: cleanup --- ext/bg/background.html | 4 +- ext/bg/js/audio.js | 154 ++++++++++++++++++++++++++++++++++++++++++++++++ ext/bg/js/request.js | 40 +++++++++++++ ext/bg/search.html | 2 +- ext/bg/settings.html | 2 +- ext/fg/float.html | 1 - ext/mixed/js/audio.js | 154 ------------------------------------------------ ext/mixed/js/request.js | 40 ------------- 8 files changed, 198 insertions(+), 199 deletions(-) create mode 100644 ext/bg/js/audio.js create mode 100644 ext/bg/js/request.js delete mode 100644 ext/mixed/js/audio.js delete mode 100644 ext/mixed/js/request.js (limited to 'ext/bg/search.html') diff --git a/ext/bg/background.html b/ext/bg/background.html index 90ad9709..97b20f46 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -11,17 +11,17 @@ + + - - diff --git a/ext/bg/js/audio.js b/ext/bg/js/audio.js new file mode 100644 index 00000000..0952887e --- /dev/null +++ b/ext/bg/js/audio.js @@ -0,0 +1,154 @@ +/* + * 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 . + */ + + +async function audioBuildUrl(definition, mode, cache={}) { + if (mode === 'jpod101') { + let kana = definition.reading; + let kanji = definition.expression; + + if (!kana && wanakana.isHiragana(kanji)) { + kana = kanji; + kanji = null; + } + + const params = []; + if (kanji) { + params.push(`kanji=${encodeURIComponent(kanji)}`); + } + if (kana) { + params.push(`kana=${encodeURIComponent(kana)}`); + } + + const url = `https://assets.languagepod101.com/dictionary/japanese/audiomp3.php?${params.join('&')}`; + return Promise.resolve(url); + } else if (mode === 'jpod101-alternate') { + return new Promise((resolve, reject) => { + const response = cache[definition.expression]; + if (response) { + resolve(response); + } else { + const data = { + post: 'dictionary_reference', + match_type: 'exact', + search_query: definition.expression + }; + + const params = []; + for (const key in data) { + params.push(`${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`); + } + + const xhr = new XMLHttpRequest(); + xhr.open('POST', 'https://www.japanesepod101.com/learningcenter/reference/dictionary_post'); + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + xhr.addEventListener('error', () => reject('failed to scrape audio data')); + xhr.addEventListener('load', () => { + cache[definition.expression] = xhr.responseText; + resolve(xhr.responseText); + }); + + xhr.send(params.join('&')); + } + }).then(response => { + const dom = new DOMParser().parseFromString(response, 'text/html'); + for (const row of dom.getElementsByClassName('dc-result-row')) { + try { + const url = row.getElementsByClassName('ill-onebuttonplayer').item(0).getAttribute('data-url'); + const reading = row.getElementsByClassName('dc-vocab_kana').item(0).innerText; + if (url && reading && (!definition.reading || definition.reading === reading)) { + return url; + } + } catch (e) { + // NOP + } + } + }); + } else if (mode === 'jisho') { + return new Promise((resolve, reject) => { + const response = cache[definition.expression]; + if (response) { + resolve(response); + } else { + const xhr = new XMLHttpRequest(); + xhr.open('GET', `http://jisho.org/search/${definition.expression}`); + xhr.addEventListener('error', () => reject('failed to scrape audio data')); + xhr.addEventListener('load', () => { + cache[definition.expression] = xhr.responseText; + resolve(xhr.responseText); + }); + + xhr.send(); + } + }).then(response => { + try { + const dom = new DOMParser().parseFromString(response, 'text/html'); + const audio = dom.getElementById(`audio_${definition.expression}:${definition.reading}`); + if (audio) { + return audio.getElementsByTagName('source').item(0).getAttribute('src'); + } + } catch (e) { + // NOP + } + }); + } + else { + return Promise.resolve(); + } +} + +function audioBuildFilename(definition) { + if (definition.reading || definition.expression) { + let filename = 'yomichan'; + if (definition.reading) { + filename += `_${definition.reading}`; + } + if (definition.expression) { + filename += `_${definition.expression}`; + } + + return filename += '.mp3'; + } +} + +async function audioInject(definition, fields, mode) { + let usesAudio = false; + for (const name in fields) { + if (fields[name].includes('{audio}')) { + usesAudio = true; + break; + } + } + + if (!usesAudio) { + return true; + } + + try { + const url = await audioBuildUrl(definition, mode); + const filename = audioBuildFilename(definition); + + if (url && filename) { + definition.audio = {url, filename}; + } + + return true; + } catch (e) { + return false; + } +} diff --git a/ext/bg/js/request.js b/ext/bg/js/request.js new file mode 100644 index 00000000..94fd135a --- /dev/null +++ b/ext/bg/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'); + } + }); +} diff --git a/ext/bg/search.html b/ext/bg/search.html index d10530f9..5fbd467a 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -37,11 +37,11 @@ + - diff --git a/ext/bg/settings.html b/ext/bg/settings.html index ba155d4a..8798aeb1 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -48,7 +48,7 @@ - +
    diff --git a/ext/fg/float.html b/ext/fg/float.html index a3b66c92..89872cce 100644 --- a/ext/fg/float.html +++ b/ext/fg/float.html @@ -35,7 +35,6 @@ - diff --git a/ext/mixed/js/audio.js b/ext/mixed/js/audio.js deleted file mode 100644 index 0952887e..00000000 --- a/ext/mixed/js/audio.js +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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 . - */ - - -async function audioBuildUrl(definition, mode, cache={}) { - if (mode === 'jpod101') { - let kana = definition.reading; - let kanji = definition.expression; - - if (!kana && wanakana.isHiragana(kanji)) { - kana = kanji; - kanji = null; - } - - const params = []; - if (kanji) { - params.push(`kanji=${encodeURIComponent(kanji)}`); - } - if (kana) { - params.push(`kana=${encodeURIComponent(kana)}`); - } - - const url = `https://assets.languagepod101.com/dictionary/japanese/audiomp3.php?${params.join('&')}`; - return Promise.resolve(url); - } else if (mode === 'jpod101-alternate') { - return new Promise((resolve, reject) => { - const response = cache[definition.expression]; - if (response) { - resolve(response); - } else { - const data = { - post: 'dictionary_reference', - match_type: 'exact', - search_query: definition.expression - }; - - const params = []; - for (const key in data) { - params.push(`${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`); - } - - const xhr = new XMLHttpRequest(); - xhr.open('POST', 'https://www.japanesepod101.com/learningcenter/reference/dictionary_post'); - xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); - xhr.addEventListener('error', () => reject('failed to scrape audio data')); - xhr.addEventListener('load', () => { - cache[definition.expression] = xhr.responseText; - resolve(xhr.responseText); - }); - - xhr.send(params.join('&')); - } - }).then(response => { - const dom = new DOMParser().parseFromString(response, 'text/html'); - for (const row of dom.getElementsByClassName('dc-result-row')) { - try { - const url = row.getElementsByClassName('ill-onebuttonplayer').item(0).getAttribute('data-url'); - const reading = row.getElementsByClassName('dc-vocab_kana').item(0).innerText; - if (url && reading && (!definition.reading || definition.reading === reading)) { - return url; - } - } catch (e) { - // NOP - } - } - }); - } else if (mode === 'jisho') { - return new Promise((resolve, reject) => { - const response = cache[definition.expression]; - if (response) { - resolve(response); - } else { - const xhr = new XMLHttpRequest(); - xhr.open('GET', `http://jisho.org/search/${definition.expression}`); - xhr.addEventListener('error', () => reject('failed to scrape audio data')); - xhr.addEventListener('load', () => { - cache[definition.expression] = xhr.responseText; - resolve(xhr.responseText); - }); - - xhr.send(); - } - }).then(response => { - try { - const dom = new DOMParser().parseFromString(response, 'text/html'); - const audio = dom.getElementById(`audio_${definition.expression}:${definition.reading}`); - if (audio) { - return audio.getElementsByTagName('source').item(0).getAttribute('src'); - } - } catch (e) { - // NOP - } - }); - } - else { - return Promise.resolve(); - } -} - -function audioBuildFilename(definition) { - if (definition.reading || definition.expression) { - let filename = 'yomichan'; - if (definition.reading) { - filename += `_${definition.reading}`; - } - if (definition.expression) { - filename += `_${definition.expression}`; - } - - return filename += '.mp3'; - } -} - -async function audioInject(definition, fields, mode) { - let usesAudio = false; - for (const name in fields) { - if (fields[name].includes('{audio}')) { - usesAudio = true; - break; - } - } - - if (!usesAudio) { - return true; - } - - try { - const url = await audioBuildUrl(definition, mode); - const filename = audioBuildFilename(definition); - - if (url && filename) { - definition.audio = {url, filename}; - } - - return true; - } catch (e) { - return false; - } -} diff --git a/ext/mixed/js/request.js b/ext/mixed/js/request.js deleted file mode 100644 index 94fd135a..00000000 --- a/ext/mixed/js/request.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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