From 7b6a4c4e36ce65af376cd87f5f9e7c657ef2a12c Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 21 Nov 2020 21:17:39 -0500 Subject: [PATCH] More display updates (#1050) * Use grid for layout * Add data-count attribute * Fix scroll issues during focus * Add index to entries * Simplify audio playback --- ext/bg/js/search.js | 6 +- ext/mixed/css/display.css | 11 ++-- ext/mixed/js/display-generator.js | 4 ++ ext/mixed/js/display.js | 106 +++++++++++++----------------- 4 files changed, 58 insertions(+), 69 deletions(-) diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index bd840981..1dda0f43 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -44,7 +44,7 @@ class DisplaySearch extends Display { }); this._onKeyDownIgnoreKeys = new Map([ ['ANY_MOD', new Set([ - 'Tab', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'PageDown', 'PageUp', 'Home', 'End', 'Enter', + 'Tab', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'PageDown', 'PageUp', 'Home', 'End', 'Enter', 'Escape', 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'F13', 'F14', 'F15', 'F16', 'F17', 'F18', 'F19', 'F20', 'F21', 'F22', 'F23', 'F24' @@ -157,7 +157,7 @@ class DisplaySearch extends Display { case 'kanji': animate = content.animate; valid = content.definitions.length > 0; - this._queryInput.blur(); + this.blurElement(this._queryInput); break; case 'clear': valid = false; @@ -183,7 +183,7 @@ class DisplaySearch extends Display { // Search e.preventDefault(); e.stopImmediatePropagation(); - e.currentTarget.blur(); + this.blurElement(e.currentTarget); this._search(); } diff --git a/ext/mixed/css/display.css b/ext/mixed/css/display.css index 997aa40a..1e502b71 100644 --- a/ext/mixed/css/display.css +++ b/ext/mixed/css/display.css @@ -240,15 +240,16 @@ a { .content { width: 100%; height: 100%; - display: flex; - flex-flow: column nowrap; position: relative; + display: grid; + grid-template-columns: 1fr; + grid-template-rows: 1fr; + grid-template-areas: "main"; + justify-items: stretch; align-items: stretch; - justify-content: flex-start; } .content-scroll { - width: 100%; - height: 100%; + grid-area: main; display: flex; flex-flow: column nowrap; overflow-x: hidden; diff --git a/ext/mixed/js/display-generator.js b/ext/mixed/js/display-generator.js index 5a563024..e90d003a 100644 --- a/ext/mixed/js/display-generator.js +++ b/ext/mixed/js/display-generator.js @@ -473,11 +473,15 @@ class DisplayGenerator { _appendMultiple(container, createItem, detailsArray, ...args) { let count = 0; + const {ELEMENT_NODE} = Node; if (Array.isArray(detailsArray)) { for (const details of detailsArray) { const item = createItem(details, ...args); if (item === null) { continue; } container.appendChild(item); + if (item.nodeType === ELEMENT_NODE) { + item.dataset.index = `${count}`; + } ++count; } } diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 9297f46b..19df9a61 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -183,8 +183,6 @@ class Display extends EventDispatcher { ['popupMessage', {async: 'dynamic', handler: this._onDirectMessage.bind(this)}] ]); window.addEventListener('focus', this._onWindowFocus.bind(this), false); - document.documentElement.addEventListener('focusin', this._onDocumentFocusIn.bind(this), false); - document.documentElement.addEventListener('focusout', this._onDocumentFocusOut.bind(this), false); this._updateFocusedElement(); this._progressIndicatorVisible.on('change', this._onProgressIndicatorVisibleChanged.bind(this)); } @@ -283,11 +281,7 @@ class Display extends EventDispatcher { if (this._definitions.length === 0) { return; } - const definition = this._definitions[0]; - const expressionIndex = this._getFirstExpressionIndex(); - const callback = () => { - this._audioPlay(definition, expressionIndex, 0); - }; + const callback = () => this._playAudio(0, 0); if (this._autoPlayAudioDelay > 0) { this._autoPlayAudioTimer = setTimeout(callback, this._autoPlayAudioDelay); @@ -413,6 +407,11 @@ class Display extends EventDispatcher { // NOP } + blurElement(element) { + element.blur(); + this._updateFocusedElement(); + } + // Message handlers _onMessage({action, params}, sender, callback) { @@ -588,14 +587,6 @@ class Display extends EventDispatcher { this._updateFocusedElement(); } - _onDocumentFocusIn() { - this._updateFocusedElement(); - } - - _onDocumentFocusOut() { - this._updateFocusedElement(); - } - async _onKanjiLookup(e) { try { e.preventDefault(); @@ -604,7 +595,7 @@ class Display extends EventDispatcher { const link = e.target; const {state} = this._history; - state.focusEntry = this._entryIndexFind(link); + state.focusEntry = this._getClosestDefinitionIndex(link); state.scrollX = this._windowScroll.x; state.scrollY = this._windowScroll.y; this._historyStateUpdate(state); @@ -664,7 +655,7 @@ class Display extends EventDispatcher { const layoutAwareScan = this._options.scanning.layoutAwareScan; const sentence = this._documentUtil.extractSentence(textSource, sentenceExtent, layoutAwareScan); - state.focusEntry = this._entryIndexFind(scannedElement); + state.focusEntry = this._getClosestDefinitionIndex(scannedElement); state.scrollX = this._windowScroll.x; state.scrollY = this._windowScroll.y; this._historyStateUpdate(state); @@ -715,23 +706,16 @@ class Display extends EventDispatcher { _onAudioPlay(e) { e.preventDefault(); const link = e.currentTarget; - const entry = link.closest('.entry'); - const index = this._entryIndexFind(entry); - if (index < 0 || index >= this._definitions.length) { return; } - - const expressionIndex = this._indexOf(entry.querySelectorAll('.term-expression .action-play-audio'), link); - this._audioPlay( - this._definitions[index], - // expressionIndex is used in audioPlay to detect result output mode - Math.max(expressionIndex, this._options.general.resultOutputMode === 'merge' ? 0 : -1), - index - ); + const definitionIndex = this._getClosestDefinitionIndex(link); + if (definitionIndex < 0) { return; } + const expressionIndex = Math.max(0, this._getClosestExpressionIndex(link)); + this._playAudio(definitionIndex, expressionIndex); } _onNoteAdd(e) { e.preventDefault(); const link = e.currentTarget; - const index = this._entryIndexFind(link); + const index = this._getClosestDefinitionIndex(link); if (index < 0 || index >= this._definitions.length) { return; } this._noteAdd(this._definitions[index], link.dataset.mode); @@ -770,7 +754,7 @@ class Display extends EventDispatcher { _onDebugLogClick(e) { const link = e.currentTarget; - const index = this._entryIndexFind(link); + const index = this._getClosestDefinitionIndex(link); if (index < 0 || index >= this._definitions.length) { return; } const definition = this._definitions[index]; console.log(definition); @@ -937,6 +921,7 @@ class Display extends EventDispatcher { this._displayGenerator.createTermEntry(definitions[i]) : this._displayGenerator.createKanjiEntry(definitions[i]) ); + entry.dataset.index = `${i}`; container.appendChild(entry); } @@ -1187,11 +1172,19 @@ class Display extends EventDispatcher { } } - async _audioPlay(definition, expressionIndex, entryIndex) { + async _playAudio(definitionIndex, expressionIndex) { + if (definitionIndex < 0 || definitionIndex >= this._definitions.length) { return; } + + const definition = this._definitions[definitionIndex]; + if (definition.type === 'kanji') { return; } + + const {expressions} = definition; + if (expressionIndex < 0 || expressionIndex >= expressions.length) { return; } + + const {expression, reading} = expressions[expressionIndex]; + const overrideToken = this._progressIndicatorVisible.setOverride(true); try { - const {expression, reading} = expressionIndex === -1 ? definition : definition.expressions[expressionIndex]; - this._stopPlayingAudio(); let audio, info; @@ -1208,7 +1201,7 @@ class Display extends EventDispatcher { info = 'Could not find audio'; } - const button = this._audioButtonFindImage(entryIndex, expressionIndex); + const button = this._audioButtonFindImage(definitionIndex, expressionIndex); if (button !== null) { let titleDefault = button.dataset.titleDefault; if (!titleDefault) { @@ -1239,6 +1232,10 @@ class Display extends EventDispatcher { } } + async _playAudioCurrent() { + return await this._playAudio(this._index, 0); + } + _stopPlayingAudio() { if (this._audioPlaying !== null) { this._audioPlaying.pause(); @@ -1246,10 +1243,6 @@ class Display extends EventDispatcher { } } - _getFirstExpressionIndex() { - return this._options.general.resultOutputMode === 'merge' ? 0 : -1; - } - _getEntry(index) { const entries = this._container.querySelectorAll('.entry'); return index >= 0 && index < entries.length ? entries[index] : null; @@ -1271,9 +1264,19 @@ class Display extends EventDispatcher { }; } - _entryIndexFind(element) { - const entry = element.closest('.entry'); - return entry !== null ? this._indexOf(this._container.querySelectorAll('.entry'), entry) : -1; + _getClosestDefinitionIndex(element) { + return this._getClosestIndex(element, '.entry'); + } + + _getClosestExpressionIndex(element) { + return this._getClosestIndex(element, '.term-expression'); + } + + _getClosestIndex(element, selector) { + const node = element.closest(selector); + if (node === null) { return -1; } + const index = parseInt(node.dataset.index, 10); + return Number.isFinite(index) ? index : -1; } _adderButtonFind(index, mode) { @@ -1307,15 +1310,6 @@ class Display extends EventDispatcher { return container !== null ? container.querySelector('.action-play-audio>img') : null; } - _indexOf(nodeList, node) { - for (let i = 0, ii = nodeList.length; i < ii; ++i) { - if (nodeList[i] === node) { - return i; - } - } - return -1; - } - _getElementTop(element) { const elementRect = element.getBoundingClientRect(); const documentRect = this._contentScrollBodyElement.getBoundingClientRect(); @@ -1331,16 +1325,6 @@ class Display extends EventDispatcher { }; } - _playAudioCurrent() { - const index = this._index; - if (index < 0 || index >= this._definitions.length) { return; } - - const entry = this._getEntry(index); - if (entry !== null && entry.dataset.type === 'term') { - this._audioPlay(this._definitions[index], this._getFirstExpressionIndex(), index); - } - } - _historyHasState() { return isObject(this._history.state); } @@ -1581,7 +1565,7 @@ class Display extends EventDispatcher { activeElement === document.documentElement || activeElement === document.body ) { - target.focus(); + target.focus({preventScroll: true}); } } }