Merge branch 'master' into firefox-amo
This commit is contained in:
commit
00c20aed42
18
README.md
18
README.md
@ -55,13 +55,15 @@ primary language is not English, you may consider also importing the English ver
|
||||
* [jmdict_swedish.zip](https://foosoft.net/projects/yomichan/dl/dict/jmdict_swedish.zip)
|
||||
* **[JMnedict](http://www.edrdg.org/enamdict/enamdict_doc.html)** (Japanese names)
|
||||
* [jmnedict.zip](https://foosoft.net/projects/yomichan/dl/dict/jmnedict.zip)
|
||||
* **[KANJIDIC](http://nihongo.monash.edu/kanjidic2/index.html)** (Japanese Kanji)
|
||||
* [kanjidic_english.zip](https://foosoft.net/projects/yomichan/dl/dict/kanjidic_english.zip)
|
||||
* [kanjidic_french.zip](https://foosoft.net/projects/yomichan/dl/dict/kanjidic_french.zip)
|
||||
* [kanjidic_portuguese.zip](https://foosoft.net/projects/yomichan/dl/dict/kanjidic_portuguese.zip)
|
||||
* [kanjidic_spanish.zip](https://foosoft.net/projects/yomichan/dl/dict/kanjidic_spanish.zip)
|
||||
* **[KireiCake](https://kireicake.com/rikaicakes/)** (Japanese slang)
|
||||
* [kireicake.zip](https://foosoft.net/projects/yomichan/dl/dict/kireicake.zip)
|
||||
* **[KANJIDIC](http://nihongo.monash.edu/kanjidic2/index.html)** (Japanese Kanji)
|
||||
* [kanjidic_english.zip](https://foosoft.net/projects/yomichan/dl/dict/kanjidic_english.zip) ([ver. 1.3.5 and older](https://foosoft.net/projects/yomichan/dl/dict/kanjidic_english_old.zip))
|
||||
* [kanjidic_french.zip](https://foosoft.net/projects/yomichan/dl/dict/kanjidic_french.zip) ([ver. 1.3.5 and older](https://foosoft.net/projects/yomichan/dl/dict/kanjidic_french_old.zip))
|
||||
* [kanjidic_portuguese.zip](https://foosoft.net/projects/yomichan/dl/dict/kanjidic_portuguese.zip) ([ver. 1.3.5 and older](https://foosoft.net/projects/yomichan/dl/dict/kanjidic_portuguese_old.zip))
|
||||
* [kanjidic_spanish.zip](https://foosoft.net/projects/yomichan/dl/dict/kanjidic_spanish.zip) ([ver. 1.3.5 and older](https://foosoft.net/projects/yomichan/dl/dict/kanjidic_spanish_old.zip))
|
||||
* **[Innocent Corpus](https://forum.koohii.com/post-168613.html#pid168613)** (Frequency list of terms and Kanji in 5000+ novels)
|
||||
* [innocent_corpus.zip](https://foosoft.net/projects/yomichan/dl/dict/innocent_corpus.zip)
|
||||
|
||||
## Basic Usage ##
|
||||
|
||||
@ -240,6 +242,12 @@ exact versions used for distribution.
|
||||
|
||||
## Frequently Asked Questions ##
|
||||
|
||||
* **Why does the Kanji results page display "No data found" for several fields?**
|
||||
|
||||
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 Yomichan expect. Please purge your database and install
|
||||
the latest version of the KANJIDIC to see additional information about characters.
|
||||
|
||||
* **Can I still create cards without HTML formatting? The option for it is gone!**
|
||||
|
||||
Developing Yomichan is a constant balance between including useful features and keeping complexity at a minimum.
|
||||
|
@ -62,7 +62,7 @@ class AnkiConnect {
|
||||
if (this.remoteVersion < this.localVersion) {
|
||||
this.remoteVersion = await this.ankiInvoke('version');
|
||||
if (this.remoteVersion < this.localVersion) {
|
||||
throw 'extension and plugin versions incompatible';
|
||||
throw 'Extension and plugin versions incompatible';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ async function apiTermsFind(text) {
|
||||
|
||||
const searcher = options.general.groupResults ?
|
||||
translator.findTermsGrouped.bind(translator) :
|
||||
translator.findTerms.bind(translator);
|
||||
translator.findTermsSplit.bind(translator);
|
||||
|
||||
const {definitions, length} = await searcher(
|
||||
text,
|
||||
|
@ -57,7 +57,7 @@ async function audioBuildUrl(definition, mode, cache={}) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', 'https://www.japanesepod101.com/learningcenter/reference/dictionary_post');
|
||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||
xhr.addEventListener('error', () => reject('failed to scrape audio data'));
|
||||
xhr.addEventListener('error', () => reject('Failed to scrape audio data'));
|
||||
xhr.addEventListener('load', () => {
|
||||
cache[definition.expression] = xhr.responseText;
|
||||
resolve(xhr.responseText);
|
||||
@ -87,7 +87,7 @@ async function audioBuildUrl(definition, mode, cache={}) {
|
||||
} else {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', `http://jisho.org/search/${definition.expression}`);
|
||||
xhr.addEventListener('error', () => reject('failed to scrape audio data'));
|
||||
xhr.addEventListener('error', () => reject('Failed to scrape audio data'));
|
||||
xhr.addEventListener('load', () => {
|
||||
cache[definition.expression] = xhr.responseText;
|
||||
resolve(xhr.responseText);
|
||||
|
@ -71,7 +71,7 @@ class Backend {
|
||||
return promise.then(result => {
|
||||
callback({result});
|
||||
}).catch(error => {
|
||||
callback({error});
|
||||
callback({error: error.toString ? error.toString() : error});
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -20,44 +20,33 @@
|
||||
class Database {
|
||||
constructor() {
|
||||
this.db = null;
|
||||
this.version = 2;
|
||||
this.tagCache = {};
|
||||
}
|
||||
|
||||
async sanitize() {
|
||||
try {
|
||||
const db = new Dexie('dict');
|
||||
await db.open();
|
||||
db.close();
|
||||
if (db.verno !== this.version) {
|
||||
await db.delete();
|
||||
}
|
||||
} catch(e) {
|
||||
// NOP
|
||||
}
|
||||
}
|
||||
|
||||
async prepare() {
|
||||
if (this.db) {
|
||||
throw 'database already initialized';
|
||||
throw 'Database already initialized';
|
||||
}
|
||||
|
||||
await this.sanitize();
|
||||
|
||||
this.db = new Dexie('dict');
|
||||
this.db.version(this.version).stores({
|
||||
this.db.version(2).stores({
|
||||
terms: '++id,dictionary,expression,reading',
|
||||
kanji: '++,dictionary,character',
|
||||
tagMeta: '++,dictionary',
|
||||
dictionaries: '++,title,version'
|
||||
});
|
||||
this.db.version(3).stores({
|
||||
termMeta: '++,dictionary,expression',
|
||||
kanjiMeta: '++,dictionary,character',
|
||||
tagMeta: '++,dictionary,name'
|
||||
});
|
||||
|
||||
await this.db.open();
|
||||
}
|
||||
|
||||
async purge() {
|
||||
if (!this.db) {
|
||||
throw 'database not initialized';
|
||||
throw 'Database not initialized';
|
||||
}
|
||||
|
||||
this.db.close();
|
||||
@ -70,7 +59,7 @@ class Database {
|
||||
|
||||
async findTerms(term, titles) {
|
||||
if (!this.db) {
|
||||
throw 'database not initialized';
|
||||
throw 'Database not initialized';
|
||||
}
|
||||
|
||||
const results = [];
|
||||
@ -89,17 +78,31 @@ class Database {
|
||||
}
|
||||
});
|
||||
|
||||
await this.cacheTagMeta(titles);
|
||||
for (const result of results) {
|
||||
result.tagMeta = this.tagCache[result.dictionary] || {};
|
||||
return results;
|
||||
}
|
||||
|
||||
async findTermMeta(term, titles) {
|
||||
if (!this.db) {
|
||||
throw 'Database not initialized';
|
||||
}
|
||||
|
||||
const results = [];
|
||||
await this.db.termMeta.where('expression').equals(term).each(row => {
|
||||
if (titles.includes(row.dictionary)) {
|
||||
results.push({
|
||||
mode: row.mode,
|
||||
data: row.data,
|
||||
dictionary: row.dictionary
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
async findKanji(kanji, titles) {
|
||||
if (!this.db) {
|
||||
return Promise.reject('database not initialized');
|
||||
throw 'Database not initialized';
|
||||
}
|
||||
|
||||
const results = [];
|
||||
@ -111,83 +114,88 @@ class Database {
|
||||
kunyomi: dictFieldSplit(row.kunyomi),
|
||||
tags: dictFieldSplit(row.tags),
|
||||
glossary: row.meanings,
|
||||
stats: row.stats,
|
||||
dictionary: row.dictionary
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
await this.cacheTagMeta(titles);
|
||||
for (const result of results) {
|
||||
result.tagMeta = this.tagCache[result.dictionary] || {};
|
||||
return results;
|
||||
}
|
||||
|
||||
async findKanjiMeta(kanji, titles) {
|
||||
if (!this.db) {
|
||||
throw 'Database not initialized';
|
||||
}
|
||||
|
||||
const results = [];
|
||||
await this.db.kanjiMeta.where('character').equals(kanji).each(row => {
|
||||
if (titles.includes(row.dictionary)) {
|
||||
results.push({
|
||||
mode: row.mode,
|
||||
data: row.data,
|
||||
dictionary: row.dictionary
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
async cacheTagMeta(titles) {
|
||||
async findTagForTitle(name, title) {
|
||||
if (!this.db) {
|
||||
throw 'database not initialized';
|
||||
throw 'Database not initialized';
|
||||
}
|
||||
|
||||
for (const title of titles) {
|
||||
if (!this.tagCache[title]) {
|
||||
const tagMeta = {};
|
||||
await this.db.tagMeta.where('dictionary').equals(title).each(row => {
|
||||
tagMeta[row.name] = {category: row.category, notes: row.notes, order: row.order};
|
||||
this.tagCache[title] = this.tagCache[title] || {};
|
||||
|
||||
let result = this.tagCache[title][name];
|
||||
if (!result) {
|
||||
await this.db.tagMeta.where('name').equals(name).each(row => {
|
||||
if (title === row.dictionary) {
|
||||
result = row;
|
||||
}
|
||||
});
|
||||
|
||||
this.tagCache[title] = tagMeta;
|
||||
}
|
||||
}
|
||||
this.tagCache[title][name] = result;
|
||||
}
|
||||
|
||||
async getDictionaries() {
|
||||
return result;
|
||||
}
|
||||
|
||||
async getTitles() {
|
||||
if (this.db) {
|
||||
return this.db.dictionaries.toArray();
|
||||
} else {
|
||||
throw 'database not initialized';
|
||||
throw 'Database not initialized';
|
||||
}
|
||||
}
|
||||
|
||||
async importDictionary(archive, callback) {
|
||||
if (!this.db) {
|
||||
return Promise.reject('database not initialized');
|
||||
throw 'Database not initialized';
|
||||
}
|
||||
|
||||
let summary = null;
|
||||
const indexLoaded = async (title, version, revision, tagMeta, hasTerms, hasKanji) => {
|
||||
summary = {title, version, revision, hasTerms, hasKanji};
|
||||
const indexDataLoaded = async summary => {
|
||||
if (summary.version > 2) {
|
||||
throw 'Unsupported dictionary version';
|
||||
}
|
||||
|
||||
const count = await this.db.dictionaries.where('title').equals(title).count();
|
||||
const count = await this.db.dictionaries.where('title').equals(summary.title).count();
|
||||
if (count > 0) {
|
||||
throw `dictionary "${title}" is already imported`;
|
||||
throw 'Dictionary is already imported';
|
||||
}
|
||||
|
||||
await this.db.dictionaries.add({title, version, revision, hasTerms, hasKanji});
|
||||
|
||||
const rows = [];
|
||||
for (const tag in tagMeta || {}) {
|
||||
const meta = tagMeta[tag];
|
||||
const row = dictTagSanitize({
|
||||
name: tag,
|
||||
category: meta.category,
|
||||
notes: meta.notes,
|
||||
order: meta.order,
|
||||
dictionary: title
|
||||
});
|
||||
|
||||
rows.push(row);
|
||||
}
|
||||
|
||||
await this.db.tagMeta.bulkAdd(rows);
|
||||
await this.db.dictionaries.add(summary);
|
||||
};
|
||||
|
||||
const termsLoaded = async (title, entries, total, current) => {
|
||||
const termDataLoaded = async (summary, entries, total, current) => {
|
||||
if (callback) {
|
||||
callback(total, current);
|
||||
}
|
||||
|
||||
const rows = [];
|
||||
if (summary.version === 1) {
|
||||
for (const [expression, reading, tags, rules, score, ...glossary] of entries) {
|
||||
rows.push({
|
||||
expression,
|
||||
@ -196,19 +204,51 @@ class Database {
|
||||
rules,
|
||||
score,
|
||||
glossary,
|
||||
dictionary: title
|
||||
dictionary: summary.title
|
||||
});
|
||||
}
|
||||
} else {
|
||||
for (const [expression, reading, tags, rules, score, glossary] of entries) {
|
||||
rows.push({
|
||||
expression,
|
||||
reading,
|
||||
tags,
|
||||
rules,
|
||||
score,
|
||||
glossary,
|
||||
dictionary: summary.title
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await this.db.terms.bulkAdd(rows);
|
||||
};
|
||||
|
||||
const kanjiLoaded = async (title, entries, total, current) => {
|
||||
const termMetaDataLoaded = async (summary, entries, total, current) => {
|
||||
if (callback) {
|
||||
callback(total, current);
|
||||
}
|
||||
|
||||
const rows = [];
|
||||
for (const [expression, mode, data] of entries) {
|
||||
rows.push({
|
||||
expression,
|
||||
mode,
|
||||
data,
|
||||
dictionary: summary.title
|
||||
});
|
||||
}
|
||||
|
||||
await this.db.termMeta.bulkAdd(rows);
|
||||
};
|
||||
|
||||
const kanjiDataLoaded = async (summary, entries, total, current) => {
|
||||
if (callback) {
|
||||
callback(total, current);
|
||||
}
|
||||
|
||||
const rows = [];
|
||||
if (summary.version === 1) {
|
||||
for (const [character, onyomi, kunyomi, tags, ...meanings] of entries) {
|
||||
rows.push({
|
||||
character,
|
||||
@ -216,60 +256,162 @@ class Database {
|
||||
kunyomi,
|
||||
tags,
|
||||
meanings,
|
||||
dictionary: title
|
||||
dictionary: summary.title
|
||||
});
|
||||
}
|
||||
} else {
|
||||
for (const [character, onyomi, kunyomi, tags, meanings, stats] of entries) {
|
||||
rows.push({
|
||||
character,
|
||||
onyomi,
|
||||
kunyomi,
|
||||
tags,
|
||||
meanings,
|
||||
stats,
|
||||
dictionary: summary.title
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await this.db.kanji.bulkAdd(rows);
|
||||
};
|
||||
|
||||
await Database.importDictionaryZip(archive, indexLoaded, termsLoaded, kanjiLoaded);
|
||||
return summary;
|
||||
const kanjiMetaDataLoaded = async (summary, entries, total, current) => {
|
||||
if (callback) {
|
||||
callback(total, current);
|
||||
}
|
||||
|
||||
static async importDictionaryZip(archive, indexLoaded, termsLoaded, kanjiLoaded) {
|
||||
const files = (await JSZip.loadAsync(archive)).files;
|
||||
const rows = [];
|
||||
for (const [character, mode, data] of entries) {
|
||||
rows.push({
|
||||
character,
|
||||
mode,
|
||||
data,
|
||||
dictionary: summary.title
|
||||
});
|
||||
}
|
||||
|
||||
const indexFile = files['index.json'];
|
||||
await this.db.kanjiMeta.bulkAdd(rows);
|
||||
};
|
||||
|
||||
const tagDataLoaded = async (summary, entries, total, current) => {
|
||||
if (callback) {
|
||||
callback(total, current);
|
||||
}
|
||||
|
||||
const rows = [];
|
||||
for (const [name, category, order, notes] of entries) {
|
||||
const row = dictTagSanitize({
|
||||
name,
|
||||
category,
|
||||
order,
|
||||
notes,
|
||||
dictionary: summary.title
|
||||
});
|
||||
|
||||
rows.push(row);
|
||||
}
|
||||
|
||||
await this.db.tagMeta.bulkAdd(rows);
|
||||
};
|
||||
|
||||
return await Database.importDictionaryZip(
|
||||
archive,
|
||||
indexDataLoaded,
|
||||
termDataLoaded,
|
||||
termMetaDataLoaded,
|
||||
kanjiDataLoaded,
|
||||
kanjiMetaDataLoaded,
|
||||
tagDataLoaded
|
||||
);
|
||||
}
|
||||
|
||||
static async importDictionaryZip(
|
||||
archive,
|
||||
indexDataLoaded,
|
||||
termDataLoaded,
|
||||
termMetaDataLoaded,
|
||||
kanjiDataLoaded,
|
||||
kanjiMetaDataLoaded,
|
||||
tagDataLoaded
|
||||
) {
|
||||
const zip = await JSZip.loadAsync(archive);
|
||||
|
||||
const indexFile = zip.files['index.json'];
|
||||
if (!indexFile) {
|
||||
throw 'no dictionary index found in archive';
|
||||
throw 'No dictionary index found in archive';
|
||||
}
|
||||
|
||||
const index = JSON.parse(await indexFile.async('string'));
|
||||
if (!index.title || !index.version || !index.revision) {
|
||||
throw 'unrecognized dictionary format';
|
||||
if (!index.title || !index.revision) {
|
||||
throw 'Unrecognized dictionary format';
|
||||
}
|
||||
|
||||
await indexLoaded(
|
||||
index.title,
|
||||
index.version,
|
||||
index.revision,
|
||||
index.tagMeta || {},
|
||||
index.termBanks > 0,
|
||||
index.kanjiBanks > 0
|
||||
);
|
||||
const summary = {
|
||||
title: index.title,
|
||||
revision: index.revision,
|
||||
version: index.format || index.version
|
||||
};
|
||||
|
||||
const banksTotal = index.termBanks + index.kanjiBanks;
|
||||
let banksLoaded = 0;
|
||||
if (indexDataLoaded) {
|
||||
await indexDataLoaded(summary);
|
||||
}
|
||||
|
||||
for (let i = 1; i <= index.termBanks; ++i) {
|
||||
const bankFile = files[`term_bank_${i}.json`];
|
||||
if (bankFile) {
|
||||
const buildTermBankName = index => `term_bank_${index + 1}.json`;
|
||||
const buildTermMetaBankName = index => `term_meta_bank_${index + 1}.json`;
|
||||
const buildKanjiBankName = index => `kanji_bank_${index + 1}.json`;
|
||||
const buildKanjiMetaBankName = index => `kanji_meta_bank_${index + 1}.json`;
|
||||
const buildTagBankName = index => `tag_bank_${index + 1}.json`;
|
||||
|
||||
const countBanks = namer => {
|
||||
let count = 0;
|
||||
while (zip.files[namer(count)]) {
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
};
|
||||
|
||||
const termBankCount = countBanks(buildTermBankName);
|
||||
const termMetaBankCount = countBanks(buildTermMetaBankName);
|
||||
const kanjiBankCount = countBanks(buildKanjiBankName);
|
||||
const kanjiMetaBankCount = countBanks(buildKanjiMetaBankName);
|
||||
const tagBankCount = countBanks(buildTagBankName);
|
||||
|
||||
let bankLoadedCount = 0;
|
||||
let bankTotalCount =
|
||||
termBankCount +
|
||||
termMetaBankCount +
|
||||
kanjiBankCount +
|
||||
kanjiMetaBankCount +
|
||||
tagBankCount;
|
||||
|
||||
if (tagDataLoaded && index.tagMeta) {
|
||||
const bank = [];
|
||||
for (const name in index.tagMeta) {
|
||||
const tag = index.tagMeta[name];
|
||||
bank.push([name, tag.category, tag.order, tag.notes]);
|
||||
}
|
||||
|
||||
tagDataLoaded(summary, bank, ++bankTotalCount, bankLoadedCount++);
|
||||
}
|
||||
|
||||
const loadBank = async (summary, namer, count, callback) => {
|
||||
if (callback) {
|
||||
for (let i = 0; i < count; ++i) {
|
||||
const bankFile = zip.files[namer(i)];
|
||||
const bank = JSON.parse(await bankFile.async('string'));
|
||||
await termsLoaded(index.title, bank, banksTotal, banksLoaded++);
|
||||
} else {
|
||||
throw 'missing term bank file';
|
||||
await callback(summary, bank, bankTotalCount, bankLoadedCount++);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (let i = 1; i <= index.kanjiBanks; ++i) {
|
||||
const bankFile = files[`kanji_bank_${i}.json`];
|
||||
if (bankFile) {
|
||||
const bank = JSON.parse(await bankFile.async('string'));
|
||||
await kanjiLoaded(index.title, bank, banksTotal, banksLoaded++);
|
||||
} else {
|
||||
throw 'missing kanji bank file';
|
||||
}
|
||||
}
|
||||
await loadBank(summary, buildTermBankName, termBankCount, termDataLoaded);
|
||||
await loadBank(summary, buildTermMetaBankName, termMetaBankCount, termMetaDataLoaded);
|
||||
await loadBank(summary, buildKanjiBankName, kanjiBankCount, kanjiDataLoaded);
|
||||
await loadBank(summary, buildKanjiMetaBankName, kanjiMetaBankCount, kanjiMetaDataLoaded);
|
||||
await loadBank(summary, buildTagBankName, tagBankCount, tagDataLoaded);
|
||||
|
||||
return summary;
|
||||
}
|
||||
}
|
||||
|
@ -55,14 +55,6 @@ function dictRowsSort(rows, options) {
|
||||
|
||||
function dictTermsSort(definitions, dictionaries=null) {
|
||||
return definitions.sort((v1, v2) => {
|
||||
const sl1 = v1.source.length;
|
||||
const sl2 = v2.source.length;
|
||||
if (sl1 > sl2) {
|
||||
return -1;
|
||||
} else if (sl1 < sl2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (dictionaries !== null) {
|
||||
const p1 = (dictionaries[v1.dictionary] || {}).priority || 0;
|
||||
const p2 = (dictionaries[v2.dictionary] || {}).priority || 0;
|
||||
@ -73,11 +65,11 @@ function dictTermsSort(definitions, dictionaries=null) {
|
||||
}
|
||||
}
|
||||
|
||||
const s1 = v1.score;
|
||||
const s2 = v2.score;
|
||||
if (s1 > s2) {
|
||||
const sl1 = v1.source.length;
|
||||
const sl2 = v2.source.length;
|
||||
if (sl1 > sl2) {
|
||||
return -1;
|
||||
} else if (s1 < s2) {
|
||||
} else if (sl1 < sl2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -89,6 +81,14 @@ function dictTermsSort(definitions, dictionaries=null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const s1 = v1.score;
|
||||
const s2 = v2.score;
|
||||
if (s1 > s2) {
|
||||
return -1;
|
||||
} else if (s1 < s2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return v2.expression.localeCompare(v1.expression);
|
||||
});
|
||||
}
|
||||
@ -148,16 +148,6 @@ function dictTagBuildSource(name) {
|
||||
return dictTagSanitize({name, category: 'dictionary', order: 100});
|
||||
}
|
||||
|
||||
function dictTagBuild(name, meta) {
|
||||
const tag = {name};
|
||||
const symbol = name.split(':')[0];
|
||||
for (const prop in meta[symbol] || {}) {
|
||||
tag[prop] = meta[symbol][prop];
|
||||
}
|
||||
|
||||
return dictTagSanitize(tag);
|
||||
}
|
||||
|
||||
function dictTagSanitize(tag) {
|
||||
tag.name = tag.name || 'untitled';
|
||||
tag.category = tag.category || 'default';
|
||||
|
@ -146,7 +146,8 @@ function optionsSetDefaults(options) {
|
||||
middleMouse: true,
|
||||
selectText: true,
|
||||
alphanumeric: true,
|
||||
delay: 15,
|
||||
autoHideResults: false,
|
||||
delay: 20,
|
||||
length: 10,
|
||||
modifier: 'shift'
|
||||
},
|
||||
|
@ -22,7 +22,7 @@ function requestJson(url, action, params) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.overrideMimeType('application/json');
|
||||
xhr.addEventListener('load', () => resolve(xhr.responseText));
|
||||
xhr.addEventListener('error', () => reject('failed to execute network request'));
|
||||
xhr.addEventListener('error', () => reject('Failed to connect'));
|
||||
xhr.open(action, url);
|
||||
if (params) {
|
||||
xhr.send(JSON.stringify(params));
|
||||
@ -34,7 +34,7 @@ function requestJson(url, action, params) {
|
||||
return JSON.parse(responseText);
|
||||
}
|
||||
catch (e) {
|
||||
return Promise.reject('invalid JSON response');
|
||||
return Promise.reject('Invalid response');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ class DisplaySearch extends Display {
|
||||
}
|
||||
|
||||
onError(error) {
|
||||
window.alert(`Error: ${error}`);
|
||||
window.alert(`Error: ${error.toString ? error.toString() : error}`);
|
||||
}
|
||||
|
||||
onSearchClear() {
|
||||
|
@ -35,6 +35,7 @@ async function formRead() {
|
||||
optionsNew.scanning.middleMouse = $('#middle-mouse-button-scan').prop('checked');
|
||||
optionsNew.scanning.selectText = $('#select-matched-text').prop('checked');
|
||||
optionsNew.scanning.alphanumeric = $('#search-alphanumeric').prop('checked');
|
||||
optionsNew.scanning.autoHideResults = $('#auto-hide-results').prop('checked');
|
||||
optionsNew.scanning.delay = parseInt($('#scan-delay').val(), 10);
|
||||
optionsNew.scanning.length = parseInt($('#scan-length').val(), 10);
|
||||
optionsNew.scanning.modifier = $('#scan-modifier-key').val();
|
||||
@ -82,7 +83,9 @@ function formUpdateVisibility(options) {
|
||||
|
||||
const debug = $('#debug');
|
||||
if (options.general.debugInfo) {
|
||||
const text = JSON.stringify(options, null, 4);
|
||||
const temp = utilIsolate(options);
|
||||
temp.anki.fieldTemplates = '...';
|
||||
const text = JSON.stringify(temp, null, 4);
|
||||
debug.html(handlebarsEscape(text));
|
||||
debug.show();
|
||||
} else {
|
||||
@ -134,11 +137,12 @@ async function onReady() {
|
||||
$('#middle-mouse-button-scan').prop('checked', options.scanning.middleMouse);
|
||||
$('#select-matched-text').prop('checked', options.scanning.selectText);
|
||||
$('#search-alphanumeric').prop('checked', options.scanning.alphanumeric);
|
||||
$('#auto-hide-results').prop('checked', options.scanning.autoHideResults);
|
||||
$('#scan-delay').val(options.scanning.delay);
|
||||
$('#scan-length').val(options.scanning.length);
|
||||
$('#scan-modifier-key').val(options.scanning.modifier);
|
||||
|
||||
$('#dict-purge').click(utilAsync(onDictionaryPurge));
|
||||
$('#dict-purge-link').click(utilAsync(onDictionaryPurge));
|
||||
$('#dict-file').change(utilAsync(onDictionaryImport));
|
||||
|
||||
$('#anki-enable').prop('checked', options.anki.enable);
|
||||
@ -175,7 +179,33 @@ $(document).ready(utilAsync(onReady));
|
||||
function dictionaryErrorShow(error) {
|
||||
const dialog = $('#dict-error');
|
||||
if (error) {
|
||||
dialog.show().find('span').text(error);
|
||||
const overrides = [
|
||||
[
|
||||
'A mutation operation was attempted on a database that did not allow mutations.',
|
||||
'Access to IndexedDB appears to be restricted. Firefox seems to require that the history preference is set to "Remember history" before IndexedDB use of any kind is allowed.'
|
||||
],
|
||||
[
|
||||
'The operation failed for reasons unrelated to the database itself and not covered by any other error code.',
|
||||
'Unable to access IndexedDB due to a possibly corrupt user profile. Try using the "Refresh Firefox" feature to reset your user profile.'
|
||||
],
|
||||
[
|
||||
'BulkError',
|
||||
'Unable to finish importing dictionary data into IndexedDB. This may indicate that you do not have sufficient disk space available to complete this operation.'
|
||||
]
|
||||
];
|
||||
|
||||
if (error.toString) {
|
||||
error = error.toString();
|
||||
}
|
||||
|
||||
for (const [match, subst] of overrides) {
|
||||
if (error.includes(match)) {
|
||||
error = subst;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dialog.show().text(error);
|
||||
} else {
|
||||
dialog.hide();
|
||||
}
|
||||
@ -211,7 +241,7 @@ async function dictionaryGroupsPopulate(options) {
|
||||
const dictGroups = $('#dict-groups').empty();
|
||||
const dictWarning = $('#dict-warning').hide();
|
||||
|
||||
const dictRows = await utilDatabaseGetDictionaries();
|
||||
const dictRows = await utilDatabaseGetTitles();
|
||||
if (dictRows.length === 0) {
|
||||
dictWarning.show();
|
||||
}
|
||||
@ -241,7 +271,7 @@ async function onDictionaryPurge(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const dictControls = $('#dict-importer, #dict-groups').hide();
|
||||
const dictProgress = $('#dict-purge-progress').show();
|
||||
const dictProgress = $('#dict-purge').show();
|
||||
|
||||
try {
|
||||
dictionaryErrorShow();
|
||||
@ -310,7 +340,7 @@ function ankiSpinnerShow(show) {
|
||||
function ankiErrorShow(error) {
|
||||
const dialog = $('#anki-error');
|
||||
if (error) {
|
||||
dialog.show().find('span').text(error);
|
||||
dialog.show().text(error);
|
||||
}
|
||||
else {
|
||||
dialog.hide();
|
||||
|
@ -22,38 +22,87 @@ templates['dictionary.html'] = template({"1":function(container,depth0,helpers,p
|
||||
+ "\" class=\"form-control dict-priority\">\n </div>\n</div>\n";
|
||||
},"useData":true});
|
||||
templates['kanji.html'] = template({"1":function(container,depth0,helpers,partials,data) {
|
||||
var stack1;
|
||||
|
||||
return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.data : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.program(8, data, 0),"data":data})) != null ? stack1 : "");
|
||||
},"2":function(container,depth0,helpers,partials,data) {
|
||||
var stack1;
|
||||
|
||||
return "<table class=\"info-output\">\n"
|
||||
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.data : depth0),{"name":"each","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ "</table>\n";
|
||||
},"3":function(container,depth0,helpers,partials,data) {
|
||||
var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {});
|
||||
|
||||
return " <tr>\n <th>"
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.notes : depth0),{"name":"if","hash":{},"fn":container.program(4, data, 0),"inverse":container.program(6, data, 0),"data":data})) != null ? stack1 : "")
|
||||
+ "</th>\n <td>"
|
||||
+ container.escapeExpression(((helper = (helper = helpers.value || (depth0 != null ? depth0.value : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(alias1,{"name":"value","hash":{},"data":data}) : helper)))
|
||||
+ "</td>\n </tr>\n";
|
||||
},"4":function(container,depth0,helpers,partials,data) {
|
||||
var helper;
|
||||
|
||||
return container.escapeExpression(((helper = (helper = helpers.notes || (depth0 != null ? depth0.notes : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"notes","hash":{},"data":data}) : helper)));
|
||||
},"6":function(container,depth0,helpers,partials,data) {
|
||||
var helper;
|
||||
|
||||
return container.escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"name","hash":{},"data":data}) : helper)));
|
||||
},"8":function(container,depth0,helpers,partials,data) {
|
||||
return "No data found\n";
|
||||
},"10":function(container,depth0,helpers,partials,data) {
|
||||
var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {});
|
||||
|
||||
return "<div class=\"entry\" data-type=\"kanji\">\n <div class=\"actions\">\n"
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.addable : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.source : depth0),{"name":"if","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.addable : depth0),{"name":"if","hash":{},"fn":container.program(11, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.source : depth0),{"name":"if","hash":{},"fn":container.program(13, 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=\"glyph\">"
|
||||
+ container.escapeExpression(((helper = (helper = helpers.character || (depth0 != null ? depth0.character : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(alias1,{"name":"character","hash":{},"data":data}) : helper)))
|
||||
+ "</div>\n\n <div class=\"reading\">\n <table>\n <tr>\n <th>Kunyomi:</th>\n <td>\n"
|
||||
+ ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.kunyomi : depth0),{"name":"each","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ " </td>\n </tr>\n <tr>\n <th>Onyomi:</th>\n <td>\n"
|
||||
+ ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.onyomi : depth0),{"name":"each","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ " </td>\n </tr>\n </table>\n </div>\n\n <div>\n"
|
||||
+ ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.tags : depth0),{"name":"each","hash":{},"fn":container.program(9, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ " </div>\n\n <div class=\"glossary\">\n"
|
||||
+ ((stack1 = helpers["if"].call(alias1,((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(11, data, 0),"inverse":container.program(15, data, 0),"data":data})) != null ? stack1 : "")
|
||||
+ "</div>\n\n"
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.debug : depth0),{"name":"if","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.frequencies : depth0),{"name":"if","hash":{},"fn":container.program(15, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ "\n"
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.tags : depth0),{"name":"if","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ "\n <table class=\"table table-condensed glyph-data\">\n <tr>\n <th>Glossary</th>\n <th>Readings</th>\n <th>Statistics</th>\n </tr>\n <tr>\n <td class=\"glossary\">\n"
|
||||
+ ((stack1 = helpers["if"].call(alias1,((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(21, data, 0),"inverse":container.program(24, data, 0),"data":data})) != null ? stack1 : "")
|
||||
+ " </td>\n <td class=\"reading\">\n "
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.onyomi : depth0),{"name":"if","hash":{},"fn":container.program(26, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ "\n "
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.kunyomi : depth0),{"name":"if","hash":{},"fn":container.program(29, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ "\n </td>\n <td>"
|
||||
+ ((stack1 = container.invokePartial(partials.table,depth0,{"name":"table","hash":{"data":((stack1 = (depth0 != null ? depth0.stats : depth0)) != null ? stack1.misc : stack1)},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
|
||||
+ "</td>\n </tr>\n <tr>\n <th colspan=\"3\">Classifications</th>\n </tr>\n <tr>\n <td colspan=\"3\">"
|
||||
+ ((stack1 = container.invokePartial(partials.table,depth0,{"name":"table","hash":{"data":((stack1 = (depth0 != null ? depth0.stats : depth0)) != null ? stack1["class"] : stack1)},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
|
||||
+ "</td>\n </tr>\n <tr>\n <th colspan=\"3\">Codepoints</th>\n </tr>\n <tr>\n <td colspan=\"3\">"
|
||||
+ ((stack1 = container.invokePartial(partials.table,depth0,{"name":"table","hash":{"data":((stack1 = (depth0 != null ? depth0.stats : depth0)) != null ? stack1.code : stack1)},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
|
||||
+ "</td>\n </tr>\n <tr>\n <th colspan=\"3\">Dictionary Indices</th>\n </tr>\n <tr>\n <td colspan=\"3\">"
|
||||
+ ((stack1 = container.invokePartial(partials.table,depth0,{"name":"table","hash":{"data":((stack1 = (depth0 != null ? depth0.stats : depth0)) != null ? stack1.index : stack1)},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
|
||||
+ "</td>\n </tr>\n </table>\n\n"
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.debug : depth0),{"name":"if","hash":{},"fn":container.program(31, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ "</div>\n";
|
||||
},"2":function(container,depth0,helpers,partials,data) {
|
||||
},"11":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=\"kanji\"><img src=\"/mixed/img/add-kanji.png\" title=\"Add Kanji (Alt + K)\" alt></a>\n";
|
||||
},"4":function(container,depth0,helpers,partials,data) {
|
||||
},"13":function(container,depth0,helpers,partials,data) {
|
||||
return " <a href=\"#\" class=\"source-term\"><img src=\"/mixed/img/source-term.png\" title=\"Source term (Alt + B)\" alt></a>\n";
|
||||
},"6":function(container,depth0,helpers,partials,data) {
|
||||
},"15":function(container,depth0,helpers,partials,data) {
|
||||
var stack1;
|
||||
|
||||
return " "
|
||||
+ container.escapeExpression(container.lambda(depth0, depth0))
|
||||
+ ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.last),{"name":"unless","hash":{},"fn":container.program(7, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ "\n";
|
||||
},"7":function(container,depth0,helpers,partials,data) {
|
||||
return ", ";
|
||||
},"9":function(container,depth0,helpers,partials,data) {
|
||||
return " <div>\n"
|
||||
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.frequencies : depth0),{"name":"each","hash":{},"fn":container.program(16, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ " </div>\n";
|
||||
},"16":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";
|
||||
},"18":function(container,depth0,helpers,partials,data) {
|
||||
var stack1;
|
||||
|
||||
return " <div>\n"
|
||||
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.tags : depth0),{"name":"each","hash":{},"fn":container.program(19, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ " </div>\n";
|
||||
},"19":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-"
|
||||
@ -63,67 +112,74 @@ templates['kanji.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)))
|
||||
+ "</span>\n";
|
||||
},"11":function(container,depth0,helpers,partials,data) {
|
||||
},"21":function(container,depth0,helpers,partials,data) {
|
||||
var stack1;
|
||||
|
||||
return " <ol>\n"
|
||||
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(12, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
return " <ol>"
|
||||
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.glossary : depth0),{"name":"each","hash":{},"fn":container.program(22, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ "</ol>\n";
|
||||
},"12":function(container,depth0,helpers,partials,data) {
|
||||
var stack1, helper, options, buffer =
|
||||
" <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(13, 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 (stack1 != null) { buffer += stack1; }
|
||||
return buffer + "</span></li>\n";
|
||||
},"13":function(container,depth0,helpers,partials,data) {
|
||||
return container.escapeExpression(container.lambda(depth0, depth0));
|
||||
},"15":function(container,depth0,helpers,partials,data) {
|
||||
var stack1, helper, options, buffer =
|
||||
" <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(16, 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 (stack1 != null) { buffer += stack1; }
|
||||
return buffer + "</div>\n";
|
||||
},"16":function(container,depth0,helpers,partials,data) {
|
||||
},"22":function(container,depth0,helpers,partials,data) {
|
||||
return "<li><span class=\"glossary-item\">"
|
||||
+ container.escapeExpression(container.lambda(depth0, depth0))
|
||||
+ "</span></li>";
|
||||
},"24":function(container,depth0,helpers,partials,data) {
|
||||
var stack1;
|
||||
|
||||
return container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["0"] : stack1), depth0));
|
||||
},"18":function(container,depth0,helpers,partials,data) {
|
||||
return " <span class=\"glossary-item\">"
|
||||
+ container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? depth0.glossary : depth0)) != null ? stack1["0"] : stack1), depth0))
|
||||
+ "</span>\n";
|
||||
},"26":function(container,depth0,helpers,partials,data) {
|
||||
var stack1;
|
||||
|
||||
return "<dl>"
|
||||
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.onyomi : depth0),{"name":"each","hash":{},"fn":container.program(27, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ "</dl>";
|
||||
},"27":function(container,depth0,helpers,partials,data) {
|
||||
return "<dd>"
|
||||
+ container.escapeExpression(container.lambda(depth0, depth0))
|
||||
+ "</dd>";
|
||||
},"29":function(container,depth0,helpers,partials,data) {
|
||||
var stack1;
|
||||
|
||||
return "<dl>"
|
||||
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.kunyomi : depth0),{"name":"each","hash":{},"fn":container.program(27, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ "</dl>";
|
||||
},"31":function(container,depth0,helpers,partials,data) {
|
||||
var stack1, helper, options, buffer =
|
||||
" <pre>";
|
||||
stack1 = ((helper = (helper = helpers.dumpObject || (depth0 != null ? depth0.dumpObject : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"dumpObject","hash":{},"fn":container.program(19, 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(32, 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 (stack1 != null) { buffer += stack1; }
|
||||
return buffer + "</pre>\n";
|
||||
},"19":function(container,depth0,helpers,partials,data) {
|
||||
},"32":function(container,depth0,helpers,partials,data) {
|
||||
var stack1;
|
||||
|
||||
return ((stack1 = container.lambda(depth0, depth0)) != null ? stack1 : "");
|
||||
},"21":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||
},"34":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||
var stack1;
|
||||
|
||||
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(22, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
|
||||
},"22":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(35, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
|
||||
},"35":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||
var stack1;
|
||||
|
||||
return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.first),{"name":"unless","hash":{},"fn":container.program(23, 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(36, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ "\n"
|
||||
+ ((stack1 = container.invokePartial(partials.kanji,depth0,{"name":"kanji","hash":{"root":(depths[1] != null ? depths[1].root : depths[1]),"source":(depths[1] != null ? depths[1].source : depths[1]),"addable":(depths[1] != null ? depths[1].addable : depths[1]),"debug":(depths[1] != null ? depths[1].debug : depths[1])},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
|
||||
},"23":function(container,depth0,helpers,partials,data) {
|
||||
},"36":function(container,depth0,helpers,partials,data) {
|
||||
return "<hr>";
|
||||
},"25":function(container,depth0,helpers,partials,data) {
|
||||
return "<p class=\"note\">No results found.</p>\n";
|
||||
},"38":function(container,depth0,helpers,partials,data) {
|
||||
return "<p class=\"note\">No results found</p>\n";
|
||||
},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||
var stack1;
|
||||
|
||||
return "\n"
|
||||
+ ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(21, data, 0, blockParams, depths),"inverse":container.program(25, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
|
||||
return "\n\n"
|
||||
+ ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(34, data, 0, blockParams, depths),"inverse":container.program(38, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
|
||||
},"main_d": function(fn, props, container, depth0, data, blockParams, depths) {
|
||||
|
||||
var decorators = container.decorators;
|
||||
|
||||
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(1, data, 0, blockParams, depths),"inverse":container.noop,"args":["kanji"],"data":data}) || fn;
|
||||
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(1, data, 0, blockParams, depths),"inverse":container.noop,"args":["table"],"data":data}) || fn;
|
||||
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(10, data, 0, blockParams, depths),"inverse":container.noop,"args":["kanji"],"data":data}) || fn;
|
||||
return fn;
|
||||
}
|
||||
|
||||
@ -203,10 +259,12 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia
|
||||
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(24, data, 0),"inverse":container.program(30, data, 0),"data":data})) != null ? stack1 : "")
|
||||
+ ((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(32, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((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";
|
||||
@ -242,53 +300,67 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia
|
||||
},"24":function(container,depth0,helpers,partials,data) {
|
||||
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(25, data, 0),"inverse":container.program(28, data, 0),"data":data})) != null ? stack1 : "");
|
||||
return " <div>\n"
|
||||
+ ((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";
|
||||
},"25":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";
|
||||
},"27":function(container,depth0,helpers,partials,data) {
|
||||
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 : "");
|
||||
},"28":function(container,depth0,helpers,partials,data) {
|
||||
var stack1;
|
||||
|
||||
return " <ol>\n"
|
||||
+ ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(26, 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(29, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ " </ol>\n";
|
||||
},"26":function(container,depth0,helpers,partials,data) {
|
||||
},"29":function(container,depth0,helpers,partials,data) {
|
||||
var stack1;
|
||||
|
||||
return " <li>"
|
||||
+ ((stack1 = container.invokePartial(partials.definition,depth0,{"name":"definition","data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
|
||||
+ "</li>\n";
|
||||
},"28":function(container,depth0,helpers,partials,data) {
|
||||
},"31":function(container,depth0,helpers,partials,data) {
|
||||
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 : "");
|
||||
},"30":function(container,depth0,helpers,partials,data) {
|
||||
},"33":function(container,depth0,helpers,partials,data) {
|
||||
var stack1;
|
||||
|
||||
return ((stack1 = container.invokePartial(partials.definition,depth0,{"name":"definition","data":data,"indent":" ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
|
||||
},"32":function(container,depth0,helpers,partials,data) {
|
||||
},"35":function(container,depth0,helpers,partials,data) {
|
||||
var stack1, helper, options, buffer =
|
||||
" <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));
|
||||
if (!helpers.dumpObject) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
|
||||
if (stack1 != null) { buffer += stack1; }
|
||||
return buffer + "</pre>\n";
|
||||
},"34":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||
},"37":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||
var stack1;
|
||||
|
||||
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(35, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
|
||||
},"35":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||
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 : "");
|
||||
},"38":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||
var stack1;
|
||||
|
||||
return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.first),{"name":"unless","hash":{},"fn":container.program(36, 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(39, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ "\n"
|
||||
+ ((stack1 = container.invokePartial(partials.term,depth0,{"name":"term","hash":{"playback":(depths[1] != null ? depths[1].playback : depths[1]),"addable":(depths[1] != null ? depths[1].addable : depths[1]),"grouped":(depths[1] != null ? depths[1].grouped : depths[1]),"debug":(depths[1] != null ? depths[1].debug : depths[1])},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
|
||||
},"36":function(container,depth0,helpers,partials,data) {
|
||||
},"39":function(container,depth0,helpers,partials,data) {
|
||||
return "<hr>";
|
||||
},"38":function(container,depth0,helpers,partials,data) {
|
||||
},"41":function(container,depth0,helpers,partials,data) {
|
||||
return "<p class=\"note\">No results found.</p>\n";
|
||||
},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
||||
var stack1;
|
||||
|
||||
return "\n\n"
|
||||
+ ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(34, data, 0, blockParams, depths),"inverse":container.program(38, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
|
||||
+ ((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 : "");
|
||||
},"main_d": function(fn, props, container, depth0, data, blockParams, depths) {
|
||||
|
||||
var decorators = container.decorators;
|
||||
|
@ -37,8 +37,26 @@ class Translator {
|
||||
}
|
||||
|
||||
async findTermsGrouped(text, dictionaries, alphanumeric) {
|
||||
const titles = Object.keys(dictionaries);
|
||||
const {length, definitions} = await this.findTerms(text, dictionaries, alphanumeric);
|
||||
return {length, definitions: dictTermsGroup(definitions, dictionaries)};
|
||||
|
||||
const definitionsGrouped = dictTermsGroup(definitions, dictionaries);
|
||||
for (const definition of definitionsGrouped) {
|
||||
await this.buildTermFrequencies(definition, titles);
|
||||
}
|
||||
|
||||
return {length, definitions: definitionsGrouped};
|
||||
}
|
||||
|
||||
async findTermsSplit(text, dictionaries, alphanumeric) {
|
||||
const titles = Object.keys(dictionaries);
|
||||
const {length, definitions} = await this.findTerms(text, dictionaries, alphanumeric);
|
||||
|
||||
for (const definition of definitions) {
|
||||
await this.buildTermFrequencies(definition, titles);
|
||||
}
|
||||
|
||||
return {length, definitions};
|
||||
}
|
||||
|
||||
async findTerms(text, dictionaries, alphanumeric) {
|
||||
@ -51,17 +69,18 @@ class Translator {
|
||||
|
||||
const cache = {};
|
||||
const titles = Object.keys(dictionaries);
|
||||
let deinflections = await this.findTermsDeinflected(text, titles, cache);
|
||||
let deinflections = await this.findTermDeinflections(text, titles, cache);
|
||||
const textHiragana = jpKatakanaToHiragana(text);
|
||||
if (text !== textHiragana) {
|
||||
deinflections = deinflections.concat(await this.findTermsDeinflected(textHiragana, titles, cache));
|
||||
deinflections = deinflections.concat(await this.findTermDeinflections(textHiragana, titles, cache));
|
||||
}
|
||||
|
||||
let definitions = [];
|
||||
for (const deinflection of deinflections) {
|
||||
for (const definition of deinflection.definitions) {
|
||||
const tags = definition.tags.map(tag => dictTagBuild(tag, definition.tagMeta));
|
||||
const tags = await this.expandTags(definition.tags, definition.dictionary);
|
||||
tags.push(dictTagBuildSource(definition.dictionary));
|
||||
|
||||
definitions.push({
|
||||
source: deinflection.source,
|
||||
reasons: deinflection.reasons,
|
||||
@ -87,7 +106,7 @@ class Translator {
|
||||
return {length, definitions};
|
||||
}
|
||||
|
||||
async findTermsDeinflected(text, titles, cache) {
|
||||
async findTermDeinflections(text, titles, cache) {
|
||||
const definer = async term => {
|
||||
if (cache.hasOwnProperty(term)) {
|
||||
return cache[term];
|
||||
@ -117,11 +136,88 @@ class Translator {
|
||||
}
|
||||
|
||||
for (const definition of definitions) {
|
||||
const tags = definition.tags.map(tag => dictTagBuild(tag, definition.tagMeta));
|
||||
const tags = await this.expandTags(definition.tags, definition.dictionary);
|
||||
tags.push(dictTagBuildSource(definition.dictionary));
|
||||
|
||||
definition.tags = dictTagsSort(tags);
|
||||
definition.stats = await this.expandStats(definition.stats, definition.dictionary);
|
||||
|
||||
definition.frequencies = [];
|
||||
for (const meta of await this.database.findKanjiMeta(definition.character, titles)) {
|
||||
if (meta.mode === 'freq') {
|
||||
definition.frequencies.push({
|
||||
character: meta.character,
|
||||
frequency: meta.data,
|
||||
dictionary: meta.dictionary
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return definitions;
|
||||
}
|
||||
|
||||
async buildTermFrequencies(definition, titles) {
|
||||
definition.frequencies = [];
|
||||
for (const meta of await this.database.findTermMeta(definition.expression, titles)) {
|
||||
if (meta.mode === 'freq') {
|
||||
definition.frequencies.push({
|
||||
expression: meta.expression,
|
||||
frequency: meta.data,
|
||||
dictionary: meta.dictionary
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async expandTags(names, title) {
|
||||
const tags = [];
|
||||
for (const name of names) {
|
||||
const base = name.split(':')[0];
|
||||
const meta = await this.database.findTagForTitle(base, title);
|
||||
|
||||
const tag = {name};
|
||||
for (const prop in meta || {}) {
|
||||
if (prop !== 'name') {
|
||||
tag[prop] = meta[prop];
|
||||
}
|
||||
}
|
||||
|
||||
tags.push(dictTagSanitize(tag));
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
async expandStats(items, title) {
|
||||
const stats = {};
|
||||
for (const name in items) {
|
||||
const base = name.split(':')[0];
|
||||
const meta = await this.database.findTagForTitle(base, title);
|
||||
const group = stats[meta.category] = stats[meta.category] || [];
|
||||
|
||||
const stat = {name, value: items[name]};
|
||||
for (const prop in meta || {}) {
|
||||
if (prop !== 'name') {
|
||||
stat[prop] = meta[prop];
|
||||
}
|
||||
}
|
||||
|
||||
group.push(dictTagSanitize(stat));
|
||||
}
|
||||
|
||||
for (const category in stats) {
|
||||
stats[category].sort((a, b) => {
|
||||
if (a.notes < b.notes) {
|
||||
return -1;
|
||||
} else if (a.notes > b.notes) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ function utilAnkiGetModelFieldNames(modelName) {
|
||||
return utilBackend().anki.getModelFieldNames(modelName);
|
||||
}
|
||||
|
||||
function utilDatabaseGetDictionaries() {
|
||||
return utilBackend().translator.database.getDictionaries();
|
||||
function utilDatabaseGetTitles() {
|
||||
return utilBackend().translator.database.getTitles();
|
||||
}
|
||||
|
||||
function utilDatabasePurge() {
|
||||
|
@ -7,7 +7,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap-theme.min.css">
|
||||
<style>
|
||||
#anki-spinner, #anki-general, #anki-error,
|
||||
#dict-spinner, #dict-error, #dict-warning, #dict-purge-progress, #dict-import-progress,
|
||||
#dict-spinner, #dict-error, #dict-warning, #dict-purge, #dict-import-progress,
|
||||
#debug, .options-advanced {
|
||||
display: none;
|
||||
}
|
||||
@ -96,6 +96,10 @@
|
||||
<label><input type="checkbox" id="search-alphanumeric"> Search alphanumeric text</label>
|
||||
</div>
|
||||
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" id="auto-hide-results"> Automatically hide results</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group options-advanced">
|
||||
<label for="scan-delay">Scan delay (in milliseconds)</label>
|
||||
<input type="number" min="1" id="scan-delay" class="form-control">
|
||||
@ -125,24 +129,16 @@
|
||||
|
||||
<p class="help-block">
|
||||
Yomichan can import and use a variety of dictionary formats. Unneeded dictionaries can be disabled,
|
||||
or you can simply <a href="#" id="dict-purge">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 class="help-block">
|
||||
Please visit the <a href="https://foosoft.net/projects/yomichan" target="_blank">Yomichan</a> homepage to download free
|
||||
dictionaries that you can use with this extension.
|
||||
</p>
|
||||
|
||||
<div id="dict-purge-progress" class="text-danger">Dictionary data is being purged, please be patient...</div>
|
||||
|
||||
<div class="alert alert-warning" id="dict-warning">
|
||||
<strong>Warning:</strong>
|
||||
<span>no dictionaries found; please use the importer below to install packaged dictionaries</span>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-danger" id="dict-error">
|
||||
<strong>Error:</strong>
|
||||
<span></span>
|
||||
</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-danger" id="dict-error"></div>
|
||||
|
||||
<div id="dict-groups"></div>
|
||||
|
||||
@ -170,10 +166,7 @@
|
||||
<a href="https://foosoft.net/projects/anki-connect/" target="_blank">AnkiConnect</a> plugin.
|
||||
</p>
|
||||
|
||||
<div class="alert alert-danger" id="anki-error">
|
||||
<strong>Error:</strong>
|
||||
<span></span>
|
||||
</div>
|
||||
<div class="alert alert-danger" id="anki-error"></div>
|
||||
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" id="anki-enable"> Enable Anki integration</label>
|
||||
|
@ -86,7 +86,7 @@ function docRangeFromPoint(point) {
|
||||
}
|
||||
|
||||
const range = document.caretRangeFromPoint(point.x, point.y);
|
||||
if (range) {
|
||||
if (range && range.startContainer.nodeType === 3 && range.endContainer.nodeType === 3) {
|
||||
return new TextSourceRange(range);
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ class DisplayFloat extends Display {
|
||||
if (window.yomichan_orphaned) {
|
||||
this.onOrphaned();
|
||||
} else {
|
||||
window.alert(`Error: ${error}`);
|
||||
window.alert(`Error: ${error.toString ? error.toString() : error}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,6 @@ class Frontend {
|
||||
const search = async () => {
|
||||
try {
|
||||
await this.searchAt({x: e.clientX, y: e.clientY});
|
||||
this.pendingLookup = false;
|
||||
} catch (e) {
|
||||
this.onError(e);
|
||||
}
|
||||
@ -153,7 +152,7 @@ class Frontend {
|
||||
}
|
||||
|
||||
onError(error) {
|
||||
window.alert(`Error: ${error}`);
|
||||
window.alert(`Error: ${error.toString ? error.toString() : error}`);
|
||||
}
|
||||
|
||||
popupTimerSet(callback) {
|
||||
@ -169,27 +168,17 @@ class Frontend {
|
||||
}
|
||||
|
||||
async searchAt(point) {
|
||||
let textSource = null;
|
||||
if (this.pendingLookup || this.popup.containsPoint(point)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const textSource = docRangeFromPoint(point);
|
||||
let hideResults = !textSource || !textSource.containsPoint(point);
|
||||
|
||||
try {
|
||||
if (this.pendingLookup) {
|
||||
return;
|
||||
}
|
||||
|
||||
textSource = docRangeFromPoint(point);
|
||||
if (!textSource || !textSource.containsPoint(point)) {
|
||||
docImposterDestroy();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.textSourceLast && this.textSourceLast.equals(textSource)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hideResults && (!this.textSourceLast || !this.textSourceLast.equals(textSource))) {
|
||||
this.pendingLookup = true;
|
||||
|
||||
if (!await this.searchTerms(textSource)) {
|
||||
await this.searchKanji(textSource);
|
||||
hideResults = !await this.searchTerms(textSource) && !await this.searchKanji(textSource);
|
||||
}
|
||||
} catch (e) {
|
||||
if (window.yomichan_orphaned) {
|
||||
@ -200,7 +189,12 @@ class Frontend {
|
||||
this.onError(e);
|
||||
}
|
||||
} finally {
|
||||
if (hideResults && this.options.scanning.autoHideResults) {
|
||||
this.searchClear();
|
||||
} else {
|
||||
docImposterDestroy();
|
||||
}
|
||||
|
||||
this.pendingLookup = false;
|
||||
}
|
||||
}
|
||||
|
@ -100,6 +100,21 @@ class Popup {
|
||||
return this.injected && this.container.style.visibility !== 'hidden';
|
||||
}
|
||||
|
||||
containsPoint(point) {
|
||||
if (!this.isVisible()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const rect = this.container.getBoundingClientRect();
|
||||
const contained =
|
||||
point.x >= rect.left &&
|
||||
point.y >= rect.top &&
|
||||
point.x < rect.right &&
|
||||
point.y < rect.bottom;
|
||||
|
||||
return contained;
|
||||
}
|
||||
|
||||
async termsShow(elementRect, definitions, options, context) {
|
||||
await this.show(elementRect, options);
|
||||
this.invokeApi('termsShow', {definitions, options, context});
|
||||
|
@ -82,7 +82,7 @@ class TextSourceRange {
|
||||
}
|
||||
|
||||
equals(other) {
|
||||
return other.range && other.range.compareBoundaryPoints(Range.START_TO_START, this.range) === 0;
|
||||
return other && other.range && other.range.compareBoundaryPoints(Range.START_TO_START, this.range) === 0;
|
||||
}
|
||||
|
||||
static shouldEnter(node) {
|
||||
@ -239,6 +239,6 @@ class TextSourceElement {
|
||||
}
|
||||
|
||||
equals(other) {
|
||||
return other.element === this.element && other.content === this.content;
|
||||
return other && other.element === this.element && other.content === this.content;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Yomichan",
|
||||
"version": "1.3.5",
|
||||
"version": "1.4.0",
|
||||
|
||||
"description": "Japanese dictionary with Anki integration",
|
||||
"icons": {"16": "mixed/img/icon16.png", "48": "mixed/img/icon48.png", "128": "mixed/img/icon128.png"},
|
||||
|
@ -84,6 +84,10 @@ hr {
|
||||
background-color: #aa66cc;
|
||||
}
|
||||
|
||||
.tag-frequency {
|
||||
background-color: #5cb85c;
|
||||
}
|
||||
|
||||
.actions .disabled {
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
@ -144,3 +148,15 @@ hr {
|
||||
padding: 0.01em;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.glyph-data {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.info-output {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.info-output td {
|
||||
text-align: right;
|
||||
}
|
||||
|
@ -32,11 +32,11 @@ class Display {
|
||||
}
|
||||
|
||||
onError(error) {
|
||||
throw 'override me';
|
||||
throw 'Override me';
|
||||
}
|
||||
|
||||
onSearchClear() {
|
||||
throw 'override me';
|
||||
throw 'Override me';
|
||||
}
|
||||
|
||||
onSourceTermView(e) {
|
||||
@ -350,7 +350,7 @@ class Display {
|
||||
Display.adderButtonFind(index, mode).addClass('disabled');
|
||||
Display.viewerButtonFind(index).removeClass('pending disabled').data('noteId', noteId);
|
||||
} else {
|
||||
throw 'note could note be added';
|
||||
throw 'Note could note be added';
|
||||
}
|
||||
} catch (e) {
|
||||
this.onError(e);
|
||||
|
@ -1,3 +1,18 @@
|
||||
{{#*inline "table"}}
|
||||
{{#if data}}
|
||||
<table class="info-output">
|
||||
{{#each data}}
|
||||
<tr>
|
||||
<th>{{#if notes}}{{notes}}{{else}}{{name}}{{/if}}</th>
|
||||
<td>{{value}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</table>
|
||||
{{else}}
|
||||
No data found
|
||||
{{/if}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "kanji"}}
|
||||
<div class="entry" data-type="kanji">
|
||||
<div class="actions">
|
||||
@ -13,44 +28,61 @@
|
||||
|
||||
<div class="glyph">{{character}}</div>
|
||||
|
||||
<div class="reading">
|
||||
<table>
|
||||
<tr>
|
||||
<th>Kunyomi:</th>
|
||||
<td>
|
||||
{{#each kunyomi}}
|
||||
{{.}}{{#unless @last}}, {{/unless}}
|
||||
{{#if frequencies}}
|
||||
<div>
|
||||
{{#each frequencies}}
|
||||
<span class="label label-default tag-frequency">{{dictionary}}:{{frequency}}</span>
|
||||
{{/each}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Onyomi:</th>
|
||||
<td>
|
||||
{{#each onyomi}}
|
||||
{{.}}{{#unless @last}}, {{/unless}}
|
||||
{{/each}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if tags}}
|
||||
<div>
|
||||
{{#each tags}}
|
||||
<span class="label label-default tag-{{category}}" title="{{notes}}">{{name}}</span>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
<div class="glossary">
|
||||
{{#if glossary.[1]}}
|
||||
<ol>
|
||||
{{#each glossary}}
|
||||
<li><span class="glossary-item">{{#multiLine}}{{.}}{{/multiLine}}</span></li>
|
||||
{{/each}}
|
||||
</ol>
|
||||
{{else}}
|
||||
<div class="glossary-item">{{#multiLine}}{{glossary.[0]}}{{/multiLine}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<table class="table table-condensed glyph-data">
|
||||
<tr>
|
||||
<th>Glossary</th>
|
||||
<th>Readings</th>
|
||||
<th>Statistics</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="glossary">
|
||||
{{#if glossary.[1]}}
|
||||
<ol>{{#each glossary}}<li><span class="glossary-item">{{.}}</span></li>{{/each}}</ol>
|
||||
{{else}}
|
||||
<span class="glossary-item">{{glossary.[0]}}</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
<td class="reading">
|
||||
{{#if onyomi}}<dl>{{#each onyomi}}<dd>{{.}}</dd>{{/each}}</dl>{{/if}}
|
||||
{{#if kunyomi}}<dl>{{#each kunyomi}}<dd>{{.}}</dd>{{/each}}</dl>{{/if}}
|
||||
</td>
|
||||
<td>{{> table data=stats.misc}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3">Classifications</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3">{{> table data=stats.class}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3">Codepoints</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3">{{> table data=stats.code}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3">Dictionary Indices</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3">{{> table data=stats.index}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
{{#if debug}}
|
||||
<pre>{{#dumpObject}}{{{.}}}{{/dumpObject}}</pre>
|
||||
@ -64,5 +96,5 @@
|
||||
{{> kanji debug=../debug addable=../addable source=../source root=../root}}
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<p class="note">No results found.</p>
|
||||
<p class="note">No results found</p>
|
||||
{{/if}}
|
||||
|
@ -41,6 +41,14 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if frequencies}}
|
||||
<div>
|
||||
{{#each frequencies}}
|
||||
<span class="label label-default tag-frequency">{{dictionary}}:{{frequency}}</span>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="glossary">
|
||||
{{#if grouped}}
|
||||
{{#if definitions.[1]}}
|
||||
|
Loading…
Reference in New Issue
Block a user