diff --git a/src/Foundation.hs b/src/Foundation.hs index e3c89b3aa..e4de524d2 100644 --- a/src/Foundation.hs +++ b/src/Foundation.hs @@ -1031,6 +1031,7 @@ siteLayout' headingOverride widget = do addScript $ StaticR js_utils_tabber_js addStylesheet $ StaticR css_utils_alerts_scss addStylesheet $ StaticR css_utils_asidenav_scss + addStylesheet $ StaticR css_utils_asyncForm_scss addStylesheet $ StaticR css_utils_form_scss addStylesheet $ StaticR css_utils_inputs_scss addStylesheet $ StaticR css_utils_modal_scss diff --git a/static/css/utils/asyncForm.scss b/static/css/utils/asyncForm.scss new file mode 100644 index 000000000..eb8dc0635 --- /dev/null +++ b/static/css/utils/asyncForm.scss @@ -0,0 +1,9 @@ +.async-form-response { + margin: 20px 0; +} + +.async-form-loading { + opacity: 0.1; + transition: opacity 400ms ease-in-out; + pointer-events: none; +} diff --git a/static/js/utils/asyncForm.js b/static/js/utils/asyncForm.js index a7086bdc3..14e77c805 100644 --- a/static/js/utils/asyncForm.js +++ b/static/js/utils/asyncForm.js @@ -3,12 +3,21 @@ window.utils = window.utils || {}; + var ASYNC_FORM_RESPONSE_CLASS = 'async-form-response'; + var ASYNC_FORM_LOADING_CLASS = 'async-form-loading'; + var ASYNC_FORM_MIN_DELAY = 600; + window.utils.asyncForm = function(formElement, options) { + var lastRequestTimestamp = 0; + function setup() { formElement.addEventListener('submit', function(event) { event.preventDefault(); + formElement.classList.add(ASYNC_FORM_LOADING_CLASS) + lastRequestTimestamp = Date.now(); + var url = formElement.getAttribute('action'); var headers = { }; var body = new FormData(formElement); @@ -23,14 +32,28 @@ .then(function(response) { return response.json(); }).then(function(response) { - console.log('asyncForm: got response', response); - // TODO: process json response once backend returns json + processResponse(response[0]) }).catch(function(error) { console.error('could not fetch or process response from ' + url, { error }); }); }); } + function processResponse(response) { + var responseElement = document.createElement('div'); + responseElement.classList.add(ASYNC_FORM_RESPONSE_CLASS); + responseElement.innerHTML = response.content; + var parentElement = formElement.parentElement; + + // make sure there is a delay between click and response + var delay = Math.max(0, ASYNC_FORM_MIN_DELAY + lastRequestTimestamp - Date.now()); + setTimeout(function() { + parentElement.insertBefore(responseElement, formElement); + formElement.remove(); + }, delay); + + } + setup(); }; })();