diff options
Diffstat (limited to 'ext/mixed')
-rw-r--r-- | ext/mixed/img/add-kanji.png | bin | 733 -> 0 bytes | |||
-rw-r--r-- | ext/mixed/img/add-term-kana.png | bin | 286 -> 0 bytes | |||
-rw-r--r-- | ext/mixed/img/add-term-kana.svg | 23 | ||||
-rw-r--r-- | ext/mixed/img/add-term-kanji.png | bin | 733 -> 0 bytes | |||
-rw-r--r-- | ext/mixed/img/add-term-kanji.svg | 24 | ||||
-rw-r--r-- | ext/mixed/img/entry-current.png | bin | 743 -> 0 bytes | |||
-rw-r--r-- | ext/mixed/img/entry-current.svg | 16 | ||||
-rw-r--r-- | ext/mixed/img/play-audio.png | bin | 610 -> 0 bytes | |||
-rw-r--r-- | ext/mixed/img/play-audio.svg | 27 | ||||
-rw-r--r-- | ext/mixed/img/source-term.png | bin | 680 -> 0 bytes | |||
-rw-r--r-- | ext/mixed/img/source-term.svg | 31 | ||||
-rw-r--r-- | ext/mixed/img/view-note.png | bin | 622 -> 0 bytes | |||
-rw-r--r-- | ext/mixed/img/view-note.svg | 22 | ||||
-rw-r--r-- | ext/mixed/js/audio.js | 60 | ||||
-rw-r--r-- | ext/mixed/js/display.js | 107 | ||||
-rw-r--r-- | ext/mixed/js/extension.js | 35 |
16 files changed, 304 insertions, 41 deletions
diff --git a/ext/mixed/img/add-kanji.png b/ext/mixed/img/add-kanji.png Binary files differdeleted file mode 100644 index 6332fefe..00000000 --- a/ext/mixed/img/add-kanji.png +++ /dev/null diff --git a/ext/mixed/img/add-term-kana.png b/ext/mixed/img/add-term-kana.png Binary files differdeleted file mode 100644 index 41ff8335..00000000 --- a/ext/mixed/img/add-term-kana.png +++ /dev/null diff --git a/ext/mixed/img/add-term-kana.svg b/ext/mixed/img/add-term-kana.svg new file mode 100644 index 00000000..bb964476 --- /dev/null +++ b/ext/mixed/img/add-term-kana.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <linearGradient id="linearGradient4719" x1="-1.7198" x2="-1.7198" y1="2.7781" y2="1.4552" gradientTransform="matrix(3.7795 0 0 3.7795 14 .5)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#8dba64" offset="0"/> + <stop stop-color="#b4d495" offset="1"/> + </linearGradient> + <linearGradient id="linearGradient4745-5" x1="2.1167" x2="1.4552" y1="2.3812" y2="1.7198" gradientTransform="scale(3.7795 3.7795)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#376b19" offset="0"/> + <stop stop-color="#81ab61" offset="1"/> + </linearGradient> + <radialGradient id="radialGradient4770-4" cx="2.1167" cy="2.1167" r=".66146" gradientTransform="matrix(2.2677 -7.9311e-7 7.9312e-7 2.2677 2.7 3.7)" gradientUnits="userSpaceOnUse"> + <stop stop-opacity=".28986" offset="0"/> + <stop stop-opacity="0" offset="1"/> + </radialGradient> + </defs> + <g> + <circle cx="7.5" cy="8.5" r="3" fill="url(#linearGradient4719)"/> + <circle cx="7.5" cy="8.5" r="3" fill="none" stroke="url(#linearGradient4745-5)"/> + <circle cx="7.5" cy="8.5" r="1.5" fill="url(#radialGradient4770-4)"/> + <path d="m6 8h1v-1h1v1h1v1h-1v1h-1v-1h-1v-1" fill="#fff"/> + </g> +</svg> diff --git a/ext/mixed/img/add-term-kanji.png b/ext/mixed/img/add-term-kanji.png Binary files differdeleted file mode 100644 index 6332fefe..00000000 --- a/ext/mixed/img/add-term-kanji.png +++ /dev/null diff --git a/ext/mixed/img/add-term-kanji.svg b/ext/mixed/img/add-term-kanji.svg new file mode 100644 index 00000000..3737eaec --- /dev/null +++ b/ext/mixed/img/add-term-kanji.svg @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <linearGradient id="linearGradient4582" x1="-1.7198" x2="-1.7198" y1="3.5719" y2=".79375" gradientTransform="matrix(3.7795 0 0 3.7795 14.5 -6.308e-7)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#6fb558" offset="0"/> + <stop stop-color="#a5db9b" offset="1"/> + </linearGradient> + <linearGradient id="linearGradient4758-7" x1="7.5406" x2="5.1594" y1="3.3073" y2=".92604" gradientTransform="matrix(3.7795 0 0 3.7795 -16 -6e-7)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#34812c" offset="0"/> + <stop stop-color="#87b870" offset="1"/> + </linearGradient> + <radialGradient id="radialGradient4683-3" cx="2.1167" cy="2.1167" r=".66146" gradientTransform="matrix(4.5354 8.0301e-7 -8.0301e-7 4.5354 -1.6 -1.6)" gradientUnits="userSpaceOnUse"> + <stop stop-opacity=".28986" offset="0"/> + <stop stop-opacity="0" offset="1"/> + </radialGradient> + </defs> + <g> + <circle cx="8" cy="8" r="6.5" fill="url(#linearGradient4582)"/> + <circle cx="8" cy="8" r="5.75" fill="none" stroke="#fff" stroke-opacity=".50196" stroke-width="1.5"/> + <circle cx="8" cy="8" r="6.5" fill="none" stroke="url(#linearGradient4758-7)"/> + <circle cx="8" cy="8" r="3" fill="url(#radialGradient4683-3)"/> + <path d="m5 7h2v-2h2v2h2v2h-2v2h-2v-2h-2v-2" fill="#fff"/> + </g> +</svg> diff --git a/ext/mixed/img/entry-current.png b/ext/mixed/img/entry-current.png Binary files differdeleted file mode 100644 index bab7cc9b..00000000 --- a/ext/mixed/img/entry-current.png +++ /dev/null diff --git a/ext/mixed/img/entry-current.svg b/ext/mixed/img/entry-current.svg new file mode 100644 index 00000000..abf3f76d --- /dev/null +++ b/ext/mixed/img/entry-current.svg @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <linearGradient id="linearGradient4930" x1="3.175" x2="1.0583" y1="3.7042" y2=".52917" gradientTransform="scale(3.7795 3.7795)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#c47a00" offset="0"/> + <stop stop-color="#fcbf00" offset="1"/> + </linearGradient> + <radialGradient id="radialGradient4938" cx="2.1167" cy="2.1167" r="1.9976" gradientTransform="matrix(3.7795 0 0 3.7753 -5.7066e-7 .0088978)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#ffeeb5" offset="0"/> + <stop stop-color="#ffe079" offset="1"/> + </radialGradient> + </defs> + <g> + <path d="m10.25 9.375 3 4.5-2.25 1.5-3-4.5-3 4.5-2.25-1.5 3-4.5h-5.25v-2.75h5.25l-3-4.5 2.25-1.5 3 4.5 3-4.5 2.25 1.5-3 4.5h5.25v2.75z" fill="url(#radialGradient4938)" stroke="url(#linearGradient4930)" stroke-linejoin="bevel" stroke-opacity=".93333"/> + </g> +</svg> diff --git a/ext/mixed/img/play-audio.png b/ext/mixed/img/play-audio.png Binary files differdeleted file mode 100644 index 6056d234..00000000 --- a/ext/mixed/img/play-audio.png +++ /dev/null diff --git a/ext/mixed/img/play-audio.svg b/ext/mixed/img/play-audio.svg new file mode 100644 index 00000000..1d5e2d9c --- /dev/null +++ b/ext/mixed/img/play-audio.svg @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <linearGradient id="linearGradient4825" x1="-.39687" x2="-1.1906" y1="3.2411" y2="1.1906" gradientTransform="matrix(3.7795 0 0 3.7795 8.5 -6.308e-7)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#777772" offset="0"/> + <stop stop-color="#a9a9a9" offset="1"/> + </linearGradient> + <linearGradient id="linearGradient4869-7" x1=".52917" x2=".52917" y1="2.6458" y2="1.4552" gradientTransform="scale(3.7795 3.7795)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#fff" stop-opacity="0" offset="0"/> + <stop stop-color="#fff" offset="1"/> + </linearGradient> + <linearGradient id="linearGradient4853-9" x1="-.26458" x2="-1.5875" y1="3.4396" y2=".7276" gradientTransform="matrix(3.7795 0 0 3.7795 8.5 -2.9535e-7)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#5d5d5a" offset="0"/> + <stop stop-color="#90908f" offset="1"/> + </linearGradient> + <radialGradient id="radialGradient4898-9" cx="15" cy="8.5578" r="3.7188" gradientTransform="matrix(2.4322e-8 -2.1513 1.6807 1.9002e-8 1.3671 40.269)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#e1293b" offset="0"/> + <stop stop-color="#e9505a" offset="1"/> + </radialGradient> + </defs> + <g> + <path d="m0.5 8v2.5h3.5l3.5 3v-11l-3.5 3h-3.5v2.5" fill="url(#linearGradient4825)"/> + <path d="m1.25 10.5v-4.25h3l3-2.75" fill="none" stroke="url(#linearGradient4869-7)" stroke-opacity=".50196" stroke-width="1.5"/> + <path d="m0.5 8v2.5h3.5l3.5 3v-11l-3.5 3h-3.5v2.5" fill="none" stroke="url(#linearGradient4853-9)" stroke-linecap="round" stroke-linejoin="round"/> + <path d="m12.75 2.75c1.5 3 1.5 7.5 0 10.5 4.25-1.75 4.25-8.75 0-10.5m-2 2c0.75 1.5 0.75 5 0 6.5 3-1.25 3-5.25 0-6.5m-0.75 1.5-1.5 1.75 1.5 1.75c0.5-1 0.5-2.5 0-3.5" fill="url(#radialGradient4898-9)"/> + </g> +</svg> diff --git a/ext/mixed/img/source-term.png b/ext/mixed/img/source-term.png Binary files differdeleted file mode 100644 index 2e53c698..00000000 --- a/ext/mixed/img/source-term.png +++ /dev/null diff --git a/ext/mixed/img/source-term.svg b/ext/mixed/img/source-term.svg new file mode 100644 index 00000000..a70938f2 --- /dev/null +++ b/ext/mixed/img/source-term.svg @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <linearGradient id="linearGradient5205" x2="-3.9688" y1="3.7042" y2="1.0583" gradientTransform="matrix(3.7795 0 0 3.7795 20.5 -.5)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#012e5b" offset="0"/> + <stop stop-color="#6399c6" offset="1"/> + </linearGradient> + <linearGradient id="linearGradient5138-3" x1="3.8365" x2=".39687" y1="3.0427" y2=".59531" gradientTransform="matrix(3.7795 0 0 3.7795 5 -6e-7)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#012e5b" offset="0"/> + <stop stop-color="#6399c6" offset="1"/> + </linearGradient> + <linearGradient id="linearGradient5227-0" x1="2.6458" x2=".52917" y1="3.9688" y2="3.3734" gradientTransform="matrix(3.7795 0 0 3.7795 -5.7066e-7 -7)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#7cbe76" offset="0"/> + <stop stop-color="#abd8a2" offset="1"/> + </linearGradient> + <linearGradient id="linearGradient5219-8" x1="2.7781" x2=".13229" y1="4.101" y2="3.175" gradientTransform="matrix(3.7795 0 0 3.7795 -5.7066e-7 -7)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#205e1d" offset="0"/> + <stop stop-color="#74c768" offset="1"/> + </linearGradient> + </defs> + <g> + <path d="m16 3.5h-1.5l-1 1h-1l-1-1h-6v10h5.75l1 1h1.5l1-1h1.25" fill="#5d8bb3" stroke="url(#linearGradient5205)" stroke-width="1px"/> + <path d="m16 2.25h-1.5l-1 1h-1l-1-1h-5v9.25h5l1 1h1l1-1h1.5" fill="#f8f8f8" stroke="url(#linearGradient5138-3)" stroke-width="1px"/> + <g fill="none" stroke-width="1px"> + <path d="m15 8.75h1m-1-2h1m-1-2h1m-8 4h3m-3-2h3m-3-2h3" stroke="#bdbdbd"/> + <path d="m12.5 10.25v-4.75" stroke="#a6a6a6"/> + <path d="m13.5 5.75v4.25" stroke="#d8d8d8"/> + </g> + <path d="m10.5 7v-1.5h-7v-2l-3 3v1l3 3v-2h7v-1.5" fill="url(#linearGradient5227-0)" stroke="url(#linearGradient5219-8)" stroke-linejoin="round"/> + </g> +</svg> diff --git a/ext/mixed/img/view-note.png b/ext/mixed/img/view-note.png Binary files differdeleted file mode 100644 index 7d863f94..00000000 --- a/ext/mixed/img/view-note.png +++ /dev/null diff --git a/ext/mixed/img/view-note.svg b/ext/mixed/img/view-note.svg new file mode 100644 index 00000000..3e6f1dce --- /dev/null +++ b/ext/mixed/img/view-note.svg @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <linearGradient id="linearGradient5010" x2="-3.9688" y1="3.7042" y2="1.0583" gradientTransform="matrix(3.7795 0 0 3.7795 15.5 -.5)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#012e5b" offset="0"/> + <stop stop-color="#6399c6" offset="1"/> + </linearGradient> + <linearGradient id="linearGradient5018-3" x1="3.8365" x2=".39687" y1="3.0427" y2=".59531" gradientTransform="scale(3.7795 3.7795)" gradientUnits="userSpaceOnUse"> + <stop stop-color="#012e5b" offset="0"/> + <stop stop-color="#6399c6" offset="1"/> + </linearGradient> + </defs> + <g stroke-width="1px"> + <path d="m9.75 13.5-1 1h-1.5l-1-1h-5.75v-10h6l1 1h1l1-1h6v10z" fill="#5d8bb3" stroke="url(#linearGradient5010)"/> + <path d="m14.5 11.5h-5l-1 1h-1l-1-1h-5v-9.25h5l1 1h1l1-1h5v9.25" fill="#f8f8f8" stroke="url(#linearGradient5018-3)"/> + <g fill="none"> + <path d="m10 8.75h3m-3-2h3m-3-2h3m-10 4h3m-3-2h3m-3-2h3" stroke="#bdbdbd"/> + <path d="m7.5 10.25v-4.75" stroke="#a6a6a6"/> + <path d="m8.5 5.75v4.25" stroke="#d8d8d8"/> + </g> + </g> +</svg> diff --git a/ext/mixed/js/audio.js b/ext/mixed/js/audio.js new file mode 100644 index 00000000..b905140c --- /dev/null +++ b/ext/mixed/js/audio.js @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 Alex Yatskov <alex@foosoft.net> + * Author: Alex Yatskov <alex@foosoft.net> + * + * 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 <http://www.gnu.org/licenses/>. + */ + + +function audioGetFromUrl(url) { + return new Promise((resolve, reject) => { + const audio = new Audio(url); + audio.addEventListener('loadeddata', () => { + if (audio.duration === 5.694694 || audio.duration === 5.720718) { + // Hardcoded values for invalid audio + reject(new Error('Could not retrieve audio')); + } else { + resolve(audio); + } + }); + audio.addEventListener('error', () => reject(audio.error)); + }); +} + +async function audioGetFromSources(expression, sources, optionsContext, createAudioObject, cache=null) { + const key = `${expression.expression}:${expression.reading}`; + if (cache !== null && cache.hasOwnProperty(expression)) { + return cache[key]; + } + + for (let i = 0, ii = sources.length; i < ii; ++i) { + const source = sources[i]; + const url = await apiAudioGetUrl(expression, source, optionsContext); + if (url === null) { + continue; + } + + try { + const audio = createAudioObject ? await audioGetFromUrl(url) : null; + const result = {audio, url, source}; + if (cache !== null) { + cache[key] = result; + } + return result; + } catch (e) { + // NOP + } + } + return {audio: null, source: null}; +} diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index dc64dbea..22181301 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -26,6 +26,8 @@ class Display { this.context = null; this.sequence = 0; this.index = 0; + this.audioPlaying = null; + this.audioFallback = null; this.audioCache = {}; this.optionsContext = {}; this.eventListeners = []; @@ -39,11 +41,11 @@ class Display { } onError(error) { - throw 'Override me'; + throw new Error('Override me'); } onSearchClear() { - throw 'Override me'; + throw new Error('Override me'); } onSourceTermView(e) { @@ -133,7 +135,7 @@ class Display { const entry = link.closest('.entry'); const definitionIndex = this.entryIndexFind(entry); const expressionIndex = Display.indexOf(entry.querySelectorAll('.expression .action-play-audio'), link); - this.audioPlay(this.definitions[definitionIndex], expressionIndex); + this.audioPlay(this.definitions[definitionIndex], expressionIndex, definitionIndex); } onNoteAdd(e) { @@ -189,7 +191,7 @@ class Display { addable: options.anki.enable, grouped: options.general.resultOutputMode === 'group', merged: options.general.resultOutputMode === 'merge', - playback: options.general.audioSource !== 'disabled', + playback: options.audio.enabled, compactGlossaries: options.general.compactGlossaries, debug: options.general.debugInfo }; @@ -209,7 +211,7 @@ class Display { const {index, scroll} = context || {}; this.entryScrollIntoView(index || 0, scroll); - if (this.options.general.autoPlayAudio && this.options.general.audioSource !== 'disabled') { + if (this.options.audio.enabled && this.options.audio.autoPlay) { this.autoPlayAudio(); } @@ -274,7 +276,7 @@ class Display { } autoPlayAudio() { - this.audioPlay(this.definitions[0], this.firstExpressionIndex); + this.audioPlay(this.definitions[0], this.firstExpressionIndex, 0); } async adderButtonUpdate(modes, sequence) { @@ -286,15 +288,23 @@ class Display { for (let i = 0; i < states.length; ++i) { const state = states[i]; + let noteId = null; for (const mode in state) { const button = this.adderButtonFind(i, mode); if (button === null) { continue; } - button.classList.toggle('disabled', !state[mode]); + const info = state[mode]; + if (!info.canAdd && noteId === null && info.noteId) { + noteId = info.noteId; + } + button.classList.toggle('disabled', !info.canAdd); button.classList.remove('pending'); } + if (noteId !== null) { + this.viewerButtonShow(i, noteId); + } } } catch (e) { this.onError(e); @@ -380,13 +390,9 @@ class Display { if (adderButton !== null) { adderButton.classList.add('disabled'); } - const viewerButton = this.viewerButtonFind(index); - if (viewerButton !== null) { - viewerButton.classList.remove('pending', 'disabled'); - viewerButton.dataset.noteId = noteId; - } + this.viewerButtonShow(index, noteId); } else { - throw 'Note could note be added'; + throw new Error('Note could not be added'); } } catch (e) { this.onError(e); @@ -395,37 +401,44 @@ class Display { } } - async audioPlay(definition, expressionIndex) { + async audioPlay(definition, expressionIndex, entryIndex) { try { this.setSpinnerVisible(true); const expression = expressionIndex === -1 ? definition : definition.expressions[expressionIndex]; - let url = await apiAudioGetUrl(expression, this.options.general.audioSource); - if (!url) { - url = '/mixed/mp3/button.mp3'; - } - for (const key in this.audioCache) { - this.audioCache[key].pause(); + if (this.audioPlaying !== null) { + this.audioPlaying.pause(); + this.audioPlaying = null; } - let audio = this.audioCache[url]; - if (audio) { - audio.currentTime = 0; - audio.volume = this.options.general.audioVolume / 100.0; - audio.play(); + const sources = this.options.audio.sources; + let {audio, source} = await audioGetFromSources(expression, sources, this.optionsContext, true, this.audioCache); + let info; + if (audio === null) { + if (this.audioFallback === null) { + this.audioFallback = new Audio('/mixed/mp3/button.mp3'); + } + audio = this.audioFallback; + info = 'Could not find audio'; } else { - audio = new Audio(url); - audio.onloadeddata = () => { - if (audio.duration === 5.694694 || audio.duration === 5.720718) { - audio = new Audio('/mixed/mp3/button.mp3'); - } + info = `From source ${1 + sources.indexOf(source)}: ${source}`; + } - this.audioCache[url] = audio; - audio.volume = this.options.general.audioVolume / 100.0; - audio.play(); - }; + const button = this.audioButtonFindImage(entryIndex); + if (button !== null) { + let titleDefault = button.dataset.titleDefault; + if (!titleDefault) { + titleDefault = button.title || ""; + button.dataset.titleDefault = titleDefault; + } + button.title = `${titleDefault}\n${info}`; } + + this.audioPlaying = audio; + audio.currentTime = 0; + audio.volume = this.options.audio.volume / 100.0; + audio.play(); } catch (e) { this.onError(e); } finally { @@ -445,7 +458,7 @@ class Display { async getScreenshot() { try { - await this.setPopupVisible(false); + await this.setPopupVisibleOverride(false); await Display.delay(1); // Wait for popup to be hidden. const {format, quality} = this.options.anki.screenshot; @@ -454,7 +467,7 @@ class Display { return {dataUrl, format}; } finally { - await this.setPopupVisible(true); + await this.setPopupVisibleOverride(null); } } @@ -462,8 +475,8 @@ class Display { return this.options.general.resultOutputMode === 'merge' ? 0 : -1; } - setPopupVisible(visible) { - return apiForward('popupSetVisible', {visible}); + setPopupVisibleOverride(visible) { + return apiForward('popupSetVisibleOverride', {visible}); } setSpinnerVisible(visible) { @@ -504,6 +517,20 @@ class Display { return entry !== null ? entry.querySelector('.action-view-note') : null; } + viewerButtonShow(index, noteId) { + const viewerButton = this.viewerButtonFind(index); + if (viewerButton === null) { + return; + } + viewerButton.classList.remove('pending', 'disabled'); + viewerButton.dataset.noteId = noteId; + } + + audioButtonFindImage(index) { + const entry = this.getEntry(index); + return entry !== null ? entry.querySelector('.action-play-audio>img') : null; + } + static delay(time) { return new Promise((resolve) => setTimeout(resolve, time)); } @@ -539,7 +566,7 @@ class Display { static getKeyFromEvent(event) { const key = event.key; - return key.length === 1 ? key.toUpperCase() : key; + return (typeof key === 'string' ? (key.length === 1 ? key.toUpperCase() : key) : ''); } } @@ -633,7 +660,7 @@ Display.onKeyDownHandlers = { if (e.altKey) { const entry = self.getEntry(self.index); if (entry !== null && entry.dataset.type === 'term') { - self.audioPlay(self.definitions[self.index], self.firstExpressionIndex); + self.audioPlay(self.definitions[self.index], self.firstExpressionIndex, self.index); } return true; } diff --git a/ext/mixed/js/extension.js b/ext/mixed/js/extension.js index 5c803132..861e52a5 100644 --- a/ext/mixed/js/extension.js +++ b/ext/mixed/js/extension.js @@ -34,7 +34,7 @@ function toIterable(value) { } } - throw 'Could not convert to iterable'; + throw new Error('Could not convert to iterable'); } function extensionHasChrome() { @@ -53,6 +53,39 @@ function extensionHasBrowser() { } } +function errorToJson(error) { + return { + name: error.name, + message: error.message, + stack: error.stack + }; +} + +function jsonToError(jsonError) { + const error = new Error(jsonError.message); + error.name = jsonError.name; + error.stack = jsonError.stack; + return error; +} + +function logError(error, alert) { + const manifest = chrome.runtime.getManifest(); + let errorMessage = `${manifest.name} v${manifest.version} has encountered an error.\n`; + errorMessage += `Originating URL: ${window.location.href}\n`; + + const errorString = `${error.toString ? error.toString() : error}`; + const stack = `${error.stack}`.trimRight(); + errorMessage += (!stack.startsWith(errorString) ? `${errorString}\n${stack}` : `${stack}`); + + errorMessage += '\n\nIssues can be reported at https://github.com/FooSoft/yomichan/issues'; + + console.error(errorMessage); + + if (alert) { + window.alert(`${errorString}\n\nCheck the developer console for more details.`); + } +} + const EXTENSION_IS_BROWSER_EDGE = ( extensionHasBrowser() && (!extensionHasChrome() || (typeof chrome.runtime === 'undefined' && typeof browser.runtime !== 'undefined')) |