feat(mass-input): automatic add before submit

This commit is contained in:
Gregor Kleen 2020-04-15 16:32:45 +02:00
parent 7018196bc7
commit 7540a4fe5f
2 changed files with 103 additions and 23 deletions

View File

@ -1,3 +1,5 @@
/* global global:writable */
import { Utility } from '../../core/utility'; import { Utility } from '../../core/utility';
import { Datepicker } from '../form/datepicker'; import { Datepicker } from '../form/datepicker';
import './mass-input.sass'; import './mass-input.sass';
@ -7,6 +9,11 @@ const MASS_INPUT_ADD_CELL_SELECTOR = '.massinput__cell--add';
const MASS_INPUT_SUBMIT_BUTTON_CLASS = 'massinput__submit-button'; const MASS_INPUT_SUBMIT_BUTTON_CLASS = 'massinput__submit-button';
const MASS_INPUT_INITIALIZED_CLASS = 'mass-input--initialized'; const MASS_INPUT_INITIALIZED_CLASS = 'mass-input--initialized';
const MASS_INPUT_ADD_CHANGE_FIELD_SELECTOR = 'select, input[type=radio]';
// const MASS_INPUT_SAFETY_SUBMITTED_CLASS = 'massinput--safety-submitted';
// const MASS_INPUT_SAFETY_SUBMITTED_TIMEOUT = 1000;
@Utility({ @Utility({
selector: '[uw-mass-input]', selector: '[uw-mass-input]',
}) })
@ -14,11 +21,14 @@ export class MassInput {
_element; _element;
_app; _app;
_global;
_massInputId; _massInputId;
_massInputFormSubmitHandler; _massInputFormSubmitHandler;
_massInputForm; _massInputForm;
_changedAdd = new Array();
constructor(element, app) { constructor(element, app) {
if (!element) { if (!element) {
throw new Error('Mass Input utility cannot be setup without an element!'); throw new Error('Mass Input utility cannot be setup without an element!');
@ -27,6 +37,14 @@ export class MassInput {
this._element = element; this._element = element;
this._app = app; this._app = app;
if (global !== undefined)
this._global = global;
else if (window !== undefined)
this._global = window;
else
throw new Error('Cannot setup Mass Input utility without window or global');
if (this._element.classList.contains(MASS_INPUT_INITIALIZED_CLASS)) { if (this._element.classList.contains(MASS_INPUT_INITIALIZED_CLASS)) {
return false; return false;
} }
@ -47,8 +65,10 @@ export class MassInput {
this._setupSubmitButton(button); this._setupSubmitButton(button);
}); });
this._massInputForm.addEventListener('submit', this._massInputFormSubmitHandler); this._massInputForm.addEventListener('submit', this._massInputFormSubmitHandler.bind(this));
this._massInputForm.addEventListener('keypress', this._keypressHandler); this._massInputForm.addEventListener('keypress', this._keypressHandler.bind(this));
Array.from(this._element.querySelectorAll(MASS_INPUT_ADD_CELL_SELECTOR)).forEach(this._setupChangedHandlers.bind(this));
// mark initialized // mark initialized
this._element.classList.add(MASS_INPUT_INITIALIZED_CLASS); this._element.classList.add(MASS_INPUT_INITIALIZED_CLASS);
@ -58,6 +78,26 @@ export class MassInput {
this._reset(); this._reset();
} }
_setupChangedHandlers(addCell) {
Array.from(addCell.querySelectorAll(MASS_INPUT_ADD_CHANGE_FIELD_SELECTOR)).forEach(inputElem => {
if (inputElem.closest('[uw-mass-input]') !== this._element)
return;
inputElem.addEventListener('change', () => { this._changedAdd.push(addCell); });
});
}
_unsafeAddCells() {
let changedAdd = this._changedAdd;
Array.from(this._element.querySelectorAll(MASS_INPUT_ADD_CELL_SELECTOR)).forEach(addCell => addCell.querySelectorAll('input:not([type=checkbox]):not([type=radio])').forEach(inputElem => {
if (inputElem.closest('[uw-mass-input]') === this._element && inputElem.value !== '')
changedAdd.push(addCell);
}));
return changedAdd;
}
_makeSubmitHandler() { _makeSubmitHandler() {
const method = this._massInputForm.getAttribute('method') || 'POST'; const method = this._massInputForm.getAttribute('method') || 'POST';
const url = this._massInputForm.getAttribute('action') || window.location.href; const url = this._massInputForm.getAttribute('action') || window.location.href;
@ -69,31 +109,58 @@ export class MassInput {
} }
return (event) => { return (event) => {
let activeElement; let submitButton;
let isAddCell;
// check if event occured from either a mass input add/delete button or let isMassInputSubmit = (() => {
// from inside one of massinput's inputs (i.e. a child is focused/active) let activeElement;
activeElement = this._element.querySelector(':focus, :active');
if (!activeElement) { // check if event occured from either a mass input add/delete button or
return false; // from inside one of massinput's inputs (i.e. a child is focused/active)
activeElement = this._element.querySelector(':focus, :active');
if (!activeElement) {
return false;
}
// find the according massinput cell thats hosts the element that triggered the submit
const massInputCell = activeElement.closest(MASS_INPUT_CELL_SELECTOR);
if (!massInputCell) {
return false;
}
submitButton = massInputCell.querySelector('.' + MASS_INPUT_SUBMIT_BUTTON_CLASS);
if (!submitButton) {
return false;
}
isAddCell = massInputCell.matches(MASS_INPUT_ADD_CELL_SELECTOR);
const 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;
}
return true;
})();
let unsafeAddCells = this._unsafeAddCells();
if (unsafeAddCells.length > 0 && !isMassInputSubmit) {
let addButtons = Array.from(unsafeAddCells[0].querySelectorAll('.' + MASS_INPUT_SUBMIT_BUTTON_CLASS)).filter(addButton => addButton.closest('[uw-mass-input]') === this._element);
if (addButtons.length > 0) {
submitButton = addButtons[0];
isMassInputSubmit = true;
isAddCell = false;
this._element.scrollIntoView();
// this._element.classList.add(MASS_INPUT_SAFETY_SUBMITTED_CLASS);
// this._global.setTimeout(() => { this._element.classList.remove(MASS_INPUT_SAFETY_SUBMITTED_CLASS) }, MASS_INPUT_SAFETY_SUBMITTED_TIMEOUT)
}
} }
// find the according massinput cell thats hosts the element that triggered the submit if (!isMassInputSubmit) {
const massInputCell = activeElement.closest(MASS_INPUT_CELL_SELECTOR);
if (!massInputCell) {
return false;
}
const submitButton = massInputCell.querySelector('.' + MASS_INPUT_SUBMIT_BUTTON_CLASS);
if (!submitButton) {
return false;
}
const isAddCell = massInputCell.matches(MASS_INPUT_ADD_CELL_SELECTOR);
const 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; return false;
} }

View File

@ -1,3 +1,5 @@
@use "../../app" as *
.massinput-list__wrapper, .massinput-list__cell .massinput-list__wrapper, .massinput-list__cell
display: grid display: grid
grid: auto / auto 50px grid: auto / auto 50px
@ -12,3 +14,14 @@
.massinput-list__cell .massinput-list__cell
grid-column: 1 / 3 grid-column: 1 / 3
/* .massinput--safety-submitted
/* animation: massinput--safety-submitted linear 1s
/* @keyframes massinput--safety-submitted
/* 0%
/* background-color: rgba(252, 153, 0, 0)
/* 50%
/* background-color: rgba(252, 153, 0, 0.8)
/* 100%
/* background-color: rgba(252, 153, 0, 0)