diff --git a/static/css/utils/modal.scss b/static/css/utils/modal.scss index 0718a4367..5cac989a3 100644 --- a/static/css/utils/modal.scss +++ b/static/css/utils/modal.scss @@ -13,6 +13,7 @@ color: var(--color-font); padding: 0 65px 0 20px; overflow: auto; + overscroll-behavior: contain; transition: opacity .2s .1s ease-in-out, transform .3s ease-in-out; diff --git a/static/js/utils/modal.js b/static/js/utils/modal.js index 1e591271a..6d12da8d5 100644 --- a/static/js/utils/modal.js +++ b/static/js/utils/modal.js @@ -6,11 +6,28 @@ var JS_INITIALIZED_CLASS = 'js-modal-initialized'; var MODAL_OPEN_CLASS = 'modal--open'; var MODAL_TRIGGER_CLASS = 'modal__trigger'; + var MODAL_CONTENT_CLASS = 'modal__content'; + var MAIN_CONTENT_CLASS = 'main__content-body' var MODAL_CLOSABLE_FLAG = 'closeable'; + var MODAL_DYNAMIC_FLAG = 'dynamic'; var OVERLAY_CLASS = 'modal__overlay'; var OVERLAY_OPEN_CLASS = 'modal__overlay--open'; var CLOSER_CLASS = 'modal__closer'; - var AJAX_SUBMIT_FLAG = 'ajaxSubmit' + var AJAX_SUBMIT_FLAG = 'ajaxSubmit'; + + // helper function for convenient http requests with appropriate headers + function httpRequest(url, method, body) { + var requestOptions = { + method: method, + credentials: 'same-origin', + headers: { + 'Is-Modal': 'True', + }, + body: body, + }; + + return fetch(url, requestOptions); + } window.utils.modal = function(modalElement, options) { @@ -22,6 +39,18 @@ var closerElement = document.createElement('div'); var triggerElement = document.querySelector('#' + modalElement.dataset.trigger); + function setup() { + document.body.insertBefore(modalElement, null); + + setupForm(); + setupCloser(); + + triggerElement.classList.add(MODAL_TRIGGER_CLASS); + triggerElement.addEventListener('click', open, false); + + modalElement.classList.add(JS_INITIALIZED_CLASS); + } + function open(event) { event.preventDefault(); @@ -29,6 +58,11 @@ overlayElement.classList.add(OVERLAY_CLASS); document.body.insertBefore(overlayElement, modalElement); overlayElement.classList.add(OVERLAY_OPEN_CLASS); + + var modalUrl = triggerElement.getAttribute('href'); + if (modalUrl && MODAL_DYNAMIC_FLAG in modalElement.dataset) { + fillModal(modalUrl); + } } function close(event) { @@ -37,50 +71,60 @@ modalElement.classList.remove(MODAL_OPEN_CLASS); }; - function setup() { - document.body.insertBefore(modalElement, null); - + function setupForm() { var form = modalElement.querySelector('form'); if (form && AJAX_SUBMIT_FLAG in form.dataset) { - setupForm(form); - } + form.addEventListener('submit', function(event) { + event.preventDefault(); + var url = form.getAttribute('action'); + var body = new FormData(form); + + return httpRequest(url, form.method, body).then(function(response) { + return response.json(); + }).then(function(response) { + // TODO: process json response once backend returns json + }).catch(function(error) { + console.error('could not fetch or process response from ' + url, { error }); + }); + }); + } + } + + function setupCloser() { if (MODAL_CLOSABLE_FLAG in modalElement.dataset) { modalElement.insertBefore(closerElement, null); closerElement.classList.add(CLOSER_CLASS); closerElement.addEventListener('click', close, false); overlayElement.addEventListener('click', close, false); } - - triggerElement.classList.add(MODAL_TRIGGER_CLASS); - triggerElement.addEventListener('click', open, false); - modalElement.classList.add(JS_INITIALIZED_CLASS); } - function setupForm(form) { - form.addEventListener('submit', function(event) { - event.preventDefault(); - - var url = form.getAttribute('action'); - var httpRequestOptions = { - method: form.method, - credentials: 'same-origin', - headers: { - 'Is-Modal': 'True' - }, - body: new FormData(form), - }; - - return fetch(url, httpRequestOptions).then(function(response) { - return response.json(); - }).then(function(response) { - // TODO: process json response once backend returns json - }).catch(function(error) { - console.error('could not fetch or process response from ' + url, { error }); - }); + function fillModal(url) { + httpRequest(url, 'GET').then(function(response) { + response.text().then(processResponse); }); } + function processResponse(reponseBody) { + var modalContent = document.createElement('div'); + modalContent.classList.add(MODAL_CONTENT_CLASS); + modalContent.innerHTML = reponseBody; + + var contentBody = modalContent.querySelector('.' + MAIN_CONTENT_CLASS); + + if (contentBody) { + modalContent.innerHTML = contentBody.innerHTML; + } + + var previousModalContent = modalElement.querySelector('.' + MODAL_CONTENT_CLASS); + if (previousModalContent) { + previousModalContent.remove(); + } + modalElement.insertBefore(modalContent, null); + setupForm(); + } + setup(); }; })();