summaryrefslogtreecommitdiff
path: root/ext/js
diff options
context:
space:
mode:
authorsoriac <soriac@users.noreply.github.com>2021-04-30 18:57:53 -0300
committerGitHub <noreply@github.com>2021-04-30 17:57:53 -0400
commitba3f7b3e96df7f034b56132d8c2c90289e16c288 (patch)
treee8f87b440d79d3c43904d43f04fe9c396602c76a /ext/js
parent69a739f00a335496e9222b4758d9c8bf2190df92 (diff)
Show any custom tags on words that have anki cards created (#1628)
* Proof-of-concept for showing card tags (#1626) * Resolved most PR comments: - Added a snackbar notification when clicking tag button - Replaced magnifying glass icon with new tag icon - Button now contains a span w/icon, to use text color - Removed unnecessary attributes from button - Backend now returns full noteInfos object - Frontend now handles filtering tags * Add options to show/hide tag button & filter tags * Do not show tags button if, after filtering, we have zero tags. * Change tags option to enums, optimize tags intersection check & fix code style. * Update options-util.js to include new tag options. * Fix wording on new tag setting. * Add CSS to remove hidden buttons from the display layout. * getAnkiNoteInfo extra parameter for additional info. * Add new tag option to tests. * Remove unnecessary changes related to anki tags option. * Code style fixes.
Diffstat (limited to 'ext/js')
-rw-r--r--ext/js/background/backend.js5
-rw-r--r--ext/js/comm/anki.js6
-rw-r--r--ext/js/comm/api.js4
-rw-r--r--ext/js/data/options-util.js3
-rw-r--r--ext/js/display/display.js65
5 files changed, 75 insertions, 8 deletions
diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js
index 5b133d79..e94ad065 100644
--- a/ext/js/background/backend.js
+++ b/ext/js/background/backend.js
@@ -458,7 +458,7 @@ class Backend {
return await this._anki.addNote(note);
}
- async _onApiGetAnkiNoteInfo({notes}) {
+ async _onApiGetAnkiNoteInfo({notes, fetchAdditionalInfo}) {
const results = [];
const cannotAdd = [];
const canAddArray = await this._anki.canAddNotes(notes);
@@ -482,6 +482,9 @@ class Backend {
const noteIds = noteIdsArray[i];
if (noteIds.length > 0) {
cannotAdd[i].info.noteIds = noteIds;
+ if (fetchAdditionalInfo) {
+ cannotAdd[i].info.noteInfos = await this._anki.notesInfo(noteIds);
+ }
}
}
}
diff --git a/ext/js/comm/anki.js b/ext/js/comm/anki.js
index da234eff..e8cf7afd 100644
--- a/ext/js/comm/anki.js
+++ b/ext/js/comm/anki.js
@@ -71,6 +71,12 @@ class AnkiConnect {
return await this._invoke('canAddNotes', {notes});
}
+ async notesInfo(notes) {
+ if (!this._enabled) { return []; }
+ await this._checkVersion();
+ return await this._invoke('notesInfo', {notes});
+ }
+
async getDeckNames() {
if (!this._enabled) { return []; }
await this._checkVersion();
diff --git a/ext/js/comm/api.js b/ext/js/comm/api.js
index 137cda41..3795dcf4 100644
--- a/ext/js/comm/api.js
+++ b/ext/js/comm/api.js
@@ -52,8 +52,8 @@ class API {
return this._invoke('addAnkiNote', {note});
}
- getAnkiNoteInfo(notes) {
- return this._invoke('getAnkiNoteInfo', {notes});
+ getAnkiNoteInfo(notes, fetchAdditionalInfo) {
+ return this._invoke('getAnkiNoteInfo', {notes, fetchAdditionalInfo});
}
injectAnkiNoteMedia(timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails) {
diff --git a/ext/js/data/options-util.js b/ext/js/data/options-util.js
index 42f9a38f..cb7946f7 100644
--- a/ext/js/data/options-util.js
+++ b/ext/js/data/options-util.js
@@ -792,6 +792,7 @@ class OptionsUtil {
// Version 11 changes:
// Changed dictionaries to an array.
// Changed audio.customSourceUrl's {expression} marker to {term}.
+ // Added anki.displayTags.
const customSourceUrlPattern = /\{expression\}/g;
for (const profile of options.profiles) {
const dictionariesNew = [];
@@ -805,6 +806,8 @@ class OptionsUtil {
customSourceUrl = customSourceUrl.replace(customSourceUrlPattern, '{term}');
}
profile.options.audio.customSourceUrl = customSourceUrl;
+
+ profile.options.anki.displayTags = 'never';
}
return options;
}
diff --git a/ext/js/display/display.js b/ext/js/display/display.js
index fcfa0244..720e1de5 100644
--- a/ext/js/display/display.js
+++ b/ext/js/display/display.js
@@ -113,6 +113,7 @@ class Display extends EventDispatcher {
this._displayAudio = new DisplayAudio(this);
this._ankiNoteNotification = null;
this._ankiNoteNotificationEventListeners = null;
+ this._ankiTagNotification = null;
this._queryPostProcessor = null;
this._optionToggleHotkeyHandler = new OptionToggleHotkeyHandler(this);
this._elementOverflowController = new ElementOverflowController();
@@ -1081,8 +1082,8 @@ class Display extends EventDispatcher {
let states;
try {
const noteContext = this._getNoteContext();
- const {checkForDuplicates} = this._options.anki;
- states = await this._areDictionaryEntriesAddable(dictionaryEntries, modes, noteContext, checkForDuplicates ? null : true);
+ const {checkForDuplicates, displayTags} = this._options.anki;
+ states = await this._areDictionaryEntriesAddable(dictionaryEntries, modes, noteContext, checkForDuplicates ? null : true, displayTags !== 'never');
} catch (e) {
return;
}
@@ -1096,11 +1097,12 @@ class Display extends EventDispatcher {
}
_updateAdderButtons2(states, modes) {
+ const {displayTags} = this._options.anki;
for (let i = 0, ii = states.length; i < ii; ++i) {
const infos = states[i];
let noteId = null;
for (let j = 0, jj = infos.length; j < jj; ++j) {
- const {canAdd, noteIds} = infos[j];
+ const {canAdd, noteIds, noteInfos} = infos[j];
const mode = modes[j];
const button = this._adderButtonFind(i, mode);
if (button === null) {
@@ -1112,6 +1114,10 @@ class Display extends EventDispatcher {
}
button.disabled = !canAdd;
button.hidden = false;
+
+ if (displayTags !== 'never' && Array.isArray(noteInfos)) {
+ this._setupTagsIndicator(i, noteInfos);
+ }
}
if (noteId !== null) {
this._viewerButtonShow(i, noteId);
@@ -1119,6 +1125,49 @@ class Display extends EventDispatcher {
}
}
+ _setupTagsIndicator(i, noteInfos) {
+ const tagsIndicator = this._tagsIndicatorFind(i);
+ if (tagsIndicator === null) {
+ return;
+ }
+
+ const {tags: optionTags, displayTags} = this._options.anki;
+ const noteTags = new Set();
+ for (const {tags} of noteInfos) {
+ for (const tag of tags) {
+ noteTags.add(tag);
+ }
+ }
+ if (displayTags === 'non-standard') {
+ for (const tag of optionTags) {
+ noteTags.delete(tag);
+ }
+ }
+
+ if (noteTags.size > 0) {
+ tagsIndicator.disabled = false;
+ tagsIndicator.hidden = false;
+ tagsIndicator.title = `Card tags: ${[...noteTags].join(', ')}`;
+ }
+ }
+
+ _onShowTags(e) {
+ e.preventDefault();
+ const tags = e.currentTarget.title;
+ this._showAnkiTagsNotification(tags);
+ }
+
+ _showAnkiTagsNotification(message) {
+ if (this._ankiTagNotification === null) {
+ const node = this._displayGenerator.createEmptyFooterNotification();
+ node.classList.add('click-scannable');
+ this._ankiTagNotification = new DisplayNotification(this._footerNotificationContainer, node);
+ }
+
+ this._ankiTagNotification.setContent(message);
+ this._ankiTagNotification.open();
+ }
+
_entrySetCurrent(index) {
const entryPre = this._getEntry(this._index);
if (entryPre !== null) {
@@ -1320,6 +1369,11 @@ class Display extends EventDispatcher {
return entry !== null ? entry.querySelector(`.action-add-note[data-mode="${mode}"]`) : null;
}
+ _tagsIndicatorFind(index) {
+ const entry = this._getEntry(index);
+ return entry !== null ? entry.querySelector('.action-view-tags') : null;
+ }
+
_viewerButtonFind(index) {
const entry = this._getEntry(index);
return entry !== null ? entry.querySelector('.action-view-note') : null;
@@ -1424,7 +1478,7 @@ class Display extends EventDispatcher {
return templates;
}
- async _areDictionaryEntriesAddable(dictionaryEntries, modes, context, forceCanAddValue) {
+ async _areDictionaryEntriesAddable(dictionaryEntries, modes, context, forceCanAddValue, fetchAdditionalInfo) {
const modeCount = modes.length;
const notePromises = [];
for (const dictionaryEntry of dictionaryEntries) {
@@ -1442,7 +1496,7 @@ class Display extends EventDispatcher {
}
infos = this._getAnkiNoteInfoForceValue(notes, forceCanAddValue);
} else {
- infos = await yomichan.api.getAnkiNoteInfo(notes);
+ infos = await yomichan.api.getAnkiNoteInfo(notes, fetchAdditionalInfo);
}
const results = [];
@@ -1703,6 +1757,7 @@ class Display extends EventDispatcher {
_addEntryEventListeners(entry) {
this._eventListeners.addEventListener(entry, 'click', this._onEntryClick.bind(this));
+ this._addMultipleEventListeners(entry, '.action-view-tags', 'click', this._onShowTags.bind(this));
this._addMultipleEventListeners(entry, '.action-add-note', 'click', this._onNoteAdd.bind(this));
this._addMultipleEventListeners(entry, '.action-view-note', 'click', this._onNoteView.bind(this));
this._addMultipleEventListeners(entry, '.headword-kanji-link', 'click', this._onKanjiLookup.bind(this));