From 544ddf3747ef55d9171274f48d8ace444ce87b78 Mon Sep 17 00:00:00 2001 From: Andreas Fernandez <a.fernandez@scripting-base.de> Date: Thu, 10 Nov 2022 16:38:03 +0100 Subject: [PATCH] [BUGFIX] Simplify some FormEngine validations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch simplifies some JavaScript-side validations in FormEngine. Most notably, parsing dates and times is now handled by moment.js (which will be replaced by luxon in the future), allowing us to remove decades-old mambo-jambo code nobody can reverse-engineer nowadays. In the same run, `ltrim()` and the unused `btrim()` methods are removed in favor of modern JavaScript functions. Previously, it was possible to supply the invalid date "13-13-2016" which was magically fixed to "13-01-2017". However, this was only possible by setting the value and triggering the `change` event via JavaScript and NOT by using the backend as a sane user. The behavior introduced with this patch is now streamlined to behave like using the datepicker or entering the field in the input field. Resolves: #99058 Releases: main Change-Id: I98af867ee3bda91222d21bcee1bc1f4c92e41d7e Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/76544 Tested-by: core-ci <typo3@b13.com> Tested-by: Roman Büchler <info@buechler.pro> Tested-by: Nikita Hovratov <nikita.h@live.de> Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de> Reviewed-by: Roman Büchler <info@buechler.pro> Reviewed-by: Nikita Hovratov <nikita.h@live.de> Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de> --- .../backend/form-engine-validation.ts | 176 +----------------- .../tests/form-engine-validation-test.ts | 45 ----- .../JavaScript/form-engine-validation.js | 2 +- .../JavaScript/form-engine-validation-test.js | 2 +- .../FormEngine/ElementsBasicInputDateCest.php | 8 - 5 files changed, 12 insertions(+), 221 deletions(-) diff --git a/Build/Sources/TypeScript/backend/form-engine-validation.ts b/Build/Sources/TypeScript/backend/form-engine-validation.ts index 045ca4c02706..f55360e79e4e 100644 --- a/Build/Sources/TypeScript/backend/form-engine-validation.ts +++ b/Build/Sources/TypeScript/backend/form-engine-validation.ts @@ -266,7 +266,7 @@ export default (function() { let maxItems: number; if (!$.isArray(value)) { - value = FormEngineValidation.ltrim(value); + value = value.trimStart(); } $.each(rules, function(k: number, rule: any): void|boolean { @@ -603,7 +603,7 @@ export default (function() { * @param {String} string * @returns {Array} */ - FormEngineValidation.trimExplode = function(delimiter: string, string: string): Array<string> { + FormEngineValidation.trimExplode = function(delimiter: string, string: string): string[] { const result = []; const items = string.split(delimiter); for (let i = 0; i < items.length; i++) { @@ -663,34 +663,6 @@ export default (function() { return theVal; }; - /** - * Trims leading whitespace characters - * - * @param {String} value - * @returns {String} - */ - FormEngineValidation.ltrim = function(value: string): string { - const theVal = '' + value; - if (!value) { - return ''; - } - return theVal.replace(/^\s+/, ''); - }; - - /** - * Trims trailing whitespace characters - * - * @param {String} value - * @returns {String} - */ - FormEngineValidation.btrim = function(value: string): string { - const theVal = '' + value; - if (!value) { - return ''; - } - return theVal.replace(/\s+$/, ''); - }; - /** * Parse datetime value * @@ -716,21 +688,7 @@ export default (function() { * @returns {*} */ FormEngineValidation.parseDate = function(value: string): number { - const today = new Date(); - let values = FormEngineValidation.split(value); - - if (values.values[1] && values.values[1].length > 2) { - const temp = values.values[1]; - values = FormEngineValidation.splitSingle(temp); - } - - const year = (values.values[3]) ? FormEngineValidation.parseInt(values.values[3]) : FormEngineValidation.getYear(today); - const month = (values.values[2]) ? FormEngineValidation.parseInt(values.values[2]) : today.getUTCMonth() + 1; - const day = (values.values[1]) ? FormEngineValidation.parseInt(values.values[1]) : today.getUTCDate(); - const theTime = moment.utc(); - // eslint-disable-next-line radix - theTime.year(parseInt(year)).month(parseInt(month) - 1).date(parseInt(day)).hour(0).minute(0).second(0); - FormEngineValidation.lastDate = theTime.unix(); + FormEngineValidation.lastDate = moment.utc(value, 'DD-MM-YYYY').unix(); return FormEngineValidation.lastDate; }; @@ -743,21 +701,8 @@ export default (function() { * @returns {*} */ FormEngineValidation.parseTime = function(value: string, type: string): number { - const today = new Date(); - let values = FormEngineValidation.split(value); - - if (values.values[1] && values.values[1].length > 2) { - const temp = values.values[1]; - values = FormEngineValidation.splitSingle(temp); - } - - const sec = (values.values[3]) ? FormEngineValidation.parseInt(values.values[3]) : today.getUTCSeconds(); - const min = (values.values[2]) ? FormEngineValidation.parseInt(values.values[2]) : today.getUTCMinutes(); - const hour = (values.values[1]) ? FormEngineValidation.parseInt(values.values[1]) : today.getUTCHours(); - const theTime = moment.utc(); - theTime.year(1970).month(0).date(1).hour(hour).minute(min).second(type === 'timesec' ? sec : 0); - - FormEngineValidation.lastTime = theTime.unix(); + const format = type === 'timesec' ? 'hh:mm:ss' : 'hh:mm'; + FormEngineValidation.lastTime = moment.utc(value, format).year(1970).month(0).date(1).unix(); if (FormEngineValidation.lastTime < 0) { FormEngineValidation.lastTime += 24 * 60 * 60; } @@ -771,10 +716,12 @@ export default (function() { * @returns {*} */ FormEngineValidation.parseYear = function(value: string): number { - const today = new Date(); - const values = FormEngineValidation.split(value); + let year = parseInt(value, 10); + if (isNaN(year)) { + year = FormEngineValidation.getYear(new Date()); + } - FormEngineValidation.lastYear = (values.values[1]) ? FormEngineValidation.parseInt(values.values[1]) : FormEngineValidation.getYear(today); + FormEngineValidation.lastYear = year; return FormEngineValidation.lastYear; }; @@ -814,25 +761,6 @@ export default (function() { return eval(((foreign == '-') ? '-' : '') + value); }; - /** - * Substract timezone offset from client to a timestamp to get UTC-timestamp to be send to server - * - * @param {Number} timestamp - * @param {Number} timeonly - * @returns {*} - */ - FormEngineValidation.convertClientTimestampToUTC = function(timestamp: number, timeonly: number): number { - const timeObj = new Date(timestamp * 1000); - timeObj.setTime((timestamp - timeObj.getTimezoneOffset() * 60) * 1000); - if (timeonly) { - // only seconds since midnight - return FormEngineValidation.getTime(timeObj); - } else { - // seconds since the "unix-epoch" - return FormEngineValidation.getTimestamp(timeObj); - } - }; - /** * Parse date string or object and return unix timestamp * @@ -893,90 +821,6 @@ export default (function() { }); }; - /** - * - * @param value - * @returns {{values: Array, pointer: number}} - */ - FormEngineValidation.splitSingle = function(value: string): {values: Array<string>, pointer: number} { - const theVal = '' + value; - const result = { - values: <Array<string>>[], - pointer: 3 - }; - result.values[1] = theVal.substr(0, 2); - result.values[2] = theVal.substr(2, 2); - result.values[3] = theVal.substr(4, 10); - return result; - }; - - /** - * - * @param theStr1 - * @param delim - * @param index - * @returns {*} - */ - FormEngineValidation.splitStr = function(theStr1: string, delim: string, index: number): string { - const theStr = '' + theStr1; - const lengthOfDelim = delim.length; - let sPos = -lengthOfDelim; - if (index < 1) { - index = 1; - } - for (let a = 1; a < index; a++) { - sPos = theStr.indexOf(delim, sPos + lengthOfDelim); - if (sPos == -1) { - return null; - } - } - let ePos = theStr.indexOf(delim, sPos + lengthOfDelim); - if (ePos == -1) { - ePos = theStr.length; - } - return (theStr.substring(sPos + lengthOfDelim, ePos)); - }; - - /** - * - * @param value - * @returns {{values: Array, valPol: Array, pointer: number, numberMode: number, theVal: string}} - */ - FormEngineValidation.split = function(value: string): { - values: Array<string>, - valPol: Array<string>, - pointer: number, - numberMode: number, - theVal: string - } { - const result = { - values: <Array<string>>[], - valPol: <Array<string>>[], - pointer: 0, - numberMode: 0, - theVal: '' - }; - value += ' '; - for (let a = 0; a < value.length; a++) { - const theChar = value.substr(a, 1); - if (theChar < '0' || theChar > '9') { - if (result.numberMode) { - result.pointer++; - result.values[result.pointer] = result.theVal; - result.theVal = ''; - result.numberMode = 0; - } - if (theChar == '+' || theChar == '-') { - result.valPol[result.pointer + 1] = theChar; - } - } else { - result.theVal += theChar; - result.numberMode = 1; - } - } - return result; - }; - FormEngineValidation.registerSubmitCallback = function () { DocumentSaveActions.getInstance().addPreSubmitCallback(function (e: Event) { if ($('.' + FormEngineValidation.errorClass).length > 0) { diff --git a/Build/Sources/TypeScript/backend/tests/form-engine-validation-test.ts b/Build/Sources/TypeScript/backend/tests/form-engine-validation-test.ts index 840a3697a111..5e0491ea304e 100644 --- a/Build/Sources/TypeScript/backend/tests/form-engine-validation-test.ts +++ b/Build/Sources/TypeScript/backend/tests/form-engine-validation-test.ts @@ -268,28 +268,6 @@ describe('TYPO3/CMS/Backend/FormEngineValidationTest:', () => { }); }); - /** - * @test - */ - describe('tests for btrim', () => { - const result = FormEngineValidation.btrim(' test '); - - it('works for string with whitespace in begin and end', () => { - expect(result).toBe(' test'); - }); - }); - - /** - * @test - */ - describe('tests for ltrim', () => { - const result = FormEngineValidation.ltrim(' test '); - - it('works for string with whitespace in begin and end', () => { - expect(result).toBe('test '); - }); - }); - /** * @test */ @@ -353,27 +331,4 @@ describe('TYPO3/CMS/Backend/FormEngineValidationTest:', () => { expect(FormEngineValidation.getDate(baseTime)).toBe(1382479200); }) }); - - /** - * @test - */ - describe('tests for splitStr', () => { - it('works for command and index', () => { - expect(FormEngineValidation.splitStr('foo,bar,baz', ',', -1)).toBe('foo'); - expect(FormEngineValidation.splitStr('foo,bar,baz', ',', 0)).toBe('foo'); - expect(FormEngineValidation.splitStr('foo,bar,baz', ',', 1)).toBe('foo'); - expect(FormEngineValidation.splitStr('foo,bar,baz', ',', 2)).toBe('bar'); - expect(FormEngineValidation.splitStr('foo,bar,baz', ',', 3)).toBe('baz'); - expect(FormEngineValidation.splitStr(' foo , bar , baz ', ',', 1)).toBe(' foo '); - expect(FormEngineValidation.splitStr(' foo , bar , baz ', ',', 2)).toBe(' bar '); - expect(FormEngineValidation.splitStr(' foo , bar , baz ', ',', 3)).toBe(' baz '); - }); - }); - - /** - * @test - */ - xdescribe('tests for split', () => { - /* tslint:disable:no-empty */ - }); }); diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/form-engine-validation.js b/typo3/sysext/backend/Resources/Public/JavaScript/form-engine-validation.js index bd80d9853a4a..a59414ccc153 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/form-engine-validation.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/form-engine-validation.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -import $ from"jquery";import moment from"moment";import Md5 from"@typo3/backend/hashing/md5.js";import DocumentSaveActions from"@typo3/backend/document-save-actions.js";import Modal from"@typo3/backend/modal.js";import Severity from"@typo3/backend/severity.js";export default(function(){const FormEngineValidation={rulesSelector:"[data-formengine-validation-rules]",inputSelector:"[data-formengine-input-params]",markerSelector:".t3js-formengine-validation-marker",groupFieldHiddenElement:".t3js-formengine-field-group input[type=hidden]",relatedFieldSelector:"[data-relatedfieldname]",errorClass:"has-error",lastYear:0,lastDate:0,lastTime:0,passwordDummy:"********"},customEvaluations=new Map;return FormEngineValidation.initialize=function(){$(document).find("."+FormEngineValidation.errorClass).removeClass(FormEngineValidation.errorClass),FormEngineValidation.initializeInputFields().promise().done((function(){$(document).on("change",FormEngineValidation.rulesSelector,(e=>{FormEngineValidation.validateField(e.currentTarget),FormEngineValidation.markFieldAsChanged(e.currentTarget)})),FormEngineValidation.registerSubmitCallback()}));const e=new Date;FormEngineValidation.lastYear=FormEngineValidation.getYear(e),FormEngineValidation.lastDate=FormEngineValidation.getDate(e),FormEngineValidation.lastTime=0,FormEngineValidation.validate()},FormEngineValidation.initializeInputFields=function(){return $(document).find(FormEngineValidation.inputSelector).each((function(e,n){const t=$(n).data("formengine-input-params"),a=t.field,i=$('[name="'+a+'"]');void 0===i.data("main-field")&&(i.data("main-field",a),i.data("config",t),FormEngineValidation.initializeInputField(a))}))},FormEngineValidation.initializeInputField=function(e){const n=$('[name="'+e+'"]'),t=$('[data-formengine-input-name="'+e+'"]');let a=$('[name="'+n.data("main-field")+'"]');0===a.length&&(a=n);const i=a.data("config");if(void 0!==i){const e=FormEngineValidation.trimExplode(",",i.evalList);let a=n.val();for(let n=0;n<e.length;n++)a=FormEngineValidation.formatValue(e[n],a,i);a.length&&t.val(a)}t.data("main-field",e),t.data("config",i),t.on("change",(function(){FormEngineValidation.updateInputField(t.attr("data-formengine-input-name"))})),t.attr("data-formengine-input-initialized","true")},FormEngineValidation.registerCustomEvaluation=function(e,n){customEvaluations.has(e)||customEvaluations.set(e,n)},FormEngineValidation.formatValue=function(e,n,t){let a,i,o="";switch(e){case"date":if(n.toString().indexOf("-")>0){o=moment.utc(n).format("DD-MM-YYYY")}else{if(a=1*n,!a)return"";i=new Date(1e3*a);o=i.getUTCDate().toString(10).padStart(2,"0")+"-"+(i.getUTCMonth()+1).toString(10).padStart(2,"0")+"-"+this.getYear(i)}break;case"datetime":if(n.toString().indexOf("-")<=0&&!("number"==typeof n?n:parseInt(n)))return"";o=FormEngineValidation.formatValue("time",n,t)+" "+FormEngineValidation.formatValue("date",n,t);break;case"time":case"timesec":let r;if(n.toString().indexOf("-")>0)r=moment.utc(n);else{if(a="number"==typeof n?n:parseInt(n),!a&&"0"!==n.toString())return"";r=moment.unix(a).utc()}o="timesec"===e?r.format("HH:mm:ss"):r.format("HH:mm");break;case"password":o=n?FormEngineValidation.passwordDummy:"";break;default:o=n}return o},FormEngineValidation.updateInputField=function(e){const n=$('[name="'+e+'"]');let t=$('[name="'+n.data("main-field")+'"]');0===t.length&&(t=n);const a=$('[data-formengine-input-name="'+t.attr("name")+'"]'),i=t.data("config");if(void 0!==i){const e=FormEngineValidation.trimExplode(",",i.evalList);let n=a.val();for(let t=0;t<e.length;t++)n=FormEngineValidation.processValue(e[t],n,i);let o=n;for(let n=0;n<e.length;n++)o=FormEngineValidation.formatValue(e[n],o,i);t.val(n),t.get(0).dispatchEvent(new Event("change")),a.val(o)}},FormEngineValidation.validateField=function(e,n){const t=e instanceof $?e.get(0):e;if(n=n||t.value||"",void 0===t.dataset.formengineValidationRules)return n;const a=JSON.parse(t.dataset.formengineValidationRules);let i,o,r,l=!1,s=0,m=n;$.isArray(n)||(n=FormEngineValidation.ltrim(n)),$.each(a,(function(e,a){if(l)return!1;switch(a.type){case"required":""===n&&(l=!0,t.closest(FormEngineValidation.markerSelector).classList.add(FormEngineValidation.errorClass));break;case"range":if(""!==n){if((a.minItems||a.maxItems)&&(i=$(document).find('[name="'+t.dataset.relatedfieldname+'"]'),s=i.length?FormEngineValidation.trimExplode(",",i.val()).length:t.value,void 0!==a.minItems&&(o=1*a.minItems,!isNaN(o)&&s<o&&(l=!0)),void 0!==a.maxItems&&(r=1*a.maxItems,!isNaN(r)&&s>r&&(l=!0))),void 0!==a.lower){const e=1*a.lower;!isNaN(e)&&n<e&&(l=!0)}if(void 0!==a.upper){const e=1*a.upper;!isNaN(e)&&n>e&&(l=!0)}}break;case"select":case"category":(a.minItems||a.maxItems)&&(i=$(document).find('[name="'+t.dataset.relatedfieldname+'"]'),s=i.length?FormEngineValidation.trimExplode(",",i.val()).length:t instanceof HTMLSelectElement?t.querySelectorAll("option:checked").length:t.querySelectorAll("input[value]:checked").length,void 0!==a.minItems&&(o=1*a.minItems,!isNaN(o)&&s<o&&(l=!0)),void 0!==a.maxItems&&(r=1*a.maxItems,!isNaN(r)&&s>r&&(l=!0)));break;case"group":case"inline":(a.minItems||a.maxItems)&&(s=FormEngineValidation.trimExplode(",",t.value).length,void 0!==a.minItems&&(o=1*a.minItems,!isNaN(o)&&s<o&&(l=!0)),void 0!==a.maxItems&&(r=1*a.maxItems,!isNaN(r)&&s>r&&(l=!0)));break;case"min":(t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement)&&t.value.length>0&&t.value.length<t.minLength&&(l=!0)}}));const d=!l,g=t.closest(FormEngineValidation.markerSelector);return null!==g&&g.classList.toggle(FormEngineValidation.errorClass,!d),FormEngineValidation.markParentTab($(t),d),$(document).trigger("t3-formengine-postfieldvalidation"),m},FormEngineValidation.processValue=function(e,n,t){let a="",i="",o="",r=0,l=n;switch(e){case"alpha":case"num":case"alphanum":case"alphanum_x":for(a="",r=0;r<n.length;r++){const t=n.substr(r,1);let i="_"===t||"-"===t,o=t>="a"&&t<="z"||t>="A"&&t<="Z",l=t>="0"&&t<="9";switch(e){case"alphanum":i=!1;break;case"alpha":l=!1,i=!1;break;case"num":o=!1,i=!1}(o||l||i)&&(a+=t)}a!==n&&(l=a);break;case"is_in":if(t.is_in){i=""+n,t.is_in=t.is_in.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&");const e=new RegExp("[^"+t.is_in+"]+","g");a=i.replace(e,"")}else a=i;l=a;break;case"nospace":l=(""+n).replace(/ /g,"");break;case"md5":""!==n&&(l=Md5.hash(n));break;case"upper":l=n.toUpperCase();break;case"lower":l=n.toLowerCase();break;case"integer":""!==n&&(l=FormEngineValidation.parseInt(n));break;case"decimal":""!==n&&(l=FormEngineValidation.parseDouble(n));break;case"trim":l=String(n).trim();break;case"datetime":""!==n&&(o=n.substr(0,1),l=FormEngineValidation.parseDateTime(n));break;case"date":""!==n&&(o=n.substr(0,1),l=FormEngineValidation.parseDate(n));break;case"time":case"timesec":""!==n&&(o=n.substr(0,1),l=FormEngineValidation.parseTime(n,e));break;case"year":""!==n&&(o=n.substr(0,1),l=FormEngineValidation.parseYear(n));break;case"null":case"password":break;default:customEvaluations.has(e)?l=customEvaluations.get(e).call(null,n):"object"==typeof TBE_EDITOR&&void 0!==TBE_EDITOR.customEvalFunctions&&"function"==typeof TBE_EDITOR.customEvalFunctions[e]&&(l=TBE_EDITOR.customEvalFunctions[e](n))}return l},FormEngineValidation.validate=function(e){(void 0===e||e instanceof Document)&&$(document).find(FormEngineValidation.markerSelector+", .t3js-tabmenu-item").removeClass(FormEngineValidation.errorClass).removeClass("has-validation-error");const n=e||document;$(n).find(FormEngineValidation.rulesSelector).each(((e,n)=>{const t=$(n);if(!t.closest(".t3js-flex-section-deleted, .t3js-inline-record-deleted, .t3js-file-reference-deleted").length){let e=!1;const n=t.val(),a=FormEngineValidation.validateField(t,n);if($.isArray(a)&&$.isArray(n)){if(a.length!==n.length)e=!0;else for(let t=0;t<a.length;t++)if(a[t]!==n[t]){e=!0;break}}else a.length&&n!==a&&(e=!0);e&&t.val(a)}}))},FormEngineValidation.markFieldAsChanged=function(e){if(e instanceof $&&(e=e.get(0)),!(e instanceof HTMLElement))return;const n=e.closest(".t3js-formengine-palette-field");null!==n&&n.classList.add("has-change")},FormEngineValidation.trimExplode=function(e,n){const t=[],a=n.split(e);for(let e=0;e<a.length;e++){const n=a[e].trim();n.length>0&&t.push(n)}return t},FormEngineValidation.parseInt=function(e){let n;return e?(n=parseInt(""+e,10),isNaN(n)?0:n):0},FormEngineValidation.parseDouble=function(e,n=2){let t=""+e;t=t.replace(/[^0-9,\.-]/g,"");const a="-"===t.substring(0,1);t=t.replace(/-/g,""),t=t.replace(/,/g,"."),-1===t.indexOf(".")&&(t+=".0");const i=t.split("."),o=i.pop();let r=Number(i.join("")+"."+o);return a&&(r*=-1),t=r.toFixed(n),t},FormEngineValidation.ltrim=function(e){return e?(""+e).replace(/^\s+/,""):""},FormEngineValidation.btrim=function(e){return e?(""+e).replace(/\s+$/,""):""},FormEngineValidation.parseDateTime=function(e){const n=e.indexOf(" ");if(-1!==n){const t=FormEngineValidation.parseDate(e.substr(n,e.length));FormEngineValidation.lastTime=t+FormEngineValidation.parseTime(e.substr(0,n),"time")}else FormEngineValidation.lastTime=FormEngineValidation.parseDate(e);return FormEngineValidation.lastTime},FormEngineValidation.parseDate=function(e){const n=new Date;let t=FormEngineValidation.split(e);if(t.values[1]&&t.values[1].length>2){const e=t.values[1];t=FormEngineValidation.splitSingle(e)}const a=t.values[3]?FormEngineValidation.parseInt(t.values[3]):FormEngineValidation.getYear(n),i=t.values[2]?FormEngineValidation.parseInt(t.values[2]):n.getUTCMonth()+1,o=t.values[1]?FormEngineValidation.parseInt(t.values[1]):n.getUTCDate(),r=moment.utc();return r.year(parseInt(a)).month(parseInt(i)-1).date(parseInt(o)).hour(0).minute(0).second(0),FormEngineValidation.lastDate=r.unix(),FormEngineValidation.lastDate},FormEngineValidation.parseTime=function(e,n){const t=new Date;let a=FormEngineValidation.split(e);if(a.values[1]&&a.values[1].length>2){const e=a.values[1];a=FormEngineValidation.splitSingle(e)}const i=a.values[3]?FormEngineValidation.parseInt(a.values[3]):t.getUTCSeconds(),o=a.values[2]?FormEngineValidation.parseInt(a.values[2]):t.getUTCMinutes(),r=a.values[1]?FormEngineValidation.parseInt(a.values[1]):t.getUTCHours(),l=moment.utc();return l.year(1970).month(0).date(1).hour(r).minute(o).second("timesec"===n?i:0),FormEngineValidation.lastTime=l.unix(),FormEngineValidation.lastTime<0&&(FormEngineValidation.lastTime+=86400),FormEngineValidation.lastTime},FormEngineValidation.parseYear=function(e){const n=new Date,t=FormEngineValidation.split(e);return FormEngineValidation.lastYear=t.values[1]?FormEngineValidation.parseInt(t.values[1]):FormEngineValidation.getYear(n),FormEngineValidation.lastYear},FormEngineValidation.getYear=function(e){return null===e?null:e.getUTCFullYear()},FormEngineValidation.getDate=function(e){const n=new Date(FormEngineValidation.getYear(e),e.getUTCMonth(),e.getUTCDate());return FormEngineValidation.getTimestamp(n)},FormEngineValidation.pol=function(foreign,value){return eval(("-"==foreign?"-":"")+value)},FormEngineValidation.convertClientTimestampToUTC=function(e,n){const t=new Date(1e3*e);return t.setTime(1e3*(e-60*t.getTimezoneOffset())),n?FormEngineValidation.getTime(t):FormEngineValidation.getTimestamp(t)},FormEngineValidation.getTimestamp=function(e){return Date.parse(e instanceof Date?e.toISOString():e)/1e3},FormEngineValidation.getTime=function(e){return 60*e.getUTCHours()*60+60*e.getUTCMinutes()+FormEngineValidation.getSecs(e)},FormEngineValidation.getSecs=function(e){return e.getUTCSeconds()},FormEngineValidation.getTimeSecs=function(e){return 60*e.getHours()*60+60*e.getMinutes()+e.getSeconds()},FormEngineValidation.markParentTab=function(e,n){e.parents(".tab-pane").each((function(e,t){const a=$(t);n&&(n=0===a.find(".has-error").length);const i=a.attr("id");$(document).find('a[href="#'+i+'"]').closest(".t3js-tabmenu-item").toggleClass("has-validation-error",!n)}))},FormEngineValidation.splitSingle=function(e){const n=""+e,t={values:[],pointer:3};return t.values[1]=n.substr(0,2),t.values[2]=n.substr(2,2),t.values[3]=n.substr(4,10),t},FormEngineValidation.splitStr=function(e,n,t){const a=""+e,i=n.length;let o=-i;t<1&&(t=1);for(let e=1;e<t;e++)if(o=a.indexOf(n,o+i),-1==o)return null;let r=a.indexOf(n,o+i);return-1==r&&(r=a.length),a.substring(o+i,r)},FormEngineValidation.split=function(e){const n={values:[],valPol:[],pointer:0,numberMode:0,theVal:""};e+=" ";for(let t=0;t<e.length;t++){const a=e.substr(t,1);a<"0"||a>"9"?(n.numberMode&&(n.pointer++,n.values[n.pointer]=n.theVal,n.theVal="",n.numberMode=0),"+"!=a&&"-"!=a||(n.valPol[n.pointer+1]=a)):(n.theVal+=a,n.numberMode=1)}return n},FormEngineValidation.registerSubmitCallback=function(){DocumentSaveActions.getInstance().addPreSubmitCallback((function(e){if($("."+FormEngineValidation.errorClass).length>0){const n=Modal.confirm(TYPO3.lang.alert||"Alert",TYPO3.lang["FormEngine.fieldsMissing"],Severity.error,[{text:TYPO3.lang["button.ok"]||"OK",active:!0,btnClass:"btn-default",name:"ok"}]);n.addEventListener("button.clicked",(()=>n.hideModal())),e.stopImmediatePropagation()}}))},FormEngineValidation}()); \ No newline at end of file +import $ from"jquery";import moment from"moment";import Md5 from"@typo3/backend/hashing/md5.js";import DocumentSaveActions from"@typo3/backend/document-save-actions.js";import Modal from"@typo3/backend/modal.js";import Severity from"@typo3/backend/severity.js";export default(function(){const FormEngineValidation={rulesSelector:"[data-formengine-validation-rules]",inputSelector:"[data-formengine-input-params]",markerSelector:".t3js-formengine-validation-marker",groupFieldHiddenElement:".t3js-formengine-field-group input[type=hidden]",relatedFieldSelector:"[data-relatedfieldname]",errorClass:"has-error",lastYear:0,lastDate:0,lastTime:0,passwordDummy:"********"},customEvaluations=new Map;return FormEngineValidation.initialize=function(){$(document).find("."+FormEngineValidation.errorClass).removeClass(FormEngineValidation.errorClass),FormEngineValidation.initializeInputFields().promise().done((function(){$(document).on("change",FormEngineValidation.rulesSelector,(e=>{FormEngineValidation.validateField(e.currentTarget),FormEngineValidation.markFieldAsChanged(e.currentTarget)})),FormEngineValidation.registerSubmitCallback()}));const e=new Date;FormEngineValidation.lastYear=FormEngineValidation.getYear(e),FormEngineValidation.lastDate=FormEngineValidation.getDate(e),FormEngineValidation.lastTime=0,FormEngineValidation.validate()},FormEngineValidation.initializeInputFields=function(){return $(document).find(FormEngineValidation.inputSelector).each((function(e,n){const t=$(n).data("formengine-input-params"),a=t.field,i=$('[name="'+a+'"]');void 0===i.data("main-field")&&(i.data("main-field",a),i.data("config",t),FormEngineValidation.initializeInputField(a))}))},FormEngineValidation.initializeInputField=function(e){const n=$('[name="'+e+'"]'),t=$('[data-formengine-input-name="'+e+'"]');let a=$('[name="'+n.data("main-field")+'"]');0===a.length&&(a=n);const i=a.data("config");if(void 0!==i){const e=FormEngineValidation.trimExplode(",",i.evalList);let a=n.val();for(let n=0;n<e.length;n++)a=FormEngineValidation.formatValue(e[n],a,i);a.length&&t.val(a)}t.data("main-field",e),t.data("config",i),t.on("change",(function(){FormEngineValidation.updateInputField(t.attr("data-formengine-input-name"))})),t.attr("data-formengine-input-initialized","true")},FormEngineValidation.registerCustomEvaluation=function(e,n){customEvaluations.has(e)||customEvaluations.set(e,n)},FormEngineValidation.formatValue=function(e,n,t){let a,i,o="";switch(e){case"date":if(n.toString().indexOf("-")>0){o=moment.utc(n).format("DD-MM-YYYY")}else{if(a=1*n,!a)return"";i=new Date(1e3*a);o=i.getUTCDate().toString(10).padStart(2,"0")+"-"+(i.getUTCMonth()+1).toString(10).padStart(2,"0")+"-"+this.getYear(i)}break;case"datetime":if(n.toString().indexOf("-")<=0&&!("number"==typeof n?n:parseInt(n)))return"";o=FormEngineValidation.formatValue("time",n,t)+" "+FormEngineValidation.formatValue("date",n,t);break;case"time":case"timesec":let r;if(n.toString().indexOf("-")>0)r=moment.utc(n);else{if(a="number"==typeof n?n:parseInt(n),!a&&"0"!==n.toString())return"";r=moment.unix(a).utc()}o="timesec"===e?r.format("HH:mm:ss"):r.format("HH:mm");break;case"password":o=n?FormEngineValidation.passwordDummy:"";break;default:o=n}return o},FormEngineValidation.updateInputField=function(e){const n=$('[name="'+e+'"]');let t=$('[name="'+n.data("main-field")+'"]');0===t.length&&(t=n);const a=$('[data-formengine-input-name="'+t.attr("name")+'"]'),i=t.data("config");if(void 0!==i){const e=FormEngineValidation.trimExplode(",",i.evalList);let n=a.val();for(let t=0;t<e.length;t++)n=FormEngineValidation.processValue(e[t],n,i);let o=n;for(let n=0;n<e.length;n++)o=FormEngineValidation.formatValue(e[n],o,i);t.val(n),t.get(0).dispatchEvent(new Event("change")),a.val(o)}},FormEngineValidation.validateField=function(e,n){const t=e instanceof $?e.get(0):e;if(n=n||t.value||"",void 0===t.dataset.formengineValidationRules)return n;const a=JSON.parse(t.dataset.formengineValidationRules);let i,o,r,l=!1,s=0,m=n;$.isArray(n)||(n=n.trimStart()),$.each(a,(function(e,a){if(l)return!1;switch(a.type){case"required":""===n&&(l=!0,t.closest(FormEngineValidation.markerSelector).classList.add(FormEngineValidation.errorClass));break;case"range":if(""!==n){if((a.minItems||a.maxItems)&&(i=$(document).find('[name="'+t.dataset.relatedfieldname+'"]'),s=i.length?FormEngineValidation.trimExplode(",",i.val()).length:t.value,void 0!==a.minItems&&(o=1*a.minItems,!isNaN(o)&&s<o&&(l=!0)),void 0!==a.maxItems&&(r=1*a.maxItems,!isNaN(r)&&s>r&&(l=!0))),void 0!==a.lower){const e=1*a.lower;!isNaN(e)&&n<e&&(l=!0)}if(void 0!==a.upper){const e=1*a.upper;!isNaN(e)&&n>e&&(l=!0)}}break;case"select":case"category":(a.minItems||a.maxItems)&&(i=$(document).find('[name="'+t.dataset.relatedfieldname+'"]'),s=i.length?FormEngineValidation.trimExplode(",",i.val()).length:t instanceof HTMLSelectElement?t.querySelectorAll("option:checked").length:t.querySelectorAll("input[value]:checked").length,void 0!==a.minItems&&(o=1*a.minItems,!isNaN(o)&&s<o&&(l=!0)),void 0!==a.maxItems&&(r=1*a.maxItems,!isNaN(r)&&s>r&&(l=!0)));break;case"group":case"inline":(a.minItems||a.maxItems)&&(s=FormEngineValidation.trimExplode(",",t.value).length,void 0!==a.minItems&&(o=1*a.minItems,!isNaN(o)&&s<o&&(l=!0)),void 0!==a.maxItems&&(r=1*a.maxItems,!isNaN(r)&&s>r&&(l=!0)));break;case"min":(t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement)&&t.value.length>0&&t.value.length<t.minLength&&(l=!0)}}));const d=!l,c=t.closest(FormEngineValidation.markerSelector);return null!==c&&c.classList.toggle(FormEngineValidation.errorClass,!d),FormEngineValidation.markParentTab($(t),d),$(document).trigger("t3-formengine-postfieldvalidation"),m},FormEngineValidation.processValue=function(e,n,t){let a="",i="",o="",r=0,l=n;switch(e){case"alpha":case"num":case"alphanum":case"alphanum_x":for(a="",r=0;r<n.length;r++){const t=n.substr(r,1);let i="_"===t||"-"===t,o=t>="a"&&t<="z"||t>="A"&&t<="Z",l=t>="0"&&t<="9";switch(e){case"alphanum":i=!1;break;case"alpha":l=!1,i=!1;break;case"num":o=!1,i=!1}(o||l||i)&&(a+=t)}a!==n&&(l=a);break;case"is_in":if(t.is_in){i=""+n,t.is_in=t.is_in.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&");const e=new RegExp("[^"+t.is_in+"]+","g");a=i.replace(e,"")}else a=i;l=a;break;case"nospace":l=(""+n).replace(/ /g,"");break;case"md5":""!==n&&(l=Md5.hash(n));break;case"upper":l=n.toUpperCase();break;case"lower":l=n.toLowerCase();break;case"integer":""!==n&&(l=FormEngineValidation.parseInt(n));break;case"decimal":""!==n&&(l=FormEngineValidation.parseDouble(n));break;case"trim":l=String(n).trim();break;case"datetime":""!==n&&(o=n.substr(0,1),l=FormEngineValidation.parseDateTime(n));break;case"date":""!==n&&(o=n.substr(0,1),l=FormEngineValidation.parseDate(n));break;case"time":case"timesec":""!==n&&(o=n.substr(0,1),l=FormEngineValidation.parseTime(n,e));break;case"year":""!==n&&(o=n.substr(0,1),l=FormEngineValidation.parseYear(n));break;case"null":case"password":break;default:customEvaluations.has(e)?l=customEvaluations.get(e).call(null,n):"object"==typeof TBE_EDITOR&&void 0!==TBE_EDITOR.customEvalFunctions&&"function"==typeof TBE_EDITOR.customEvalFunctions[e]&&(l=TBE_EDITOR.customEvalFunctions[e](n))}return l},FormEngineValidation.validate=function(e){(void 0===e||e instanceof Document)&&$(document).find(FormEngineValidation.markerSelector+", .t3js-tabmenu-item").removeClass(FormEngineValidation.errorClass).removeClass("has-validation-error");const n=e||document;$(n).find(FormEngineValidation.rulesSelector).each(((e,n)=>{const t=$(n);if(!t.closest(".t3js-flex-section-deleted, .t3js-inline-record-deleted, .t3js-file-reference-deleted").length){let e=!1;const n=t.val(),a=FormEngineValidation.validateField(t,n);if($.isArray(a)&&$.isArray(n)){if(a.length!==n.length)e=!0;else for(let t=0;t<a.length;t++)if(a[t]!==n[t]){e=!0;break}}else a.length&&n!==a&&(e=!0);e&&t.val(a)}}))},FormEngineValidation.markFieldAsChanged=function(e){if(e instanceof $&&(e=e.get(0)),!(e instanceof HTMLElement))return;const n=e.closest(".t3js-formengine-palette-field");null!==n&&n.classList.add("has-change")},FormEngineValidation.trimExplode=function(e,n){const t=[],a=n.split(e);for(let e=0;e<a.length;e++){const n=a[e].trim();n.length>0&&t.push(n)}return t},FormEngineValidation.parseInt=function(e){let n;return e?(n=parseInt(""+e,10),isNaN(n)?0:n):0},FormEngineValidation.parseDouble=function(e,n=2){let t=""+e;t=t.replace(/[^0-9,\.-]/g,"");const a="-"===t.substring(0,1);t=t.replace(/-/g,""),t=t.replace(/,/g,"."),-1===t.indexOf(".")&&(t+=".0");const i=t.split("."),o=i.pop();let r=Number(i.join("")+"."+o);return a&&(r*=-1),t=r.toFixed(n),t},FormEngineValidation.parseDateTime=function(e){const n=e.indexOf(" ");if(-1!==n){const t=FormEngineValidation.parseDate(e.substr(n,e.length));FormEngineValidation.lastTime=t+FormEngineValidation.parseTime(e.substr(0,n),"time")}else FormEngineValidation.lastTime=FormEngineValidation.parseDate(e);return FormEngineValidation.lastTime},FormEngineValidation.parseDate=function(e){return FormEngineValidation.lastDate=moment.utc(e,"DD-MM-YYYY").unix(),FormEngineValidation.lastDate},FormEngineValidation.parseTime=function(e,n){const t="timesec"===n?"hh:mm:ss":"hh:mm";return FormEngineValidation.lastTime=moment.utc(e,t).year(1970).month(0).date(1).unix(),FormEngineValidation.lastTime<0&&(FormEngineValidation.lastTime+=86400),FormEngineValidation.lastTime},FormEngineValidation.parseYear=function(e){let n=parseInt(e,10);return isNaN(n)&&(n=FormEngineValidation.getYear(new Date)),FormEngineValidation.lastYear=n,FormEngineValidation.lastYear},FormEngineValidation.getYear=function(e){return null===e?null:e.getUTCFullYear()},FormEngineValidation.getDate=function(e){const n=new Date(FormEngineValidation.getYear(e),e.getUTCMonth(),e.getUTCDate());return FormEngineValidation.getTimestamp(n)},FormEngineValidation.pol=function(foreign,value){return eval(("-"==foreign?"-":"")+value)},FormEngineValidation.getTimestamp=function(e){return Date.parse(e instanceof Date?e.toISOString():e)/1e3},FormEngineValidation.getTime=function(e){return 60*e.getUTCHours()*60+60*e.getUTCMinutes()+FormEngineValidation.getSecs(e)},FormEngineValidation.getSecs=function(e){return e.getUTCSeconds()},FormEngineValidation.getTimeSecs=function(e){return 60*e.getHours()*60+60*e.getMinutes()+e.getSeconds()},FormEngineValidation.markParentTab=function(e,n){e.parents(".tab-pane").each((function(e,t){const a=$(t);n&&(n=0===a.find(".has-error").length);const i=a.attr("id");$(document).find('a[href="#'+i+'"]').closest(".t3js-tabmenu-item").toggleClass("has-validation-error",!n)}))},FormEngineValidation.registerSubmitCallback=function(){DocumentSaveActions.getInstance().addPreSubmitCallback((function(e){if($("."+FormEngineValidation.errorClass).length>0){const n=Modal.confirm(TYPO3.lang.alert||"Alert",TYPO3.lang["FormEngine.fieldsMissing"],Severity.error,[{text:TYPO3.lang["button.ok"]||"OK",active:!0,btnClass:"btn-default",name:"ok"}]);n.addEventListener("button.clicked",(()=>n.hideModal())),e.stopImmediatePropagation()}}))},FormEngineValidation}()); \ No newline at end of file diff --git a/typo3/sysext/backend/Tests/JavaScript/form-engine-validation-test.js b/typo3/sysext/backend/Tests/JavaScript/form-engine-validation-test.js index da1e25a8914e..e72e7932fa9b 100644 --- a/typo3/sysext/backend/Tests/JavaScript/form-engine-validation-test.js +++ b/typo3/sysext/backend/Tests/JavaScript/form-engine-validation-test.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -import FormEngineValidation from"@typo3/backend/form-engine-validation.js";describe("TYPO3/CMS/Backend/FormEngineValidationTest:",(()=>{const e=[{description:"works for type date",type:"date",value:0,config:{},result:""},{description:"works for type date with timestamp",type:"date",value:1e7,config:{},result:"26-04-1970"},{description:"works for type date with iso date",type:"date",value:"2016-12-02T11:16:06+00:00",config:{},result:"02-12-2016"},{description:"works for type datetime",type:"datetime",value:0,config:{},result:""},{description:"works for type datetime with timestamp",type:"datetime",value:1e7,config:{},result:"17:46 26-04-1970"},{description:"works for type datetime with iso date",type:"datetime",value:"2016-12-02T11:16:06+00:00",config:{},result:"11:16 02-12-2016"},{description:"resolves to empty result for zero value",type:"datetime",value:0,config:{},result:""},{description:"resolves to empty result for invalid value",type:"datetime",value:"invalid",config:{},result:""},{description:"works for type time",type:"time",value:0,config:{},result:"00:00"},{description:"works for type time with timestamp",type:"time",value:1e7,config:{},result:"17:46"},{description:"works for type time with iso date",type:"time",value:"2016-12-02T11:16:06+00:00",config:{},result:"11:16"}];describe("tests for formatValue",(()=>{using(e,(function(e){it(e.description,(()=>{FormEngineValidation.initialize();const t=FormEngineValidation.formatValue(e.type,e.value,e.config);expect(t).toBe(e.result)}))}))}));const t=[{description:"works for command alpha with numeric value",command:"alpha",value:"1234",config:{},result:""},{description:"works for command alpha with string value",command:"alpha",value:"abc",config:{},result:"abc"},{description:"works for command alpha with alphanum input",command:"alpha",value:"abc123",config:{},result:"abc"},{description:"works for command alpha with alphanum input",command:"alpha",value:"123abc123",config:{},result:"abc"}];describe("test for processValue",(()=>{using(t,(function(e){it(e.description,(()=>{const t=FormEngineValidation.processValue(e.command,e.value,e.config);expect(t).toBe(e.result)}))}))})),xdescribe("tests for validateField",(()=>{})),describe("tests for trimExplode",(()=>{it("works for comma as separator and list without spaces",(()=>{expect(FormEngineValidation.trimExplode(",","foo,bar,baz")).toEqual(["foo","bar","baz"])})),it("works for comma as separator and list with spaces",(()=>{expect(FormEngineValidation.trimExplode(","," foo , bar , baz ")).toEqual(["foo","bar","baz"])})),it("works for pipe as separator and list with spaces",(()=>{expect(FormEngineValidation.trimExplode("|"," foo | bar | baz ")).toEqual(["foo","bar","baz"])}))})),describe("tests for parseInt",(()=>{it("works for value 0",(()=>{expect(FormEngineValidation.parseInt(0)).toBe(0)})),it("works for value 1",(()=>{expect(FormEngineValidation.parseInt(1)).toBe(1)})),it("works for value -1",(()=>{expect(FormEngineValidation.parseInt(-1)).toBe(-1)})),it('works for value "0"',(()=>{expect(FormEngineValidation.parseInt("0")).toBe(0)})),it('works for value "1"',(()=>{expect(FormEngineValidation.parseInt("1")).toBe(1)})),it('works for value "-1"',(()=>{expect(FormEngineValidation.parseInt("-1")).toBe(-1)})),it("works for value 0.5",(()=>{expect(FormEngineValidation.parseInt(.5)).toBe(0)})),it('works for value "0.5"',(()=>{expect(FormEngineValidation.parseInt("0.5")).toBe(0)})),it('works for value "foo"',(()=>{expect(FormEngineValidation.parseInt("foo")).toBe(0)})),it("works for value true",(()=>{expect(FormEngineValidation.parseInt(!0)).toBe(0)})),it("works for value false",(()=>{expect(FormEngineValidation.parseInt(!1)).toBe(0)})),it("works for value null",(()=>{expect(FormEngineValidation.parseInt(null)).toBe(0)}))})),describe("tests for parseDouble",(()=>{it("works for value 0",(()=>{expect(FormEngineValidation.parseDouble(0)).toBe("0.00")})),it("works for value 1",(()=>{expect(FormEngineValidation.parseDouble(1)).toBe("1.00")})),it("works for value -1",(()=>{expect(FormEngineValidation.parseDouble(-1)).toBe("-1.00")})),it('works for value "0"',(()=>{expect(FormEngineValidation.parseDouble("0")).toBe("0.00")})),it('works for value "1"',(()=>{expect(FormEngineValidation.parseDouble("1")).toBe("1.00")})),it('works for value "-1"',(()=>{expect(FormEngineValidation.parseDouble("-1")).toBe("-1.00")})),it("works for value 0.5",(()=>{expect(FormEngineValidation.parseDouble(.5)).toBe("0.50")})),it('works for value "0.5"',(()=>{expect(FormEngineValidation.parseDouble("0.5")).toBe("0.50")})),it('works for value "foo"',(()=>{expect(FormEngineValidation.parseDouble("foo")).toBe("0.00")})),it("works for value true",(()=>{expect(FormEngineValidation.parseDouble(!0)).toBe("0.00")})),it("works for value false",(()=>{expect(FormEngineValidation.parseDouble(!1)).toBe("0.00")})),it("works for value null",(()=>{expect(FormEngineValidation.parseDouble(null)).toBe("0.00")}))})),describe("tests for btrim",(()=>{const e=FormEngineValidation.btrim(" test ");it("works for string with whitespace in begin and end",(()=>{expect(e).toBe(" test")}))})),describe("tests for ltrim",(()=>{const e=FormEngineValidation.ltrim(" test ");it("works for string with whitespace in begin and end",(()=>{expect(e).toBe("test ")}))})),xdescribe("tests for parseDateTime",(()=>{})),xdescribe("tests for parseDate",(()=>{})),xdescribe("tests for parseTime",(()=>{})),xdescribe("tests for parseYear",(()=>{})),describe("tests for getYear",(()=>{const e=new Date;afterEach((()=>{jasmine.clock().mockDate(e)})),it("works for current date",(()=>{const e=new Date;expect(FormEngineValidation.getYear(e)).toBe(e.getFullYear())})),it("works for year 2013",(()=>{const e=new Date(2013,9,23);jasmine.clock().mockDate(e),expect(FormEngineValidation.getYear(e)).toBe(2013)}))})),describe("tests for getDate",(()=>{const e=new Date;afterEach((()=>{jasmine.clock().mockDate(e)})),xit("works for year 2013",(()=>{const e=new Date(2013,9,23,13,13,13);jasmine.clock().mockDate(e),expect(FormEngineValidation.getDate(e)).toBe(1382479200)}))})),describe("tests for splitStr",(()=>{it("works for command and index",(()=>{expect(FormEngineValidation.splitStr("foo,bar,baz",",",-1)).toBe("foo"),expect(FormEngineValidation.splitStr("foo,bar,baz",",",0)).toBe("foo"),expect(FormEngineValidation.splitStr("foo,bar,baz",",",1)).toBe("foo"),expect(FormEngineValidation.splitStr("foo,bar,baz",",",2)).toBe("bar"),expect(FormEngineValidation.splitStr("foo,bar,baz",",",3)).toBe("baz"),expect(FormEngineValidation.splitStr(" foo , bar , baz ",",",1)).toBe(" foo "),expect(FormEngineValidation.splitStr(" foo , bar , baz ",",",2)).toBe(" bar "),expect(FormEngineValidation.splitStr(" foo , bar , baz ",",",3)).toBe(" baz ")}))})),xdescribe("tests for split",(()=>{}))})); \ No newline at end of file +import FormEngineValidation from"@typo3/backend/form-engine-validation.js";describe("TYPO3/CMS/Backend/FormEngineValidationTest:",(()=>{const e=[{description:"works for type date",type:"date",value:0,config:{},result:""},{description:"works for type date with timestamp",type:"date",value:1e7,config:{},result:"26-04-1970"},{description:"works for type date with iso date",type:"date",value:"2016-12-02T11:16:06+00:00",config:{},result:"02-12-2016"},{description:"works for type datetime",type:"datetime",value:0,config:{},result:""},{description:"works for type datetime with timestamp",type:"datetime",value:1e7,config:{},result:"17:46 26-04-1970"},{description:"works for type datetime with iso date",type:"datetime",value:"2016-12-02T11:16:06+00:00",config:{},result:"11:16 02-12-2016"},{description:"resolves to empty result for zero value",type:"datetime",value:0,config:{},result:""},{description:"resolves to empty result for invalid value",type:"datetime",value:"invalid",config:{},result:""},{description:"works for type time",type:"time",value:0,config:{},result:"00:00"},{description:"works for type time with timestamp",type:"time",value:1e7,config:{},result:"17:46"},{description:"works for type time with iso date",type:"time",value:"2016-12-02T11:16:06+00:00",config:{},result:"11:16"}];describe("tests for formatValue",(()=>{using(e,(function(e){it(e.description,(()=>{FormEngineValidation.initialize();const t=FormEngineValidation.formatValue(e.type,e.value,e.config);expect(t).toBe(e.result)}))}))}));const t=[{description:"works for command alpha with numeric value",command:"alpha",value:"1234",config:{},result:""},{description:"works for command alpha with string value",command:"alpha",value:"abc",config:{},result:"abc"},{description:"works for command alpha with alphanum input",command:"alpha",value:"abc123",config:{},result:"abc"},{description:"works for command alpha with alphanum input",command:"alpha",value:"123abc123",config:{},result:"abc"}];describe("test for processValue",(()=>{using(t,(function(e){it(e.description,(()=>{const t=FormEngineValidation.processValue(e.command,e.value,e.config);expect(t).toBe(e.result)}))}))})),xdescribe("tests for validateField",(()=>{})),describe("tests for trimExplode",(()=>{it("works for comma as separator and list without spaces",(()=>{expect(FormEngineValidation.trimExplode(",","foo,bar,baz")).toEqual(["foo","bar","baz"])})),it("works for comma as separator and list with spaces",(()=>{expect(FormEngineValidation.trimExplode(","," foo , bar , baz ")).toEqual(["foo","bar","baz"])})),it("works for pipe as separator and list with spaces",(()=>{expect(FormEngineValidation.trimExplode("|"," foo | bar | baz ")).toEqual(["foo","bar","baz"])}))})),describe("tests for parseInt",(()=>{it("works for value 0",(()=>{expect(FormEngineValidation.parseInt(0)).toBe(0)})),it("works for value 1",(()=>{expect(FormEngineValidation.parseInt(1)).toBe(1)})),it("works for value -1",(()=>{expect(FormEngineValidation.parseInt(-1)).toBe(-1)})),it('works for value "0"',(()=>{expect(FormEngineValidation.parseInt("0")).toBe(0)})),it('works for value "1"',(()=>{expect(FormEngineValidation.parseInt("1")).toBe(1)})),it('works for value "-1"',(()=>{expect(FormEngineValidation.parseInt("-1")).toBe(-1)})),it("works for value 0.5",(()=>{expect(FormEngineValidation.parseInt(.5)).toBe(0)})),it('works for value "0.5"',(()=>{expect(FormEngineValidation.parseInt("0.5")).toBe(0)})),it('works for value "foo"',(()=>{expect(FormEngineValidation.parseInt("foo")).toBe(0)})),it("works for value true",(()=>{expect(FormEngineValidation.parseInt(!0)).toBe(0)})),it("works for value false",(()=>{expect(FormEngineValidation.parseInt(!1)).toBe(0)})),it("works for value null",(()=>{expect(FormEngineValidation.parseInt(null)).toBe(0)}))})),describe("tests for parseDouble",(()=>{it("works for value 0",(()=>{expect(FormEngineValidation.parseDouble(0)).toBe("0.00")})),it("works for value 1",(()=>{expect(FormEngineValidation.parseDouble(1)).toBe("1.00")})),it("works for value -1",(()=>{expect(FormEngineValidation.parseDouble(-1)).toBe("-1.00")})),it('works for value "0"',(()=>{expect(FormEngineValidation.parseDouble("0")).toBe("0.00")})),it('works for value "1"',(()=>{expect(FormEngineValidation.parseDouble("1")).toBe("1.00")})),it('works for value "-1"',(()=>{expect(FormEngineValidation.parseDouble("-1")).toBe("-1.00")})),it("works for value 0.5",(()=>{expect(FormEngineValidation.parseDouble(.5)).toBe("0.50")})),it('works for value "0.5"',(()=>{expect(FormEngineValidation.parseDouble("0.5")).toBe("0.50")})),it('works for value "foo"',(()=>{expect(FormEngineValidation.parseDouble("foo")).toBe("0.00")})),it("works for value true",(()=>{expect(FormEngineValidation.parseDouble(!0)).toBe("0.00")})),it("works for value false",(()=>{expect(FormEngineValidation.parseDouble(!1)).toBe("0.00")})),it("works for value null",(()=>{expect(FormEngineValidation.parseDouble(null)).toBe("0.00")}))})),xdescribe("tests for parseDateTime",(()=>{})),xdescribe("tests for parseDate",(()=>{})),xdescribe("tests for parseTime",(()=>{})),xdescribe("tests for parseYear",(()=>{})),describe("tests for getYear",(()=>{const e=new Date;afterEach((()=>{jasmine.clock().mockDate(e)})),it("works for current date",(()=>{const e=new Date;expect(FormEngineValidation.getYear(e)).toBe(e.getFullYear())})),it("works for year 2013",(()=>{const e=new Date(2013,9,23);jasmine.clock().mockDate(e),expect(FormEngineValidation.getYear(e)).toBe(2013)}))})),describe("tests for getDate",(()=>{const e=new Date;afterEach((()=>{jasmine.clock().mockDate(e)})),xit("works for year 2013",(()=>{const e=new Date(2013,9,23,13,13,13);jasmine.clock().mockDate(e),expect(FormEngineValidation.getDate(e)).toBe(1382479200)}))}))})); \ No newline at end of file diff --git a/typo3/sysext/core/Tests/Acceptance/Application/FormEngine/ElementsBasicInputDateCest.php b/typo3/sysext/core/Tests/Acceptance/Application/FormEngine/ElementsBasicInputDateCest.php index 7a1a0d6e70a0..3b88d3055eec 100644 --- a/typo3/sysext/core/Tests/Acceptance/Application/FormEngine/ElementsBasicInputDateCest.php +++ b/typo3/sysext/core/Tests/Acceptance/Application/FormEngine/ElementsBasicInputDateCest.php @@ -68,14 +68,6 @@ class ElementsBasicInputDateCest extends AbstractElementsBasicCest 'expectedValueAfterSave' => '2016-01-29T00:00:00+00:00', 'comment' => 'inputdatetime_2 dbType=date eval=date simple input', ], - [ - 'label' => 'inputdatetime_2', - 'inputValue' => '13-13-2016', - 'expectedValue' => '13-01-2017', - 'expectedInternalValue' => '2017-01-13T00:00:00Z', - 'expectedValueAfterSave' => '2017-01-13T00:00:00+00:00', - 'comment' => 'inputdatetime_2 dbType=date eval=date month transformation', - ], [ 'label' => 'inputdatetime_2', 'inputValue' => '29-02-2016', -- GitLab