[TASK] Resident Eval - The Removal from FormEngine 12/40912/17
authorFrank Nägler <typo3@naegler.net>
Fri, 3 Jul 2015 08:01:27 +0000 (10:01 +0200)
committerMarkus Klein <markus.klein@typo3.org>
Tue, 14 Jul 2015 14:18:24 +0000 (16:18 +0200)
A long long time ago jsfunc.evalfield.js found its way into the core.
Now - after 12 years - it is time to leave.

This patch removes the usage of jsfunc.evalfield.js from FormEngine
and moves the logic into FormEngineValidation.js as a first step.
The validators and processors have been split up into two methods.

Resolves: #67852
Releases: master
Change-Id: I781bae602ea09a4a4e359df0a461f2cfc1cdf6d8
Reviewed-on: http://review.typo3.org/40912
Reviewed-by: Stefan Froemken <froemken@gmail.com>
Tested-by: Stefan Froemken <froemken@gmail.com>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein <markus.klein@typo3.org>
typo3/sysext/backend/Classes/Form/AbstractNode.php
typo3/sysext/backend/Classes/Form/Element/InputElement.php
typo3/sysext/backend/Classes/Form/FormEngine.php
typo3/sysext/backend/Resources/Public/JavaScript/FormEngineValidation.js
typo3/sysext/backend/Resources/Public/JavaScript/jsfunc.evalfield.js
typo3/sysext/backend/Resources/Public/JavaScript/jsfunc.tbe_editor.js
typo3/sysext/core/Documentation/Changelog/master/Important-67852-RemoveJsfuncevalfieldjsFromFormEngine.rst [new file with mode: 0644]
typo3/sysext/frontend/Configuration/TCA/tt_content.php
typo3/sysext/recordlist/Classes/Browser/ElementBrowser.php

