go back to having Timeline.html manage focus

This commit is contained in:
Nolan Lawson 2018-03-22 21:59:02 -07:00
parent 7a9cb22269
commit cd968245e1
5 changed files with 21 additions and 48 deletions

View File

@ -7,8 +7,7 @@
{{else}}
<article class="notification-article"
tabindex="0"
aria-posinset="{{index}}" aria-setsize="{{length}}"
ref:node >
aria-posinset="{{index}}" aria-setsize="{{length}}" >
<StatusHeader :notification :notificationId :status :statusId :timelineType
:account :accountId :uuid isStatusInNotification="true" />
</article>
@ -32,16 +31,8 @@
import Status from './Status.html'
import StatusHeader from './StatusHeader.html'
import { store } from '../../_store/store'
import { restoreFocus } from '../../_utils/restoreFocus'
export default {
oncreate() {
let focusSelector = this.get('focusSelector')
if (this.refs.node && focusSelector &&
this.store.getForCurrentTimeline('shouldRestoreFocus')) {
restoreFocus(this.refs.node, focusSelector)
}
},
components: {
Status,
StatusHeader

View File

@ -5,8 +5,7 @@
aria-posinset="{{index}}"
aria-setsize="{{length}}"
aria-label="{{ariaLabel}}"
on:recalculateHeight
ref:node >
on:recalculateHeight >
{{#if showHeader}}
<StatusHeader :notification :notificationId :status :statusId :timelineType
:account :accountId :uuid :isStatusInNotification />
@ -103,7 +102,6 @@
import { goto } from 'sapper/runtime.js'
import { registerClickDelegate, unregisterClickDelegate } from '../../_utils/delegate'
import { classname } from '../../_utils/classname'
import { restoreFocus } from '../../_utils/restoreFocus'
export default {
oncreate() {
@ -112,11 +110,6 @@
// the whole <article> is clickable in this case
registerClickDelegate(delegateKey, (e) => this.onClickOrKeydown(e))
}
let focusSelector = this.get('focusSelector')
if (this.refs.node && focusSelector &&
this.store.getForCurrentTimeline('shouldRestoreFocus')) {
restoreFocus(this.refs.node, focusSelector)
}
},
ondestroy() {
let delegateKey = this.get('delegateKey')

View File

@ -79,6 +79,7 @@
console.log('timeline oncreate()')
this.setupFocus()
setupTimeline()
this.restoreFocus()
this.setupStreaming()
},
ondestroy() {
@ -98,7 +99,7 @@
VirtualListComponent: (timelineType) => {
return timelineType === 'notifications' ? NotificationVirtualListItem : StatusVirtualListItem
},
makeProps: ($currentInstance, timelineType, timelineValue, $lastFocusedElementSelector) => async (itemId) => {
makeProps: ($currentInstance, timelineType, timelineValue) => async (itemId) => {
let res = {
timelineType,
timelineValue
@ -108,12 +109,6 @@
} else {
res.status = await database.getStatus($currentInstance, itemId)
}
if ($lastFocusedElementSelector && $lastFocusedElementSelector.includes(itemId)) {
// this selector is guaranteed to contain the statusId. false positives
// (e.g. notification id "1" matches notification id "11") are okay
// because Status.html won't be able to find the selector which is fine.
res.focusSelector = $lastFocusedElementSelector
}
return res
},
label: (timeline, $currentInstance, timelineType, timelineValue) => {
@ -177,16 +172,6 @@
},
onScrollTopChanged(scrollTop) {
this.set({scrollTop: scrollTop})
if (!this.get('observedOnScrollTopChanged')) {
// ignore the first scroll top change, e.g.
// because we forced a scroll top change
this.set({observedOnScrollTopChanged: true})
} else {
// after that, don't allow statuses/notifications to call focus()
// after we've already started scrolling. that causes scrolling to
// jump around
this.store.setForCurrentTimeline({shouldRestoreFocus: false})
}
},
onScrollToBottom() {
if (!this.store.get('initialized') ||
@ -244,8 +229,7 @@
setupFocus() {
this.onPushState = this.onPushState.bind(this)
this.store.setForCurrentTimeline({
ignoreBlurEvents: false,
shouldRestoreFocus: true
ignoreBlurEvents: false
})
window.addEventListener('pushState', this.onPushState)
},
@ -289,7 +273,22 @@
} catch (err) {
console.error('unable to clear focus', err)
}
}
},
restoreFocus() {
let lastFocusedElementSelector = this.store.get('lastFocusedElementSelector')
if (!lastFocusedElementSelector) {
return
}
console.log('restoreFocus', lastFocusedElementSelector)
requestAnimationFrame(() => {
requestAnimationFrame(() => {
let element = document.querySelector(lastFocusedElementSelector)
if (element) {
element.focus()
}
})
})
},
}
}
</script>

View File

@ -18,7 +18,6 @@ export function timelineComputations (store) {
computeForTimeline(store, 'showHeader', false)
computeForTimeline(store, 'shouldShowHeader', false)
computeForTimeline(store, 'timelineItemIdsAreStale', false)
computeForTimeline(store, 'shouldRestoreFocus', false)
store.compute('firstTimelineItemId', ['timelineItemIds'], (timelineItemIds) => {
return timelineItemIds && timelineItemIds[0]

View File

@ -1,9 +0,0 @@
export function restoreFocus (element, selector) {
// Have to check from the parent because otherwise this element itself wouldn't match.
// This is fine for <article class=status> elements because they already have a div wrapper.
let elementToFocus = element.parentElement.querySelector(selector)
console.log('restoreFocus', selector, elementToFocus)
if (elementToFocus) {
elementToFocus.focus()
}
}