diff options
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/bg/background.html | 1 | ||||
| -rw-r--r-- | ext/bg/js/display-window.js | 14 | ||||
| -rw-r--r-- | ext/bg/search.html | 2 | ||||
| -rw-r--r-- | ext/fg/frame.html | 4 | ||||
| -rw-r--r-- | ext/fg/js/display-frame.js | 58 | ||||
| -rw-r--r-- | ext/fg/js/frontend.js | 141 | ||||
| -rw-r--r-- | ext/fg/js/util.js | 2 | ||||
| -rw-r--r-- | ext/mixed/js/display.js | 344 | 
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) { |