index 04c4830..98cfd32 100644 (file)
@@ -153,6 +153,22 @@ abstract class AbstractNode implements NodeInterface {
         */
        protected function getValidationDataAsJsonString(array $config) {
                $validationRules = array();
+               if (!empty($config['eval'])) {
+                       $evalList = GeneralUtility::trimExplode(',', $config['eval'], TRUE);
+                       unset($config['eval']);
+                       foreach ($evalList as $evalType) {
+                               $validationRules[] = array(
+                                       'type' => $evalType,
+                                       'config' => $config
+                               );
+                       }
+               }
+               if (!empty($config['range'])) {
+                       $validationRules[] = array(
+                               'type' => 'range',
+                               'config' => $config['range']
+                       );
+               }
                if (!empty($config['maxitems']) || !empty($config['minitems'])) {
                        $minItems = (isset($config['minitems'])) ? (int)$config['minitems'] : 0;
                        $maxItems = (isset($config['maxitems'])) ? (int)$config['maxitems'] : 10000;
index bb319c6..d589b9e 100644 (file)
@@ -153,20 +153,25 @@ class InputElement extends AbstractFormElement {
                                        }
                        }
                }
-               $paramsList = GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . ',' . GeneralUtility::quoteJSvalue(implode(',', $evalList)) . ',' . GeneralUtility::quoteJSvalue(trim($config['is_in'])) . ',' . ($config['checkbox'] ? 1 : 0) . ',' . GeneralUtility::quoteJSvalue($config['checkbox']);
-               $parameterArray['fieldChangeFunc'] = array_merge(array('typo3form.fieldGet' => 'typo3form.fieldGet(' . $paramsList . ');'), $parameterArray['fieldChangeFunc']);
-
+               $paramsList = array(
+                       'field' => $parameterArray['itemFormElName'],
+                       'evalList' => implode(',', $evalList),
+                       'is_in' => trim($config['is_in']),
+                       'checkbox' => ($config['checkbox'] ? 1 : 0),
+                       'checkboxValue' => $config['checkbox'],
+               );
                // set classes
                $classes[] = 'form-control';
                $classes[] = 't3js-clearable';
                $classes[] = 'hasDefaultValue';
 
                // calculate attributes
+               $attributes['data-formengine-validation-rules'] = $this->getValidationDataAsJsonString($config);
+               $attributes['data-formengine-input-params'] = json_encode($paramsList);
                $attributes['id'] = str_replace('.', '', uniqid('formengine-input-', TRUE));
                $attributes['name'] = $parameterArray['itemFormElName'] . '_hr';
                $attributes['value'] = '';
                $attributes['maxlength'] = $config['max'] ?: 256;
-               $attributes['onchange'] = implode('', $parameterArray['fieldChangeFunc']);
 
                if (!empty($styles)) {
                        $attributes['style'] = implode(' ', $styles);
@@ -178,30 +183,26 @@ class InputElement extends AbstractFormElement {
                        $attributes['maxlength'] = (int)$config['max'];
                }
 
+               // This is the EDITABLE form field.
+               $placeholderValue = $this->getPlaceholderValue($table, $config, $row);
+               if (!empty($placeholderValue)) {
+                       $attributes['placeholder'] = trim($languageService->sL($placeholderValue));
+               }
+
                // Build the attribute string
                $attributeString = '';
                foreach ($attributes as $attributeName => $attributeValue) {
                        $attributeString .= ' ' . $attributeName . '="' . htmlspecialchars($attributeValue) . '"';
                }
 
-               // This is the EDITABLE form field.
-               $placeholderValue = $this->getPlaceholderValue($table, $config, $row);
-               $placeholderAttribute = '';
-               if (!empty($placeholderValue)) {
-                       $placeholderAttribute = ' placeholder="' . htmlspecialchars(trim($languageService->sL($placeholderValue))) . '" ';
-               }
-
                $html = '
                        <input type="text"'
                                . $attributeString
-                               . $placeholderAttribute
                                . $parameterArray['onFocus'] . ' />';
 
                // This is the ACTUAL form field - values from the EDITABLE field must be transferred to this field which is the one that is written to the database.
                $html .= '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '" value="' . htmlspecialchars($parameterArray['itemFormElValue']) . '" />';
 
-               $resultArray['extJSCODE'] = 'typo3form.fieldSet(' . $paramsList . ');';
-
                // Going through all custom evaluations configured for this field
                // @todo: Similar to above code!
                foreach ($evalList as $evalData) {
index d5952a8..84ed661 100644 (file)
@@ -211,9 +211,7 @@ class FormEngine {
         *
         * @var array
         */
-       protected $requireJsModules = array(
-               'TYPO3/CMS/Backend/FormEngineValidation' => NULL
-       );
+       protected $requireJsModules = array();
 
        /**
         * Constructor function, setting internal variables, loading the styles used.
@@ -1227,6 +1225,11 @@ class FormEngine {
                        $this->requireJsModules['TYPO3/CMS/Backend/FormEngine'] = 'function(FormEngine) {
                                FormEngine.setBrowserUrl(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('browser')) . ');
                        }';
+                       $this->requireJsModules['TYPO3/CMS/Backend/FormEngineValidation'] = 'function(FormEngineValidation) {
+                               FormEngineValidation.setUsMode(' . ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? '1' : '0') . ');
+                               FormEngineValidation.registerReady();
+                       }';
+
                        foreach ($this->requireJsModules as $moduleName => $callbacks) {
                                if (!is_array($callbacks)) {
                                        $callbacks = array($callbacks);
@@ -1247,7 +1250,6 @@ class FormEngine {
                        );
                        $pageRenderer->addInlineSettingArray('Textarea', $textareaSettings);
 
-                       $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.evalfield.js');
                        $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.tbe_editor.js');
                        $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ValueSlider');
                        // Needed for FormEngine manipulation (date picker)
@@ -1290,8 +1292,6 @@ class FormEngine {
                        TBE_EDITOR.labels.refresh_login = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login')) . ';
                        TBE_EDITOR.labels.onChangeAlert = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:mess.onChangeAlert')) . ';
                        TBE_EDITOR.labels.remainingCharacters = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.remainingCharacters')) . ';
-                       evalFunc.USmode = ' . ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? '1' : '0') . ';
-
                        TBE_EDITOR.customEvalFunctions = {};
 
                        ';
index 5c975ee..a8cff87 100644 (file)
 
 /**
  * contains all JS functions related to TYPO3 TCEforms/FormEngineValidation
+ * @internal
  */
 define('TYPO3/CMS/Backend/FormEngineValidation', ['jquery', 'TYPO3/CMS/Backend/FormEngine'], function ($, FormEngine) {
 
        /**
-        * the main FormEngineValidation object
+        * The main FormEngineValidation object
         *
-        * @type {{rulesSelector: string, dateTimeSelector: string, groupFieldHiddenElement: string, relatedFieldSelector: string}}
+        * @type {{rulesSelector: string, inputSelector: string, markerSelector: string, dateTimeSelector: string, groupFieldHiddenElement: string, relatedFieldSelector: string, errorClass: string, lastYear: number, lastDate: number, lastTime: number, refDate: Date, USmode: number, passwordDummy: string}}
         */
        var FormEngineValidation = {
                rulesSelector: '[data-formengine-validation-rules]',
+               inputSelector: '[data-formengine-input-params]',
+               markerSelector: '.t3js-formengine-validation-marker',
                dateTimeSelector: '.t3js-datetimepicker',
                groupFieldHiddenElement: '.t3js-formengine-field-group input[type=hidden]',
-               relatedFieldSelector: '[data-relatedfieldname]'
+               relatedFieldSelector: '[data-relatedfieldname]',
+               errorClass: 'has-error',
+               lastYear: 0,
+               lastDate: 0,
+               lastTime: 0,
+               refDate: new Date(),
+               USmode: 0,
+               passwordDummy: '********'
        };
 
        /**
-        * initialize validation for the first time
+        * Initialize validation for the first time
         */
        FormEngineValidation.initialize = function() {
-               $(document).find('.has-error').removeClass('has-error');
+               $(document).find('.' + FormEngineValidation.errorClass).removeClass(FormEngineValidation.errorClass);
 
-               // bind to field changes
+               // Bind to field changes
                $(document).on('change', FormEngineValidation.rulesSelector, function() {
-                       // we need to wait, because the update of the select field needs some time
+                       // we need to wait, because the update of the select fields needs some time
                        window.setTimeout(function() {
                                FormEngineValidation.validate();
                        }, 500);
+                       var $paletteField = $(this).closest('.t3js-formengine-palette-field');
+                       $paletteField.addClass('has-change');
                });
 
-               // bind to datepicker changes
+               // Bind to datepicker changes
                $(document).on('dp.change', FormEngineValidation.dateTimeSelector, function(event) {
                        FormEngineValidation.validate();
+                       var $paletteField = $(this).closest('.t3js-formengine-palette-field');
+                       $paletteField.addClass('has-change');
                });
 
-               if (typeof RTEarea !== 'undefined') {
-                       console.log(RTEarea);
+               // Initialize input fields
+               $(document).find(FormEngineValidation.inputSelector).each(function() {
+                       var config = $(this).data('formengine-input-params');
+                       var fieldName = config.field;
+                       var $field = $('[name="' + fieldName + '"]');
+                       $field.data('main-field', fieldName);
+                       $field.data('config', config);
+                       FormEngineValidation.initializeInputField(fieldName);
+               });
+
+               var today = new Date();
+               FormEngineValidation.lastYear = FormEngineValidation.getYear(today);
+               FormEngineValidation.lastDate = FormEngineValidation.getDate(today);
+               FormEngineValidation.lastTime = 0;
+               FormEngineValidation.refDate = today;
+               FormEngineValidation.USmode = 0;
+       };
+
+       /**
+        *
+        * @param {number} mode
+        */
+       FormEngineValidation.setUsMode = function(mode) {
+               FormEngineValidation.USmode = mode;
+       };
+
+       /**
+        * Initialize field by name
+        *
+        * @param {string} fieldName
+        */
+       FormEngineValidation.initializeInputField = function(fieldName) {
+               var $field = $('[name="' + fieldName + '"]');
+               var $humanReadableField = $('[name="' + fieldName + '_hr"]');
+               var $checkboxField = $('[name="' + fieldName + '_cb"]');
+               var $mainField = $('[name="' + $field.data('main-field') + '"]');
+               if ($mainField.length === 0) {
+                       $mainField = $field;
+               }
+
+               var config = $mainField.data('config');
+               if (typeof config !== 'undefined') {
+                       var evalList = FormEngineValidation.trimExplode(',', config.evalList);
+                       var value = $field.val();
+
+                       if (config.checkbox && value == config.checkboxValue) {
+                               $field.val('');
+                               if ($checkboxField.length) {
+                                       $checkboxField.attr('checked', '');
+                               }
+                       } else {
+                               for (var i = 0; i < evalList.length; i++) {
+                                       value = FormEngineValidation.formatValue(evalList[i], value, config)
+                               }
+                               if (value.length) {
+                                       $humanReadableField.val(value);
+                               }
+                               if ($checkboxField.length) {
+                                       $checkboxField.attr('checked', 'checked');
+                               }
+                       }
                }
+
+               $humanReadableField.data('main-field', fieldName);
+               $humanReadableField.data('config', config);
+               $humanReadableField.on('change', function() {
+                       FormEngineValidation.updateInputField($(this).attr('name'));
+               });
+
+               $checkboxField.data('main-field', fieldName);
+               $checkboxField.data('config', config);
+               $checkboxField.on('click', function() {
+                       FormEngineValidation.updateInputField($(this).attr('name'));
+               });
        };
 
        /**
-        * validate the complete form
+        * Format field value
+        *
+        * @param {string} type
+        * @param {string} value
+        * @param {array} config
+        * @returns {string}
         */
-       FormEngineValidation.validate = function() {
-               $(document).find('.t3js-formengine-validation-marker, .t3js-tabmenu-item')
-                       .removeClass('has-error')
-                       .removeClass('has-validation-error');
+       FormEngineValidation.formatValue = function(type, value, config) {
+               var theString = '';
+               switch (type) {
+                       case 'date':
+                               if (!parseInt(value)) {
+                                       return '';
+                               }
+                               theTime = new Date(parseInt(value) * 1000);
+                               if (FormEngineValidation.USmode) {
+                                       theString = (theTime.getUTCMonth() + 1) + '-' + theTime.getUTCDate() + '-' + this.getYear(theTime);
+                               } else {
+                                       theString = theTime.getUTCDate() + '-' + (theTime.getUTCMonth() + 1) + '-' + this.getYear(theTime);
+                               }
+                               break;
+                       case 'datetime':
+                               if (!parseInt(value)) {
+                                       return '';
+                               }
+                               theString = FormEngineValidation.formatValue('time', value, config) + ' ' + FormEngineValidation.formatValue('date', value, config);
+                               break;
+                       case 'time':
+                       case 'timesec':
+                               if (!parseInt(value)) {
+                                       return '';
+                               }
+                               var theTime = new Date(parseInt(value) * 1000);
+                               var h = theTime.getUTCHours();
+                               var m = theTime.getUTCMinutes();
+                               var s = theTime.getUTCSeconds();
+                               theString = h + ':' + ((m < 10) ? '0' : '') + m + ((type == 'timesec') ? ':' + ((s < 10) ? '0' : '') + s : '');
+                               break;
+                       case 'password':
+                               theString = (value) ? FormEngineValidation.passwordDummy : '';
+                               break;
+                       case 'int':
+                               theString = (config.checkbox && value == config.checkboxValue) ? '' : value;
+                               break;
+                       default:
+                               theString = value;
+               }
+               return theString;
+       };
 
-               $(FormEngineValidation.rulesSelector).each(function() {
-                       var $field = $(this);
-                       var $rules = $field.data('formengine-validation-rules');
-                       var markParent = false;
-                       var selected = 0;
-                       $rules.each(function(rule) {
-                               switch (rule.type) {
-                                       case 'required':
-                                               if ($field.val() === '') {
-                                                       markParent = true;
-                                                       $field.closest('.t3js-formengine-validation-marker').addClass('has-error');
-                                               }
-                                               break;
-                                       case 'range':
+       /**
+        * Update input field after change
+        *
+        * @param {string} fieldName
+        */
+       FormEngineValidation.updateInputField = function(fieldName) {
+               var $field = $('[name="' + fieldName + '"]');
+               var $mainField = $('[name="' + $field.data('main-field') + '"]');
+               if ($mainField.length === 0) {
+                       $mainField = $field;
+               }
+               var $humanReadableField = $('[name="' + $mainField.attr('name') + '_hr"]');
+
+               var config = $mainField.data('config');
+               if (typeof config !== 'undefined') {
+                       var evalList = FormEngineValidation.trimExplode(',', config.evalList);
+                       var origValue = $humanReadableField.val();
+                       var newValue = $humanReadableField.val();
+
+                       for (var i = 0; i < evalList.length; i++) {
+                               newValue = FormEngineValidation.processValue(evalList[i], newValue, config);
+                       }
+                       var typeConfig = $field.data('formengine-validation-rules');
+                       var type = '';
+                       if (typeof typeConfig !== 'undefined' && typeConfig.length) {
+                               type = typeConfig[0].type;
+                       }
+                       switch (type) {
+                               case 'password':
+                                       $mainField.val(origValue);
+                                       $humanReadableField.val(newValue);
+                                       break;
+                               default:
+                                       $mainField.val(newValue);
+                                       $humanReadableField.val(newValue);
+                       }
+               }
+       };
+
+       /**
+        * Run validation for field
+        *
+        * @param {object} $field
+        * @param {string} value
+        * @returns {string}
+        */
+       FormEngineValidation.validateField = function($field, value) {
+               value = value || FormEngineValidation.ltrim($field.val());
+
+               var $rules = $field.data('formengine-validation-rules');
+               var markParent = false;
+               var selected = 0;
+               var returnValue = value;
+               $rules.each(function(rule) {
+                       switch (rule.type) {
+                               case 'required':
+                                       if (value === '') {
+                                               markParent = true;
+                                               $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
+                                       }
+                                       break;
+                               case 'range':
+                                       if (value !== '') {
                                                if (rule.minItems || rule.maxItems) {
                                                        $relatedField = $(document).find('[name="' + $field.data('relatedfieldname') + '"]');
                                                        if ($relatedField.length) {
                                                                selected = FormEngineValidation.trimExplode(',', $relatedField.val()).length;
                                                                if (selected < rule.minItems || selected > rule.maxItems) {
                                                                        markParent = true;
-                                                                       $field.closest('.t3js-formengine-validation-marker').addClass('has-error');
+                                                                       $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
                                                                }
                                                        } else {
                                                                selected = $field.val();
                                                                if (selected < rule.minItems || selected > rule.maxItems) {
                                                                        markParent = true;
-                                                                       $field.closest('.t3js-formengine-validation-marker').addClass('has-error');
+                                                                       $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
                                                                }
 
                                                        }
                                                }
-                                               break;
-                                       case 'select':
-                                               if (rule.minItems || rule.maxItems) {
-                                                       $relatedField = $(document).find('[name="' + $field.data('relatedfieldname') + '"]');
-                                                       if ($relatedField.length) {
-                                                               selected = FormEngineValidation.trimExplode(',', $relatedField.val()).length;
-                                                               if (selected < rule.minItems || selected > rule.maxItems) {
-                                                                       markParent = true;
-                                                                       $field.closest('.t3js-formengine-validation-marker').addClass('has-error');
-                                                               }
-                                                       } else {
-                                                               selected = $field.find('option:selected').length;
-                                                               if (selected < rule.minItems || selected > rule.maxItems) {
-                                                                       markParent = true;
-                                                                       $field.closest('.t3js-formengine-validation-marker').addClass('has-error');
-                                                               }
-
+                                               if (rule.config.lower || rule.config.upper) {
+                                                       minValue = rule.config.lower || 0;
+                                                       maxValue = rule.config.upper || Number.MAX_VALUE;
+                                                       if (value < minValue || value > maxValue) {
+                                                               markParent = true;
+                                                               $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
                                                        }
                                                }
-                                               break;
-                                       case 'group':
-                                               if (rule.minItems || rule.maxItems) {
-                                                       selected = $field.find('option').length;
+                                       }
+                                       break;
+                               case 'select':
+                                       if (rule.minItems || rule.maxItems) {
+                                               $relatedField = $(document).find('[name="' + $field.data('relatedfieldname') + '"]');
+                                               if ($relatedField.length) {
+                                                       selected = FormEngineValidation.trimExplode(',', $relatedField.val()).length;
                                                        if (selected < rule.minItems || selected > rule.maxItems) {
                                                                markParent = true;
-                                                               $field.closest('.t3js-formengine-validation-marker').addClass('has-error');
+                                                               $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
                                                        }
-                                               }
-                                               break;
-                                       case 'inline':
-                                               if (rule.minItems || rule.maxItems) {
-                                                       selected = FormEngineValidation.trimExplode(',', $field.val()).length;
+                                               } else {
+                                                       selected = $field.find('option:selected').length;
                                                        if (selected < rule.minItems || selected > rule.maxItems) {
                                                                markParent = true;
-                                                               $field.closest('.t3js-formengine-validation-marker').addClass('has-error');
+                                                               $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
                                                        }
+
+                                               }
+                                       }
+                                       break;
+                               case 'group':
+                                       if (rule.minItems || rule.maxItems) {
+                                               selected = $field.find('option').length;
+                                               if (selected < rule.minItems || selected > rule.maxItems) {
+                                                       markParent = true;
+                                                       $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
+                                               }
+                                       }
+                                       break;
+                               case 'inline':
+                                       if (rule.minItems || rule.maxItems) {
+                                               selected = FormEngineValidation.trimExplode(',', $field.val()).length;
+                                               if (selected < rule.minItems || selected > rule.maxItems) {
+                                                       markParent = true;
+                                                       $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
+                                               }
+                                       }
+                                       break;
+                               case 'null':
+                                       // unknown type null, we ignore it
+                                       break;
+                               default:
+                       }
+               });
+               if (markParent) {
+                       // check tabs
+                       FormEngineValidation.markParentTab($field);
+               }
+               return returnValue;
+       };
+
+       /**
+        * Process a value by given command and config
+        *
+        * @param {string} command
+        * @param {string} value
+        * @param {array} config
+        * @returns {string}
+        */
+       FormEngineValidation.processValue = function(command, value, config) {
+               var newString = '';
+               var theValue = '';
+               var theCmd = '';
+               var a = 0;
+               var returnValue = value;
+               switch (command) {
+                       case 'alpha':
+                       case 'num':
+                       case 'alphanum':
+                       case 'alphanum_x':
+                               newString = '';
+                               for (a = 0; a < value.length; a++) {
+                                       theChar = value.substr(a, 1);
+                                       var special = (theChar === '_' || theChar === '-');
+                                       var alpha = (theChar >= 'a' && theChar <= 'z') || (theChar >= 'A' && theChar <= 'Z');
+                                       var num = (theChar >= '0' && theChar <= '9');
+                                       switch (command) {
+                                               case 'alphanum':
+                                                       special = 0;
+                                                       break;
+                                               case 'alpha':
+                                                       num = 0;
+                                                       special = 0;
+                                                       break;
+                                               case 'num':
+                                                       alpha = 0;
+                                                       special = 0;
+                                                       break;
+                                       }
+                                       if (alpha || num || theChar == ' ' || special) {
+                                               newString += theChar;
+                                       }
+                               }
+                               if (newString !== value) {
+                                       returnValue = newString;
+                               }
+                               break;
+                       case 'is_in':
+                               if (config.is_in) {
+                                       theValue = '' + value;
+                                       for (a = 0; a < theValue.length; a++) {
+                                               theChar = theValue.substr(a, 1);
+                                               if (config.is_in.indexOf(theChar) != -1) {
+                                                       newString += theChar;
                                                }
-                                               break;
-                                       default:
-                                               FormEngineValidation.log('unknown validation type: ' + rule.type);
-                               }
-                       });
-                       if (markParent) {
-                               // check tabs
-                               FormEngineValidation.markParentTab($field);
+                                       }
+                               } else {
+                                       newString = theValue;
+                               }
+                               returnValue = newString;
+                               break;
+                       case 'nospace':
+                               theValue = '' + value;
+                               newString = '';
+                               for (a = 0; a < theValue.length; a++) {
+                                       var theChar = theValue.substr(a, 1);
+                                       if (theChar != ' ') {
+                                               newString += theChar;
+                                       }
+                               }
+                               returnValue = newString;
+                               break;
+                       case 'md5':
+                               if (value !== '') {
+                                       returnValue = MD5(value);
+                               }
+                               break;
+                       case 'upper':
+                               returnValue = value.toUpperCase();
+                               break;
+                       case 'lower':
+                               returnValue = value.toLowerCase();
+                               break;
+                       case 'int':
+                               if (value !== '') {
+                                       returnValue = FormEngineValidation.parseInt(value);
+                               }
+                               break;
+                       case 'double2':
+                               if (value !== '') {
+                                       returnValue = FormEngineValidation.parseDouble(value);
+                               }
+                               break;
+                       case 'trim':
+                               returnValue = FormEngineValidation.ltrim(FormEngineValidation.btrim(value));
+                               break;
+                       case 'datetime':
+                               if (value !== '') {
+                                       theCmd = value.substr(0, 1);
+                                       returnValue = FormEngineValidation.parseDateTime(value, theCmd);
+                               }
+                               break;
+                       case 'date':
+                               if (value !== '') {
+                                       theCmd = value.substr(0, 1);
+                                       returnValue = FormEngineValidation.parseDate(value, theCmd);
+                               }
+                               break;
+                       case 'time':
+                       case 'timesec':
+                               if (value !== '') {
+                                       theCmd = value.substr(0, 1);
+                                       returnValue = FormEngineValidation.parseTime(value, theCmd, command);
+                               }
+                               break;
+                       case 'year':
+                               if (value !== '') {
+                                       theCmd = value.substr(0, 1);
+                                       returnValue = FormEngineValidation.parseYear(value, theCmd);
+                               }
+                               break;
+                       case 'null':
+                               // unknown type null, we ignore it
+                               break;
+                       case 'password':
+                               var theString = (value) ? FormEngineValidation.passwordDummy : '';
+                               returnValue = theString;
+                               break;
+                       default:
+                               if (typeof TBE_EDITOR.customEvalFunctions !== 'undefined' && typeof TBE_EDITOR.customEvalFunctions[command] === 'function') {
+                                       returnValue = TBE_EDITOR.customEvalFunctions[command](value);
+                               }
+               }
+               return returnValue;
+       };
+
+       /**
+        * Validate the complete form
+        */
+       FormEngineValidation.validate = function() {
+               $(document).find(FormEngineValidation.markerSelector + ', .t3js-tabmenu-item')
+                       .removeClass(FormEngineValidation.errorClass)
+                       .removeClass('has-validation-error');
+
+               $(FormEngineValidation.rulesSelector).each(function() {
+                       var $field = $(this);
+                       var newValue = FormEngineValidation.validateField($field);
+                       if (newValue.length) {
+                               $field.val(newValue);
                        }
                });
        };
 
        /**
-        * helper function to get clean trimmed array from comma list
+        * Helper function to get clean trimmed array from comma list
         *
-        * @param delimiter
-        * @param string
+        * @param {string} delimiter
+        * @param {string} string
         * @returns {Array}
         */
        FormEngineValidation.trimExplode = function(delimiter, string) {
@@ -160,9 +500,400 @@ define('TYPO3/CMS/Backend/FormEngineValidation', ['jquery', 'TYPO3/CMS/Backend/F
        };
 
        /**
-        * find tab by field and mark it as has-validation-error
+        * Parse value to integer
+        *
+        * @param {string} value
+        * @returns {number}
+        */
+       FormEngineValidation.parseInt = function(value) {
+               var theVal = '' + value;
+               if (!value) {
+                       return 0;
+               }
+               for (var a = 0; a < theVal.length; a++) {
+                       if (theVal.substr(a,1)!='0') {
+                               return parseInt(theVal.substr(a,theVal.length)) || 0;
+                       }
+               }
+               return 0;
+       };
+
+       /**
+        * Parse value to double
+        *
+        * @param {string} value
+        * @returns {string}
+        */
+       FormEngineValidation.parseDouble = function(value) {
+               var theVal = '' + value;
+               theVal = theVal.replace(/[^0-9,\.-]/g, '');
+               var negative = theVal.substring(0, 1) === '-';
+               theVal = theVal.replace(/-/g, '');
+               theVal = theVal.replace(/,/g, '.');
+               if (theVal.indexOf('.') === -1) {
+                       theVal += '.0';
+               }
+               var parts = theVal.split('.');
+               var dec = parts.pop();
+               theVal = Number(parts.join('') + '.' + dec);
+               if (negative) {
+                       theVal *= -1;
+               }
+               theVal = theVal.toFixed(2);
+
+               return theVal;
+       };
+
+       /**
         *
-        * @param $element
+        * @param {string} value
+        * @returns {string}
+        */
+       FormEngineValidation.ltrim = function(value) {
+               var theVal = '' + value;
+               if (!value) {
+                       return '';
+               }
+               for (var a = 0; a < theVal.length; a++) {
+                       if (theVal.substr(a, 1) != ' ') {
+                               return theVal.substr(a, theVal.length);
+                       }
+               }
+               return '';
+       };
+
+       /**
+        *
+        * @param {string} value
+        * @returns {string}
+        */
+       FormEngineValidation.btrim = function(value) {
+               var theVal = '' + value;
+               if (!value) {
+                       return '';
+               }
+               for (var a = theVal.length; a > 0; a--) {
+                       if (theVal.substr(a-1, 1) != ' ') {
+                               return theVal.substr(0, a);
+                       }
+               }
+               return '';
+       };
+
+       /**
+        * Parse datetime value
+        *
+        * @param {string} value
+        * @param {string} command
+        * @returns {*}
+        */
+       FormEngineValidation.parseDateTime = function(value, command) {
+               var today = new Date();
+               var lastTime;
+               var values = FormEngineValidation.split(value);
+               var add;
+               switch (command) {
+                       case 'd':
+                       case 't':
+                       case 'n':
+                               lastTime = FormEngineValidation.convertClientTimestampToUTC(FormEngineValidation.getTimestamp(today), 0);
+                               if (values.valPol[1]) {
+                                       add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
+                               }
+                               break;
+                       case '+':
+                       case '-':
+                               if (lastTime == 0) {
+                                       lastTime = FormEngineValidation.convertClientTimestampToUTC(FormEngineValidation.getTimestamp(today), 0);
+                               }
+                               if (values.valPol[1]) {
+                                       add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
+                               }
+                               break;
+                       default:
+                               var index = value.indexOf(' ');
+                               if (index != -1) {
+                                       var dateVal = FormEngineValidation.parseDate(value, value.substr(index,value.length));
+                                       // set refDate so that evalFunc_input on time will work with correct DST information
+                                       FormEngineValidation.refDate = new Date(dateVal * 1000);
+                                       lastTime = dateVal + FormEngineValidation.parseTime(value, value.substr(0,index));
+                               } else {
+                                       // only date, no time
+                                       lastTime = FormEngineValidation.parseDate(value, value);
+                               }
+               }
+               lastTime += add * 24 * 60 * 60;
+               return lastTime;
+       };
+
+       /**
+        * Parse date value
+        *
+        * @param {string} value
+        * @param {string} command
+        * @returns {*}
+        */
+       FormEngineValidation.parseDate = function(value, command) {
+               var today = new Date();
+               var lastDate;
+               var values = FormEngineValidation.split(value);
+               var add;
+               switch (command) {
+                       case 'd':
+                       case 't':
+                       case 'n':
+                               lastDate = FormEngineValidation.getTimestamp(today);
+                               if (values.valPol[1]) {
+                                       add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
+                               }
+                               break;
+                       case '+':
+                       case '-':
+                               if (values.valPol[1]) {
+                                       add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
+                               }
+                               break;
+                       default:
+                               var index = 4;
+                               if (values.valPol[index]) {
+                                       add = FormEngineValidation.pol(values.valPol[index], FormEngineValidation.parseInt(values.values[index]));
+                               }
+                               if (values.values[1] && values.values[1].length > 2) {
+                                       if (values.valPol[2]) {
+                                               add = FormEngineValidation.pol(values.valPol[2], FormEngineValidation.parseInt(values.values[2]));
+                                       }
+                                       var temp = values.values[1];
+                                       values = FormEngineValidation.splitSingle(temp);
+                               }
+
+                               var year = (values.values[3]) ? FormEngineValidation.parseInt(values.values[3]) : FormEngineValidation.getYear(today);
+                               if ((year >= 0 && year < 38) || (year >= 70 && year < 100) || (year >= 1902 && year < 2038)) {
+                                       if (year < 100) {
+                                               year = (year < 38) ? year += 2000 : year += 1900;
+                                       }
+                               } else {
+                                       year = FormEngineValidation.getYear(today);
+                               }
+                               var usMode = FormEngineValidation.USmode ? 1 : 2;
+                               var month = (values.values[usMode]) ? FormEngineValidation.parseInt(values.values[usMode]) : today.getUTCMonth() + 1;
+                               usMode = FormEngineValidation.USmode ? 2 : 1;
+                               var day = (values.values[usMode]) ? FormEngineValidation.parseInt(values.values[usMode]) : today.getUTCDate();
+
+                               var theTime = new Date(parseInt(year), parseInt(month)-1, parseInt(day));
+
+                               // Substract timezone offset from client
+                               lastDate = FormEngineValidation.convertClientTimestampToUTC(FormEngineValidation.getTimestamp(theTime), 0);
+               }
+               lastDate += add * 24 * 60 * 60;
+               return lastDate;
+       };
+
+       /**
+        * Parse time value
+        *
+        * @param {string} value
+        * @param {string} command
+        * @returns {*}
+        */
+       FormEngineValidation.parseTime = function(value, command, type) {
+               var today = new Date();
+               var lastTime;
+               var values = FormEngineValidation.split(value);
+               var add;
+               switch (command) {
+                       case 'd':
+                       case 't':
+                       case 'n':
+                               lastTime = FormEngineValidation.getTimeSecs(today);
+                               if (values.valPol[1]) {
+                                       add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
+                               }
+                               break;
+                       case '+':
+                       case '-':
+                               if (lastTime == 0) {
+                                       lastTime = FormEngineValidation.getTimeSecs(today);
+                               }
+                               if (values.valPol[1]) {
+                                       add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
+                               }
+                               break;
+                       default:
+                               var index = (type == 'timesec') ? 4 : 3;
+                               if (values.valPol[index]) {
+                                       add = FormEngineValidation.pol(values.valPol[index], FormEngineValidation.parseInt(values.values[index]));
+                               }
+                               if (values.values[1] && values.values[1].length > 2) {
+                                       if (values.valPol[2]) {
+                                               add = FormEngineValidation.pol(values.valPol[2], FormEngineValidation.parseInt(values.values[2]));
+                                       }
+                                       var temp = values.values[1];
+                                       values = FormEngineValidation.splitSingle(temp);
+                               }
+                               var sec = (values.values[3]) ? FormEngineValidation.parseInt(values.values[3]) : today.getUTCSeconds();
+                               if (sec > 59) {
+                                       sec = 59;
+                               }
+                               var min = (values.values[2]) ? FormEngineValidation.parseInt(values.values[2]) : today.getUTCMinutes();
+                               if (min > 59) {
+                                       min = 59;
+                               }
+                               var hour = (values.values[1]) ? FormEngineValidation.parseInt(values.values[1]) : today.getUTCHours();
+                               if (hour >= 24) {
+                                       hour = 0;
+                               }
+
+                               var theTime = new Date(FormEngineValidation.getYear(FormEngineValidation.refDate), FormEngineValidation.refDate.getUTCMonth(), FormEngineValidation.refDate.getUTCDate(), hour, min, (( type == 'timesec' ) ? sec : 0));
+
+                               // Substract timezone offset from client
+                               lastTime = FormEngineValidation.convertClientTimestampToUTC(FormEngineValidation.getTimestamp(theTime), 1);
+               }
+               lastTime += add * 60;
+               if (lastTime < 0) {
+                       lastTime += 24 * 60 * 60;
+               }
+               return lastTime;
+       };
+
+       /**
+        * Parse year value
+        *
+        * @param {string} value
+        * @param {string} command
+        * @returns {*}
+        */
+       FormEngineValidation.parseYear = function(value, command) {
+               var today = new Date();
+               var values = FormEngineValidation.split(value);
+               var add = 0;
+               switch (command) {
+                       case 'd':
+                       case 't':
+                       case 'n':
+                               FormEngineValidation.lastYear = FormEngineValidation.getYear(today);
+                               if (values.valPol[1]) {
+                                       add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
+                               }
+                               break;
+                       case '+':
+                       case '-':
+                               if (values.valPol[1]) {
+                                       add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
+                               }
+                               break;
+                       default:
+                               if (values.valPol[2]) {
+                                       add = FormEngineValidation.pol(values.valPol[2], FormEngineValidation.parseInt(values.values[2]));
+                               }
+                               var year = (values.values[1]) ? FormEngineValidation.parseInt(values.values[1]) : FormEngineValidation.getYear(today);
+                               if ((year >= 0 && year < 38) || (year >= 70 && year<100) || (year >= 1902 && year < 2038)) {
+                                       if (year < 100) {
+                                               year = (year < 38) ? year += 2000 : year += 1900;
+                                       }
+                               } else {
+                                       year = FormEngineValidation.getYear(today);
+                               }
+                               FormEngineValidation.lastYear = year;
+               }
+               FormEngineValidation.lastYear += add;
+               return FormEngineValidation.lastYear;
+       };
+
+       /**
+        * Get year from date object
+        *
+        * @param {Date} timeObj
+        * @returns {number}
+        */
+       FormEngineValidation.getYear = function(timeObj) {
+               if (timeObj === null) {
+                       return;
+               }
+               return timeObj.getUTCFullYear();
+       };
+
+       /**
+        * Get date as timestamp from Date object
+        *
+        * @param {Date} timeObj
+        * @returns {number}
+        */
+       FormEngineValidation.getDate = function(timeObj) {
+               var theTime = new Date(FormEngineValidation.getYear(timeObj), timeObj.getUTCMonth(), timeObj.getUTCDate());
+               return FormEngineValidation.getTimestamp(theTime);
+       };
+
+       /**
+        *
+        * @param {string} foreign
+        * @param {string} value
+        * @returns {Object}
+        */
+       FormEngineValidation.pol = function(foreign, value) {
+               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, timeonly) {
+               var 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
+        *
+        * @param {string} timeObj
+        * @returns {number}
+        */
+       FormEngineValidation.getTimestamp = function(timeObj) {
+               return Date.parse(timeObj)/1000;
+       };
+
+       /**
+        * Seconds since midnight
+        *
+        * @param timeObj
+        * @returns {*}
+        */
+       FormEngineValidation.getTime = function(timeObj) {
+               return timeObj.getUTCHours() * 60 * 60 + timeObj.getUTCMinutes() * 60 + FormEngineValidation.getSecs(timeObj);
+       };
+
+       /**
+        *
+        * @param timeObj
+        * @returns {number}
+        */
+       FormEngineValidation.getSecs = function(timeObj) {
+               return timeObj.getUTCSeconds();
+       };
+
+       /**
+        *
+        * @param timeObj
+        * @returns {number}
+        */
+       FormEngineValidation.getTimeSecs = function(timeObj) {
+               return timeObj.getHours() * 60 * 60 + timeObj.getMinutes() * 60 + timeObj.getSeconds();
+       };
+
+       /**
+        * Find tab by field and mark it as has-validation-error
+        *
+        * @param {object} $element
         */
        FormEngineValidation.markParentTab = function($element) {
                var $panes = $element.parents('.tab-pane');
@@ -177,24 +908,98 @@ define('TYPO3/CMS/Backend/FormEngineValidation', ['jquery', 'TYPO3/CMS/Backend/F
        };
 
        /**
-        * helper function for console.log message
         *
-        * @param msg
+        * @param value
+        * @returns {{values: Array, pointer: number}}
+        */
+       FormEngineValidation.splitSingle = function(value) {
+               var theVal = '' + value;
+               var result = {
+                       values: [],
+                       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.log = function(msg) {
-               if (typeof console !== 'undefined') {
-                       console.log(msg);
+       FormEngineValidation.splitStr = function(theStr1, delim, index) {
+               var theStr = '' + theStr1;
+               var lengthOfDelim = delim.length;
+               sPos = -lengthOfDelim;
+               if (index < 1) {
+                       index = 1;
                }
+               for (a = 1; a < index; a++) {
+                       sPos = theStr.indexOf(delim, sPos + lengthOfDelim);
+                       if (sPos == -1) {
+                               return null;
+                       }
+               }
+               ePos = theStr.indexOf(delim, sPos + lengthOfDelim);
+               if (ePos == -1) {
+                       ePos = theStr.length;
+               }
+               return (theStr.substring(sPos + lengthOfDelim, ePos));
        };
 
        /**
-        * initialize function
+        *
+        * @param value
+        * @returns {{values: Array, valPol: Array, pointer: number, numberMode: number, theVal: string}}
         */
-       FormEngineValidation.initialize();
-       // Start first validation after one second, because all fields are initial empty (typo3form.fieldSet)
-       window.setTimeout(function() {
-               FormEngineValidation.validate();
-       }, 1000);
+       FormEngineValidation.split = function(value) {
+               var result = {
+                       values: [],
+                       valPol: [],
+                       pointer: 0,
+                       numberMode: 0,
+                       theVal: ''
+               };
+               value += ' ';
+               for (var a=0; a < value.length; a++) {
+                       var 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.registerReady = function() {
+               $(document).ready(function() {
+                       FormEngineValidation.initialize();
+                       // Start first validation after one second, because all fields are initial empty (typo3form.fieldSet)
+                       window.setTimeout(function() {
+                               FormEngineValidation.validate();
+                       }, 1000);
+               });
+       };
+
+       /**
+        * Initialize function
+        */
+
 
        FormEngine.Validation = FormEngineValidation;
+       return FormEngine.Validation;
 });
index ce40145..d62fe62 100644 (file)
@@ -38,9 +38,9 @@ function evalFunc() {
        this.ltrim = evalFunc_ltrim;
        this.btrim = evalFunc_btrim;
        var today = new Date();
-       this.lastYear = this.getYear(today);
-       this.lastDate = this.getDate(today);
-       this.lastTime = 0;
+       this.lastYear = this.getYear(today);
+       this.lastDate = this.getDate(today);
+       this.lastTime = 0;
        this.refDate = today;
        this.isInString = '';
        this.USmode = 0;
@@ -101,7 +101,7 @@ function evalFunc_caseSwitch(type,inVal) {
                                        newString+=theChar;
                                }
                        }
-               break;
+                       break;
                case "is_in":
                        if (this.isInString) {
                                for (var a=0;a<theVal.length;a++) {
@@ -111,16 +111,16 @@ function evalFunc_caseSwitch(type,inVal) {
                                        }
                                }
                        } else {newString = theVal;}
-               break;
+                       break;
                case "nospace":
                        newString = this.noSpace(theVal);
-               break;
+                       break;
                case "upper":
                        newString = theVal.toUpperCase();
-               break;
+                       break;
                case "lower":
                        newString = theVal.toLowerCase();
-               break;
+                       break;
                default:
                        return inVal;
        }
@@ -164,7 +164,7 @@ function evalFunc_parseDouble(value) {
        var dec = parts.pop();
        theVal = Number(parts.join("") + "." + dec);
        if (negative) {
-           theVal *= -1;
+               theVal *= -1;
        }
        theVal = theVal.toFixed(2);
 
@@ -272,31 +272,31 @@ function evalFunc_input(type,inVal) {
                                        if (values.valPol[1]) {
                                                add = this.pol(values.valPol[1],this.parseInt(values.values[1]));
                                        }
-                               break;
+                                       break;
                                case "+":
                                case "-":
                                        if (this.lastTime == 0) {
                                                this.lastTime = this.convertClientTimestampToUTC(this.getTimestamp(today), 0);
                                        }
                                        if (values.valPol[1]) {
-                                               add = this.pol(values.valPol[1],this.parseInt(values.values[1]));
+                                               add = this.pol(values.valPol[1], this.parseInt(values.values[1]));
                                        }
-                               break;
+                                       break;
                                default:
                                        var index = value.indexOf(' ');
                                        if (index!=-1) {
-                                               var dateVal = this.input("date",value.substr(index,value.length));
-                                                       // set refDate so that evalFunc_input on time will work with correct DST information
+                                               var dateVal = this.input("date", value.substr(index,value.length));
+                                               // set refDate so that evalFunc_input on time will work with correct DST information
                                                this.refDate = new Date(dateVal*1000);
-                                               this.lastTime = dateVal + this.input("time",value.substr(0,index));
+                                               this.lastTime = dateVal + this.input("time", value.substr(0,index));
                                        } else  {
-                                                       // only date, no time
+                                               // only date, no time
                                                this.lastTime = this.input("date", value);
                                        }
                        }
                        this.lastTime+=add*24*60*60;
                        return this.lastTime;
-               break;
+                       break;
                case "year":
                        switch (theCmd) {
                                case "d":
@@ -306,13 +306,13 @@ function evalFunc_input(type,inVal) {
                                        if (values.valPol[1]) {
                                                add = this.pol(values.valPol[1],this.parseInt(values.values[1]));
                                        }
-                               break;
+                                       break;
                                case "+":
                                case "-":
                                        if (values.valPol[1]) {
                                                add = this.pol(values.valPol[1],this.parseInt(values.values[1]));
                                        }
-                               break;
+                                       break;
                                default:
                                        if (values.valPol[2]) {
                                                add = this.pol(values.valPol[2],this.parseInt(values.values[2]));
@@ -329,7 +329,7 @@ function evalFunc_input(type,inVal) {
                        }
                        this.lastYear+=add;
                        return this.lastYear;
-               break;
+                       break;
                case "date":
                        switch (theCmd) {
                                case "d":
@@ -339,13 +339,13 @@ function evalFunc_input(type,inVal) {
                                        if (values.valPol[1]) {
                                                add = this.pol(values.valPol[1],this.parseInt(values.values[1]));
                                        }
-                               break;
+                                       break;
                                case "+":
                                case "-":
                                        if (values.valPol[1]) {
                                                add = this.pol(values.valPol[1],this.parseInt(values.values[1]));
                                        }
-                               break;
+                                       break;
                                default:
                                        var index = 4;
                                        if (values.valPol[index]) {
@@ -372,12 +372,12 @@ function evalFunc_input(type,inVal) {
 
                                        var theTime = new Date(parseInt(year), parseInt(month)-1, parseInt(day));
 
-                                               // Substract timezone offset from client
+                                       // Substract timezone offset from client
                                        this.lastDate = this.convertClientTimestampToUTC(this.getTimestamp(theTime), 0);
                        }
                        this.lastDate+=add*24*60*60;
                        return this.lastDate;
-               break;
+                       break;
                case "time":
                case "timesec":
                        switch (theCmd) {
@@ -388,7 +388,7 @@ function evalFunc_input(type,inVal) {
                                        if (values.valPol[1]) {
                                                add = this.pol(values.valPol[1],this.parseInt(values.values[1]));
                                        }
-                               break;
+                                       break;
                                case "+":
                                case "-":
                                        if (this.lastTime == 0) {
@@ -397,7 +397,7 @@ function evalFunc_input(type,inVal) {
                                        if (values.valPol[1]) {
                                                add = this.pol(values.valPol[1],this.parseInt(values.values[1]));
                                        }
-                               break;
+                                       break;
                                default:
                                        var index = (type=="timesec")?4:3;
                                        if (values.valPol[index]) {
@@ -419,13 +419,13 @@ function evalFunc_input(type,inVal) {
 
                                        var theTime = new Date(this.getYear(this.refDate), this.refDate.getUTCMonth(), this.refDate.getUTCDate(), hour, min, ((type=="timesec")?sec:0));
 
-                                               // Substract timezone offset from client
+                                       // Substract timezone offset from client
                                        this.lastTime = this.convertClientTimestampToUTC(this.getTimestamp(theTime), 1);
                        }
                        this.lastTime+=add*60;
                        if (this.lastTime<0) {this.lastTime+=24*60*60;}
                        return this.lastTime;
-               break;
+                       break;
                default:
                        return value;
        }
@@ -441,11 +441,11 @@ function evalFunc_output(type,value,FObj) {
                        } else {
                                theString = theTime.getUTCDate()+'-'+(theTime.getUTCMonth()+1)+'-'+this.getYear(theTime);
                        }
-               break;
+                       break;
                case "datetime":
                        if (!parseInt(value))   {return '';}
                        theString = this.output("time",value)+' '+this.output("date",value);
-               break;
+                       break;
                case "time":
                case "timesec":
                        if (!parseInt(value))   {return '';}
@@ -454,13 +454,13 @@ function evalFunc_output(type,value,FObj) {
                        var m = theTime.getUTCMinutes();
                        var s = theTime.getUTCSeconds();
                        theString = h+':'+((m<10)?'0':'')+m + ((type=="timesec")?':'+((s<10)?'0':'')+s:'');
-               break;
+                       break;
                case "password":
                        theString = (value)     ? TS.passwordDummy : "";
-               break;
+                       break;
                case "int":
                        theString = (FObj.checkbox && value==FObj.checkboxValue)?'':value;
-               break;
+                       break;
                default:
                        theString = value;
        }
@@ -512,10 +512,10 @@ function evalFunc_convertClientTimestampToUTC(timestamp, timeonly) {
        var timeObj = new Date(timestamp*1000);
        timeObj.setTime((timestamp - timeObj.getTimezoneOffset()*60)*1000);
        if (timeonly) {
-                       // only seconds since midnight
+               // only seconds since midnight
                return this.getTime(timeObj);
        } else  {
-                       // seconds since the "unix-epoch"
+               // seconds since the "unix-epoch"
                return this.getTimestamp(timeObj);
        }
 }
index ce56cd7..dbc1c7e 100644 (file)
@@ -150,6 +150,8 @@ var TBE_EDITOR = {
 
                // modify the "field has changed" info by adding a class to the container element (based on palette or main field)
                var $formField = TYPO3.jQuery('[name="' + el + '"]');
+               var $humanReadableField = TYPO3.jQuery('[name="' + el + '_hr"]');
+               $humanReadableField.triggerHandler('change');
                var $paletteField = $formField.closest('.t3js-formengine-palette-field');
                $paletteField.addClass('has-change');
 
@@ -347,8 +349,8 @@ function typoSetup  () {
        this.passwordDummy = '********';
        this.decimalSign = '.';
 }
+// @todo: maybe obsolete, need a deeper check
 var TS = new typoSetup();
-var evalFunc = new evalFunc();
 
 // backwards compatibility for extensions
 var TBE_EDITOR_setHiddenContent = TBE_EDITOR.setHiddenContent;
@@ -440,6 +442,15 @@ var typo3form = {
        }
 };
 
+// @TODO: This function is a copy from jsfunc.evalfield.js
+// @TODO: Remove it later, after TBE_EDITOR is not used anymore.
+function evalFunc_dummy (evallist,is_in,checkbox,checkboxValue) {
+       this.evallist = evallist;
+       this.is_in = is_in;
+       this.checkboxValue = checkboxValue;
+       this.checkbox = checkbox;
+}
+
 // backwards compatibility for extensions
 var typo3FormFieldSet = typo3form.fieldSet;
 var typo3FormFieldGet = typo3form.fieldGet;
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Important-67852-RemoveJsfuncevalfieldjsFromFormEngine.rst b/typo3/sysext/core/Documentation/Changelog/master/Important-67852-RemoveJsfuncevalfieldjsFromFormEngine.rst
new file mode 100644 (file)
index 0000000..b2dab20
--- /dev/null
@@ -0,0 +1,12 @@
+==============================================================
+Important: #67852 - Remove jsfunc.evalfield.js from FormEngine
+==============================================================
+
+Description
+===========
+
+After 12 years, the usage of ``jsfunc.evalfield.js`` has been removed from ``FormEngine``.
+The JavaScript has been moved into FormEngineValidation AMD module.
+Processors and Validator has been split up in two different function.
+
+Including the ``jsfunc.evalfield.js`` still works, but will be removed shortly.
\ No newline at end of file
index ba85fe6..f959ab8 100644 (file)
@@ -471,8 +471,8 @@ return array(
                                'max' => '4',
                                'eval' => 'int',
                                'range' => array(
-                                       'upper' => '999',
-                                       'lower' => '25'
+                                       'upper' => 1999,
+                                       'lower' => 0,
                                ),
                                'default' => 0
                        )
@@ -486,8 +486,8 @@ return array(
                                'max' => '4',
                                'eval' => 'int',
                                'range' => array(
-                                       'upper' => '700',
-                                       'lower' => '25'
+                                       'upper' => 1999,
+                                       'lower' => 0,
                                ),
                                'default' => 0
                        )
index 468fb6b..150dfb0 100644 (file)
@@ -618,7 +618,9 @@ class ElementBrowser {
                                                } else {
                                                        field.value = input;
                                                }
-                                               field.onchange();
+                                               if (typeof field.onchange === \'function\') {
+                                                       field.onchange();
+                                               }
                                                ' . $update . '
                                        }
                                }