aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/bg/background.html1
-rw-r--r--ext/bg/js/display-window.js14
-rw-r--r--ext/bg/search.html2
-rw-r--r--ext/fg/frame.html4
-rw-r--r--ext/fg/js/display-frame.js58
-rw-r--r--ext/fg/js/frontend.js141
-rw-r--r--ext/fg/js/util.js2
-rw-r--r--ext/mixed/js/display.js344
8 files changed, 291 insertions, 275 deletions
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 @@
<script src="/bg/js/templates.js"></script>
<script src="/bg/js/translator.js"></script>
<script src="/bg/js/util.js"></script>
+ <script src="/bg/js/util.js"></script>
<script src="/mixed/js/audio.js"></script>
<script src="/mixed/js/japanese.js"></script>
<script src="/mixed/js/request.js"></script>
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 @@
<script src="/bg/js/dictionary.js"></script>
<script src="/bg/js/handlebars.js"></script>
<script src="/bg/js/templates.js"></script>
+ <script src="/bg/js/util.js"></script>
<script src="/mixed/js/audio.js"></script>
<script src="/mixed/js/display.js"></script>
<script src="/mixed/js/japanese.js"></script>
- <script src="/mixed/js/request.js"></script>
<script src="/bg/js/display-window.js"></script>
</body>
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 @@
<img src="/mixed/img/spinner.gif">
</div>
- <div id="content"></div>
+ <div id="definitions"></div>
- <div id="orphan">
+ <div id="error-orphaned">
<div class="container-fluid">
<h1>Yomichan Updated!</h1>
<p>
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) {