More display updates (#1050)

* Use grid for layout

* Add data-count attribute

* Fix scroll issues during focus

* Add index to entries

* Simplify audio playback
This commit is contained in:
toasted-nutbread 2020-11-21 21:17:39 -05:00 committed by GitHub
parent af33fff6fb
commit 7b6a4c4e36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 69 deletions

View File

@ -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();
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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});
}
}
}