aboutsummaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/bg/guide.html13
-rw-r--r--ext/bg/js/display-window.js9
-rw-r--r--ext/bg/js/popup.js7
-rw-r--r--ext/bg/js/templates.js12
-rw-r--r--ext/bg/js/util.js9
-rw-r--r--ext/bg/js/yomichan.js22
-rw-r--r--ext/bg/search.html2
-rw-r--r--ext/fg/frame.html30
-rw-r--r--ext/fg/js/driver.js3
-rw-r--r--ext/manifest.json14
-rw-r--r--ext/mixed/css/frame.css3
-rw-r--r--ext/mixed/img/entry-current.pngbin0 -> 743 bytes
-rw-r--r--ext/mixed/js/display.js177
13 files changed, 222 insertions, 79 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.png
new file mode 100644
index 00000000..bab7cc9b
--- /dev/null
+++ b/ext/mixed/img/entry-current.png
Binary files differ
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();