Files
openfoodnetwork/app/webpacker/controllers/unsaved_changes_controller.js
Gaetan Craig-Riou fd278e0086 Fix bug when submitting form triggered a warning and potentially left submit button disable
jquery-ujs automatically disable submit button when submitting the form.
If one choose cancel on the leaving page warning, then the submit buttons
end up in a disable state, with no way to re enable them. This fix
prevent the warning from being triggered when submitting the form, so
we can't end up in the scenario described.
2023-02-08 16:28:41 +11:00

116 lines
3.5 KiB
JavaScript

import { Controller } from "stimulus";
// UnsavedChanges allows you to promp the user about unsaved changes when trying to leave the page
//
// Usage :
// - with beforeunload event :
// <form
// data-controller="unsaved-changes"
// data-action="unsaved-changes#submit beforeunload@window->unsaved-changes#leavingPage"
// data-unsaved-changes-changed="true"
// >
// <input data-action="change->unsaved-changes#formIsChanged" />
// </form>
//
// - with turbolinks :
// <form
// data-controller="unsaved-changes"
// data-action="unsaved-changes#submit turbolinks:before-visit@window->unsaved-changes#leavingPage"
// data-unsaved-changes-changed="true"
// >
// <input data-action="change->unsaved-changes#formIsChanged" />
// </form>
//
// You can also combine the two event trigger ie :
// <form
// data-controller="unsaved-changes"
// data-action="unsaved-changes#submit beforeunload@window->unsaved-changes#leavingPage turbolinks:before-visit@window->unsaved-changes#leavingPage"
// data-unsaved-changes-changed="true"
// >
// You then need to add 'data-action="change->unsaved-changes#formIsChanged"' on all the form element
// that can be interacted with
//
// Optional, you can add 'data-unsaved-changes-changed="true"' if you want to disable all
// submit buttons when the form hasn't been interacted with
//
export default class extends Controller {
connect() {
// disable submit button when first loading the page
if (!this.isFormChanged() && this.isSubmitButtonDisabled()) {
this.disableButtons();
}
}
formIsChanged(event) {
// We only do something if the form hasn't already been changed
if (!this.isFormChanged()) {
this.setChanged("true");
if (this.isSubmitButtonDisabled()) {
this.enableButtons();
}
}
}
leavingPage(event) {
const LEAVING_PAGE_MESSAGE = I18n.t("admin.unsaved_confirm_leave");
if (this.isFormChanged()) {
if (event.type == "turbolinks:before-visit") {
if (!window.confirm(LEAVING_PAGE_MESSAGE)) {
event.preventDefault();
}
} else {
// We cover our bases, according to the documentation we should be able to prompt the user
// by calling event.preventDefault(), but it's not really supported yet.
// Instead we set the value of event.returnValue, and return a string, both of them
// should prompt the user.
// Note, in most modern browser a generic string not under the control of the webpage is shown
// instead of the returned string.
//
// More info : https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
//
event.returnValue = LEAVING_PAGE_MESSAGE;
return event.returnValue;
}
}
}
submit(event) {
// if we are submitting the form, we don't want to trigger a warning so set changed to false
this.setChanged("false")
}
setChanged(changed) {
this.data.set("changed", changed);
}
isFormChanged() {
return this.data.get("changed") == "true";
}
isSubmitButtonDisabled() {
if (this.data.has("disable-submit-button")) {
return this.data.get("disable-submit-button") == "true";
}
return false;
}
enableButtons() {
this.submitButtons().forEach((button) => {
button.disabled = false;
});
}
disableButtons() {
this.submitButtons().forEach((button) => {
button.disabled = true;
});
}
submitButtons() {
return this.element.querySelectorAll("input[type='submit']");
}
}