Merge branch 'dev'
This commit is contained in:
commit
d505edb94b
86
README.md
86
README.md
@ -258,52 +258,72 @@ versions packaged.
|
|||||||
|
|
||||||
## Frequently Asked Questions ##
|
## Frequently Asked Questions ##
|
||||||
|
|
||||||
* **Why does the Kanji results page display "No data found" for several fields?**
|
**I'm having problems importing dictionaries in Firefox, what do I do?**
|
||||||
|
|
||||||
You are using data from the KANJIDIC dictionary that was exported for an earlier version of Yomichan. It does not
|
Yomichan uses the cross-browser IndexedDB system for storing imported dictionary data into your user profile. Although
|
||||||
contain the additional information which newer versions of Yofomichan expect. Unfortunately, since major browser
|
everything "just works" in Chrome, depending on settings, Firefox users can run into problems due browser bugs.
|
||||||
implementations of IndexedDB do not provide reliable means for selective bulk data deletion, you will need purge
|
Yomichan catches errors and tries to offer suggestions about how to work around Firefox issues, but in general at least
|
||||||
your database and install the latest version of the KANJIDIC to see additional information about characters.
|
one of the following solutions should work for you:
|
||||||
|
|
||||||
* **Can I still create cards without HTML formatting? The option for it is gone!**
|
* Make sure you have cookies enabled. It appears that disabling them also disables IndexedDB for some reason. You
|
||||||
|
can still have cookies be disabled on other sites; just make sure to add the Yomichan extension to the whitelist of
|
||||||
|
whatever tool you are using to restrict cookies. You can get the extension "URL" by looking at the address bar when
|
||||||
|
you have the search page open.
|
||||||
|
* Make sure that you have sufficient disk space available on the drive Firefox uses to store your user profile.
|
||||||
|
Firefox limits the amount of space that can be used by IndexedDB to a small fraction of the disk space actually
|
||||||
|
available on your computer.
|
||||||
|
* Make sure that you have history set to "Remember history" enabled in your privacy settings. When this option is
|
||||||
|
set to "Never remember history", IndexedDB access is once again disabled for an inexplicable reason.
|
||||||
|
* As a last resort, try using the [Refresh Firefox](https://support.mozilla.org/en-US/kb/reset-preferences-fix-problems)
|
||||||
|
feature to reset your user profile. It appears that the Firefox profile system can corrupt itself preventing
|
||||||
|
IndexedDB from being accessible to Yomichan.
|
||||||
|
|
||||||
Developing Yomichan is a constant balance between including useful features and keeping complexity at a minimum.
|
**Why does the Kanji results page display "No data found" for several fields?**
|
||||||
With the new user-editable card template system, it is possible to create text-only cards without having to double
|
|
||||||
the number field of templates in the extension itself. If you would like to stop HTML tags from being added to your
|
|
||||||
cards, simply copy the contents of the <a href="dl/fields.txt">text-only field template</a> into the template box on
|
|
||||||
the Anki settings page (make sure you have the *Show advanced options* checkbox ticked), making sure to replace the
|
|
||||||
existing values.
|
|
||||||
|
|
||||||
* **Will you add support for online dictionaries?**
|
You are using data from the KANJIDIC dictionary that was exported for an earlier version of Yomichan. It does not
|
||||||
|
contain the additional information which newer versions of Yofomichan expect. Unfortunately, since major browser
|
||||||
|
implementations of IndexedDB do not provide reliable means for selective bulk data deletion, you will need purge
|
||||||
|
your database and install the latest version of the KANJIDIC to see additional information about characters.
|
||||||
|
|
||||||
Online dictionaries will never be implemented because it is impossible to support them in a robust way. In order to
|
**Can I still create cards without HTML formatting? The option for it is gone!**
|
||||||
perform Japanese deinflection, Yomichan must execute dozens of database queries per every single word. Factoring in
|
|
||||||
network latency and the fragility of web scraping, I do not believe that it is possible to realize a good user
|
|
||||||
experience.
|
|
||||||
|
|
||||||
* **Is it possible to use Yomichan with files saved locally on my computer with Chrome?**
|
Developing Yomichan is a constant balance between including useful features and keeping complexity at a minimum.
|
||||||
|
With the new user-editable card template system, it is possible to create text-only cards without having to double
|
||||||
|
the number field of templates in the extension itself. If you would like to stop HTML tags from being added to your
|
||||||
|
cards, simply copy the contents of the <a href="dl/fields.txt">text-only field template</a> into the template box on
|
||||||
|
the Anki settings page (make sure you have the *Show advanced options* checkbox ticked), making sure to replace the
|
||||||
|
existing values.
|
||||||
|
|
||||||
In order to use Yomichan with local files in Chrome, you must first tick the *Allow access to file URLs* checkbox
|
**Will you add support for online dictionaries?**
|
||||||
for Yomichan on the extensions page. Due to the restrictions placed on browser addons in the WebExtensions model, it
|
|
||||||
will likely never be possible to use Yomichan with PDF files.
|
|
||||||
|
|
||||||
* **Is it possible to delete individual dictionaries without purging the database?**
|
Online dictionaries will never be implemented because it is impossible to support them in a robust way. In order to
|
||||||
|
perform Japanese deinflection, Yomichan must execute dozens of database queries per every single word. Factoring in
|
||||||
|
network latency and the fragility of web scraping, I do not believe that it is possible to realize a good user
|
||||||
|
experience.
|
||||||
|
|
||||||
Although it is technically possible to purge specific dictionaries, due to the limitations of the underlying browser
|
**Is it possible to use Yomichan with files saved locally on my computer with Chrome?**
|
||||||
IndexedDB system, this process is *extremely* slow. For example, it can take up to ten minutes to delete a single
|
|
||||||
moderately-sized term dictionary! Instead of including a borderline unusable feature in Yomichan, I have chosen to
|
|
||||||
disable dictionary deletion entirely.
|
|
||||||
|
|
||||||
* **Why aren't EPWING dictionaries bundled with Yomichan?**
|
In order to use Yomichan with local files in Chrome, you must first tick the *Allow access to file URLs* checkbox
|
||||||
|
for Yomichan on the extensions page. Due to the restrictions placed on browser addons in the WebExtensions model, it
|
||||||
|
will likely never be possible to use Yomichan with PDF files.
|
||||||
|
|
||||||
The vast majority of EPWING dictionaries are proprietary, so unfortunately I am unable to legally include them in
|
**Is it possible to delete individual dictionaries without purging the database?**
|
||||||
this extension for copyright reasons.
|
|
||||||
|
|
||||||
* **When are you going to add support for $MYLANGUAGE?**
|
Although it is technically possible to purge specific dictionaries, due to the limitations of the underlying browser
|
||||||
|
IndexedDB system, this process is *extremely* slow. For example, it can take up to ten minutes to delete a single
|
||||||
|
moderately-sized term dictionary! Instead of including a borderline unusable feature in Yomichan, I have chosen to
|
||||||
|
disable dictionary deletion entirely.
|
||||||
|
|
||||||
Developing Yomichan requires a significant understanding of Japanese sentence structure and grammar. I have no time
|
**Why aren't EPWING dictionaries bundled with Yomichan?**
|
||||||
to invest in learning yet another language; therefore other languages will not be supported. I will also not accept
|
|
||||||
pull request containing this functionality, as I will ultimately be the one maintaining your code.
|
The vast majority of EPWING dictionaries are proprietary, so unfortunately I am unable to legally include them in
|
||||||
|
this extension for copyright reasons.
|
||||||
|
|
||||||
|
**When are you going to add support for $MYLANGUAGE?**
|
||||||
|
|
||||||
|
Developing Yomichan requires a significant understanding of Japanese sentence structure and grammar. I have no time
|
||||||
|
to invest in learning yet another language; therefore other languages will not be supported. I will also not accept
|
||||||
|
pull request containing this functionality, as I will ultimately be the one maintaining your code.
|
||||||
|
|
||||||
## Screenshots ##
|
## Screenshots ##
|
||||||
|
|
||||||
|
@ -29,9 +29,11 @@ async function apiTermsFind(text) {
|
|||||||
const options = utilBackend().options;
|
const options = utilBackend().options;
|
||||||
const translator = utilBackend().translator;
|
const translator = utilBackend().translator;
|
||||||
|
|
||||||
const searcher = options.general.groupResults ?
|
const searcher = {
|
||||||
translator.findTermsGrouped.bind(translator) :
|
'merge': translator.findTermsMerged,
|
||||||
translator.findTermsSplit.bind(translator);
|
'split': translator.findTermsSplit,
|
||||||
|
'group': translator.findTermsGrouped
|
||||||
|
}[options.general.resultOutputMode].bind(translator);
|
||||||
|
|
||||||
const {definitions, length} = await searcher(
|
const {definitions, length} = await searcher(
|
||||||
text,
|
text,
|
||||||
|
@ -140,8 +140,13 @@ async function audioInject(definition, fields, mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = await audioBuildUrl(definition, mode);
|
let audioSourceDefinition = definition;
|
||||||
const filename = audioBuildFilename(definition);
|
if (definition.hasOwnProperty('expressions')) {
|
||||||
|
audioSourceDefinition = definition.expressions[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = await audioBuildUrl(audioSourceDefinition, mode);
|
||||||
|
const filename = audioBuildFilename(audioSourceDefinition);
|
||||||
|
|
||||||
if (url && filename) {
|
if (url && filename) {
|
||||||
definition.audio = {url, filename};
|
definition.audio = {url, filename};
|
||||||
|
@ -40,6 +40,9 @@ class Database {
|
|||||||
kanjiMeta: '++,dictionary,character',
|
kanjiMeta: '++,dictionary,character',
|
||||||
tagMeta: '++,dictionary,name'
|
tagMeta: '++,dictionary,name'
|
||||||
});
|
});
|
||||||
|
this.db.version(4).stores({
|
||||||
|
terms: '++id,dictionary,expression,reading,sequence'
|
||||||
|
});
|
||||||
|
|
||||||
await this.db.open();
|
await this.db.open();
|
||||||
}
|
}
|
||||||
@ -68,12 +71,66 @@ class Database {
|
|||||||
results.push({
|
results.push({
|
||||||
expression: row.expression,
|
expression: row.expression,
|
||||||
reading: row.reading,
|
reading: row.reading,
|
||||||
tags: dictFieldSplit(row.tags),
|
definitionTags: dictFieldSplit(row.definitionTags || row.tags || ''),
|
||||||
|
termTags: dictFieldSplit(row.termTags || ''),
|
||||||
rules: dictFieldSplit(row.rules),
|
rules: dictFieldSplit(row.rules),
|
||||||
glossary: row.glossary,
|
glossary: row.glossary,
|
||||||
score: row.score,
|
score: row.score,
|
||||||
dictionary: row.dictionary,
|
dictionary: row.dictionary,
|
||||||
id: row.id
|
id: row.id,
|
||||||
|
sequence: typeof row.sequence === 'undefined' ? -1 : row.sequence
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
async findTermsExact(term, reading, titles) {
|
||||||
|
if (!this.db) {
|
||||||
|
throw 'Database not initialized';
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
await this.db.terms.where('expression').equals(term).each(row => {
|
||||||
|
if (row.reading === reading && titles.includes(row.dictionary)) {
|
||||||
|
results.push({
|
||||||
|
expression: row.expression,
|
||||||
|
reading: row.reading,
|
||||||
|
definitionTags: dictFieldSplit(row.definitionTags || row.tags || ''),
|
||||||
|
termTags: dictFieldSplit(row.termTags || ''),
|
||||||
|
rules: dictFieldSplit(row.rules),
|
||||||
|
glossary: row.glossary,
|
||||||
|
score: row.score,
|
||||||
|
dictionary: row.dictionary,
|
||||||
|
id: row.id,
|
||||||
|
sequence: typeof row.sequence === 'undefined' ? -1 : row.sequence
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
async findTermsBySequence(sequence, mainDictionary) {
|
||||||
|
if (!this.db) {
|
||||||
|
throw 'Database not initialized';
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
await this.db.terms.where('sequence').equals(sequence).each(row => {
|
||||||
|
if (row.dictionary === mainDictionary) {
|
||||||
|
results.push({
|
||||||
|
expression: row.expression,
|
||||||
|
reading: row.reading,
|
||||||
|
definitionTags: dictFieldSplit(row.definitionTags || row.tags || ''),
|
||||||
|
termTags: dictFieldSplit(row.termTags || ''),
|
||||||
|
rules: dictFieldSplit(row.rules),
|
||||||
|
glossary: row.glossary,
|
||||||
|
score: row.score,
|
||||||
|
dictionary: row.dictionary,
|
||||||
|
id: row.id,
|
||||||
|
sequence: typeof row.sequence === 'undefined' ? -1 : row.sequence
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -163,7 +220,7 @@ class Database {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTitles() {
|
async summarize() {
|
||||||
if (this.db) {
|
if (this.db) {
|
||||||
return this.db.dictionaries.toArray();
|
return this.db.dictionaries.toArray();
|
||||||
} else {
|
} else {
|
||||||
@ -177,7 +234,7 @@ class Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const indexDataLoaded = async summary => {
|
const indexDataLoaded = async summary => {
|
||||||
if (summary.version > 2) {
|
if (summary.version > 3) {
|
||||||
throw 'Unsupported dictionary version';
|
throw 'Unsupported dictionary version';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,11 +253,11 @@ class Database {
|
|||||||
|
|
||||||
const rows = [];
|
const rows = [];
|
||||||
if (summary.version === 1) {
|
if (summary.version === 1) {
|
||||||
for (const [expression, reading, tags, rules, score, ...glossary] of entries) {
|
for (const [expression, reading, definitionTags, rules, score, ...glossary] of entries) {
|
||||||
rows.push({
|
rows.push({
|
||||||
expression,
|
expression,
|
||||||
reading,
|
reading,
|
||||||
tags,
|
definitionTags,
|
||||||
rules,
|
rules,
|
||||||
score,
|
score,
|
||||||
glossary,
|
glossary,
|
||||||
@ -208,14 +265,16 @@ class Database {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const [expression, reading, tags, rules, score, glossary] of entries) {
|
for (const [expression, reading, definitionTags, rules, score, glossary, sequence, termTags] of entries) {
|
||||||
rows.push({
|
rows.push({
|
||||||
expression,
|
expression,
|
||||||
reading,
|
reading,
|
||||||
tags,
|
definitionTags,
|
||||||
rules,
|
rules,
|
||||||
score,
|
score,
|
||||||
glossary,
|
glossary,
|
||||||
|
sequence,
|
||||||
|
termTags,
|
||||||
dictionary: summary.title
|
dictionary: summary.title
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -300,12 +359,13 @@ class Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const rows = [];
|
const rows = [];
|
||||||
for (const [name, category, order, notes] of entries) {
|
for (const [name, category, order, notes, score] of entries) {
|
||||||
const row = dictTagSanitize({
|
const row = dictTagSanitize({
|
||||||
name,
|
name,
|
||||||
category,
|
category,
|
||||||
order,
|
order,
|
||||||
notes,
|
notes,
|
||||||
|
score,
|
||||||
dictionary: summary.title
|
dictionary: summary.title
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -350,12 +410,11 @@ class Database {
|
|||||||
const summary = {
|
const summary = {
|
||||||
title: index.title,
|
title: index.title,
|
||||||
revision: index.revision,
|
revision: index.revision,
|
||||||
|
sequenced: index.sequenced,
|
||||||
version: index.format || index.version
|
version: index.format || index.version
|
||||||
};
|
};
|
||||||
|
|
||||||
if (indexDataLoaded) {
|
|
||||||
await indexDataLoaded(summary);
|
await indexDataLoaded(summary);
|
||||||
}
|
|
||||||
|
|
||||||
const buildTermBankName = index => `term_bank_${index + 1}.json`;
|
const buildTermBankName = index => `term_bank_${index + 1}.json`;
|
||||||
const buildTermMetaBankName = index => `term_meta_bank_${index + 1}.json`;
|
const buildTermMetaBankName = index => `term_meta_bank_${index + 1}.json`;
|
||||||
@ -390,7 +449,7 @@ class Database {
|
|||||||
const bank = [];
|
const bank = [];
|
||||||
for (const name in index.tagMeta) {
|
for (const name in index.tagMeta) {
|
||||||
const tag = index.tagMeta[name];
|
const tag = index.tagMeta[name];
|
||||||
bank.push([name, tag.category, tag.order, tag.notes]);
|
bank.push([name, tag.category, tag.order, tag.notes, tag.score]);
|
||||||
}
|
}
|
||||||
|
|
||||||
tagDataLoaded(summary, bank, ++bankTotalCount, bankLoadedCount++);
|
tagDataLoaded(summary, bank, ++bankTotalCount, bankLoadedCount++);
|
||||||
|
@ -89,7 +89,7 @@ function dictTermsSort(definitions, dictionaries=null) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return v2.expression.localeCompare(v1.expression);
|
return v2.expression.toString().localeCompare(v1.expression.toString());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +110,33 @@ function dictTermsUndupe(definitions) {
|
|||||||
return definitionsUnique;
|
return definitionsUnique;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function dictTermsCompressTags(definitions) {
|
||||||
|
let lastDictionary = '';
|
||||||
|
let lastPartOfSpeech = '';
|
||||||
|
|
||||||
|
for (const definition of definitions) {
|
||||||
|
const dictionary = JSON.stringify(definition.definitionTags.filter(tag => tag.category === 'dictionary').map(tag => tag.name).sort());
|
||||||
|
const partOfSpeech = JSON.stringify(definition.definitionTags.filter(tag => tag.category === 'partOfSpeech').map(tag => tag.name).sort());
|
||||||
|
|
||||||
|
const filterOutCategories = [];
|
||||||
|
|
||||||
|
if (lastDictionary === dictionary) {
|
||||||
|
filterOutCategories.push('dictionary');
|
||||||
|
} else {
|
||||||
|
lastDictionary = dictionary;
|
||||||
|
lastPartOfSpeech = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastPartOfSpeech === partOfSpeech) {
|
||||||
|
filterOutCategories.push('partOfSpeech');
|
||||||
|
} else {
|
||||||
|
lastPartOfSpeech = partOfSpeech;
|
||||||
|
}
|
||||||
|
|
||||||
|
definition.definitionTags = definition.definitionTags.filter(tag => !filterOutCategories.includes(tag.category));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function dictTermsGroup(definitions, dictionaries) {
|
function dictTermsGroup(definitions, dictionaries) {
|
||||||
const groups = {};
|
const groups = {};
|
||||||
for (const definition of definitions) {
|
for (const definition of definitions) {
|
||||||
@ -136,6 +163,7 @@ function dictTermsGroup(definitions, dictionaries) {
|
|||||||
expression: firstDef.expression,
|
expression: firstDef.expression,
|
||||||
reading: firstDef.reading,
|
reading: firstDef.reading,
|
||||||
reasons: firstDef.reasons,
|
reasons: firstDef.reasons,
|
||||||
|
termTags: groupDefs[0].termTags,
|
||||||
score: groupDefs.reduce((p, v) => v.score > p ? v.score : p, Number.MIN_SAFE_INTEGER),
|
score: groupDefs.reduce((p, v) => v.score > p ? v.score : p, Number.MIN_SAFE_INTEGER),
|
||||||
source: firstDef.source
|
source: firstDef.source
|
||||||
});
|
});
|
||||||
@ -144,6 +172,116 @@ function dictTermsGroup(definitions, dictionaries) {
|
|||||||
return dictTermsSort(results);
|
return dictTermsSort(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function dictTermsMergeBySequence(definitions, mainDictionary) {
|
||||||
|
const definitionsBySequence = {'-1': []};
|
||||||
|
for (const definition of definitions) {
|
||||||
|
if (mainDictionary === definition.dictionary && definition.sequence >= 0) {
|
||||||
|
if (!definitionsBySequence[definition.sequence]) {
|
||||||
|
definitionsBySequence[definition.sequence] = {
|
||||||
|
reasons: definition.reasons,
|
||||||
|
score: Number.MIN_SAFE_INTEGER,
|
||||||
|
expression: new Set(),
|
||||||
|
reading: new Set(),
|
||||||
|
expressions: new Map(),
|
||||||
|
source: definition.source,
|
||||||
|
dictionary: definition.dictionary,
|
||||||
|
definitions: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const score = Math.max(definitionsBySequence[definition.sequence].score, definition.score);
|
||||||
|
definitionsBySequence[definition.sequence].score = score;
|
||||||
|
} else {
|
||||||
|
definitionsBySequence['-1'].push(definition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return definitionsBySequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
function dictTermsMergeByGloss(result, definitions, appendTo, mergedIndices) {
|
||||||
|
const definitionsByGloss = appendTo || {};
|
||||||
|
for (const [index, definition] of definitions.entries()) {
|
||||||
|
if (appendTo) {
|
||||||
|
let match = false;
|
||||||
|
for (const expression of result.expressions.keys()) {
|
||||||
|
if (definition.expression === expression) {
|
||||||
|
for (const reading of result.expressions.get(expression).keys()) {
|
||||||
|
if (definition.reading === reading) {
|
||||||
|
match = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (match) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!match) {
|
||||||
|
continue;
|
||||||
|
} else if (mergedIndices) {
|
||||||
|
mergedIndices.add(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const gloss = JSON.stringify(definition.glossary.concat(definition.dictionary));
|
||||||
|
if (!definitionsByGloss[gloss]) {
|
||||||
|
definitionsByGloss[gloss] = {
|
||||||
|
expression: new Set(),
|
||||||
|
reading: new Set(),
|
||||||
|
definitionTags: [],
|
||||||
|
glossary: definition.glossary,
|
||||||
|
source: result.source,
|
||||||
|
reasons: [],
|
||||||
|
score: definition.score,
|
||||||
|
id: definition.id,
|
||||||
|
dictionary: definition.dictionary
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
definitionsByGloss[gloss].expression.add(definition.expression);
|
||||||
|
definitionsByGloss[gloss].reading.add(definition.reading);
|
||||||
|
|
||||||
|
result.expression.add(definition.expression);
|
||||||
|
result.reading.add(definition.reading);
|
||||||
|
|
||||||
|
// result->expressions[ Expression1[ Reading1[ Tag1, Tag2 ] ], Expression2, ... ]
|
||||||
|
if (!result.expressions.has(definition.expression)) {
|
||||||
|
result.expressions.set(definition.expression, new Map());
|
||||||
|
}
|
||||||
|
if (!result.expressions.get(definition.expression).has(definition.reading)) {
|
||||||
|
result.expressions.get(definition.expression).set(definition.reading, new Set());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const tag of definition.definitionTags) {
|
||||||
|
if (!definitionsByGloss[gloss].definitionTags.find(existingTag => existingTag.name === tag.name)) {
|
||||||
|
definitionsByGloss[gloss].definitionTags.push(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const tag of definition.termTags) {
|
||||||
|
result.expressions.get(definition.expression).get(definition.reading).add(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const gloss in definitionsByGloss) {
|
||||||
|
const definition = definitionsByGloss[gloss];
|
||||||
|
definition.only = [];
|
||||||
|
if (!utilSetEqual(definition.expression, result.expression)) {
|
||||||
|
for (const expression of utilSetIntersection(definition.expression, result.expression)) {
|
||||||
|
definition.only.push(expression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!utilSetEqual(definition.reading, result.reading)) {
|
||||||
|
for (const reading of utilSetIntersection(definition.reading, result.reading)) {
|
||||||
|
definition.only.push(reading);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return definitionsByGloss;
|
||||||
|
}
|
||||||
|
|
||||||
function dictTagBuildSource(name) {
|
function dictTagBuildSource(name) {
|
||||||
return dictTagSanitize({name, category: 'dictionary', order: 100});
|
return dictTagSanitize({name, category: 'dictionary', order: 100});
|
||||||
}
|
}
|
||||||
@ -153,6 +291,7 @@ function dictTagSanitize(tag) {
|
|||||||
tag.category = tag.category || 'default';
|
tag.category = tag.category || 'default';
|
||||||
tag.notes = tag.notes || '';
|
tag.notes = tag.notes || '';
|
||||||
tag.order = tag.order || 0;
|
tag.order = tag.order || 0;
|
||||||
|
tag.score = tag.score || 0;
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,10 +346,12 @@ async function dictFieldFormat(field, definition, mode, options) {
|
|||||||
const data = {
|
const data = {
|
||||||
marker,
|
marker,
|
||||||
definition,
|
definition,
|
||||||
group: options.general.groupResults,
|
group: options.general.resultOutputMode === 'group',
|
||||||
|
merge: options.general.resultOutputMode === 'merge',
|
||||||
modeTermKanji: mode === 'term-kanji',
|
modeTermKanji: mode === 'term-kanji',
|
||||||
modeTermKana: mode === 'term-kana',
|
modeTermKana: mode === 'term-kana',
|
||||||
modeKanji: mode === 'kanji'
|
modeKanji: mode === 'kanji',
|
||||||
|
compactGlossaries: options.general.compactGlossaries
|
||||||
};
|
};
|
||||||
|
|
||||||
const html = await apiTemplateRender(options.anki.fieldTemplates, data, true);
|
const html = await apiTemplateRender(options.anki.fieldTemplates, data, true);
|
||||||
|
@ -19,12 +19,26 @@
|
|||||||
|
|
||||||
function optionsFieldTemplates() {
|
function optionsFieldTemplates() {
|
||||||
return `
|
return `
|
||||||
|
<style>
|
||||||
|
.expression-popular {
|
||||||
|
color: #0275d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expression-rare {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
{{#*inline "glossary-single"}}
|
{{#*inline "glossary-single"}}
|
||||||
{{~#unless brief~}}
|
{{~#unless brief~}}
|
||||||
{{~#if tags~}}<i>({{#each tags}}{{name}}{{#unless @last}}, {{/unless}}{{/each}})</i> {{/if~}}
|
{{~#if definitionTags~}}<i>({{#each definitionTags}}{{name}}{{#unless @last}}, {{/unless}}{{/each}})</i> {{/if~}}
|
||||||
|
{{~#if only~}}({{#each only}}{{{.}}}{{#unless @last}}, {{/unless}}{{/each}} only) {{/if~}}
|
||||||
{{~/unless~}}
|
{{~/unless~}}
|
||||||
{{~#if glossary.[1]~}}
|
{{~#if glossary.[1]~}}
|
||||||
|
{{~#if compactGlossaries~}}
|
||||||
|
{{#each glossary}}{{#multiLine}}{{.}}{{/multiLine}}{{#unless @last}} | {{/unless}}{{/each}}
|
||||||
|
{{~else~}}
|
||||||
<ul>{{#each glossary}}<li>{{#multiLine}}{{.}}{{/multiLine}}</li>{{/each}}</ul>
|
<ul>{{#each glossary}}<li>{{#multiLine}}{{.}}{{/multiLine}}</li>{{/each}}</ul>
|
||||||
|
{{~/if~}}
|
||||||
{{~else~}}
|
{{~else~}}
|
||||||
{{~#multiLine}}{{glossary.[0]}}{{/multiLine~}}
|
{{~#multiLine}}{{glossary.[0]}}{{/multiLine~}}
|
||||||
{{~/if~}}
|
{{~/if~}}
|
||||||
@ -41,6 +55,24 @@ function optionsFieldTemplates() {
|
|||||||
{{/inline}}
|
{{/inline}}
|
||||||
|
|
||||||
{{#*inline "expression"}}
|
{{#*inline "expression"}}
|
||||||
|
{{~#if merge~}}
|
||||||
|
{{~#if modeTermKana~}}
|
||||||
|
{{~#each definition.reading~}}
|
||||||
|
{{{.}}}
|
||||||
|
{{~#unless @last}}、{{/unless~}}
|
||||||
|
{{~else~}}
|
||||||
|
{{~#each definition.expression~}}
|
||||||
|
{{{.}}}
|
||||||
|
{{~#unless @last}}、{{/unless~}}
|
||||||
|
{{~/each~}}
|
||||||
|
{{~/each~}}
|
||||||
|
{{~else~}}
|
||||||
|
{{~#each definition.expression~}}
|
||||||
|
{{{.}}}
|
||||||
|
{{~#unless @last}}、{{/unless~}}
|
||||||
|
{{~/each~}}
|
||||||
|
{{~/if~}}
|
||||||
|
{{~else~}}
|
||||||
{{~#if modeTermKana~}}
|
{{~#if modeTermKana~}}
|
||||||
{{~#if definition.reading~}}
|
{{~#if definition.reading~}}
|
||||||
{{definition.reading}}
|
{{definition.reading}}
|
||||||
@ -50,14 +82,29 @@ function optionsFieldTemplates() {
|
|||||||
{{~else~}}
|
{{~else~}}
|
||||||
{{definition.expression}}
|
{{definition.expression}}
|
||||||
{{~/if~}}
|
{{~/if~}}
|
||||||
|
{{~/if~}}
|
||||||
{{/inline}}
|
{{/inline}}
|
||||||
|
|
||||||
{{#*inline "furigana"}}
|
{{#*inline "furigana"}}
|
||||||
|
{{~#if merge~}}
|
||||||
|
{{~#each definition.expressions~}}
|
||||||
|
<span class="expression-{{termFrequency}}">{{~#furigana}}{{{.}}}{{/furigana~}}</span>
|
||||||
|
{{~#unless @last}}、{{/unless~}}
|
||||||
|
{{~/each~}}
|
||||||
|
{{~else~}}
|
||||||
{{#furigana}}{{{definition}}}{{/furigana}}
|
{{#furigana}}{{{definition}}}{{/furigana}}
|
||||||
|
{{~/if~}}
|
||||||
{{/inline}}
|
{{/inline}}
|
||||||
|
|
||||||
{{#*inline "furigana-plain"}}
|
{{#*inline "furigana-plain"}}
|
||||||
|
{{~#if merge~}}
|
||||||
|
{{~#each definition.expressions~}}
|
||||||
|
<span class="expression-{{termFrequency}}">{{~#furiganaPlain}}{{{.}}}{{/furiganaPlain~}}</span>
|
||||||
|
{{~#unless @last}}、{{/unless~}}
|
||||||
|
{{~/each~}}
|
||||||
|
{{~else~}}
|
||||||
{{#furiganaPlain}}{{{definition}}}{{/furiganaPlain}}
|
{{#furiganaPlain}}{{{definition}}}{{/furiganaPlain}}
|
||||||
|
{{~/if~}}
|
||||||
{{/inline}}
|
{{/inline}}
|
||||||
|
|
||||||
{{#*inline "glossary"}}
|
{{#*inline "glossary"}}
|
||||||
@ -71,12 +118,18 @@ function optionsFieldTemplates() {
|
|||||||
{{~else~}}
|
{{~else~}}
|
||||||
{{~#if group~}}
|
{{~#if group~}}
|
||||||
{{~#if definition.definitions.[1]~}}
|
{{~#if definition.definitions.[1]~}}
|
||||||
<ol>{{#each definition.definitions}}<li>{{> glossary-single brief=../brief}}</li>{{/each}}</ol>
|
<ol>{{#each definition.definitions}}<li>{{> glossary-single brief=../brief compactGlossaries=../compactGlossaries}}</li>{{/each}}</ol>
|
||||||
{{~else~}}
|
{{~else~}}
|
||||||
{{~> glossary-single definition.definitions.[0] brief=brief~}}
|
{{~> glossary-single definition.definitions.[0] brief=brief compactGlossaries=compactGlossaries~}}
|
||||||
|
{{~/if~}}
|
||||||
|
{{~else if merge~}}
|
||||||
|
{{~#if definition.definitions.[1]~}}
|
||||||
|
<ol>{{#each definition.definitions}}<li>{{> glossary-single brief=../brief compactGlossaries=../compactGlossaries}}</li>{{/each}}</ol>
|
||||||
|
{{~else~}}
|
||||||
|
{{~> glossary-single definition.definitions.[0] brief=brief compactGlossaries=compactGlossaries~}}
|
||||||
{{~/if~}}
|
{{~/if~}}
|
||||||
{{~else~}}
|
{{~else~}}
|
||||||
{{~> glossary-single definition brief=brief~}}
|
{{~> glossary-single definition brief=brief compactGlossaries=compactGlossaries~}}
|
||||||
{{~/if~}}
|
{{~/if~}}
|
||||||
{{~/if~}}
|
{{~/if~}}
|
||||||
</div>
|
</div>
|
||||||
@ -95,7 +148,16 @@ function optionsFieldTemplates() {
|
|||||||
{{/inline}}
|
{{/inline}}
|
||||||
|
|
||||||
{{#*inline "reading"}}
|
{{#*inline "reading"}}
|
||||||
{{~#unless modeTermKana}}{{definition.reading}}{{/unless~}}
|
{{~#unless modeTermKana~}}
|
||||||
|
{{~#if merge~}}
|
||||||
|
{{~#each definition.reading~}}
|
||||||
|
{{{.}}}
|
||||||
|
{{~#unless @last}}、{{/unless~}}
|
||||||
|
{{~/each~}}
|
||||||
|
{{~else~}}
|
||||||
|
{{~definition.reading~}}
|
||||||
|
{{~/if~}}
|
||||||
|
{{~/unless~}}
|
||||||
{{/inline}}
|
{{/inline}}
|
||||||
|
|
||||||
{{#*inline "sentence"}}
|
{{#*inline "sentence"}}
|
||||||
@ -115,7 +177,7 @@ function optionsFieldTemplates() {
|
|||||||
{{/inline}}
|
{{/inline}}
|
||||||
|
|
||||||
{{#*inline "tags"}}
|
{{#*inline "tags"}}
|
||||||
{{~#each definition.tags}}{{name}}{{#unless @last}}, {{/unless}}{{/each~}}
|
{{~#each definition.definitionTags}}{{name}}{{#unless @last}}, {{/unless}}{{/each~}}
|
||||||
{{/inline}}
|
{{/inline}}
|
||||||
|
|
||||||
{{#*inline "url"}}
|
{{#*inline "url"}}
|
||||||
@ -132,14 +194,17 @@ function optionsSetDefaults(options) {
|
|||||||
enable: true,
|
enable: true,
|
||||||
audioSource: 'jpod101',
|
audioSource: 'jpod101',
|
||||||
audioVolume: 100,
|
audioVolume: 100,
|
||||||
groupResults: true,
|
resultOutputMode: 'group',
|
||||||
debugInfo: false,
|
debugInfo: false,
|
||||||
maxResults: 32,
|
maxResults: 32,
|
||||||
showAdvanced: false,
|
showAdvanced: false,
|
||||||
popupWidth: 400,
|
popupWidth: 400,
|
||||||
popupHeight: 250,
|
popupHeight: 250,
|
||||||
popupOffset: 10,
|
popupOffset: 10,
|
||||||
showGuide: true
|
showGuide: true,
|
||||||
|
compactTags: false,
|
||||||
|
compactGlossaries: false,
|
||||||
|
mainDictionary: ''
|
||||||
},
|
},
|
||||||
|
|
||||||
scanning: {
|
scanning: {
|
||||||
@ -205,6 +270,24 @@ function optionsVersion(options) {
|
|||||||
} else {
|
} else {
|
||||||
options.scanning.modifier = 'none';
|
options.scanning.modifier = 'none';
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
if (options.general.groupResults) {
|
||||||
|
options.general.resultOutputMode = 'group';
|
||||||
|
} else {
|
||||||
|
options.general.resultOutputMode = 'split';
|
||||||
|
}
|
||||||
|
if (utilStringHashCode(options.anki.fieldTemplates) !== -805327496) { // a3c8508031a1073629803d0616a2ee416cd3cccc
|
||||||
|
options.anki.fieldTemplates = `
|
||||||
|
{{#if merge}}
|
||||||
|
${optionsFieldTemplates()}
|
||||||
|
{{else}}
|
||||||
|
${options.anki.fieldTemplates}
|
||||||
|
{{/if}}
|
||||||
|
`.trim();
|
||||||
|
} else {
|
||||||
|
options.anki.fieldTemplates = optionsFieldTemplates();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -22,9 +22,11 @@ async function formRead() {
|
|||||||
const optionsNew = $.extend(true, {}, optionsOld);
|
const optionsNew = $.extend(true, {}, optionsOld);
|
||||||
|
|
||||||
optionsNew.general.showGuide = $('#show-usage-guide').prop('checked');
|
optionsNew.general.showGuide = $('#show-usage-guide').prop('checked');
|
||||||
|
optionsNew.general.compactTags = $('#compact-tags').prop('checked');
|
||||||
|
optionsNew.general.compactGlossaries = $('#compact-glossaries').prop('checked');
|
||||||
|
optionsNew.general.resultOutputMode = $('#result-output-mode').val();
|
||||||
optionsNew.general.audioSource = $('#audio-playback-source').val();
|
optionsNew.general.audioSource = $('#audio-playback-source').val();
|
||||||
optionsNew.general.audioVolume = parseFloat($('#audio-playback-volume').val());
|
optionsNew.general.audioVolume = parseFloat($('#audio-playback-volume').val());
|
||||||
optionsNew.general.groupResults = $('#group-terms-results').prop('checked');
|
|
||||||
optionsNew.general.debugInfo = $('#show-debug-info').prop('checked');
|
optionsNew.general.debugInfo = $('#show-debug-info').prop('checked');
|
||||||
optionsNew.general.showAdvanced = $('#show-advanced-options').prop('checked');
|
optionsNew.general.showAdvanced = $('#show-advanced-options').prop('checked');
|
||||||
optionsNew.general.maxResults = parseInt($('#max-displayed-results').val(), 10);
|
optionsNew.general.maxResults = parseInt($('#max-displayed-results').val(), 10);
|
||||||
@ -55,12 +57,14 @@ async function formRead() {
|
|||||||
optionsNew.anki.kanji.fields = ankiFieldsToDict($('#kanji .anki-field-value'));
|
optionsNew.anki.kanji.fields = ankiFieldsToDict($('#kanji .anki-field-value'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
optionsNew.general.mainDictionary = $('#dict-main').val();
|
||||||
$('.dict-group').each((index, element) => {
|
$('.dict-group').each((index, element) => {
|
||||||
const dictionary = $(element);
|
const dictionary = $(element);
|
||||||
const title = dictionary.data('title');
|
optionsNew.dictionaries[dictionary.data('title')] = {
|
||||||
const priority = parseInt(dictionary.find('.dict-priority').val(), 10);
|
priority: parseInt(dictionary.find('.dict-priority').val(), 10),
|
||||||
const enabled = dictionary.find('.dict-enabled').prop('checked');
|
enabled: dictionary.find('.dict-enabled').prop('checked'),
|
||||||
optionsNew.dictionaries[title] = {priority, enabled};
|
allowSecondarySearches: dictionary.find('.dict-allow-secondary-searches').prop('checked')
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return {optionsNew, optionsOld};
|
return {optionsNew, optionsOld};
|
||||||
@ -81,6 +85,13 @@ function formUpdateVisibility(options) {
|
|||||||
advanced.hide();
|
advanced.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mainGroup = $('#dict-main-group');
|
||||||
|
if (options.general.resultOutputMode === 'merge') {
|
||||||
|
mainGroup.show();
|
||||||
|
} else {
|
||||||
|
mainGroup.hide();
|
||||||
|
}
|
||||||
|
|
||||||
const debug = $('#debug');
|
const debug = $('#debug');
|
||||||
if (options.general.debugInfo) {
|
if (options.general.debugInfo) {
|
||||||
const temp = utilIsolate(options);
|
const temp = utilIsolate(options);
|
||||||
@ -93,17 +104,33 @@ function formUpdateVisibility(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function formMainDictionaryOptionsPopulate(options) {
|
||||||
|
const select = $('#dict-main').empty();
|
||||||
|
select.append($('<option class="text-muted" value="">Not selected</option>'));
|
||||||
|
|
||||||
|
let mainDictionary = '';
|
||||||
|
for (const dictRow of await utilDatabaseSummarize()) {
|
||||||
|
if (dictRow.sequenced) {
|
||||||
|
select.append($(`<option value="${dictRow.title}">${dictRow.title}</option>`));
|
||||||
|
if (dictRow.title === options.general.mainDictionary) {
|
||||||
|
mainDictionary = dictRow.title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select.val(mainDictionary);
|
||||||
|
}
|
||||||
|
|
||||||
async function onFormOptionsChanged(e) {
|
async function onFormOptionsChanged(e) {
|
||||||
try {
|
|
||||||
if (!e.originalEvent && !e.isTrigger) {
|
if (!e.originalEvent && !e.isTrigger) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {optionsNew, optionsOld} = await formRead();
|
const {optionsNew, optionsOld} = await formRead();
|
||||||
await optionsSave(optionsNew);
|
await optionsSave(optionsNew);
|
||||||
|
|
||||||
formUpdateVisibility(optionsNew);
|
formUpdateVisibility(optionsNew);
|
||||||
|
|
||||||
|
try {
|
||||||
const ankiUpdated =
|
const ankiUpdated =
|
||||||
optionsNew.anki.enable !== optionsOld.anki.enable ||
|
optionsNew.anki.enable !== optionsOld.anki.enable ||
|
||||||
optionsNew.anki.server !== optionsOld.anki.server;
|
optionsNew.anki.server !== optionsOld.anki.server;
|
||||||
@ -124,9 +151,11 @@ async function onReady() {
|
|||||||
const options = await optionsLoad();
|
const options = await optionsLoad();
|
||||||
|
|
||||||
$('#show-usage-guide').prop('checked', options.general.showGuide);
|
$('#show-usage-guide').prop('checked', options.general.showGuide);
|
||||||
|
$('#compact-tags').prop('checked', options.general.compactTags);
|
||||||
|
$('#compact-glossaries').prop('checked', options.general.compactGlossaries);
|
||||||
|
$('#result-output-mode').val(options.general.resultOutputMode);
|
||||||
$('#audio-playback-source').val(options.general.audioSource);
|
$('#audio-playback-source').val(options.general.audioSource);
|
||||||
$('#audio-playback-volume').val(options.general.audioVolume);
|
$('#audio-playback-volume').val(options.general.audioVolume);
|
||||||
$('#group-terms-results').prop('checked', options.general.groupResults);
|
|
||||||
$('#show-debug-info').prop('checked', options.general.debugInfo);
|
$('#show-debug-info').prop('checked', options.general.debugInfo);
|
||||||
$('#show-advanced-options').prop('checked', options.general.showAdvanced);
|
$('#show-advanced-options').prop('checked', options.general.showAdvanced);
|
||||||
$('#max-displayed-results').val(options.general.maxResults);
|
$('#max-displayed-results').val(options.general.maxResults);
|
||||||
@ -156,6 +185,7 @@ async function onReady() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await dictionaryGroupsPopulate(options);
|
await dictionaryGroupsPopulate(options);
|
||||||
|
await formMainDictionaryOptionsPopulate(options);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dictionaryErrorShow(e);
|
dictionaryErrorShow(e);
|
||||||
}
|
}
|
||||||
@ -241,19 +271,26 @@ async function dictionaryGroupsPopulate(options) {
|
|||||||
const dictGroups = $('#dict-groups').empty();
|
const dictGroups = $('#dict-groups').empty();
|
||||||
const dictWarning = $('#dict-warning').hide();
|
const dictWarning = $('#dict-warning').hide();
|
||||||
|
|
||||||
const dictRows = await utilDatabaseGetTitles();
|
const dictRows = await utilDatabaseSummarize();
|
||||||
if (dictRows.length === 0) {
|
if (dictRows.length === 0) {
|
||||||
dictWarning.show();
|
dictWarning.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const dictRow of dictRowsSort(dictRows, options)) {
|
for (const dictRow of dictRowsSort(dictRows, options)) {
|
||||||
const dictOptions = options.dictionaries[dictRow.title] || {enabled: false, priority: 0};
|
const dictOptions = options.dictionaries[dictRow.title] || {
|
||||||
|
enabled: false,
|
||||||
|
priority: 0,
|
||||||
|
allowSecondarySearches: false
|
||||||
|
};
|
||||||
|
|
||||||
const dictHtml = await apiTemplateRender('dictionary.html', {
|
const dictHtml = await apiTemplateRender('dictionary.html', {
|
||||||
|
enabled: dictOptions.enabled,
|
||||||
|
priority: dictOptions.priority,
|
||||||
|
allowSecondarySearches: dictOptions.allowSecondarySearches,
|
||||||
title: dictRow.title,
|
title: dictRow.title,
|
||||||
version: dictRow.version,
|
version: dictRow.version,
|
||||||
revision: dictRow.revision,
|
revision: dictRow.revision,
|
||||||
priority: dictOptions.priority,
|
outdated: dictRow.version < 3
|
||||||
enabled: dictOptions.enabled
|
|
||||||
});
|
});
|
||||||
|
|
||||||
dictGroups.append($(dictHtml));
|
dictGroups.append($(dictHtml));
|
||||||
@ -261,7 +298,7 @@ async function dictionaryGroupsPopulate(options) {
|
|||||||
|
|
||||||
formUpdateVisibility(options);
|
formUpdateVisibility(options);
|
||||||
|
|
||||||
$('.dict-enabled, .dict-priority').change(e => {
|
$('.dict-enabled, .dict-priority, .dict-allow-secondary-searches').change(e => {
|
||||||
dictionaryGroupsSort();
|
dictionaryGroupsSort();
|
||||||
onFormOptionsChanged(e);
|
onFormOptionsChanged(e);
|
||||||
});
|
});
|
||||||
@ -270,7 +307,7 @@ async function dictionaryGroupsPopulate(options) {
|
|||||||
async function onDictionaryPurge(e) {
|
async function onDictionaryPurge(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const dictControls = $('#dict-importer, #dict-groups').hide();
|
const dictControls = $('#dict-importer, #dict-groups, #dict-main-group').hide();
|
||||||
const dictProgress = $('#dict-purge').show();
|
const dictProgress = $('#dict-purge').show();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -280,9 +317,11 @@ async function onDictionaryPurge(e) {
|
|||||||
await utilDatabasePurge();
|
await utilDatabasePurge();
|
||||||
const options = await optionsLoad();
|
const options = await optionsLoad();
|
||||||
options.dictionaries = {};
|
options.dictionaries = {};
|
||||||
|
options.general.mainDictionary = '';
|
||||||
await optionsSave(options);
|
await optionsSave(options);
|
||||||
|
|
||||||
await dictionaryGroupsPopulate(options);
|
await dictionaryGroupsPopulate(options);
|
||||||
|
await formMainDictionaryOptionsPopulate(options);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dictionaryErrorShow(e);
|
dictionaryErrorShow(e);
|
||||||
} finally {
|
} finally {
|
||||||
@ -308,10 +347,14 @@ async function onDictionaryImport(e) {
|
|||||||
|
|
||||||
const options = await optionsLoad();
|
const options = await optionsLoad();
|
||||||
const summary = await utilDatabaseImport(e.target.files[0], updateProgress);
|
const summary = await utilDatabaseImport(e.target.files[0], updateProgress);
|
||||||
options.dictionaries[summary.title] = {enabled: true, priority: 0};
|
options.dictionaries[summary.title] = {enabled: true, priority: 0, allowSecondarySearches: false};
|
||||||
|
if (summary.sequenced && options.general.mainDictionary === '') {
|
||||||
|
options.general.mainDictionary = summary.title;
|
||||||
|
}
|
||||||
await optionsSave(options);
|
await optionsSave(options);
|
||||||
|
|
||||||
await dictionaryGroupsPopulate(options);
|
await dictionaryGroupsPopulate(options);
|
||||||
|
await formMainDictionaryOptionsPopulate(options);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dictionaryErrorShow(e);
|
dictionaryErrorShow(e);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
(function() {
|
(function() {
|
||||||
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
|
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
|
||||||
templates['dictionary.html'] = template({"1":function(container,depth0,helpers,partials,data) {
|
templates['dictionary.html'] = template({"1":function(container,depth0,helpers,partials,data) {
|
||||||
|
return " <p class=\"text-warning\">This dictionary is outdated and may not support new extension features; please import the latest version.</p>\n";
|
||||||
|
},"3":function(container,depth0,helpers,partials,data) {
|
||||||
return "checked";
|
return "checked";
|
||||||
},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
|
},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
|
||||||
var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
|
var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
|
||||||
@ -11,9 +13,13 @@ 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)))
|
+ 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."
|
+ " <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)))
|
+ 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=\"checkbox\">\n <label><input type=\"checkbox\" class=\"dict-enabled\" "
|
+ "</small></h4>\n"
|
||||||
+ ((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 : "")
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.outdated : 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 options-advanced\">\n <label for=\"dict-"
|
+ "\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(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ "> Enable search</label>\n </div>\n <div class=\"checkbox options-advanced\">\n <label><input type=\"checkbox\" class=\"dict-allow-secondary-searches\" "
|
||||||
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.allowSecondarySearches : depth0),{"name":"if","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ "> Allow secondary searches</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)))
|
+ 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=\""
|
+ "\">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)))
|
+ 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)))
|
||||||
@ -204,15 +210,20 @@ templates['model.html'] = template({"1":function(container,depth0,helpers,partia
|
|||||||
templates['terms.html'] = template({"1":function(container,depth0,helpers,partials,data) {
|
templates['terms.html'] = template({"1":function(container,depth0,helpers,partials,data) {
|
||||||
var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {});
|
var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {});
|
||||||
|
|
||||||
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 : "")
|
return ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.definitionTags : 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 : "");
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.only : depth0),{"name":"if","hash":{},"fn":container.program(7, 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(11, data, 0),"inverse":container.program(17, data, 0),"data":data})) != null ? stack1 : "");
|
||||||
},"2":function(container,depth0,helpers,partials,data) {
|
},"2":function(container,depth0,helpers,partials,data) {
|
||||||
var stack1;
|
var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {});
|
||||||
|
|
||||||
return "<div>\n"
|
return "<div "
|
||||||
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.tags : depth0),{"name":"each","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.compactGlossaries : depth0),{"name":"if","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ ">\n"
|
||||||
|
+ ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.definitionTags : depth0),{"name":"each","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
+ "</div>\n";
|
+ "</div>\n";
|
||||||
},"3":function(container,depth0,helpers,partials,data) {
|
},"3":function(container,depth0,helpers,partials,data) {
|
||||||
|
return "class=\"compact-info\"";
|
||||||
|
},"5":function(container,depth0,helpers,partials,data) {
|
||||||
var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
|
var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
|
||||||
|
|
||||||
return " <span class=\"label label-default tag-"
|
return " <span class=\"label label-default tag-"
|
||||||
@ -222,88 +233,136 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia
|
|||||||
+ "\">"
|
+ "\">"
|
||||||
+ 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)))
|
+ 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";
|
+ "</span>\n";
|
||||||
},"5":function(container,depth0,helpers,partials,data) {
|
},"7":function(container,depth0,helpers,partials,data) {
|
||||||
|
var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {});
|
||||||
|
|
||||||
|
return "<div "
|
||||||
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.compactGlossaries : depth0),{"name":"if","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ ">\n ("
|
||||||
|
+ ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.only : depth0),{"name":"each","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ " only)\n</div>\n";
|
||||||
|
},"8":function(container,depth0,helpers,partials,data) {
|
||||||
var stack1;
|
var stack1;
|
||||||
|
|
||||||
return "<ul>\n"
|
return ((stack1 = container.lambda(depth0, depth0)) != null ? stack1 : "")
|
||||||
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
+ ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.last),{"name":"unless","hash":{},"fn":container.program(9, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ "\n";
|
||||||
|
},"9":function(container,depth0,helpers,partials,data) {
|
||||||
|
return ", ";
|
||||||
|
},"11":function(container,depth0,helpers,partials,data) {
|
||||||
|
var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {});
|
||||||
|
|
||||||
|
return "<ul "
|
||||||
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.compactGlossaries : depth0),{"name":"if","hash":{},"fn":container.program(12, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ ">\n"
|
||||||
|
+ ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(14, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
+ "</ul>\n";
|
+ "</ul>\n";
|
||||||
},"6":function(container,depth0,helpers,partials,data) {
|
},"12":function(container,depth0,helpers,partials,data) {
|
||||||
|
return "class=\"compact-glossary\"";
|
||||||
|
},"14":function(container,depth0,helpers,partials,data) {
|
||||||
var stack1, helper, options, buffer =
|
var stack1, helper, options, buffer =
|
||||||
" <li><span class=\"glossary-item\">";
|
" <li><span class=\"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 : (container.nullContext || {}),options) : helper));
|
stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(15, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper));
|
||||||
if (!helpers.multiLine) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
|
if (!helpers.multiLine) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
|
||||||
if (stack1 != null) { buffer += stack1; }
|
if (stack1 != null) { buffer += stack1; }
|
||||||
return buffer + "</span></li>\n";
|
return buffer + "</span></li>\n";
|
||||||
},"7":function(container,depth0,helpers,partials,data) {
|
},"15":function(container,depth0,helpers,partials,data) {
|
||||||
return container.escapeExpression(container.lambda(depth0, depth0));
|
return container.escapeExpression(container.lambda(depth0, depth0));
|
||||||
},"9":function(container,depth0,helpers,partials,data) {
|
},"17":function(container,depth0,helpers,partials,data) {
|
||||||
var stack1, helper, options, buffer =
|
var stack1, helper, options, alias1=depth0 != null ? depth0 : (container.nullContext || {}), buffer =
|
||||||
"<div class=\"glossary-item\">";
|
"<div class=\"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 : (container.nullContext || {}),options) : helper));
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.compactGlossaries : depth0),{"name":"if","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ "\">";
|
||||||
|
stack1 = ((helper = (helper = helpers.multiLine || (depth0 != null ? depth0.multiLine : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"multiLine","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(alias1,options) : helper));
|
||||||
if (!helpers.multiLine) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
|
if (!helpers.multiLine) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
|
||||||
if (stack1 != null) { buffer += stack1; }
|
if (stack1 != null) { buffer += stack1; }
|
||||||
return buffer + "</div>\n";
|
return buffer + "</div>\n";
|
||||||
},"10":function(container,depth0,helpers,partials,data) {
|
|
||||||
var stack1;
|
|
||||||
|
|
||||||
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, helper, options, alias1=depth0 != null ? depth0 : (container.nullContext || {}), buffer =
|
|
||||||
"<div class=\"entry\" data-type=\"term\">\n <div class=\"actions\">\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 : "")
|
|
||||||
+ " <img src=\"/mixed/img/entry-current.png\" class=\"current\" title=\"Current entry (Alt + Up/Down/Home/End/PgUp/PgDn)\" alt>\n </div>\n\n <div class=\"expression\">";
|
|
||||||
stack1 = ((helper = (helper = helpers.kanjiLinks || (depth0 != null ? depth0.kanjiLinks : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"kanjiLinks","hash":{},"fn":container.program(17, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(alias1,options) : helper));
|
|
||||||
if (!helpers.kanjiLinks) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
|
|
||||||
if (stack1 != null) { buffer += stack1; }
|
|
||||||
return buffer + "</div>\n\n"
|
|
||||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.reasons : depth0),{"name":"if","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
|
||||||
+ "\n"
|
|
||||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.frequencies : depth0),{"name":"if","hash":{},"fn":container.program(24, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
|
||||||
+ "\n <div class=\"glossary\">\n"
|
|
||||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.grouped : depth0),{"name":"if","hash":{},"fn":container.program(27, data, 0),"inverse":container.program(33, data, 0),"data":data})) != null ? stack1 : "")
|
|
||||||
+ " </div>\n\n"
|
|
||||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.debug : depth0),{"name":"if","hash":{},"fn":container.program(35, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
|
||||||
+ "</div>\n";
|
|
||||||
},"13":function(container,depth0,helpers,partials,data) {
|
|
||||||
return " <a href=\"#\" class=\"action-view-note pending disabled\"><img src=\"/mixed/img/view-note.png\" title=\"View added note (Alt + V)\" alt></a>\n <a href=\"#\" class=\"action-add-note pending disabled\" data-mode=\"term-kanji\"><img src=\"/mixed/img/add-term-kanji.png\" title=\"Add expression (Alt + E)\" alt></a>\n <a href=\"#\" class=\"action-add-note pending disabled\" data-mode=\"term-kana\"><img src=\"/mixed/img/add-term-kana.png\" title=\"Add reading (Alt + R)\" alt></a>\n";
|
|
||||||
},"15":function(container,depth0,helpers,partials,data) {
|
|
||||||
return " <a href=\"#\" class=\"action-play-audio\"><img src=\"/mixed/img/play-audio.png\" title=\"Play audio (Alt + P)\" alt></a>\n";
|
|
||||||
},"17":function(container,depth0,helpers,partials,data) {
|
|
||||||
var stack1, helper, options;
|
|
||||||
|
|
||||||
stack1 = ((helper = (helper = helpers.furigana || (depth0 != null ? depth0.furigana : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"furigana","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper));
|
|
||||||
if (!helpers.furigana) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
|
|
||||||
if (stack1 != null) { return stack1; }
|
|
||||||
else { return ''; }
|
|
||||||
},"18":function(container,depth0,helpers,partials,data) {
|
},"18":function(container,depth0,helpers,partials,data) {
|
||||||
var stack1;
|
return "compact-glossary";
|
||||||
|
|
||||||
return ((stack1 = container.lambda(depth0, depth0)) != null ? stack1 : "");
|
|
||||||
},"20":function(container,depth0,helpers,partials,data) {
|
},"20":function(container,depth0,helpers,partials,data) {
|
||||||
var stack1;
|
var stack1;
|
||||||
|
|
||||||
return " <div class=\"reasons\">\n"
|
return container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["0"] : stack1), depth0));
|
||||||
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.reasons : depth0),{"name":"each","hash":{},"fn":container.program(21, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
},"22":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||||
+ " </div>\n";
|
var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {});
|
||||||
},"21":function(container,depth0,helpers,partials,data) {
|
|
||||||
var stack1;
|
|
||||||
|
|
||||||
return " <span class=\"reasons\">"
|
return "<div class=\"entry\" data-type=\"term\">\n <div class=\"actions\">\n"
|
||||||
+ container.escapeExpression(container.lambda(depth0, depth0))
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.addable : depth0),{"name":"if","hash":{},"fn":container.program(23, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
+ "</span> "
|
+ ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.merged : depth0),{"name":"unless","hash":{},"fn":container.program(25, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
+ ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.last),{"name":"unless","hash":{},"fn":container.program(22, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
+ " <img src=\"/mixed/img/entry-current.png\" class=\"current\" title=\"Current entry (Alt + Up/Down/Home/End/PgUp/PgDn)\" alt>\n </div>\n\n"
|
||||||
+ "\n";
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.merged : depth0),{"name":"if","hash":{},"fn":container.program(28, data, 0, blockParams, depths),"inverse":container.program(43, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "")
|
||||||
},"22":function(container,depth0,helpers,partials,data) {
|
+ "\n"
|
||||||
return "«";
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.reasons : depth0),{"name":"if","hash":{},"fn":container.program(47, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
},"24":function(container,depth0,helpers,partials,data) {
|
+ "\n"
|
||||||
var stack1;
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.frequencies : depth0),{"name":"if","hash":{},"fn":container.program(51, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ "\n <div class=\"glossary\">\n"
|
||||||
return " <div>\n"
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.grouped : depth0),{"name":"if","hash":{},"fn":container.program(54, data, 0, blockParams, depths),"inverse":container.program(60, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "")
|
||||||
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.frequencies : depth0),{"name":"each","hash":{},"fn":container.program(25, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
+ " </div>\n\n"
|
||||||
+ " </div>\n";
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.debug : depth0),{"name":"if","hash":{},"fn":container.program(63, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ "</div>\n";
|
||||||
|
},"23":function(container,depth0,helpers,partials,data) {
|
||||||
|
return " <a href=\"#\" class=\"action-view-note pending disabled\"><img src=\"/mixed/img/view-note.png\" title=\"View added note (Alt + V)\" alt></a>\n <a href=\"#\" class=\"action-add-note pending disabled\" data-mode=\"term-kanji\"><img src=\"/mixed/img/add-term-kanji.png\" title=\"Add expression (Alt + E)\" alt></a>\n <a href=\"#\" class=\"action-add-note pending disabled\" data-mode=\"term-kana\"><img src=\"/mixed/img/add-term-kana.png\" title=\"Add reading (Alt + R)\" alt></a>\n";
|
||||||
},"25":function(container,depth0,helpers,partials,data) {
|
},"25":function(container,depth0,helpers,partials,data) {
|
||||||
|
var stack1;
|
||||||
|
|
||||||
|
return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.playback : depth0),{"name":"if","hash":{},"fn":container.program(26, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
|
||||||
|
},"26":function(container,depth0,helpers,partials,data) {
|
||||||
|
return " <a href=\"#\" class=\"action-play-audio\"><img src=\"/mixed/img/play-audio.png\" title=\"Play audio (Alt + P)\" alt></a>\n";
|
||||||
|
},"28":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||||
|
var stack1;
|
||||||
|
|
||||||
|
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.expressions : depth0),{"name":"each","hash":{},"fn":container.program(29, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
|
||||||
|
},"29":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||||
|
var stack1, helper, options, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", buffer =
|
||||||
|
"<div class=\"expression\">\n <span class=\"expression-"
|
||||||
|
+ container.escapeExpression(((helper = (helper = helpers.termFrequency || (depth0 != null ? depth0.termFrequency : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"termFrequency","hash":{},"data":data}) : helper)))
|
||||||
|
+ "\">";
|
||||||
|
stack1 = ((helper = (helper = helpers.kanjiLinks || (depth0 != null ? depth0.kanjiLinks : depth0)) != null ? helper : alias2),(options={"name":"kanjiLinks","hash":{},"fn":container.program(30, data, 0, blockParams, depths),"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 + "</span>\n <div class=\"peek-wrapper\">"
|
||||||
|
+ ((stack1 = helpers["if"].call(alias1,(depths[1] != null ? depths[1].playback : depths[1]),{"name":"if","hash":{},"fn":container.program(33, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.termTags : depth0),{"name":"if","hash":{},"fn":container.program(35, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.frequencies : depth0),{"name":"if","hash":{},"fn":container.program(38, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ "</div>\n <span class=\""
|
||||||
|
+ ((stack1 = helpers["if"].call(alias1,(data && data.last),{"name":"if","hash":{},"fn":container.program(41, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ "\">、</span>\n </div>";
|
||||||
|
},"30":function(container,depth0,helpers,partials,data) {
|
||||||
|
var stack1, helper, options;
|
||||||
|
|
||||||
|
stack1 = ((helper = (helper = helpers.furigana || (depth0 != null ? depth0.furigana : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"furigana","hash":{},"fn":container.program(31, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper));
|
||||||
|
if (!helpers.furigana) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
|
||||||
|
if (stack1 != null) { return stack1; }
|
||||||
|
else { return ''; }
|
||||||
|
},"31":function(container,depth0,helpers,partials,data) {
|
||||||
|
var stack1;
|
||||||
|
|
||||||
|
return ((stack1 = container.lambda(depth0, depth0)) != null ? stack1 : "");
|
||||||
|
},"33":function(container,depth0,helpers,partials,data) {
|
||||||
|
return "<a href=\"#\" class=\"action-play-audio\"><img src=\"/mixed/img/play-audio.png\" title=\"Play audio\" alt></a>";
|
||||||
|
},"35":function(container,depth0,helpers,partials,data) {
|
||||||
|
var stack1;
|
||||||
|
|
||||||
|
return "<div class=\"tags\">"
|
||||||
|
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.termTags : depth0),{"name":"each","hash":{},"fn":container.program(36, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ "</div>";
|
||||||
|
},"36":function(container,depth0,helpers,partials,data) {
|
||||||
|
var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
|
||||||
|
|
||||||
|
return " <span class=\"label label-default 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";
|
||||||
|
},"38":function(container,depth0,helpers,partials,data) {
|
||||||
|
var stack1;
|
||||||
|
|
||||||
|
return "<div class=\"frequencies\">"
|
||||||
|
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.frequencies : depth0),{"name":"each","hash":{},"fn":container.program(39, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ "</div>";
|
||||||
|
},"39":function(container,depth0,helpers,partials,data) {
|
||||||
var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
|
var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
|
||||||
|
|
||||||
return " <span class=\"label label-default tag-frequency\">"
|
return " <span class=\"label label-default tag-frequency\">"
|
||||||
@ -311,62 +370,123 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia
|
|||||||
+ ":"
|
+ ":"
|
||||||
+ alias4(((helper = (helper = helpers.frequency || (depth0 != null ? depth0.frequency : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"frequency","hash":{},"data":data}) : helper)))
|
+ alias4(((helper = (helper = helpers.frequency || (depth0 != null ? depth0.frequency : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"frequency","hash":{},"data":data}) : helper)))
|
||||||
+ "</span>\n";
|
+ "</span>\n";
|
||||||
},"27":function(container,depth0,helpers,partials,data) {
|
},"41":function(container,depth0,helpers,partials,data) {
|
||||||
|
return "invisible";
|
||||||
|
},"43":function(container,depth0,helpers,partials,data) {
|
||||||
|
var stack1, helper, options, alias1=depth0 != null ? depth0 : (container.nullContext || {}), buffer =
|
||||||
|
" <div class=\"expression\">";
|
||||||
|
stack1 = ((helper = (helper = helpers.kanjiLinks || (depth0 != null ? depth0.kanjiLinks : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"kanjiLinks","hash":{},"fn":container.program(30, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(alias1,options) : helper));
|
||||||
|
if (!helpers.kanjiLinks) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
|
||||||
|
if (stack1 != null) { buffer += stack1; }
|
||||||
|
return buffer + "</div>\n"
|
||||||
|
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.termTags : depth0),{"name":"if","hash":{},"fn":container.program(44, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
|
||||||
|
},"44":function(container,depth0,helpers,partials,data) {
|
||||||
var stack1;
|
var stack1;
|
||||||
|
|
||||||
return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definitions : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(28, data, 0),"inverse":container.program(31, data, 0),"data":data})) != null ? stack1 : "");
|
return " <div style=\"display: inline-block;\">\n"
|
||||||
},"28":function(container,depth0,helpers,partials,data) {
|
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.termTags : depth0),{"name":"each","hash":{},"fn":container.program(45, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ " </div>\n";
|
||||||
|
},"45":function(container,depth0,helpers,partials,data) {
|
||||||
|
var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
|
||||||
|
|
||||||
|
return " <span class=\"label label-default 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";
|
||||||
|
},"47":function(container,depth0,helpers,partials,data) {
|
||||||
|
var stack1;
|
||||||
|
|
||||||
|
return " <div class=\"reasons\">\n"
|
||||||
|
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.reasons : depth0),{"name":"each","hash":{},"fn":container.program(48, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ " </div>\n";
|
||||||
|
},"48":function(container,depth0,helpers,partials,data) {
|
||||||
|
var stack1;
|
||||||
|
|
||||||
|
return " <span class=\"reasons\">"
|
||||||
|
+ container.escapeExpression(container.lambda(depth0, depth0))
|
||||||
|
+ "</span> "
|
||||||
|
+ ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.last),{"name":"unless","hash":{},"fn":container.program(49, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ "\n";
|
||||||
|
},"49":function(container,depth0,helpers,partials,data) {
|
||||||
|
return "«";
|
||||||
|
},"51":function(container,depth0,helpers,partials,data) {
|
||||||
|
var stack1;
|
||||||
|
|
||||||
|
return " <div>\n"
|
||||||
|
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.frequencies : depth0),{"name":"each","hash":{},"fn":container.program(52, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
|
+ " </div>\n";
|
||||||
|
},"52":function(container,depth0,helpers,partials,data) {
|
||||||
|
var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
|
||||||
|
|
||||||
|
return " <span class=\"label label-default tag-frequency\">"
|
||||||
|
+ alias4(((helper = (helper = helpers.dictionary || (depth0 != null ? depth0.dictionary : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"dictionary","hash":{},"data":data}) : helper)))
|
||||||
|
+ ":"
|
||||||
|
+ alias4(((helper = (helper = helpers.frequency || (depth0 != null ? depth0.frequency : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"frequency","hash":{},"data":data}) : helper)))
|
||||||
|
+ "</span>\n";
|
||||||
|
},"54":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||||
|
var stack1;
|
||||||
|
|
||||||
|
return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definitions : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(55, data, 0, blockParams, depths),"inverse":container.program(58, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
|
||||||
|
},"55":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||||
var stack1;
|
var stack1;
|
||||||
|
|
||||||
return " <ol>\n"
|
return " <ol>\n"
|
||||||
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(29, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(56, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
+ " </ol>\n";
|
+ " </ol>\n";
|
||||||
},"29":function(container,depth0,helpers,partials,data) {
|
},"56":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||||
var stack1;
|
var stack1;
|
||||||
|
|
||||||
return " <li>"
|
return " <li>"
|
||||||
+ ((stack1 = container.invokePartial(partials.definition,depth0,{"name":"definition","data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
|
+ ((stack1 = container.invokePartial(partials.definition,depth0,{"name":"definition","hash":{"compactGlossaries":(depths[1] != null ? depths[1].compactGlossaries : depths[1])},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
|
||||||
+ "</li>\n";
|
+ "</li>\n";
|
||||||
},"31":function(container,depth0,helpers,partials,data) {
|
},"58":function(container,depth0,helpers,partials,data) {
|
||||||
var stack1;
|
var stack1;
|
||||||
|
|
||||||
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 : "");
|
return ((stack1 = container.invokePartial(partials.definition,((stack1 = (depth0 != null ? depth0.definitions : depth0)) != null ? stack1["0"] : stack1),{"name":"definition","hash":{"compactGlossaries":(depth0 != null ? depth0.compactGlossaries : depth0)},"data":data,"indent":" ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
|
||||||
},"33":function(container,depth0,helpers,partials,data) {
|
},"60":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||||
var stack1;
|
var stack1;
|
||||||
|
|
||||||
return ((stack1 = container.invokePartial(partials.definition,depth0,{"name":"definition","data":data,"indent":" ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
|
return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.merged : depth0),{"name":"if","hash":{},"fn":container.program(54, data, 0, blockParams, depths),"inverse":container.program(61, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
|
||||||
},"35":function(container,depth0,helpers,partials,data) {
|
},"61":function(container,depth0,helpers,partials,data) {
|
||||||
|
var stack1;
|
||||||
|
|
||||||
|
return ((stack1 = container.invokePartial(partials.definition,depth0,{"name":"definition","hash":{"compactGlossaries":(depth0 != null ? depth0.compactGlossaries : depth0)},"data":data,"indent":" ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
|
||||||
|
+ " ";
|
||||||
|
},"63":function(container,depth0,helpers,partials,data) {
|
||||||
var stack1, helper, options, buffer =
|
var stack1, helper, options, buffer =
|
||||||
" <pre>";
|
" <pre>";
|
||||||
stack1 = ((helper = (helper = helpers.dumpObject || (depth0 != null ? depth0.dumpObject : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"dumpObject","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper));
|
stack1 = ((helper = (helper = helpers.dumpObject || (depth0 != null ? depth0.dumpObject : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"dumpObject","hash":{},"fn":container.program(31, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper));
|
||||||
if (!helpers.dumpObject) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
|
if (!helpers.dumpObject) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
|
||||||
if (stack1 != null) { buffer += stack1; }
|
if (stack1 != null) { buffer += stack1; }
|
||||||
return buffer + "</pre>\n";
|
return buffer + "</pre>\n";
|
||||||
},"37":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
},"65":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||||
var stack1;
|
var stack1;
|
||||||
|
|
||||||
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(38, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
|
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(66, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
|
||||||
},"38":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
},"66":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||||
var stack1;
|
var stack1;
|
||||||
|
|
||||||
return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.first),{"name":"unless","hash":{},"fn":container.program(39, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.first),{"name":"unless","hash":{},"fn":container.program(67, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||||
+ "\n"
|
+ "\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]),"debug":(depths[1] != null ? depths[1].debug : depths[1])},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
|
+ ((stack1 = container.invokePartial(partials.term,depth0,{"name":"term","hash":{"compactGlossaries":(depths[1] != null ? depths[1].compactGlossaries : depths[1]),"playback":(depths[1] != null ? depths[1].playback : depths[1]),"addable":(depths[1] != null ? depths[1].addable : depths[1]),"merged":(depths[1] != null ? depths[1].merged : depths[1]),"grouped":(depths[1] != null ? depths[1].grouped : depths[1]),"debug":(depths[1] != null ? depths[1].debug : depths[1])},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
|
||||||
},"39":function(container,depth0,helpers,partials,data) {
|
},"67":function(container,depth0,helpers,partials,data) {
|
||||||
return "<hr>";
|
return "<hr>";
|
||||||
},"41":function(container,depth0,helpers,partials,data) {
|
},"69":function(container,depth0,helpers,partials,data) {
|
||||||
return "<p class=\"note\">No results found.</p>\n";
|
return "<p class=\"note\">No results found.</p>\n";
|
||||||
},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||||
var stack1;
|
var stack1;
|
||||||
|
|
||||||
return "\n\n"
|
return "\n\n"
|
||||||
+ ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(37, data, 0, blockParams, depths),"inverse":container.program(41, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
|
+ ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(65, data, 0, blockParams, depths),"inverse":container.program(69, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
|
||||||
},"main_d": function(fn, props, container, depth0, data, blockParams, depths) {
|
},"main_d": function(fn, props, container, depth0, data, blockParams, depths) {
|
||||||
|
|
||||||
var decorators = container.decorators;
|
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(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;
|
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(22, data, 0, blockParams, depths),"inverse":container.noop,"args":["term"],"data":data}) || fn;
|
||||||
return fn;
|
return fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ class Translator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async findTermsGrouped(text, dictionaries, alphanumeric) {
|
async findTermsGrouped(text, dictionaries, alphanumeric) {
|
||||||
|
const options = await apiOptionsGet();
|
||||||
const titles = Object.keys(dictionaries);
|
const titles = Object.keys(dictionaries);
|
||||||
const {length, definitions} = await this.findTerms(text, dictionaries, alphanumeric);
|
const {length, definitions} = await this.findTerms(text, dictionaries, alphanumeric);
|
||||||
|
|
||||||
@ -45,9 +46,118 @@ class Translator {
|
|||||||
await this.buildTermFrequencies(definition, titles);
|
await this.buildTermFrequencies(definition, titles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.general.compactTags) {
|
||||||
|
for (const definition of definitionsGrouped) {
|
||||||
|
dictTermsCompressTags(definition.definitions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {length, definitions: definitionsGrouped};
|
return {length, definitions: definitionsGrouped};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findTermsMerged(text, dictionaries, alphanumeric) {
|
||||||
|
const options = await apiOptionsGet();
|
||||||
|
const secondarySearchTitles = Object.keys(options.dictionaries).filter(dict => options.dictionaries[dict].allowSecondarySearches);
|
||||||
|
const titles = Object.keys(dictionaries);
|
||||||
|
const {length, definitions} = await this.findTerms(text, dictionaries, alphanumeric);
|
||||||
|
|
||||||
|
const definitionsBySequence = dictTermsMergeBySequence(definitions, options.general.mainDictionary);
|
||||||
|
|
||||||
|
const definitionsMerged = [];
|
||||||
|
const mergedByTermIndices = new Set();
|
||||||
|
for (const sequence in definitionsBySequence) {
|
||||||
|
if (sequence < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = definitionsBySequence[sequence];
|
||||||
|
|
||||||
|
const rawDefinitionsBySequence = await this.database.findTermsBySequence(Number(sequence), options.general.mainDictionary);
|
||||||
|
|
||||||
|
for (const definition of rawDefinitionsBySequence) {
|
||||||
|
const tags = await this.expandTags(definition.definitionTags, definition.dictionary);
|
||||||
|
tags.push(dictTagBuildSource(definition.dictionary));
|
||||||
|
definition.definitionTags = tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
const definitionsByGloss = dictTermsMergeByGloss(result, rawDefinitionsBySequence);
|
||||||
|
|
||||||
|
const secondarySearchResults = [];
|
||||||
|
if (secondarySearchTitles.length > 0) {
|
||||||
|
for (const expression of result.expressions.keys()) {
|
||||||
|
if (expression === text) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const reading of result.expressions.get(expression).keys()) {
|
||||||
|
for (const definition of await this.database.findTermsExact(expression, reading, secondarySearchTitles)) {
|
||||||
|
const tags = await this.expandTags(definition.definitionTags, definition.dictionary);
|
||||||
|
tags.push(dictTagBuildSource(definition.dictionary));
|
||||||
|
definition.definitionTags = tags;
|
||||||
|
secondarySearchResults.push(definition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dictTermsMergeByGloss(result, definitionsBySequence['-1'].concat(secondarySearchResults), definitionsByGloss, mergedByTermIndices);
|
||||||
|
|
||||||
|
for (const gloss in definitionsByGloss) {
|
||||||
|
const definition = definitionsByGloss[gloss];
|
||||||
|
dictTagsSort(definition.definitionTags);
|
||||||
|
result.definitions.push(definition);
|
||||||
|
}
|
||||||
|
|
||||||
|
dictTermsSort(result.definitions, dictionaries);
|
||||||
|
|
||||||
|
const expressions = [];
|
||||||
|
for (const expression of result.expressions.keys()) {
|
||||||
|
for (const reading of result.expressions.get(expression).keys()) {
|
||||||
|
const tags = await this.expandTags(result.expressions.get(expression).get(reading), result.dictionary);
|
||||||
|
expressions.push({
|
||||||
|
expression: expression,
|
||||||
|
reading: reading,
|
||||||
|
termTags: dictTagsSort(tags),
|
||||||
|
termFrequency: (score => {
|
||||||
|
if (score > 0) {
|
||||||
|
return 'popular';
|
||||||
|
} else if (score < 0) {
|
||||||
|
return 'rare';
|
||||||
|
} else {
|
||||||
|
return 'normal';
|
||||||
|
}
|
||||||
|
})(tags.map(tag => tag.score).reduce((p, v) => p + v, 0))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.expressions = expressions;
|
||||||
|
|
||||||
|
result.expression = Array.from(result.expression);
|
||||||
|
result.reading = Array.from(result.reading);
|
||||||
|
|
||||||
|
definitionsMerged.push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
const strayDefinitions = definitionsBySequence['-1'].filter((definition, index) => !mergedByTermIndices.has(index));
|
||||||
|
for (const groupedDefinition of dictTermsGroup(strayDefinitions, dictionaries)) {
|
||||||
|
groupedDefinition.expressions = [{expression: groupedDefinition.expression, reading: groupedDefinition.reading}];
|
||||||
|
definitionsMerged.push(groupedDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const definition of definitionsMerged) {
|
||||||
|
await this.buildTermFrequencies(definition, titles);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.general.compactTags) {
|
||||||
|
for (const definition of definitionsMerged) {
|
||||||
|
dictTermsCompressTags(definition.definitions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {length, definitions: dictTermsSort(definitionsMerged)};
|
||||||
|
}
|
||||||
|
|
||||||
async findTermsSplit(text, dictionaries, alphanumeric) {
|
async findTermsSplit(text, dictionaries, alphanumeric) {
|
||||||
const titles = Object.keys(dictionaries);
|
const titles = Object.keys(dictionaries);
|
||||||
const {length, definitions} = await this.findTerms(text, dictionaries, alphanumeric);
|
const {length, definitions} = await this.findTerms(text, dictionaries, alphanumeric);
|
||||||
@ -78,8 +188,9 @@ class Translator {
|
|||||||
let definitions = [];
|
let definitions = [];
|
||||||
for (const deinflection of deinflections) {
|
for (const deinflection of deinflections) {
|
||||||
for (const definition of deinflection.definitions) {
|
for (const definition of deinflection.definitions) {
|
||||||
const tags = await this.expandTags(definition.tags, definition.dictionary);
|
const definitionTags = await this.expandTags(definition.definitionTags, definition.dictionary);
|
||||||
tags.push(dictTagBuildSource(definition.dictionary));
|
definitionTags.push(dictTagBuildSource(definition.dictionary));
|
||||||
|
const termTags = await this.expandTags(definition.termTags, definition.dictionary);
|
||||||
|
|
||||||
definitions.push({
|
definitions.push({
|
||||||
source: deinflection.source,
|
source: deinflection.source,
|
||||||
@ -90,7 +201,9 @@ class Translator {
|
|||||||
expression: definition.expression,
|
expression: definition.expression,
|
||||||
reading: definition.reading,
|
reading: definition.reading,
|
||||||
glossary: definition.glossary,
|
glossary: definition.glossary,
|
||||||
tags: dictTagsSort(tags)
|
definitionTags: dictTagsSort(definitionTags),
|
||||||
|
termTags: dictTagsSort(termTags),
|
||||||
|
sequence: definition.sequence
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,10 +271,18 @@ class Translator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async buildTermFrequencies(definition, titles) {
|
async buildTermFrequencies(definition, titles) {
|
||||||
definition.frequencies = [];
|
let terms = [];
|
||||||
for (const meta of await this.database.findTermMeta(definition.expression, titles)) {
|
if (definition.expressions) {
|
||||||
|
terms = terms.concat(definition.expressions);
|
||||||
|
} else {
|
||||||
|
terms.push(definition);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const term of terms) {
|
||||||
|
term.frequencies = [];
|
||||||
|
for (const meta of await this.database.findTermMeta(term.expression, titles)) {
|
||||||
if (meta.mode === 'freq') {
|
if (meta.mode === 'freq') {
|
||||||
definition.frequencies.push({
|
term.frequencies.push({
|
||||||
expression: meta.expression,
|
expression: meta.expression,
|
||||||
frequency: meta.data,
|
frequency: meta.data,
|
||||||
dictionary: meta.dictionary
|
dictionary: meta.dictionary
|
||||||
@ -169,6 +290,7 @@ class Translator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async expandTags(names, title) {
|
async expandTags(names, title) {
|
||||||
const tags = [];
|
const tags = [];
|
||||||
|
@ -26,6 +26,43 @@ function utilIsolate(data) {
|
|||||||
return JSON.parse(JSON.stringify(data));
|
return JSON.parse(JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function utilSetEqual(setA, setB) {
|
||||||
|
if (setA.size !== setB.size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const value of setA) {
|
||||||
|
if (!setB.has(value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function utilSetIntersection(setA, setB) {
|
||||||
|
return new Set(
|
||||||
|
[...setA].filter(value => setB.has(value))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function utilSetDifference(setA, setB) {
|
||||||
|
return new Set(
|
||||||
|
[...setA].filter(value => !setB.has(value))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function utilStringHashCode(string) {
|
||||||
|
let hashCode = 0;
|
||||||
|
|
||||||
|
for (let i = 0, charCode = string.charCodeAt(i); i < string.length; charCode = string.charCodeAt(++i)) {
|
||||||
|
hashCode = ((hashCode << 5) - hashCode) + charCode;
|
||||||
|
hashCode |= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
function utilBackend() {
|
function utilBackend() {
|
||||||
return chrome.extension.getBackgroundPage().yomichan_backend;
|
return chrome.extension.getBackgroundPage().yomichan_backend;
|
||||||
}
|
}
|
||||||
@ -38,12 +75,12 @@ function utilAnkiGetDeckNames() {
|
|||||||
return utilBackend().anki.getDeckNames();
|
return utilBackend().anki.getDeckNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
function utilAnkiGetModelFieldNames(modelName) {
|
function utilDatabaseSummarize() {
|
||||||
return utilBackend().anki.getModelFieldNames(modelName);
|
return utilBackend().translator.database.summarize();
|
||||||
}
|
}
|
||||||
|
|
||||||
function utilDatabaseGetTitles() {
|
function utilAnkiGetModelFieldNames(modelName) {
|
||||||
return utilBackend().translator.database.getTitles();
|
return utilBackend().anki.getModelFieldNames(modelName);
|
||||||
}
|
}
|
||||||
|
|
||||||
function utilDatabasePurge() {
|
function utilDatabasePurge() {
|
||||||
|
@ -36,7 +36,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label><input type="checkbox" id="group-terms-results"> Group term results</label>
|
<label><input type="checkbox" id="compact-tags"> Compact tags</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="checkbox">
|
||||||
|
<label><input type="checkbox" id="compact-glossaries"> Compact glossaries</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
@ -47,6 +51,15 @@
|
|||||||
<label><input type="checkbox" id="show-debug-info"> Show debug information</label>
|
<label><input type="checkbox" id="show-debug-info"> Show debug information</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="result-output-mode">Result grouping</label>
|
||||||
|
<select class="form-control" id="result-output-mode">
|
||||||
|
<option value="group">Group results by term-reading pairs</option>
|
||||||
|
<option value="merge">Group results by main dictionary entry</option>
|
||||||
|
<option value="split">Split definitions to their own results</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="audio-playback-source">Audio playback source</label>
|
<label for="audio-playback-source">Audio playback source</label>
|
||||||
<select class="form-control" id="audio-playback-source">
|
<select class="form-control" id="audio-playback-source">
|
||||||
@ -132,10 +145,14 @@
|
|||||||
or you can simply <a href="#" id="dict-purge-link">purge the database</a> to delete everything.
|
or you can simply <a href="#" id="dict-purge-link">purge the database</a> to delete everything.
|
||||||
</p>
|
</p>
|
||||||
<p class="help-block">
|
<p class="help-block">
|
||||||
Please visit the <a href="https://foosoft.net/projects/yomichan" target="_blank">Yomichan</a> homepage to download free
|
Deleting individual dictionaries is not currently feasible due to limitations of browser database technology.
|
||||||
dictionaries that you can use with this extension.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div class="form-group" id="dict-main-group">
|
||||||
|
<label for="dict-main">Main dictionary for merged mode</label>
|
||||||
|
<select class="form-control" id="dict-main"></select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="text-danger" id="dict-purge">Dictionary data is being purged, please be patient...</div>
|
<div class="text-danger" id="dict-purge">Dictionary data is being purged, please be patient...</div>
|
||||||
<div class="alert alert-warning" id="dict-warning">No dictionaries have been installed</div>
|
<div class="alert alert-warning" id="dict-warning">No dictionaries have been installed</div>
|
||||||
<div class="alert alert-danger" id="dict-error"></div>
|
<div class="alert alert-danger" id="dict-error"></div>
|
||||||
@ -150,6 +167,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="dict-importer">
|
<div id="dict-importer">
|
||||||
|
<p class="help-block">
|
||||||
|
Select a dictionary to import for use below. Please visit the Yomichan homepage to
|
||||||
|
<a href="https://foosoft.net/projects/yomichan" target="_blank">download free dictionaries</a>
|
||||||
|
for use with this extension and to learn about importing proprietary EPWING dictionaries.
|
||||||
|
</p>
|
||||||
<input type="file" id="dict-file">
|
<input type="file" id="dict-file">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -76,7 +76,7 @@ function docRangeFromPoint(point) {
|
|||||||
if (!document.caretRangeFromPoint) {
|
if (!document.caretRangeFromPoint) {
|
||||||
document.caretRangeFromPoint = (x, y) => {
|
document.caretRangeFromPoint = (x, y) => {
|
||||||
const position = document.caretPositionFromPoint(x,y);
|
const position = document.caretPositionFromPoint(x,y);
|
||||||
if (position && position.offsetNode) {
|
if (position && position.offsetNode && position.offsetNode.nodeType === Node.TEXT_NODE) {
|
||||||
const range = document.createRange();
|
const range = document.createRange();
|
||||||
range.setStart(position.offsetNode, position.offset);
|
range.setStart(position.offsetNode, position.offset);
|
||||||
range.setEnd(position.offsetNode, position.offset);
|
range.setEnd(position.offsetNode, position.offset);
|
||||||
@ -86,7 +86,7 @@ function docRangeFromPoint(point) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const range = document.caretRangeFromPoint(point.x, point.y);
|
const range = document.caretRangeFromPoint(point.x, point.y);
|
||||||
if (range && range.startContainer.nodeType === 3 && range.endContainer.nodeType === 3) {
|
if (range) {
|
||||||
return new TextSourceRange(range);
|
return new TextSourceRange(range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "Yomichan",
|
"name": "Yomichan",
|
||||||
"version": "1.4.0",
|
"version": "1.5.0",
|
||||||
|
|
||||||
"description": "Japanese dictionary with Anki integration",
|
"description": "Japanese dictionary with Anki integration",
|
||||||
"icons": {"16": "mixed/img/icon16.png", "48": "mixed/img/icon48.png", "128": "mixed/img/icon128.png"},
|
"icons": {"16": "mixed/img/icon16.png", "48": "mixed/img/icon48.png", "128": "mixed/img/icon128.png"},
|
||||||
|
@ -46,6 +46,10 @@ hr {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.invisible {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Entries
|
* Entries
|
||||||
@ -88,6 +92,10 @@ hr {
|
|||||||
background-color: #5cb85c;
|
background-color: #5cb85c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tag-partOfSpeech {
|
||||||
|
background-color: #565656;
|
||||||
|
}
|
||||||
|
|
||||||
.actions .disabled {
|
.actions .disabled {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
@ -118,21 +126,79 @@ hr {
|
|||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.expression a {
|
.expression .kanji-link {
|
||||||
border-bottom: 1px #777 dashed;
|
border-bottom: 1px #777 dashed;
|
||||||
color: #333;
|
color: #333;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.expression-popular, .expression-popular .kanji-link {
|
||||||
|
color: #0275d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expression-rare, .expression-rare .kanji-link {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expression .peek-wrapper {
|
||||||
|
font-size: 14px;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
width: 0px;
|
||||||
|
height: 0px;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expression .peek-wrapper .action-play-audio {
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expression .peek-wrapper .tags {
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
bottom: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expression .peek-wrapper .frequencies {
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
bottom: -30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expression:hover .peek-wrapper {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
.reasons {
|
.reasons {
|
||||||
color: #777;
|
color: #777;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.compact-info {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
.glossary ol, .glossary ul {
|
.glossary ol, .glossary ul {
|
||||||
padding-left: 1.4em;
|
padding-left: 1.4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.glossary ul.compact-glossary {
|
||||||
|
display: inline;
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glossary .compact-glossary li {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glossary .compact-glossary li:not(:first-child):before {
|
||||||
|
content: " | ";
|
||||||
|
}
|
||||||
|
|
||||||
.glossary li {
|
.glossary li {
|
||||||
color: #777;
|
color: #777;
|
||||||
}
|
}
|
||||||
@ -141,6 +207,10 @@ hr {
|
|||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.glossary-item.compact-glossary {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
.glyph {
|
.glyph {
|
||||||
font-family: kanji-stroke-orders;
|
font-family: kanji-stroke-orders;
|
||||||
font-size: 120px;
|
font-size: 120px;
|
||||||
|
@ -29,6 +29,7 @@ class Display {
|
|||||||
this.audioCache = {};
|
this.audioCache = {};
|
||||||
|
|
||||||
$(document).keydown(this.onKeyDown.bind(this));
|
$(document).keydown(this.onKeyDown.bind(this));
|
||||||
|
$(document).on('wheel', this.onWheel.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
onError(error) {
|
onError(error) {
|
||||||
@ -70,8 +71,10 @@ class Display {
|
|||||||
|
|
||||||
onAudioPlay(e) {
|
onAudioPlay(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const index = Display.entryIndexFind($(e.currentTarget));
|
const link = $(e.currentTarget);
|
||||||
this.audioPlay(this.definitions[index]);
|
const definitionIndex = Display.entryIndexFind(link);
|
||||||
|
const expressionIndex = link.closest('.entry').find('.expression .action-play-audio').index(link);
|
||||||
|
this.audioPlay(this.definitions[definitionIndex], expressionIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
onNoteAdd(e) {
|
onNoteAdd(e) {
|
||||||
@ -182,7 +185,8 @@ class Display {
|
|||||||
80: /* p */ () => {
|
80: /* p */ () => {
|
||||||
if (e.altKey) {
|
if (e.altKey) {
|
||||||
if ($('.entry').eq(this.index).data('type') === 'term') {
|
if ($('.entry').eq(this.index).data('type') === 'term') {
|
||||||
this.audioPlay(this.definitions[this.index]);
|
const expressionIndex = this.options.general.resultOutputMode === 'merge' ? 0 : -1;
|
||||||
|
this.audioPlay(this.definitions[this.index], expressionIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -202,6 +206,25 @@ class Display {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onWheel(e) {
|
||||||
|
const event = e.originalEvent;
|
||||||
|
const handler = () => {
|
||||||
|
if (event.altKey) {
|
||||||
|
if (event.deltaY < 0) { // scroll up
|
||||||
|
this.entryScrollIntoView(this.index - 1, true);
|
||||||
|
return true;
|
||||||
|
} else if (event.deltaY > 0) { // scroll down
|
||||||
|
this.entryScrollIntoView(this.index + 1, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (handler()) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async termsShow(definitions, options, context) {
|
async termsShow(definitions, options, context) {
|
||||||
try {
|
try {
|
||||||
window.focus();
|
window.focus();
|
||||||
@ -214,8 +237,10 @@ class Display {
|
|||||||
const params = {
|
const params = {
|
||||||
definitions,
|
definitions,
|
||||||
addable: options.anki.enable,
|
addable: options.anki.enable,
|
||||||
grouped: options.general.groupResults,
|
grouped: options.general.resultOutputMode === 'group',
|
||||||
|
merged: options.general.resultOutputMode === 'merge',
|
||||||
playback: options.general.audioSource !== 'disabled',
|
playback: options.general.audioSource !== 'disabled',
|
||||||
|
compactGlossaries: options.general.compactGlossaries,
|
||||||
debug: options.general.debugInfo
|
debug: options.general.debugInfo
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -359,11 +384,12 @@ class Display {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async audioPlay(definition) {
|
async audioPlay(definition, expressionIndex) {
|
||||||
try {
|
try {
|
||||||
this.spinner.show();
|
this.spinner.show();
|
||||||
|
|
||||||
let url = await apiAudioGetUrl(definition, this.options.general.audioSource);
|
const expression = expressionIndex === -1 ? definition : definition.expressions[expressionIndex];
|
||||||
|
let url = await apiAudioGetUrl(expression, this.options.general.audioSource);
|
||||||
if (!url) {
|
if (!url) {
|
||||||
url = '/mixed/mp3/button.mp3';
|
url = '/mixed/mp3/button.mp3';
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
<div class="dict-group well well-sm" data-title="{{title}}">
|
<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>
|
<h4><span class="text-muted glyphicon glyphicon-book"></span> {{title}} <small>rev.{{revision}}</small></h4>
|
||||||
|
{{#if outdated}}
|
||||||
|
<p class="text-warning">This dictionary is outdated and may not support new extension features; please import the latest version.</p>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label><input type="checkbox" class="dict-enabled" {{#if enabled}}checked{{/if}}> Enable search</label>
|
<label><input type="checkbox" class="dict-enabled" {{#if enabled}}checked{{/if}}> Enable search</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="checkbox options-advanced">
|
||||||
|
<label><input type="checkbox" class="dict-allow-secondary-searches" {{#if allowSecondarySearches}}checked{{/if}}> Allow secondary searches</label>
|
||||||
|
</div>
|
||||||
<div class="form-group options-advanced">
|
<div class="form-group options-advanced">
|
||||||
<label for="dict-{{title}}">Result priority</label>
|
<label for="dict-{{title}}">Result priority</label>
|
||||||
<input type="number" value="{{priority}}" id="dict-{{title}}" class="form-control dict-priority">
|
<input type="number" value="{{priority}}" id="dict-{{title}}" class="form-control dict-priority">
|
||||||
|
@ -1,19 +1,28 @@
|
|||||||
{{#*inline "definition"}}
|
{{#*inline "definition"}}
|
||||||
{{#if tags}}
|
{{#if definitionTags}}
|
||||||
<div>
|
<div {{#if compactGlossaries}}class="compact-info"{{/if}}>
|
||||||
{{#each tags}}
|
{{#each definitionTags}}
|
||||||
<span class="label label-default tag-{{category}}" title="{{notes}}">{{name}}</span>
|
<span class="label label-default tag-{{category}}" title="{{notes}}">{{name}}</span>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
{{#if only}}
|
||||||
|
<div {{#if compactGlossaries}}class="compact-info"{{/if}}>
|
||||||
|
(
|
||||||
|
{{~#each only~}}
|
||||||
|
{{{.}}}{{#unless @last}}, {{/unless}}
|
||||||
|
{{/each}}
|
||||||
|
only)
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
{{#if glossary.[1]}}
|
{{#if glossary.[1]}}
|
||||||
<ul>
|
<ul {{#if compactGlossaries}}class="compact-glossary"{{/if}}>
|
||||||
{{#each glossary}}
|
{{#each glossary}}
|
||||||
<li><span class="glossary-item">{{#multiLine}}{{.}}{{/multiLine}}</span></li>
|
<li><span class="glossary-item">{{#multiLine}}{{.}}{{/multiLine}}</span></li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="glossary-item">{{#multiLine}}{{glossary.[0]}}{{/multiLine}}</div>
|
<div class="glossary-item {{#if compactGlossaries}}compact-glossary{{/if}}">{{#multiLine}}{{glossary.[0]}}{{/multiLine}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/inline}}
|
{{/inline}}
|
||||||
|
|
||||||
@ -25,13 +34,50 @@
|
|||||||
<a href="#" class="action-add-note pending disabled" data-mode="term-kanji"><img src="/mixed/img/add-term-kanji.png" title="Add expression (Alt + E)" alt></a>
|
<a href="#" class="action-add-note pending disabled" data-mode="term-kanji"><img src="/mixed/img/add-term-kanji.png" title="Add expression (Alt + E)" alt></a>
|
||||||
<a href="#" class="action-add-note pending disabled" data-mode="term-kana"><img src="/mixed/img/add-term-kana.png" title="Add reading (Alt + R)" alt></a>
|
<a href="#" class="action-add-note pending disabled" data-mode="term-kana"><img src="/mixed/img/add-term-kana.png" title="Add reading (Alt + R)" alt></a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
{{#unless merged}}
|
||||||
{{#if playback}}
|
{{#if playback}}
|
||||||
<a href="#" class="action-play-audio"><img src="/mixed/img/play-audio.png" title="Play audio (Alt + P)" alt></a>
|
<a href="#" class="action-play-audio"><img src="/mixed/img/play-audio.png" title="Play audio (Alt + P)" alt></a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
{{/unless}}
|
||||||
<img src="/mixed/img/entry-current.png" class="current" title="Current entry (Alt + Up/Down/Home/End/PgUp/PgDn)" alt>
|
<img src="/mixed/img/entry-current.png" class="current" title="Current entry (Alt + Up/Down/Home/End/PgUp/PgDn)" alt>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{#if merged}}
|
||||||
|
{{~#each expressions~}}
|
||||||
|
<div class="expression">
|
||||||
|
<span class="expression-{{termFrequency}}">{{#kanjiLinks}}{{#furigana}}{{{.}}}{{/furigana}}{{/kanjiLinks}}</span>
|
||||||
|
<div class="peek-wrapper">
|
||||||
|
{{~#if ../playback~}}
|
||||||
|
<a href="#" class="action-play-audio"><img src="/mixed/img/play-audio.png" title="Play audio" alt></a>
|
||||||
|
{{~/if~}}
|
||||||
|
{{~#if termTags~}}
|
||||||
|
<div class="tags">
|
||||||
|
{{~#each termTags}}
|
||||||
|
<span class="label label-default tag-{{category}}" title="{{notes}}">{{name}}</span>
|
||||||
|
{{/each~}}
|
||||||
|
</div>
|
||||||
|
{{~/if~}}
|
||||||
|
{{~#if frequencies~}}
|
||||||
|
<div class="frequencies">
|
||||||
|
{{~#each frequencies}}
|
||||||
|
<span class="label label-default tag-frequency">{{dictionary}}:{{frequency}}</span>
|
||||||
|
{{/each~}}
|
||||||
|
</div>
|
||||||
|
{{~/if~}}
|
||||||
|
</div>
|
||||||
|
<span class="{{#if @last}}invisible{{/if}}">、</span>
|
||||||
|
</div>
|
||||||
|
{{~/each~}}
|
||||||
|
{{else}}
|
||||||
<div class="expression">{{#kanjiLinks}}{{#furigana}}{{{.}}}{{/furigana}}{{/kanjiLinks}}</div>
|
<div class="expression">{{#kanjiLinks}}{{#furigana}}{{{.}}}{{/furigana}}{{/kanjiLinks}}</div>
|
||||||
|
{{#if termTags}}
|
||||||
|
<div style="display: inline-block;">
|
||||||
|
{{#each termTags}}
|
||||||
|
<span class="label label-default tag-{{category}}" title="{{notes}}">{{name}}</span>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{#if reasons}}
|
{{#if reasons}}
|
||||||
<div class="reasons">
|
<div class="reasons">
|
||||||
@ -54,14 +100,24 @@
|
|||||||
{{#if definitions.[1]}}
|
{{#if definitions.[1]}}
|
||||||
<ol>
|
<ol>
|
||||||
{{#each definitions}}
|
{{#each definitions}}
|
||||||
<li>{{> definition}}</li>
|
<li>{{> definition compactGlossaries=../compactGlossaries}}</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ol>
|
</ol>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{> definition definitions.[0]}}
|
{{> definition definitions.[0] compactGlossaries=compactGlossaries}}
|
||||||
|
{{/if}}
|
||||||
|
{{else if merged}}
|
||||||
|
{{#if definitions.[1]}}
|
||||||
|
<ol>
|
||||||
|
{{#each definitions}}
|
||||||
|
<li>{{> definition compactGlossaries=../compactGlossaries}}</li>
|
||||||
|
{{/each}}
|
||||||
|
</ol>
|
||||||
|
{{else}}
|
||||||
|
{{> definition definitions.[0] compactGlossaries=compactGlossaries}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{> definition}}
|
{{> definition compactGlossaries=compactGlossaries}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -74,7 +130,7 @@
|
|||||||
{{#if definitions}}
|
{{#if definitions}}
|
||||||
{{#each definitions}}
|
{{#each definitions}}
|
||||||
{{#unless @first}}<hr>{{/unless}}
|
{{#unless @first}}<hr>{{/unless}}
|
||||||
{{> term debug=../debug grouped=../grouped addable=../addable playback=../playback}}
|
{{> term debug=../debug grouped=../grouped merged=../merged addable=../addable playback=../playback compactGlossaries=../compactGlossaries}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<p class="note">No results found.</p>
|
<p class="note">No results found.</p>
|
||||||
|
Loading…
Reference in New Issue
Block a user