aboutsummaryrefslogtreecommitdiff
path: root/ext/bg
diff options
context:
space:
mode:
Diffstat (limited to 'ext/bg')
-rw-r--r--ext/bg/js/ankiweb.js180
-rw-r--r--ext/bg/js/options-form.js7
-rw-r--r--ext/bg/js/options.js14
-rw-r--r--ext/bg/js/templates.js355
-rw-r--r--ext/bg/js/translator.js21
-rw-r--r--ext/bg/js/util.js154
-rw-r--r--ext/bg/js/yomichan.js96
-rw-r--r--ext/bg/options.html4
8 files changed, 578 insertions, 253 deletions
diff --git a/ext/bg/js/ankiweb.js b/ext/bg/js/ankiweb.js
new file mode 100644
index 00000000..69a1b44d
--- /dev/null
+++ b/ext/bg/js/ankiweb.js
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2016 Alex Yatskov <alex@foosoft.net>
+ * Author: Alex Yatskov <alex@foosoft.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+class AnkiWeb {
+ constructor(username, password) {
+ this.username = username;
+ this.password = password;
+ this.noteInfo = null;
+
+ chrome.webRequest.onBeforeSendHeaders.addListener(
+ details => {
+ details.requestHeaders.push({name: 'Origin', value: 'https://ankiweb.net'});
+ return {requestHeaders: details.requestHeaders};
+ },
+ {urls: ['https://ankiweb.net/*']},
+ ['blocking', 'requestHeaders']
+ );
+ }
+
+ addNote(note) {
+ return this.retrieve().then(info => {
+ const model = info.models.find(m => m.name === note.modelName);
+ if (!model) {
+ return Promise.reject('cannot add note model provided');
+ }
+
+ const fields = [];
+ for (const field of model.fields) {
+ fields.push(note.fields[field]);
+ }
+
+ const data = {
+ data: JSON.stringify([fields, note.tags.join(' ')]),
+ mid: model.id,
+ deck: note.deckName,
+ csrf_token: info.token
+ };
+
+ return AnkiWeb.loadAccountPage('https://ankiweb.net/edit/save', data, this.username, this.password);
+ }).then(response => response !== '0');
+ }
+
+ canAddNotes(notes) {
+ return Promise.resolve(new Array(notes.length).fill(true));
+ }
+
+ getDeckNames() {
+ return this.retrieve().then(info => info.deckNames);
+ }
+
+ getModelNames() {
+ return this.retrieve().then(info => info.models.map(m => m.name));
+ }
+
+ getModelFieldNames(modelName) {
+ return this.retrieve().then(info => {
+ const model = info.models.find(m => m.name === modelName);
+ return model ? model.fields : [];
+ });
+ }
+
+ retrieve() {
+ if (this.noteInfo !== null) {
+ return Promise.resolve(this.noteInfo);
+ }
+
+ return AnkiWeb.scrape(this.username, this.password).then(({deckNames, models, token}) => {
+ this.noteInfo = {deckNames, models, token};
+ return this.noteInfo;
+ });
+ }
+
+ logout() {
+ return AnkiWeb.loadPage('https://ankiweb.net/account/logout', null);
+ }
+
+ static scrape(username, password) {
+ return AnkiWeb.loadAccountPage('https://ankiweb.net/edit/', null, username, password).then(response => {
+ const modelsMatch = /editor\.models = (.*}]);/.exec(response);
+ if (modelsMatch === null) {
+ return Promise.reject('failed to scrape model data');
+ }
+
+ const decksMatch = /editor\.decks = (.*}});/.exec(response);
+ if (decksMatch === null) {
+ return Promise.reject('failed to scrape deck data');
+ }
+
+ const tokenMatch = /editor\.csrf_token = \'(.*)\';/.exec(response);
+ if (tokenMatch === null) {
+ return Promise.reject('failed to acquire csrf_token');
+ }
+
+ const modelsJson = JSON.parse(modelsMatch[1]);
+ const decksJson = JSON.parse(decksMatch[1]);
+ const token = tokenMatch[1];
+
+ const deckNames = Object.keys(decksJson).map(d => decksJson[d].name);
+ const models = [];
+ for (const modelJson of modelsJson) {
+ models.push({
+ name: modelJson.name,
+ id: modelJson.id,
+ fields: modelJson.flds.map(f => f.name)
+ });
+ }
+
+ return {deckNames, models, token};
+ });
+ }
+
+ static login(username, password, token) {
+ if (username.length === 0 || password.length === 0) {
+ return Promise.reject('login credentials not specified');
+ }
+
+ const data = {username, password, csrf_token: token, submitted: 1};
+ return AnkiWeb.loadPage('https://ankiweb.net/account/login', data).then(response => {
+ if (!response.includes('class="mitem"')) {
+ return Promise.reject('failed to authenticate');
+ }
+ });
+ }
+
+ static loadAccountPage(url, data, username, password) {
+ return AnkiWeb.loadPage(url, data).then(response => {
+ if (response.includes('name="password"')) {
+ const tokenMatch = /name="csrf_token" value="(.*)"/.exec(response);
+ if (tokenMatch === null) {
+ return Promise.reject('failed to acquire csrf_token');
+ }
+
+ return AnkiWeb.login(username, password, tokenMatch[1]).then(() => AnkiWeb.loadPage(url, data));
+ } else {
+ return response;
+ }
+ });
+ }
+
+ static loadPage(url, data) {
+ return new Promise((resolve, reject) => {
+ let dataEnc = null;
+ if (data) {
+ const params = [];
+ for (const key in data) {
+ params.push(`${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`);
+ }
+
+ dataEnc = params.join('&');
+ }
+
+ const xhr = new XMLHttpRequest();
+ xhr.addEventListener('error', () => reject('failed to execute network request'));
+ xhr.addEventListener('load', () => resolve(xhr.responseText));
+ if (dataEnc) {
+ xhr.open('POST', url);
+ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+ xhr.send(dataEnc);
+ } else {
+ xhr.open('GET', url);
+ xhr.send();
+ }
+ });
+ }
+}
diff --git a/ext/bg/js/options-form.js b/ext/bg/js/options-form.js
index 8216f158..8cffb2f7 100644
--- a/ext/bg/js/options-form.js
+++ b/ext/bg/js/options-form.js
@@ -30,8 +30,9 @@ function getFormValues() {
optsNew.activateOnStartup = $('#activate-on-startup').prop('checked');
optsNew.enableAudioPlayback = $('#enable-audio-playback').prop('checked');
- optsNew.showAdvancedOptions = $('#show-advanced-options').prop('checked');
optsNew.enableSoftKatakanaSearch = $('#enable-soft-katakana-search').prop('checked');
+ optsNew.groupTermResults = $('#group-term-results').prop('checked');
+ optsNew.showAdvancedOptions = $('#show-advanced-options').prop('checked');
optsNew.holdShiftToScan = $('#hold-shift-to-scan').prop('checked');
optsNew.selectMatchedText = $('#select-matched-text').prop('checked');
@@ -87,6 +88,7 @@ $(document).ready(() => {
$('#activate-on-startup').prop('checked', opts.activateOnStartup);
$('#enable-audio-playback').prop('checked', opts.enableAudioPlayback);
$('#enable-soft-katakana-search').prop('checked', opts.enableSoftKatakanaSearch);
+ $('#group-term-results').prop('checked', opts.groupTermResults);
$('#show-advanced-options').prop('checked', opts.showAdvancedOptions);
$('#hold-shift-to-scan').prop('checked', opts.holdShiftToScan);
@@ -313,6 +315,7 @@ function modelIdToMarkers(id) {
return {
'anki-term-model': [
'audio',
+ 'dictionary',
'expression',
'expression-furigana',
'glossary',
@@ -324,6 +327,7 @@ function modelIdToMarkers(id) {
],
'anki-kanji-model': [
'character',
+ 'dictionary',
'glossary',
'glossary-list',
'kunyomi',
@@ -338,7 +342,6 @@ function populateAnkiDeckAndModel(opts) {
showAnkiSpinner(true);
const ankiFormat = $('#anki-format').hide();
-
return Promise.all([anki().getDeckNames(), anki().getModelNames()]).then(([deckNames, modelNames]) => {
const ankiDeck = $('.anki-deck');
ankiDeck.find('option').remove();
diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js
index f1fe0dac..2f0bd189 100644
--- a/ext/bg/js/options.js
+++ b/ext/bg/js/options.js
@@ -17,11 +17,25 @@
*/
+function versionOptions(options) {
+ const version = options.version || 0;
+ const fixups = [
+ () => {}
+ ];
+
+ if (version < fixups.length) {
+ fixups[version]();
+ ++options.version;
+ versionOptions(options);
+ }
+}
+
function sanitizeOptions(options) {
const defaults = {
activateOnStartup: true,
enableAudioPlayback: true,
enableSoftKatakanaSearch: true,
+ groupTermResults: true,
showAdvancedOptions: false,
selectMatchedText: true,
holdShiftToScan: true,
diff --git a/ext/bg/js/templates.js b/ext/bg/js/templates.js
index f6ff8467..89719a24 100644
--- a/ext/bg/js/templates.js
+++ b/ext/bg/js/templates.js
@@ -31,112 +31,104 @@ templates['dictionary.html'] = template({"1":function(container,depth0,helpers,p
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.enableKanji : depth0),{"name":"if","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ "> Enable Kanji search</label>\n </div>\n</div>\n";
},"useData":true});
-templates['footer.html'] = template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
- var helper;
-
- return " <script src=\""
- + container.escapeExpression(((helper = (helper = helpers.root || (depth0 != null ? depth0.root : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},{"name":"root","hash":{},"data":data}) : helper)))
- + "/js/frame.js\"></script>\n </body>\n</html>\n";
-},"useData":true});
-templates['header.html'] = template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
- var helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
+templates['kanji-list.html'] = template({"1":function(container,depth0,helpers,partials,data) {
+ var stack1, helper, alias1=depth0 != null ? depth0 : {};
- return "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\">\n <title></title>\n <style>\n @font-face {\n font-family: kanji-stroke-orders;\n src: url('"
- + alias4(((helper = (helper = helpers.root || (depth0 != null ? depth0.root : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"root","hash":{},"data":data}) : helper)))
- + "/ttf/kanji-stroke-orders.ttf');\n }\n @font-face {\n font-family: vl-gothic-regular;\n src: url('"
- + alias4(((helper = (helper = helpers.root || (depth0 != null ? depth0.root : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"root","hash":{},"data":data}) : helper)))
- + "/ttf/vl-gothic-regular.ttf');\n }\n </style>\n <link rel=\"stylesheet\" href=\""
- + alias4(((helper = (helper = helpers.root || (depth0 != null ? depth0.root : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"root","hash":{},"data":data}) : helper)))
- + "/css/frame.css\">\n </head>\n <body>\n";
-},"useData":true});
-templates['kanji-link.html'] = template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
+ return "<div class=\"kanji-definition\">\n <div class=\"action-bar\">\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 : "")
+ + " </div>\n\n <div class=\"kanji-glyph\">"
+ + container.escapeExpression(((helper = (helper = helpers.character || (depth0 != null ? depth0.character : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(alias1,{"name":"character","hash":{},"data":data}) : helper)))
+ + "</div>\n\n <div class=\"kanji-reading\">\n <table>\n <tr>\n <th>Kunyomi:</th>\n <td>\n"
+ + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.kunyomi : depth0),{"name":"each","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + " </td>\n </tr>\n <tr>\n <th>Onyomi:</th>\n <td>\n"
+ + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.onyomi : depth0),{"name":"each","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + " </td>\n </tr>\n </table>\n </div>\n\n <div class=\"kanji-tags\">\n"
+ + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.tags : depth0),{"name":"each","hash":{},"fn":container.program(7, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + " </div>\n\n <div class=\"kanji-glossary\">\n"
+ + ((stack1 = helpers["if"].call(alias1,((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(9, data, 0),"inverse":container.program(13, data, 0),"data":data})) != null ? stack1 : "")
+ + " </div>\n</div>\n";
+},"2":function(container,depth0,helpers,partials,data) {
var helper;
- return "<a href=\"#\" class=\"kanji-link\">"
- + container.escapeExpression(((helper = (helper = helpers.kanji || (depth0 != null ? depth0.kanji : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},{"name":"kanji","hash":{},"data":data}) : helper)))
- + "</a>\n";
-},"useData":true});
-templates['kanji-list.html'] = template({"1":function(container,depth0,helpers,partials,data,blockParams,depths) {
- var stack1;
-
- return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(2, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
-},"2":function(container,depth0,helpers,partials,data,blockParams,depths) {
- var stack1;
-
- return ((stack1 = container.invokePartial(partials["kanji.html"],depth0,{"name":"kanji.html","hash":{"sequence":(depths[1] != null ? depths[1].sequence : depths[1]),"options":(depths[1] != null ? depths[1].options : depths[1]),"root":(depths[1] != null ? depths[1].root : depths[1]),"addable":(depths[1] != null ? depths[1].addable : depths[1])},"data":data,"indent":" ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
+ return " <a href=\"#\" title=\"Add Kanji\" class=\"action-add-note pending disabled\" data-mode=\"kanji\" data-index=\""
+ + container.escapeExpression(((helper = (helper = helpers.index || (data && data.index)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},{"name":"index","hash":{},"data":data}) : helper)))
+ + "\"><img src=\"img/add_kanji.png\"></a>\n";
},"4":function(container,depth0,helpers,partials,data) {
- return " <p>No results found</p>\n";
-},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
- var stack1;
-
- return ((stack1 = container.invokePartial(partials["header.html"],depth0,{"name":"header.html","data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
- + ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0, blockParams, depths),"inverse":container.program(4, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "")
- + ((stack1 = container.invokePartial(partials["footer.html"],depth0,{"name":"footer.html","data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
-},"usePartial":true,"useData":true,"useDepths":true});
-templates['kanji.html'] = template({"1":function(container,depth0,helpers,partials,data) {
- var helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
-
- return " <a href=\"#\" title=\"Add Kanji\" class=\"action-add-note disabled\" data-mode=\"kanji\" data-index=\""
- + alias4(((helper = (helper = helpers.index || (data && data.index)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"index","hash":{},"data":data}) : helper)))
- + "\"><img src=\""
- + alias4(((helper = (helper = helpers.root || (depth0 != null ? depth0.root : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"root","hash":{},"data":data}) : helper)))
- + "/img/add_kanji.png\"></a>\n";
-},"3":function(container,depth0,helpers,partials,data) {
var stack1;
- return " "
+ return " "
+ container.escapeExpression(container.lambda(depth0, depth0))
- + ((stack1 = helpers.unless.call(depth0 != null ? depth0 : {},(data && data.last),{"name":"unless","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + ((stack1 = helpers.unless.call(depth0 != null ? depth0 : {},(data && data.last),{"name":"unless","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ "\n";
-},"4":function(container,depth0,helpers,partials,data) {
+},"5":function(container,depth0,helpers,partials,data) {
return ", ";
-},"6":function(container,depth0,helpers,partials,data) {
+},"7":function(container,depth0,helpers,partials,data) {
var helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
- return " <span class=\"tag tag-"
+ return " <span class=\"tag tag-"
+ alias4(((helper = (helper = helpers.category || (depth0 != null ? depth0.category : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"category","hash":{},"data":data}) : helper)))
+ "\" title=\""
+ alias4(((helper = (helper = helpers.notes || (depth0 != null ? depth0.notes : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"notes","hash":{},"data":data}) : helper)))
+ "\">"
+ alias4(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"name","hash":{},"data":data}) : helper)))
+ "</span>\n";
-},"8":function(container,depth0,helpers,partials,data) {
+},"9":function(container,depth0,helpers,partials,data) {
var stack1;
- return " <ol>\n"
- + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(9, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
- + " </ol>\n";
-},"9":function(container,depth0,helpers,partials,data) {
- return " <li><span>"
- + container.escapeExpression(container.lambda(depth0, depth0))
- + "</span></li>\n";
+ return " <ol \"kanji-glossary-group\">\n"
+ + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + " </ol>\n";
+},"10":function(container,depth0,helpers,partials,data) {
+ var stack1, helper, options, buffer =
+ " <li><span class=\"kanji-glossary-item\">";
+ stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(11, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},options) : helper));
+ if (!helpers.multiLine) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
+ if (stack1 != null) { buffer += stack1; }
+ return buffer + "</span></li>\n";
},"11":function(container,depth0,helpers,partials,data) {
+ return container.escapeExpression(container.lambda(depth0, depth0));
+},"13":function(container,depth0,helpers,partials,data) {
+ var stack1, helper, options, buffer =
+ " <div class=\"kanji-glossary-group kanji-glossary-item\">";
+ stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(14, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},options) : helper));
+ if (!helpers.multiLine) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
+ if (stack1 != null) { buffer += stack1; }
+ return buffer + "</div>\n";
+},"14":function(container,depth0,helpers,partials,data) {
var stack1;
- return " <p>\n "
- + container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["0"] : stack1), depth0))
- + "\n </p>\n";
-},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
- var stack1, helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
+ return container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["0"] : stack1), depth0));
+},"16":function(container,depth0,helpers,partials,data,blockParams,depths) {
+ var stack1;
- return "<div class=\"kanji-definition\">\n <div class=\"action-bar\" data-sequence=\""
- + alias4(((helper = (helper = helpers.sequence || (depth0 != null ? depth0.sequence : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"sequence","hash":{},"data":data}) : helper)))
- + "\">\n"
- + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.addable : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
- + " </div>\n\n <div class=\"kanji-glyph\">"
- + alias4(((helper = (helper = helpers.character || (depth0 != null ? depth0.character : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"character","hash":{},"data":data}) : helper)))
- + "</div>\n\n <div class=\"kanji-reading\">\n <table>\n <tr>\n <th>Kunyomi:</th>\n <td>\n"
- + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.kunyomi : depth0),{"name":"each","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
- + " </td>\n </tr>\n <tr>\n <th>Onyomi:</th>\n <td>\n"
- + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.onyomi : depth0),{"name":"each","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
- + " </td>\n </tr>\n </table>\n </div>\n\n <div class=\"kanji-tags\">\n"
- + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.tags : depth0),{"name":"each","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
- + " </div>\n\n <div class=\"kanji-glossary\">\n"
- + ((stack1 = helpers["if"].call(alias1,((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(8, data, 0),"inverse":container.program(11, data, 0),"data":data})) != null ? stack1 : "")
- + " </div>\n</div>\n";
-},"useData":true});
+ return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(17, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
+},"17":function(container,depth0,helpers,partials,data,blockParams,depths) {
+ var stack1;
+
+ return " "
+ + ((stack1 = helpers.unless.call(depth0 != null ? depth0 : {},(data && data.first),{"name":"unless","hash":{},"fn":container.program(18, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + "\n"
+ + ((stack1 = container.invokePartial(partials.kanji,depth0,{"name":"kanji","hash":{"root":(depths[1] != null ? depths[1].root : depths[1]),"addable":(depths[1] != null ? depths[1].addable : depths[1])},"data":data,"indent":" ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
+},"18":function(container,depth0,helpers,partials,data) {
+ return "<hr>";
+},"20":function(container,depth0,helpers,partials,data) {
+ return " <p>No results found</p>\n";
+},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
+ var stack1;
+
+ return "\n"
+ + ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(16, data, 0, blockParams, depths),"inverse":container.program(20, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
+},"main_d": function(fn, props, container, depth0, data, blockParams, depths) {
+
+ var decorators = container.decorators;
+
+ fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(1, data, 0, blockParams, depths),"inverse":container.noop,"args":["kanji"],"data":data}) || fn;
+ return fn;
+ }
+
+,"useDecorators":true,"usePartial":true,"useData":true,"useDepths":true});
templates['model.html'] = template({"1":function(container,depth0,helpers,partials,data) {
- return " <li><a class=\"marker-link\" href=\"#\">"
+ return " <li><a class=\"marker-link\" href=\"#\">"
+ container.escapeExpression(container.lambda(depth0, depth0))
+ "</a></li>\n";
},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
@@ -152,115 +144,168 @@ templates['model.html'] = template({"1":function(container,depth0,helpers,partia
+ ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.markers : depth0),{"name":"each","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ " </ul>\n </div>\n </div>\n </td>\n</tr>\n";
},"useData":true});
-templates['term-list.html'] = template({"1":function(container,depth0,helpers,partials,data,blockParams,depths) {
+templates['term-list.html'] = template({"1":function(container,depth0,helpers,partials,data) {
+ var stack1, alias1=depth0 != null ? depth0 : {};
+
+ return ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.tags : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + ((stack1 = helpers["if"].call(alias1,((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(5, data, 0),"inverse":container.program(9, data, 0),"data":data})) != null ? stack1 : "");
+},"2":function(container,depth0,helpers,partials,data) {
var stack1;
- return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(2, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
-},"2":function(container,depth0,helpers,partials,data,blockParams,depths) {
+ return " <div class=\"term-tags\">\n"
+ + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.tags : depth0),{"name":"each","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + " </div>\n";
+},"3":function(container,depth0,helpers,partials,data) {
+ var helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
+
+ return " <span class=\"tag tag-"
+ + alias4(((helper = (helper = helpers.category || (depth0 != null ? depth0.category : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"category","hash":{},"data":data}) : helper)))
+ + "\" title=\""
+ + alias4(((helper = (helper = helpers.notes || (depth0 != null ? depth0.notes : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"notes","hash":{},"data":data}) : helper)))
+ + "\">"
+ + alias4(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"name","hash":{},"data":data}) : helper)))
+ + "</span>\n";
+},"5":function(container,depth0,helpers,partials,data) {
var stack1;
- return ((stack1 = container.invokePartial(partials["term.html"],depth0,{"name":"term.html","hash":{"sequence":(depths[1] != null ? depths[1].sequence : depths[1]),"options":(depths[1] != null ? depths[1].options : depths[1]),"root":(depths[1] != null ? depths[1].root : depths[1]),"addable":(depths[1] != null ? depths[1].addable : depths[1])},"data":data,"indent":" ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
-},"4":function(container,depth0,helpers,partials,data) {
- return " <p>No results found</p>\n";
-},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
+ return " <ul class=\"term-glossary-group\">\n"
+ + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + " </ul>\n";
+},"6":function(container,depth0,helpers,partials,data) {
+ var stack1, helper, options, buffer =
+ " <li><span class=\"term-glossary-item\">";
+ stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(7, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},options) : helper));
+ if (!helpers.multiLine) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
+ if (stack1 != null) { buffer += stack1; }
+ return buffer + "</span></li>\n";
+},"7":function(container,depth0,helpers,partials,data) {
+ return container.escapeExpression(container.lambda(depth0, depth0));
+},"9":function(container,depth0,helpers,partials,data) {
+ var stack1, helper, options, buffer =
+ " <div class=\"term-glossary-group term-glossary-item\">";
+ stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},options) : helper));
+ if (!helpers.multiLine) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
+ if (stack1 != null) { buffer += stack1; }
+ return buffer + "</div>\n";
+},"10":function(container,depth0,helpers,partials,data) {
var stack1;
- return ((stack1 = container.invokePartial(partials["header.html"],depth0,{"name":"header.html","data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
- + ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0, blockParams, depths),"inverse":container.program(4, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "")
- + ((stack1 = container.invokePartial(partials["footer.html"],depth0,{"name":"footer.html","data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
-},"usePartial":true,"useData":true,"useDepths":true});
-templates['term.html'] = template({"1":function(container,depth0,helpers,partials,data) {
- var helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
+ return container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["0"] : stack1), depth0));
+},"12":function(container,depth0,helpers,partials,data) {
+ var stack1, alias1=depth0 != null ? depth0 : {};
- return " <a href=\"#\" title=\"Play audio\" class=\"action-play-audio\" data-index=\""
- + alias4(((helper = (helper = helpers.index || (data && data.index)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"index","hash":{},"data":data}) : helper)))
- + "\"><img src=\""
- + alias4(((helper = (helper = helpers.root || (depth0 != null ? depth0.root : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"root","hash":{},"data":data}) : helper)))
- + "/img/play_audio.png\"></a>\n";
-},"3":function(container,depth0,helpers,partials,data) {
+ return "<div class=\"term-definition\">\n <div class=\"action-bar\">\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"
+ + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.reading : depth0),{"name":"if","hash":{},"fn":container.program(17, data, 0),"inverse":container.program(20, data, 0),"data":data})) != null ? stack1 : "")
+ + "\n"
+ + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.reasons : depth0),{"name":"if","hash":{},"fn":container.program(22, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + "\n <div class=\"term-glossary\">\n"
+ + ((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) {
var helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
- return " <a href=\"#\" title=\"Add term as expression\" class=\"action-add-note disabled\" data-mode=\"term_kanji\" data-index=\""
+ return " <a href=\"#\" title=\"Add term as expression\" class=\"action-add-note pending disabled\" data-mode=\"term_kanji\" data-index=\""
+ alias4(((helper = (helper = helpers.index || (data && data.index)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"index","hash":{},"data":data}) : helper)))
- + "\"><img src=\""
- + alias4(((helper = (helper = helpers.root || (depth0 != null ? depth0.root : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"root","hash":{},"data":data}) : helper)))
- + "/img/add_term_kanji.png\"></a>\n <a href=\"#\" title=\"Add term as reading\" class=\"action-add-note disabled\" data-mode=\"term_kana\" data-index=\""
+ + "\"><img src=\"img/add_term_kanji.png\"></a>\n <a href=\"#\" title=\"Add term as reading\" class=\"action-add-note pending disabled\" data-mode=\"term_kana\" data-index=\""
+ alias4(((helper = (helper = helpers.index || (data && data.index)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"index","hash":{},"data":data}) : helper)))
- + "\"><img src=\""
- + alias4(((helper = (helper = helpers.root || (depth0 != null ? depth0.root : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"root","hash":{},"data":data}) : helper)))
- + "/img/add_term_kana.png\"></a>\n";
-},"5":function(container,depth0,helpers,partials,data) {
+ + "\"><img src=\"img/add_term_kana.png\"></a>\n";
+},"15":function(container,depth0,helpers,partials,data) {
+ var helper;
+
+ return " <a href=\"#\" title=\"Play audio\" class=\"action-play-audio\" data-index=\""
+ + container.escapeExpression(((helper = (helper = helpers.index || (data && data.index)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},{"name":"index","hash":{},"data":data}) : helper)))
+ + "\"><img src=\"img/play_audio.png\"></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=\"term-expression\"><ruby>";
- stack1 = ((helper = (helper = helpers.kanjiLinks || (depth0 != null ? depth0.kanjiLinks : depth0)) != null ? helper : alias2),(options={"name":"kanjiLinks","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data}),(typeof helper === alias3 ? helper.call(alias1,options) : helper));
+ " <div class=\"term-expression\"><ruby>";
+ stack1 = ((helper = (helper = helpers.kanjiLinks || (depth0 != null ? depth0.kanjiLinks : depth0)) != null ? helper : alias2),(options={"name":"kanjiLinks","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data}),(typeof helper === alias3 ? helper.call(alias1,options) : helper));
if (!helpers.kanjiLinks) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
if (stack1 != null) { buffer += stack1; }
return buffer + "<rt>"
+ container.escapeExpression(((helper = (helper = helpers.reading || (depth0 != null ? depth0.reading : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"reading","hash":{},"data":data}) : helper)))
+ "</rt></ruby></div>\n";
-},"6":function(container,depth0,helpers,partials,data) {
+},"18":function(container,depth0,helpers,partials,data) {
var helper;
return container.escapeExpression(((helper = (helper = helpers.expression || (depth0 != null ? depth0.expression : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},{"name":"expression","hash":{},"data":data}) : helper)));
-},"8":function(container,depth0,helpers,partials,data) {
+},"20":function(container,depth0,helpers,partials,data) {
var stack1, helper, options, buffer =
- " <div class=\"term-expression\">";
- stack1 = ((helper = (helper = helpers.kanjiLinks || (depth0 != null ? depth0.kanjiLinks : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"kanjiLinks","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},options) : helper));
+ " <div class=\"term-expression\">";
+ stack1 = ((helper = (helper = helpers.kanjiLinks || (depth0 != null ? depth0.kanjiLinks : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"kanjiLinks","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},options) : helper));
if (!helpers.kanjiLinks) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
if (stack1 != null) { buffer += stack1; }
return buffer + "</div>\n";
-},"10":function(container,depth0,helpers,partials,data) {
+},"22":function(container,depth0,helpers,partials,data) {
+ var stack1;
+
+ return " <div class=\"term-reasons\">\n"
+ + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.reasons : depth0),{"name":"each","hash":{},"fn":container.program(23, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + " </div>\n";
+},"23":function(container,depth0,helpers,partials,data) {
var stack1;
- return " <span class=\"reasons\">"
+ return " <span class=\"reasons\">"
+ container.escapeExpression(container.lambda(depth0, depth0))
+ "</span> "
- + ((stack1 = helpers.unless.call(depth0 != null ? depth0 : {},(data && data.last),{"name":"unless","hash":{},"fn":container.program(11, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + ((stack1 = helpers.unless.call(depth0 != null ? depth0 : {},(data && data.last),{"name":"unless","hash":{},"fn":container.program(24, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ "\n";
-},"11":function(container,depth0,helpers,partials,data) {
+},"24":function(container,depth0,helpers,partials,data) {
return "&laquo;";
-},"13":function(container,depth0,helpers,partials,data) {
- var helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
+},"26":function(container,depth0,helpers,partials,data) {
+ var stack1;
- return " <span class=\"tag tag-"
- + alias4(((helper = (helper = helpers.category || (depth0 != null ? depth0.category : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"category","hash":{},"data":data}) : helper)))
- + "\" title=\""
- + alias4(((helper = (helper = helpers.notes || (depth0 != null ? depth0.notes : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"notes","hash":{},"data":data}) : helper)))
- + "\">"
- + alias4(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"name","hash":{},"data":data}) : helper)))
- + "</span>\n";
-},"15":function(container,depth0,helpers,partials,data) {
+ return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definitions : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(27, data, 0),"inverse":container.program(30, data, 0),"data":data})) != null ? stack1 : "");
+},"27":function(container,depth0,helpers,partials,data) {
var stack1;
return " <ol>\n"
- + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(16, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(28, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ " </ol>\n";
-},"16":function(container,depth0,helpers,partials,data) {
- return " <li><span>"
- + container.escapeExpression(container.lambda(depth0, depth0))
- + "</span></li>\n";
-},"18":function(container,depth0,helpers,partials,data) {
+},"28":function(container,depth0,helpers,partials,data) {
var stack1;
- return " <p>"
- + container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["0"] : stack1), depth0))
- + "</p>\n";
-},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
- var stack1, helper, alias1=depth0 != null ? depth0 : {};
+ return " <li>"
+ + ((stack1 = container.invokePartial(partials.definition,depth0,{"name":"definition","data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
+ + "</li>\n";
+},"30":function(container,depth0,helpers,partials,data) {
+ var stack1;
- return "<div class=\"term-definition\">\n <div class=\"action-bar\" data-sequence=\""
- + container.escapeExpression(((helper = (helper = helpers.sequence || (depth0 != null ? depth0.sequence : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(alias1,{"name":"sequence","hash":{},"data":data}) : helper)))
- + "\">\n"
- + ((stack1 = helpers["if"].call(alias1,((stack1 = (depth0 != null ? depth0.options : depth0)) != null ? stack1.enableAudioPlayback : stack1),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
- + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.addable : depth0),{"name":"if","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
- + " </div>\n\n"
- + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.reading : depth0),{"name":"if","hash":{},"fn":container.program(5, data, 0),"inverse":container.program(8, data, 0),"data":data})) != null ? stack1 : "")
- + "\n <div class=\"term-reasons\">\n"
- + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.reasons : depth0),{"name":"each","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
- + " </div>\n\n <div class=\"term-tags\">\n"
- + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.tags : depth0),{"name":"each","hash":{},"fn":container.program(13, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
- + " </div>\n\n <div class=\"term-glossary\">\n"
- + ((stack1 = helpers["if"].call(alias1,((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(15, data, 0),"inverse":container.program(18, data, 0),"data":data})) != null ? stack1 : "")
- + " </div>\n</div>\n";
-},"useData":true});
+ return ((stack1 = container.invokePartial(partials.definition,((stack1 = (depth0 != null ? depth0.definitions : depth0)) != null ? stack1["0"] : stack1),{"name":"definition","data":data,"indent":" ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
+},"32":function(container,depth0,helpers,partials,data) {
+ var stack1;
+
+ return ((stack1 = container.invokePartial(partials.definition,depth0,{"name":"definition","data":data,"indent":" ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
+},"34":function(container,depth0,helpers,partials,data,blockParams,depths) {
+ var stack1;
+
+ return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(35, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
+},"35":function(container,depth0,helpers,partials,data,blockParams,depths) {
+ var stack1;
+
+ return " "
+ + ((stack1 = helpers.unless.call(depth0 != null ? depth0 : {},(data && data.first),{"name":"unless","hash":{},"fn":container.program(36, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + "\n"
+ + ((stack1 = container.invokePartial(partials.term,depth0,{"name":"term","hash":{"playback":(depths[1] != null ? depths[1].playback : depths[1]),"addable":(depths[1] != null ? depths[1].addable : depths[1]),"grouped":(depths[1] != null ? depths[1].grouped : depths[1])},"data":data,"indent":" ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
+},"36":function(container,depth0,helpers,partials,data) {
+ return "<hr>";
+},"38":function(container,depth0,helpers,partials,data) {
+ return " <p>No results found</p>\n";
+},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
+ var stack1;
+
+ return "\n\n"
+ + ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(34, data, 0, blockParams, depths),"inverse":container.program(38, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
+},"main_d": function(fn, props, container, depth0, data, blockParams, depths) {
+
+ var decorators = container.decorators;
+
+ fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(1, data, 0, blockParams, depths),"inverse":container.noop,"args":["definition"],"data":data}) || fn;
+ fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(12, data, 0, blockParams, depths),"inverse":container.noop,"args":["term"],"data":data}) || fn;
+ return fn;
+ }
+
+,"useDecorators":true,"usePartial":true,"useData":true,"useDepths":true});
})(); \ No newline at end of file
diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js
index 2b6b87c1..8710f568 100644
--- a/ext/bg/js/translator.js
+++ b/ext/bg/js/translator.js
@@ -54,6 +54,8 @@ class Translator {
let definitions = [];
for (const deinflection of deinflections) {
for (const definition of deinflection.definitions) {
+ const tags = definition.tags.map(tag => buildTag(tag, definition.tagMeta));
+ tags.push(buildDictTag(definition.dictionary));
definitions.push({
source: deinflection.source,
reasons: deinflection.reasons,
@@ -63,7 +65,7 @@ class Translator {
expression: definition.expression,
reading: definition.reading,
glossary: definition.glossary,
- tags: sortTags(definition.tags.map(tag => buildTag(tag, definition.tagMeta)))
+ tags: sortTags(tags)
});
}
}
@@ -80,6 +82,12 @@ class Translator {
});
}
+ findTermGrouped(text, dictionaries, enableSoftKatakanaSearch) {
+ return this.findTerm(text, dictionaries, enableSoftKatakanaSearch).then(({length, definitions}) => {
+ return {length, definitions: groupTermDefs(definitions)};
+ });
+ }
+
findKanji(text, dictionaries) {
const processed = {}, promises = [];
for (const c of text) {
@@ -89,7 +97,16 @@ class Translator {
}
}
- return Promise.all(promises).then(sets => this.processKanji(sets.reduce((a, b) => a.concat(b), [])));
+ return Promise.all(promises).then(defSets => {
+ const definitions = defSets.reduce((a, b) => a.concat(b), []);
+ for (const definition of definitions) {
+ const tags = definition.tags.map(tag => buildTag(tag, definition.tagMeta));
+ tags.push(buildDictTag(definition.dictionary));
+ definition.tags = sortTags(tags);
+ }
+
+ return definitions;
+ });
}
findTermDeinflections(text, dictionaries, cache) {
diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js
index 059f3160..504deeda 100644
--- a/ext/bg/js/util.js
+++ b/ext/bg/js/util.js
@@ -21,7 +21,7 @@ function kanjiLinks(options) {
let result = '';
for (const c of options.fn(this)) {
if (isKanji(c)) {
- result += Handlebars.templates['kanji-link.html']({kanji: c}).trim();
+ result += `<a href="#" class="kanji-link">${c}</a>`;
} else {
result += c;
}
@@ -30,6 +30,10 @@ function kanjiLinks(options) {
return result;
}
+function multiLine(options) {
+ return options.fn(this).split('\n').join('<br>');
+}
+
function isKanji(c) {
const code = c.charCodeAt(0);
return code >= 0x4e00 && code < 0x9fb0 || code >= 0x3400 && code < 0x4dc0;
@@ -44,28 +48,6 @@ function promiseCallback(promise, callback) {
});
}
-function sortTags(tags) {
- return tags.sort((v1, v2) => {
- const order1 = v1.order;
- const order2 = v2.order;
- if (order1 < order2) {
- return -1;
- } else if (order1 > order2) {
- return 1;
- }
-
- const name1 = v1.name;
- const name2 = v2.name;
- if (name1 < name2) {
- return -1;
- } else if (name1 > name2) {
- return 1;
- }
-
- return 0;
- });
-}
-
function sortTermDefs(definitions) {
return definitions.sort((v1, v2) => {
const sl1 = v1.source.length;
@@ -113,6 +95,43 @@ function undupeTermDefs(definitions) {
return definitionsUnique;
}
+function groupTermDefs(definitions) {
+ const groups = {};
+ for (const definition of definitions) {
+ const key = [definition.source, definition.expression].concat(definition.reasons);
+ if (definition.reading) {
+ key.push(definition.reading);
+ }
+
+ const group = groups[key];
+ if (group) {
+ group.push(definition);
+ } else {
+ groups[key] = [definition];
+ }
+ }
+
+ const results = [];
+ for (const key in groups) {
+ const groupDefs = groups[key];
+ const firstDef = groupDefs[0];
+ results.push({
+ definitions: groupDefs,
+ expression: firstDef.expression,
+ reading: firstDef.reading,
+ reasons: firstDef.reasons,
+ score: groupDefs.reduce((x, y) => x > y ? x : y, Number.MIN_SAFE_INTEGER),
+ source: firstDef.source,
+ });
+ }
+
+ return sortTermDefs(results);
+}
+
+function buildDictTag(name) {
+ return sanitizeTag({name, category: 'dictionary', order: 100});
+}
+
function buildTag(name, meta) {
const tag = {name};
const symbol = name.split(':')[0];
@@ -135,6 +154,95 @@ function splitField(field) {
return field.length === 0 ? [] : field.split(' ');
}
+function sortTags(tags) {
+ return tags.sort((v1, v2) => {
+ const order1 = v1.order;
+ const order2 = v2.order;
+ if (order1 < order2) {
+ return -1;
+ } else if (order1 > order2) {
+ return 1;
+ }
+
+ const name1 = v1.name;
+ const name2 = v2.name;
+ if (name1 < name2) {
+ return -1;
+ } else if (name1 > name2) {
+ return 1;
+ }
+
+ return 0;
+ });
+}
+
+function formatField(field, definition, mode) {
+ const markers = [
+ 'audio',
+ 'character',
+ 'dictionary',
+ 'expression',
+ 'expression-furigana',
+ 'glossary',
+ 'glossary-list',
+ 'kunyomi',
+ 'onyomi',
+ 'reading',
+ 'sentence',
+ 'tags',
+ 'url',
+ ];
+
+ for (const marker of markers) {
+ let value = definition[marker] || null;
+ switch (marker) {
+ case 'expression':
+ if (mode === 'term_kana' && definition.reading) {
+ value = definition.reading;
+ }
+ break;
+ case 'expression-furigana':
+ if (mode === 'term_kana' && definition.reading) {
+ value = definition.reading;
+ } else {
+ value = `<ruby>${definition.expression}<rt>${definition.reading}</rt></ruby>`;
+ }
+ break;
+ case 'reading':
+ if (mode === 'term_kana') {
+ value = null;
+ }
+ break;
+ case 'glossary-list':
+ if (definition.glossary) {
+ if (definition.glossary.length > 1) {
+ value = '<ol style="white-space: pre; text-align: left; overflow-x: auto;">';
+ for (const gloss of definition.glossary) {
+ value += `<li>${gloss}</li>`;
+ }
+ value += '</ol>';
+ } else {
+ value = `<p style="white-space: pre; overflow-x: auto;">${definition.glossary.join('')}</p>`;
+ }
+ }
+ break;
+ case 'tags':
+ if (definition.tags) {
+ value = definition.tags.map(t => t.name);
+ }
+ break;
+ }
+
+ if (value !== null && typeof(value) !== 'string') {
+ value = value.join(', ');
+ }
+
+ field = field.replace(`{${marker}}`, value || '');
+ }
+
+ return field;
+}
+
function loadJson(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js
index 12dd89ac..2cdcf1c8 100644
--- a/ext/bg/js/yomichan.js
+++ b/ext/bg/js/yomichan.js
@@ -21,6 +21,7 @@ class Yomichan {
constructor() {
Handlebars.partials = Handlebars.templates;
Handlebars.registerHelper('kanjiLinks', kanjiLinks);
+ Handlebars.registerHelper('multiLine', multiLine);
this.translator = new Translator();
this.anki = new AnkiNull();
@@ -117,75 +118,6 @@ class Yomichan {
chrome.tabs.sendMessage(tabId, {action, params}, () => null);
}
- formatField(field, definition, mode) {
- const markers = [
- 'audio',
- 'character',
- 'expression',
- 'expression-furigana',
- 'glossary',
- 'glossary-list',
- 'kunyomi',
- 'onyomi',
- 'reading',
- 'sentence',
- 'tags',
- 'url',
- ];
-
- for (const marker of markers) {
- let value = definition[marker] || null;
- switch (marker) {
- case 'audio':
- value = '';
- break;
- case 'expression':
- if (mode === 'term_kana' && definition.reading) {
- value = definition.reading;
- }
- break;
- case 'expression-furigana':
- if (mode === 'term_kana' && definition.reading) {
- value = definition.reading;
- } else {
- value = `<ruby>${definition.expression}<rt>${definition.reading}</rt></ruby>`;
- }
- break;
- case 'reading':
- if (mode === 'term_kana') {
- value = null;
- }
- break;
- case 'glossary-list':
- if (definition.glossary) {
- if (definition.glossary.length > 1) {
- value = '<ol style="white-space: pre; text-align: left; overflow-x: auto;">';
- for (const gloss of definition.glossary) {
- value += `<li>${gloss}</li>`;
- }
- value += '</ol>';
- } else {
- value = `<p style="white-space: pre; overflow-x: auto;">${definition.glossary.join('')}</p>`;
- }
- }
- break;
- case 'tags':
- if (definition.tags) {
- value = definition.tags.map(t => t.name);
- }
- break;
- }
-
- if (value !== null && typeof(value) !== 'string') {
- value = value.join(', ');
- }
-
- field = field.replace(`{${marker}}`, value || '');
- }
-
- return field;
- }
-
formatNote(definition, mode) {
const note = {fields: {}, tags: this.options.ankiCardTags};
@@ -217,7 +149,7 @@ class Yomichan {
}
for (const name in fields) {
- note.fields[name] = this.formatField(fields[name], definition, mode);
+ note.fields[name] = formatField(fields[name], definition, mode);
}
return note;
@@ -254,7 +186,29 @@ class Yomichan {
}
promiseCallback(
- this.translator.findTerm(text, dictionaries, this.options.enableSoftKatakanaSearch),
+ this.translator.findTerm(
+ text,
+ dictionaries,
+ this.options.enableSoftKatakanaSearch
+ ),
+ callback
+ );
+ }
+
+ api_findTermGrouped({text, callback}) {
+ const dictionaries = [];
+ for (const title in this.options.dictionaries) {
+ if (this.options.dictionaries[title].enableTerms) {
+ dictionaries.push(title);
+ }
+ }
+
+ promiseCallback(
+ this.translator.findTermGrouped(
+ text,
+ dictionaries,
+ this.options.enableSoftKatakanaSearch
+ ),
callback
);
}
diff --git a/ext/bg/options.html b/ext/bg/options.html
index 0ef65abb..6bf6fb7b 100644
--- a/ext/bg/options.html
+++ b/ext/bg/options.html
@@ -38,6 +38,10 @@
</div>
<div class="checkbox">
+ <label><input type="checkbox" id="group-term-results"> Group term results</label>
+ </div>
+
+ <div class="checkbox">
<label><input type="checkbox" id="show-advanced-options"> Show advanced options</label>
</div>
</div>