diff options
Diffstat (limited to 'ext/bg/js/dictionary.js')
-rw-r--r-- | ext/bg/js/dictionary.js | 216 |
1 files changed, 176 insertions, 40 deletions
diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index a6438523..4562c821 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -19,63 +19,199 @@ class Dictionary { constructor() { - this.termDicts = {}; - this.kanjiDicts = {}; + this.db = null; + this.dbVer = 1; + this.entities = null; } - addTermDict(name, dict) { - this.termDicts[name] = dict; - } + initDb() { + if (this.db !== null) { + return Promise.reject('database already initialized'); + } - addKanjiDict(name, dict) { - this.kanjiDicts[name] = dict; + this.db = new Dexie('dict'); + this.db.version(1).stores({ + terms: '++id,expression,reading', + entities: '++,name', + kanji: '++,character', + meta: 'name,value', + }); } - findTerm(term) { - let results = []; + prepareDb() { + this.initDb(); - for (let name in this.termDicts) { - const dict = this.termDicts[name]; - if (!(term in dict.i)) { - continue; + return this.db.meta.get('version').then(row => { + return row ? row.value : 0; + }).catch(() => { + return 0; + }).then(version => { + if (this.dbVer === version) { + return true; } - const indices = dict.i[term].split(' ').map(Number); - results = results.concat( - indices.map(index => { - const [e, r, t, ...g] = dict.d[index]; - return { - expression: e, - reading: r, - tags: t.split(' '), - glossary: g, - entities: dict.e, - id: index - }; - }) - ); + const db = this.db; + this.db.close(); + this.db = null; + + return db.delete().then(() => { + this.initDb(); + return false; + }); + }); + } + + sealDb() { + if (this.db === null) { + return Promise.reject('database not initialized'); } - return results; + return this.db.meta.put({name: 'version', value: this.dbVer}); + } + + findTerm(term) { + if (this.db === null) { + return Promise.reject('database not initialized'); + } + + const results = []; + return this.db.terms.where('expression').equals(term).or('reading').equals(term).each(row => { + results.push({ + expression: row.expression, + reading: row.reading, + tags: row.tags.split(' '), + glossary: row.glossary, + id: row.id + }); + }).then(() => { + return this.getEntities(); + }).then(entities => { + for (const result of results) { + result.entities = entities; + } + + return results; + }); } findKanji(kanji) { + if (this.db === null) { + return Promise.reject('database not initialized'); + } + const results = []; + return this.db.kanji.where('character').equals(kanji).each(row => { + results.push({ + character: row.character, + onyomi: row.onyomi.split(' '), + kunyomi: row.kunyomi.split(' '), + tags: row.tags.split(' '), + glossary: row.meanings + }); + }).then(() => results); + } - for (let name in this.kanjiDicts) { - const def = this.kanjiDicts[name].c[kanji]; - if (def) { - const [k, o, t, ...g] = def; - results.push({ - character: kanji, - kunyomi: k.split(' '), - onyomi: o.split(' '), - tags: t.split(' '), - glossary: g - }); + getEntities(tags) { + if (this.db === null) { + return Promise.reject('database not initialized'); + } + + if (this.entities !== null) { + return Promise.resolve(this.entities); + } + + return this.db.entities.toArray(rows => { + this.entities = {}; + for (const row of rows) { + this.entities[row.name] = row.value; + } + + return this.entities; + }); + } + + importTermDict(indexUrl, callback) { + if (this.db === null) { + return Promise.reject('database not initialized'); + } + + const indexDir = indexUrl.slice(0, indexUrl.lastIndexOf('/')); + return loadJson(indexUrl).then(index => { + const entities = []; + for (const [name, value] of index.ents) { + entities.push({name, value}); } + + return this.db.entities.bulkAdd(entities).then(() => { + if (this.entities === null) { + this.entities = {}; + } + + for (const entity of entities) { + this.entities[entity.name] = entity.value; + } + }).then(() => { + const loaders = []; + for (let i = 1; i <= index.banks; ++i) { + const bankUrl = `${indexDir}/bank_${i}.json`; + loaders.push(() => { + return loadJson(bankUrl).then(definitions => { + const rows = []; + for (const [expression, reading, tags, ...glossary] of definitions) { + rows.push({expression, reading, tags, glossary}); + } + + return this.db.terms.bulkAdd(rows).then(() => { + if (callback) { + callback(i, index.banks, indexUrl); + } + }); + }); + }); + } + + let chain = Promise.resolve(); + for (const loader of loaders) { + chain = chain.then(loader); + } + + return chain; + }); + }); + } + + importKanjiDict(indexUrl, callback) { + if (this.db === null) { + return Promise.reject('database not initialized'); } - return results; + const indexDir = indexUrl.slice(0, indexUrl.lastIndexOf('/')); + return loadJson(indexUrl).then(index => { + const loaders = []; + for (let i = 1; i <= index.banks; ++i) { + const bankUrl = `${indexDir}/bank_${i}.json`; + loaders.push(() => { + return loadJson(bankUrl).then(definitions => { + const rows = []; + for (const [character, onyomi, kunyomi, tags, ...meanings] of definitions) { + rows.push({character, onyomi, kunyomi, tags, meanings}); + } + + return this.db.kanji.bulkAdd(rows).then(() => { + if (callback) { + callback(i, index.banks, indexUrl); + } + }); + }); + }); + } + + let chain = Promise.resolve(); + for (const loader of loaders) { + chain = chain.then(loader); + } + + return chain; + }); } } |