From 74705379cb8f66edcf03f9f2e4bd0db946623659 Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Fri, 1 May 2026 11:53:06 +0300 Subject: [PATCH 1/6] test enter submits add child form assert that pressing enter while typing in the add-child input submits the form. currently fails: only the save-child button click triggers the post. --- cypress/e2e/adminText.cy.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/cypress/e2e/adminText.cy.js b/cypress/e2e/adminText.cy.js index a92e595..628c3ff 100644 --- a/cypress/e2e/adminText.cy.js +++ b/cypress/e2e/adminText.cy.js @@ -101,6 +101,25 @@ describe('The admin text detail page', () => { .should('contain', 'Shemos') }) + it('pressing Enter in the add-child input submits', () => { + cy.intercept('POST', '/api/nodes').as('createNode') + cy.intercept('GET', '/api/nodes/0').as('getNodesRefresh') + + cy.get('#text-detail > ul > li') + .first() + .children('button.add-child') + .click() + cy.get('#text-detail > ul > li') + .first() + .children('input.child-title') + .type('Enter Child{enter}') + + cy.wait('@createNode').its('response.statusCode').should('eq', 201) + cy.wait('@getNodesRefresh') + + cy.get('#text-detail li').should('contain', 'Enter Child') + }) + it('newly added child persists after page reload', () => { cy.intercept('POST', '/api/nodes').as('createNode') cy.intercept('GET', '/api/nodes/0').as('getNodesRefresh') From 3928fef213832864fa05715a93a2a199878a52aa Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Fri, 1 May 2026 11:53:54 +0300 Subject: [PATCH 2/6] submit add child form on enter key extract the save-child handler into a submit closure shared by the save button click and a keydown listener on the input. also focus the input as soon as the form opens so the user can type and hit enter without touching the mouse. --- public/js/text.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/public/js/text.js b/public/js/text.js index 486f7f5..3b2b37e 100644 --- a/public/js/text.js +++ b/public/js/text.js @@ -117,7 +117,8 @@ function toggleAddForm(li, parentNodeId, textId) { const saveBtn = document.createElement('button'); saveBtn.textContent = 'Save'; saveBtn.className = 'save-child'; - saveBtn.addEventListener('click', () => { + + function submit() { const title = input.value.trim(); if (!title) return; @@ -133,10 +134,19 @@ function toggleAddForm(li, parentNodeId, textId) { return res.json(); }) .then(() => fetchAndRenderNodes(textId)); + } + + saveBtn.addEventListener('click', submit); + input.addEventListener('keydown', (event) => { + if (event.key === 'Enter') { + event.preventDefault(); + submit(); + } }); li.appendChild(input); li.appendChild(saveBtn); + input.focus(); } function toggleBulkAddForm(li, parentNodeId, textId) { From ff8ec9a2ab7efbc6c23642952c4a374726c5036b Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Fri, 1 May 2026 11:54:53 +0300 Subject: [PATCH 3/6] test enter submits bulk add form assert that pressing enter from either the bulk-title or bulk-count input submits the bulk add form. currently fails: only the save-bulk button click triggers the post. --- cypress/e2e/adminTextBulkAdd.cy.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/cypress/e2e/adminTextBulkAdd.cy.js b/cypress/e2e/adminTextBulkAdd.cy.js index 7d1afc2..47d3c7f 100644 --- a/cypress/e2e/adminTextBulkAdd.cy.js +++ b/cypress/e2e/adminTextBulkAdd.cy.js @@ -65,6 +65,30 @@ describe('Bulk add children on the admin text detail page', () => { cy.get('@bulkCreate.all').should('have.length', 0) }) + it('pressing Enter in the bulk-count input submits', () => { + cy.intercept('POST', '/api/nodes/bulk').as('bulkCreate') + cy.intercept('GET', '/api/nodes/0').as('getNodesRefresh') + cy.get('#text-detail > ul > li').first().children('button.bulk-add-children').click() + cy.get('#text-detail > ul > li').first().children('input.bulk-title').type('Enter') + cy.get('#text-detail > ul > li').first().children('input.bulk-count').type('2{enter}') + cy.wait('@bulkCreate').its('response.statusCode').should('eq', 201) + cy.wait('@getNodesRefresh') + cy.get('#text-detail li').should('contain', 'Enter 1') + cy.get('#text-detail li').should('contain', 'Enter 2') + }) + + it('pressing Enter in the bulk-title input submits', () => { + cy.intercept('POST', '/api/nodes/bulk').as('bulkCreate') + cy.intercept('GET', '/api/nodes/0').as('getNodesRefresh') + cy.get('#text-detail > ul > li').first().children('button.bulk-add-children').click() + cy.get('#text-detail > ul > li').first().children('input.bulk-count').type('2') + cy.get('#text-detail > ul > li').first().children('input.bulk-title').type('Title{enter}') + cy.wait('@bulkCreate').its('response.statusCode').should('eq', 201) + cy.wait('@getNodesRefresh') + cy.get('#text-detail li').should('contain', 'Title 1') + cy.get('#text-detail li').should('contain', 'Title 2') + }) + it('bulk added nodes persist after page reload', () => { cy.intercept('POST', '/api/nodes/bulk').as('bulkCreate') cy.intercept('GET', '/api/nodes/0').as('getNodesRefresh') From bd14bfd7a1a8f9da2df780fa7dd4822f82ae05ec Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Fri, 1 May 2026 11:55:43 +0300 Subject: [PATCH 4/6] submit bulk add form on enter key extract the save-bulk handler into a submit closure shared by the save button click and a keydown listener on both the title and count inputs. focus the title input as soon as the form opens. --- public/js/text.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/public/js/text.js b/public/js/text.js index 3b2b37e..c15e711 100644 --- a/public/js/text.js +++ b/public/js/text.js @@ -172,7 +172,8 @@ function toggleBulkAddForm(li, parentNodeId, textId) { const saveBtn = document.createElement('button'); saveBtn.textContent = 'Save'; saveBtn.className = 'save-bulk'; - saveBtn.addEventListener('click', () => { + + function submit() { const titlePrefix = titleInput.value.trim(); const count = parseInt(countInput.value); if (!titlePrefix || !count || count < 1) return; @@ -189,9 +190,21 @@ function toggleBulkAddForm(li, parentNodeId, textId) { return res.json(); }) .then(() => fetchAndRenderNodes(textId)); - }); + } + + function submitOnEnter(event) { + if (event.key === 'Enter') { + event.preventDefault(); + submit(); + } + } + + saveBtn.addEventListener('click', submit); + titleInput.addEventListener('keydown', submitOnEnter); + countInput.addEventListener('keydown', submitOnEnter); li.appendChild(titleInput); li.appendChild(countInput); li.appendChild(saveBtn); + titleInput.focus(); } From d61d68571d27c62366429d3ce8d007b59e767e51 Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Fri, 1 May 2026 11:56:44 +0300 Subject: [PATCH 5/6] test only one add form open at a time assert that opening any add-child or bulk-add form closes any other open add form across the tree. currently fails: each toggle function only checks for an open form on its own li. --- cypress/e2e/adminText.cy.js | 54 +++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/cypress/e2e/adminText.cy.js b/cypress/e2e/adminText.cy.js index 628c3ff..4e0893c 100644 --- a/cypress/e2e/adminText.cy.js +++ b/cypress/e2e/adminText.cy.js @@ -120,6 +120,60 @@ describe('The admin text detail page', () => { cy.get('#text-detail li').should('contain', 'Enter Child') }) + it('opening add-child on another node closes the first one', () => { + cy.get('#text-detail > ul > li') + .first() + .children('button.add-child') + .click() + cy.get('#text-detail > ul > li') + .first() + .children('input.child-title') + .should('be.visible') + + cy.get('#text-detail > ul > li > ul > li') + .first() + .children('button.add-child') + .click() + + cy.get('#text-detail > ul > li') + .first() + .children('input.child-title') + .should('not.exist') + cy.get('#text-detail > ul > li') + .first() + .children('button.save-child') + .should('not.exist') + cy.get('#text-detail > ul > li > ul > li') + .first() + .children('input.child-title') + .should('be.visible') + }) + + it('opening bulk-add closes an open add-child form', () => { + cy.get('#text-detail > ul > li') + .first() + .children('button.add-child') + .click() + cy.get('#text-detail > ul > li') + .first() + .children('input.child-title') + .should('be.visible') + + cy.get('#text-detail > ul > li > ul > li') + .first() + .children('button.bulk-add-children') + .click() + + cy.get('#text-detail > ul > li') + .first() + .children('input.child-title') + .should('not.exist') + cy.get('#text-detail > ul > li > ul > li') + .first() + .children('input.bulk-title') + .should('be.visible') + }) + it('newly added child persists after page reload', () => { cy.intercept('POST', '/api/nodes').as('createNode') cy.intercept('GET', '/api/nodes/0').as('getNodesRefresh') From a1bfe4f7c131061c17919e883ee3d36786a241e3 Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Fri, 1 May 2026 11:58:12 +0300 Subject: [PATCH 6/6] close other add forms when opening a new one introduce closeAllAddForms which strips every add-child and bulk-add input/button from the tree, and call it at the start of toggleAddForm and toggleBulkAddForm (after the same-li toggle-off short-circuit, so clicking the same trigger still closes its own form). enforces a single open add form across the whole tree. --- public/js/text.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/public/js/text.js b/public/js/text.js index c15e711..90221d2 100644 --- a/public/js/text.js +++ b/public/js/text.js @@ -101,6 +101,21 @@ function renderTree(nodes, textId, depth = 0) { return ul; } +function closeAllAddForms() { + const selectors = [ + 'input.child-title', + 'button.save-child', + 'input.bulk-title', + 'input.bulk-count', + 'button.save-bulk', + ]; + selectors.forEach((selector) => { + document + .querySelectorAll('#text-detail ' + selector) + .forEach((element) => element.remove()); + }); +} + function toggleAddForm(li, parentNodeId, textId) { const existing = li.querySelector('input.child-title'); if (existing) { @@ -109,6 +124,8 @@ function toggleAddForm(li, parentNodeId, textId) { return; } + closeAllAddForms(); + const input = document.createElement('input'); input.type = 'text'; input.className = 'child-title'; @@ -158,6 +175,8 @@ function toggleBulkAddForm(li, parentNodeId, textId) { return; } + closeAllAddForms(); + const titleInput = document.createElement('input'); titleInput.type = 'text'; titleInput.className = 'bulk-title';