Skip to content

Commit 24b7d3c

Browse files
committed
Merge branch 'master' into composition
2 parents e020ae2 + 0876179 commit 24b7d3c

File tree

1 file changed

+47
-62
lines changed

1 file changed

+47
-62
lines changed

index.js

Lines changed: 47 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -37,52 +37,53 @@ class DetailsMenuElement extends HTMLElement {
3737
if (!summary.hasAttribute('role')) summary.setAttribute('role', 'button')
3838
}
3939

40-
this.addEventListener('compositionstart', trackComposition)
41-
this.addEventListener('compositionend', trackComposition)
42-
details.addEventListener('click', shouldCommit)
43-
details.addEventListener('change', shouldCommit)
44-
details.addEventListener('keydown', keydown)
45-
details.addEventListener('toggle', loadFragment, {once: true})
46-
details.addEventListener('toggle', closeCurrentMenu)
47-
if (this.preload) {
48-
details.addEventListener('mouseover', loadFragment, {once: true})
49-
}
50-
51-
const subscriptions = [focusOnOpen(details)]
52-
states.set(this, {details, subscriptions, loaded: false, isComposing: false})
40+
const subscriptions = [
41+
fromEvent(details, 'compositionstart', e => trackComposition(this, e)),
42+
fromEvent(details, 'compositionend', e => trackComposition(this, e)),
43+
fromEvent(details, 'click', e => shouldCommit(details, this, e)),
44+
fromEvent(details, 'change', e => shouldCommit(details, this, e)),
45+
fromEvent(details, 'keydown', e => keydown(details, this, e)),
46+
fromEvent(details, 'toggle', () => loadFragment(details, this), {once: true}),
47+
fromEvent(details, 'toggle', () => closeCurrentMenu(details)),
48+
this.preload
49+
? fromEvent(details, 'mouseover', () => loadFragment(details, this), {once: true})
50+
: NullSubscription,
51+
...focusOnOpen(details)
52+
]
53+
54+
states.set(this, {subscriptions, loaded: false, isComposing: false})
5355
}
5456

5557
disconnectedCallback() {
5658
const state = states.get(this)
5759
if (!state) return
58-
5960
states.delete(this)
60-
61-
const {details, subscriptions} = state
62-
for (const sub of subscriptions) {
61+
for (const sub of state.subscriptions) {
6362
sub.unsubscribe()
6463
}
65-
66-
this.addEventListener('compositionstart', trackComposition)
67-
this.addEventListener('compositionend', trackComposition)
68-
details.removeEventListener('click', shouldCommit)
69-
details.removeEventListener('change', shouldCommit)
70-
details.removeEventListener('keydown', keydown)
71-
details.removeEventListener('toggle', loadFragment, {once: true})
72-
details.removeEventListener('toggle', closeCurrentMenu)
73-
details.removeEventListener('mouseover', loadFragment, {once: true})
7464
}
7565
}
7666

7767
const states = new WeakMap()
7868

79-
function loadFragment(event: Event) {
80-
const details = event.currentTarget
81-
if (!(details instanceof Element)) return
69+
type Subscription = {unsubscribe(): void}
70+
const NullSubscription = {unsubscribe() {}}
8271

83-
const menu = details.querySelector('details-menu')
84-
if (!menu) return
72+
function fromEvent(
73+
target: EventTarget,
74+
eventName: string,
75+
onNext: EventHandler,
76+
options: EventListenerOptionsOrUseCapture = false
77+
): Subscription {
78+
target.addEventListener(eventName, onNext, options)
79+
return {
80+
unsubscribe: () => {
81+
target.removeEventListener(eventName, onNext, options)
82+
}
83+
}
84+
}
8585

86+
function loadFragment(details: Element, menu: DetailsMenuElement) {
8687
const src = menu.getAttribute('src')
8788
if (!src) return
8889

@@ -99,7 +100,7 @@ function loadFragment(event: Event) {
99100
}
100101
}
101102

102-
function focusOnOpen(details: Element) {
103+
function focusOnOpen(details: Element): Array<Subscription> {
103104
let isMouse = false
104105
const onmousedown = () => (isMouse = true)
105106
const onkeydown = () => (isMouse = false)
@@ -109,27 +110,19 @@ function focusOnOpen(details: Element) {
109110
if (!isMouse) focusFirstItem(details)
110111
}
111112

112-
details.addEventListener('mousedown', onmousedown)
113-
details.addEventListener('keydown', onkeydown)
114-
details.addEventListener('toggle', ontoggle)
115-
116-
return {
117-
unsubscribe: () => {
118-
details.removeEventListener('mousedown', onmousedown)
119-
details.removeEventListener('keydown', onkeydown)
120-
details.removeEventListener('toggle', ontoggle)
121-
}
122-
}
113+
return [
114+
fromEvent(details, 'mousedown', onmousedown),
115+
fromEvent(details, 'keydown', onkeydown),
116+
fromEvent(details, 'toggle', ontoggle)
117+
]
123118
}
124119

125-
function closeCurrentMenu(event: Event) {
126-
const el = event.currentTarget
127-
if (!(el instanceof Element)) return
128-
if (!el.hasAttribute('open')) return
120+
function closeCurrentMenu(details: Element) {
121+
if (!details.hasAttribute('open')) return
129122

130123
for (const menu of document.querySelectorAll('details[open] > details-menu')) {
131124
const opened = menu.closest('details')
132-
if (opened && opened !== el && !opened.contains(el)) {
125+
if (opened && opened !== details && !opened.contains(details)) {
133126
opened.removeAttribute('open')
134127
}
135128
}
@@ -168,13 +161,10 @@ function sibling(details: Element, next: boolean): ?HTMLElement {
168161

169162
const ctrlBindings = navigator.userAgent.match(/Macintosh/)
170163

171-
function shouldCommit(event: Event) {
164+
function shouldCommit(details: Element, menu: DetailsMenuElement, event: Event) {
172165
const target = event.target
173166
if (!(target instanceof Element)) return
174167

175-
const details = event.currentTarget
176-
if (!(details instanceof Element)) return
177-
178168
// Ignore clicks from nested details.
179169
if (target.closest('details') !== details) return
180170

@@ -224,16 +214,11 @@ function commit(selected: Element, details: Element) {
224214
)
225215
}
226216

227-
function keydown(event: KeyboardEvent) {
228-
const details = event.currentTarget
229-
if (!(details instanceof Element)) return
230-
const menu = details.querySelector('details-menu')
231-
if (!menu) return
217+
function keydown(details: Element, menu: DetailsMenuElement, event: Event) {
218+
if (!(event instanceof KeyboardEvent)) return
232219
const state = states.get(menu)
233220
if (!state) return
234-
const {isComposing} = state
235-
if (isComposing) return
236-
221+
if (state.isComposing) return
237222
const isSummaryFocused = event.target instanceof Element && event.target.tagName === 'SUMMARY'
238223

239224
// Ignore key presses from nested details.
@@ -338,8 +323,8 @@ function labelHTML(el: ?Element): ?string {
338323
return contentsEl ? contentsEl.innerHTML : null
339324
}
340325

341-
function trackComposition(event: Event) {
342-
const state = states.get(event.currentTarget)
326+
function trackComposition(menu, event: Event) {
327+
const state = states.get(menu)
343328
if (!state) return
344329
state.isComposing = event.type === 'compositionstart'
345330
}

0 commit comments

Comments
 (0)