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
This commit is contained in:
parent
9ce682272c
commit
a531618c48
@ -24,7 +24,6 @@
|
|||||||
<script src="/mixed/js/japanese.js"></script>
|
<script src="/mixed/js/japanese.js"></script>
|
||||||
|
|
||||||
<script src="/bg/js/anki.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/backend.js"></script>
|
||||||
<script src="/bg/js/mecab.js"></script>
|
<script src="/bg/js/mecab.js"></script>
|
||||||
<script src="/bg/js/audio-uri-builder.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/options.js"></script>
|
||||||
<script src="/bg/js/profile-conditions.js"></script>
|
<script src="/bg/js/profile-conditions.js"></script>
|
||||||
<script src="/bg/js/request-builder.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/simple-dom-parser.js"></script>
|
||||||
<script src="/bg/js/text-source-map.js"></script>
|
<script src="/bg/js/text-source-map.js"></script>
|
||||||
<script src="/bg/js/translator.js"></script>
|
<script src="/bg/js/translator.js"></script>
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
/* global
|
/* global
|
||||||
* AnkiConnect
|
* AnkiConnect
|
||||||
* AnkiNoteBuilder
|
|
||||||
* AudioSystem
|
* AudioSystem
|
||||||
* AudioUriBuilder
|
* AudioUriBuilder
|
||||||
* ClipboardMonitor
|
* ClipboardMonitor
|
||||||
@ -29,7 +28,6 @@
|
|||||||
* OptionsUtil
|
* OptionsUtil
|
||||||
* ProfileConditions
|
* ProfileConditions
|
||||||
* RequestBuilder
|
* RequestBuilder
|
||||||
* TemplateRenderer
|
|
||||||
* Translator
|
* Translator
|
||||||
* jp
|
* jp
|
||||||
*/
|
*/
|
||||||
@ -57,10 +55,6 @@ class Backend {
|
|||||||
requestBuilder: this._requestBuilder,
|
requestBuilder: this._requestBuilder,
|
||||||
useCache: false
|
useCache: false
|
||||||
});
|
});
|
||||||
this._ankiNoteBuilder = new AnkiNoteBuilder({
|
|
||||||
renderTemplate: this._renderTemplate.bind(this)
|
|
||||||
});
|
|
||||||
this._templateRenderer = new TemplateRenderer();
|
|
||||||
|
|
||||||
this._clipboardPasteTarget = null;
|
this._clipboardPasteTarget = null;
|
||||||
this._clipboardPasteTargetInitialized = false;
|
this._clipboardPasteTargetInitialized = false;
|
||||||
@ -94,10 +88,7 @@ class Backend {
|
|||||||
['addAnkiNote', {async: true, contentScript: true, handler: this._onApiAddAnkiNote.bind(this)}],
|
['addAnkiNote', {async: true, contentScript: true, handler: this._onApiAddAnkiNote.bind(this)}],
|
||||||
['getAnkiNoteInfo', {async: true, contentScript: true, handler: this._onApiGetAnkiNoteInfo.bind(this)}],
|
['getAnkiNoteInfo', {async: true, contentScript: true, handler: this._onApiGetAnkiNoteInfo.bind(this)}],
|
||||||
['injectAnkiNoteMedia', {async: true, contentScript: true, handler: this._onApiInjectAnkiNoteMedia.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)}],
|
['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)}],
|
['commandExec', {async: false, contentScript: true, handler: this._onApiCommandExec.bind(this)}],
|
||||||
['audioGetUri', {async: true, contentScript: true, handler: this._onApiAudioGetUri.bind(this)}],
|
['audioGetUri', {async: true, contentScript: true, handler: this._onApiAudioGetUri.bind(this)}],
|
||||||
['screenshotGet', {async: true, contentScript: true, handler: this._onApiScreenshotGet.bind(this)}],
|
['screenshotGet', {async: true, contentScript: true, handler: this._onApiScreenshotGet.bind(this)}],
|
||||||
@ -473,7 +464,11 @@ class Backend {
|
|||||||
return results;
|
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(
|
return await this._injectAnkNoteMedia(
|
||||||
this._anki,
|
this._anki,
|
||||||
expression,
|
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}) {
|
async _onApiNoteView({noteId}) {
|
||||||
return await this._anki.guiBrowseNote(noteId);
|
return await this._anki.guiBrowseNote(noteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onApiTemplateRender({template, data, marker}) {
|
|
||||||
return this._renderTemplate(template, data, marker);
|
|
||||||
}
|
|
||||||
|
|
||||||
_onApiCommandExec({command, params}) {
|
_onApiCommandExec({command, params}) {
|
||||||
return this._runCommand(command, params);
|
return this._runCommand(command, params);
|
||||||
}
|
}
|
||||||
@ -1381,10 +1341,6 @@ class Backend {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async _renderTemplate(template, data, marker) {
|
|
||||||
return await this._templateRenderer.render(template, data, marker);
|
|
||||||
}
|
|
||||||
|
|
||||||
_getTemplates(options) {
|
_getTemplates(options) {
|
||||||
const templates = options.anki.fieldTemplates;
|
const templates = options.anki.fieldTemplates;
|
||||||
return typeof templates === 'string' ? templates : this._defaultAnkiFieldTemplates;
|
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) {
|
async _getScreenshot(windowId, tabId, ownerFrameId, format, quality) {
|
||||||
if (typeof windowId !== 'number') {
|
if (typeof windowId !== 'number') {
|
||||||
throw new Error('Invalid window ID');
|
throw new Error('Invalid window ID');
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
/* global
|
/* global
|
||||||
* AnkiNoteBuilder
|
* AnkiNoteBuilder
|
||||||
|
* TemplateRenderer
|
||||||
* api
|
* api
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ class AnkiTemplatesController {
|
|||||||
this._cachedDefinitionValue = null;
|
this._cachedDefinitionValue = null;
|
||||||
this._cachedDefinitionText = null;
|
this._cachedDefinitionText = null;
|
||||||
this._defaultFieldTemplates = null;
|
this._defaultFieldTemplates = null;
|
||||||
|
this._templateRenderer = new TemplateRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
async prepare() {
|
async prepare() {
|
||||||
@ -144,7 +146,7 @@ class AnkiTemplatesController {
|
|||||||
let templates = options.anki.fieldTemplates;
|
let templates = options.anki.fieldTemplates;
|
||||||
if (typeof templates !== 'string') { templates = this._defaultFieldTemplates; }
|
if (typeof templates !== 'string') { templates = this._defaultFieldTemplates; }
|
||||||
const ankiNoteBuilder = new AnkiNoteBuilder({
|
const ankiNoteBuilder = new AnkiNoteBuilder({
|
||||||
renderTemplate: api.templateRender.bind(api)
|
renderTemplate: this._renderTemplate.bind(this)
|
||||||
});
|
});
|
||||||
const {general: {resultOutputMode, compactGlossaries}} = options;
|
const {general: {resultOutputMode, compactGlossaries}} = options;
|
||||||
const note = await ankiNoteBuilder.createNote({
|
const note = await ankiNoteBuilder.createNote({
|
||||||
@ -176,4 +178,8 @@ class AnkiTemplatesController {
|
|||||||
input.classList.toggle('is-invalid', hasException);
|
input.classList.toggle('is-invalid', hasException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _renderTemplate(template, data, marker) {
|
||||||
|
return await this._templateRenderer.render(template, data, marker);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,9 @@
|
|||||||
<script src="/mixed/js/template-handler.js"></script>
|
<script src="/mixed/js/template-handler.js"></script>
|
||||||
<script src="/mixed/js/text-to-speech-audio.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-generator.js"></script>
|
||||||
<script src="/bg/js/query-parser.js"></script>
|
<script src="/bg/js/query-parser.js"></script>
|
||||||
<script src="/bg/js/clipboard-monitor.js"></script>
|
<script src="/bg/js/clipboard-monitor.js"></script>
|
||||||
|
@ -1183,6 +1183,7 @@
|
|||||||
<script src="/bg/js/dictionary-importer.js"></script>
|
<script src="/bg/js/dictionary-importer.js"></script>
|
||||||
<script src="/bg/js/json-schema.js"></script>
|
<script src="/bg/js/json-schema.js"></script>
|
||||||
<script src="/bg/js/media-utility.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/keyboard-mouse-input-field.js"></script>
|
||||||
<script src="/bg/js/settings/profile-conditions-ui.js"></script>
|
<script src="/bg/js/settings/profile-conditions-ui.js"></script>
|
||||||
|
@ -44,6 +44,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script src="/mixed/lib/handlebars.min.js"></script>
|
||||||
|
|
||||||
<script src="/mixed/js/core.js"></script>
|
<script src="/mixed/js/core.js"></script>
|
||||||
<script src="/mixed/js/yomichan.js"></script>
|
<script src="/mixed/js/yomichan.js"></script>
|
||||||
<script src="/mixed/js/comm.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/template-handler.js"></script>
|
||||||
<script src="/mixed/js/text-to-speech-audio.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-generator.js"></script>
|
||||||
<script src="/bg/js/query-parser.js"></script>
|
<script src="/bg/js/query-parser.js"></script>
|
||||||
<script src="/fg/js/float.js"></script>
|
<script src="/fg/js/float.js"></script>
|
||||||
|
@ -89,22 +89,10 @@ const api = (() => {
|
|||||||
return this._invoke('injectAnkiNoteMedia', {expression, reading, timestamp, audioDetails, screenshotDetails, clipboardImage});
|
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) {
|
noteView(noteId) {
|
||||||
return this._invoke('noteView', {noteId});
|
return this._invoke('noteView', {noteId});
|
||||||
}
|
}
|
||||||
|
|
||||||
templateRender(template, data, marker) {
|
|
||||||
return this._invoke('templateRender', {data, template, marker});
|
|
||||||
}
|
|
||||||
|
|
||||||
audioGetUri(source, expression, reading, details) {
|
audioGetUri(source, expression, reading, details) {
|
||||||
return this._invoke('audioGetUri', {source, expression, reading, details});
|
return this._invoke('audioGetUri', {source, expression, reading, details});
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* global
|
/* global
|
||||||
|
* AnkiNoteBuilder
|
||||||
* AudioSystem
|
* AudioSystem
|
||||||
* DisplayGenerator
|
* DisplayGenerator
|
||||||
* DisplayHistory
|
* DisplayHistory
|
||||||
@ -24,6 +25,7 @@
|
|||||||
* MediaLoader
|
* MediaLoader
|
||||||
* PopupFactory
|
* PopupFactory
|
||||||
* QueryParser
|
* QueryParser
|
||||||
|
* TemplateRenderer
|
||||||
* WindowScroll
|
* WindowScroll
|
||||||
* api
|
* api
|
||||||
* dynamicLoader
|
* dynamicLoader
|
||||||
@ -83,6 +85,12 @@ class Display extends EventDispatcher {
|
|||||||
});
|
});
|
||||||
this._mode = null;
|
this._mode = null;
|
||||||
this._ownerFrameId = 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([
|
this.registerActions([
|
||||||
['close', () => { this.onEscape(); }],
|
['close', () => { this.onEscape(); }],
|
||||||
@ -891,7 +899,8 @@ class Display extends EventDispatcher {
|
|||||||
const modes = isTerms ? ['term-kanji', 'term-kana'] : ['kanji'];
|
const modes = isTerms ? ['term-kanji', 'term-kana'] : ['kanji'];
|
||||||
let states;
|
let states;
|
||||||
try {
|
try {
|
||||||
states = await this._getDefinitionsAddable(definitions, modes);
|
const noteContext = await this._getNoteContext();
|
||||||
|
states = await this._areDefinitionsAddable(definitions, modes, noteContext);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1054,10 +1063,8 @@ class Display extends EventDispatcher {
|
|||||||
try {
|
try {
|
||||||
this.setSpinnerVisible(true);
|
this.setSpinnerVisible(true);
|
||||||
|
|
||||||
const ownerFrameId = this._ownerFrameId;
|
|
||||||
const optionsContext = this.getOptionsContext();
|
|
||||||
const noteContext = await this._getNoteContext();
|
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) {
|
if (noteId) {
|
||||||
const index = this._definitions.indexOf(definition);
|
const index = this._definitions.indexOf(definition);
|
||||||
const adderButton = this._adderButtonFind(index, mode);
|
const adderButton = this._adderButtonFind(index, mode);
|
||||||
@ -1196,15 +1203,6 @@ class Display extends EventDispatcher {
|
|||||||
return container !== null ? container.querySelector('.action-play-audio>img') : null;
|
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) {
|
_indexOf(nodeList, node) {
|
||||||
for (let i = 0, ii = nodeList.length; i < ii; ++i) {
|
for (let i = 0, ii = nodeList.length; i < ii; ++i) {
|
||||||
if (nodeList[i] === node) {
|
if (nodeList[i] === node) {
|
||||||
@ -1315,4 +1313,108 @@ class Display extends EventDispatcher {
|
|||||||
this._mode = mode;
|
this._mode = mode;
|
||||||
this.trigger('modeChange', {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
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user