Display refactoring (#1978)

* Refactor _setContentTermsOrKanji

* Update query assignment

* Simplify

* Remove redundant _updateQueryParser

* Reorder query assignment

* Remove isTerms, replace with isKanji

* Simplify defaults

* Refactor events

* Update DisplayAnki to use events

* Simplify

* Update DisplayAudio to use events

* Simplify

* Move audio hotkeys

* Add frameVisibilityChange event

* Fix name

* Add logDictionaryEntryData event

* Move clearAutoPlayTimer handler

* Fix call

* Externalize DisplayAnki and DisplayAudio from Display

* Simplify clear
This commit is contained in:
toasted-nutbread 2021-10-03 16:46:15 -04:00 committed by GitHub
parent d14268eb57
commit be8ef53e90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 203 additions and 199 deletions

View File

@ -23,8 +23,9 @@
*/ */
class DisplayAnki { class DisplayAnki {
constructor(display, japaneseUtil) { constructor(display, displayAudio, japaneseUtil) {
this._display = display; this._display = display;
this._displayAudio = displayAudio;
this._ankiFieldTemplates = null; this._ankiFieldTemplates = null;
this._ankiFieldTemplatesDefault = null; this._ankiFieldTemplatesDefault = null;
this._ankiNoteBuilder = new AnkiNoteBuilder({japaneseUtil}); this._ankiNoteBuilder = new AnkiNoteBuilder({japaneseUtil});
@ -70,28 +71,11 @@ class DisplayAnki {
['viewNote', this._viewNoteForSelectedEntry.bind(this)] ['viewNote', this._viewNoteForSelectedEntry.bind(this)]
]); ]);
this._display.on('optionsUpdated', this._onOptionsUpdated.bind(this)); this._display.on('optionsUpdated', this._onOptionsUpdated.bind(this));
} this._display.on('contentClear', this._onContentClear.bind(this));
this._display.on('contentUpdateStart', this._onContentUpdateStart.bind(this));
cleanupEntries() { this._display.on('contentUpdateEntry', this._onContentUpdateEntry.bind(this));
this._updateDictionaryEntryDetailsToken = null; this._display.on('contentUpdateComplete', this._onContentUpdateComplete.bind(this));
this._dictionaryEntryDetails = null; this._display.on('logDictionaryEntryData', this._onLogDictionaryEntryData.bind(this));
this._hideAnkiNoteErrors(false);
}
setupEntriesBegin() {
this._noteContext = this._getNoteContext();
}
setupEntry(entry) {
this._addMultipleEventListeners(entry, '.action-view-tags', 'click', this._onShowTagsBind);
this._addMultipleEventListeners(entry, '.action-add-note', 'click', this._onNoteAddBind);
this._addMultipleEventListeners(entry, '.action-view-note', 'click', this._onViewNoteButtonClickBind);
this._addMultipleEventListeners(entry, '.action-view-note', 'contextmenu', this._onViewNoteButtonContextMenuBind);
this._addMultipleEventListeners(entry, '.action-view-note', 'menuClose', this._onViewNoteButtonMenuCloseBind);
}
setupEntriesComplete() {
this._updateDictionaryEntryDetails();
} }
async getLogData(dictionaryEntry) { async getLogData(dictionaryEntry) {
@ -173,6 +157,32 @@ class DisplayAnki {
this._updateAnkiFieldTemplates(options); this._updateAnkiFieldTemplates(options);
} }
_onContentClear() {
this._updateDictionaryEntryDetailsToken = null;
this._dictionaryEntryDetails = null;
this._hideAnkiNoteErrors(false);
}
_onContentUpdateStart() {
this._noteContext = this._getNoteContext();
}
_onContentUpdateEntry({element}) {
this._addMultipleEventListeners(element, '.action-view-tags', 'click', this._onShowTagsBind);
this._addMultipleEventListeners(element, '.action-add-note', 'click', this._onNoteAddBind);
this._addMultipleEventListeners(element, '.action-view-note', 'click', this._onViewNoteButtonClickBind);
this._addMultipleEventListeners(element, '.action-view-note', 'contextmenu', this._onViewNoteButtonContextMenuBind);
this._addMultipleEventListeners(element, '.action-view-note', 'menuClose', this._onViewNoteButtonMenuCloseBind);
}
_onContentUpdateComplete() {
this._updateDictionaryEntryDetails();
}
_onLogDictionaryEntryData({dictionaryEntry, promises}) {
promises.push(this.getLogData(dictionaryEntry));
}
_onNoteAdd(e) { _onNoteAdd(e) {
e.preventDefault(); e.preventDefault();
const node = e.currentTarget; const node = e.currentTarget;
@ -526,7 +536,7 @@ class DisplayAnki {
const fields = Object.entries(modeOptions.fields); const fields = Object.entries(modeOptions.fields);
const contentOrigin = this._display.getContentOrigin(); const contentOrigin = this._display.getContentOrigin();
const details = this._ankiNoteBuilder.getDictionaryEntryDetailsForNote(dictionaryEntry); const details = this._ankiNoteBuilder.getDictionaryEntryDetailsForNote(dictionaryEntry);
const audioDetails = (details.type === 'term' ? this._display.getAnkiNoteMediaAudioDetails(details.term, details.reading) : null); const audioDetails = (details.type === 'term' ? this._displayAudio.getAnkiNoteMediaAudioDetails(details.term, details.reading) : null);
const optionsContext = this._display.getOptionsContext(); const optionsContext = this._display.getOptionsContext();
const {note, errors, requirements: outputRequirements} = await this._ankiNoteBuilder.createNote({ const {note, errors, requirements: outputRequirements} = await this._ankiNoteBuilder.createNote({

View File

@ -56,49 +56,21 @@ class DisplayAudio {
prepare() { prepare() {
this._audioSystem.prepare(); this._audioSystem.prepare();
this._display.hotkeyHandler.registerActions([
['playAudio', this._onHotkeyActionPlayAudio.bind(this)],
['playAudioFromSource', this._onHotkeyActionPlayAudioFromSource.bind(this)]
]);
this._display.registerDirectMessageHandlers([
['clearAutoPlayTimer', {async: false, handler: this._onMessageClearAutoPlayTimer.bind(this)}]
]);
this._display.on('optionsUpdated', this._onOptionsUpdated.bind(this)); this._display.on('optionsUpdated', this._onOptionsUpdated.bind(this));
this._display.on('contentClear', this._onContentClear.bind(this));
this._display.on('contentUpdateEntry', this._onContentUpdateEntry.bind(this));
this._display.on('contentUpdateComplete', this._onContentUpdateComplete.bind(this));
this._display.on('frameVisibilityChange', this._onFrameVisibilityChange.bind(this));
this._onOptionsUpdated({options: this._display.getOptions()}); this._onOptionsUpdated({options: this._display.getOptions()});
} }
cleanupEntries() {
this._entriesToken = {};
this._cache.clear();
this.clearAutoPlayTimer();
this._eventListeners.removeAllEventListeners();
}
setupEntry(entry, dictionaryEntryIndex) {
for (const button of entry.querySelectorAll('.action-play-audio')) {
const headwordIndex = this._getAudioPlayButtonHeadwordIndex(button);
this._eventListeners.addEventListener(button, 'click', this._onAudioPlayButtonClick.bind(this, dictionaryEntryIndex, headwordIndex), false);
this._eventListeners.addEventListener(button, 'contextmenu', this._onAudioPlayButtonContextMenu.bind(this, dictionaryEntryIndex, headwordIndex), false);
this._eventListeners.addEventListener(button, 'menuClose', this._onAudioPlayMenuCloseClick.bind(this, dictionaryEntryIndex, headwordIndex), false);
}
}
setupEntriesComplete() {
if (!this._autoPlay || !this._display.frameVisible) { return; }
this.clearAutoPlayTimer();
const {dictionaryEntries} = this._display;
if (dictionaryEntries.length === 0) { return; }
const firstDictionaryEntries = dictionaryEntries[0];
if (firstDictionaryEntries.type === 'kanji') { return; }
const callback = () => {
this._autoPlayAudioTimer = null;
this.playAudio(0, 0);
};
if (this._autoPlayAudioDelay > 0) {
this._autoPlayAudioTimer = setTimeout(callback, this._autoPlayAudioDelay);
} else {
callback();
}
}
clearAutoPlayTimer() { clearAutoPlayTimer() {
if (this._autoPlayAudioTimer === null) { return; } if (this._autoPlayAudioTimer === null) { return; }
clearTimeout(this._autoPlayAudioTimer); clearTimeout(this._autoPlayAudioTimer);
@ -171,6 +143,64 @@ class DisplayAudio {
this._cache.clear(); this._cache.clear();
} }
_onContentClear() {
this._entriesToken = {};
this._cache.clear();
this.clearAutoPlayTimer();
this._eventListeners.removeAllEventListeners();
}
_onContentUpdateEntry({element, index}) {
for (const button of element.querySelectorAll('.action-play-audio')) {
const headwordIndex = this._getAudioPlayButtonHeadwordIndex(button);
this._eventListeners.addEventListener(button, 'click', this._onAudioPlayButtonClick.bind(this, index, headwordIndex), false);
this._eventListeners.addEventListener(button, 'contextmenu', this._onAudioPlayButtonContextMenu.bind(this, index, headwordIndex), false);
this._eventListeners.addEventListener(button, 'menuClose', this._onAudioPlayMenuCloseClick.bind(this, index, headwordIndex), false);
}
}
_onContentUpdateComplete() {
if (!this._autoPlay || !this._display.frameVisible) { return; }
this.clearAutoPlayTimer();
const {dictionaryEntries} = this._display;
if (dictionaryEntries.length === 0) { return; }
const firstDictionaryEntries = dictionaryEntries[0];
if (firstDictionaryEntries.type === 'kanji') { return; }
const callback = () => {
this._autoPlayAudioTimer = null;
this.playAudio(0, 0);
};
if (this._autoPlayAudioDelay > 0) {
this._autoPlayAudioTimer = setTimeout(callback, this._autoPlayAudioDelay);
} else {
callback();
}
}
_onFrameVisibilityChange({value}) {
if (!value) {
this.clearAutoPlayTimer();
this.stopAudio();
}
}
_onHotkeyActionPlayAudio() {
this.playAudio(this._display.selectedIndex, 0);
}
_onHotkeyActionPlayAudioFromSource(source) {
this.playAudio(this._display.selectedIndex, 0, source);
}
_onMessageClearAutoPlayTimer() {
this.clearAutoPlayTimer();
}
_addAudioSourceInfo(type, url, voice, isInOptions, nameMap) { _addAudioSourceInfo(type, url, voice, isInOptions, nameMap) {
const index = this._audioSources.length; const index = this._audioSources.length;
const downloadable = this._sourceIsDownloadable(type); const downloadable = this._sourceIsDownloadable(type);

View File

@ -16,8 +16,6 @@
*/ */
/* global /* global
* DisplayAnki
* DisplayAudio
* DisplayGenerator * DisplayGenerator
* DisplayHistory * DisplayHistory
* DisplayNotification * DisplayNotification
@ -106,10 +104,8 @@ class Display extends EventDispatcher {
this._contentTextScanner = null; this._contentTextScanner = null;
this._tagNotification = null; this._tagNotification = null;
this._footerNotificationContainer = document.querySelector('#content-footer'); this._footerNotificationContainer = document.querySelector('#content-footer');
this._displayAudio = new DisplayAudio(this);
this._optionToggleHotkeyHandler = new OptionToggleHotkeyHandler(this); this._optionToggleHotkeyHandler = new OptionToggleHotkeyHandler(this);
this._elementOverflowController = new ElementOverflowController(); this._elementOverflowController = new ElementOverflowController();
this._displayAnki = new DisplayAnki(this, japaneseUtil);
this._frameVisible = (pageType === 'search'); this._frameVisible = (pageType === 'search');
this._hotkeyHandler.registerActions([ this._hotkeyHandler.registerActions([
@ -120,8 +116,6 @@ class Display extends EventDispatcher {
['firstEntry', () => { this._focusEntry(0, 0, true); }], ['firstEntry', () => { this._focusEntry(0, 0, true); }],
['historyBackward', () => { this._sourceTermView(); }], ['historyBackward', () => { this._sourceTermView(); }],
['historyForward', () => { this._nextTermView(); }], ['historyForward', () => { this._nextTermView(); }],
['playAudio', () => { this._playAudioCurrent(); }],
['playAudioFromSource', this._onHotkeyActionPlayAudioFromSource.bind(this)],
['copyHostSelection', () => this._copyHostSelection()], ['copyHostSelection', () => this._copyHostSelection()],
['nextEntryDifferentDictionary', () => { this._focusEntryWithDifferentDictionary(1, true); }], ['nextEntryDifferentDictionary', () => { this._focusEntryWithDifferentDictionary(1, true); }],
['previousEntryDifferentDictionary', () => { this._focusEntryWithDifferentDictionary(-1, true); }] ['previousEntryDifferentDictionary', () => { this._focusEntryWithDifferentDictionary(-1, true); }]
@ -129,7 +123,6 @@ class Display extends EventDispatcher {
this.registerDirectMessageHandlers([ this.registerDirectMessageHandlers([
['setOptionsContext', {async: false, handler: this._onMessageSetOptionsContext.bind(this)}], ['setOptionsContext', {async: false, handler: this._onMessageSetOptionsContext.bind(this)}],
['setContent', {async: false, handler: this._onMessageSetContent.bind(this)}], ['setContent', {async: false, handler: this._onMessageSetContent.bind(this)}],
['clearAutoPlayTimer', {async: false, handler: this._onMessageClearAutoPlayTimer.bind(this)}],
['setCustomCss', {async: false, handler: this._onMessageSetCustomCss.bind(this)}], ['setCustomCss', {async: false, handler: this._onMessageSetCustomCss.bind(this)}],
['setContentScale', {async: false, handler: this._onMessageSetContentScale.bind(this)}], ['setContentScale', {async: false, handler: this._onMessageSetContentScale.bind(this)}],
['configure', {async: true, handler: this._onMessageConfigure.bind(this)}], ['configure', {async: true, handler: this._onMessageConfigure.bind(this)}],
@ -144,14 +137,6 @@ class Display extends EventDispatcher {
return this._displayGenerator; return this._displayGenerator;
} }
get autoPlayAudioDelay() {
return this._displayAudio.autoPlayAudioDelay;
}
set autoPlayAudioDelay(value) {
this._displayAudio.autoPlayAudioDelay = value;
}
get queryParserVisible() { get queryParserVisible() {
return this._queryParserVisible; return this._queryParserVisible;
} }
@ -230,8 +215,6 @@ class Display extends EventDispatcher {
// Prepare // Prepare
await this._hotkeyHelpController.prepare(); await this._hotkeyHelpController.prepare();
await this._displayGenerator.prepare(); await this._displayGenerator.prepare();
this._displayAudio.prepare();
this._displayAnki.prepare();
this._queryParser.prepare(); this._queryParser.prepare();
this._history.prepare(); this._history.prepare();
this._optionToggleHotkeyHandler.prepare(); this._optionToggleHotkeyHandler.prepare();
@ -345,10 +328,6 @@ class Display extends EventDispatcher {
this.trigger('optionsUpdated', {options}); this.trigger('optionsUpdated', {options});
} }
clearAutoPlayTimer() {
this._displayAudio.clearAutoPlayTimer();
}
setContent(details) { setContent(details) {
const {focus, params, state, content} = details; const {focus, params, state, content} = details;
const historyMode = this._historyHasChanged ? details.historyMode : 'clear'; const historyMode = this._historyHasChanged ? details.historyMode : 'clear';
@ -468,10 +447,6 @@ class Display extends EventDispatcher {
return Number.isFinite(index) ? index : -1; return Number.isFinite(index) ? index : -1;
} }
getAnkiNoteMediaAudioDetails(term, reading) {
return this._displayAudio.getAnkiNoteMediaAudioDetails(term, reading);
}
// Message handlers // Message handlers
_onDirectMessage(data) { _onDirectMessage(data) {
@ -511,10 +486,6 @@ class Display extends EventDispatcher {
this.setContent(details); this.setContent(details);
} }
_onMessageClearAutoPlayTimer() {
this.clearAutoPlayTimer();
}
_onMessageSetCustomCss({css}) { _onMessageSetCustomCss({css}) {
this.setCustomCss(css); this.setCustomCss(css);
} }
@ -534,10 +505,7 @@ class Display extends EventDispatcher {
_onMessageVisibilityChanged({value}) { _onMessageVisibilityChanged({value}) {
this._frameVisible = value; this._frameVisible = value;
if (!value) { this.trigger('frameVisibilityChange', {value});
this._displayAudio.clearAutoPlayTimer();
this._displayAudio.stopAudio();
}
} }
_onMessageExtensionUnloaded() { _onMessageExtensionUnloaded() {
@ -568,9 +536,8 @@ class Display extends EventDispatcher {
this._closeAllPopupMenus(); this._closeAllPopupMenus();
this._eventListeners.removeAllEventListeners(); this._eventListeners.removeAllEventListeners();
this._mediaLoader.unloadAll(); this._mediaLoader.unloadAll();
this._displayAudio.cleanupEntries();
this._displayAnki.cleanupEntries();
this._hideTagNotification(false); this._hideTagNotification(false);
this._triggerContentClear();
this._dictionaryEntries = []; this._dictionaryEntries = [];
this._dictionaryEntryNodes = []; this._dictionaryEntryNodes = [];
this._elementOverflowController.clearElements(); this._elementOverflowController.clearElements();
@ -582,62 +549,25 @@ class Display extends EventDispatcher {
const fullVisible = urlSearchParams.get('full-visible'); const fullVisible = urlSearchParams.get('full-visible');
this._queryParserVisibleOverride = (fullVisible === null ? null : (fullVisible !== 'false')); this._queryParserVisibleOverride = (fullVisible === null ? null : (fullVisible !== 'false'));
this._updateQueryParser();
let clear = true;
this._historyHasChanged = true; this._historyHasChanged = true;
this._contentType = type; this._contentType = type;
this._query = '';
const eventArgs = {type, urlSearchParams, token};
// Set content // Set content
switch (type) { switch (type) {
case 'terms': case 'terms':
case 'kanji': case 'kanji':
{ await this._setContentTermsOrKanji(type, urlSearchParams, token);
const query = urlSearchParams.get('query');
if (query === null) { break; }
this._query = query;
clear = false;
const isTerms = (type === 'terms');
let queryFull = urlSearchParams.get('full');
queryFull = (queryFull !== null ? queryFull : query);
let queryOffset = urlSearchParams.get('offset');
if (queryOffset !== null) {
queryOffset = Number.parseInt(queryOffset, 10);
if (!Number.isFinite(queryOffset)) { queryOffset = null; }
}
const wildcardsEnabled = (urlSearchParams.get('wildcards') !== 'off');
const lookup = (urlSearchParams.get('lookup') !== 'false');
await this._setContentTermsOrKanji(token, isTerms, query, queryFull, queryOffset, lookup, wildcardsEnabled, eventArgs);
}
break; break;
case 'unloaded': case 'unloaded':
{
clear = false;
const {content} = this._history;
eventArgs.content = content;
this.trigger('contentUpdating', eventArgs);
this._setContentExtensionUnloaded(); this._setContentExtensionUnloaded();
}
break; break;
} default:
// Clear
if (clear) {
type = 'clear'; type = 'clear';
this._contentType = type; this._contentType = type;
const {content} = this._history;
eventArgs.type = type;
eventArgs.content = content;
this.trigger('contentUpdating', eventArgs);
this._clearContent(); this._clearContent();
break;
} }
const stale = (this._setContentToken !== token);
eventArgs.stale = stale;
this.trigger('contentUpdated', eventArgs);
} catch (e) { } catch (e) {
this.onError(e); this.onError(e);
} }
@ -874,8 +804,11 @@ class Display extends EventDispatcher {
document.documentElement.dataset.theme = themeName; document.documentElement.dataset.theme = themeName;
} }
async _findDictionaryEntries(isTerms, source, wildcardsEnabled, optionsContext) { async _findDictionaryEntries(isKanji, source, wildcardsEnabled, optionsContext) {
if (isTerms) { if (isKanji) {
const dictionaryEntries = await yomichan.api.kanjiFind(source, optionsContext);
return dictionaryEntries;
} else {
const findDetails = {}; const findDetails = {};
if (wildcardsEnabled) { if (wildcardsEnabled) {
const match = /^([*\uff0a]*)([\w\W]*?)([*\uff0a]*)$/.exec(source); const match = /^([*\uff0a]*)([\w\W]*?)([*\uff0a]*)$/.exec(source);
@ -891,13 +824,24 @@ class Display extends EventDispatcher {
const {dictionaryEntries} = await yomichan.api.termsFind(source, findDetails, optionsContext); const {dictionaryEntries} = await yomichan.api.termsFind(source, findDetails, optionsContext);
return dictionaryEntries; return dictionaryEntries;
} else {
const dictionaryEntries = await yomichan.api.kanjiFind(source, optionsContext);
return dictionaryEntries;
} }
} }
async _setContentTermsOrKanji(token, isTerms, query, queryFull, queryOffset, lookup, wildcardsEnabled, eventArgs) { async _setContentTermsOrKanji(type, urlSearchParams, token) {
const lookup = (urlSearchParams.get('lookup') !== 'false');
const wildcardsEnabled = (urlSearchParams.get('wildcards') !== 'off');
// Set query
const query = urlSearchParams.get('query');
let queryFull = urlSearchParams.get('full');
queryFull = (queryFull !== null ? queryFull : query);
let queryOffset = urlSearchParams.get('offset');
if (queryOffset !== null) {
queryOffset = Number.parseInt(queryOffset, 10);
queryOffset = Number.isFinite(queryOffset) ? Math.max(0, Math.min(queryFull.length - query.length, queryOffset)) : null;
}
this._setQuery(query, queryFull, queryOffset);
let {state, content} = this._history; let {state, content} = this._history;
let changeHistory = false; let changeHistory = false;
if (!isObject(content)) { if (!isObject(content)) {
@ -909,12 +853,7 @@ class Display extends EventDispatcher {
changeHistory = true; changeHistory = true;
} }
let { let {focusEntry, scrollX, scrollY, optionsContext} = state;
focusEntry=null,
scrollX=null,
scrollY=null,
optionsContext=null
} = state;
if (typeof focusEntry !== 'number') { focusEntry = 0; } if (typeof focusEntry !== 'number') { focusEntry = 0; }
if (!(typeof optionsContext === 'object' && optionsContext !== null)) { if (!(typeof optionsContext === 'object' && optionsContext !== null)) {
optionsContext = this.getOptionsContext(); optionsContext = this.getOptionsContext();
@ -922,16 +861,9 @@ class Display extends EventDispatcher {
changeHistory = true; changeHistory = true;
} }
if (queryOffset !== null) {
queryOffset = Math.max(0, Math.min(queryFull.length - query.length, queryOffset));
}
this._setFullQuery(queryFull, queryOffset);
this._setTitleText(query);
let {dictionaryEntries} = content; let {dictionaryEntries} = content;
if (!Array.isArray(dictionaryEntries)) { if (!Array.isArray(dictionaryEntries)) {
dictionaryEntries = lookup && query.length > 0 ? await this._findDictionaryEntries(isTerms, query, wildcardsEnabled, optionsContext) : []; dictionaryEntries = lookup && query.length > 0 ? await this._findDictionaryEntries(type === 'kanji', query, wildcardsEnabled, optionsContext) : [];
if (this._setContentToken !== token) { return; } if (this._setContentToken !== token) { return; }
content.dictionaryEntries = dictionaryEntries; content.dictionaryEntries = dictionaryEntries;
changeHistory = true; changeHistory = true;
@ -964,10 +896,6 @@ class Display extends EventDispatcher {
this._replaceHistoryStateNoNavigate(state, content); this._replaceHistoryStateNoNavigate(state, content);
} }
eventArgs.source = query;
eventArgs.content = content;
this.trigger('contentUpdating', eventArgs);
this._dictionaryEntries = dictionaryEntries; this._dictionaryEntries = dictionaryEntries;
this._updateNavigation(this._history.hasPrevious(), this._history.hasNext()); this._updateNavigation(this._history.hasPrevious(), this._history.hasNext());
@ -976,7 +904,7 @@ class Display extends EventDispatcher {
const container = this._container; const container = this._container;
container.textContent = ''; container.textContent = '';
this._displayAnki.setupEntriesBegin(); this._triggerContentUpdateStart();
for (let i = 0, ii = dictionaryEntries.length; i < ii; ++i) { for (let i = 0, ii = dictionaryEntries.length; i < ii; ++i) {
if (i > 0) { if (i > 0) {
@ -986,15 +914,14 @@ class Display extends EventDispatcher {
const dictionaryEntry = dictionaryEntries[i]; const dictionaryEntry = dictionaryEntries[i];
const entry = ( const entry = (
isTerms ? dictionaryEntry.type === 'term' ?
this._displayGenerator.createTermEntry(dictionaryEntry) : this._displayGenerator.createTermEntry(dictionaryEntry) :
this._displayGenerator.createKanjiEntry(dictionaryEntry) this._displayGenerator.createKanjiEntry(dictionaryEntry)
); );
entry.dataset.index = `${i}`; entry.dataset.index = `${i}`;
this._dictionaryEntryNodes.push(entry); this._dictionaryEntryNodes.push(entry);
this._addEntryEventListeners(entry); this._addEntryEventListeners(entry);
this._displayAudio.setupEntry(entry, i); this._triggerContentUpdateEntry(dictionaryEntry, entry, i);
this._displayAnki.setupEntry(entry, i);
container.appendChild(entry); container.appendChild(entry);
if (focusEntry === i) { if (focusEntry === i) {
this._focusEntry(i, 0, false); this._focusEntry(i, 0, false);
@ -1011,8 +938,7 @@ class Display extends EventDispatcher {
this._windowScroll.to(x, y); this._windowScroll.to(x, y);
} }
this._displayAudio.setupEntriesComplete(); this._triggerContentUpdateComplete();
this._displayAnki.setupEntriesComplete();
} }
_setContentExtensionUnloaded() { _setContentExtensionUnloaded() {
@ -1028,14 +954,18 @@ class Display extends EventDispatcher {
this._updateNavigation(false, false); this._updateNavigation(false, false);
this._setNoContentVisible(false); this._setNoContentVisible(false);
this._setTitleText(''); this._setQuery('', '', 0);
this._setFullQuery('', 0);
this._triggerContentUpdateStart();
this._triggerContentUpdateComplete();
} }
_clearContent() { _clearContent() {
this._container.textContent = ''; this._container.textContent = '';
this._setTitleText(''); this._setQuery('', '', 0);
this._setFullQuery('', 0);
this._triggerContentUpdateStart();
this._triggerContentUpdateComplete();
} }
_setNoContentVisible(visible) { _setNoContentVisible(visible) {
@ -1046,10 +976,12 @@ class Display extends EventDispatcher {
} }
} }
_setFullQuery(text, offset) { _setQuery(query, fullQuery, queryOffset) {
this._fullQuery = text; this._query = query;
this._queryOffset = offset; this._fullQuery = fullQuery;
this._queryOffset = queryOffset;
this._updateQueryParser(); this._updateQueryParser();
this._setTitleText(query);
} }
_updateQueryParser() { _updateQueryParser() {
@ -1219,10 +1151,6 @@ class Display extends EventDispatcher {
} }
} }
async _playAudioCurrent() {
await this._displayAudio.playAudio(this._index, 0);
}
_getEntry(index) { _getEntry(index) {
const entries = this._dictionaryEntryNodes; const entries = this._dictionaryEntryNodes;
return index >= 0 && index < entries.length ? entries[index] : null; return index >= 0 && index < entries.length ? entries[index] : null;
@ -1575,10 +1503,6 @@ class Display extends EventDispatcher {
this._focusEntry(this._index + count * sign, 0, true); this._focusEntry(this._index + count * sign, 0, true);
} }
_onHotkeyActionPlayAudioFromSource(source) {
this._displayAudio.playAudio(this._index, 0, source);
}
_closeAllPopupMenus() { _closeAllPopupMenus() {
for (const popupMenu of PopupMenu.openMenus) { for (const popupMenu of PopupMenu.openMenus) {
popupMenu.close(); popupMenu.close();
@ -1598,9 +1522,32 @@ class Display extends EventDispatcher {
const dictionaryEntry = this._dictionaryEntries[index]; const dictionaryEntry = this._dictionaryEntries[index];
const result = {dictionaryEntry}; const result = {dictionaryEntry};
const result2 = await this._displayAnki.getLogData(dictionaryEntry); const promises = [];
this.trigger('logDictionaryEntryData', {dictionaryEntry, promises});
if (promises.length > 0) {
for (const result2 of await Promise.all(promises)) {
Object.assign(result, result2); Object.assign(result, result2);
}
}
console.log(result); console.log(result);
} }
_triggerContentClear() {
this.trigger('contentClear', {});
}
_triggerContentUpdateStart() {
let {content} = this._history;
if (typeof content !== 'object' || content === null) { content = {}; }
this.trigger('contentUpdateStart', {type: this._contentType, query: this._query, content});
}
_triggerContentUpdateEntry(dictionaryEntry, element, index) {
this.trigger('contentUpdateEntry', {dictionaryEntry, element, index});
}
_triggerContentUpdateComplete() {
this.trigger('contentUpdateComplete', {type: this._contentType});
}
} }

View File

@ -17,6 +17,8 @@
/* global /* global
* Display * Display
* DisplayAnki
* DisplayAudio
* DisplayProfileSelection * DisplayProfileSelection
* DisplayResizer * DisplayResizer
* DocumentFocusController * DocumentFocusController
@ -41,6 +43,12 @@
const display = new Display(tabId, frameId, 'popup', japaneseUtil, documentFocusController, hotkeyHandler); const display = new Display(tabId, frameId, 'popup', japaneseUtil, documentFocusController, hotkeyHandler);
await display.prepare(); await display.prepare();
const displayAudio = new DisplayAudio(display);
displayAudio.prepare();
const displayAnki = new DisplayAnki(display, displayAudio, japaneseUtil);
displayAnki.prepare();
const displayProfileSelection = new DisplayProfileSelection(display); const displayProfileSelection = new DisplayProfileSelection(display);
displayProfileSelection.prepare(); displayProfileSelection.prepare();

View File

@ -21,10 +21,11 @@
*/ */
class SearchDisplayController { class SearchDisplayController {
constructor(tabId, frameId, display, japaneseUtil, searchPersistentStateController) { constructor(tabId, frameId, display, displayAudio, japaneseUtil, searchPersistentStateController) {
this._tabId = tabId; this._tabId = tabId;
this._frameId = frameId; this._frameId = frameId;
this._display = display; this._display = display;
this._displayAudio = displayAudio;
this._searchPersistentStateController = searchPersistentStateController; this._searchPersistentStateController = searchPersistentStateController;
this._searchButton = document.querySelector('#search-button'); this._searchButton = document.querySelector('#search-button');
this._queryInput = document.querySelector('#search-textbox'); this._queryInput = document.querySelector('#search-textbox');
@ -56,7 +57,7 @@ class SearchDisplayController {
yomichan.on('optionsUpdated', this._onOptionsUpdated.bind(this)); yomichan.on('optionsUpdated', this._onOptionsUpdated.bind(this));
this._display.on('optionsUpdated', this._onDisplayOptionsUpdated.bind(this)); this._display.on('optionsUpdated', this._onDisplayOptionsUpdated.bind(this));
this._display.on('contentUpdating', this._onContentUpdating.bind(this)); this._display.on('contentUpdateStart', this._onContentUpdateStart.bind(this));
this._display.hotkeyHandler.registerActions([ this._display.hotkeyHandler.registerActions([
['focusSearchBox', this._onActionFocusSearchBox.bind(this)] ['focusSearchBox', this._onActionFocusSearchBox.bind(this)]
@ -69,7 +70,7 @@ class SearchDisplayController {
this._updateClipboardMonitorEnabled(); this._updateClipboardMonitorEnabled();
this._display.autoPlayAudioDelay = 0; this._displayAudio.autoPlayAudioDelay = 0;
this._display.queryParserVisible = true; this._display.queryParserVisible = true;
this._display.setHistorySettings({useBrowserHistory: true}); this._display.setHistorySettings({useBrowserHistory: true});
@ -145,27 +146,27 @@ class SearchDisplayController {
this._setWanakanaEnabled(enableWanakana); this._setWanakanaEnabled(enableWanakana);
} }
_onContentUpdating({type, content, source}) { _onContentUpdateStart({type, query, content}) {
let animate = false; let animate = false;
let valid = false; let valid = false;
switch (type) { switch (type) {
case 'terms': case 'terms':
case 'kanji': case 'kanji':
animate = !!content.animate; animate = !!content.animate;
valid = (typeof source === 'string' && source.length > 0); valid = (typeof query === 'string' && query.length > 0);
this._display.blurElement(this._queryInput); this._display.blurElement(this._queryInput);
break; break;
case 'clear': case 'clear':
valid = false; valid = false;
animate = true; animate = true;
source = ''; query = '';
break; break;
} }
if (typeof source !== 'string') { source = ''; } if (typeof query !== 'string') { query = ''; }
if (this._queryInput.value !== source) { if (this._queryInput.value !== query) {
this._queryInput.value = source; this._queryInput.value = query;
this._updateSearchHeight(true); this._updateSearchHeight(true);
} }
this._setIntroVisible(!valid, animate); this._setIntroVisible(!valid, animate);

View File

@ -17,6 +17,8 @@
/* global /* global
* Display * Display
* DisplayAnki
* DisplayAudio
* DocumentFocusController * DocumentFocusController
* HotkeyHandler * HotkeyHandler
* JapaneseUtil * JapaneseUtil
@ -49,7 +51,13 @@
const display = new Display(tabId, frameId, 'search', japaneseUtil, documentFocusController, hotkeyHandler); const display = new Display(tabId, frameId, 'search', japaneseUtil, documentFocusController, hotkeyHandler);
await display.prepare(); await display.prepare();
const searchDisplayController = new SearchDisplayController(tabId, frameId, display, japaneseUtil, searchPersistentStateController); const displayAudio = new DisplayAudio(display);
displayAudio.prepare();
const displayAnki = new DisplayAnki(display, displayAudio, japaneseUtil);
displayAnki.prepare();
const searchDisplayController = new SearchDisplayController(tabId, frameId, display, displayAudio, japaneseUtil, searchPersistentStateController);
await searchDisplayController.prepare(); await searchDisplayController.prepare();
display.initializeState(); display.initializeState();