Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MBS-13320: Prompt before unloading modified forms #3054

Merged
merged 9 commits into from
Oct 26, 2023

Conversation

derat
Copy link
Contributor

@derat derat commented Oct 16, 2023

MBS-13320

Install a beforeunload event listener on the artist, event, label, place, recording, release group, series, and work edit pages that prompts the user if any of the form's inputs have been changed.

One limitation of the approach used here is that it doesn't detect relationship changes.

Note that the release editor already displays a prompt if the page is unloaded with unsubmitted changes.

Problem

If an editing page is accidentally closed or navigated away from by a user before it's been submitted, data entered in JavaScript-dependent fields like Area, Relationships, and External Links are lost.

Solution

Listen for change events within form elements and install a beforeunload handler that prompts the user if the page is being unloaded after changes have been made. I added a small MB.installFormUnloadWarning function that seems to be sufficient for all of the forms that I'm updating here.

Note that since I'm watching for change events (rather than input), the prompt won't be primed until the user actually commits a change by e.g. de-focusing an input after typing into it. The approach used here doesn't seem to detect relationship changes; I think that the separate implementation of the relationship editor may make this challenging.

I think that the release editor is able to use a different approach where it maintains a list of unsubmitted changes, but I believe that that approach is unavailable in (all?) other pages.

Testing

I verified that all of the pages that I've updated don't prompt if I close them without making any changes, but do prompt if I've made name, area, URL, etc. changes. They also don't prompt when the submit button is clicked.

As mentioned above, the prompt isn't shown if only relationships are changed.

Install a beforeunload event listener on the artist, event,
label, place, recording, release group, series, and work
edit pages that prompts the user if any of the form's inputs
have been changed. This is intended to prevent data loss
if the page is accidentally closed before the form has been
submitted.

One limitation of the approach used here is that it doesn't
detect relationship changes.

Note that the release editor already displays a prompt if
the page is unloaded with unsubmitted changes.
*/
form.addEventListener('change', () => {
modified = true;
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the relationship editor e.g. emit custom events for changes that I could also listen for here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No custom events, but...perhaps if you check #relationship-editor for the presence of hidden inputs, that would indicate whether changes were made.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. That's a clever idea, but I'm not seeing any hidden relationship inputs at the time of the beforeunload event. This is my first time glancing at the relationship editor code, but is it possible that root/static/scripts/relationship-editor/utility/prepareHtmlFormSubmission.js only adds the hidden inputs immediately before the form is posted? If so, I don't think I'll be able to use that approach here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that's right, it only adds them once the submit event is triggered. Sorry.

@derat
Copy link
Contributor Author

derat commented Oct 17, 2023

@reosarevok Okay, I think I finally got all the Selenium tests passing. Mind taking a quick look and letting me know if this seems like a reasonable approach?

@derat
Copy link
Contributor Author

derat commented Oct 23, 2023

@mwiencek and/or @yvanzo, mind taking a look? Sorry, not sure who I should be asking for reviews. :-)

@mwiencek
Copy link
Member

Okay, I think I finally got all the Selenium tests passing. Mind taking a quick look and letting me know if this seems like a reasonable approach?

Seems like a reasonable approach for now! When these forms are converted to React later, we'll probably have a more direct way of calculating changes from the internal state, but things can always be improved later, and this is a good improvement on its own.

@derat
Copy link
Contributor Author

derat commented Oct 23, 2023

Thanks for the quick review! I think that this is ready to go in on my side (assuming there isn't some other easy way to check for pending relationship edits).

Copy link
Member

@reosarevok reosarevok left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quickly tested locally and it seems to work fine - it does not trigger if I close the page with ctrl+w while still inside the first field I have changed, but that's not a big issue since there's very little to lose in that case. As soon as I tab out of the first field the alert activates when trying to close the tab.

I guess we should squash all the test fixes for merging? :)

@derat
Copy link
Contributor Author

derat commented Oct 24, 2023

Quickly tested locally and it seems to work fine - it does not trigger if I close the page with ctrl+w while still inside the first field I have changed, but that's not a big issue since there's very little to lose in that case. As soon as I tab out of the first field the alert activates when trying to close the tab.

Would it be better to additionally watch for input events? I tend to prefer change since it's less spammy when the user is typing, but watching for input would catch modifications before they've been committed by a focus change.

https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event warns that checkboxes and radio buttons haven't always triggered input events (presumably on old versions of IE), so maybe it's safest to continue listening for change in either case.

And just to mention it, I noticed that neither change nor input appears to fire if the Area field on the artist form is empty and I select a new value from the suggestions using only the mouse. Lots of weird edge cases that'll be easier to handle once this is using React. :-)

I guess we should squash all the test fixes for merging? :)

