diff --git a/frontend/cypress/e2e/task/task.spec.ts b/frontend/cypress/e2e/task/task.spec.ts
index 2335b45d3..d32d7c51c 100644
--- a/frontend/cypress/e2e/task/task.spec.ts
+++ b/frontend/cypress/e2e/task/task.spec.ts
@@ -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: `
@@ -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: `
+`,
+ })
+ 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, {
diff --git a/frontend/src/components/input/editor/TipTap.vue b/frontend/src/components/input/editor/TipTap.vue
index 7f36fb75b..f2d58835e 100644
--- a/frontend/src/components/input/editor/TipTap.vue
+++ b/frontend/src/components/input/editor/TipTap.vue
@@ -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},
)