Merge branch 'dev' into firefox

This commit is contained in:
Alex Yatskov 2017-02-26 11:05:41 -08:00
commit 32f95e59a9
43 changed files with 10244 additions and 424 deletions

View File

@ -32,13 +32,11 @@ support and feedback encourages continued development of this tool.
## Basic Functionality ##
1. Left-click on the ![](https://foosoft.net/projects/yomichan-chrome/img/logo.png) icon to enable or disable Yomichan for the current browser instance.
2. Right-click on the ![](https://foosoft.net/projects/yomichan-chrome/img/logo.png) icon and select <em>Options</em> to open the Yomichan options page.
3. Import any dictionaries (bundled or custom) you wish to use for Kanji and term searches; none are imported by default.
4. Hold down <kbd>Shift</kbd> (or the middle mouse button) as you hover over text to see term definitions.
5. Resize the definitions window by dragging the bottom-left corner inwards or outwards to make it smaller or larger.
6. Click on Kanji in the definition window to view additional information about that character.
7. Click on the ![](https://foosoft.net/projects/yomichan-chrome/img/play-audio.png) icon to hear the term pronounced by a native speaker.
1. Click on the ![](https://foosoft.net/projects/yomichan-chrome/img/logo.png) icon in the browser toolbar to open the Yomichan options page.
2. Import the dictionaries (bundled or custom) you wish to use for term and Kanji searches.
3. Hold down <kbd>Shift</kbd> (or the middle mouse button) as you hover over text to see term definitions.
4. Click on the ![](https://foosoft.net/projects/yomichan-chrome/img/play-audio.png) icon to hear the term pronounced by a native speaker (if audio is available).
5. Click on Kanji in the definition window to view additional information about that character.
## Custom Dictionaries ##

View File

@ -3,8 +3,8 @@
<head>
<meta charset="UTF-8">
<title>Welcome to Yomichan!</title>
<link rel="stylesheet" type="text/css" href="../lib/bootstrap-3.3.6-dist/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../lib/bootstrap-3.3.6-dist/css/bootstrap-theme.min.css">
<link rel="stylesheet" type="text/css" href="../lib/bootstrap-3.3.7-dist/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../lib/bootstrap-3.3.7-dist/css/bootstrap-theme.min.css">
</head>
<body>
<div class="container">
@ -23,11 +23,10 @@
</p>
<ol>
<li>Left-click on the <img src="../img/icon16.png" alt> icon to enable or disable Yomichan for the current browser instance.</li>
<li>Right-click on the <img src="../img/icon16.png" alt> icon and select <em>Options</em> to open the Yomichan options page.</li>
<li>Import any dictionaries (bundled or custom) you wish to use for Kanji and term searches; none are imported by default.</li>
<li>Click on the <img src="../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>Resize the definitions window by dragging the bottom-left corner inwards or outwards to make it smaller or larger.</li>
<li>Click on the <img src="../fg/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>
</ol>
</div>

View File

@ -17,9 +17,10 @@
*/
class AnkiConnect {
constructor() {
constructor(server) {
this.server = server;
this.asyncPools = {};
this.localVersion = 1;
this.localVersion = 2;
this.remoteVersion = null;
}
@ -50,8 +51,8 @@ class AnkiConnect {
return this.ankiInvoke('version', {}, null).then(version => {
this.remoteVersion = version;
if (this.remoteVersion !== this.localVersion) {
return Promise.reject('extension and plugin version mismatch');
if (this.remoteVersion < this.localVersion) {
return Promise.reject('extension and plugin versions incompatible');
}
});
}
@ -75,7 +76,7 @@ class AnkiConnect {
}
});
xhr.open('POST', 'http://127.0.0.1:8765');
xhr.open('POST', this.server);
xhr.send(JSON.stringify({action, params}));
});
}

View File

@ -45,7 +45,7 @@ class Database {
terms: '++id,dictionary,expression,reading',
kanji: '++,dictionary,character',
tagMeta: '++,dictionary',
dictionaries: '++,title,version',
dictionaries: '++,title,version'
});
return this.db.open();
@ -155,82 +155,6 @@ class Database {
return this.db.dictionaries.toArray();
}
deleteDictionary(title, callback) {
if (this.db === null) {
return Promise.reject('database not initialized');
}
return this.db.dictionaries.where('title').equals(title).first(info => {
if (!info) {
return;
}
let termCounter = Promise.resolve(0);
if (info.hasTerms) {
termCounter = this.db.terms.where('dictionary').equals(title).count();
}
let kanjiCounter = Promise.resolve(0);
if (info.hasKanji) {
kanjiCounter = this.db.kanji.where('dictionary').equals(title).count();
}
return Promise.all([termCounter, kanjiCounter]).then(([termCount, kanjiCount]) => {
const rowLimit = 500;
const totalCount = termCount + kanjiCount;
let deletedCount = 0;
let termDeleter = Promise.resolve();
if (info.hasTerms) {
const termDeleterFunc = () => {
return this.db.terms.where('dictionary').equals(title).limit(rowLimit).delete().then(count => {
if (count === 0) {
return Promise.resolve();
}
deletedCount += count;
if (callback) {
callback(totalCount, deletedCount);
}
return termDeleterFunc();
});
};
termDeleter = termDeleterFunc();
}
let kanjiDeleter = Promise.resolve();
if (info.hasKanji) {
const kanjiDeleterFunc = () => {
return this.db.kanji.where('dictionary').equals(title).limit(rowLimit).delete().then(count => {
if (count === 0) {
return Promise.resolve();
}
deletedCount += count;
if (callback) {
callback(totalCount, deletedCount);
}
return kanjiDeleterFunc();
});
};
kanjiDeleter = kanjiDeleterFunc();
}
return Promise.all([termDeleter, kanjiDeleter]);
});
}).then(() => {
return this.db.tagMeta.where('dictionary').equals(title).delete();
}).then(() => {
return this.db.dictionaries.where('title').equals(title).delete();
}).then(() => {
delete this.cacheTagMeta[title];
});
}
importDictionary(indexUrl, callback) {
if (this.db === null) {
return Promise.reject('database not initialized');

View File

@ -28,7 +28,7 @@ function getFormData() {
return optionsLoad().then(optionsOld => {
const optionsNew = $.extend(true, {}, optionsOld);
optionsNew.general.autoStart = $('#activate-on-startup').prop('checked');
optionsNew.general.enable = $('#enable-search').prop('checked');
optionsNew.general.audioPlayback = $('#audio-playback-buttons').prop('checked');
optionsNew.general.groupResults = $('#group-terms-results').prop('checked');
optionsNew.general.softKatakana = $('#soft-katakana-search').prop('checked');
@ -37,6 +37,7 @@ function getFormData() {
optionsNew.scanning.requireShift = $('#hold-shift-to-scan').prop('checked');
optionsNew.scanning.selectText = $('#select-matched-text').prop('checked');
optionsNew.scanning.imposter = $('#search-form-text-fields').prop('checked');
optionsNew.scanning.delay = parseInt($('#scan-delay').val(), 10);
optionsNew.scanning.length = parseInt($('#scan-length').val(), 10);
@ -44,6 +45,7 @@ function getFormData() {
optionsNew.anki.tags = $('#card-tags').val().split(/[,; ]+/);
optionsNew.anki.htmlCards = $('#generate-html-cards').prop('checked');
optionsNew.anki.sentenceExt = parseInt($('#sentence-detection-extent').val(), 10);
optionsNew.anki.server = $('#interface-server').val();
if (optionsOld.anki.enable) {
optionsNew.anki.terms.deck = $('#anki-terms-deck').val();
optionsNew.anki.terms.model = $('#anki-terms-model').val();
@ -85,7 +87,7 @@ $(document).ready(() => {
Handlebars.partials = Handlebars.templates;
optionsLoad().then(options => {
$('#activate-on-startup').prop('checked', options.general.autoStart);
$('#enable-search').prop('checked', options.general.enable);
$('#audio-playback-buttons').prop('checked', options.general.audioPlayback);
$('#group-terms-results').prop('checked', options.general.groupResults);
$('#soft-katakana-search').prop('checked', options.general.softKatakana);
@ -94,6 +96,7 @@ $(document).ready(() => {
$('#hold-shift-to-scan').prop('checked', options.scanning.requireShift);
$('#select-matched-text').prop('checked', options.scanning.selectText);
$('#search-form-text-fields').prop('checked', options.scanning.imposter);
$('#scan-delay').val(options.scanning.delay);
$('#scan-length').val(options.scanning.length);
@ -106,6 +109,7 @@ $(document).ready(() => {
$('#card-tags').val(options.anki.tags.join(' '));
$('#generate-html-cards').prop('checked', options.anki.htmlCards);
$('#sentence-detection-extent').val(options.anki.sentenceExt);
$('#interface-server').val(options.anki.server);
$('input, select').not('.anki-model').change(onOptionsChanged);
$('.anki-model').change(onAnkiModelChanged);
@ -164,11 +168,10 @@ function populateDictionaries(options) {
++dictCount;
});
updateVisibility(options);
$('.dict-enabled, .dict-priority').change(onOptionsChanged);
$('.dict-delete').click(onDictionaryDelete);
}).catch(error => {
showDictionaryError(error);
}).then(() => {
}).catch(showDictionaryError).then(() => {
showDictionarySpinner(false);
if (dictCount === 0) {
dictWarning.show();
@ -185,36 +188,17 @@ function onDictionaryPurge(e) {
const dictControls = $('#dict-importer, #dict-groups').hide();
const dictProgress = $('#dict-purge-progress').show();
return database().purge().catch(error => {
showDictionaryError(error);
}).then(() => {
return database().purge().catch(showDictionaryError).then(() => {
showDictionarySpinner(false);
dictControls.show();
dictProgress.hide();
return optionsLoad().then(options => populateDictionaries(options));
return optionsLoad();
}).then(options => {
options.dictionaries = {};
return optionsSave(options).then(() => {
populateDictionaries(options);
yomichan().setOptions(options);
});
}
function onDictionaryDelete() {
showDictionaryError(null);
showDictionarySpinner(true);
const dictGroup = $(this).closest('.dict-group');
const dictProgress = dictGroup.find('.dict-delete-progress').show();
const dictControls = dictGroup.find('.dict-group-controls').hide();
const setProgress = percent => {
dictProgress.find('.progress-bar').css('width', `${percent}%`);
};
setProgress(0.0);
database().deleteDictionary(dictGroup.data('title'), (total, current) => setProgress(current / total * 100.0)).catch(error => {
showDictionaryError(error);
}).then(() => {
showDictionarySpinner(false);
dictProgress.hide();
dictControls.show();
return optionsLoad().then(options => populateDictionaries(options));
});
}
@ -225,9 +209,7 @@ function onDictionaryImport() {
const dictUrl = $('#dict-url');
const dictImporter = $('#dict-importer').hide();
const dictProgress = $('#dict-import-progress').show();
const setProgress = percent => {
dictProgress.find('.progress-bar').css('width', `${percent}%`);
};
const setProgress = percent => dictProgress.find('.progress-bar').css('width', `${percent}%`);
setProgress(0.0);
@ -235,11 +217,7 @@ function onDictionaryImport() {
database().importDictionary(dictUrl.val(), (total, current) => setProgress(current / total * 100.0)).then(summary => {
options.dictionaries[summary.title] = {enabled: true, priority: 0};
return optionsSave(options).then(() => yomichan().setOptions(options));
}).then(() => {
return populateDictionaries(options);
}).catch(error => {
showDictionaryError(error);
}).then(() => {
}).then(() => populateDictionaries(options)).catch(showDictionaryError).then(() => {
showDictionarySpinner(false);
dictProgress.hide();
dictImporter.show();
@ -324,13 +302,7 @@ function populateAnkiDeckAndModel(options) {
populateAnkiFields($('#anki-terms-model').val(options.anki.terms.model), options),
populateAnkiFields($('#anki-kanji-model').val(options.anki.kanji.model), options)
]);
}).then(() => {
ankiFormat.show();
}).catch(error => {
showAnkiError(error);
}).then(() => {
showAnkiSpinner(false);
});
}).then(() => ankiFormat.show()).catch(showAnkiError).then(() => showAnkiSpinner(false));
}
function populateAnkiFields(element, options) {
@ -345,7 +317,7 @@ function populateAnkiFields(element, options) {
const markers = {
'terms': ['audio', 'dictionary', 'expression', 'furigana', 'glossary', 'reading', 'sentence', 'tags', 'url'],
'kanji': ['character', 'dictionary', 'glossary', 'kunyomi', 'onyomi', 'url']
'kanji': ['character', 'dictionary', 'glossary', 'kunyomi', 'onyomi', 'sentence', 'tags', 'url']
}[tabId] || {};
return anki().getModelFieldNames(modelName).then(names => {
@ -380,11 +352,7 @@ function onAnkiModelChanged(e) {
optionsNew.anki[tabId].fields = {};
populateAnkiFields(element, optionsNew).then(() => {
optionsSave(optionsNew).then(() => yomichan().setOptions(optionsNew));
}).catch(error => {
showAnkiError(error);
}).then(() => {
showAnkiSpinner(false);
});
}).catch(showAnkiError).then(() => showAnkiSpinner(false));
});
}
@ -397,15 +365,16 @@ function onOptionsChanged(e) {
return optionsSave(optionsNew).then(() => {
yomichan().setOptions(optionsNew);
updateVisibility(optionsNew);
if (optionsNew.anki.enable !== optionsOld.anki.enable) {
const ankiUpdated =
optionsNew.anki.enable !== optionsOld.anki.enable ||
optionsNew.anki.server !== optionsOld.anki.server;
if (ankiUpdated) {
showAnkiError(null);
showAnkiSpinner(true);
return populateAnkiDeckAndModel(optionsNew);
}
});
}).catch(error => {
showAnkiError(error);
}).then(() => {
showAnkiSpinner(false);
});
}).catch(showAnkiError).then(() => showAnkiSpinner(false));
}

View File

@ -20,7 +20,7 @@
function optionsSetDefaults(options) {
const defaults = {
general: {
autoStart: true,
enable: true,
audioPlayback: true,
groupResults: true,
softKatakana: true,
@ -31,6 +31,7 @@ function optionsSetDefaults(options) {
scanning: {
requireShift: true,
selectText: true,
imposter: true,
delay: 15,
length: 10
},
@ -39,6 +40,7 @@ function optionsSetDefaults(options) {
anki: {
enable: false,
server: 'http://127.0.0.1:8765',
tags: ['yomichan'],
htmlCards: true,
sentenceExt: 200,
@ -48,8 +50,8 @@ function optionsSetDefaults(options) {
};
const combine = (target, source) => {
for (let key in source) {
if (!(key in target)) {
for (const key in source) {
if (!target.hasOwnProperty(key)) {
target[key] = source[key];
}
}
@ -67,15 +69,12 @@ function optionsSetDefaults(options) {
function optionsVersion(options) {
const fixups = [
() => {
const copy = (targetDict, targetKey, sourceDict, sourceKey) => {
targetDict[targetKey] = sourceDict.hasOwnProperty(sourceKey) ? sourceDict[sourceKey] : targetDict[targetKey];
};
options.version = options.version || 0;
const fixups = [
() => {
optionsSetDefaults(options);
copy(options.general, 'autoStart', options, 'activateOnStartup');
copy(options.general, 'audioPlayback', options, 'enableAudioPlayback');
copy(options.general, 'softKatakana', options, 'enableSoftKatakanaSearch');
@ -98,23 +97,7 @@ function optionsVersion(options) {
copy(options.anki.kanji, 'model', options, 'ankiKanjiModel');
copy(options.anki.kanji, 'fields', options, 'ankiKanjiFields');
const fixupFields = fields => {
const fixups = {
'{expression-furigana}': '{furigana}',
'{glossary-list}': '{glossary}'
};
for (let name in fields) {
for (let fixup in fixups) {
fields[name] = fields[name].replace(fixup, fixups[fixup]);
}
}
};
fixupFields(options.anki.terms.fields);
fixupFields(options.anki.kanji.fields);
for (let title in options.dictionaries) {
for (const title in options.dictionaries) {
const dictionary = options.dictionaries[title];
dictionary.enabled = dictionary.enableTerms || dictionary.enableKanji;
dictionary.priority = 0;
@ -127,8 +110,8 @@ function optionsVersion(options) {
'{glossary-list}': '{glossary}'
};
for (let name in fields) {
for (let fixup in fixups) {
for (const name in fields) {
for (const fixup in fixups) {
fields[name] = fields[name].replace(fixup, fixups[fixup]);
}
}
@ -139,10 +122,13 @@ function optionsVersion(options) {
}
];
if (options.version < fixups.length) {
fixups[options.version]();
++options.version;
optionsVersion(options);
optionsSetDefaults(options);
if (!options.hasOwnProperty('version')) {
options.version = fixups.length;
}
while (options.version < fixups.length) {
fixups[options.version++]();
}
return options;

View File

@ -11,13 +11,9 @@ templates['dictionary.html'] = template({"1":function(container,depth0,helpers,p
+ alias4(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"title","hash":{},"data":data}) : helper)))
+ " <small>rev."
+ alias4(((helper = (helper = helpers.revision || (depth0 != null ? depth0.revision : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"revision","hash":{},"data":data}) : helper)))
+ "</small></h4>\n\n <!-- <div class=\"row\"> -->\n <!-- <div class=\"col-xs-8\"> -->\n <!-- <h4><span class=\"text-muted glyphicon glyphicon-book\"></span> "
+ alias4(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"title","hash":{},"data":data}) : helper)))
+ " <small>v."
+ alias4(((helper = (helper = helpers.version || (depth0 != null ? depth0.version : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"version","hash":{},"data":data}) : helper)))
+ "</small></h4> -->\n <!-- </div> -->\n <!-- <div class=\"col-xs-4 text-right disabled\"> -->\n <!-- <button type=\"button\" class=\"dict-group-controls dict-delete btn btn-danger\">Delete</button> -->\n <!-- </div> -->\n <!-- </div> -->\n\n <div class=\"dict-delete-progress\">\n Dictionary data is being deleted, please be patient...\n <div class=\"progress\">\n <div class=\"progress-bar progress-bar-striped progress-bar-danger\" style=\"width: 0%\"></div>\n </div>\n </div>\n\n <div class=\"checkbox dict-group-controls\">\n <label><input type=\"checkbox\" class=\"dict-enabled\" "
+ "</small></h4>\n\n <div class=\"checkbox\">\n <label><input type=\"checkbox\" class=\"dict-enabled\" "
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.enabled : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ "> Enable search</label>\n </div>\n <div class=\"form-group dict-group-controls options-advanced\">\n <label for=\"dict-"
+ "> Enable search</label>\n </div>\n <div class=\"form-group options-advanced\">\n <label for=\"dict-"
+ alias4(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"title","hash":{},"data":data}) : helper)))
+ "\">Result priority</label>\n <input type=\"number\" value=\""
+ alias4(((helper = (helper = helpers.priority || (depth0 != null ? depth0.priority : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"priority","hash":{},"data":data}) : helper)))
@ -150,74 +146,104 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti
var stack1, alias1=depth0 != null ? depth0 : {};
return ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(40, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.group : depth0),{"name":"if","hash":{},"fn":container.program(42, data, 0, blockParams, depths),"inverse":container.program(52, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "")
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(54, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.modeKanji : depth0),{"name":"if","hash":{},"fn":container.program(42, data, 0, blockParams, depths),"inverse":container.program(51, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "")
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(64, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
},"40":function(container,depth0,helpers,partials,data) {
return "<div style=\"text-align: left;\">";
},"42":function(container,depth0,helpers,partials,data,blockParams,depths) {
},"42":function(container,depth0,helpers,partials,data) {
var stack1;
return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(43, data, 0, blockParams, depths),"inverse":container.program(50, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
},"43":function(container,depth0,helpers,partials,data,blockParams,depths) {
return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(43, data, 0),"inverse":container.program(49, data, 0),"data":data})) != null ? stack1 : "");
},"43":function(container,depth0,helpers,partials,data) {
var stack1;
return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(44, data, 0, blockParams, depths),"inverse":container.program(47, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
},"44":function(container,depth0,helpers,partials,data,blockParams,depths) {
return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(44, data, 0),"inverse":container.program(47, data, 0),"data":data})) != null ? stack1 : "");
},"44":function(container,depth0,helpers,partials,data) {
var stack1;
return "<ol>"
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1),{"name":"each","hash":{},"fn":container.program(45, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1),{"name":"each","hash":{},"fn":container.program(45, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ "</ol>";
},"45":function(container,depth0,helpers,partials,data,blockParams,depths) {
},"45":function(container,depth0,helpers,partials,data) {
return "<li>"
+ container.escapeExpression(container.lambda(depth0, depth0))
+ "</li>";
},"47":function(container,depth0,helpers,partials,data) {
var stack1;
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1),{"name":"each","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
},"49":function(container,depth0,helpers,partials,data) {
var stack1;
return container.escapeExpression(container.lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1)) != null ? stack1["0"] : stack1), depth0));
},"51":function(container,depth0,helpers,partials,data,blockParams,depths) {
var stack1;
return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.group : depth0),{"name":"if","hash":{},"fn":container.program(52, data, 0, blockParams, depths),"inverse":container.program(62, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
},"52":function(container,depth0,helpers,partials,data,blockParams,depths) {
var stack1;
return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(53, data, 0, blockParams, depths),"inverse":container.program(60, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
},"53":function(container,depth0,helpers,partials,data,blockParams,depths) {
var stack1;
return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(54, data, 0, blockParams, depths),"inverse":container.program(57, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
},"54":function(container,depth0,helpers,partials,data,blockParams,depths) {
var stack1;
return "<ol>"
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1),{"name":"each","hash":{},"fn":container.program(55, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ "</ol>";
},"55":function(container,depth0,helpers,partials,data,blockParams,depths) {
var stack1;
return "<li>"
+ ((stack1 = container.invokePartial(partials["glossary-single"],depth0,{"name":"glossary-single","hash":{"html":(depths[1] != null ? depths[1].html : depths[1])},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
+ "</li>";
},"47":function(container,depth0,helpers,partials,data,blockParams,depths) {
},"57":function(container,depth0,helpers,partials,data,blockParams,depths) {
var stack1;
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1),{"name":"each","hash":{},"fn":container.program(48, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
},"48":function(container,depth0,helpers,partials,data,blockParams,depths) {
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1),{"name":"each","hash":{},"fn":container.program(58, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
},"58":function(container,depth0,helpers,partials,data,blockParams,depths) {
var stack1;
return " * "
+ ((stack1 = container.invokePartial(partials["glossary-single"],depth0,{"name":"glossary-single","hash":{"html":(depths[1] != null ? depths[1].html : depths[1])},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
},"50":function(container,depth0,helpers,partials,data) {
var stack1;
return ((stack1 = container.invokePartial(partials["glossary-single"],((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1)) != null ? stack1["0"] : stack1),{"name":"glossary-single","hash":{"html":(depth0 != null ? depth0.html : depth0)},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
},"52":function(container,depth0,helpers,partials,data) {
var stack1;
return ((stack1 = container.invokePartial(partials["glossary-single"],(depth0 != null ? depth0.definition : depth0),{"name":"glossary-single","hash":{"html":(depth0 != null ? depth0.html : depth0)},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
},"54":function(container,depth0,helpers,partials,data) {
return "</div>";
},"56":function(container,depth0,helpers,partials,data) {
var stack1;
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.kunyomi : stack1),{"name":"each","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
},"58":function(container,depth0,helpers,partials,data) {
var stack1;
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.onyomi : stack1),{"name":"each","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
},"60":function(container,depth0,helpers,partials,data) {
var stack1;
return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.modeTermKana : depth0),{"name":"unless","hash":{},"fn":container.program(28, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
return ((stack1 = container.invokePartial(partials["glossary-single"],((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1)) != null ? stack1["0"] : stack1),{"name":"glossary-single","hash":{"html":(depth0 != null ? depth0.html : depth0)},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
},"62":function(container,depth0,helpers,partials,data) {
var stack1;
return container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.sentence : stack1), depth0));
return ((stack1 = container.invokePartial(partials["glossary-single"],(depth0 != null ? depth0.definition : depth0),{"name":"glossary-single","hash":{"html":(depth0 != null ? depth0.html : depth0)},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
},"64":function(container,depth0,helpers,partials,data) {
var stack1;
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.tags : stack1),{"name":"each","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
return "</div>";
},"66":function(container,depth0,helpers,partials,data) {
var stack1;
return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(67, data, 0),"inverse":container.program(69, data, 0),"data":data})) != null ? stack1 : "");
},"67":function(container,depth0,helpers,partials,data) {
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.kunyomi : stack1),{"name":"each","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
},"68":function(container,depth0,helpers,partials,data) {
var stack1;
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.onyomi : stack1),{"name":"each","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
},"70":function(container,depth0,helpers,partials,data) {
var stack1;
return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.modeTermKana : depth0),{"name":"unless","hash":{},"fn":container.program(28, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
},"72":function(container,depth0,helpers,partials,data) {
var stack1;
return container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.sentence : stack1), depth0));
},"74":function(container,depth0,helpers,partials,data) {
var stack1;
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.tags : stack1),{"name":"each","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
},"76":function(container,depth0,helpers,partials,data) {
var stack1;
return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(77, data, 0),"inverse":container.program(79, data, 0),"data":data})) != null ? stack1 : "");
},"77":function(container,depth0,helpers,partials,data) {
var stack1, alias1=container.lambda, alias2=container.escapeExpression;
return "<a href=\""
@ -225,7 +251,7 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti
+ "\">"
+ alias2(alias1(((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.url : stack1), depth0))
+ "</a>";
},"69":function(container,depth0,helpers,partials,data) {
},"79":function(container,depth0,helpers,partials,data) {
var stack1;
return container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.url : stack1), depth0));
@ -245,12 +271,12 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(26, data, 0, blockParams, depths),"inverse":container.noop,"args":["expression"],"data":data}) || fn;
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(32, data, 0, blockParams, depths),"inverse":container.noop,"args":["furigana"],"data":data}) || fn;
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(39, data, 0, blockParams, depths),"inverse":container.noop,"args":["glossary"],"data":data}) || fn;
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(56, data, 0, blockParams, depths),"inverse":container.noop,"args":["kunyomi"],"data":data}) || fn;
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(58, data, 0, blockParams, depths),"inverse":container.noop,"args":["onyomi"],"data":data}) || fn;
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(60, data, 0, blockParams, depths),"inverse":container.noop,"args":["reading"],"data":data}) || fn;
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(62, data, 0, blockParams, depths),"inverse":container.noop,"args":["sentence"],"data":data}) || fn;
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(64, data, 0, blockParams, depths),"inverse":container.noop,"args":["tags"],"data":data}) || fn;
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(66, data, 0, blockParams, depths),"inverse":container.noop,"args":["url"],"data":data}) || fn;
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(66, data, 0, blockParams, depths),"inverse":container.noop,"args":["kunyomi"],"data":data}) || fn;
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(68, data, 0, blockParams, depths),"inverse":container.noop,"args":["onyomi"],"data":data}) || fn;
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(70, data, 0, blockParams, depths),"inverse":container.noop,"args":["reading"],"data":data}) || fn;
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(72, data, 0, blockParams, depths),"inverse":container.noop,"args":["sentence"],"data":data}) || fn;
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(74, data, 0, blockParams, depths),"inverse":container.noop,"args":["tags"],"data":data}) || fn;
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(76, data, 0, blockParams, depths),"inverse":container.noop,"args":["url"],"data":data}) || fn;
return fn;
}

View File

@ -26,18 +26,12 @@ class Yomichan {
this.translator = new Translator();
this.anki = new AnkiNull();
this.options = null;
this.setEnabled(false);
chrome.runtime.onMessage.addListener(this.onMessage.bind(this));
chrome.browserAction.onClicked.addListener(this.onBrowserAction.bind(this));
chrome.runtime.onInstalled.addListener(this.onInstalled.bind(this));
chrome.browserAction.onClicked.addListener(e => chrome.runtime.openOptionsPage());
this.translator.prepare().then(optionsLoad).then(options => {
this.setOptions(options);
if (this.options.general.autoStart) {
this.setEnabled(true);
}
});
this.translator.prepare().then(optionsLoad).then(this.setOptions.bind(this));
}
onInstalled(details) {
@ -57,21 +51,28 @@ class Yomichan {
return true;
}
onBrowserAction() {
this.setEnabled(!this.enabled);
}
setEnabled(enabled) {
this.enabled = enabled;
this.tabInvokeAll('setEnabled', this.enabled);
chrome.browserAction.setBadgeText({text: enabled ? '' : 'off'});
}
// setEnabled(enabled) {
// this.enabled = enabled;
// this.tabInvokeAll('setEnabled', this.enabled);
// chrome.browserAction.setBadgeText({text: enabled ? '' : 'off'});
// }
setOptions(options) {
this.options = options;
let usable = false;
for (const title in options.dictionaries) {
if (options.dictionaries[title].enabled) {
usable = true;
break;
}
}
chrome.browserAction.setBadgeBackgroundColor({color: '#f0ad4e'});
chrome.browserAction.setBadgeText({text: usable ? '' : '!'});
if (options.anki.enable) {
this.anki = new AnkiConnect();
this.anki = new AnkiConnect(this.options.anki.server);
} else {
this.anki = new AnkiNull();
}
@ -81,7 +82,7 @@ class Yomichan {
tabInvokeAll(action, params) {
chrome.tabs.query({}, tabs => {
for (let tab of tabs) {
for (const tab of tabs) {
chrome.tabs.sendMessage(tab.id, {action, params}, () => null);
}
});
@ -100,13 +101,15 @@ class Yomichan {
note.deckName = this.options.anki.terms.deck;
note.modelName = this.options.anki.terms.model;
if (definition.audio) {
const audio = {
kanji: definition.expression,
kana: definition.reading,
url: definition.audio.url,
filename: definition.audio.filename,
skipHash: '7e2c2f954ef6051373ba916f000168dc',
fields: []
};
for (let name in fields) {
for (const name in fields) {
if (fields[name].includes('{audio}')) {
audio.fields.push(name);
}
@ -116,8 +119,9 @@ class Yomichan {
note.audio = audio;
}
}
}
for (let name in fields) {
for (const name in fields) {
note.fields[name] = formatField(
fields[name],
definition,
@ -129,10 +133,6 @@ class Yomichan {
return note;
}
api_getEnabled({callback}) {
callback({result: this.enabled});
}
api_getOptions({callback}) {
promiseCallback(optionsLoad(), callback);
}
@ -175,8 +175,8 @@ class Yomichan {
api_canAddDefinitions({definitions, modes, callback}) {
const notes = [];
for (let definition of definitions) {
for (let mode of modes) {
for (const definition of definitions) {
for (const mode of modes) {
notes.push(this.formatNote(definition, mode));
}
}

View File

@ -3,8 +3,8 @@
<head>
<meta charset="UTF-8">
<title>Yomichan Legal</title>
<link rel="stylesheet" type="text/css" href="../lib/bootstrap-3.3.6-dist/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../lib/bootstrap-3.3.6-dist/css/bootstrap-theme.min.css">
<link rel="stylesheet" type="text/css" href="../lib/bootstrap-3.3.7-dist/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../lib/bootstrap-3.3.7-dist/css/bootstrap-theme.min.css">
</head>
<body>
<div class="container">

View File

@ -3,11 +3,11 @@
<head>
<meta charset="UTF-8">
<title>Yomichan Options</title>
<link rel="stylesheet" type="text/css" href="../lib/bootstrap-3.3.6-dist/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../lib/bootstrap-3.3.6-dist/css/bootstrap-theme.min.css">
<link rel="stylesheet" type="text/css" href="../lib/bootstrap-3.3.7-dist/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../lib/bootstrap-3.3.7-dist/css/bootstrap-theme.min.css">
<style>
#anki-spinner, #anki-general, #anki-error,
#dict-spinner, #dict-error, #dict-warning, #dict-purge-progress, #dict-import-progress, .dict-delete-progress,
#dict-spinner, #dict-error, #dict-warning, #dict-purge-progress, #dict-import-progress,
.options-advanced {
display: none;
}
@ -26,7 +26,7 @@
<h3>General Options</h3>
<div class="checkbox">
<label><input type="checkbox" id="activate-on-startup"> Activate on startup</label>
<label><input type="checkbox" id="enable-search"> Enable search</label>
</div>
<div class="checkbox">
@ -62,6 +62,10 @@
<label><input type="checkbox" id="select-matched-text"> Select matched text</label>
</div>
<div class="checkbox">
<label><input type="checkbox" id="search-form-text-fields"> Search form text fields</label>
</div>
<div class="form-group options-advanced">
<label for="scan-delay">Scan delay</label>
<input type="number" min="1" id="scan-delay" class="form-control">
@ -111,9 +115,9 @@
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a href="#" data-url="edict">JMdict</a></li>
<li><a href="#" data-url="enamdict">JMnedict</a></li>
<li><a href="#" data-url="kanjidic">KANJIDIC2</a></li>
<li><a href="#" data-url="edict">JMdict <span class="text-muted">(terms)</span></a></li>
<li><a href="#" data-url="enamdict">JMnedict <span class="text-muted">(names)</span></a></li>
<li><a href="#" data-url="kanjidic">KANJIDIC2 <span class="text-muted">(characters)</span></a></li>
<li role="separator" class="divider"></li>
<li><a href="#" data-url="http://localhost:9876/index.json">Local dictionary</a></li>
</ul>
@ -161,6 +165,11 @@
<input type="number" min="1" id="sentence-detection-extent" class="form-control">
</div>
<div class="form-group options-advanced">
<label for="interface-server">Interface server</label>
<input type="text" id="interface-server" class="form-control">
</div>
<div id="anki-format">
<ul class="nav nav-tabs">
<li class="active"><a href="#terms" data-toggle="tab">Terms</a></li>
@ -228,8 +237,8 @@
</div>
</div>
<script src="../lib/jquery-2.2.2.min.js"></script>
<script src="../lib/bootstrap-3.3.6-dist/js/bootstrap.min.js"></script>
<script src="../lib/jquery-3.1.1.min.js"></script>
<script src="../lib/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
<script src="../lib/handlebars.min.js"></script>
<script src="js/templates.js"></script>
<script src="js/gecko.js"></script>

View File

@ -119,6 +119,10 @@ hr {
height: 1px;
}
#orphan {
display: none;
}
/* term styles */
.term-expression {

View File

@ -10,10 +10,14 @@
<img src="img/spinner.gif">
</div>
<div class="content"></div>
<div id="content"></div>
<div id="orphan">
<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="../lib/jquery-2.2.2.min.js"></script>
<script src="js/gecko.js"></script>
<script src="../lib/jquery-3.1.1.min.js"></script>
<script src="../lib/wanakana.min.js"></script>
<script src="js/util.js"></script>
<script src="js/frame.js"></script>
</body>

View File

@ -24,21 +24,16 @@ class Driver {
this.lastMousePos = null;
this.lastTextSource = null;
this.pendingLookup = false;
this.enabled = false;
this.options = null;
chrome.runtime.onMessage.addListener(this.onBgMessage.bind(this));
getOptions().then(options => {
this.options = options;
window.addEventListener('mouseover', this.onMouseOver.bind(this));
window.addEventListener('mousedown', this.onMouseDown.bind(this));
window.addEventListener('mousemove', this.onMouseMove.bind(this));
window.addEventListener('resize', e => this.searchClear());
getOptions().then(options => {
this.options = options;
return isEnabled();
}).then(enabled => {
this.enabled = enabled;
});
chrome.runtime.onMessage.addListener(this.onBgMessage.bind(this));
}).catch(this.handleError.bind(this));
}
popupTimerSet(callback) {
@ -63,7 +58,7 @@ class Driver {
this.lastMousePos = {x: e.clientX, y: e.clientY};
this.popupTimerClear();
if (!this.enabled) {
if (!this.options.general.enable) {
return;
}
@ -75,7 +70,7 @@ class Driver {
return;
}
const searcher = () => this.searchAt(this.lastMousePos, false);
const searcher = () => this.searchAt(this.lastMousePos);
if (!this.popup.isVisible() || e.shiftKey || e.which === 2 /* mmb */) {
searcher();
} else {
@ -98,17 +93,13 @@ class Driver {
callback();
}
searchAt(point, hideNotFound) {
searchAt(point) {
if (this.pendingLookup) {
return;
}
const textSource = textSourceFromPoint(point);
const textSource = textSourceFromPoint(point, this.options.scanning.imposter);
if (textSource === null || !textSource.containsPoint(point)) {
if (hideNotFound) {
this.searchClear();
}
return;
}
@ -119,14 +110,10 @@ class Driver {
this.pendingLookup = true;
this.searchTerms(textSource).then(found => {
if (!found) {
this.searchKanji(textSource).then(found => {
if (!found && hideNotFound) {
this.searchClear();
}
});
return this.searchKanji(textSource);
}
}).catch(error => {
window.alert('Error: ' + error);
this.handleError(error, textSource);
}).then(() => {
this.pendingLookup = false;
});
@ -143,13 +130,11 @@ class Driver {
textSource.setEndOffset(length);
const sentence = extractSentence(textSource, this.options.anki.sentenceExt);
definitions.forEach(definition => {
definition.url = window.location.href;
definition.sentence = sentence;
});
const url = window.location.href;
this.popup.showNextTo(textSource.getRect());
this.popup.showTermDefs(definitions, this.options);
this.popup.showTermDefs(definitions, this.options, {sentence, url});
this.lastTextSource = textSource;
if (this.options.scanning.selectText) {
textSource.select();
@ -157,9 +142,6 @@ class Driver {
return true;
}
}).catch(error => {
window.alert('Error: ' + error);
return false;
});
}
@ -170,10 +152,12 @@ class Driver {
if (definitions.length === 0) {
return false;
} else {
definitions.forEach(definition => definition.url = window.location.href);
const sentence = extractSentence(textSource, this.options.anki.sentenceExt);
const url = window.location.href;
this.popup.showNextTo(textSource.getRect());
this.popup.showKanjiDefs(definitions, this.options);
this.popup.showKanjiDefs(definitions, this.options, {sentence, url});
this.lastTextSource = textSource;
if (this.options.scanning.selectText) {
textSource.select();
@ -181,13 +165,11 @@ class Driver {
return true;
}
}).catch(error => {
window.alert('Error: ' + error);
return false;
});
}
searchClear() {
destroyImposters();
this.popup.hide();
if (this.options.scanning.selectText && this.lastTextSource !== null) {
@ -197,14 +179,19 @@ class Driver {
this.lastTextSource = null;
}
api_setOptions(options) {
this.options = options;
handleError(error, textSource) {
if (window.orphaned) {
if (textSource) {
this.popup.showNextTo(textSource.getRect());
this.popup.showOrphaned();
}
} else {
showError(error);
}
}
api_setEnabled(enabled) {
if (!(this.enabled = enabled)) {
this.searchClear();
}
api_setOptions(options) {
this.options = options;
}
}

View File

@ -30,26 +30,32 @@ class Frame {
});
}
api_showTermDefs({definitions, options}) {
api_showTermDefs({definitions, options, context}) {
const sequence = ++this.sequence;
const context = {
const params = {
definitions,
grouped: options.general.groupResults,
addable: options.ankiMethod !== 'disabled',
playback: options.general.audioPlayback
};
definitions.forEach(definition => {
definition.sentence = context.sentence;
definition.url = context.url;
});
this.definitions = definitions;
this.showSpinner(false);
window.scrollTo(0, 0);
renderText(context, 'terms.html').then(content => {
$('.content').html(content);
renderText(params, 'terms.html').then(content => {
$('#content').html(content);
$('.action-add-note').click(this.onAddNote.bind(this));
$('.kanji-link').click(e => {
e.preventDefault();
findKanji($(e.target).text()).then(kdefs => this.api_showKanjiDefs({options, definitions: kdefs}));
const character = $(e.target).text();
findKanji(character).then(definitions => this.api_showKanjiDefs({definitions, options, context}));
});
$('.action-play-audio').click(e => {
@ -59,28 +65,42 @@ class Frame {
});
this.updateAddNoteButtons(['term_kanji', 'term_kana'], sequence);
}).catch(error => {
this.handleError(error);
});
}
api_showKanjiDefs({definitions, options}) {
api_showKanjiDefs({definitions, options, context}) {
const sequence = ++this.sequence;
const context = {
const params = {
definitions,
addable: options.ankiMethod !== 'disabled'
};
definitions.forEach(definition => {
definition.sentence = context.sentence;
definition.url = context.url;
});
this.definitions = definitions;
this.showSpinner(false);
window.scrollTo(0, 0);
renderText(context, 'kanji.html').then(content => {
$('.content').html(content);
renderText(params, 'kanji.html').then(content => {
$('#content').html(content);
$('.action-add-note').click(this.onAddNote.bind(this));
this.updateAddNoteButtons(['kanji'], sequence);
}).catch(error => {
this.handleError(error);
});
}
api_showOrphaned() {
$('#content').hide();
$('#orphan').show();
}
findAddNoteButton(index, mode) {
return $(`.action-add-note[data-index="${index}"][data-mode="${mode}"]`);
}
@ -93,15 +113,24 @@ class Frame {
const index = link.data('index');
const mode = link.data('mode');
addDefinition(this.definitions[index], mode).then(success => {
const definition = this.definitions[index];
if (mode !== 'kanji') {
const url = buildAudioUrl(definition);
const filename = buildAudioFilename(definition);
if (url && filename) {
definition.audio = {url, filename};
}
}
addDefinition(definition, mode).then(success => {
if (success) {
const button = this.findAddNoteButton(index, mode);
button.addClass('disabled');
} else {
window.alert('Note could not be added');
showError('note could not be added');
}
}).catch(error => {
window.alert('Error: ' + error);
this.handleError(error);
}).then(() => {
this.showSpinner(false);
});
@ -118,7 +147,7 @@ class Frame {
}
states.forEach((state, index) => {
for (let mode in state) {
for (const mode in state) {
const button = this.findAddNoteButton(index, mode);
if (state[mode]) {
button.removeClass('disabled');
@ -129,6 +158,8 @@ class Frame {
button.removeClass('pending');
}
});
}).catch(error => {
this.handleError(error);
});
}
@ -142,18 +173,41 @@ class Frame {
}
playAudio(definition) {
let url = `https://assets.languagepod101.com/dictionary/japanese/audiomp3.php?kanji=${encodeURIComponent(definition.expression)}`;
if (definition.reading) {
url += `&kana=${encodeURIComponent(definition.reading)}`;
for (const key in this.audioCache) {
const audio = this.audioCache[key];
if (audio !== null) {
audio.pause();
}
}
for (let key in this.audioCache) {
this.audioCache[key].pause();
const url = buildAudioUrl(definition);
if (!url) {
return;
}
const audio = this.audioCache[url] || new Audio(url);
let audio = this.audioCache[url];
if (audio) {
audio.currentTime = 0;
audio.play();
} else {
audio = new Audio(url);
audio.onloadeddata = () => {
if (audio.duration === 5.694694) {
audio = new Audio('mp3/button.mp3');
}
this.audioCache[url] = audio;
audio.play();
};
}
}
handleError(error) {
if (window.orphaned) {
this.api_showOrphaned();
} else {
showError(error);
}
}
}

View File

@ -68,15 +68,19 @@ class Popup {
return this.container.style.visibility !== 'hidden';
}
showTermDefs(definitions, options) {
this.invokeApi('showTermDefs', {definitions, options});
showTermDefs(definitions, options, context) {
this.invokeApi('showTermDefs', {definitions, options, context});
}
showKanjiDefs(definitions, options) {
this.invokeApi('showKanjiDefs', {definitions, options});
showKanjiDefs(definitions, options, context) {
this.invokeApi('showKanjiDefs', {definitions, options, context});
}
invokeApi(action, params) {
showOrphaned() {
this.invokeApi('showOrphaned');
}
invokeApi(action, params={}) {
this.container.contentWindow.postMessage({action, params}, '*');
}
}

View File

@ -19,6 +19,7 @@
function invokeBgApi(action, params) {
return new Promise((resolve, reject) => {
try {
chrome.runtime.sendMessage({action, params}, ({result, error}) => {
if (error) {
reject(error);
@ -26,11 +27,15 @@ function invokeBgApi(action, params) {
resolve(result);
}
});
} catch (e) {
window.orphaned = true;
reject(e.message);
}
});
}
function isEnabled() {
return invokeBgApi('getEnabled', {});
function showError(error) {
window.alert(`Error: ${error}`);
}
function getOptions() {
@ -61,12 +66,36 @@ function addDefinition(definition, mode) {
return invokeBgApi('addDefinition', {definition, mode});
}
function textSourceFromPoint(point) {
function createImposter(element) {
const imposter = document.createElement('div');
const elementRect = element.getBoundingClientRect();
imposter.className = 'yomichan-imposter';
imposter.innerText = element.value;
imposter.style.cssText = window.getComputedStyle(element).cssText;
imposter.style.position = 'absolute';
imposter.style.top = elementRect.top + 'px';
imposter.style.left = elementRect.left + 'px';
imposter.style.zIndex = 2147483646;
document.body.appendChild(imposter);
imposter.scrollTop = element.scrollTop;
imposter.scrollLeft = element.scrollLeft;
}
function destroyImposters() {
for (const element of document.getElementsByClassName('yomichan-imposter')) {
element.parentNode.removeChild(element);
}
}
function textSourceFromPoint(point, imposter) {
const element = document.elementFromPoint(point.x, point.y);
if (element !== null) {
const names = ['IMG', 'INPUT', 'BUTTON', 'TEXTAREA'];
if (names.includes(element.nodeName)) {
if (element.nodeName === 'IMG' || element.nodeName === 'BUTTON') {
return new TextSourceElement(element);
} else if (imposter && (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA')) {
createImposter(element);
}
}
@ -75,6 +104,7 @@ function textSourceFromPoint(point) {
return new TextSourceRange(range);
}
destroyImposters();
return null;
}
@ -132,3 +162,43 @@ function extractSentence(source, extent) {
return content.substring(startPos, endPos).trim();
}
function buildAudioUrl(definition) {
let kana = definition.reading;
let kanji = definition.expression;
if (!kana && !kanji) {
return null;
}
if (!kana && wanakana.isHiragana(kanji)) {
kana = kanji;
kanji = null;
}
const params = [];
if (kanji) {
params.push(`kanji=${encodeURIComponent(kanji)}`);
}
if (kana) {
params.push(`kana=${encodeURIComponent(kana)}`);
}
return `https://assets.languagepod101.com/dictionary/japanese/audiomp3.php?${params.join('&')}`;
}
function buildAudioFilename(definition) {
if (!definition.reading && !definition.expression) {
return null;
}
let filename = 'yomichan';
if (definition.reading) {
filename += `_${definition.reading}`;
}
if (definition.expression) {
filename += `_${definition.expression}`;
}
return filename += '.mp3';
}

BIN
ext/fg/mp3/button.mp3 Normal file

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,587 @@
/*!
* Bootstrap v3.3.7 (http://getbootstrap.com)
* Copyright 2011-2016 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
.btn-default,
.btn-primary,
.btn-success,
.btn-info,
.btn-warning,
.btn-danger {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
}
.btn-default:active,
.btn-primary:active,
.btn-success:active,
.btn-info:active,
.btn-warning:active,
.btn-danger:active,
.btn-default.active,
.btn-primary.active,
.btn-success.active,
.btn-info.active,
.btn-warning.active,
.btn-danger.active {
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
}
.btn-default.disabled,
.btn-primary.disabled,
.btn-success.disabled,
.btn-info.disabled,
.btn-warning.disabled,
.btn-danger.disabled,
.btn-default[disabled],
.btn-primary[disabled],
.btn-success[disabled],
.btn-info[disabled],
.btn-warning[disabled],
.btn-danger[disabled],
fieldset[disabled] .btn-default,
fieldset[disabled] .btn-primary,
fieldset[disabled] .btn-success,
fieldset[disabled] .btn-info,
fieldset[disabled] .btn-warning,
fieldset[disabled] .btn-danger {
-webkit-box-shadow: none;
box-shadow: none;
}
.btn-default .badge,
.btn-primary .badge,
.btn-success .badge,
.btn-info .badge,
.btn-warning .badge,
.btn-danger .badge {
text-shadow: none;
}
.btn:active,
.btn.active {
background-image: none;
}
.btn-default {
text-shadow: 0 1px 0 #fff;
background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #dbdbdb;
border-color: #ccc;
}
.btn-default:hover,
.btn-default:focus {
background-color: #e0e0e0;
background-position: 0 -15px;
}
.btn-default:active,
.btn-default.active {
background-color: #e0e0e0;
border-color: #dbdbdb;
}
.btn-default.disabled,
.btn-default[disabled],
fieldset[disabled] .btn-default,
.btn-default.disabled:hover,
.btn-default[disabled]:hover,
fieldset[disabled] .btn-default:hover,
.btn-default.disabled:focus,
.btn-default[disabled]:focus,
fieldset[disabled] .btn-default:focus,
.btn-default.disabled.focus,
.btn-default[disabled].focus,
fieldset[disabled] .btn-default.focus,
.btn-default.disabled:active,
.btn-default[disabled]:active,
fieldset[disabled] .btn-default:active,
.btn-default.disabled.active,
.btn-default[disabled].active,
fieldset[disabled] .btn-default.active {
background-color: #e0e0e0;
background-image: none;
}
.btn-primary {
background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));
background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #245580;
}
.btn-primary:hover,
.btn-primary:focus {
background-color: #265a88;
background-position: 0 -15px;
}
.btn-primary:active,
.btn-primary.active {
background-color: #265a88;
border-color: #245580;
}
.btn-primary.disabled,
.btn-primary[disabled],
fieldset[disabled] .btn-primary,
.btn-primary.disabled:hover,
.btn-primary[disabled]:hover,
fieldset[disabled] .btn-primary:hover,
.btn-primary.disabled:focus,
.btn-primary[disabled]:focus,
fieldset[disabled] .btn-primary:focus,
.btn-primary.disabled.focus,
.btn-primary[disabled].focus,
fieldset[disabled] .btn-primary.focus,
.btn-primary.disabled:active,
.btn-primary[disabled]:active,
fieldset[disabled] .btn-primary:active,
.btn-primary.disabled.active,
.btn-primary[disabled].active,
fieldset[disabled] .btn-primary.active {
background-color: #265a88;
background-image: none;
}
.btn-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #3e8f3e;
}
.btn-success:hover,
.btn-success:focus {
background-color: #419641;
background-position: 0 -15px;
}
.btn-success:active,
.btn-success.active {
background-color: #419641;
border-color: #3e8f3e;
}
.btn-success.disabled,
.btn-success[disabled],
fieldset[disabled] .btn-success,
.btn-success.disabled:hover,
.btn-success[disabled]:hover,
fieldset[disabled] .btn-success:hover,
.btn-success.disabled:focus,
.btn-success[disabled]:focus,
fieldset[disabled] .btn-success:focus,
.btn-success.disabled.focus,
.btn-success[disabled].focus,
fieldset[disabled] .btn-success.focus,
.btn-success.disabled:active,
.btn-success[disabled]:active,
fieldset[disabled] .btn-success:active,
.btn-success.disabled.active,
.btn-success[disabled].active,
fieldset[disabled] .btn-success.active {
background-color: #419641;
background-image: none;
}
.btn-info {
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #28a4c9;
}
.btn-info:hover,
.btn-info:focus {
background-color: #2aabd2;
background-position: 0 -15px;
}
.btn-info:active,
.btn-info.active {
background-color: #2aabd2;
border-color: #28a4c9;
}
.btn-info.disabled,
.btn-info[disabled],
fieldset[disabled] .btn-info,
.btn-info.disabled:hover,
.btn-info[disabled]:hover,
fieldset[disabled] .btn-info:hover,
.btn-info.disabled:focus,
.btn-info[disabled]:focus,
fieldset[disabled] .btn-info:focus,
.btn-info.disabled.focus,
.btn-info[disabled].focus,
fieldset[disabled] .btn-info.focus,
.btn-info.disabled:active,
.btn-info[disabled]:active,
fieldset[disabled] .btn-info:active,
.btn-info.disabled.active,
.btn-info[disabled].active,
fieldset[disabled] .btn-info.active {
background-color: #2aabd2;
background-image: none;
}
.btn-warning {
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #e38d13;
}
.btn-warning:hover,
.btn-warning:focus {
background-color: #eb9316;
background-position: 0 -15px;
}
.btn-warning:active,
.btn-warning.active {
background-color: #eb9316;
border-color: #e38d13;
}
.btn-warning.disabled,
.btn-warning[disabled],
fieldset[disabled] .btn-warning,
.btn-warning.disabled:hover,
.btn-warning[disabled]:hover,
fieldset[disabled] .btn-warning:hover,
.btn-warning.disabled:focus,
.btn-warning[disabled]:focus,
fieldset[disabled] .btn-warning:focus,
.btn-warning.disabled.focus,
.btn-warning[disabled].focus,
fieldset[disabled] .btn-warning.focus,
.btn-warning.disabled:active,
.btn-warning[disabled]:active,
fieldset[disabled] .btn-warning:active,
.btn-warning.disabled.active,
.btn-warning[disabled].active,
fieldset[disabled] .btn-warning.active {
background-color: #eb9316;
background-image: none;
}
.btn-danger {
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #b92c28;
}
.btn-danger:hover,
.btn-danger:focus {
background-color: #c12e2a;
background-position: 0 -15px;
}
.btn-danger:active,
.btn-danger.active {
background-color: #c12e2a;
border-color: #b92c28;
}
.btn-danger.disabled,
.btn-danger[disabled],
fieldset[disabled] .btn-danger,
.btn-danger.disabled:hover,
.btn-danger[disabled]:hover,
fieldset[disabled] .btn-danger:hover,
.btn-danger.disabled:focus,
.btn-danger[disabled]:focus,
fieldset[disabled] .btn-danger:focus,
.btn-danger.disabled.focus,
.btn-danger[disabled].focus,
fieldset[disabled] .btn-danger.focus,
.btn-danger.disabled:active,
.btn-danger[disabled]:active,
fieldset[disabled] .btn-danger:active,
.btn-danger.disabled.active,
.btn-danger[disabled].active,
fieldset[disabled] .btn-danger.active {
background-color: #c12e2a;
background-image: none;
}
.thumbnail,
.img-thumbnail {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
background-color: #e8e8e8;
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-repeat: repeat-x;
}
.dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
.dropdown-menu > .active > a:focus {
background-color: #2e6da4;
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
background-repeat: repeat-x;
}
.navbar-default {
background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
}
.navbar-default .navbar-nav > .open > a,
.navbar-default .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
}
.navbar-brand,
.navbar-nav > li > a {
text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
}
.navbar-inverse {
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-radius: 4px;
}
.navbar-inverse .navbar-nav > .open > a,
.navbar-inverse .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);
background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
}
.navbar-inverse .navbar-brand,
.navbar-inverse .navbar-nav > li > a {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
}
.navbar-static-top,
.navbar-fixed-top,
.navbar-fixed-bottom {
border-radius: 0;
}
@media (max-width: 767px) {
.navbar .navbar-nav .open .dropdown-menu > .active > a,
.navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
.navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
color: #fff;
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
background-repeat: repeat-x;
}
}
.alert {
text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
}
.alert-success {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
background-repeat: repeat-x;
border-color: #b2dba1;
}
.alert-info {
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
background-repeat: repeat-x;
border-color: #9acfea;
}
.alert-warning {
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
background-repeat: repeat-x;
border-color: #f5e79e;
}
.alert-danger {
background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
background-repeat: repeat-x;
border-color: #dca7a7;
}
.progress {
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar {
background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));
background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-info {
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-warning {
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-danger {
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-striped {
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
}
.list-group {
border-radius: 4px;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}
.list-group-item.active,
.list-group-item.active:hover,
.list-group-item.active:focus {
text-shadow: 0 -1px 0 #286090;
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));
background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
background-repeat: repeat-x;
border-color: #2b669a;
}
.list-group-item.active .badge,
.list-group-item.active:hover .badge,
.list-group-item.active:focus .badge {
text-shadow: none;
}
.panel {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
}
.panel-default > .panel-heading {
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-repeat: repeat-x;
}
.panel-primary > .panel-heading {
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
background-repeat: repeat-x;
}
.panel-success > .panel-heading {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
background-repeat: repeat-x;
}
.panel-info > .panel-heading {
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
background-repeat: repeat-x;
}
.panel-warning > .panel-heading {
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
background-repeat: repeat-x;
}
.panel-danger > .panel-heading {
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
background-repeat: repeat-x;
}
.well {
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x;
border-color: #dcdcdc;
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
}
/*# sourceMappingURL=bootstrap-theme.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

13
ext/lib/bootstrap-3.3.7-dist/js/npm.js vendored Normal file
View File

@ -0,0 +1,13 @@
// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
require('../../js/transition.js')
require('../../js/alert.js')
require('../../js/button.js')
require('../../js/carousel.js')
require('../../js/collapse.js')
require('../../js/dropdown.js')
require('../../js/modal.js')
require('../../js/tooltip.js')
require('../../js/popover.js')
require('../../js/scrollspy.js')
require('../../js/tab.js')
require('../../js/affix.js')

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
ext/lib/jquery-3.1.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "Yomichan",
"version": "1.0.6",
"version": "1.0.15",
"description": "Japanese dictionary with Anki integration",
"icons": {"16": "img/icon16.png", "48": "img/icon48.png", "128": "img/icon128.png"},
@ -32,13 +32,14 @@
],
"web_accessible_resources": [
"fg/css/frame.css",
"fg/frame.html",
"fg/img/add_kanji.png",
"fg/img/add_term_kana.png",
"fg/img/add_term_kanji.png",
"fg/img/play_audio.png",
"fg/img/spinner.gif",
"fg/js/frame.js",
"fg/frame.html",
"fg/mp3/button.mp3",
"fg/ttf/kanji-stroke-orders.ttf",
"fg/ttf/vl-gothic-regular.ttf"
],

View File

@ -1,26 +1,10 @@
<div class="dict-group well well-sm" data-title="{{title}}">
<h4><span class="text-muted glyphicon glyphicon-book"></span> {{title}} <small>rev.{{revision}}</small></h4>
<!-- <div class="row"> -->
<!-- <div class="col-xs-8"> -->
<!-- <h4><span class="text-muted glyphicon glyphicon-book"></span> {{title}} <small>v.{{version}}</small></h4> -->
<!-- </div> -->
<!-- <div class="col-xs-4 text-right disabled"> -->
<!-- <button type="button" class="dict-group-controls dict-delete btn btn-danger">Delete</button> -->
<!-- </div> -->
<!-- </div> -->
<div class="dict-delete-progress">
Dictionary data is being deleted, please be patient...
<div class="progress">
<div class="progress-bar progress-bar-striped progress-bar-danger" style="width: 0%"></div>
</div>
</div>
<div class="checkbox dict-group-controls">
<div class="checkbox">
<label><input type="checkbox" class="dict-enabled" {{#if enabled}}checked{{/if}}> Enable search</label>
</div>
<div class="form-group dict-group-controls options-advanced">
<div class="form-group options-advanced">
<label for="dict-{{title}}">Result priority</label>
<input type="number" value="{{priority}}" id="dict-{{title}}" class="form-control dict-priority">
</div>

View File

@ -48,6 +48,14 @@
{{#*inline "glossary"}}
{{~#if html}}<div style="text-align: left;">{{/if~}}
{{~#if modeKanji~}}
{{~#if definition.glossary.[1]~}}
{{~#if html}}<ol>{{#each definition.glossary}}<li>{{.}}</li>{{/each}}</ol>
{{~else}}{{#each definition.glossary}}{{.}}{{#unless @last}}, {{/unless}}{{/each}}{{/if~}}
{{~else~}}
{{definition.glossary.[0]}}
{{~/if~}}
{{~else~}}
{{~#if group~}}
{{~#if definition.definitions.[1]~}}
{{~#if html}}<ol>{{#each definition.definitions}}<li>{{> glossary-single html=../html}}</li>{{/each}}</ol>
@ -58,6 +66,7 @@
{{~else~}}
{{~> glossary-single definition html=html~}}
{{~/if~}}
{{~/if~}}
{{~#if html}}</div>{{/if~}}
{{/inline}}