233 lines
7.0 KiB
JavaScript
233 lines
7.0 KiB
JavaScript
(function() {
|
|
'use strict';
|
|
|
|
/**
|
|
*
|
|
* Mass Input Utility
|
|
* allows form shapes to be manipulated asynchronously:
|
|
* will asynchronously submit the containing form and replace the contents
|
|
* of the mass input element with the one from the BE response
|
|
* The utility will only trigger an AJAX request if the mass input element has
|
|
* an active/focused element whilst the form is being submitted.
|
|
*
|
|
* Attribute: uw-mass-input
|
|
*
|
|
* Example usage:
|
|
* <form method="POST" action="...">
|
|
* <input type="text">
|
|
* <div uw-mass-input>
|
|
* <input type="text">
|
|
* <button type="submit">
|
|
*/
|
|
|
|
var MASS_INPUT_UTIL_NAME = 'massInput';
|
|
var MASS_INPUT_UTIL_SELECTOR = '[uw-mass-input]';
|
|
|
|
var MASS_INPUT_CELL_SELECTOR = '.massinput__cell';
|
|
var MASS_INPUT_ADD_CELL_SELECTOR = '.massinput__cell--add';
|
|
var MASS_INPUT_SUBMIT_BUTTON_CLASS = 'massinput__submit-button';
|
|
var MASS_INPUT_INITIALIZED_CLASS = 'mass-input--initialized';
|
|
|
|
var massInputUtil = function(element) {
|
|
var massInputId;
|
|
var massInputFormSubmitHandler;
|
|
var massInputForm;
|
|
|
|
function init() {
|
|
if (!element) {
|
|
throw new Error('Mass Input utility cannot be setup without an element!');
|
|
}
|
|
|
|
if (element.classList.contains(MASS_INPUT_INITIALIZED_CLASS)) {
|
|
return false;
|
|
}
|
|
|
|
massInputId = element.dataset.massInputIdent || '_';
|
|
massInputForm = element.closest('form');
|
|
|
|
if (!massInputForm) {
|
|
throw new Error('Mass Input utility cannot be setup without being wrapped in a <form>!');
|
|
}
|
|
|
|
massInputFormSubmitHandler = makeSubmitHandler();
|
|
|
|
// setup submit buttons inside this massinput so browser
|
|
// uses correct submit button for form submission.
|
|
var buttons = getMassInputSubmitButtons();
|
|
buttons.forEach(function(button) {
|
|
setupSubmitButton(button);
|
|
});
|
|
|
|
massInputForm.addEventListener('submit', massInputFormSubmitHandler);
|
|
massInputForm.addEventListener('keypress', keypressHandler);
|
|
|
|
// mark initialized
|
|
element.classList.add(MASS_INPUT_INITIALIZED_CLASS);
|
|
|
|
return {
|
|
name: MASS_INPUT_UTIL_NAME,
|
|
element: element,
|
|
destroy: function() {
|
|
reset();
|
|
},
|
|
};
|
|
}
|
|
|
|
function makeSubmitHandler() {
|
|
if (!HttpClient) {
|
|
throw new Error('HttpClient not found!');
|
|
}
|
|
|
|
var method = massInputForm.getAttribute('method') || 'POST';
|
|
var url = massInputForm.getAttribute('action') || window.location.href;
|
|
var enctype = massInputForm.getAttribute('enctype') || 'application/json';
|
|
|
|
var requestFn;
|
|
if (HttpClient[method.toLowerCase()]) {
|
|
requestFn = HttpClient[method.toLowerCase()];
|
|
}
|
|
|
|
return function(event) {
|
|
var activeElement;
|
|
|
|
// check if event occured from either a mass input add/delete button or
|
|
// from inside one of massinput's inputs (i.e. a child is focused/active)
|
|
activeElement = element.querySelector(':focus, :active');
|
|
|
|
if (!activeElement) {
|
|
return false;
|
|
}
|
|
|
|
// find the according massinput cell thats hosts the element that triggered the submit
|
|
var massInputCell = activeElement.closest(MASS_INPUT_CELL_SELECTOR);
|
|
if (!massInputCell) {
|
|
return false;
|
|
}
|
|
|
|
var submitButton = massInputCell.querySelector('.' + MASS_INPUT_SUBMIT_BUTTON_CLASS);
|
|
if (!submitButton) {
|
|
return false;
|
|
}
|
|
|
|
var isAddCell = massInputCell.matches(MASS_INPUT_ADD_CELL_SELECTOR);
|
|
var submitButtonIsActive = submitButton.matches(':focus, :active');
|
|
// if the cell is not an add cell the active element must at least be the cells submit button
|
|
if (!isAddCell && !submitButtonIsActive) {
|
|
return false;
|
|
}
|
|
|
|
event.preventDefault();
|
|
var requestBody = serializeForm(submitButton, enctype);
|
|
|
|
if (requestFn && requestBody) {
|
|
var headers = {'Mass-Input-Shortcircuit': massInputId};
|
|
|
|
if (enctype !== 'multipart/form-data')
|
|
headers['Content-Type'] = enctype;
|
|
|
|
requestFn({
|
|
url: url,
|
|
headers: headers,
|
|
body: requestBody,
|
|
accept: HttpClient.ACCEPT.TEXT_HTML,
|
|
}).then(function(response) {
|
|
return HtmlHelpers.parseResponse(response);
|
|
}).then(function(response) {
|
|
processResponse(response.element);
|
|
if (isAddCell) {
|
|
reFocusAddCell();
|
|
}
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
function keypressHandler(event) {
|
|
if (event.keyCode !== 13) {
|
|
return false;
|
|
}
|
|
|
|
if (massInputFormSubmitHandler) {
|
|
return massInputFormSubmitHandler(event);
|
|
}
|
|
}
|
|
|
|
function getMassInputSubmitButtons() {
|
|
return Array.from(element.querySelectorAll('button[type="submit"][name][value], .' + MASS_INPUT_SUBMIT_BUTTON_CLASS));
|
|
}
|
|
|
|
function setupSubmitButton(button) {
|
|
button.setAttribute('type', 'button');
|
|
button.classList.add(MASS_INPUT_SUBMIT_BUTTON_CLASS);
|
|
button.addEventListener('click', massInputFormSubmitHandler);
|
|
}
|
|
|
|
function resetSubmitButton(button) {
|
|
button.setAttribute('type', 'submit');
|
|
button.classList.remove(MASS_INPUT_SUBMIT_BUTTON_CLASS);
|
|
button.removeEventListener('click', massInputFormSubmitHandler);
|
|
}
|
|
|
|
function processResponse(responseElement) {
|
|
element.innerHTML = "";
|
|
element.appendChild(responseElement);
|
|
|
|
reset();
|
|
|
|
if (UtilRegistry) {
|
|
UtilRegistry.setupAll(element);
|
|
}
|
|
}
|
|
|
|
function serializeForm(submitButton, enctype) {
|
|
var formData = new FormData(massInputForm);
|
|
|
|
// manually add name and value of submit button to formData
|
|
formData.append(submitButton.name, submitButton.value);
|
|
|
|
if (enctype === 'application/x-www-form-urlencoded') {
|
|
return new URLSearchParams(formData);
|
|
} else if (enctype === 'multipart/form-data') {
|
|
return formData;
|
|
} else {
|
|
throw new Error('Unsupported form enctype: ' + enctype);
|
|
}
|
|
}
|
|
|
|
function reFocusAddCell() {
|
|
var addCell = element.querySelector(MASS_INPUT_ADD_CELL_SELECTOR);
|
|
if (!addCell) {
|
|
return false;
|
|
}
|
|
|
|
var addCellInput = addCell.querySelector('input:not([type="hidden"])');
|
|
if (addCellInput) {
|
|
// Clearing of add-inputs is done in the backend
|
|
addCellInput.focus();
|
|
}
|
|
}
|
|
|
|
function reset() {
|
|
element.classList.remove(MASS_INPUT_INITIALIZED_CLASS);
|
|
massInputForm.removeEventListener('submit', massInputFormSubmitHandler)
|
|
massInputForm.removeEventListener('keypress', keypressHandler);
|
|
|
|
var buttons = getMassInputSubmitButtons();
|
|
buttons.forEach(function(button) {
|
|
resetSubmitButton(button);
|
|
});
|
|
}
|
|
|
|
return init();
|
|
};
|
|
|
|
// register mass input util
|
|
if (UtilRegistry) {
|
|
UtilRegistry.register({
|
|
name: MASS_INPUT_UTIL_NAME,
|
|
selector: MASS_INPUT_UTIL_SELECTOR,
|
|
setup: massInputUtil
|
|
});
|
|
}
|
|
})();
|