Merge branch 'alert-on-form-leave' into 'master'
Show prompt if user has touched a form and tries to leave page Closes #377 See merge request !233
This commit is contained in:
commit
0cabee0826
@ -247,6 +247,88 @@
|
|||||||
setup: interactiveFieldsetUtil,
|
setup: interactiveFieldsetUtil,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Navigate Away Prompt Utility
|
||||||
|
* This utility asks the user if (s)he really wants to navigate away
|
||||||
|
* from a page containing a form if (s)he already touched an input.
|
||||||
|
* Form-Submits will not trigger the prompt.
|
||||||
|
* Utility will ignore forms that contain auto submit elements (buttons, inputs).
|
||||||
|
*
|
||||||
|
* Attribute: [none]
|
||||||
|
* (automatically setup on all form tags that dont automatically submit, see AutoSubmitButtonUtil)
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
* (any page with a form)
|
||||||
|
*/
|
||||||
|
|
||||||
|
var NAVIGATE_AWAY_PROMPT_UTIL_NAME = 'navigateAwayPrompt';
|
||||||
|
var NAVIGATE_AWAY_PROMPT_UTIL_SELECTOR = 'form';
|
||||||
|
|
||||||
|
var NAVIGATE_AWAY_PROMPT_INITIALIZED_CLASS = 'navigate-away-prompt--initialized';
|
||||||
|
|
||||||
|
var navigateAwayPromptUtil = function(element) {
|
||||||
|
var touched = false;
|
||||||
|
var unloadDueToSubmit = false;
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
if (!element) {
|
||||||
|
throw new Error('Navigate Away Prompt utility needs to be passed an element!');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.classList.contains(NAVIGATE_AWAY_PROMPT_INITIALIZED_CLASS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore forms that get submitted automatically
|
||||||
|
if (element.querySelector(AUTO_SUBMIT_BUTTON_UTIL_SELECTOR) || element.querySelector(AUTO_SUBMIT_INPUT_UTIL_SELECTOR)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('beforeunload', beforeUnloadHandler);
|
||||||
|
|
||||||
|
element.addEventListener('submit', function() {
|
||||||
|
unloadDueToSubmit = true;
|
||||||
|
});
|
||||||
|
element.addEventListener('change', function() {
|
||||||
|
touched = true;
|
||||||
|
unloadDueToSubmit = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// mark initialized
|
||||||
|
element.classList.add(NAVIGATE_AWAY_PROMPT_INITIALIZED_CLASS);
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: NAVIGATE_AWAY_PROMPT_UTIL_NAME,
|
||||||
|
element: element,
|
||||||
|
destroy: function() {
|
||||||
|
window.removeEventListener('beforeunload', beforeUnloadHandler);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function beforeUnloadHandler(event) {
|
||||||
|
// allow the event to happen if the form was not touched by the
|
||||||
|
// user or the unload event was initiated by a form submit
|
||||||
|
if (!touched || unloadDueToSubmit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cancel the unload event. This is the standard to force the prompt to appear.
|
||||||
|
event.preventDefault();
|
||||||
|
// for all non standard compliant browsers we return a truthy value to activate the prompt.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return init();
|
||||||
|
};
|
||||||
|
|
||||||
|
formUtilities.push({
|
||||||
|
name: NAVIGATE_AWAY_PROMPT_UTIL_NAME,
|
||||||
|
selector: NAVIGATE_AWAY_PROMPT_UTIL_SELECTOR,
|
||||||
|
setup: navigateAwayPromptUtil,
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Auto Submit Button Utility
|
* Auto Submit Button Utility
|
||||||
@ -270,6 +352,10 @@
|
|||||||
throw new Error('Auto Submit Button utility needs to be passed an element!');
|
throw new Error('Auto Submit Button utility needs to be passed an element!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (element.classList.contains(AUTO_SUBMIT_BUTTON_INITIALIZED_CLASS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// hide and mark initialized
|
// hide and mark initialized
|
||||||
element.classList.add(AUTO_SUBMIT_BUTTON_HIDDEN_CLASS, AUTO_SUBMIT_BUTTON_INITIALIZED_CLASS);
|
element.classList.add(AUTO_SUBMIT_BUTTON_HIDDEN_CLASS, AUTO_SUBMIT_BUTTON_INITIALIZED_CLASS);
|
||||||
|
|
||||||
@ -315,6 +401,10 @@
|
|||||||
throw new Error('Auto Submit Input utility needs to be passed an element!');
|
throw new Error('Auto Submit Input utility needs to be passed an element!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (element.classList.contains(AUTO_SUBMIT_INPUT_INITIALIZED_CLASS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
form = element.form;
|
form = element.form;
|
||||||
if (!form) {
|
if (!form) {
|
||||||
throw new Error('Could not determine associated form for auto submit input');
|
throw new Error('Could not determine associated form for auto submit input');
|
||||||
@ -374,6 +464,10 @@
|
|||||||
throw new Error('Form Error Remover utility needs to be passed an element!');
|
throw new Error('Form Error Remover utility needs to be passed an element!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (element.classList.contains(FORM_ERROR_REMOVER_INITIALIZED_CLASS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// find form groups
|
// find form groups
|
||||||
formGroups = Array.from(element.querySelectorAll(FORM_GROUP_SELECTOR));
|
formGroups = Array.from(element.querySelectorAll(FORM_GROUP_SELECTOR));
|
||||||
|
|
||||||
@ -428,6 +522,8 @@
|
|||||||
var DATEPICKER_UTIL_NAME = 'datepicker';
|
var DATEPICKER_UTIL_NAME = 'datepicker';
|
||||||
var DATEPICKER_UTIL_SELECTOR = 'input[type="date"], input[type="time"], input[type="datetime-local"]';
|
var DATEPICKER_UTIL_SELECTOR = 'input[type="date"], input[type="time"], input[type="datetime-local"]';
|
||||||
|
|
||||||
|
var DATEPICKER_INITIALIZED_CLASS = 'datepicker--initialized';
|
||||||
|
|
||||||
var DATEPICKER_CONFIG = {
|
var DATEPICKER_CONFIG = {
|
||||||
"datetime-local": {
|
"datetime-local": {
|
||||||
enableTime: true,
|
enableTime: true,
|
||||||
@ -459,6 +555,10 @@
|
|||||||
throw new Error('Datepicker utility needs to be passed an element!');
|
throw new Error('Datepicker utility needs to be passed an element!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (element.classList.contains(DATEPICKER_INITIALIZED_CLASS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var flatpickrConfig = DATEPICKER_CONFIG[element.getAttribute("type")];
|
var flatpickrConfig = DATEPICKER_CONFIG[element.getAttribute("type")];
|
||||||
|
|
||||||
if (!flatpickrConfig) {
|
if (!flatpickrConfig) {
|
||||||
@ -467,6 +567,9 @@
|
|||||||
|
|
||||||
flatpickrInstance = flatpickr(element, flatpickrConfig);
|
flatpickrInstance = flatpickr(element, flatpickrConfig);
|
||||||
|
|
||||||
|
// mark initialized
|
||||||
|
element.classList.add(DATEPICKER_INITIALIZED_CLASS);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: DATEPICKER_UTIL_NAME,
|
name: DATEPICKER_UTIL_NAME,
|
||||||
element: element,
|
element: element,
|
||||||
|
|||||||
Reference in New Issue
Block a user