Skip to content

Commit 9b2da29

Browse files
committed
Fix unsaved-changes detection to compare against initial form state
- Track dirtiness by comparing the current form serialization to a snapshot taken on load, so reverting an edit (typing then deleting it) correctly clears the warning instead of leaving the form permanently 'dirty'. - Also listen for 'change' so status-select edits are detected, and guard the back/logo click handlers against missing elements on non-edit pages. - Add a feature spec covering the revert-to-original case.
1 parent 255df35 commit 9b2da29

2 files changed

Lines changed: 32 additions & 4 deletions

File tree

app/assets/javascripts/stories.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,19 @@ document.addEventListener("DOMContentLoaded", () => {
3232
let isDirty = false;
3333

3434
if (form) {
35-
// Mark the form as dirty when any input changes
36-
form.addEventListener("input", function () {
37-
isDirty = true;
35+
// Snapshot the initial form state so we can compare against it. Tracking a
36+
// plain "changed at least once" flag reported the form as dirty even after
37+
// the user undid their edits (e.g. typed some text and then deleted it).
38+
const initialState = serializeForm(form);
39+
40+
const refreshDirtyState = function () {
41+
isDirty = serializeForm(form) !== initialState;
3842
addBeforeUnloadEventListener(isDirty);
39-
});
43+
};
44+
45+
// "input" covers text fields; "change" covers selects like the status.
46+
form.addEventListener("input", refreshDirtyState);
47+
form.addEventListener("change", refreshDirtyState);
4048

4149
// Reset isDirty on form submission
4250
form.addEventListener("submit", function () {
@@ -47,6 +55,8 @@ document.addEventListener("DOMContentLoaded", () => {
4755

4856
// Attach a click event to the custom back button
4957
[backButton, logo].forEach(element => {
58+
if (!element) return;
59+
5060
element.addEventListener("click", function (event) {
5161
if (isDirty) {
5262
const confirmLeave = confirm("You have unsaved changes. Are you sure you want to go back?");
@@ -63,6 +73,10 @@ document.addEventListener("DOMContentLoaded", () => {
6373
});
6474
});
6575

76+
function serializeForm(form) {
77+
return new URLSearchParams(new FormData(form)).toString();
78+
}
79+
6680
function addBeforeUnloadEventListener(isDirty) {
6781
if (isDirty) {
6882
window.addEventListener("beforeunload", warnUserIfUnsavedEdits);

spec/features/stories_manage_spec.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,20 @@
9494
assert_current_path project_path(id: project.id)
9595
end
9696

97+
it "does not alert me when I revert my edits back to their original values", js: true do
98+
visit edit_project_story_path(project, story)
99+
original_title = find_field("story[title]").value
100+
101+
# Make a change and then undo it, returning the form to its initial state.
102+
fill_in "story[title]", with: "A temporary edit"
103+
fill_in "story[title]", with: original_title
104+
105+
# No unsaved-changes confirm should appear, so navigation happens directly.
106+
click_link "Back"
107+
108+
assert_current_path project_path(id: project.id)
109+
end
110+
97111
it "allows me to delete a story" do
98112
visit project_path(id: project.id)
99113

0 commit comments

Comments
 (0)