Unsaved changes: ask in Postulo's own dialog when the person leaves through a link or a button on the page #657
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#657
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
From the maintainer's list: “Make a save guard that prevents losing unsaved data, for instance prompting a dialog if abandoning a page without saving it.” #258 made the guard, and it asks with the browser's own prompt, whose words a page cannot set or translate. A dialog can be Postulo's, translated and styled. This issue adds one for the leaving a page can see, and keeps the browser's prompt for the rest. It does not reopen what #258 delivered, and it comes after #518.
What #258 delivered, and stays
src/postulo/static/js/app.js:810-877).GETform, one markeddata-no-guard, adata-autosubmitcontrol (app.js:833-843).beforeunloadasks when anything is dirty (app.js:879-887);pageshowclears the marks (:889-894). The capture review'sdandjkeys respect it.tests/e2e/test_unsaved_work.py:61-143(a letter, an untouched page, a submit, a filter form,d,j).app.js:805-808), and stay out.What exists today for a dialog
<c-dialog>(templates/cotton/dialog.html, #303) is a<dialog popover>: with scripts it is opened modally byapp.js(:1798-1862) with focus returned to its opener; without, the button that names it opens it as a popover. Cancel, the answer that changes nothing, is drawn first and takes focus. Without anactionits body is a plain<div>.tests/e2e/test_dialog.pycovers both modes.What a page can and cannot intercept
templates/base.html:234; the capture review's discard), and the keys that click them.beforeunloadremains, as it is.Checked against
mainatf09b6010b.Proposal
a[href]links (no modifier key, notarget, nodownload, not a fragment on this page), and a capture-phasesubmitlistener for forms other than a dirty one. When anything is dirty, it cancels the action, remembers where it was going, and opens the dialog. Capturing runs before the double-submit guard marks the form, which is how the dead form of #518 does not arise on this route.data-dirtymark, sobeforeunloadis silent and the person is asked once, then goes to the link or submits the form they had pressed. Cancel and Escape change nothing; focus returns to the link or button that was used.beforeunloadstays, unchanged, as the answer for everything above the line.showModalkeepsbeforeunloadalone.Decisions
target="_blank"and a download do not leave the page. Recommended: no question for them.Builds on
Issues #258, #518, #303 (the dialog) and #656.
Done when
tests/e2e/test_unsaved_work.pygains: typing into a letter and clicking a sidebar link opens the dialog and puts up nobeforeunload; Cancel keeps the typed text and returns focus to the link; Leave this page goes and the browser puts up no second prompt; Sign out with a dirty form asks, and after Cancel still works (the #518 case);dandjon the capture review open the dialog; an untouched page and a filter form do not; the tab-close case still raisesbeforeunload. The six tests there pass unchanged.tests/e2e/test_accessibility.pycovers the page with the dialog open in both schemes;tests/e2e/test_reflow.pyat 320 pixels; the dialog is operable by keyboard alone, announced as an alert dialog, and closes on Escape.From the list of improvements of 2026-10-02.
Landed on main with a green Forgejo CI run. Its entry in the CHANGELOG's Unreleased section ends in (#657).