refactor async form js util
This commit is contained in:
parent
63aef9e362
commit
559fb3fb9d
@ -1071,6 +1071,7 @@ siteLayout' headingOverride widget = do
|
|||||||
-- addScript $ StaticR js_utils_alerts_js
|
-- addScript $ StaticR js_utils_alerts_js
|
||||||
-- addScript $ StaticR js_utils_asidenav_js
|
-- addScript $ StaticR js_utils_asidenav_js
|
||||||
-- JavaScript utils
|
-- JavaScript utils
|
||||||
|
addScript $ StaticR js_utils_asyncForm_js
|
||||||
addScript $ StaticR js_utils_asyncTable_js
|
addScript $ StaticR js_utils_asyncTable_js
|
||||||
addScript $ StaticR js_utils_checkAll_js
|
addScript $ StaticR js_utils_checkAll_js
|
||||||
addScript $ StaticR js_utils_form_js
|
addScript $ StaticR js_utils_form_js
|
||||||
|
|||||||
@ -121,7 +121,7 @@ postAdminTestR = do
|
|||||||
let emailWidget' = wrapForm emailWidget def
|
let emailWidget' = wrapForm emailWidget def
|
||||||
{ formAction = Just . SomeRoute $ AdminTestR
|
{ formAction = Just . SomeRoute $ AdminTestR
|
||||||
, formEncoding = emailEnctype
|
, formEncoding = emailEnctype
|
||||||
, formAttrs = [("data-ajax-submit", "")]
|
, formAttrs = [("uw-async-form", "")]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -261,7 +261,7 @@ postHelpR = do
|
|||||||
let form = wrapForm formWidget def
|
let form = wrapForm formWidget def
|
||||||
{ formAction = Just $ SomeRoute HelpR
|
{ formAction = Just $ SomeRoute HelpR
|
||||||
, formEncoding = formEnctype
|
, formEncoding = formEnctype
|
||||||
, formAttrs = [ ("data-ajax-submit", "") | isModal ]
|
, formAttrs = [ ("uw-async-form", "") | isModal ]
|
||||||
}
|
}
|
||||||
|
|
||||||
formResultModal res HelpR $ \HelpForm{..} -> do
|
formResultModal res HelpR $ \HelpForm{..} -> do
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
.async-form-response {
|
.async-form__response {
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -7,15 +7,15 @@
|
|||||||
padding-top: 60px;
|
padding-top: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.async-form-response::before,
|
.async-form__response::before,
|
||||||
.async-form-response::after {
|
.async-form__response::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.async-form-response--success::before {
|
.async-form__response--success::before {
|
||||||
content: '';
|
content: '';
|
||||||
width: 17px;
|
width: 17px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
@ -24,7 +24,7 @@
|
|||||||
transform: translateX(-50%) rotate(45deg);
|
transform: translateX(-50%) rotate(45deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.async-form-response--info::before {
|
.async-form__response--info::before {
|
||||||
content: '';
|
content: '';
|
||||||
width: 5px;
|
width: 5px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
@ -32,7 +32,7 @@
|
|||||||
background-color: #777;
|
background-color: #777;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
}
|
}
|
||||||
.async-form-response--info::after {
|
.async-form__response--info::after {
|
||||||
content: '';
|
content: '';
|
||||||
width: 5px;
|
width: 5px;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
@ -40,14 +40,14 @@
|
|||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.async-form-response--warning::before {
|
.async-form__response--warning::before {
|
||||||
content: '';
|
content: '';
|
||||||
width: 5px;
|
width: 5px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
background-color: rgb(255, 187, 0);
|
background-color: rgb(255, 187, 0);
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
}
|
}
|
||||||
.async-form-response--warning::after {
|
.async-form__response--warning::after {
|
||||||
content: '';
|
content: '';
|
||||||
width: 5px;
|
width: 5px;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
@ -56,14 +56,14 @@
|
|||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.async-form-response--error::before {
|
.async-form__response--error::before {
|
||||||
content: '';
|
content: '';
|
||||||
width: 5px;
|
width: 5px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
background-color: #940d0d;
|
background-color: #940d0d;
|
||||||
transform: translateX(-50%) rotate(-45deg);
|
transform: translateX(-50%) rotate(-45deg);
|
||||||
}
|
}
|
||||||
.async-form-response--error::after {
|
.async-form__response--error::after {
|
||||||
content: '';
|
content: '';
|
||||||
width: 5px;
|
width: 5px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
@ -71,7 +71,7 @@
|
|||||||
transform: translateX(-50%) rotate(45deg);
|
transform: translateX(-50%) rotate(45deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.async-form-loading {
|
.async-form--loading {
|
||||||
opacity: 0.1;
|
opacity: 0.1;
|
||||||
transition: opacity 800ms ease-out;
|
transition: opacity 800ms ease-out;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|||||||
@ -1,33 +1,62 @@
|
|||||||
(function collonadeClosure() {
|
(function collonadeClosure() {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
window.utils = window.utils || {};
|
/**
|
||||||
|
*
|
||||||
|
* Async Form Utility
|
||||||
|
* prevents form submissions from reloading the page but instead firing an AJAX request
|
||||||
|
*
|
||||||
|
* Attribute: uw-async-form
|
||||||
|
* (works only on <form> elements)
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
* <form uw-async-form method='POST' action='...'>
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
|
||||||
var ASYNC_FORM_RESPONSE_CLASS = 'async-form-response';
|
var ASYNC_FORM_UTIL_NAME = 'asyncForm';
|
||||||
var ASYNC_FORM_LOADING_CLASS = 'async-form-loading';
|
var ASYNC_FORM_UTIL_SELECTOR = 'form[uw-async-form]';
|
||||||
|
|
||||||
|
var ASYNC_FORM_INITIALIZED_CLASS = 'check-all--initialized';
|
||||||
|
var ASYNC_FORM_RESPONSE_CLASS = 'async-form__response';
|
||||||
|
var ASYNC_FORM_LOADING_CLASS = 'async-form--loading';
|
||||||
var ASYNC_FORM_MIN_DELAY = 600;
|
var ASYNC_FORM_MIN_DELAY = 600;
|
||||||
var DEFAULT_FAILURE_MESSAGE = 'The response we received from the server did not match what we expected. Please let us know this happened via the help widget in the top navigation.';
|
var ASYNC_FORM_DEFAULT_FAILURE_MESSAGE = 'The response we received from the server did not match what we expected. Please let us know this happened via the help widget in the top navigation.';
|
||||||
|
|
||||||
window.utils.asyncForm = function(formElement, options) {
|
var asyncFormUtil = function(element) {
|
||||||
|
|
||||||
options = options || {};
|
|
||||||
|
|
||||||
var lastRequestTimestamp = 0;
|
var lastRequestTimestamp = 0;
|
||||||
|
|
||||||
function setup() {
|
function init() {
|
||||||
formElement.addEventListener('submit', submitHandler);
|
if (!element) {
|
||||||
|
throw new Error('Async Form Utility cannot be setup without an element!');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.classList.contains(ASYNC_FORM_INITIALIZED_CLASS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
element.addEventListener('submit', submitHandler);
|
||||||
|
|
||||||
|
element.classList.add(ASYNC_FORM_INITIALIZED_CLASS);
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: ASYNC_FORM_UTIL_NAME,
|
||||||
|
element: element,
|
||||||
|
destroy: function() {},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function processResponse(response) {
|
function processResponse(response) {
|
||||||
var responseElement = makeResponseElement(response.content, response.status);
|
var responseElement = makeResponseElement(response.content, response.status);
|
||||||
var parentElement = formElement.parentElement;
|
var parentElement = element.parentElement;
|
||||||
|
|
||||||
// make sure there is a delay between click and response
|
// make sure there is a delay between click and response
|
||||||
var delay = Math.max(0, ASYNC_FORM_MIN_DELAY + lastRequestTimestamp - Date.now());
|
var delay = Math.max(0, ASYNC_FORM_MIN_DELAY + lastRequestTimestamp - Date.now());
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
parentElement.insertBefore(responseElement, formElement);
|
parentElement.insertBefore(responseElement, element);
|
||||||
formElement.remove();
|
element.remove();
|
||||||
}, delay);
|
}, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,12 +72,12 @@
|
|||||||
function submitHandler(event) {
|
function submitHandler(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
formElement.classList.add(ASYNC_FORM_LOADING_CLASS)
|
element.classList.add(ASYNC_FORM_LOADING_CLASS)
|
||||||
lastRequestTimestamp = Date.now();
|
lastRequestTimestamp = Date.now();
|
||||||
|
|
||||||
var url = formElement.getAttribute('action');
|
var url = element.getAttribute('action');
|
||||||
var headers = { };
|
var headers = { };
|
||||||
var body = new FormData(formElement);
|
var body = new FormData(element);
|
||||||
|
|
||||||
if (options && options.headers) {
|
if (options && options.headers) {
|
||||||
Object.keys(options.headers).forEach(function(headerKey) {
|
Object.keys(options.headers).forEach(function(headerKey) {
|
||||||
@ -66,21 +95,24 @@
|
|||||||
}).then(function(response) {
|
}).then(function(response) {
|
||||||
processResponse(response[0]);
|
processResponse(response[0]);
|
||||||
}).catch(function(error) {
|
}).catch(function(error) {
|
||||||
var failureMessage = DEFAULT_FAILURE_MESSAGE;
|
var failureMessage = ASYNC_FORM_DEFAULT_FAILURE_MESSAGE;
|
||||||
if (options.i18n && options.i18n.asyncFormFailure) {
|
if (options.i18n && options.i18n.asyncFormFailure) {
|
||||||
failureMessage = options.i18n.asyncFormFailure;
|
failureMessage = options.i18n.asyncFormFailure;
|
||||||
}
|
}
|
||||||
processResponse({ content: failureMessage });
|
processResponse({ content: failureMessage });
|
||||||
|
|
||||||
formElement.classList.remove(ASYNC_FORM_LOADING_CLASS);
|
element.classList.remove(ASYNC_FORM_LOADING_CLASS);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setup();
|
return init();
|
||||||
|
|
||||||
return {
|
|
||||||
scope: formElement,
|
|
||||||
destroy: function() {},
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (UtilRegistry) {
|
||||||
|
UtilRegistry.register({
|
||||||
|
name: ASYNC_FORM_UTIL_NAME,
|
||||||
|
selector: ASYNC_FORM_UTIL_SELECTOR,
|
||||||
|
setup: asyncFormUtil
|
||||||
|
});
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user