Yeah, that was my hope! Is there a preferred approach to use here for MBS, by the way? I'd usually amend my change locally and force-push it to the branch, but I think that confuses GitHub when there are ongoing conversations on the older version of the change, so I sometimes avoid doing it.

@derat
Copy link
Contributor Author

derat commented Oct 26, 2023

@mwiencek or @reosarevok, mind merging this? Or please let me know if you'd prefer that I also add a listener for input events.

Copy link
Member

@mwiencek mwiencek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine with just handling change events for now!

@mwiencek mwiencek merged commit 2c808bb into metabrainz:master Oct 26, 2023
3 checks passed
@jesus2099
Copy link
Contributor

I'm only on phone for a few days but I think unsubmitted relationships (add, edit, remove) might have some specific CSS class, that we could test.

If we see such classes with document.querySelector(".pending-rel-add, .pending-rel-edit, .pending-rel-remove") or something like document.querySelector("[class^='pending-rel']") then we would trigger the stop code.

Just an idea.

@jesus2099
Copy link
Contributor

I checked with Kiwi Browser devtools, the pending relationship classes are:

  • table.rel-editor-table span.rel-add
  • table.rel-editor-table span.rel-edit
  • table.rel-editor-table span.rel-remove

@jesus2099
Copy link
Contributor

jesus2099 commented Oct 27, 2023

@derat

  • input change events: handled
  • relationship changes: see above
  • URL relationship changes: is it handled?

@derat
Copy link
Contributor Author

derat commented Oct 27, 2023

@jesus2099 Thanks for the suggestion! I've created #3064 to detect relationship and URL changes.

