mirror of
https://github.com/go-vikunja/vikunja.git
synced 2026-04-24 22:25:15 +00:00
fix(tasklist): refresh editor after checkbox toggle
This commit is contained in:
@@ -911,8 +911,8 @@ describe('Task', () => {
|
||||
.should('exist')
|
||||
})
|
||||
|
||||
it('Can check items off a checklist', () => {
|
||||
const tasks = TaskFactory.create(1, {
|
||||
it('Can check items off a checklist', () => {
|
||||
const tasks = TaskFactory.create(1, {
|
||||
id: 1,
|
||||
description: `
|
||||
<ul data-type="taskList">
|
||||
@@ -950,8 +950,35 @@ describe('Task', () => {
|
||||
cy.get('.tiptap__editor input[type=checkbox]')
|
||||
.should('have.length', 5)
|
||||
cy.get('.task-view .checklist-summary')
|
||||
.should('contain.text', '2 of 5 tasks')
|
||||
})
|
||||
.should('contain.text', '2 of 5 tasks')
|
||||
})
|
||||
|
||||
it('Checklist item stays checked after reload', () => {
|
||||
const tasks = TaskFactory.create(1, {
|
||||
id: 1,
|
||||
description: `
|
||||
<ul data-type="taskList">
|
||||
<li data-checked="false" data-type="taskItem"><label><input type="checkbox"><span></span></label>
|
||||
<div><p>First Item</p></div>
|
||||
</li>
|
||||
</ul>`,
|
||||
})
|
||||
cy.visit(`/tasks/${tasks[0].id}`)
|
||||
|
||||
cy.get('.tiptap__editor ul > li input[type=checkbox]')
|
||||
.click()
|
||||
|
||||
cy.get('.task-view .details.content.description h3 span.is-small.has-text-success')
|
||||
.contains('Saved!')
|
||||
.should('exist')
|
||||
|
||||
cy.reload()
|
||||
|
||||
cy.get('.tiptap__editor ul > li input[type=checkbox]')
|
||||
.should('be.checked')
|
||||
cy.get('.task-view .checklist-summary')
|
||||
.should('contain.text', '1 of 1 tasks')
|
||||
})
|
||||
|
||||
it('Should use the editor to render description', () => {
|
||||
const tasks = TaskFactory.create(1, {
|
||||
|
||||
@@ -454,10 +454,11 @@ const extensions : Extensions = [
|
||||
...node.attrs,
|
||||
checked,
|
||||
})
|
||||
editor.value!.view.dispatch(tr)
|
||||
bubbleSave()
|
||||
}
|
||||
})
|
||||
editor.value!.view.dispatch(tr)
|
||||
bubbleSave()
|
||||
refreshTasklistCheckboxes()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
return true
|
||||
@@ -679,57 +680,59 @@ function focusIfEditing() {
|
||||
}
|
||||
|
||||
function clickTasklistCheckbox(event) {
|
||||
event.stopImmediatePropagation()
|
||||
event.stopImmediatePropagation()
|
||||
|
||||
if (event.target.localName !== 'p') {
|
||||
return
|
||||
}
|
||||
if (event.target.localName !== 'p') {
|
||||
return
|
||||
}
|
||||
|
||||
event.target.parentNode.parentNode.firstChild.click()
|
||||
event.target.parentNode.parentNode.firstChild.click()
|
||||
}
|
||||
|
||||
async function refreshTasklistCheckboxes() {
|
||||
await nextTick()
|
||||
|
||||
let checkboxes = tiptapInstanceRef.value?.querySelectorAll('[data-checked]')
|
||||
if (typeof checkboxes === 'undefined' || checkboxes.length === 0) {
|
||||
// For some reason, this works when we check a second time.
|
||||
await nextTick()
|
||||
|
||||
checkboxes = tiptapInstanceRef.value?.querySelectorAll('[data-checked]')
|
||||
if (typeof checkboxes === 'undefined' || checkboxes.length === 0) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (isEditing.value) {
|
||||
checkboxes.forEach(check => {
|
||||
if (check.children.length < 2) {
|
||||
return
|
||||
}
|
||||
|
||||
// We assume the first child contains the label element with the checkbox and the second child the actual label
|
||||
// When the actual label is clicked, we forward that click to the checkbox.
|
||||
check.children[1].removeEventListener('click', clickTasklistCheckbox)
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
checkboxes.forEach(check => {
|
||||
if (check.children.length < 2) {
|
||||
return
|
||||
}
|
||||
|
||||
// We assume the first child contains the label element with the checkbox and the second child the actual label
|
||||
// When the actual label is clicked, we forward that click to the checkbox.
|
||||
check.children[1].removeEventListener('click', clickTasklistCheckbox)
|
||||
check.children[1].addEventListener('click', clickTasklistCheckbox)
|
||||
})
|
||||
}
|
||||
|
||||
watch(
|
||||
() => isEditing.value,
|
||||
async editing => {
|
||||
await nextTick()
|
||||
|
||||
let checkboxes = tiptapInstanceRef.value?.querySelectorAll('[data-checked]')
|
||||
if (typeof checkboxes === 'undefined' || checkboxes.length === 0) {
|
||||
// For some reason, this works when we check a second time.
|
||||
await nextTick()
|
||||
|
||||
checkboxes = tiptapInstanceRef.value?.querySelectorAll('[data-checked]')
|
||||
if (typeof checkboxes === 'undefined' || checkboxes.length === 0) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (editing) {
|
||||
checkboxes.forEach(check => {
|
||||
if (check.children.length < 2) {
|
||||
return
|
||||
}
|
||||
|
||||
// We assume the first child contains the label element with the checkbox and the second child the actual label
|
||||
// When the actual label is clicked, we forward that click to the checkbox.
|
||||
check.children[1].removeEventListener('click', clickTasklistCheckbox)
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
checkboxes.forEach(check => {
|
||||
if (check.children.length < 2) {
|
||||
return
|
||||
}
|
||||
|
||||
// We assume the first child contains the label element with the checkbox and the second child the actual label
|
||||
// When the actual label is clicked, we forward that click to the checkbox.
|
||||
check.children[1].removeEventListener('click', clickTasklistCheckbox)
|
||||
check.children[1].addEventListener('click', clickTasklistCheckbox)
|
||||
})
|
||||
},
|
||||
{immediate: true},
|
||||
() => isEditing.value,
|
||||
() => refreshTasklistCheckboxes(),
|
||||
{immediate: true},
|
||||
)
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user