feat(datepicker): new approach stub for formatting dates in formdata

This commit is contained in:
Sarah Vaupel 2019-08-27 15:49:31 +02:00
parent 0998d11312
commit 9ea7b2e3f7
6 changed files with 1609 additions and 1335 deletions

View File

@ -72,10 +72,8 @@ export class AsyncForm {
const url = this._element.getAttribute('action'); const url = this._element.getAttribute('action');
const headers = { }; const headers = { };
// format any date values before submission // create new FormData and format any date values
Datepicker.formatAllFormInputDateValues(this._element); const body = Datepicker.unformatAll(this._element, new FormData(this._element));
const body = new FormData(this._element);
const isModal = this._element.closest(MODAL_SELECTOR); const isModal = this._element.closest(MODAL_SELECTOR);
if (isModal) { if (isModal) {

View File

@ -241,7 +241,7 @@ export class AsyncTable {
const url = new URL(getLocalStorageParameter('currentTableUrl') || window.location.href); const url = new URL(getLocalStorageParameter('currentTableUrl') || window.location.href);
// format any date values before submission // format any date values before submission
Datepicker.formatAllFormInputDateValues(tableFilterForm); Datepicker.destroyAllFormInputDates(tableFilterForm);
const formData = new FormData(tableFilterForm); const formData = new FormData(tableFilterForm);
@ -304,10 +304,8 @@ export class AsyncTable {
_changePagesizeHandler = () => { _changePagesizeHandler = () => {
const url = new URL(getLocalStorageParameter('currentTableUrl') || window.location.href); const url = new URL(getLocalStorageParameter('currentTableUrl') || window.location.href);
// format any date values before submission // create new FormData and format any date values
Datepicker.formatAllFormInputDateValues(this._pagesizeForm); const formData = Datepicker.unformatAll(this._pagesizeForm, new FormData(this._pagesizeForm));
const formData = new FormData(this._pagesizeForm);
for (var k of url.searchParams.keys()) { for (var k of url.searchParams.keys()) {
url.searchParams.delete(k); url.searchParams.delete(k);

View File

@ -1,14 +1,32 @@
import datetime from 'tail.datetime'; import datetime from 'tail.datetime';
import dateFormat from 'dateformat';
import { Utility } from '../../core/utility'; import { Utility } from '../../core/utility';
import moment from 'moment';
// formats for displaying all dates and/or times const KEYCODE_ESCAPE = 27;
const FORM_DATE_FORMAT_DATE = 'yyyy-mm-dd';
const FORM_DATE_FORMAT_TIME = 'HH:MM:ss'; // INTERNAL (Uni2work specific) formats for formatting dates and/or times
const FORM_DATE_FORMAT = { const FORM_DATE_FORMAT = {
'date': FORM_DATE_FORMAT_DATE, 'date': moment.HTML5_FMT.DATE,
'time': FORM_DATE_FORMAT_TIME, 'time': moment.HTML5_FMT.TIME_SECONDS,
'datetime-local': `${FORM_DATE_FORMAT_DATE}"T"${FORM_DATE_FORMAT_TIME}`, 'datetime-local': moment.HTML5_FMT.DATETIME_LOCAL_SECONDS,
};
// FANCY (tail.datetime specific) formats for displaying dates and/or times
const FORM_DATE_FORMAT_DATE_DT = 'dd.mm.YYYY';
const FORM_DATE_FORMAT_TIME_DT = 'HH:ii:ss';
// const FORM_DATE_FORMAT_DT = {
// 'date': FORM_DATE_FORMAT_DATE_DT,
// 'time': FORM_DATE_FORMAT_TIME_DT,
// 'datetime-local': `${FORM_DATE_FORMAT_DATE_DT} ${FORM_DATE_FORMAT_TIME_DT}`,
// };
// FANCY (moment specific) formats for displaying dates and/or times
const FORM_DATE_FORMAT_DATE_MOMENT = 'DD.MM.YYYY';
const FORM_DATE_FORMAT_TIME_MOMENT = 'HH:mm:ss';
const FORM_DATE_FORMAT_MOMENT = {
'date': FORM_DATE_FORMAT_DATE_MOMENT,
'time': FORM_DATE_FORMAT_TIME_MOMENT,
'datetime-local': `${FORM_DATE_FORMAT_DATE_MOMENT} ${FORM_DATE_FORMAT_TIME_MOMENT}`,
}; };
const DATEPICKER_UTIL_SELECTOR = 'input[type="date"], input[type="time"], input[type="datetime-local"]'; const DATEPICKER_UTIL_SELECTOR = 'input[type="date"], input[type="time"], input[type="datetime-local"]';
@ -29,7 +47,8 @@ const DATEPICKER_CONFIG = {
// TODO: hardcoded, get from current language / settings // TODO: hardcoded, get from current language / settings
locale: 'de', locale: 'de',
weekStart: 1, weekStart: 1,
dateFormat: 'dd.mm.YYYY', dateFormat: FORM_DATE_FORMAT_DATE_DT,
timeFormat: FORM_DATE_FORMAT_TIME_DT,
// prevent the instance from closing when selecting a date before selecting a time // prevent the instance from closing when selecting a date before selecting a time
stayOpen: true, stayOpen: true,
@ -116,6 +135,15 @@ export class Datepicker {
// mark the form input element as initialized // mark the form input element as initialized
this._element.classList.add(DATEPICKER_INITIALIZED_CLASS); this._element.classList.add(DATEPICKER_INITIALIZED_CLASS);
const changeEvent = () => {
const parsedDate = moment(this._element.value, FORM_DATE_FORMAT_MOMENT[this.elementType]).toDate();
this.datepickerInstance.selectDate(parsedDate);
// reregister change event to prevent event loop
this._element.addEventListener('change', changeEvent, { once: true });
};
// change the selected date in the tail.datetime instance if the value of the input element is changed
this._element.addEventListener('change', changeEvent, { once: true });
// close the instance if something other than the instance was clicked (i.e. if the target is not within the datepicker instance and if any previously clicked calendar view was replaced (is not in the window anymore) because it was clicked). YES, I KNOW // close the instance if something other than the instance was clicked (i.e. if the target is not within the datepicker instance and if any previously clicked calendar view was replaced (is not in the window anymore) because it was clicked). YES, I KNOW
window.addEventListener('click', event => { window.addEventListener('click', event => {
if (!this.datepickerInstance.dt.contains(event.target) && window.document.contains(event.target)) { if (!this.datepickerInstance.dt.contains(event.target) && window.document.contains(event.target)) {
@ -125,47 +153,75 @@ export class Datepicker {
// close the datepicker on escape keydown events // close the datepicker on escape keydown events
this._element.addEventListener('keydown', event => { this._element.addEventListener('keydown', event => {
if (event.keyCode === 27) { if (event.keyCode === KEYCODE_ESCAPE) {
this.datepickerInstance.close(); this.datepickerInstance.close();
} }
}); });
// format the date value of the form input element of this datepicker before form submission // format the date value of the form input element of this datepicker before form submission
this._element.form.addEventListener('submit', () => this.formatElementValue()); this._element.form.addEventListener('submit', () => this.formatElementValue());
// format any existing dates to fancy display format on pageload
this.formatElementValue(true);
} }
destroy() { destroy() {
this.datepickerInstance.destroy(); this.datepickerInstance.remove();
} }
/** /**
* 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 * 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.
*/ */
formatElementValue() { formatElementValue(toFancy) {
if (!this.datepickerInstance.select || !this._element.value) return; // console.log("Hello from formatElementValue with toFancy ", toFancy, " and element value ", this._element.value, " and datepicker instance ", this.datepickerInstance);
this._element.value = dateFormat(this.datepickerInstance.select, FORM_DATE_FORMAT[this.elementType]);
const dp = this.datepickerInstance;
if (this._element.value) {
if (toFancy) {
// console.log(" toFancy");
const d = new Date(this._element.value);
// console.log(" calling selectDate with ", d);
dp.selectDate(d);
} else {
// console.log(" not toFancy");
this._element.value = this.unformat();
// console.log(" new element value is ", this._element.value);
}
}
} }
/** /**
* Calls formatElementValue on all datepicker objects registered for a form. * Returns a datestring in internal format from the current state of the input element value.
* @param {*} form form for which all datepicker date values should be formatted
*/ */
static formatAllFormInputDateValues(form) { unformat() {
if (!Datepicker.datepickerCollections) { return moment(this._element.value, FORM_DATE_FORMAT_MOMENT[this.elementType]).format(FORM_DATE_FORMAT[this.elementType]);
// no datepicker collections yet (i.e. constructor was never called) => do nothing }
return;
} /**
* Takes a Form and a FormData and returns a new FormData with all dates formatted to uni2work date format. This function will not change the value of the date input elements.
// if the form has no id, assign one randomly * @param {*} form Form for which all dates will be formatted in the FormData
if (!form.id) { * @param {*} formData Initial FormData
form.id = `f${Math.floor(Math.random() * 100000)}`; */
static unformatAll(form, formData) {
// only proceed if there are any datepickers and if both form and formData are defined
if (Datepicker.datepickerCollections && form && formData) {
// if the form has no id, assign one randomly
if (!form.id) {
form.id = `f${Math.floor(Math.random() * 100000)}`;
}
const formId = form.id;
if (Datepicker.datepickerCollections.has(formId)) {
const datepickerInstances = Datepicker.datepickerCollections.get(formId);
datepickerInstances.forEach(instance => {
formData.set(instance._element.name, instance.unformat());
});
}
} }
const formID = form.id; // return the (possibly changed) FormData
return formData;
if (Datepicker.datepickerCollections.has(formID)) {
const datepickerInstances = Datepicker.datepickerCollections.get(formID);
datepickerInstances.forEach(instance => instance.formatElementValue());
}
} }
} }

View File

@ -158,10 +158,8 @@ export class MassInput {
} }
_serializeForm(submitButton, enctype) { _serializeForm(submitButton, enctype) {
// format any date values before submission // create new FormData and format any date values
Datepicker.formatAllFormInputDateValues(this._massInputForm); const formData = Datepicker.unformatAll(this._massInputForm, new FormData(this._massInputForm));
const formData = new FormData(this._massInputForm);
// manually add name and value of submit button to formData // manually add name and value of submit button to formData
formData.append(submitButton.name, submitButton.value); formData.append(submitButton.name, submitButton.value);

2775
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -49,16 +49,16 @@
"defaults" "defaults"
], ],
"devDependencies": { "devDependencies": {
"@babel/cli": "^7.4.4", "@babel/cli": "^7.5.5",
"@babel/core": "^7.4.5", "@babel/core": "^7.5.5",
"@babel/plugin-proposal-class-properties": "^7.4.4", "@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/plugin-proposal-decorators": "^7.4.4", "@babel/plugin-proposal-decorators": "^7.4.4",
"@babel/preset-env": "^7.4.5", "@babel/preset-env": "^7.5.5",
"@commitlint/cli": "^8.1.0", "@commitlint/cli": "^8.1.0",
"@commitlint/config-conventional": "^8.0.0", "@commitlint/config-conventional": "^8.1.0",
"autoprefixer": "^9.6.0", "autoprefixer": "^9.6.1",
"babel-core": "^6.26.3", "babel-core": "^6.26.3",
"babel-eslint": "^10.0.1", "babel-eslint": "^10.0.3",
"babel-loader": "^8.0.6", "babel-loader": "^8.0.6",
"babel-plugin-syntax-dynamic-import": "^6.18.0", "babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-transform-decorators-legacy": "^1.3.5", "babel-plugin-transform-decorators-legacy": "^1.3.5",
@ -66,9 +66,9 @@
"css-loader": "^2.1.1", "css-loader": "^2.1.1",
"eslint": "^5.16.0", "eslint": "^5.16.0",
"extract-text-webpack-plugin": "^4.0.0-beta.0", "extract-text-webpack-plugin": "^4.0.0-beta.0",
"husky": "^2.4.1", "husky": "^2.7.0",
"jasmine-core": "^3.4.0", "jasmine-core": "^3.4.0",
"karma": "^4.1.0", "karma": "^4.2.0",
"karma-chrome-launcher": "^2.2.0", "karma-chrome-launcher": "^2.2.0",
"karma-cli": "^2.0.0", "karma-cli": "^2.0.0",
"karma-jasmine": "^2.0.1", "karma-jasmine": "^2.0.1",
@ -81,17 +81,16 @@
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"null-loader": "^2.0.0", "null-loader": "^2.0.0",
"postcss-loader": "^3.0.0", "postcss-loader": "^3.0.0",
"sass-loader": "^7.1.0", "sass-loader": "^7.3.1",
"standard-version": "^6.0.1", "standard-version": "^6.0.1",
"style-loader": "^0.23.1", "style-loader": "^0.23.1",
"uglifyjs-webpack-plugin": "^2.1.3", "uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^4.34.0", "webpack": "^4.39.3",
"webpack-cli": "^3.3.4" "webpack-cli": "^3.3.7"
}, },
"dependencies": { "dependencies": {
"dateformat": "^3.0.3", "moment": "^2.24.0",
"flatpickr": "^4.5.7", "npm": "^6.11.2",
"npm": "^6.10.3", "tail.datetime": "git+https://git@github.com/uni2work/tail.DateTime.git#update-view-on-select"
"tail.datetime": "git+https://git@github.com/uni2work/tail.DateTime.git#master"
} }
} }