aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2020-09-10 18:03:46 -0400
committerGitHub <noreply@github.com>2020-09-10 18:03:46 -0400
commita531618c48481a30d63112cf59b7806291f0bda4 (patch)
tree04b185c11406952a179ee229e39847234d592ea4
parent9ce682272c5d665bbbe9cbd1380416c3d22f9b04 (diff)
Use Anki classes directly in Display (#804)
* Add _getTemplates function * Add template renderer to display pages * Add AnkiNoteBuilder to Display * Update AnkiTemplatesController to directly use TemplateRenderer * Remove old APIs
-rw-r--r--ext/bg/background.html2
-rw-r--r--ext/bg/js/backend.js100
-rw-r--r--ext/bg/js/settings/anki-templates-controller.js8
-rw-r--r--ext/bg/search.html3
-rw-r--r--ext/bg/settings.html1
-rw-r--r--ext/fg/float.html5
-rw-r--r--ext/mixed/js/api.js12
-rw-r--r--ext/mixed/js/display.js128
8 files changed, 136 insertions, 123 deletions
diff --git a/ext/bg/background.html b/ext/bg/background.html
index 93e4b5c7..2f3fd441 100644
--- a/ext/bg/background.html
+++ b/ext/bg/background.html
@@ -24,7 +24,6 @@
<script src="/mixed/js/japanese.js"></script>
<script src="/bg/js/anki.js"></script>
- <script src="/bg/js/anki-note-builder.js"></script>
<script src="/bg/js/backend.js"></script>
<script src="/bg/js/mecab.js"></script>
<script src="/bg/js/audio-uri-builder.js"></script>
@@ -36,7 +35,6 @@
<script src="/bg/js/options.js"></script>
<script src="/bg/js/profile-conditions.js"></script>
<script src="/bg/js/request-builder.js"></script>
- <script src="/bg/js/template-renderer.js"></script>
<script src="/bg/js/simple-dom-parser.js"></script>
<script src="/bg/js/text-source-map.js"></script>
<script src="/bg/js/translator.js"></script>
diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js
index 3d1b1544..b9be9d0a 100644
--- a/ext/bg/js/backend.js
+++ b/ext/bg/js/backend.js
@@ -17,7 +17,6 @@
/* global
* AnkiConnect
- * AnkiNoteBuilder
* AudioSystem
* AudioUriBuilder
* ClipboardMonitor
@@ -29,7 +28,6 @@
* OptionsUtil
* ProfileConditions
* RequestBuilder
- * TemplateRenderer
* Translator
* jp
*/
@@ -57,10 +55,6 @@ class Backend {
requestBuilder: this._requestBuilder,
useCache: false
});
- this._ankiNoteBuilder = new AnkiNoteBuilder({
- renderTemplate: this._renderTemplate.bind(this)
- });
- this._templateRenderer = new TemplateRenderer();
this._clipboardPasteTarget = null;
this._clipboardPasteTargetInitialized = false;
@@ -94,10 +88,7 @@ class Backend {
['addAnkiNote', {async: true, contentScript: true, handler: this._onApiAddAnkiNote.bind(this)}],
['getAnkiNoteInfo', {async: true, contentScript: true, handler: this._onApiGetAnkiNoteInfo.bind(this)}],
['injectAnkiNoteMedia', {async: true, contentScript: true, handler: this._onApiInjectAnkiNoteMedia.bind(this)}],
- ['definitionAdd', {async: true, contentScript: true, handler: this._onApiDefinitionAdd.bind(this)}],
- ['definitionsAddable', {async: true, contentScript: true, handler: this._onApiDefinitionsAddable.bind(this)}],
['noteView', {async: true, contentScript: true, handler: this._onApiNoteView.bind(this)}],
- ['templateRender', {async: true, contentScript: true, handler: this._onApiTemplateRender.bind(this)}],
['commandExec', {async: false, contentScript: true, handler: this._onApiCommandExec.bind(this)}],
['audioGetUri', {async: true, contentScript: true, handler: this._onApiAudioGetUri.bind(this)}],
['screenshotGet', {async: true, contentScript: true, handler: this._onApiScreenshotGet.bind(this)}],
@@ -473,7 +464,11 @@ class Backend {
return results;
}
- async _onApiInjectAnkiNoteMedia({expression, reading, timestamp, audioDetails, screenshotDetails, clipboardImage}) {
+ async _onApiInjectAnkiNoteMedia({expression, reading, timestamp, audioDetails, screenshotDetails, clipboardImage}, sender) {
+ if (isObject(screenshotDetails)) {
+ const {id: tabId, windowId} = (sender && sender.tab ? sender.tab : {});
+ screenshotDetails = Object.assign({}, screenshotDetails, {tabId, windowId});
+ }
return await this._injectAnkNoteMedia(
this._anki,
expression,
@@ -485,45 +480,10 @@ class Backend {
);
}
- async _onApiDefinitionAdd({definition, mode, context, ownerFrameId, optionsContext}, sender) {
- const options = this.getOptions(optionsContext);
- const templates = this._getTemplates(options);
- const {id: tabId, windowId} = (sender && sender.tab ? sender.tab : {});
- const note = await this._createNote(definition, mode, context, options, templates, true, {windowId, tabId, ownerFrameId});
- return await this._onApiAddAnkiNote({note});
- }
-
- async _onApiDefinitionsAddable({definitions, modes, context, optionsContext}) {
- const options = this.getOptions(optionsContext);
- const templates = this._getTemplates(options);
-
- const modeCount = modes.length;
- const {duplicateScope} = options.anki;
- const notePromises = [];
- for (const definition of definitions) {
- for (const mode of modes) {
- const notePromise = this._createNote(definition, mode, context, options, templates, false, null);
- notePromises.push(notePromise);
- }
- }
- const notes = await Promise.all(notePromises);
-
- const infos = await this._onApiGetAnkiNoteInfo({notes, duplicateScope});
- const results = [];
- for (let i = 0, ii = infos.length; i < ii; i += modeCount) {
- results.push(infos.slice(i, i + modeCount));
- }
- return results;
- }
-
async _onApiNoteView({noteId}) {
return await this._anki.guiBrowseNote(noteId);
}
- async _onApiTemplateRender({template, data, marker}) {
- return this._renderTemplate(template, data, marker);
- }
-
_onApiCommandExec({command, params}) {
return this._runCommand(command, params);
}
@@ -1381,10 +1341,6 @@ class Backend {
return false;
}
- async _renderTemplate(template, data, marker) {
- return await this._templateRenderer.render(template, data, marker);
- }
-
_getTemplates(options) {
const templates = options.anki.fieldTemplates;
return typeof templates === 'string' ? templates : this._defaultAnkiFieldTemplates;
@@ -1595,52 +1551,6 @@ class Backend {
});
}
- async _createNote(definition, mode, context, options, templates, injectMedia, screenshotTarget) {
- const {
- general: {resultOutputMode, compactGlossaries},
- anki: {tags, duplicateScope, kanji, terms, screenshot: {format, quality}},
- audio: {sources, customSourceUrl}
- } = options;
- const modeOptions = (mode === 'kanji') ? kanji : terms;
- const {windowId, tabId, ownerFrameId} = (isObject(screenshotTarget) ? screenshotTarget : {});
-
- if (injectMedia) {
- const fields = modeOptions.fields;
- const timestamp = Date.now();
- const definitionExpressions = definition.expressions;
- const {expression, reading} = Array.isArray(definitionExpressions) ? definitionExpressions[0] : definition;
- const audioDetails = (mode !== 'kanji' && this._ankiNoteBuilder.containsMarker(fields, 'audio') ? {sources, customSourceUrl} : null);
- const screenshotDetails = (this._ankiNoteBuilder.containsMarker(fields, 'screenshot') ? {windowId, tabId, ownerFrameId, format, quality} : null);
- const clipboardImage = (this._ankiNoteBuilder.containsMarker(fields, 'clipboard-image'));
- const {screenshotFileName, clipboardImageFileName, audioFileName} = await this._onApiInjectAnkiNoteMedia({
- expression,
- reading,
- timestamp,
- audioDetails,
- screenshotDetails,
- clipboardImage
- });
- if (screenshotFileName !== null) { definition.screenshotFileName = screenshotFileName; }
- if (clipboardImageFileName !== null) { definition.clipboardImageFileName = clipboardImageFileName; }
- if (audioFileName !== null) { definition.audioFileName = audioFileName; }
- }
-
- return await this._ankiNoteBuilder.createNote({
- definition,
- mode,
- context,
- templates,
- tags,
- duplicateScope,
- resultOutputMode,
- compactGlossaries,
- modeOptions,
- audioDetails: {sources, customSourceUrl},
- screenshotDetails: {windowId, tabId, ownerFrameId, format, quality},
- clipboardImage: true
- });
- }
-
async _getScreenshot(windowId, tabId, ownerFrameId, format, quality) {
if (typeof windowId !== 'number') {
throw new Error('Invalid window ID');
diff --git a/ext/bg/js/settings/anki-templates-controller.js b/ext/bg/js/settings/anki-templates-controller.js
index c05301df..c53e4553 100644
--- a/ext/bg/js/settings/anki-templates-controller.js
+++ b/ext/bg/js/settings/anki-templates-controller.js
@@ -17,6 +17,7 @@
/* global
* AnkiNoteBuilder
+ * TemplateRenderer
* api
*/
@@ -27,6 +28,7 @@ class AnkiTemplatesController {
this._cachedDefinitionValue = null;
this._cachedDefinitionText = null;
this._defaultFieldTemplates = null;
+ this._templateRenderer = new TemplateRenderer();
}
async prepare() {
@@ -144,7 +146,7 @@ class AnkiTemplatesController {
let templates = options.anki.fieldTemplates;
if (typeof templates !== 'string') { templates = this._defaultFieldTemplates; }
const ankiNoteBuilder = new AnkiNoteBuilder({
- renderTemplate: api.templateRender.bind(api)
+ renderTemplate: this._renderTemplate.bind(this)
});
const {general: {resultOutputMode, compactGlossaries}} = options;
const note = await ankiNoteBuilder.createNote({
@@ -176,4 +178,8 @@ class AnkiTemplatesController {
input.classList.toggle('is-invalid', hasException);
}
}
+
+ async _renderTemplate(template, data, marker) {
+ return await this._templateRenderer.render(template, data, marker);
+ }
}
diff --git a/ext/bg/search.html b/ext/bg/search.html
index f18bed0d..ae117fd1 100644
--- a/ext/bg/search.html
+++ b/ext/bg/search.html
@@ -91,6 +91,9 @@
<script src="/mixed/js/template-handler.js"></script>
<script src="/mixed/js/text-to-speech-audio.js"></script>
+ <script src="/bg/js/anki-note-builder.js"></script>
+ <script src="/bg/js/template-renderer.js"></script>
+
<script src="/bg/js/query-parser-generator.js"></script>
<script src="/bg/js/query-parser.js"></script>
<script src="/bg/js/clipboard-monitor.js"></script>
diff --git a/ext/bg/settings.html b/ext/bg/settings.html
index 5ee23785..5e6af7f7 100644
--- a/ext/bg/settings.html
+++ b/ext/bg/settings.html
@@ -1183,6 +1183,7 @@
<script src="/bg/js/dictionary-importer.js"></script>
<script src="/bg/js/json-schema.js"></script>
<script src="/bg/js/media-utility.js"></script>
+ <script src="/bg/js/template-renderer.js"></script>
<script src="/bg/js/settings/keyboard-mouse-input-field.js"></script>
<script src="/bg/js/settings/profile-conditions-ui.js"></script>
diff --git a/ext/fg/float.html b/ext/fg/float.html
index 725b7d8b..98e849f0 100644
--- a/ext/fg/float.html
+++ b/ext/fg/float.html
@@ -44,6 +44,8 @@
</div>
</div>
+ <script src="/mixed/lib/handlebars.min.js"></script>
+
<script src="/mixed/js/core.js"></script>
<script src="/mixed/js/yomichan.js"></script>
<script src="/mixed/js/comm.js"></script>
@@ -66,6 +68,9 @@
<script src="/mixed/js/template-handler.js"></script>
<script src="/mixed/js/text-to-speech-audio.js"></script>
+ <script src="/bg/js/anki-note-builder.js"></script>
+ <script src="/bg/js/template-renderer.js"></script>
+
<script src="/bg/js/query-parser-generator.js"></script>
<script src="/bg/js/query-parser.js"></script>
<script src="/fg/js/float.js"></script>
diff --git a/ext/mixed/js/api.js b/ext/mixed/js/api.js
index 4a1b0c11..1e7625da 100644
--- a/ext/mixed/js/api.js
+++ b/ext/mixed/js/api.js
@@ -89,22 +89,10 @@ const api = (() => {
return this._invoke('injectAnkiNoteMedia', {expression, reading, timestamp, audioDetails, screenshotDetails, clipboardImage});
}
- definitionAdd(definition, mode, context, ownerFrameId, optionsContext) {
- return this._invoke('definitionAdd', {definition, mode, context, ownerFrameId, optionsContext});
- }
-
- definitionsAddable(definitions, modes, context, optionsContext) {
- return this._invoke('definitionsAddable', {definitions, modes, context, optionsContext});
- }
-
noteView(noteId) {
return this._invoke('noteView', {noteId});
}
- templateRender(template, data, marker) {
- return this._invoke('templateRender', {data, template, marker});
- }
-
audioGetUri(source, expression, reading, details) {
return this._invoke('audioGetUri', {source, expression, reading, details});
}
diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js
index 7dd5920a..4c42a48d 100644
--- a/ext/mixed/js/display.js
+++ b/ext/mixed/js/display.js
@@ -16,6 +16,7 @@
*/
/* global
+ * AnkiNoteBuilder
* AudioSystem
* DisplayGenerator
* DisplayHistory
@@ -24,6 +25,7 @@
* MediaLoader
* PopupFactory
* QueryParser
+ * TemplateRenderer
* WindowScroll
* api
* dynamicLoader
@@ -83,6 +85,12 @@ class Display extends EventDispatcher {
});
this._mode = null;
this._ownerFrameId = null;
+ this._defaultAnkiFieldTemplates = null;
+ this._defaultAnkiFieldTemplatesPromise = null;
+ this._templateRenderer = new TemplateRenderer();
+ this._ankiNoteBuilder = new AnkiNoteBuilder({
+ renderTemplate: this._renderTemplate.bind(this)
+ });
this.registerActions([
['close', () => { this.onEscape(); }],
@@ -891,7 +899,8 @@ class Display extends EventDispatcher {
const modes = isTerms ? ['term-kanji', 'term-kana'] : ['kanji'];
let states;
try {
- states = await this._getDefinitionsAddable(definitions, modes);
+ const noteContext = await this._getNoteContext();
+ states = await this._areDefinitionsAddable(definitions, modes, noteContext);
} catch (e) {
return;
}
@@ -1054,10 +1063,8 @@ class Display extends EventDispatcher {
try {
this.setSpinnerVisible(true);
- const ownerFrameId = this._ownerFrameId;
- const optionsContext = this.getOptionsContext();
const noteContext = await this._getNoteContext();
- const noteId = await api.definitionAdd(definition, mode, noteContext, ownerFrameId, optionsContext);
+ const noteId = await this._addDefinition(definition, mode, noteContext);
if (noteId) {
const index = this._definitions.indexOf(definition);
const adderButton = this._adderButtonFind(index, mode);
@@ -1196,15 +1203,6 @@ class Display extends EventDispatcher {
return container !== null ? container.querySelector('.action-play-audio>img') : null;
}
- async _getDefinitionsAddable(definitions, modes) {
- try {
- const noteContext = await this._getNoteContext();
- return await api.definitionsAddable(definitions, modes, noteContext, this.getOptionsContext());
- } catch (e) {
- return [];
- }
- }
-
_indexOf(nodeList, node) {
for (let i = 0, ii = nodeList.length; i < ii; ++i) {
if (nodeList[i] === node) {
@@ -1315,4 +1313,108 @@ class Display extends EventDispatcher {
this._mode = mode;
this.trigger('modeChange', {mode});
}
+
+ async _getTemplates(options) {
+ let templates = options.anki.fieldTemplates;
+ if (typeof templates === 'string') { return templates; }
+
+ templates = this._defaultAnkiFieldTemplates;
+ if (typeof templates === 'string') { return templates; }
+
+ return await this._getDefaultTemplatesPromise();
+ }
+
+ _getDefaultTemplatesPromise() {
+ if (this._defaultAnkiFieldTemplatesPromise === null) {
+ this._defaultAnkiFieldTemplatesPromise = this._getDefaultTemplates();
+ this._defaultAnkiFieldTemplatesPromise.then(
+ () => { this._defaultAnkiFieldTemplatesPromise = null; },
+ () => {} // NOP
+ );
+ }
+ return this._defaultAnkiFieldTemplatesPromise;
+ }
+
+ async _getDefaultTemplates() {
+ const value = await api.getDefaultAnkiFieldTemplates();
+ this._defaultAnkiFieldTemplates = value;
+ return value;
+ }
+
+ async _renderTemplate(template, data, marker) {
+ return await this._templateRenderer.render(template, data, marker);
+ }
+
+ async _addDefinition(definition, mode, context) {
+ const options = this._options;
+ const templates = await this._getTemplates(options);
+ const note = await this._createNote(definition, mode, context, options, templates, true);
+ return await api.addAnkiNote(note);
+ }
+
+ async _areDefinitionsAddable(definitions, modes, context) {
+ const options = this._options;
+ const templates = await this._getTemplates(options);
+
+ const modeCount = modes.length;
+ const {duplicateScope} = options.anki;
+ const notePromises = [];
+ for (const definition of definitions) {
+ for (const mode of modes) {
+ const notePromise = this._createNote(definition, mode, context, options, templates, false);
+ notePromises.push(notePromise);
+ }
+ }
+ const notes = await Promise.all(notePromises);
+
+ const infos = await api.getAnkiNoteInfo(notes, duplicateScope);
+ const results = [];
+ for (let i = 0, ii = infos.length; i < ii; i += modeCount) {
+ results.push(infos.slice(i, i + modeCount));
+ }
+ return results;
+ }
+
+ async _createNote(definition, mode, context, options, templates, injectMedia) {
+ const {
+ general: {resultOutputMode, compactGlossaries},
+ anki: {tags, duplicateScope, kanji, terms, screenshot: {format, quality}},
+ audio: {sources, customSourceUrl}
+ } = options;
+ const modeOptions = (mode === 'kanji') ? kanji : terms;
+
+ if (injectMedia) {
+ const timestamp = Date.now();
+ const ownerFrameId = this._ownerFrameId;
+ const {fields} = modeOptions;
+ const definitionExpressions = definition.expressions;
+ const {expression, reading} = Array.isArray(definitionExpressions) ? definitionExpressions[0] : definition;
+ const audioDetails = (mode !== 'kanji' && this._ankiNoteBuilder.containsMarker(fields, 'audio') ? {sources, customSourceUrl} : null);
+ const screenshotDetails = (this._ankiNoteBuilder.containsMarker(fields, 'screenshot') ? {ownerFrameId, format, quality} : null);
+ const clipboardImage = (this._ankiNoteBuilder.containsMarker(fields, 'clipboard-image'));
+ const {screenshotFileName, clipboardImageFileName, audioFileName} = await api.injectAnkiNoteMedia(
+ expression,
+ reading,
+ timestamp,
+ audioDetails,
+ screenshotDetails,
+ clipboardImage
+ );
+ if (screenshotFileName !== null) { definition.screenshotFileName = screenshotFileName; }
+ if (clipboardImageFileName !== null) { definition.clipboardImageFileName = clipboardImageFileName; }
+ if (audioFileName !== null) { definition.audioFileName = audioFileName; }
+ }
+
+ return await this._ankiNoteBuilder.createNote({
+ definition,
+ mode,
+ context,
+ templates,
+ tags,
+ duplicateScope,
+ resultOutputMode,
+ compactGlossaries,
+ modeOptions
+ });
+ }
}