diff options
| -rw-r--r-- | ext/bg/guide.html | 13 | ||||
| -rw-r--r-- | ext/bg/js/display-window.js | 9 | ||||
| -rw-r--r-- | ext/bg/js/popup.js | 7 | ||||
| -rw-r--r-- | ext/bg/js/templates.js | 12 | ||||
| -rw-r--r-- | ext/bg/js/util.js | 9 | ||||
| -rw-r--r-- | ext/bg/js/yomichan.js | 22 | ||||
| -rw-r--r-- | ext/bg/search.html | 2 | ||||
| -rw-r--r-- | ext/fg/frame.html | 30 | ||||
| -rw-r--r-- | ext/fg/js/driver.js | 3 | ||||
| -rw-r--r-- | ext/manifest.json | 14 | ||||
| -rw-r--r-- | ext/mixed/css/frame.css | 3 | ||||
| -rw-r--r-- | ext/mixed/img/entry-current.png | bin | 0 -> 743 bytes | |||
| -rw-r--r-- | ext/mixed/js/display.js | 177 | ||||
| -rw-r--r-- | tmpl/kanji.html | 5 | ||||
| -rw-r--r-- | tmpl/terms.html | 7 | 
15 files changed, 229 insertions, 84 deletions
| diff --git a/ext/bg/guide.html b/ext/bg/guide.html index 130d6d68..3b3dcab7 100644 --- a/ext/bg/guide.html +++ b/ext/bg/guide.html @@ -7,7 +7,7 @@          <link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap-3.3.7-dist/css/bootstrap-theme.min.css">      </head>      <body> -        <div class="container-fluid"> +        <div class="container">              <div class="page-header">                  <h1>Welcome to Yomichan!</h1>              </div> @@ -23,11 +23,12 @@                  </p>                  <ol> -                    <li>Click on the <img src="/mixed/img/icon16.png" alt> icon in the browser toolbar to open the Yomichan options page.</li> -                    <li>Import the dictionaries (bundled or custom) you wish to use for term and Kanji searches.</li> -                    <li>Hold down <kbd>Shift</kbd> (or the middle mouse button) as you hover over text to see term definitions.</li> -                    <li>Click on the <img src="/mixed/img/play-audio.png" alt> icon to hear the term pronounced by a native speaker (if audio is available).</li> -                    <li>Click on Kanji in the definition window to view additional information about that character.</li> +                    <li>Click on the <img src="/mixed/img/icon16.png" alt> icon in the browser toolbar to open the Yomichan actions dialog.</li> +                    <li>Click on the <em>monkey wrench</em> icon in the middle to open the options page.</li> +                    <li>Import the dictionaries you wish to use for term and Kanji searches.</li> +                    <li>Hold down <kbd>Shift</kbd> key or the middle mouse button as you move your mouse over text to display definitions.</li> +                    <li>Click on the <img src="/mixed/img/play-audio.png" alt> icon to hear the term pronounced by a native speaker.</li> +                    <li>Click on individual Kanji in the term definition results to view additional information about those characters.</li>                  </ol>              </div>          </div> diff --git a/ext/bg/js/display-window.js b/ext/bg/js/display-window.js index ad193c5b..8c732ddd 100644 --- a/ext/bg/js/display-window.js +++ b/ext/bg/js/display-window.js @@ -20,8 +20,13 @@  window.displayWindow = new class extends Display {      constructor() {          super($('#spinner'), $('#content')); -        $('#search').click(this.onSearch.bind(this)); -        window.wanakana.bind($('#query').get(0)); + +        const search = $('#search'); +        search.click(this.onSearch.bind(this)); + +        const query = $('#query'); +        query.on('input', () => search.prop('disabled', query.val().length === 0)); +        window.wanakana.bind(query.get(0));      }      definitionAdd(definition, mode) { diff --git a/ext/bg/js/popup.js b/ext/bg/js/popup.js index 9f2567df..5bc7def4 100644 --- a/ext/bg/js/popup.js +++ b/ext/bg/js/popup.js @@ -18,7 +18,7 @@  $(document).ready(() => { -    $('#open-search').click(() => window.open(chrome.extension.getURL('/bg/search.html'))); +    $('#open-search').click(() => commandExec('search'));      $('#open-options').click(() => chrome.runtime.openOptionsPage());      $('#open-help').click(() => window.open('http://foosoft.net/projects/yomichan')); @@ -26,9 +26,6 @@ $(document).ready(() => {          const toggle = $('#enable-search');          toggle.prop('checked', options.general.enable).change();          toggle.bootstrapToggle(); -        toggle.change(() => { -            options.general.enable = toggle.prop('checked'); -            optionsSave(options).then(() => instYomi().optionsSet(options)); -        }); +        toggle.change(() => commandExec('toggle'));      });  }); diff --git a/ext/bg/js/templates.js b/ext/bg/js/templates.js index 91518e84..f267da80 100644 --- a/ext/bg/js/templates.js +++ b/ext/bg/js/templates.js @@ -284,7 +284,7 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti  templates['kanji.html'] = template({"1":function(container,depth0,helpers,partials,data) {      var stack1, helper, alias1=depth0 != null ? depth0 : {}; -  return "<div class=\"entry\">\n    <div class=\"actions\">\n" +  return "<div class=\"entry\">\n    <div class=\"actions\">\n        <img src=\"/mixed/img/entry-current.png\" class=\"current\" title=\"Current entry (arrows / home / end)\" alt>\n"      + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.addable : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")      + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.source : depth0),{"name":"if","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")      + "    </div>\n\n    <div class=\"glyph\">" @@ -299,9 +299,9 @@ templates['kanji.html'] = template({"1":function(container,depth0,helpers,partia      + ((stack1 = helpers["if"].call(alias1,((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(11, data, 0),"inverse":container.program(15, data, 0),"data":data})) != null ? stack1 : "")      + "    </div>\n</div>\n";  },"2":function(container,depth0,helpers,partials,data) { -    return "        <a href=\"#\" title=\"Add Kanji\" class=\"action-add-note pending disabled\" data-mode=\"kanji\"><img src=\"/mixed/img/add-kanji.png\" alt></a>\n"; +    return "        <a href=\"#\" class=\"action-add-note pending disabled\" data-mode=\"kanji\"><img src=\"/mixed/img/add-kanji.png\" title=\"Add Kanji ([)\" alt></a>\n";  },"4":function(container,depth0,helpers,partials,data) { -    return "        <a href=\"#\" title=\"Source term\" class=\"source-term\"><img src=\"/mixed/img/source-term.png\" alt></a>\n"; +    return "        <a href=\"#\" class=\"source-term\"><img src=\"/mixed/img/source-term.png\" title=\"Source term (Backspace)\" alt></a>\n";  },"6":function(container,depth0,helpers,partials,data) {      var stack1; @@ -442,7 +442,7 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia  },"12":function(container,depth0,helpers,partials,data) {      var stack1, alias1=depth0 != null ? depth0 : {}; -  return "<div class=\"entry\">\n    <div class=\"actions\">\n" +  return "<div class=\"entry\">\n    <div class=\"actions\">\n        <img src=\"/mixed/img/entry-current.png\" class=\"current\" title=\"Current entry (arrows / home / end)\" alt>\n"      + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.addable : depth0),{"name":"if","hash":{},"fn":container.program(13, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")      + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.playback : depth0),{"name":"if","hash":{},"fn":container.program(15, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")      + "    </div>\n\n" @@ -453,9 +453,9 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia      + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.grouped : depth0),{"name":"if","hash":{},"fn":container.program(26, data, 0),"inverse":container.program(32, data, 0),"data":data})) != null ? stack1 : "")      + "    </div>\n</div>\n";  },"13":function(container,depth0,helpers,partials,data) { -    return "        <a href=\"#\" title=\"Add expression\" class=\"action-add-note pending disabled\" data-mode=\"term-kanji\"><img src=\"/mixed/img/add-term-kanji.png\" alt></a>\n        <a href=\"#\" title=\"Add reading\" class=\"action-add-note pending disabled\" data-mode=\"term-kana\"><img src=\"/mixed/img/add-term-kana.png\" alt></a>\n"; +    return "        <a href=\"#\" class=\"action-add-note pending disabled\" data-mode=\"term-kanji\"><img src=\"/mixed/img/add-term-kanji.png\" title=\"Add expression ([)\" alt></a>\n        <a href=\"#\" class=\"action-add-note pending disabled\" data-mode=\"term-kana\"><img src=\"/mixed/img/add-term-kana.png\" title=\"Add reading (])\" alt></a>\n";  },"15":function(container,depth0,helpers,partials,data) { -    return "        <a href=\"#\" title=\"Play audio\" class=\"action-play-audio\"><img src=\"/mixed/img/play-audio.png\" alt></a>\n"; +    return "        <a href=\"#\" class=\"action-play-audio\"><img src=\"/mixed/img/play-audio.png\" title=\"Play audio (\\)\" alt></a>\n";  },"17":function(container,depth0,helpers,partials,data) {      var stack1, helper, options, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", buffer =     "    <div class=\"expression\"><ruby>"; diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js index 59eb9269..6999cae3 100644 --- a/ext/bg/js/util.js +++ b/ext/bg/js/util.js @@ -34,6 +34,15 @@ function promiseCallback(promise, callback) {  /* + * Commands + */ + +function commandExec(command) { +    instYomi().onCommand(command); +} + + +/*   * Instance   */ diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js index a61be8be..3a42c594 100644 --- a/ext/bg/js/yomichan.js +++ b/ext/bg/js/yomichan.js @@ -25,12 +25,13 @@ window.yomichan = new class {          this.anki = new AnkiNull();          this.options = null; -        chrome.runtime.onMessage.addListener(this.onMessage.bind(this)); -        if (chrome.runtime.onInstalled) { -            chrome.runtime.onInstalled.addListener(this.onInstalled.bind(this)); -        } - -        this.translator.prepare().then(optionsLoad).then(this.optionsSet.bind(this)); +        this.translator.prepare().then(optionsLoad).then(this.optionsSet.bind(this)).then(() => { +            chrome.commands.onCommand.addListener(this.onCommand.bind(this)); +            chrome.runtime.onMessage.addListener(this.onMessage.bind(this)); +            if (chrome.runtime.onInstalled) { +                chrome.runtime.onInstalled.addListener(this.onInstalled.bind(this)); +            } +        });      }      optionsSet(options) { @@ -153,6 +154,15 @@ window.yomichan = new class {          }      } +    onCommand(command) { +        if (command === 'search') { +            window.open(chrome.extension.getURL('/bg/search.html')); +        } else if (command === 'toggle') { +            this.options.general.enable = !this.options.general.enable; +            optionsSave(this.options).then(() => this.optionsSet(this.options)); +        } +    } +      onMessage(request, sender, callback) {          const handlers = new class {              api_optionsGet({callback}) { diff --git a/ext/bg/search.html b/ext/bg/search.html index e9c25e15..2fd44fc7 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -20,7 +20,7 @@                  <form class="input-group">                      <input type="text" class="form-control" placeholder="Search for..." id="query" autofocus>                      <span class="input-group-btn"> -                        <input type="submit" class="btn btn-default form-control" id="search" value="Search"> +                        <input type="submit" class="btn btn-default form-control" id="search" value="Search" disabled>                      </span>                  </form>              </p> diff --git a/ext/fg/frame.html b/ext/fg/frame.html index ec0acf64..09d1689e 100644 --- a/ext/fg/frame.html +++ b/ext/fg/frame.html @@ -6,28 +6,34 @@          <link rel="stylesheet" href="/mixed/lib/bootstrap-3.3.7-dist/css/bootstrap.min.css">          <link rel="stylesheet" href="/mixed/lib/bootstrap-3.3.7-dist/css/bootstrap-theme.min.css">          <link rel="stylesheet" href="/mixed/css/frame.css"> +        <style type="text/css"> +            .entry { +                padding-left: 10px; +                padding-right: 10px; +            } +        </style>      </head>      <body> -        <div class="container-fluid"> -            <div id="spinner"> -                <img src="/mixed/img/spinner.gif"> -            </div> +        <div id="spinner"> +            <img src="/mixed/img/spinner.gif"> +        </div> -            <div id="content"></div> +        <div id="content"></div> -            <div id="orphan"> +        <div id="orphan"> +            <div class="container-fluid">                  <h1>Yomichan Updated!</h1>                  <p>                      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.                  </p>              </div> - -            <script src="/mixed/lib/jquery-3.1.1.min.js"></script> -            <script src="/mixed/lib/wanakana.min.js"></script> -            <script src="/fg/js/util.js"></script> -            <script src="/mixed/js/display.js"></script> -            <script src="/fg/js/display-frame.js"></script>          </div> + +        <script src="/mixed/lib/jquery-3.1.1.min.js"></script> +        <script src="/mixed/lib/wanakana.min.js"></script> +        <script src="/fg/js/util.js"></script> +        <script src="/mixed/js/display.js"></script> +        <script src="/fg/js/display-frame.js"></script>      </body>  </html> diff --git a/ext/fg/js/driver.js b/ext/fg/js/driver.js index fbe89ab8..16b12d5e 100644 --- a/ext/fg/js/driver.js +++ b/ext/fg/js/driver.js @@ -105,6 +105,9 @@ window.driver = new class {          const handlers = new class {              api_optionsSet(options) {                  this.options = options; +                if (!this.options.enable) { +                    this.searchClear(); +                }              }          }; diff --git a/ext/manifest.json b/ext/manifest.json index 9c311b2f..215397d0 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -31,6 +31,20 @@          "<all_urls>",          "storage"      ], +    "commands": { +        "toggle": { +            "suggested_key": { +                "default": "Alt+Delete" +            }, +            "description": "Toggle text scanning" +        }, +        "search": { +            "suggested_key": { +                "default": "Alt+Insert" +            }, +            "description": "Open search window" +        } +    },      "web_accessible_resources": ["fg/frame.html"],      "applications": {          "gecko": { diff --git a/ext/mixed/css/frame.css b/ext/mixed/css/frame.css index af689cbe..a425aca8 100644 --- a/ext/mixed/css/frame.css +++ b/ext/mixed/css/frame.css @@ -52,7 +52,8 @@ hr {   */  .entry { -    padding: 15px 0px 15px 0px; +    padding-top: 10px; +    padding-bottom: 10px;  }  .tag-default { diff --git a/ext/mixed/img/entry-current.png b/ext/mixed/img/entry-current.pngBinary files differ new file mode 100644 index 00000000..bab7cc9b --- /dev/null +++ b/ext/mixed/img/entry-current.png diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 63620dc6..45c1e08c 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -25,6 +25,9 @@ class Display {          this.audioCache = {};          this.responseCache = {};          this.sequence = 0; +        this.index = 0; + +        $(document).keydown(this.onKeyDown.bind(this));      }      definitionAdd(definition, mode) { @@ -48,8 +51,12 @@ class Display {      }      showTermDefs(definitions, options, context) { +        window.focus(); +          this.spinner.hide();          this.definitions = definitions; +        this.context = context; +        this.options = options;          const sequence = ++this.sequence;          const params = { @@ -69,42 +76,24 @@ class Display {          this.templateRender('terms.html', params).then(content => {              this.container.html(content); -            let offset = 0; -            if (context && context.hasOwnProperty('index') && context.index < definitions.length) { -                const entry = $('.entry').eq(context.index); -                offset = entry.offset().top; -            } +            const index = context && context.hasOwnProperty('index') ? context.index : 0; +            this.entryScroll(index); -            window.scrollTo(0, offset); - -            $('.action-add-note').click(this.onActionAddNote.bind(this)); -            $('.action-play-audio').click(e => { -                e.preventDefault(); -                const index = Display.entryIndexFind($(e.currentTarget)); -                this.audioPlay(this.definitions[index]); -            }); -            $('.kanji-link').click(e => { -                e.preventDefault(); - -                const link = $(e.target); -                context = context || {}; -                context.source = { -                    definitions, -                    index: Display.entryIndexFind(link) -                }; - -                this.kanjiFind(link.text()).then(kanjiDefs => { -                    this.showKanjiDefs(kanjiDefs, options, context); -                }).catch(this.handleError.bind(this)); -            }); +            $('.action-add-note').click(this.onAddNote.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.context = context; +        this.options = options;          const sequence = ++this.sequence;          const params = { @@ -122,17 +111,12 @@ class Display {          this.templateRender('kanji.html', params).then(content => {              this.container.html(content); -            window.scrollTo(0, 0); -            $('.action-add-note').click(this.onActionAddNote.bind(this)); -            $('.source-term').click(e => { -                e.preventDefault(); +            const index = context && context.hasOwnProperty('index') ? context.index : 0; +            this.entryScroll(index); -                if (context && context.source) { -                    context.index = context.source.index; -                    this.showTermDefs(context.source.definitions, options, context); -                } -            }); +            $('.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)); @@ -159,13 +143,125 @@ class Display {          });      } -    onActionAddNote(e) { +    entryScroll(index, smooth) { +        if (index < 0 || index >= this.definitions.length) { +            return; +        } + +        $('.current').hide().eq(index).show(); + +        const body = $('body').stop(); +        const entry = $('.entry').eq(index); +        const target = index === 0 ? 0 : entry.offset().top; + +        if (smooth) { +            body.animate({scrollTop: target}, 200); +        } else { +            body.scrollTop(target); +        } + +        this.index = index; +    } + +    onSourceTerm(e) { +        e.preventDefault(); + +        if (this.context && this.context.source) { +            const context = { +                url: this.context.source.url, +                sentence: this.context.source.sentence, +                index: this.context.source.index +            }; + +            this.showTermDefs(this.context.source.definitions, this.options, context); +        } +    } + +    onKanjiLookup(e) { +        e.preventDefault(); + +        const link = $(e.target); +        const context = { +            source: { +                definitions, +                index: Display.entryIndexFind(link) +            } +        }; + +        if (this.context) { +            context.sentence = this.context.sentence || ''; +            context.url = this.context.url || ''; +        } + +        this.kanjiFind(link.text()).then(kanjiDefs => { +            this.showKanjiDefs(kanjiDefs, options, context); +        }).catch(this.handleError.bind(this)); +    } + +    onPlayAudio(e) { +        e.preventDefault(); + +        const index = Display.entryIndexFind($(e.currentTarget)); +        this.audioPlay(this.definitions[index]); +    } + +    onAddNote(e) {          e.preventDefault(); -        this.spinner.show();          const link = $(e.currentTarget); -        const mode = link.data('mode');          const index = Display.entryIndexFind(link); +        this.noteAdd(index, link.data('mode')); +    } + +    onKeyDown(e) { +        const handlers = { +            36: /* home */ () => { +                this.entryScroll(0, true); +            }, + +            35: /* end */ () => { +                this.entryScroll(this.definitions.length - 1, true); +            }, + +            38: /* up */ () => { +                this.entryScroll(this.index - 1, true); +            }, + +            40: /* down */ () => { +                this.entryScroll(this.index + 1, true); +            }, + +            209: /* [ */ () => { + +            }, + +            221: /* ] */ () => { + +            }, + +            220: /* \ */ () => { +                this.audioPlay(this.definitions[this.index]); +            }, + +            8: /* backspace */ () => { + +            } +        }; + +        const handler = handlers[e.keyCode]; +        if (handler) { +            e.preventDefault(); +            handler(); +        } +    } + +    sourceTerm(index) { + + +    } + +    noteAdd(index, mode) { +        this.spinner.show();          const definition = this.definitions[index];          let promise = Promise.resolve(); @@ -187,8 +283,9 @@ class Display {          }).catch(this.handleError.bind(this)).then(() => this.spinner.hide());      } -    audioPlay(definition) { +    audioPlay(index) {          this.spinner.show(); +        const definition = this.definitions[index];          for (const key in this.audioCache) {              this.audioCache[key].pause(); diff --git a/tmpl/kanji.html b/tmpl/kanji.html index 4bb524cf..be5e8541 100644 --- a/tmpl/kanji.html +++ b/tmpl/kanji.html @@ -1,11 +1,12 @@  {{#*inline "kanji"}}  <div class="entry">      <div class="actions"> +        <img src="/mixed/img/entry-current.png" class="current" title="Current entry (arrows / home / end)" alt>          {{#if addable}} -        <a href="#" title="Add Kanji" class="action-add-note pending disabled" data-mode="kanji"><img src="/mixed/img/add-kanji.png" alt></a> +        <a href="#" class="action-add-note pending disabled" data-mode="kanji"><img src="/mixed/img/add-kanji.png" title="Add Kanji ([)" alt></a>          {{/if}}          {{#if source}} -        <a href="#" title="Source term" class="source-term"><img src="/mixed/img/source-term.png" alt></a> +        <a href="#" class="source-term"><img src="/mixed/img/source-term.png" title="Source term (Backspace)" alt></a>          {{/if}}      </div> diff --git a/tmpl/terms.html b/tmpl/terms.html index fa32cea1..f108da26 100644 --- a/tmpl/terms.html +++ b/tmpl/terms.html @@ -20,12 +20,13 @@  {{#*inline "term"}}  <div class="entry">      <div class="actions"> +        <img src="/mixed/img/entry-current.png" class="current" title="Current entry (arrows / home / end)" alt>          {{#if addable}} -        <a href="#" title="Add expression" class="action-add-note pending disabled" data-mode="term-kanji"><img src="/mixed/img/add-term-kanji.png" alt></a> -        <a href="#" title="Add reading" class="action-add-note pending disabled" data-mode="term-kana"><img src="/mixed/img/add-term-kana.png" alt></a> +        <a href="#" class="action-add-note pending disabled" data-mode="term-kanji"><img src="/mixed/img/add-term-kanji.png" title="Add expression ([)" alt></a> +        <a href="#" class="action-add-note pending disabled" data-mode="term-kana"><img src="/mixed/img/add-term-kana.png" title="Add reading (])" alt></a>          {{/if}}          {{#if playback}} -        <a href="#" title="Play audio" class="action-play-audio"><img src="/mixed/img/play-audio.png" alt></a> +        <a href="#" class="action-play-audio"><img src="/mixed/img/play-audio.png" title="Play audio (\)" alt></a>          {{/if}}      </div> |