reosarevok added a commit that referenced this pull request Nov 1, 2023
* master:
  Update POT file from the current database
  Upgrade Flow to 0.220.0
  MBS-13320 (II): Warn on form unload with rel changes (#3064)
  Add labels to all tests in Data::Editor
  Give a name to remaining 'all' test and add labels
  Split various_edit_counts into separate test
  Split editor subscription methods into separate test
  MBS-13334: Also find emails with capitalization differences
  Split and expand email checking tests
  MBS-13320: Prompt before unloading modified forms (#3054)
  Split new editor creation test to new subtest
  Upgrade Flow to 0.219.3
  Remove a few $FlowIgnores
  Remove uses of any in SeriesIndex.js
  Replace $MakeReadOnly type with one using infer
  Upgrade Flow to 0.219.2
  Upgrade Flow to 0.219.0
  Upgrade Flow to 0.218.1
  Upgrade Flow to 0.218.0
  Upgrade Flow to 0.217.2
  Upgrade Flow to 0.217.1
  Upgrade Flow to 0.217.0
  Remove unnecessary check in concatStringMatch
  Fix indentation in PhraseVarArgs class
  Upgrade Flow to 0.216.1
  Upgrade Flow to 0.216.0
  Upgrade Flow to 0.215.1
  Upgrade Flow to 0.215.0
  MBS-13319: Show help bubble for language/script on release editor (#3053)
  Use our new contains_ functions in more places (#3051)
  MBS-8952: Can rename recordings via autocomplete (#3039)
  MBS-13317: Remove Kget.jp from lyrics whitelist (#3052)
  Fix newly detected eslint issues
  Upgrade ESLint and associated plugins
  Upgrade Babel dependencies
  Regenerate yarn.lock
  Upgrade Flow to 0.214.0
  Upgrade Flow to 0.213.1
  Upgrade Flow to 0.213.0
  Upgrade Flow to 0.212.0
  Upgrade Flow to 0.211.1
  Upgrade Flow to 0.211.0
  Upgrade Flow to 0.210.2
  Upgrade Flow to 0.210.1
  Upgrade Flow to 0.210.0
  Upgrade Flow to 0.209.0
  Upgrade Flow to 0.208.1
  Upgrade Flow to 0.208.0
  Switch Babel & ESLint parsers to hermes
  Upgrade Flow to 0.207.0
  Upgrade Flow to 0.206.0
  Upgrade Flow to 0.205.1
  Upgrade Flow to 0.205.0
  Upgrade Flow to 0.204.1
  Upgrade Flow to 0.204.0
  Upgrade Flow to 0.203.1
  Upgrade Flow to 0.203.0
  Upgrade Flow to 0.202.1
  Upgrade Flow to 0.202.0
  Remove all uses of the switch feature (given/when)
  Remove all uses of the smartmatch operator
  Link directly to the anchor in Markdown
  Update INSTALL.md's building static resources section (#3042)
yvanzo added a commit that referenced this pull request Nov 13, 2023
* beta:
  Translated using Weblate (Italian)
  Translated using Weblate (Lithuanian)
  Added translation using Weblate (Thai)
  Added translation using Weblate (Thai)
  Translated using Weblate (Russian)
  Translated using Weblate (French)
  Update translation files
  Update POT files using the production database
  Translated using Weblate (Italian)
  Update translation files
  Fix wrongly ordered calls l(addColonText(()
  Update POT files using the production database
  MBS-13336: Add a script to rebuild all indexes using collations (#3062)
  MBS-13309: Restrict cross-origin requests to /ws/js/edit (#3075)
  MBS-13348: Fix edit_data_idx_link_type (#3073)
  MBS-13349: Support LibraryThing disambiguation URLs (#3077)
  MBS-13347: Relationship Type edit search times out (#3074)
  MBS-5987: Add "Submit votes & edit notes" to top (#3072)
  MBS-13350: Return all barcode matches in release editor (#3076)
  Translated using Weblate (Chinese (Simplified))
  Translated using Weblate (German)
  Translated using Weblate (Italian)
  Translated using Weblate (French)
  Update translation files
  Add test for isObjectEmpty
  Add test for isBlank
  Add test for escapeLuceneValue
  Add test for escapeRegExp
  Add test for relationshipDateText
  Add test for sortByEntityName
  Move getSortName entities to constants
  Add test for isDisabledLink
  Add test for isFutureDate
  Add tests for strings
  Make renderMergeCheckboxElement function a component
  Fix require sort order
  Add test for isDateEmpty
  Add test for formatEndDate
  Add test for entityHref
  Make generic entity consts reusable
  Add test for isGuid
  Add test for isolateText
  Add test for natatime
  Add test for primaryAreaCode
  Add test for isDatabaseRowId
  Add test for getSortName
  More precise comparison for null barcode
  Add test for formatBarcode
  Add tests for clean
  Add tests for arrays.js functions
  Add test for calculateFullToc
  Add test for bracketed
  Add renderToStaticMarkup wrapper
  Use compareDates as the base for areDatesEqual
  Add test for areDatePeriodsEqual
  Use exactCount for newline-after-import eslint rule (#3071)
  MBS-12727: Show genre alias connections for tags (#2757)
  MBS-4822: Drop duplicate colon strings
  Add context to "Cancelled" and drop duplicate colons
  Add context to "Ended" and drop duplicate colons
  Add context to "Location" and drop duplicate colons
  Add context to EditReleaseEvents headings
  Standardize election headers and drop duplicate colons
  Add context to "Old" and drop duplicate colons
  Add context to "Status" and drop duplicate colons
  Add context to "Merge" and drop duplicate colons
  Add context to "Preview" and drop duplicate colons
  MBS-13207 (II): Move "Add a new recording" above suggestions (#3069)
  MBS-12893: Add places column to country statistics
  MBS-12852: Add events column to country statistics
  Ensure release stats are calculated for every country
  Use "create", "add", "enter" in more specific ways (#3070)
  Bump hermes-eslint to 0.17.1
  Bump eslint-plugin-ft-flow to 3.0.1
  Move eslint-plugin-simple-import-sort to devDependencies
  Migrate to Yarn v4
  Fix permission errors in run_selenium_tests.sh
  Bump SIR_TAG to v3.0.1 in the test images
  Switch to chrome-for-testing in tests
  Bump chromedriver to 119.0.6045.105
  Create the pgtap extension as a superuser
  Bump musicbrainz-tests-perl-5-dot-30 image
  Fix phusion/baseimage focal tag
  Fix PGDATA permission issues
  MBS-13261: Upgrade the required version of Node.js to 20
  Move duplicated CircleCI steps to script
  Regenerate cpanfile.snapshot
  Fix apt-key deprecation warning
  Upgrade the Docker base images to jammy
  Bump ARTWORK_REDIRECT_COMMIT
  Copy Dockerfile.tests to Dockerfile.perl5.30.tests
  Explicitly list the .gitignore'd Dockerfiles
  Replace xgettext-js with forked copy using hermes-parser (#3067)
  Use Unicode quotes for string being changed already
  Use Unicode quotes for string being changed already
  Remove i.e. from user-facing strings
  Remove e.g. from user-facing strings
  Capitalize URL in user-facing string (#3058)
  Normalize "track duration" to "track length" in UI (#3057)
  Normalize "pending edits" to "open edits" in UI (#3056)
  Update POT file from the current database
  Translated using Weblate (Turkish)
  Translated using Weblate (German)
  Translated using Weblate (Japanese)
  Added translation using Weblate (Chinese (Traditional))
  Translated using Weblate (Japanese)
  Translated using Weblate (Spanish)
  Translated using Weblate (Portuguese)
  Translated using Weblate (Chinese (Simplified))
  Translated using Weblate (Russian)
  Translated using Weblate (French)
  Translated using Weblate (Bengali)
  Translated using Weblate (Portuguese)
  Translated using Weblate (German)
  Translated using Weblate (Italian)
  Translated using Weblate (Lithuanian)
  Use "remove" consistently for non-editor cases
  Translated using Weblate (Turkish)
  Translated using Weblate (German)
  Translated using Weblate (Japanese)
  Added translation using Weblate (Chinese (Traditional))
  Translated using Weblate (Japanese)
  Translated using Weblate (Spanish)
  Translated using Weblate (Portuguese)
  Translated using Weblate (Chinese (Simplified))
  Translated using Weblate (Russian)
  Translated using Weblate (French)
  Translated using Weblate (Bengali)
  Translated using Weblate (Portuguese)
  Translated using Weblate (German)
  Translated using Weblate (Italian)
  Translated using Weblate (Lithuanian)
  Upgrade Flow to 0.220.0
  MBS-13320 (II): Warn on form unload with rel changes (#3064)
  Add labels to all tests in Data::Editor
  Give a name to remaining 'all' test and add labels
  Split various_edit_counts into separate test
  Split editor subscription methods into separate test
  MBS-13334: Also find emails with capitalization differences
  Split and expand email checking tests
  MBS-13320: Prompt before unloading modified forms (#3054)
  Split new editor creation test to new subtest
  Upgrade Flow to 0.219.3
  Remove a few $FlowIgnores
  Remove uses of any in SeriesIndex.js
  Replace $MakeReadOnly type with one using infer
  Upgrade Flow to 0.219.2
  Upgrade Flow to 0.219.0
  Upgrade Flow to 0.218.1
  Upgrade Flow to 0.218.0
  Upgrade Flow to 0.217.2
  Upgrade Flow to 0.217.1
  Upgrade Flow to 0.217.0
  Remove unnecessary check in concatStringMatch
  Fix indentation in PhraseVarArgs class
  Upgrade Flow to 0.216.1
  Upgrade Flow to 0.216.0
  Upgrade Flow to 0.215.1
  Upgrade Flow to 0.215.0
  MBS-13319: Show help bubble for language/script on release editor (#3053)
  Use our new contains_ functions in more places (#3051)
  MBS-8952: Can rename recordings via autocomplete (#3039)
  MBS-13317: Remove Kget.jp from lyrics whitelist (#3052)
  Fix newly detected eslint issues
  Upgrade ESLint and associated plugins
  Upgrade Babel dependencies
  Regenerate yarn.lock
  Upgrade Flow to 0.214.0
  Upgrade Flow to 0.213.1
  Upgrade Flow to 0.213.0
  Upgrade Flow to 0.212.0
  Upgrade Flow to 0.211.1
  Upgrade Flow to 0.211.0
  Upgrade Flow to 0.210.2
  Upgrade Flow to 0.210.1
  Upgrade Flow to 0.210.0
  Upgrade Flow to 0.209.0
  Upgrade Flow to 0.208.1
  Upgrade Flow to 0.208.0
  Switch Babel & ESLint parsers to hermes
  Upgrade Flow to 0.207.0
  Upgrade Flow to 0.206.0
  Upgrade Flow to 0.205.1
  Upgrade Flow to 0.205.0
  Upgrade Flow to 0.204.1
  Upgrade Flow to 0.204.0
  Upgrade Flow to 0.203.1
  Upgrade Flow to 0.203.0
  Upgrade Flow to 0.202.1
  Upgrade Flow to 0.202.0
  Remove all uses of the switch feature (given/when)
  Remove all uses of the smartmatch operator
  Link directly to the anchor in Markdown
  Update INSTALL.md's building static resources section (#3042)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants