623e73df7a8b049333a71b3e1dc46e8969366715
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Resources / Public / JavaScript / FormEngineValidation.js
1 /*
2 * This file is part of the TYPO3 CMS project.
3 *
4 * It is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU General Public License, either version 2
6 * of the License, or any later version.
7 *
8 * For the full copyright and license information, please read the
9 * LICENSE.txt file that was distributed with this source code.
10 *
11 * The TYPO3 project - inspiring people to share!
12 */
13
14 /**
15 * contains all JS functions related to TYPO3 TCEforms/FormEngineValidation
16 * @internal
17 */
18 define(['jquery', 'TYPO3/CMS/Backend/FormEngine'], function ($, FormEngine) {
19
20 /**
21 * The main FormEngineValidation object
22 *
23 * @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}}
24 */
25 var FormEngineValidation = {
26 rulesSelector: '[data-formengine-validation-rules]',
27 inputSelector: '[data-formengine-input-params]',
28 markerSelector: '.t3js-formengine-validation-marker',
29 dateTimeSelector: '.t3js-datetimepicker',
30 groupFieldHiddenElement: '.t3js-formengine-field-group input[type=hidden]',
31 relatedFieldSelector: '[data-relatedfieldname]',
32 errorClass: 'has-error',
33 lastYear: 0,
34 lastDate: 0,
35 lastTime: 0,
36 refDate: new Date(),
37 USmode: 0,
38 passwordDummy: '********'
39 };
40
41 /**
42 * Initialize validation for the first time
43 */
44 FormEngineValidation.initialize = function() {
45 $(document).find('.' + FormEngineValidation.errorClass).removeClass(FormEngineValidation.errorClass);
46
47 // Initialize input fields
48 FormEngineValidation.initializeInputFields().promise().done(function () {
49 // Bind to field changes
50 $(document).on('change', FormEngineValidation.rulesSelector, function() {
51 // we need to wait, because the update of the select fields needs some time
52 window.setTimeout(function() {
53 FormEngineValidation.validate();
54 }, 500);
55 var $paletteField = $(this).closest('.t3js-formengine-palette-field');
56 $paletteField.addClass('has-change');
57 });
58
59 // Bind to datepicker change event, but wait some milliseconds, because the init is not so fast
60 window.setTimeout(function() {
61 //noinspection JSUnusedLocalSymbols
62 $(document).on('dp.change', FormEngineValidation.dateTimeSelector, function(event) {
63 FormEngineValidation.validate();
64 var $paletteField = $(this).closest('.t3js-formengine-palette-field');
65 $paletteField.addClass('has-change');
66 });
67 }, 500);
68 });
69
70 var today = new Date();
71 FormEngineValidation.lastYear = FormEngineValidation.getYear(today);
72 FormEngineValidation.lastDate = FormEngineValidation.getDate(today);
73 FormEngineValidation.lastTime = 0;
74 FormEngineValidation.refDate = today;
75 FormEngineValidation.USmode = 0;
76 };
77
78 /**
79 * initialize all input fields
80 *
81 * @returns {*|jQuery}
82 */
83 FormEngineValidation.initializeInputFields = function() {
84 return $(document).find(FormEngineValidation.inputSelector).each(function() {
85 var config = $(this).data('formengine-input-params');
86 var fieldName = config.field;
87 var $field = $('[name="' + fieldName + '"]');
88
89 // ignore fields which already have been initialized
90 if ($field.data('main-field') === undefined) {
91 $field.data('main-field', fieldName);
92 $field.data('config', config);
93 FormEngineValidation.initializeInputField(fieldName);
94 }
95 });
96 };
97
98 /**
99 *
100 * @param {number} mode
101 */
102 FormEngineValidation.setUsMode = function(mode) {
103 FormEngineValidation.USmode = mode;
104 };
105
106 /**
107 * Initialize field by name
108 *
109 * @param {string} fieldName
110 */
111 FormEngineValidation.initializeInputField = function(fieldName) {
112 var $field = $('[name="' + fieldName + '"]');
113 var $humanReadableField = $('[data-formengine-input-name="' + fieldName + '"]');
114 var $mainField = $('[name="' + $field.data('main-field') + '"]');
115 if ($mainField.length === 0) {
116 $mainField = $field;
117 }
118
119 var config = $mainField.data('config');
120 if (typeof config !== 'undefined') {
121 var evalList = FormEngineValidation.trimExplode(',', config.evalList);
122 var value = $field.val();
123
124 for (var i = 0; i < evalList.length; i++) {
125 value = FormEngineValidation.formatValue(evalList[i], value, config)
126 }
127 // Prevent password fields to be overwritten with original value
128 if (value.length && $humanReadableField.attr('type') != 'password') {
129 $humanReadableField.val(value);
130 }
131 }
132
133 $humanReadableField.data('main-field', fieldName);
134 $humanReadableField.data('config', config);
135 $humanReadableField.on('change', function() {
136 FormEngineValidation.updateInputField($(this).attr('data-formengine-input-name'));
137 });
138 $humanReadableField.on('keyup', FormEngineValidation.validate);
139 };
140
141 /**
142 * Format field value
143 *
144 * @param {string} type
145 * @param {string} value
146 * @param {array} config
147 * @returns {string}
148 */
149 FormEngineValidation.formatValue = function(type, value, config) {
150 var theString = '';
151 switch (type) {
152 case 'date':
153 if (!parseInt(value)) {
154 return '';
155 }
156 theTime = new Date(parseInt(value) * 1000);
157 if (FormEngineValidation.USmode) {
158 theString = (theTime.getUTCMonth() + 1) + '-' + theTime.getUTCDate() + '-' + this.getYear(theTime);
159 } else {
160 theString = theTime.getUTCDate() + '-' + (theTime.getUTCMonth() + 1) + '-' + this.getYear(theTime);
161 }
162 break;
163 case 'datetime':
164 if (!parseInt(value)) {
165 return '';
166 }
167 theString = FormEngineValidation.formatValue('time', value, config) + ' ' + FormEngineValidation.formatValue('date', value, config);
168 break;
169 case 'time':
170 case 'timesec':
171 if (!parseInt(value)) {
172 return '';
173 }
174 var theTime = new Date(parseInt(value) * 1000);
175 var h = theTime.getUTCHours();
176 var m = theTime.getUTCMinutes();
177 var s = theTime.getUTCSeconds();
178 theString = h + ':' + ((m < 10) ? '0' : '') + m + ((type == 'timesec') ? ':' + ((s < 10) ? '0' : '') + s : '');
179 break;
180 case 'password':
181 theString = (value) ? FormEngineValidation.passwordDummy : '';
182 break;
183 default:
184 theString = value;
185 }
186 return theString;
187 };
188
189 /**
190 * Update input field after change
191 *
192 * @param {string} fieldName
193 */
194 FormEngineValidation.updateInputField = function(fieldName) {
195 var $field = $('[name="' + fieldName + '"]');
196 var $mainField = $('[name="' + $field.data('main-field') + '"]');
197 if ($mainField.length === 0) {
198 $mainField = $field;
199 }
200 var $humanReadableField = $('[data-formengine-input-name="' + $mainField.attr('name') + '"]');
201
202 var config = $mainField.data('config');
203 if (typeof config !== 'undefined') {
204 var evalList = FormEngineValidation.trimExplode(',', config.evalList);
205 var origValue = $humanReadableField.val();
206 var newValue = $humanReadableField.val();
207 var i;
208
209 for (i = 0; i < evalList.length; i++) {
210 newValue = FormEngineValidation.processValue(evalList[i], newValue, config);
211 }
212
213 var formattedValue = newValue;
214 for (i = 0; i < evalList.length; i++) {
215 formattedValue = FormEngineValidation.formatValue(evalList[i], formattedValue, config);
216 }
217
218 if ($.inArray('password', evalList) !== -1) {
219 $mainField.val(origValue);
220 $humanReadableField.val(newValue);
221 } else {
222 $mainField.val(newValue);
223 $humanReadableField.val(formattedValue);
224 }
225 }
226 };
227
228 /**
229 * Run validation for field
230 *
231 * @param {object} $field
232 * @param {string=} [value=$field.val()]
233 * @returns {string}
234 */
235 FormEngineValidation.validateField = function($field, value) {
236 value = value || FormEngineValidation.ltrim($field.val());
237
238 var rules = $field.data('formengine-validation-rules');
239 var markParent = false;
240 var selected = 0;
241 var returnValue = value;
242 var $relatedField;
243 $.each(rules, function(k, rule) {
244 switch (rule.type) {
245 case 'required':
246 if (value === '') {
247 markParent = true;
248 $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
249 }
250 break;
251 case 'range':
252 if (value !== '') {
253 if (rule.minItems || rule.maxItems) {
254 $relatedField = $(document).find('[name="' + $field.data('relatedfieldname') + '"]');
255 if ($relatedField.length) {
256 selected = FormEngineValidation.trimExplode(',', $relatedField.val()).length;
257 if (selected < rule.minItems || selected > rule.maxItems) {
258 markParent = true;
259 $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
260 }
261 } else {
262 selected = $field.val();
263 if (selected < rule.minItems || selected > rule.maxItems) {
264 markParent = true;
265 $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
266 }
267 }
268 }
269 if (rule.config.lower || rule.config.upper) {
270 var minValue = rule.config.lower || 0;
271 var maxValue = rule.config.upper || Number.MAX_VALUE;
272 if (value < minValue || value > maxValue) {
273 markParent = true;
274 $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
275 }
276 }
277 }
278 break;
279 case 'select':
280 if (rule.minItems || rule.maxItems) {
281 $relatedField = $(document).find('[name="' + $field.data('relatedfieldname') + '"]');
282 if ($relatedField.length) {
283 selected = FormEngineValidation.trimExplode(',', $relatedField.val()).length;
284 if (selected < rule.minItems || selected > rule.maxItems) {
285 markParent = true;
286 $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
287 }
288 } else {
289 selected = $field.find('option:selected').length;
290 if (selected < rule.minItems || selected > rule.maxItems) {
291 markParent = true;
292 $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
293 }
294 }
295 }
296 break;
297 case 'group':
298 if (rule.minItems || rule.maxItems) {
299 selected = $field.find('option').length;
300 if (selected < rule.minItems || selected > rule.maxItems) {
301 markParent = true;
302 $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
303 }
304 }
305 break;
306 case 'inline':
307 if (rule.minItems || rule.maxItems) {
308 selected = FormEngineValidation.trimExplode(',', $field.val()).length;
309 if (selected < rule.minItems || selected > rule.maxItems) {
310 markParent = true;
311 $field.closest(FormEngineValidation.markerSelector).addClass(FormEngineValidation.errorClass);
312 }
313 }
314 break;
315 case 'null':
316 // unknown type null, we ignore it
317 break;
318 default:
319 }
320 });
321 if (markParent) {
322 // check tabs
323 FormEngineValidation.markParentTab($field);
324 }
325 return returnValue;
326 };
327
328 /**
329 * Process a value by given command and config
330 *
331 * @param {string} command
332 * @param {string} value
333 * @param {array} config
334 * @returns {string}
335 */
336 FormEngineValidation.processValue = function(command, value, config) {
337 var newString = '';
338 var theValue = '';
339 var theCmd = '';
340 var a = 0;
341 var returnValue = value;
342 switch (command) {
343 case 'alpha':
344 case 'num':
345 case 'alphanum':
346 case 'alphanum_x':
347 newString = '';
348 for (a = 0; a < value.length; a++) {
349 theChar = value.substr(a, 1);
350 var special = (theChar === '_' || theChar === '-');
351 var alpha = (theChar >= 'a' && theChar <= 'z') || (theChar >= 'A' && theChar <= 'Z');
352 var num = (theChar >= '0' && theChar <= '9');
353 switch (command) {
354 case 'alphanum':
355 special = 0;
356 break;
357 case 'alpha':
358 num = 0;
359 special = 0;
360 break;
361 case 'num':
362 alpha = 0;
363 special = 0;
364 break;
365 }
366 if (alpha || num || theChar == ' ' || special) {
367 newString += theChar;
368 }
369 }
370 if (newString !== value) {
371 returnValue = newString;
372 }
373 break;
374 case 'is_in':
375 if (config.is_in) {
376 theValue = '' + value;
377 for (a = 0; a < theValue.length; a++) {
378 theChar = theValue.substr(a, 1);
379 if (config.is_in.indexOf(theChar) != -1) {
380 newString += theChar;
381 }
382 }
383 } else {
384 newString = theValue;
385 }
386 returnValue = newString;
387 break;
388 case 'nospace':
389 theValue = '' + value;
390 newString = '';
391 for (a = 0; a < theValue.length; a++) {
392 var theChar = theValue.substr(a, 1);
393 if (theChar != ' ') {
394 newString += theChar;
395 }
396 }
397 returnValue = newString;
398 break;
399 case 'md5':
400 if (value !== '') {
401 returnValue = MD5(value);
402 }
403 break;
404 case 'upper':
405 returnValue = value.toUpperCase();
406 break;
407 case 'lower':
408 returnValue = value.toLowerCase();
409 break;
410 case 'int':
411 if (value !== '') {
412 returnValue = FormEngineValidation.parseInt(value);
413 }
414 break;
415 case 'double2':
416 if (value !== '') {
417 returnValue = FormEngineValidation.parseDouble(value);
418 }
419 break;
420 case 'trim':
421 returnValue = FormEngineValidation.ltrim(FormEngineValidation.btrim(value));
422 break;
423 case 'datetime':
424 if (value !== '') {
425 theCmd = value.substr(0, 1);
426 returnValue = FormEngineValidation.parseDateTime(value, theCmd);
427 }
428 break;
429 case 'date':
430 if (value !== '') {
431 theCmd = value.substr(0, 1);
432 returnValue = FormEngineValidation.parseDate(value, theCmd);
433 }
434 break;
435 case 'time':
436 case 'timesec':
437 if (value !== '') {
438 theCmd = value.substr(0, 1);
439 returnValue = FormEngineValidation.parseTime(value, theCmd, command);
440 }
441 break;
442 case 'year':
443 if (value !== '') {
444 theCmd = value.substr(0, 1);
445 returnValue = FormEngineValidation.parseYear(value, theCmd);
446 }
447 break;
448 case 'null':
449 // unknown type null, we ignore it
450 break;
451 case 'password':
452 var theString = (value) ? FormEngineValidation.passwordDummy : '';
453 returnValue = theString;
454 break;
455 default:
456 if (typeof TBE_EDITOR.customEvalFunctions !== 'undefined' && typeof TBE_EDITOR.customEvalFunctions[command] === 'function') {
457 returnValue = TBE_EDITOR.customEvalFunctions[command](value);
458 }
459 }
460 return returnValue;
461 };
462
463 /**
464 * Validate the complete form
465 */
466 FormEngineValidation.validate = function() {
467 $(document).find(FormEngineValidation.markerSelector + ', .t3js-tabmenu-item')
468 .removeClass(FormEngineValidation.errorClass)
469 .removeClass('has-validation-error');
470
471 $(FormEngineValidation.rulesSelector).each(function() {
472 var $field = $(this);
473 var newValue = FormEngineValidation.validateField($field);
474 if (newValue.length && $field.val() !== newValue) {
475 $field.attr('value', newValue);
476 FormEngineValidation.setCaretPosition($field, 0);
477 }
478 });
479 };
480
481 /**
482 * Set the caret position in a text field
483 */
484 FormEngineValidation.setCaretPosition = function($element, caretPos) {
485 var elem = $element.get(0);
486
487 if (elem.createTextRange) {
488 var range = elem.createTextRange();
489 range.move('character', caretPos);
490 range.select();
491 } else {
492 if (elem.selectionStart) {
493 elem.focus();
494 elem.setSelectionRange(caretPos, caretPos);
495 } else {
496 elem.focus();
497 }
498 }
499 };
500
501 /**
502 * Helper function to get clean trimmed array from comma list
503 *
504 * @param {string} delimiter
505 * @param {string} string
506 * @returns {Array}
507 */
508 FormEngineValidation.trimExplode = function(delimiter, string) {
509 var result = [];
510 var items = string.split(delimiter);
511 for (var i=0; i<items.length; i++) {
512 var item = items[i].trim();
513 if (item.length > 0) {
514 result.push(item);
515 }
516 }
517 return result;
518 };
519
520 /**
521 * Parse value to integer
522 *
523 * @param {(number|string)} value
524 * @returns {number}
525 */
526 FormEngineValidation.parseInt = function(value) {
527 var theVal = '' + value;
528 if (!value) {
529 return 0;
530 }
531 for (var a = 0; a < theVal.length; a++) {
532 if (theVal.substr(a,1)!='0') {
533 return parseInt(theVal.substr(a,theVal.length)) || 0;
534 }
535 }
536 return 0;
537 };
538
539 /**
540 * Parse value to double
541 *
542 * @param {string} value
543 * @returns {string}
544 */
545 FormEngineValidation.parseDouble = function(value) {
546 var theVal = '' + value;
547 theVal = theVal.replace(/[^0-9,\.-]/g, '');
548 var negative = theVal.substring(0, 1) === '-';
549 theVal = theVal.replace(/-/g, '');
550 theVal = theVal.replace(/,/g, '.');
551 if (theVal.indexOf('.') === -1) {
552 theVal += '.0';
553 }
554 var parts = theVal.split('.');
555 var dec = parts.pop();
556 theVal = Number(parts.join('') + '.' + dec);
557 if (negative) {
558 theVal *= -1;
559 }
560 theVal = theVal.toFixed(2);
561
562 return theVal;
563 };
564
565 /**
566 *
567 * @param {string} value
568 * @returns {string}
569 */
570 FormEngineValidation.ltrim = function(value) {
571 var theVal = '' + value;
572 if (!value) {
573 return '';
574 }
575 for (var a = 0; a < theVal.length; a++) {
576 if (theVal.substr(a, 1) != ' ') {
577 return theVal.substr(a, theVal.length);
578 }
579 }
580 return '';
581 };
582
583 /**
584 *
585 * @param {string} value
586 * @returns {string}
587 */
588 FormEngineValidation.btrim = function(value) {
589 var theVal = '' + value;
590 if (!value) {
591 return '';
592 }
593 for (var a = theVal.length; a > 0; a--) {
594 if (theVal.substr(a-1, 1) != ' ') {
595 return theVal.substr(0, a);
596 }
597 }
598 return '';
599 };
600
601 /**
602 * Parse datetime value
603 *
604 * @param {string} value
605 * @param {string} command
606 * @returns {*}
607 */
608 FormEngineValidation.parseDateTime = function(value, command) {
609 var today = new Date();
610 var values = FormEngineValidation.split(value);
611 var add = 0;
612 switch (command) {
613 case 'd':
614 case 't':
615 case 'n':
616 FormEngineValidation.lastTime = FormEngineValidation.convertClientTimestampToUTC(FormEngineValidation.getTimestamp(today), 0);
617 if (values.valPol[1]) {
618 add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
619 }
620 break;
621 case '+':
622 case '-':
623 if (FormEngineValidation.lastTime == 0) {
624 FormEngineValidation.lastTime = FormEngineValidation.convertClientTimestampToUTC(FormEngineValidation.getTimestamp(today), 0);
625 }
626 if (values.valPol[1]) {
627 add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
628 }
629 break;
630 default:
631 var index = value.indexOf(' ');
632 if (index != -1) {
633 var dateVal = FormEngineValidation.parseDate(value.substr(index, value.length), value.substr(0, 1));
634 // set refDate so that evalFunc_input on time will work with correct DST information
635 FormEngineValidation.refDate = new Date(dateVal * 1000);
636 FormEngineValidation.lastTime = dateVal + FormEngineValidation.parseTime(value.substr(0,index), value.substr(0, 1), 'time');
637 } else {
638 // only date, no time
639 FormEngineValidation.lastTime = FormEngineValidation.parseDate(value, value.substr(0, 1));
640 }
641 }
642 FormEngineValidation.lastTime += add * 24 * 60 * 60;
643 return FormEngineValidation.lastTime;
644 };
645
646 /**
647 * Parse date value
648 *
649 * @param {string} value
650 * @param {string} command
651 * @returns {*}
652 */
653 FormEngineValidation.parseDate = function(value, command) {
654 var today = new Date();
655 var values = FormEngineValidation.split(value);
656 var add = 0;
657 switch (command) {
658 case 'd':
659 case 't':
660 case 'n':
661 FormEngineValidation.lastDate = FormEngineValidation.getTimestamp(today);
662 if (values.valPol[1]) {
663 add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
664 }
665 break;
666 case '+':
667 case '-':
668 if (values.valPol[1]) {
669 add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
670 }
671 break;
672 default:
673 var index = 4;
674 if (values.valPol[index]) {
675 add = FormEngineValidation.pol(values.valPol[index], FormEngineValidation.parseInt(values.values[index]));
676 }
677 if (values.values[1] && values.values[1].length > 2) {
678 if (values.valPol[2]) {
679 add = FormEngineValidation.pol(values.valPol[2], FormEngineValidation.parseInt(values.values[2]));
680 }
681 var temp = values.values[1];
682 values = FormEngineValidation.splitSingle(temp);
683 }
684
685 var year = (values.values[3]) ? FormEngineValidation.parseInt(values.values[3]) : FormEngineValidation.getYear(today);
686 if ((year >= 0 && year < 38) || (year >= 70 && year < 100) || (year >= 1902 && year < 2038)) {
687 if (year < 100) {
688 year = (year < 38) ? year += 2000 : year += 1900;
689 }
690 } else {
691 year = FormEngineValidation.getYear(today);
692 }
693 var usMode = FormEngineValidation.USmode ? 1 : 2;
694 var month = (values.values[usMode]) ? FormEngineValidation.parseInt(values.values[usMode]) : today.getUTCMonth() + 1;
695 usMode = FormEngineValidation.USmode ? 2 : 1;
696 var day = (values.values[usMode]) ? FormEngineValidation.parseInt(values.values[usMode]) : today.getUTCDate();
697
698 var theTime = new Date(parseInt(year), parseInt(month)-1, parseInt(day));
699
700 // Substract timezone offset from client
701 FormEngineValidation.lastDate = FormEngineValidation.convertClientTimestampToUTC(FormEngineValidation.getTimestamp(theTime), 0);
702 }
703 FormEngineValidation.lastDate += add * 24 * 60 * 60;
704 return FormEngineValidation.lastDate;
705 };
706
707 /**
708 * Parse time value
709 *
710 * @param {string} value
711 * @param {string} command
712 * @param {string} type
713 * @returns {*}
714 */
715 FormEngineValidation.parseTime = function(value, command, type) {
716 var today = new Date();
717 var values = FormEngineValidation.split(value);
718 var add = 0;
719 switch (command) {
720 case 'd':
721 case 't':
722 case 'n':
723 FormEngineValidation.lastTime = FormEngineValidation.getTimeSecs(today);
724 if (values.valPol[1]) {
725 add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
726 }
727 break;
728 case '+':
729 case '-':
730 if (FormEngineValidation.lastTime == 0) {
731 FormEngineValidation.lastTime = FormEngineValidation.getTimeSecs(today);
732 }
733 if (values.valPol[1]) {
734 add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
735 }
736 break;
737 default:
738 var index = (type == 'timesec') ? 4 : 3;
739 if (values.valPol[index]) {
740 add = FormEngineValidation.pol(values.valPol[index], FormEngineValidation.parseInt(values.values[index]));
741 }
742 if (values.values[1] && values.values[1].length > 2) {
743 if (values.valPol[2]) {
744 add = FormEngineValidation.pol(values.valPol[2], FormEngineValidation.parseInt(values.values[2]));
745 }
746 var temp = values.values[1];
747 values = FormEngineValidation.splitSingle(temp);
748 }
749 var sec = (values.values[3]) ? FormEngineValidation.parseInt(values.values[3]) : today.getUTCSeconds();
750 if (sec > 59) {
751 sec = 59;
752 }
753 var min = (values.values[2]) ? FormEngineValidation.parseInt(values.values[2]) : today.getUTCMinutes();
754 if (min > 59) {
755 min = 59;
756 }
757 var hour = (values.values[1]) ? FormEngineValidation.parseInt(values.values[1]) : today.getUTCHours();
758 if (hour >= 24) {
759 hour = 0;
760 }
761
762 var theTime = new Date(FormEngineValidation.getYear(FormEngineValidation.refDate), FormEngineValidation.refDate.getUTCMonth(), FormEngineValidation.refDate.getUTCDate(), hour, min, (( type == 'timesec' ) ? sec : 0));
763
764 // Substract timezone offset from client
765 FormEngineValidation.lastTime = FormEngineValidation.convertClientTimestampToUTC(FormEngineValidation.getTimestamp(theTime), 1);
766 }
767 FormEngineValidation.lastTime += add * 60;
768 if (FormEngineValidation.lastTime < 0) {
769 FormEngineValidation.lastTime += 24 * 60 * 60;
770 }
771 return FormEngineValidation.lastTime;
772 };
773
774 /**
775 * Parse year value
776 *
777 * @param {string} value
778 * @param {string} command
779 * @returns {*}
780 */
781 FormEngineValidation.parseYear = function(value, command) {
782 var today = new Date();
783 var values = FormEngineValidation.split(value);
784 var add = 0;
785 switch (command) {
786 case 'd':
787 case 't':
788 case 'n':
789 FormEngineValidation.lastYear = FormEngineValidation.getYear(today);
790 if (values.valPol[1]) {
791 add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
792 }
793 break;
794 case '+':
795 case '-':
796 if (values.valPol[1]) {
797 add = FormEngineValidation.pol(values.valPol[1], FormEngineValidation.parseInt(values.values[1]));
798 }
799 break;
800 default:
801 if (values.valPol[2]) {
802 add = FormEngineValidation.pol(values.valPol[2], FormEngineValidation.parseInt(values.values[2]));
803 }
804 var year = (values.values[1]) ? FormEngineValidation.parseInt(values.values[1]) : FormEngineValidation.getYear(today);
805 if ((year >= 0 && year < 38) || (year >= 70 && year<100) || (year >= 1902 && year < 2038)) {
806 if (year < 100) {
807 year = (year < 38) ? year += 2000 : year += 1900;
808 }
809 } else {
810 year = FormEngineValidation.getYear(today);
811 }
812 FormEngineValidation.lastYear = year;
813 }
814 FormEngineValidation.lastYear += add;
815 return FormEngineValidation.lastYear;
816 };
817
818 /**
819 * Get year from date object
820 *
821 * @param {Date} timeObj
822 * @returns {?number}
823 */
824 FormEngineValidation.getYear = function(timeObj) {
825 if (timeObj === null) {
826 return null;
827 }
828 return timeObj.getUTCFullYear();
829 };
830
831 /**
832 * Get date as timestamp from Date object
833 *
834 * @param {Date} timeObj
835 * @returns {number}
836 */
837 FormEngineValidation.getDate = function(timeObj) {
838 var theTime = new Date(FormEngineValidation.getYear(timeObj), timeObj.getUTCMonth(), timeObj.getUTCDate());
839 return FormEngineValidation.getTimestamp(theTime);
840 };
841
842 /**
843 *
844 * @param {string} foreign
845 * @param {string} value
846 * @returns {Object}
847 */
848 FormEngineValidation.pol = function(foreign, value) {
849 return eval(((foreign == '-') ? '-' : '') + value);
850 };
851
852 /**
853 * Substract timezone offset from client to a timestamp to get UTC-timestamp to be send to server
854 *
855 * @param {number} timestamp
856 * @param {number} timeonly
857 * @returns {*}
858 */
859 FormEngineValidation.convertClientTimestampToUTC = function(timestamp, timeonly) {
860 var timeObj = new Date(timestamp*1000);
861 timeObj.setTime((timestamp - timeObj.getTimezoneOffset()*60)*1000);
862 if (timeonly) {
863 // only seconds since midnight
864 return FormEngineValidation.getTime(timeObj);
865 } else {
866 // seconds since the "unix-epoch"
867 return FormEngineValidation.getTimestamp(timeObj);
868 }
869 };
870
871 /**
872 * Parse date string or object and return unix timestamp
873 *
874 * @param {(string|Date)} timeObj
875 * @returns {number}
876 */
877 FormEngineValidation.getTimestamp = function(timeObj) {
878 return Date.parse(timeObj)/1000;
879 };
880
881 /**
882 * Seconds since midnight
883 *
884 * @param timeObj
885 * @returns {*}
886 */
887 FormEngineValidation.getTime = function(timeObj) {
888 return timeObj.getUTCHours() * 60 * 60 + timeObj.getUTCMinutes() * 60 + FormEngineValidation.getSecs(timeObj);
889 };
890
891 /**
892 *
893 * @param timeObj
894 * @returns {number}
895 */
896 FormEngineValidation.getSecs = function(timeObj) {
897 return timeObj.getUTCSeconds();
898 };
899
900 /**
901 *
902 * @param timeObj
903 * @returns {number}
904 */
905 FormEngineValidation.getTimeSecs = function(timeObj) {
906 return timeObj.getHours() * 60 * 60 + timeObj.getMinutes() * 60 + timeObj.getSeconds();
907 };
908
909 /**
910 * Find tab by field and mark it as has-validation-error
911 *
912 * @param {object} $element
913 */
914 FormEngineValidation.markParentTab = function($element) {
915 var $panes = $element.parents('.tab-pane');
916 $panes.each(function() {
917 var $pane = $(this);
918 var id = $pane.attr('id');
919 $(document)
920 .find('a[href="#' + id + '"]')
921 .closest('.t3js-tabmenu-item')
922 .addClass('has-validation-error');
923 });
924 };
925
926 /**
927 *
928 * @param value
929 * @returns {{values: Array, pointer: number}}
930 */
931 FormEngineValidation.splitSingle = function(value) {
932 var theVal = '' + value;
933 var result = {
934 values: [],
935 pointer: 3
936 };
937 result.values[1] = theVal.substr(0,2);
938 result.values[2] = theVal.substr(2,2);
939 result.values[3] = theVal.substr(4,10);
940 return result;
941 };
942
943 /**
944 *
945 * @param theStr1
946 * @param delim
947 * @param index
948 * @returns {*}
949 */
950 FormEngineValidation.splitStr = function(theStr1, delim, index) {
951 var theStr = '' + theStr1;
952 var lengthOfDelim = delim.length;
953 var sPos = -lengthOfDelim;
954 if (index < 1) {
955 index = 1;
956 }
957 for (var a = 1; a < index; a++) {
958 sPos = theStr.indexOf(delim, sPos + lengthOfDelim);
959 if (sPos == -1) {
960 return null;
961 }
962 }
963 var ePos = theStr.indexOf(delim, sPos + lengthOfDelim);
964 if (ePos == -1) {
965 ePos = theStr.length;
966 }
967 return (theStr.substring(sPos + lengthOfDelim, ePos));
968 };
969
970 /**
971 *
972 * @param value
973 * @returns {{values: Array, valPol: Array, pointer: number, numberMode: number, theVal: string}}
974 */
975 FormEngineValidation.split = function(value) {
976 var result = {
977 values: [],
978 valPol: [],
979 pointer: 0,
980 numberMode: 0,
981 theVal: ''
982 };
983 value += ' ';
984 for (var a=0; a < value.length; a++) {
985 var theChar = value.substr(a, 1);
986 if (theChar < '0' || theChar > '9') {
987 if (result.numberMode) {
988 result.pointer++;
989 result.values[result.pointer] = result.theVal;
990 result.theVal = '';
991 result.numberMode = 0;
992 }
993 if (theChar == '+' || theChar == '-') {
994 result.valPol[result.pointer + 1] = theChar;
995 }
996 } else {
997 result.theVal += theChar;
998 result.numberMode = 1;
999 }
1000 }
1001 return result;
1002 };
1003
1004 FormEngineValidation.registerReady = function() {
1005 $(function() {
1006 FormEngineValidation.initialize();
1007 // Start first validation after one second, because all fields are initial empty (typo3form.fieldSet)
1008 window.setTimeout(function() {
1009 FormEngineValidation.validate();
1010 }, 1000);
1011 });
1012 };
1013
1014 FormEngine.Validation = FormEngineValidation;
1015
1016 return FormEngine.Validation;
1017 });