summaryrefslogtreecommitdiff
path: root/ext/bg/js
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2020-08-01 16:23:33 -0400
committerGitHub <noreply@github.com>2020-08-01 16:23:33 -0400
commit838fd211c6737ce7e2b6802a43837cf4300b60d2 (patch)
tree24fb7fd7d8e6c494a3e51defc7f32a6c3aa73107 /ext/bg/js
parent1e839cd230e53f822478f945cb415a8af2b09aef (diff)
Pitch accent Anki field templates (#701)
* Template helper updates * Add pitch data to exported field formatting data * Reuse note data * Add no-op * Set up pitch accent templates * Refactor version update functions * Implement upgrade process for new Anki templates * Consistency * Update README and anki.js to have matching markers
Diffstat (limited to 'ext/bg/js')
-rw-r--r--ext/bg/js/anki-note-builder.js18
-rw-r--r--ext/bg/js/options.js94
-rw-r--r--ext/bg/js/settings/anki-templates.js3
-rw-r--r--ext/bg/js/settings/anki.js6
-rw-r--r--ext/bg/js/template-renderer.js55
5 files changed, 136 insertions, 40 deletions
diff --git a/ext/bg/js/anki-note-builder.js b/ext/bg/js/anki-note-builder.js
index 7fe8962a..2405543e 100644
--- a/ext/bg/js/anki-note-builder.js
+++ b/ext/bg/js/anki-note-builder.js
@@ -15,6 +15,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+/* global
+ * DictionaryDataUtil
+ */
+
class AnkiNoteBuilder {
constructor({anki, audioSystem, renderTemplate}) {
this._anki = anki;
@@ -39,9 +43,10 @@ class AnkiNoteBuilder {
}
};
+ const data = this.createNoteData(definition, mode, context, options);
const formattedFieldValuePromises = [];
for (const [, fieldValue] of modeOptionsFieldEntries) {
- const formattedFieldValuePromise = this.formatField(fieldValue, definition, mode, context, options, templates, null);
+ const formattedFieldValuePromise = this.formatField(fieldValue, data, templates, null);
formattedFieldValuePromises.push(formattedFieldValuePromise);
}
@@ -55,10 +60,14 @@ class AnkiNoteBuilder {
return note;
}
- async formatField(field, definition, mode, context, options, templates, errors=null) {
- const data = {
+ createNoteData(definition, mode, context, options) {
+ const pitches = DictionaryDataUtil.getPitchAccentInfos(definition);
+ const pitchCount = pitches.reduce((i, v) => i + v.pitches.length, 0);
+ return {
marker: null,
definition,
+ pitches,
+ pitchCount,
group: options.general.resultOutputMode === 'group',
merge: options.general.resultOutputMode === 'merge',
modeTermKanji: mode === 'term-kanji',
@@ -67,6 +76,9 @@ class AnkiNoteBuilder {
compactGlossaries: options.general.compactGlossaries,
context
};
+ }
+
+ async formatField(field, data, templates, errors=null) {
const pattern = /\{([\w-]+)\}/g;
return await AnkiNoteBuilder.stringReplaceAsync(field, pattern, async (g0, marker) => {
data.marker = marker;
diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js
index ffea96f8..0d83f428 100644
--- a/ext/bg/js/options.js
+++ b/ext/bg/js/options.js
@@ -380,31 +380,83 @@ class OptionsUtil {
return [
{
async: false,
- update: (options) => {
- // Version 1 changes:
- // Added options.global.database.prefixWildcardsSupported = false
- options.global = {
- database: {
- prefixWildcardsSupported: false
- }
- };
- return options;
- }
+ update: this._updateVersion1.bind(this)
},
{
async: false,
- update: (options) => {
- // Version 2 changes:
- // Legacy profile update process moved into this upgrade function.
- for (const profile of options.profiles) {
- if (!Array.isArray(profile.conditionGroups)) {
- profile.conditionGroups = [];
- }
- profile.options = this._legacyProfileUpdateUpdateVersion(profile.options);
- }
- return options;
- }
+ update: this._updateVersion2.bind(this)
+ },
+ {
+ async: true,
+ update: this._updateVersion3.bind(this)
}
];
}
+
+ static _updateVersion1(options) {
+ // Version 1 changes:
+ // Added options.global.database.prefixWildcardsSupported = false.
+ options.global = {
+ database: {
+ prefixWildcardsSupported: false
+ }
+ };
+ return options;
+ }
+
+ static _updateVersion2(options) {
+ // Version 2 changes:
+ // Legacy profile update process moved into this upgrade function.
+ for (const profile of options.profiles) {
+ if (!Array.isArray(profile.conditionGroups)) {
+ profile.conditionGroups = [];
+ }
+ profile.options = this._legacyProfileUpdateUpdateVersion(profile.options);
+ }
+ return options;
+ }
+
+ static async _updateVersion3(options) {
+ // Version 3 changes:
+ // Pitch accent Anki field templates added.
+ let addition = null;
+ for (const {options: profileOptions} of options.profiles) {
+ const fieldTemplates = profileOptions.anki.fieldTemplates;
+ if (fieldTemplates !== null) {
+ if (addition === null) {
+ addition = await this._updateVersion3GetAnkiFieldTemplates();
+ }
+ profileOptions.anki.fieldTemplates = this._addFieldTemplatesBeforeEnd(fieldTemplates, addition);
+ }
+ }
+ return options;
+ }
+
+ static async _updateVersion3GetAnkiFieldTemplates() {
+ const url = chrome.runtime.getURL('/bg/data/anki-field-templates-upgrade-v2.handlebars');
+ const response = await fetch(url, {
+ method: 'GET',
+ mode: 'no-cors',
+ cache: 'default',
+ credentials: 'omit',
+ redirect: 'follow',
+ referrerPolicy: 'no-referrer'
+ });
+ return await response.text();
+ }
+
+ static async _addFieldTemplatesBeforeEnd(fieldTemplates, addition) {
+ const pattern = /[ \t]*\{\{~?>\s*\(\s*lookup\s*\.\s*"marker"\s*\)\s*~?\}\}/;
+ const newline = '\n';
+ let replaced = false;
+ fieldTemplates = fieldTemplates.replace(pattern, (g0) => {
+ replaced = true;
+ return `${addition}${newline}${g0}`;
+ });
+ if (!replaced) {
+ fieldTemplates += newline;
+ fieldTemplates += addition;
+ }
+ return fieldTemplates;
+ }
}
diff --git a/ext/bg/js/settings/anki-templates.js b/ext/bg/js/settings/anki-templates.js
index 88d4fe04..4e004308 100644
--- a/ext/bg/js/settings/anki-templates.js
+++ b/ext/bg/js/settings/anki-templates.js
@@ -144,7 +144,8 @@ class AnkiTemplatesController {
let templates = options.anki.fieldTemplates;
if (typeof templates !== 'string') { templates = this._defaultFieldTemplates; }
const ankiNoteBuilder = new AnkiNoteBuilder({renderTemplate: api.templateRender.bind(api)});
- result = await ankiNoteBuilder.formatField(field, definition, mode, context, options, templates, exceptions);
+ const data = ankiNoteBuilder.createNoteData(definition, mode, context, options);
+ result = await ankiNoteBuilder.formatField(field, data, templates, exceptions);
}
} catch (e) {
exceptions.push(e);
diff --git a/ext/bg/js/settings/anki.js b/ext/bg/js/settings/anki.js
index 51dabba4..ac4c5455 100644
--- a/ext/bg/js/settings/anki.js
+++ b/ext/bg/js/settings/anki.js
@@ -54,6 +54,9 @@ class AnkiController {
'furigana-plain',
'glossary',
'glossary-brief',
+ 'pitch-accents',
+ 'pitch-accent-graphs',
+ 'pitch-accent-positions',
'reading',
'screenshot',
'sentence',
@@ -63,6 +66,9 @@ class AnkiController {
case 'kanji':
return [
'character',
+ 'cloze-body',
+ 'cloze-prefix',
+ 'cloze-suffix',
'dictionary',
'document-title',
'glossary',
diff --git a/ext/bg/js/template-renderer.js b/ext/bg/js/template-renderer.js
index ef05cbd8..59af74c8 100644
--- a/ext/bg/js/template-renderer.js
+++ b/ext/bg/js/template-renderer.js
@@ -82,7 +82,10 @@ class TemplateRenderer {
['get', this._get.bind(this)],
['set', this._set.bind(this)],
['scope', this._scope.bind(this)],
- ['isMoraPitchHigh', this._isMoraPitchHigh.bind(this)]
+ ['property', this._property.bind(this)],
+ ['noop', this._noop.bind(this)],
+ ['isMoraPitchHigh', this._isMoraPitchHigh.bind(this)],
+ ['getKanaMorae', this._getKanaMorae.bind(this)]
];
for (const [name, helper] of helpers) {
@@ -316,21 +319,20 @@ class TemplateRenderer {
_set(context, ...args) {
switch (args.length) {
case 2:
- {
- const [key, options] = args;
- const value = options.fn(context);
- this._stateStack[this._stateStack.length - 1].set(key, value);
- return value;
- }
+ {
+ const [key, options] = args;
+ const value = options.fn(context);
+ this._stateStack[this._stateStack.length - 1].set(key, value);
+ }
+ break;
case 3:
- {
- const [key, value] = args;
- this._stateStack[this._stateStack.length - 1].set(key, value);
- return value;
- }
- default:
- return void 0;
+ {
+ const [key, value] = args;
+ this._stateStack[this._stateStack.length - 1].set(key, value);
+ }
+ break;
}
+ return '';
}
_scope(context, options) {
@@ -344,7 +346,30 @@ class TemplateRenderer {
}
}
- _isMoraPitchHigh(context, position, index) {
+ _property(context, ...args) {
+ const ii = args.length - 1;
+ if (ii <= 0) { return void 0; }
+
+ try {
+ let value = args[0];
+ for (let i = 1; i < ii; ++i) {
+ value = value[args[i]];
+ }
+ return value;
+ } catch (e) {
+ return void 0;
+ }
+ }
+
+ _noop(context, options) {
+ return options.fn(context);
+ }
+
+ _isMoraPitchHigh(context, index, position) {
return jp.isMoraPitchHigh(index, position);
}
+
+ _getKanaMorae(context, text) {
+ return jp.getKanaMorae(`${text}`);
+ }
}