Merge pull request #415 from toasted-nutbread/anki-marker-document-title
Anki marker document title
This commit is contained in:
commit
fa68a87736
@ -156,6 +156,7 @@ Flashcard fields can be configured with the following steps:
|
|||||||
`{cloze-prefix}` | Text for the containing `{sentence}` from the start up to the value of `{cloze-body}`.
|
`{cloze-prefix}` | Text for the containing `{sentence}` from the start up to the value of `{cloze-body}`.
|
||||||
`{cloze-suffix}` | Text for the containing `{sentence}` from the value of `{cloze-body}` to the end.
|
`{cloze-suffix}` | Text for the containing `{sentence}` from the value of `{cloze-body}` to the end.
|
||||||
`{dictionary}` | Name of the dictionary from which the card is being created (unavailable in *grouped* mode).
|
`{dictionary}` | Name of the dictionary from which the card is being created (unavailable in *grouped* mode).
|
||||||
|
`{document-title}` | Title of the web page that the term appeared in.
|
||||||
`{expression}` | Term expressed as Kanji (will be displayed in Kana if Kanji is not available).
|
`{expression}` | Term expressed as Kanji (will be displayed in Kana if Kanji is not available).
|
||||||
`{furigana}` | Term expressed as Kanji with Furigana displayed above it (e.g. <ruby>日本語<rt>にほんご</rt></ruby>).
|
`{furigana}` | Term expressed as Kanji with Furigana displayed above it (e.g. <ruby>日本語<rt>にほんご</rt></ruby>).
|
||||||
`{furigana-plain}` | Term expressed as Kanji with Furigana displayed next to it in brackets (e.g. 日本語[にほんご]).
|
`{furigana-plain}` | Term expressed as Kanji with Furigana displayed next to it in brackets (e.g. 日本語[にほんご]).
|
||||||
@ -175,6 +176,7 @@ Flashcard fields can be configured with the following steps:
|
|||||||
`{cloze-prefix}` | Text for the containing `{sentence}` from the start up to the value of `{cloze-body}`.
|
`{cloze-prefix}` | Text for the containing `{sentence}` from the start up to the value of `{cloze-body}`.
|
||||||
`{cloze-suffix}` | Text for the containing `{sentence}` from the value of `{cloze-body}` to the end.
|
`{cloze-suffix}` | Text for the containing `{sentence}` from the value of `{cloze-body}` to the end.
|
||||||
`{dictionary}` | Name of the dictionary from which the card is being created.
|
`{dictionary}` | Name of the dictionary from which the card is being created.
|
||||||
|
`{document-title}` | Title of the web page that the Kanji appeared in.
|
||||||
`{glossary}` | List of definitions for the Kanji.
|
`{glossary}` | List of definitions for the Kanji.
|
||||||
`{kunyomi}` | Kunyomi (Japanese reading) for the Kanji expressed as Katakana.
|
`{kunyomi}` | Kunyomi (Japanese reading) for the Kanji expressed as Katakana.
|
||||||
`{onyomi}` | Onyomi (Chinese reading) for the Kanji expressed as Hiragana.
|
`{onyomi}` | Onyomi (Chinese reading) for the Kanji expressed as Hiragana.
|
||||||
|
@ -158,4 +158,8 @@
|
|||||||
<img src="{{definition.screenshotFileName}}" />
|
<img src="{{definition.screenshotFileName}}" />
|
||||||
{{/inline}}
|
{{/inline}}
|
||||||
|
|
||||||
|
{{#*inline "document-title"}}
|
||||||
|
{{~context.document.title~}}
|
||||||
|
{{/inline}}
|
||||||
|
|
||||||
{{~> (lookup . "marker") ~}}
|
{{~> (lookup . "marker") ~}}
|
@ -21,7 +21,7 @@ class AnkiNoteBuilder {
|
|||||||
this._renderTemplate = renderTemplate;
|
this._renderTemplate = renderTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
async createNote(definition, mode, options, templates) {
|
async createNote(definition, mode, context, options, templates) {
|
||||||
const isKanji = (mode === 'kanji');
|
const isKanji = (mode === 'kanji');
|
||||||
const tags = options.anki.tags;
|
const tags = options.anki.tags;
|
||||||
const modeOptions = isKanji ? options.anki.kanji : options.anki.terms;
|
const modeOptions = isKanji ? options.anki.kanji : options.anki.terms;
|
||||||
@ -35,7 +35,7 @@ class AnkiNoteBuilder {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (const [fieldName, fieldValue] of modeOptionsFieldEntries) {
|
for (const [fieldName, fieldValue] of modeOptionsFieldEntries) {
|
||||||
note.fields[fieldName] = await this.formatField(fieldValue, definition, mode, options, templates, null);
|
note.fields[fieldName] = await this.formatField(fieldValue, definition, mode, context, options, templates, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isKanji && definition.audio) {
|
if (!isKanji && definition.audio) {
|
||||||
@ -60,7 +60,7 @@ class AnkiNoteBuilder {
|
|||||||
return note;
|
return note;
|
||||||
}
|
}
|
||||||
|
|
||||||
async formatField(field, definition, mode, options, templates, errors=null) {
|
async formatField(field, definition, mode, context, options, templates, errors=null) {
|
||||||
const data = {
|
const data = {
|
||||||
marker: null,
|
marker: null,
|
||||||
definition,
|
definition,
|
||||||
@ -69,7 +69,8 @@ class AnkiNoteBuilder {
|
|||||||
modeTermKanji: mode === 'term-kanji',
|
modeTermKanji: mode === 'term-kanji',
|
||||||
modeTermKana: mode === 'term-kana',
|
modeTermKana: mode === 'term-kana',
|
||||||
modeKanji: mode === 'kanji',
|
modeKanji: mode === 'kanji',
|
||||||
compactGlossaries: options.general.compactGlossaries
|
compactGlossaries: options.general.compactGlossaries,
|
||||||
|
context
|
||||||
};
|
};
|
||||||
const pattern = /\{([\w-]+)\}/g;
|
const pattern = /\{([\w-]+)\}/g;
|
||||||
return await AnkiNoteBuilder.stringReplaceAsync(field, pattern, async (g0, marker) => {
|
return await AnkiNoteBuilder.stringReplaceAsync(field, pattern, async (g0, marker) => {
|
||||||
|
@ -455,7 +455,7 @@ class Backend {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onApiDefinitionAdd({definition, mode, context, optionsContext}) {
|
async _onApiDefinitionAdd({definition, mode, context, details, optionsContext}) {
|
||||||
const options = this.getOptions(optionsContext);
|
const options = this.getOptions(optionsContext);
|
||||||
const templates = this.defaultAnkiFieldTemplates;
|
const templates = this.defaultAnkiFieldTemplates;
|
||||||
|
|
||||||
@ -468,19 +468,19 @@ class Backend {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context && context.screenshot) {
|
if (details && details.screenshot) {
|
||||||
await this._injectScreenshot(
|
await this._injectScreenshot(
|
||||||
definition,
|
definition,
|
||||||
options.anki.terms.fields,
|
options.anki.terms.fields,
|
||||||
context.screenshot
|
details.screenshot
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const note = await this.ankiNoteBuilder.createNote(definition, mode, options, templates);
|
const note = await this.ankiNoteBuilder.createNote(definition, mode, context, options, templates);
|
||||||
return this.anki.addNote(note);
|
return this.anki.addNote(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onApiDefinitionsAddable({definitions, modes, optionsContext}) {
|
async _onApiDefinitionsAddable({definitions, modes, context, optionsContext}) {
|
||||||
const options = this.getOptions(optionsContext);
|
const options = this.getOptions(optionsContext);
|
||||||
const templates = this.defaultAnkiFieldTemplates;
|
const templates = this.defaultAnkiFieldTemplates;
|
||||||
const states = [];
|
const states = [];
|
||||||
@ -489,7 +489,7 @@ class Backend {
|
|||||||
const notes = [];
|
const notes = [];
|
||||||
for (const definition of definitions) {
|
for (const definition of definitions) {
|
||||||
for (const mode of modes) {
|
for (const mode of modes) {
|
||||||
const note = await this.ankiNoteBuilder.createNote(definition, mode, options, templates);
|
const note = await this.ankiNoteBuilder.createNote(definition, mode, context, options, templates);
|
||||||
notes.push(note);
|
notes.push(note);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,15 @@ const profileOptionsVersionUpdates = [
|
|||||||
if (utilStringHashCode(options.anki.fieldTemplates) === 1444379824) {
|
if (utilStringHashCode(options.anki.fieldTemplates) === 1444379824) {
|
||||||
options.anki.fieldTemplates = null;
|
options.anki.fieldTemplates = null;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
(options) => {
|
||||||
|
// Version 13 changes:
|
||||||
|
// Default anki field tempaltes updated to include {document-title}.
|
||||||
|
let fieldTemplates = options.anki.fieldTemplates;
|
||||||
|
if (typeof fieldTemplates === 'string') {
|
||||||
|
fieldTemplates += '\n\n{{#*inline "document-title"}}\n {{~context.document.title~}}\n{{/inline}}';
|
||||||
|
options.anki.fieldTemplates = fieldTemplates;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -99,10 +99,15 @@ async function ankiTemplatesValidate(infoNode, field, mode, showSuccessResult, i
|
|||||||
const definition = await ankiTemplatesValidateGetDefinition(text, optionsContext);
|
const definition = await ankiTemplatesValidateGetDefinition(text, optionsContext);
|
||||||
if (definition !== null) {
|
if (definition !== null) {
|
||||||
const options = await apiOptionsGet(optionsContext);
|
const options = await apiOptionsGet(optionsContext);
|
||||||
|
const context = {
|
||||||
|
document: {
|
||||||
|
title: document.title
|
||||||
|
}
|
||||||
|
};
|
||||||
let templates = options.anki.fieldTemplates;
|
let templates = options.anki.fieldTemplates;
|
||||||
if (typeof templates !== 'string') { templates = await apiGetDefaultAnkiFieldTemplates(); }
|
if (typeof templates !== 'string') { templates = await apiGetDefaultAnkiFieldTemplates(); }
|
||||||
const ankiNoteBuilder = new AnkiNoteBuilder({renderTemplate: apiTemplateRender});
|
const ankiNoteBuilder = new AnkiNoteBuilder({renderTemplate: apiTemplateRender});
|
||||||
result = await ankiNoteBuilder.formatField(field, definition, mode, options, templates, exceptions);
|
result = await ankiNoteBuilder.formatField(field, definition, mode, context, options, templates, exceptions);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
exceptions.push(e);
|
exceptions.push(e);
|
||||||
|
@ -243,6 +243,7 @@ function ankiGetFieldMarkers(type) {
|
|||||||
'cloze-prefix',
|
'cloze-prefix',
|
||||||
'cloze-suffix',
|
'cloze-suffix',
|
||||||
'dictionary',
|
'dictionary',
|
||||||
|
'document-title',
|
||||||
'expression',
|
'expression',
|
||||||
'furigana',
|
'furigana',
|
||||||
'furigana-plain',
|
'furigana-plain',
|
||||||
@ -258,6 +259,7 @@ function ankiGetFieldMarkers(type) {
|
|||||||
return [
|
return [
|
||||||
'character',
|
'character',
|
||||||
'dictionary',
|
'dictionary',
|
||||||
|
'document-title',
|
||||||
'glossary',
|
'glossary',
|
||||||
'kunyomi',
|
'kunyomi',
|
||||||
'onyomi',
|
'onyomi',
|
||||||
|
@ -162,6 +162,33 @@ class DisplayFloat extends Display {
|
|||||||
setContentScale(scale) {
|
setContentScale(scale) {
|
||||||
document.body.style.fontSize = `${scale}em`;
|
document.body.style.fontSize = `${scale}em`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getDocumentTitle() {
|
||||||
|
try {
|
||||||
|
const uniqueId = yomichan.generateId(16);
|
||||||
|
|
||||||
|
const promise = yomichan.getTemporaryListenerResult(
|
||||||
|
chrome.runtime.onMessage,
|
||||||
|
({action, params}, {resolve}) => {
|
||||||
|
if (
|
||||||
|
action === 'documentInformationBroadcast' &&
|
||||||
|
isObject(params) &&
|
||||||
|
params.uniqueId === uniqueId &&
|
||||||
|
params.frameId === 0
|
||||||
|
) {
|
||||||
|
resolve(params);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
2000
|
||||||
|
);
|
||||||
|
apiForward('requestDocumentInformationBroadcast', {uniqueId});
|
||||||
|
|
||||||
|
const {title} = await promise;
|
||||||
|
return title;
|
||||||
|
} catch (e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplayFloat.instance = new DisplayFloat();
|
DisplayFloat.instance = new DisplayFloat();
|
||||||
|
@ -54,7 +54,8 @@ class Frontend extends TextScanner {
|
|||||||
|
|
||||||
this._runtimeMessageHandlers = new Map([
|
this._runtimeMessageHandlers = new Map([
|
||||||
['popupSetVisibleOverride', ({visible}) => { this.popup.setVisibleOverride(visible); }],
|
['popupSetVisibleOverride', ({visible}) => { this.popup.setVisibleOverride(visible); }],
|
||||||
['rootPopupRequestInformationBroadcast', () => { this._broadcastRootPopupInformation(); }]
|
['rootPopupRequestInformationBroadcast', () => { this._broadcastRootPopupInformation(); }],
|
||||||
|
['requestDocumentInformationBroadcast', ({uniqueId}) => { this._broadcastDocumentInformation(uniqueId); }]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,6 +265,14 @@ class Frontend extends TextScanner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_broadcastDocumentInformation(uniqueId) {
|
||||||
|
apiForward('documentInformationBroadcast', {
|
||||||
|
uniqueId,
|
||||||
|
frameId: this.popup.frameId,
|
||||||
|
title: document.title
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async _updatePopupPosition() {
|
async _updatePopupPosition() {
|
||||||
const textSource = this.getCurrentTextSource();
|
const textSource = this.getCurrentTextSource();
|
||||||
if (textSource !== null && await this.popup.isVisible()) {
|
if (textSource !== null && await this.popup.isVisible()) {
|
||||||
|
@ -53,12 +53,12 @@ function apiKanjiFind(text, optionsContext) {
|
|||||||
return _apiInvoke('kanjiFind', {text, optionsContext});
|
return _apiInvoke('kanjiFind', {text, optionsContext});
|
||||||
}
|
}
|
||||||
|
|
||||||
function apiDefinitionAdd(definition, mode, context, optionsContext) {
|
function apiDefinitionAdd(definition, mode, context, details, optionsContext) {
|
||||||
return _apiInvoke('definitionAdd', {definition, mode, context, optionsContext});
|
return _apiInvoke('definitionAdd', {definition, mode, context, details, optionsContext});
|
||||||
}
|
}
|
||||||
|
|
||||||
function apiDefinitionsAddable(definitions, modes, optionsContext) {
|
function apiDefinitionsAddable(definitions, modes, context, optionsContext) {
|
||||||
return _apiInvoke('definitionsAddable', {definitions, modes, optionsContext});
|
return _apiInvoke('definitionsAddable', {definitions, modes, context, optionsContext});
|
||||||
}
|
}
|
||||||
|
|
||||||
function apiNoteView(noteId) {
|
function apiNoteView(noteId) {
|
||||||
|
@ -752,15 +752,16 @@ class Display {
|
|||||||
try {
|
try {
|
||||||
this.setSpinnerVisible(true);
|
this.setSpinnerVisible(true);
|
||||||
|
|
||||||
const context = {};
|
const details = {};
|
||||||
if (this.noteUsesScreenshot(mode)) {
|
if (this.noteUsesScreenshot(mode)) {
|
||||||
const screenshot = await this.getScreenshot();
|
const screenshot = await this.getScreenshot();
|
||||||
if (screenshot) {
|
if (screenshot) {
|
||||||
context.screenshot = screenshot;
|
details.screenshot = screenshot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const noteId = await apiDefinitionAdd(definition, mode, context, this.getOptionsContext());
|
const context = await this._getNoteContext();
|
||||||
|
const noteId = await apiDefinitionAdd(definition, mode, context, details, this.getOptionsContext());
|
||||||
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);
|
||||||
@ -908,12 +909,17 @@ class Display {
|
|||||||
|
|
||||||
async getDefinitionsAddable(definitions, modes) {
|
async getDefinitionsAddable(definitions, modes) {
|
||||||
try {
|
try {
|
||||||
return await apiDefinitionsAddable(definitions, modes, this.getOptionsContext());
|
const context = await this._getNoteContext();
|
||||||
|
return await apiDefinitionsAddable(definitions, modes, context, this.getOptionsContext());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getDocumentTitle() {
|
||||||
|
return document.title;
|
||||||
|
}
|
||||||
|
|
||||||
static indexOf(nodeList, node) {
|
static 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) {
|
||||||
@ -934,6 +940,15 @@ class Display {
|
|||||||
return (typeof key === 'string' ? (key.length === 1 ? key.toUpperCase() : key) : '');
|
return (typeof key === 'string' ? (key.length === 1 ? key.toUpperCase() : key) : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _getNoteContext() {
|
||||||
|
const documentTitle = await this.getDocumentTitle();
|
||||||
|
return {
|
||||||
|
document: {
|
||||||
|
title: documentTitle
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async _getAudioUri(definition, source) {
|
async _getAudioUri(definition, source) {
|
||||||
const optionsContext = this.getOptionsContext();
|
const optionsContext = this.getOptionsContext();
|
||||||
return await apiAudioGetUri(definition, source, optionsContext);
|
return await apiAudioGetUri(definition, source, optionsContext);
|
||||||
|
Loading…
Reference in New Issue
Block a user