Skip to content

Commit e710b1b

Browse files
committed
Merge branch 'fix/checkbox-dblclk' into post-milestone3m
2 parents 3cd29aa + 5db3791 commit e710b1b

2 files changed

Lines changed: 61 additions & 1 deletion

File tree

src/widgets/forms.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,7 +1903,14 @@ export function buildCheckboxForm (dom, kb, lab, del, ins, form, dataDoc, trista
19031903
refresh()
19041904
if (!editable) return box
19051905

1906+
let isUpdating = false // Prevent concurrent updates on double-click
1907+
19061908
const boxHandler = function (_e) {
1909+
if (isUpdating) {
1910+
return // Ignore clicks while update is in progress
1911+
}
1912+
isUpdating = true
1913+
input.disabled = true // Disable button to provide user feedback
19071914
colorCarrier.style.color = '#bbb' // grey -- not saved yet
19081915
const toDelete = input.state === true ? ins : input.state === false ? del : []
19091916
input.newState =
@@ -1924,6 +1931,8 @@ export function buildCheckboxForm (dom, kb, lab, del, ins, form, dataDoc, trista
19241931
success,
19251932
errorBody
19261933
) {
1934+
isUpdating = false
1935+
input.disabled = false
19271936
if (!success) {
19281937
if (toDelete.why) {
19291938
const hmmm = kb.holds(

test/unit/widgets/forms/index.test.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { silenceDebugMessages } from '../../helpers/debugger'
2-
import { namedNode } from 'rdflib'
2+
import { namedNode, st } from 'rdflib'
33
import ns from '../../../../src/ns'
44
import { store } from 'solid-logic'
55

@@ -594,6 +594,57 @@ describe('buildCheckboxForm', () => {
594594
)
595595
).toBeInstanceOf(HTMLDivElement)
596596
})
597+
598+
it('ignores rapid second click while async update is in progress and reenables button afterward', async () => {
599+
const dataDoc = namedNode('http://example.com/#doc')
600+
const form = namedNode('http://example.com/#form')
601+
const subject = namedNode('http://example.com/#subject')
602+
const predicate = namedNode('http://example.com/#predicate')
603+
const object = namedNode('http://example.com/#object')
604+
const statement = st(subject, predicate, object, dataDoc)
605+
606+
const originalEditable = store.updater.editable
607+
const originalUpdate = store.updater.update
608+
609+
const updateSpy = jest.fn((_deletes, _inserts, callback) => {
610+
return new Promise(resolve => {
611+
setTimeout(() => {
612+
callback('uri', true, 'ok')
613+
resolve(true)
614+
}, 0)
615+
})
616+
})
617+
618+
store.updater.editable = jest.fn(() => true) as any
619+
store.updater.update = updateSpy as any
620+
621+
try {
622+
const box = buildCheckboxForm(
623+
document,
624+
store,
625+
'label',
626+
[],
627+
statement,
628+
form,
629+
dataDoc,
630+
false
631+
)
632+
const checkboxButton = box.querySelector('button') as HTMLButtonElement
633+
634+
checkboxButton.click()
635+
checkboxButton.click()
636+
637+
expect(updateSpy).toHaveBeenCalledTimes(1)
638+
expect(checkboxButton.disabled).toEqual(true)
639+
640+
await new Promise(resolve => setTimeout(resolve, 5))
641+
642+
expect(checkboxButton.disabled).toEqual(false)
643+
} finally {
644+
store.updater.editable = originalEditable
645+
store.updater.update = originalUpdate
646+
}
647+
})
597648
})
598649

599650
describe('newThing', () => {

0 commit comments

Comments
 (0)