From a13c32a784ec41c9e46d841c14e790ffa4ab7466 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Tue, 31 Jan 2017 21:27:38 -0800 Subject: updating libraries --- ext/fg/frame.html | 2 +- ext/fg/ttf/kanji-stroke-orders.ttf | Bin 17944324 -> 17999116 bytes 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/fg') diff --git a/ext/fg/frame.html b/ext/fg/frame.html index 8246787b..959855ba 100644 --- a/ext/fg/frame.html +++ b/ext/fg/frame.html @@ -12,7 +12,7 @@
- + diff --git a/ext/fg/ttf/kanji-stroke-orders.ttf b/ext/fg/ttf/kanji-stroke-orders.ttf index 4cced85d..154fa473 100644 Binary files a/ext/fg/ttf/kanji-stroke-orders.ttf and b/ext/fg/ttf/kanji-stroke-orders.ttf differ -- cgit v1.2.3 From 4e3792aba319b52f957c70347e859f677972e4e2 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 5 Feb 2017 16:39:40 -0800 Subject: handle content script and background script desync on version update --- ext/fg/css/frame.css | 4 ++++ ext/fg/frame.html | 6 +++++- ext/fg/js/driver.js | 27 ++++++++++++++++----------- ext/fg/js/frame.js | 27 +++++++++++++++++++++++---- ext/fg/js/popup.js | 6 +++++- ext/fg/js/util.js | 23 ++++++++++++++++------- ext/manifest.json | 2 +- 7 files changed, 70 insertions(+), 25 deletions(-) (limited to 'ext/fg') diff --git a/ext/fg/css/frame.css b/ext/fg/css/frame.css index 7e9c3b19..27aaadb6 100644 --- a/ext/fg/css/frame.css +++ b/ext/fg/css/frame.css @@ -119,6 +119,10 @@ hr { height: 1px; } +#orphan { + display: none; +} + /* term styles */ .term-expression { diff --git a/ext/fg/frame.html b/ext/fg/frame.html index 959855ba..b7e2b41a 100644 --- a/ext/fg/frame.html +++ b/ext/fg/frame.html @@ -10,7 +10,11 @@ -
+
+
+

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/driver.js b/ext/fg/js/driver.js index 5467a9f0..8904c12c 100644 --- a/ext/fg/js/driver.js +++ b/ext/fg/js/driver.js @@ -33,11 +33,11 @@ class Driver { window.addEventListener('mousemove', this.onMouseMove.bind(this)); window.addEventListener('resize', e => this.searchClear()); - getOptions().then(options => { + Promise.all([getOptions(), isEnabled()]).then(([options, enabled]) => { this.options = options; - return isEnabled(); - }).then(enabled => { this.enabled = enabled; + }).catch(error => { + this.handleError(error); }); } @@ -119,14 +119,14 @@ class Driver { this.pendingLookup = true; this.searchTerms(textSource).then(found => { if (!found) { - this.searchKanji(textSource).then(found => { + return this.searchKanji(textSource).then(found => { if (!found && hideNotFound) { this.searchClear(); } }); } }).catch(error => { - window.alert('Error: ' + error); + this.handleError(error, textSource); }).then(() => { this.pendingLookup = false; }); @@ -157,9 +157,6 @@ class Driver { return true; } - }).catch(error => { - window.alert('Error: ' + error); - return false; }); } @@ -181,9 +178,6 @@ class Driver { return true; } - }).catch(error => { - window.alert('Error: ' + error); - return false; }); } @@ -197,6 +191,17 @@ class Driver { this.lastTextSource = null; } + handleError(error, textSource) { + if (window.orphaned) { + if (textSource) { + this.popup.showNextTo(textSource.getRect()); + this.popup.showOrphaned(); + } + } else { + showError(error); + } + } + api_setOptions(options) { this.options = options; } diff --git a/ext/fg/js/frame.js b/ext/fg/js/frame.js index 66fa131d..dba59000 100644 --- a/ext/fg/js/frame.js +++ b/ext/fg/js/frame.js @@ -44,7 +44,7 @@ class Frame { window.scrollTo(0, 0); renderText(context, 'terms.html').then(content => { - $('.content').html(content); + $('#content').html(content); $('.action-add-note').click(this.onAddNote.bind(this)); $('.kanji-link').click(e => { @@ -59,6 +59,8 @@ class Frame { }); this.updateAddNoteButtons(['term_kanji', 'term_kana'], sequence); + }).catch(error => { + this.handleError(error); }); } @@ -74,13 +76,20 @@ class Frame { window.scrollTo(0, 0); renderText(context, 'kanji.html').then(content => { - $('.content').html(content); + $('#content').html(content); $('.action-add-note').click(this.onAddNote.bind(this)); this.updateAddNoteButtons(['kanji'], sequence); + }).catch(error => { + this.handleError(error); }); } + api_showOrphaned() { + $('#content').hide(); + $('#orphan').show(); + } + findAddNoteButton(index, mode) { return $(`.action-add-note[data-index="${index}"][data-mode="${mode}"]`); } @@ -98,10 +107,10 @@ class Frame { const button = this.findAddNoteButton(index, mode); button.addClass('disabled'); } else { - window.alert('Note could not be added'); + showError('note could not be added'); } }).catch(error => { - window.alert('Error: ' + error); + this.handleError(error); }).then(() => { this.showSpinner(false); }); @@ -129,6 +138,8 @@ class Frame { button.removeClass('pending'); } }); + }).catch(error => { + this.handleError(error); }); } @@ -155,6 +166,14 @@ class Frame { audio.currentTime = 0; audio.play(); } + + handleError(error) { + if (window.orphaned) { + this.api_showOrphaned(); + } else { + showError(error); + } + } } window.frame = new Frame(); diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index d47ab4ae..74e25c7d 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -76,7 +76,11 @@ class Popup { this.invokeApi('showKanjiDefs', {definitions, options}); } - invokeApi(action, params) { + showOrphaned() { + this.invokeApi('showOrphaned'); + } + + invokeApi(action, params={}) { this.container.contentWindow.postMessage({action, params}, '*'); } } diff --git a/ext/fg/js/util.js b/ext/fg/js/util.js index ef45d08c..ba872467 100644 --- a/ext/fg/js/util.js +++ b/ext/fg/js/util.js @@ -19,16 +19,25 @@ function invokeBgApi(action, params) { return new Promise((resolve, reject) => { - chrome.runtime.sendMessage({action, params}, ({result, error}) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); + try { + chrome.runtime.sendMessage({action, params}, ({result, error}) => { + if (error) { + reject(error); + } else { + resolve(result); + } + }); + } catch (e) { + window.orphaned = true; + reject(e.message); + } }); } +function showError(error) { + window.alert(`Error: ${error}`); +} + function isEnabled() { return invokeBgApi('getEnabled', {}); } diff --git a/ext/manifest.json b/ext/manifest.json index 31b2c8c4..e296ec06 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Yomichan", - "version": "1.0.8", + "version": "1.0.9", "description": "Japanese dictionary with Anki integration", "icons": {"16": "img/icon16.png", "48": "img/icon48.png", "128": "img/icon128.png"}, -- cgit v1.2.3 From e73d2d96c9cadce1364ae48a0dc68e24f2019c72 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Tue, 7 Feb 2017 21:46:37 -0800 Subject: add support for looking up definitions for textareas and textboxes --- ext/fg/js/driver.js | 1 + ext/fg/js/util.js | 28 ++++++++++++++++++++++++++-- ext/manifest.json | 2 +- 3 files changed, 28 insertions(+), 3 deletions(-) (limited to 'ext/fg') diff --git a/ext/fg/js/driver.js b/ext/fg/js/driver.js index 8904c12c..97f29f89 100644 --- a/ext/fg/js/driver.js +++ b/ext/fg/js/driver.js @@ -182,6 +182,7 @@ class Driver { } searchClear() { + destroyImposters(); this.popup.hide(); if (this.options.scanning.selectText && this.lastTextSource !== null) { diff --git a/ext/fg/js/util.js b/ext/fg/js/util.js index ba872467..a7533846 100644 --- a/ext/fg/js/util.js +++ b/ext/fg/js/util.js @@ -70,12 +70,36 @@ function addDefinition(definition, mode) { return invokeBgApi('addDefinition', {definition, mode}); } +function createImposter(element) { + const imposter = document.createElement('div'); + const elementRect = element.getBoundingClientRect(); + + imposter.className = 'yomichan-imposter'; + imposter.innerText = element.value; + imposter.style.cssText = window.getComputedStyle(element).cssText; + imposter.style.position = 'absolute'; + imposter.style.top = elementRect.top + 'px'; + imposter.style.left = elementRect.left + 'px'; + imposter.style.zIndex = 2147483646; + document.body.appendChild(imposter); + + imposter.scrollTop = element.scrollTop; + imposter.scrollLeft = element.scrollLeft; +} + +function destroyImposters() { + for (const element of document.getElementsByClassName('yomichan-imposter')) { + element.parentNode.removeChild(element); + } +} + function textSourceFromPoint(point) { const element = document.elementFromPoint(point.x, point.y); if (element !== null) { - const names = ['IMG', 'INPUT', 'BUTTON', 'TEXTAREA']; - if (names.includes(element.nodeName)) { + if (element.nodeName === 'IMG' || element.nodeName === 'BUTTON') { return new TextSourceElement(element); + } else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { + createImposter(element); } } diff --git a/ext/manifest.json b/ext/manifest.json index e296ec06..ba7e36e6 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Yomichan", - "version": "1.0.9", + "version": "1.0.10", "description": "Japanese dictionary with Anki integration", "icons": {"16": "img/icon16.png", "48": "img/icon48.png", "128": "img/icon128.png"}, -- cgit v1.2.3 From f3fe0994f52067d7c6d1886b02afd8f0a2a15099 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Wed, 8 Feb 2017 09:24:14 -0800 Subject: add option to disable imposters, bump version --- ext/bg/js/options-form.js | 2 ++ ext/bg/js/options.js | 1 + ext/bg/options.html | 4 ++++ ext/fg/js/driver.js | 2 +- ext/fg/js/util.js | 4 ++-- ext/manifest.json | 2 +- 6 files changed, 11 insertions(+), 4 deletions(-) (limited to 'ext/fg') diff --git a/ext/bg/js/options-form.js b/ext/bg/js/options-form.js index 00b6a63e..4470d105 100644 --- a/ext/bg/js/options-form.js +++ b/ext/bg/js/options-form.js @@ -37,6 +37,7 @@ function getFormData() { optionsNew.scanning.requireShift = $('#hold-shift-to-scan').prop('checked'); optionsNew.scanning.selectText = $('#select-matched-text').prop('checked'); + optionsNew.scanning.imposter = $('#search-form-text-fields').prop('checked'); optionsNew.scanning.delay = parseInt($('#scan-delay').val(), 10); optionsNew.scanning.length = parseInt($('#scan-length').val(), 10); @@ -95,6 +96,7 @@ $(document).ready(() => { $('#hold-shift-to-scan').prop('checked', options.scanning.requireShift); $('#select-matched-text').prop('checked', options.scanning.selectText); + $('#search-form-text-fields').prop('checked', options.scanning.imposter); $('#scan-delay').val(options.scanning.delay); $('#scan-length').val(options.scanning.length); diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index a4e39e41..65712c12 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -31,6 +31,7 @@ function optionsSetDefaults(options) { scanning: { requireShift: true, selectText: true, + imposter: true, delay: 15, length: 10 }, diff --git a/ext/bg/options.html b/ext/bg/options.html index d9d23c6a..ebb12f15 100644 --- a/ext/bg/options.html +++ b/ext/bg/options.html @@ -62,6 +62,10 @@ +
+ +
+
diff --git a/ext/fg/js/driver.js b/ext/fg/js/driver.js index 97f29f89..7facda0a 100644 --- a/ext/fg/js/driver.js +++ b/ext/fg/js/driver.js @@ -103,7 +103,7 @@ class Driver { return; } - const textSource = textSourceFromPoint(point); + const textSource = textSourceFromPoint(point, this.options.scanning.imposter); if (textSource === null || !textSource.containsPoint(point)) { if (hideNotFound) { this.searchClear(); diff --git a/ext/fg/js/util.js b/ext/fg/js/util.js index a7533846..641b73ac 100644 --- a/ext/fg/js/util.js +++ b/ext/fg/js/util.js @@ -93,12 +93,12 @@ function destroyImposters() { } } -function textSourceFromPoint(point) { +function textSourceFromPoint(point, imposter) { const element = document.elementFromPoint(point.x, point.y); if (element !== null) { if (element.nodeName === 'IMG' || element.nodeName === 'BUTTON') { return new TextSourceElement(element); - } else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { + } else if (imposter && (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA')) { createImposter(element); } } diff --git a/ext/manifest.json b/ext/manifest.json index ba7e36e6..83651a62 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Yomichan", - "version": "1.0.10", + "version": "1.0.11", "description": "Japanese dictionary with Anki integration", "icons": {"16": "img/icon16.png", "48": "img/icon48.png", "128": "img/icon128.png"}, -- cgit v1.2.3 From 2e3aec9ba11b15d7ac2b5d99af2dacac88e9c276 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Wed, 8 Feb 2017 20:13:45 -0800 Subject: fix "url" not being set on kanji cards, add more fields --- ext/bg/js/options-form.js | 2 +- ext/fg/js/driver.js | 6 +++++- ext/fg/js/frame.js | 10 +++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) (limited to 'ext/fg') diff --git a/ext/bg/js/options-form.js b/ext/bg/js/options-form.js index 4470d105..91c6f140 100644 --- a/ext/bg/js/options-form.js +++ b/ext/bg/js/options-form.js @@ -351,7 +351,7 @@ function populateAnkiFields(element, options) { const markers = { 'terms': ['audio', 'dictionary', 'expression', 'furigana', 'glossary', 'reading', 'sentence', 'tags', 'url'], - 'kanji': ['character', 'dictionary', 'glossary', 'kunyomi', 'onyomi', 'url'] + 'kanji': ['character', 'dictionary', 'glossary', 'kunyomi', 'onyomi', 'sentence', 'tags', 'url'] }[tabId] || {}; return anki().getModelFieldNames(modelName).then(names => { diff --git a/ext/fg/js/driver.js b/ext/fg/js/driver.js index 7facda0a..cb7f2ea6 100644 --- a/ext/fg/js/driver.js +++ b/ext/fg/js/driver.js @@ -167,7 +167,11 @@ class Driver { if (definitions.length === 0) { return false; } else { - definitions.forEach(definition => definition.url = window.location.href); + const sentence = extractSentence(textSource, this.options.anki.sentenceExt); + definitions.forEach(definition => { + definition.url = window.location.href; + definition.sentence = sentence; + }); this.popup.showNextTo(textSource.getRect()); this.popup.showKanjiDefs(definitions, this.options); diff --git a/ext/fg/js/frame.js b/ext/fg/js/frame.js index dba59000..df8ca894 100644 --- a/ext/fg/js/frame.js +++ b/ext/fg/js/frame.js @@ -49,7 +49,15 @@ class Frame { $('.kanji-link').click(e => { e.preventDefault(); - findKanji($(e.target).text()).then(kdefs => this.api_showKanjiDefs({options, definitions: kdefs})); + const character = $(e.target).text(); + findKanji(character).then(kdefs => { + kdefs.forEach(kdef => { + kdef.url = definitions[0].url; + kdef.sentence = definitions[0].sentence; + }); + + this.api_showKanjiDefs({options, definitions: kdefs}); + }); }); $('.action-play-audio').click(e => { -- cgit v1.2.3 From caa09c63a18a0d5f30fda365c18c0d58235ec7e9 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Wed, 8 Feb 2017 21:30:00 -0800 Subject: destroy imposters earlier --- ext/fg/js/util.js | 1 + 1 file changed, 1 insertion(+) (limited to 'ext/fg') diff --git a/ext/fg/js/util.js b/ext/fg/js/util.js index 641b73ac..aeda36b5 100644 --- a/ext/fg/js/util.js +++ b/ext/fg/js/util.js @@ -108,6 +108,7 @@ function textSourceFromPoint(point, imposter) { return new TextSourceRange(range); } + destroyImposters(); return null; } -- cgit v1.2.3 From 78d5b511278cd9b8f9319220bec55b8628f6cb36 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Fri, 10 Feb 2017 20:45:01 -0800 Subject: fix url and sentence tags on kanji cards --- ext/fg/js/driver.js | 16 ++++++---------- ext/fg/js/frame.js | 31 +++++++++++++++++-------------- ext/fg/js/popup.js | 8 ++++---- 3 files changed, 27 insertions(+), 28 deletions(-) (limited to 'ext/fg') diff --git a/ext/fg/js/driver.js b/ext/fg/js/driver.js index cb7f2ea6..c84805d7 100644 --- a/ext/fg/js/driver.js +++ b/ext/fg/js/driver.js @@ -143,13 +143,11 @@ class Driver { textSource.setEndOffset(length); const sentence = extractSentence(textSource, this.options.anki.sentenceExt); - definitions.forEach(definition => { - definition.url = window.location.href; - definition.sentence = sentence; - }); + const url = window.location.href; this.popup.showNextTo(textSource.getRect()); - this.popup.showTermDefs(definitions, this.options); + this.popup.showTermDefs(definitions, this.options, {sentence, url}); + this.lastTextSource = textSource; if (this.options.scanning.selectText) { textSource.select(); @@ -168,13 +166,11 @@ class Driver { return false; } else { const sentence = extractSentence(textSource, this.options.anki.sentenceExt); - definitions.forEach(definition => { - definition.url = window.location.href; - definition.sentence = sentence; - }); + const url = window.location.href; this.popup.showNextTo(textSource.getRect()); - this.popup.showKanjiDefs(definitions, this.options); + this.popup.showKanjiDefs(definitions, this.options, {sentence, url}); + this.lastTextSource = textSource; if (this.options.scanning.selectText) { textSource.select(); diff --git a/ext/fg/js/frame.js b/ext/fg/js/frame.js index df8ca894..83d6d7ef 100644 --- a/ext/fg/js/frame.js +++ b/ext/fg/js/frame.js @@ -30,34 +30,32 @@ class Frame { }); } - api_showTermDefs({definitions, options}) { + api_showTermDefs({definitions, options, context}) { const sequence = ++this.sequence; - const context = { + const params = { definitions, grouped: options.general.groupResults, addable: options.ankiMethod !== 'disabled', playback: options.general.audioPlayback }; + definitions.forEach(definition => { + definition.sentence = context.sentence; + definition.url = context.url; + }); + this.definitions = definitions; this.showSpinner(false); window.scrollTo(0, 0); - renderText(context, 'terms.html').then(content => { + renderText(params, 'terms.html').then(content => { $('#content').html(content); $('.action-add-note').click(this.onAddNote.bind(this)); $('.kanji-link').click(e => { e.preventDefault(); const character = $(e.target).text(); - findKanji(character).then(kdefs => { - kdefs.forEach(kdef => { - kdef.url = definitions[0].url; - kdef.sentence = definitions[0].sentence; - }); - - this.api_showKanjiDefs({options, definitions: kdefs}); - }); + findKanji(character).then(definitions => this.api_showKanjiDefs({definitions, options, context})); }); $('.action-play-audio').click(e => { @@ -72,18 +70,23 @@ class Frame { }); } - api_showKanjiDefs({definitions, options}) { + api_showKanjiDefs({definitions, options, context}) { const sequence = ++this.sequence; - const context = { + const params = { definitions, addable: options.ankiMethod !== 'disabled' }; + definitions.forEach(definition => { + definition.sentence = context.sentence; + definition.url = context.url; + }); + this.definitions = definitions; this.showSpinner(false); window.scrollTo(0, 0); - renderText(context, 'kanji.html').then(content => { + renderText(params, 'kanji.html').then(content => { $('#content').html(content); $('.action-add-note').click(this.onAddNote.bind(this)); diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index 74e25c7d..751c6acc 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -68,12 +68,12 @@ class Popup { return this.container.style.visibility !== 'hidden'; } - showTermDefs(definitions, options) { - this.invokeApi('showTermDefs', {definitions, options}); + showTermDefs(definitions, options, context) { + this.invokeApi('showTermDefs', {definitions, options, context}); } - showKanjiDefs(definitions, options) { - this.invokeApi('showKanjiDefs', {definitions, options}); + showKanjiDefs(definitions, options, context) { + this.invokeApi('showKanjiDefs', {definitions, options, context}); } showOrphaned() { -- cgit v1.2.3 From 7398e74d71a91dfc1397c28f8dc5df4205d96249 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Fri, 10 Feb 2017 21:11:34 -0800 Subject: delete dead code --- ext/fg/js/driver.js | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'ext/fg') diff --git a/ext/fg/js/driver.js b/ext/fg/js/driver.js index c84805d7..421c3591 100644 --- a/ext/fg/js/driver.js +++ b/ext/fg/js/driver.js @@ -75,7 +75,7 @@ class Driver { return; } - const searcher = () => this.searchAt(this.lastMousePos, false); + const searcher = () => this.searchAt(this.lastMousePos); if (!this.popup.isVisible() || e.shiftKey || e.which === 2 /* mmb */) { searcher(); } else { @@ -98,17 +98,13 @@ class Driver { callback(); } - searchAt(point, hideNotFound) { + searchAt(point) { if (this.pendingLookup) { return; } const textSource = textSourceFromPoint(point, this.options.scanning.imposter); if (textSource === null || !textSource.containsPoint(point)) { - if (hideNotFound) { - this.searchClear(); - } - return; } @@ -119,11 +115,7 @@ class Driver { this.pendingLookup = true; this.searchTerms(textSource).then(found => { if (!found) { - return this.searchKanji(textSource).then(found => { - if (!found && hideNotFound) { - this.searchClear(); - } - }); + return this.searchKanji(textSource); } }).catch(error => { this.handleError(error, textSource); -- cgit v1.2.3 From 701c91ea66852631ccc6e7bfb23b49578646ff33 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sat, 11 Feb 2017 12:16:14 -0800 Subject: block placeholder audio with a short audio clip --- ext/fg/js/frame.js | 23 +++++++++++++++++++---- ext/fg/mp3/button.mp3 | Bin 0 -> 17735 bytes ext/manifest.json | 5 +++-- 3 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 ext/fg/mp3/button.mp3 (limited to 'ext/fg') diff --git a/ext/fg/js/frame.js b/ext/fg/js/frame.js index 83d6d7ef..ca0636f9 100644 --- a/ext/fg/js/frame.js +++ b/ext/fg/js/frame.js @@ -170,12 +170,27 @@ class Frame { } for (const key in this.audioCache) { - this.audioCache[key].pause(); + const audio = this.audioCache[key]; + if (audio !== null) { + audio.pause(); + } } - const audio = this.audioCache[url] || new Audio(url); - audio.currentTime = 0; - audio.play(); + let audio = this.audioCache[url]; + if (audio) { + audio.currentTime = 0; + audio.play(); + } else { + audio = new Audio(url); + audio.onloadeddata = () => { + if (audio.duration === 5.694694) { + audio = new Audio('mp3/button.mp3'); + } + + this.audioCache[url] = audio; + audio.play(); + }; + } } handleError(error) { diff --git a/ext/fg/mp3/button.mp3 b/ext/fg/mp3/button.mp3 new file mode 100644 index 00000000..7a9728d1 Binary files /dev/null and b/ext/fg/mp3/button.mp3 differ diff --git a/ext/manifest.json b/ext/manifest.json index 1c80435f..0a1301c1 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Yomichan", - "version": "1.0.12", + "version": "1.0.13", "description": "Japanese dictionary with Anki integration", "icons": {"16": "img/icon16.png", "48": "img/icon48.png", "128": "img/icon128.png"}, @@ -31,13 +31,14 @@ ], "web_accessible_resources": [ "fg/css/frame.css", + "fg/frame.html", "fg/img/add_kanji.png", "fg/img/add_term_kana.png", "fg/img/add_term_kanji.png", "fg/img/play_audio.png", "fg/img/spinner.gif", "fg/js/frame.js", - "fg/frame.html", + "fg/mp3/button.mp3", "fg/ttf/kanji-stroke-orders.ttf", "fg/ttf/vl-gothic-regular.ttf" ] -- cgit v1.2.3 From 1a52a2d8d5f5ea5c106ae244ca1e5bbf0da22b6e Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sat, 18 Feb 2017 19:12:39 -0800 Subject: fix not being able to play audio for kana only terms --- ext/fg/frame.html | 1 + ext/fg/js/frame.js | 27 ++++++++++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) (limited to 'ext/fg') diff --git a/ext/fg/frame.html b/ext/fg/frame.html index b7e2b41a..bf7f0f7b 100644 --- a/ext/fg/frame.html +++ b/ext/fg/frame.html @@ -17,6 +17,7 @@
+ diff --git a/ext/fg/js/frame.js b/ext/fg/js/frame.js index ca0636f9..4f4a6378 100644 --- a/ext/fg/js/frame.js +++ b/ext/fg/js/frame.js @@ -164,11 +164,6 @@ class Frame { } playAudio(definition) { - let url = `https://assets.languagepod101.com/dictionary/japanese/audiomp3.php?kanji=${encodeURIComponent(definition.expression)}`; - if (definition.reading) { - url += `&kana=${encodeURIComponent(definition.reading)}`; - } - for (const key in this.audioCache) { const audio = this.audioCache[key]; if (audio !== null) { @@ -176,6 +171,28 @@ class Frame { } } + let kana = definition.reading; + let kanji = definition.expression; + if (!kana) { + if (!kanji) { + return; + } + + if (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('&')}`; let audio = this.audioCache[url]; if (audio) { audio.currentTime = 0; -- cgit v1.2.3 From 64db42d536318cc4b91ed5a7484de302db7979f4 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 19 Feb 2017 10:09:15 -0800 Subject: switch to new ankiconnect interface --- ext/bg/js/ankiconnect.js | 2 +- ext/bg/js/yomichan.js | 27 +++++++++++++++------------ ext/fg/js/frame.js | 34 +++++++++++++--------------------- ext/fg/js/util.js | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 34 deletions(-) (limited to 'ext/fg') diff --git a/ext/bg/js/ankiconnect.js b/ext/bg/js/ankiconnect.js index f6f94329..3a6e3690 100644 --- a/ext/bg/js/ankiconnect.js +++ b/ext/bg/js/ankiconnect.js @@ -20,7 +20,7 @@ class AnkiConnect { constructor(server) { this.server = server; this.asyncPools = {}; - this.localVersion = 1; + this.localVersion = 2; this.remoteVersion = null; } diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js index 80a67588..4c70bf0f 100644 --- a/ext/bg/js/yomichan.js +++ b/ext/bg/js/yomichan.js @@ -100,20 +100,23 @@ class Yomichan { note.deckName = this.options.anki.terms.deck; note.modelName = this.options.anki.terms.model; - const audio = { - kanji: definition.expression, - kana: definition.reading, - fields: [] - }; - - for (const name in fields) { - if (fields[name].includes('{audio}')) { - audio.fields.push(name); + 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; + if (audio.fields.length > 0) { + note.audio = audio; + } } } diff --git a/ext/fg/js/frame.js b/ext/fg/js/frame.js index 4f4a6378..1028f0f6 100644 --- a/ext/fg/js/frame.js +++ b/ext/fg/js/frame.js @@ -113,7 +113,16 @@ class Frame { const index = link.data('index'); const mode = link.data('mode'); - addDefinition(this.definitions[index], mode).then(success => { + const definition = this.definitions[index]; + if (mode !== 'kanji') { + const url = buildAudioUrl(definition); + const filename = buildAudioFilename(definition); + if (url && filename) { + definition.audio = {url, filename}; + } + } + + addDefinition(definition, mode).then(success => { if (success) { const button = this.findAddNoteButton(index, mode); button.addClass('disabled'); @@ -171,28 +180,11 @@ class Frame { } } - let kana = definition.reading; - let kanji = definition.expression; - if (!kana) { - if (!kanji) { - return; - } - - if (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 = buildAudioUrl(definition); + if (!url) { + return; } - const url = `https://assets.languagepod101.com/dictionary/japanese/audiomp3.php?${params.join('&')}`; let audio = this.audioCache[url]; if (audio) { audio.currentTime = 0; diff --git a/ext/fg/js/util.js b/ext/fg/js/util.js index aeda36b5..c9ee4ed7 100644 --- a/ext/fg/js/util.js +++ b/ext/fg/js/util.js @@ -166,3 +166,43 @@ function extractSentence(source, extent) { return content.substring(startPos, endPos).trim(); } + +function buildAudioUrl(definition) { + let kana = definition.reading; + let kanji = definition.expression; + + if (!kana && !kanji) { + return null; + } + + 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)}`); + } + + return `https://assets.languagepod101.com/dictionary/japanese/audiomp3.php?${params.join('&')}`; +} + +function buildAudioFilename(definition) { + if (!definition.reading && !definition.expression) { + return null; + } + + let filename = 'yomichan'; + if (definition.reading) { + filename += `_${definition.reading}`; + } + if (definition.expression) { + filename += `_${definition.expression}`; + } + + return filename += '.mp3'; +} -- cgit v1.2.3 From 465a8e21c0a9d7b2d1e704ab9a42b5f662fd82d3 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sat, 25 Feb 2017 19:14:44 -0800 Subject: usability improvements --- ext/bg/js/options-form.js | 52 ++++++++++++++++------------------------------- ext/bg/js/options.js | 2 +- ext/bg/js/yomichan.js | 39 ++++++++++++++++------------------- ext/bg/options.html | 2 +- ext/fg/js/driver.js | 27 ++++++++---------------- ext/fg/js/util.js | 4 ---- 6 files changed, 45 insertions(+), 81 deletions(-) (limited to 'ext/fg') diff --git a/ext/bg/js/options-form.js b/ext/bg/js/options-form.js index 91c6f140..7824164c 100644 --- a/ext/bg/js/options-form.js +++ b/ext/bg/js/options-form.js @@ -28,7 +28,7 @@ function getFormData() { return optionsLoad().then(optionsOld => { const optionsNew = $.extend(true, {}, optionsOld); - optionsNew.general.autoStart = $('#activate-on-startup').prop('checked'); + optionsNew.general.enable = $('#enable-search').prop('checked'); optionsNew.general.audioPlayback = $('#audio-playback-buttons').prop('checked'); optionsNew.general.groupResults = $('#group-terms-results').prop('checked'); optionsNew.general.softKatakana = $('#soft-katakana-search').prop('checked'); @@ -87,7 +87,7 @@ $(document).ready(() => { Handlebars.partials = Handlebars.templates; optionsLoad().then(options => { - $('#activate-on-startup').prop('checked', options.general.autoStart); + $('#enable-search').prop('checked', options.general.enable); $('#audio-playback-buttons').prop('checked', options.general.audioPlayback); $('#group-terms-results').prop('checked', options.general.groupResults); $('#soft-katakana-search').prop('checked', options.general.softKatakana); @@ -172,9 +172,7 @@ function populateDictionaries(options) { $('.dict-enabled, .dict-priority').change(onOptionsChanged); $('.dict-delete').click(onDictionaryDelete); - }).catch(error => { - showDictionaryError(error); - }).then(() => { + }).catch(showDictionaryError).then(() => { showDictionarySpinner(false); if (dictCount === 0) { dictWarning.show(); @@ -191,13 +189,17 @@ function onDictionaryPurge(e) { const dictControls = $('#dict-importer, #dict-groups').hide(); const dictProgress = $('#dict-purge-progress').show(); - return database().purge().catch(error => { - showDictionaryError(error); - }).then(() => { + return database().purge().catch(showDictionaryError).then(() => { showDictionarySpinner(false); dictControls.show(); dictProgress.hide(); - return optionsLoad().then(options => populateDictionaries(options)); + return optionsLoad(); + }).then(options => { + options.dictionaries = {}; + return optionsSave(options).then(() => { + yomichan().setOptions(options); + populateDictionaries(options); + }); }); } @@ -214,13 +216,11 @@ function onDictionaryDelete() { setProgress(0.0); - database().deleteDictionary(dictGroup.data('title'), (total, current) => setProgress(current / total * 100.0)).catch(error => { - showDictionaryError(error); - }).then(() => { + database().deleteDictionary(dictGroup.data('title'), (total, current) => setProgress(current / total * 100.0)).catch(showDictionaryError).then(() => { showDictionarySpinner(false); dictProgress.hide(); dictControls.show(); - return optionsLoad().then(options => populateDictionaries(options)); + return optionsLoad().then(populateDictionaries); }); } @@ -241,11 +241,7 @@ function onDictionaryImport() { database().importDictionary(dictUrl.val(), (total, current) => setProgress(current / total * 100.0)).then(summary => { options.dictionaries[summary.title] = {enabled: true, priority: 0}; return optionsSave(options).then(() => yomichan().setOptions(options)); - }).then(() => { - return populateDictionaries(options); - }).catch(error => { - showDictionaryError(error); - }).then(() => { + }).then(() => populateDictionaries(options)).catch(showDictionaryError).then(() => { showDictionarySpinner(false); dictProgress.hide(); dictImporter.show(); @@ -330,13 +326,7 @@ function populateAnkiDeckAndModel(options) { populateAnkiFields($('#anki-terms-model').val(options.anki.terms.model), options), populateAnkiFields($('#anki-kanji-model').val(options.anki.kanji.model), options) ]); - }).then(() => { - ankiFormat.show(); - }).catch(error => { - showAnkiError(error); - }).then(() => { - showAnkiSpinner(false); - }); + }).then(() => ankiFormat.show()).catch(showAnkiError).then(() => showAnkiSpinner(false)); } function populateAnkiFields(element, options) { @@ -386,11 +376,7 @@ function onAnkiModelChanged(e) { optionsNew.anki[tabId].fields = {}; populateAnkiFields(element, optionsNew).then(() => { optionsSave(optionsNew).then(() => yomichan().setOptions(optionsNew)); - }).catch(error => { - showAnkiError(error); - }).then(() => { - showAnkiSpinner(false); - }); + }).catch(showAnkiError).then(() => showAnkiSpinner(false)); }); } @@ -409,9 +395,5 @@ function onOptionsChanged(e) { return populateAnkiDeckAndModel(optionsNew); } }); - }).catch(error => { - showAnkiError(error); - }).then(() => { - showAnkiSpinner(false); - }); + }).catch(showAnkiError).then(() => showAnkiSpinner(false)); } diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index 65712c12..127f0421 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -20,7 +20,7 @@ function optionsSetDefaults(options) { const defaults = { general: { - autoStart: true, + enable: true, audioPlayback: true, groupResults: true, softKatakana: true, diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js index 4c70bf0f..b1bf710f 100644 --- a/ext/bg/js/yomichan.js +++ b/ext/bg/js/yomichan.js @@ -26,18 +26,12 @@ class Yomichan { this.translator = new Translator(); this.anki = new AnkiNull(); this.options = null; - this.setEnabled(false); chrome.runtime.onMessage.addListener(this.onMessage.bind(this)); - chrome.browserAction.onClicked.addListener(this.onBrowserAction.bind(this)); chrome.runtime.onInstalled.addListener(this.onInstalled.bind(this)); + chrome.browserAction.onClicked.addListener(e => chrome.runtime.openOptionsPage()); - this.translator.prepare().then(optionsLoad).then(options => { - this.setOptions(options); - if (this.options.general.autoStart) { - this.setEnabled(true); - } - }); + this.translator.prepare().then(optionsLoad).then(this.setOptions.bind(this)); } onInstalled(details) { @@ -57,19 +51,26 @@ class Yomichan { return true; } - onBrowserAction() { - this.setEnabled(!this.enabled); - } - - setEnabled(enabled) { - this.enabled = enabled; - this.tabInvokeAll('setEnabled', this.enabled); - chrome.browserAction.setBadgeText({text: enabled ? '' : 'off'}); - } + // setEnabled(enabled) { + // this.enabled = enabled; + // this.tabInvokeAll('setEnabled', this.enabled); + // chrome.browserAction.setBadgeText({text: enabled ? '' : 'off'}); + // } setOptions(options) { this.options = options; + let usable = false; + for (const title in options.dictionaries) { + if (options.dictionaries[title].enabled) { + usable = true; + break; + } + } + + chrome.browserAction.setBadgeBackgroundColor({color: '#f0ad4e'}); + chrome.browserAction.setBadgeText({text: usable ? '' : '!'}); + if (options.anki.enable) { this.anki = new AnkiConnect(this.options.anki.server); } else { @@ -132,10 +133,6 @@ class Yomichan { return note; } - api_getEnabled({callback}) { - callback({result: this.enabled}); - } - api_getOptions({callback}) { promiseCallback(optionsLoad(), callback); } diff --git a/ext/bg/options.html b/ext/bg/options.html index ebb12f15..03e328d2 100644 --- a/ext/bg/options.html +++ b/ext/bg/options.html @@ -26,7 +26,7 @@

General Options

- +
diff --git a/ext/fg/js/driver.js b/ext/fg/js/driver.js index 421c3591..3b4c0c76 100644 --- a/ext/fg/js/driver.js +++ b/ext/fg/js/driver.js @@ -24,21 +24,16 @@ class Driver { this.lastMousePos = null; this.lastTextSource = null; this.pendingLookup = false; - this.enabled = false; this.options = null; - chrome.runtime.onMessage.addListener(this.onBgMessage.bind(this)); - window.addEventListener('mouseover', this.onMouseOver.bind(this)); - window.addEventListener('mousedown', this.onMouseDown.bind(this)); - window.addEventListener('mousemove', this.onMouseMove.bind(this)); - window.addEventListener('resize', e => this.searchClear()); - - Promise.all([getOptions(), isEnabled()]).then(([options, enabled]) => { + getOptions().then(options => { this.options = options; - this.enabled = enabled; - }).catch(error => { - this.handleError(error); - }); + window.addEventListener('mouseover', this.onMouseOver.bind(this)); + window.addEventListener('mousedown', this.onMouseDown.bind(this)); + window.addEventListener('mousemove', this.onMouseMove.bind(this)); + window.addEventListener('resize', e => this.searchClear()); + chrome.runtime.onMessage.addListener(this.onBgMessage.bind(this)); + }).catch(this.handleError.bind(this)); } popupTimerSet(callback) { @@ -63,7 +58,7 @@ class Driver { this.lastMousePos = {x: e.clientX, y: e.clientY}; this.popupTimerClear(); - if (!this.enabled) { + if (!this.options.general.enable) { return; } @@ -198,12 +193,6 @@ class Driver { api_setOptions(options) { this.options = options; } - - api_setEnabled(enabled) { - if (!(this.enabled = enabled)) { - this.searchClear(); - } - } } window.driver = new Driver(); diff --git a/ext/fg/js/util.js b/ext/fg/js/util.js index c9ee4ed7..99da6381 100644 --- a/ext/fg/js/util.js +++ b/ext/fg/js/util.js @@ -38,10 +38,6 @@ function showError(error) { window.alert(`Error: ${error}`); } -function isEnabled() { - return invokeBgApi('getEnabled', {}); -} - function getOptions() { return invokeBgApi('getOptions', {}); } -- cgit v1.2.3