feat(async-table): no submit on locked inputs
This commit is contained in:
parent
eeabdb1b2b
commit
22b3780efd
@ -6,6 +6,8 @@ import * as debounce from 'lodash.debounce';
|
||||
import './async-table-filter.sass';
|
||||
import './async-table.sass';
|
||||
|
||||
const ATTR_SUBMIT_LOCKED = 'submit-locked';
|
||||
|
||||
const INPUT_DEBOUNCE = 600;
|
||||
const HEADER_HEIGHT = 80;
|
||||
|
||||
@ -153,21 +155,18 @@ export class AsyncTable {
|
||||
}
|
||||
|
||||
_gatherTableFilterInputs(tableFilterForm) {
|
||||
Array.from(tableFilterForm.querySelectorAll('input[type="search"]')).forEach((input) => {
|
||||
this._tableFilterInputs.search.push(input);
|
||||
Array.from(tableFilterForm.querySelectorAll('input')).forEach((input) => {
|
||||
const inputType = input.getAttribute('type');
|
||||
if (inputType === 'search') {
|
||||
this._tableFilterInputs.search.push(input);
|
||||
} else if (['text','date','time','datetime-local'].includes(inputType)) {
|
||||
this._tableFilterInputs.input.push(input);
|
||||
} else {
|
||||
this._tableFilterInputs.change.push(input);
|
||||
}
|
||||
});
|
||||
|
||||
Array.from(tableFilterForm.querySelectorAll('input[type="text"]')).forEach((input) => {
|
||||
this._tableFilterInputs.input.push(input);
|
||||
});
|
||||
|
||||
Array.from(tableFilterForm.querySelectorAll('input:not([type="text"]):not([type="search"])')).forEach((input) => {
|
||||
this._tableFilterInputs.change.push(input);
|
||||
});
|
||||
|
||||
Array.from(tableFilterForm.querySelectorAll('select')).forEach((input) => {
|
||||
this._tableFilterInputs.select.push(input);
|
||||
});
|
||||
Array.from(tableFilterForm.querySelectorAll('select')).forEach((input) => this._tableFilterInputs.select.push(input));
|
||||
}
|
||||
|
||||
_addTableFilterEventListeners(tableFilterForm) {
|
||||
@ -186,7 +185,8 @@ export class AsyncTable {
|
||||
|
||||
this._tableFilterInputs.input.forEach((input) => {
|
||||
const debouncedInput = debounce(() => {
|
||||
if (input.value.length === 0 || input.value.length > 2) {
|
||||
const submitLocked = input.getAttribute(ATTR_SUBMIT_LOCKED);
|
||||
if ((submitLocked === 'false' || submitLocked === null) && (input.value.length === 0 || input.value.length > 2)) {
|
||||
this._updateFromTableFilter(tableFilterForm);
|
||||
}
|
||||
}, INPUT_DEBOUNCE);
|
||||
|
||||
@ -6,6 +6,10 @@ import moment from 'moment';
|
||||
const KEYCODE_ESCAPE = 27;
|
||||
const Z_INDEX_MODAL = 9999;
|
||||
|
||||
// should be the same as ATTR_SUBMIT_LOCKED in async-table util
|
||||
// TODO move to global config
|
||||
const ATTR_DATEPICKER_OPEN = 'submit-locked';
|
||||
|
||||
// INTERNAL (Uni2work specific) formats for formatting dates and/or times
|
||||
const FORM_DATE_FORMAT = {
|
||||
'date': moment.HTML5_FMT.DATE,
|
||||
@ -26,21 +30,10 @@ const FORM_DATE_FORMAT_MOMENT = {
|
||||
'datetime-local': `${FORM_DATE_FORMAT_DATE_MOMENT} ${FORM_DATE_FORMAT_TIME_MOMENT}`,
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes a string representation of a date, an input ('previous') format and a desired output format and returns a reformatted date string.
|
||||
* If the date string is not valid (i.e. cannot be parsed with the given input format string), returns the original date string;
|
||||
* @param {*} dateStr string representation of a date (needs to be in format formatIn)
|
||||
* @param {*} formatIn input format string
|
||||
* @param {*} formatOut format string of the desired output date string
|
||||
*/
|
||||
function reformatDateString(dateStr, formatIn, formatOut) {
|
||||
const parsedMomentDate = moment(dateStr, [formatIn, formatOut]);
|
||||
return parsedMomentDate.isValid() ? parsedMomentDate.format(formatOut) : dateStr;
|
||||
}
|
||||
|
||||
const DATEPICKER_UTIL_SELECTOR = 'input[type="date"], input[type="time"], input[type="datetime-local"]';
|
||||
|
||||
const DATEPICKER_INITIALIZED_CLASS = 'datepicker--initialized';
|
||||
const DATEPICKER_OPEN_CLASS = 'calendar-open';
|
||||
|
||||
const DATEPICKER_CONFIG = {
|
||||
'global': {
|
||||
@ -163,6 +156,21 @@ export class Datepicker {
|
||||
// mark the form input element as initialized
|
||||
this._element.classList.add(DATEPICKER_INITIALIZED_CLASS);
|
||||
|
||||
// create a mutation observer that observes the datepicker instance class and sets
|
||||
// the datepicker-open DOM attribute of the input element if the datepicker has been opened
|
||||
const datepickerInstanceObserver = new MutationObserver((mutations) => {
|
||||
mutations.forEach(mutation => {
|
||||
if (!mutation.oldValue.includes(DATEPICKER_OPEN_CLASS) && this.datepickerInstance.dt.getAttribute('class').includes(DATEPICKER_OPEN_CLASS)) {
|
||||
this._element.setAttribute(ATTR_DATEPICKER_OPEN, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
datepickerInstanceObserver.observe(this.datepickerInstance.dt, {
|
||||
attributes: true,
|
||||
attributeFilter: ['class'],
|
||||
attributeOldValue: true,
|
||||
});
|
||||
|
||||
const setDatepickerDate = () => {
|
||||
// try to parse the current input element value with fancy and internal format string
|
||||
const parsedMomentDate = moment(this._element.value, FORM_DATE_FORMAT_MOMENT[this.elementType]);
|
||||
@ -188,7 +196,7 @@ export class Datepicker {
|
||||
const focussedIsNotElement = event.relatedTarget !== this._element;
|
||||
const focussedIsInDocument = window.document.contains(event.relatedTarget);
|
||||
if (hasFocus && focussedIsNotTimepicker && focussedIsNotElement && focussedIsInDocument)
|
||||
this.datepickerInstance.close();
|
||||
this.closeDatepickerInstance();
|
||||
});
|
||||
|
||||
// close the instance on click on any element outside of the datepicker (except the input element itself)
|
||||
@ -198,13 +206,13 @@ export class Datepicker {
|
||||
const targetIsInDocument = window.document.contains(event.target);
|
||||
const targetIsNotElement = event.target !== this._element;
|
||||
if (targetIsOutside && targetIsInDocument && targetIsNotElement)
|
||||
this.datepickerInstance.close();
|
||||
this.closeDatepickerInstance();
|
||||
});
|
||||
|
||||
// close the instance on escape keydown events
|
||||
this._element.addEventListener('keydown', event => {
|
||||
if (event.keyCode === KEYCODE_ESCAPE) {
|
||||
this.datepickerInstance.close();
|
||||
this.closeDatepickerInstance();
|
||||
}
|
||||
});
|
||||
|
||||
@ -216,6 +224,24 @@ export class Datepicker {
|
||||
this.datepickerInstance.remove();
|
||||
}
|
||||
|
||||
|
||||
// DATEPICKER INSTANCE CONTROL
|
||||
|
||||
/**
|
||||
* Closes the datepicker instance, releasing the lock on the input element.
|
||||
*/
|
||||
closeDatepickerInstance() {
|
||||
if (!this._element.datepicker-open) {
|
||||
throw new Error('Cannot close already closed datepicker instance!');
|
||||
}
|
||||
|
||||
this._element.setAttribute(ATTR_DATEPICKER_OPEN, false);
|
||||
this.datepickerInstance.close();
|
||||
}
|
||||
|
||||
|
||||
// FORMAT METHODS
|
||||
|
||||
/**
|
||||
* Formats the value of this input element from datepicker format (i.e. DATEPICKER_CONFIG.dateFormat + " " + datetime.defaults.timeFormat) to Uni2work internal date format (i.e. FORM_DATE_FORMAT) required for form submission
|
||||
* @param {*} toFancy optional target format switch (boolean value; default is false). If set to a truthy value, formats the element value to fancy instead of internal date format.
|
||||
@ -226,8 +252,6 @@ export class Datepicker {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns a datestring in internal format from the current state of the input element value.
|
||||
* @param {*} toFancy Format date from internal to fancy or vice versa. When omitted, toFancy is falsy and results in fancy -> internal
|
||||
@ -265,3 +289,18 @@ export class Datepicker {
|
||||
return formData;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// HELPER FUNCTIONS
|
||||
|
||||
/**
|
||||
* Takes a string representation of a date, an input ('previous') format and a desired output format and returns a reformatted date string.
|
||||
* If the date string is not valid (i.e. cannot be parsed with the given input format string), returns the original date string;
|
||||
* @param {*} dateStr string representation of a date (needs to be in format formatIn)
|
||||
* @param {*} formatIn input format string
|
||||
* @param {*} formatOut format string of the desired output date string
|
||||
*/
|
||||
function reformatDateString(dateStr, formatIn, formatOut) {
|
||||
const parsedMomentDate = moment(dateStr, [formatIn, formatOut]);
|
||||
return parsedMomentDate.isValid() ? parsedMomentDate.format(formatOut) : dateStr;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user