[TASK] Flash message warning for max number of IRRE items
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / FormEngine.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Form\Element\AbstractFormElement;
18 use TYPO3\CMS\Backend\Form\Element\InlineElement;
19 use TYPO3\CMS\Backend\Template\DocumentTemplate;
20 use TYPO3\CMS\Backend\Utility\BackendUtility;
21 use TYPO3\CMS\Backend\Utility\IconUtility;
22 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
23 use TYPO3\CMS\Core\Database\DatabaseConnection;
24 use TYPO3\CMS\Core\Html\HtmlParser;
25 use TYPO3\CMS\Core\Messaging\FlashMessage;
26 use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
27 use TYPO3\CMS\Core\Messaging\FlashMessageService;
28 use TYPO3\CMS\Core\Utility\ArrayUtility;
29 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
30 use TYPO3\CMS\Core\Utility\GeneralUtility;
31 use TYPO3\CMS\Core\Utility\MathUtility;
32 use TYPO3\CMS\Core\Utility\PathUtility;
33 use TYPO3\CMS\Lang\LanguageService;
34
35 /**
36 * 'TCEforms' - Class for creating the backend editing forms.
37 *
38 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
39 * @coauthor René Fritz <r.fritz@colorcube.de>
40 */
41 class FormEngine {
42
43 /**
44 * @var string A CSS class name prefix for all element types, single elements add their type to this string
45 */
46 protected $cssClassTypeElementPrefix = 't3-formengine-field-';
47
48 /**
49 * @var array
50 */
51 public $palFieldArr = array();
52
53 /**
54 * @var bool
55 */
56 public $disableWizards = FALSE;
57
58 /**
59 * @var bool
60 */
61 public $isPalettedoc = FALSE;
62
63 /**
64 * @var int
65 */
66 public $paletteMargin = 1;
67
68 /**
69 * @var string
70 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
71 */
72 public $defStyle = '';
73
74 /**
75 * @var array
76 */
77 public $cachedTSconfig = array();
78
79 /**
80 * @var array
81 */
82 public $cachedTSconfig_fieldLevel = array();
83
84 /**
85 * @var array
86 */
87 public $cachedLanguageFlag = array();
88
89 /**
90 * @var array|NULL
91 */
92 public $cachedAdditionalPreviewLanguages = NULL;
93
94 /**
95 * @var array
96 */
97 public $transformedRow = array();
98
99 /**
100 * @var string
101 */
102 public $extJSCODE = '';
103
104 /**
105 * @var array
106 */
107 public $printNeededJS = array();
108
109 /**
110 * @var array
111 */
112 public $hiddenFieldAccum = array();
113
114 /**
115 * @var string
116 */
117 public $TBE_EDITOR_fieldChanged_func = '';
118
119 /**
120 * @var bool
121 */
122 public $loadMD5_JS = TRUE;
123
124 /**
125 * Array where records in the default language is stored. (processed by transferdata)
126 *
127 * @var array
128 */
129 public $defaultLanguageData = array();
130
131 /**
132 * Array where records in the default language is stored (raw without any processing. used for making diff)
133 *
134 * @var array
135 */
136 public $defaultLanguageData_diff = array();
137
138 /**
139 * @var array
140 */
141 public $additionalPreviewLanguageData = array();
142
143 /**
144 * Set this to the 'backPath' pointing back to the typo3 admin directory
145 * from the script where this form is displayed.
146 *
147 * @var string
148 */
149 public $backPath = '';
150
151 /**
152 * Alternative return URL path (default is \TYPO3\CMS\Core\Utility\GeneralUtility::linkThisScript())
153 *
154 * @var string
155 */
156 public $returnUrl = '';
157
158 /**
159 * Can be set to point to a field name in the form which will be set to '1' when the form
160 * is submitted with a *save* button. This way the recipient script can determine that
161 * the form was submitted for save and not "close" for example.
162 *
163 * @var string
164 */
165 public $doSaveFieldName = '';
166
167 /**
168 * Can be set TRUE/FALSE to whether palettes (secondary options) are in the topframe or in form.
169 * TRUE means they are NOT IN-form. So a collapsed palette is one, which is shown in the top frame, not in the page.
170 *
171 * @var bool
172 */
173 public $palettesCollapsed = FALSE;
174
175 /**
176 * If set, the RTE is disabled (from form display, eg. by checkbox in the bottom of the page!)
177 *
178 * @var bool
179 */
180 public $disableRTE = FALSE;
181
182 /**
183 * If FALSE, then all CSH will be disabled, regardless of settings in $this->edit_showFieldHelp
184 *
185 * @var bool
186 */
187 public $globalShowHelp = TRUE;
188
189 /**
190 * If this evaluates to TRUE, the forms are rendering only localization relevant fields of the records.
191 *
192 * @var string
193 */
194 public $localizationMode = '';
195
196 /**
197 * Overrule the field order set in TCA[types][showitem], eg for tt_content this value,
198 * 'bodytext,image', would make first the 'bodytext' field, then the 'image' field (if set for display)...
199 * and then the rest in the old order.
200 *
201 * @var string
202 */
203 public $fieldOrder = '';
204
205 /**
206 * If set to FALSE, palettes will NEVER be rendered.
207 *
208 * @var bool
209 */
210 public $doPrintPalette = TRUE;
211
212 /**
213 * Set to initialized clipboard object;
214 * Then the element browser will offer a link to paste in records from clipboard.
215 *
216 * @var \TYPO3\CMS\Backend\Clipboard\Clipboard|NULL
217 */
218 public $clipObj = NULL;
219
220 /**
221 * Enable click menu on reference icons.
222 *
223 * @var bool
224 */
225 public $enableClickMenu = FALSE;
226
227 /**
228 * @var bool
229 */
230 public $enableTabMenu = FALSE;
231
232 /**
233 * When enabled all fields are rendered non-editable
234 *
235 * @var bool
236 */
237 protected $renderReadonly = FALSE;
238
239 /**
240 * Form field width compensation: Factor of "size=12" to "style="width: 12*9.58px"
241 * for form field widths of style-aware browsers
242 *
243 * @var float
244 */
245 public $form_rowsToStylewidth = 9.58;
246
247 /**
248 * Value that gets added for style="width: ...px" for textareas compared to input fields.
249 *
250 * @var int
251 */
252 protected $form_additionalTextareaStyleWidth = 23;
253
254 /**
255 * Form field width compensation: Compensation for large documents, doc-tab (editing)
256 *
257 * @var float
258 */
259 public $form_largeComp = 1.33;
260
261 /**
262 * The number of chars expected per row when the height of a text area field is
263 * automatically calculated based on the number of characters found in the field content.
264 *
265 * @var int
266 */
267 public $charsPerRow = 40;
268
269 /**
270 * The maximum abstract value for textareas
271 *
272 * @var int
273 */
274 public $maxTextareaWidth = 48;
275
276 /**
277 * The maximum abstract value for input fields
278 *
279 * @var int
280 */
281 public $maxInputWidth = 48;
282
283 /**
284 * Default style for the selector boxes used for multiple items in "select" and "group" types.
285 *
286 * @var string
287 */
288 public $defaultMultipleSelectorStyle = 'width:310px;';
289
290 // INTERNAL, static
291 /**
292 * The string to prepend formfield names with.
293 *
294 * @var string
295 */
296 public $prependFormFieldNames = 'data';
297
298 /**
299 * The string to prepend commands for tcemain::process_cmdmap with
300 *
301 * @var string
302 */
303 public $prependCmdFieldNames = 'cmd';
304
305 /**
306 * The string to prepend FILE form field names with
307 *
308 * @var string
309 */
310 public $prependFormFieldNames_file = 'data_files';
311
312 /**
313 * The string to prepend form field names that are active (not NULL)
314 *
315 * @var string
316 */
317 protected $prependFormFieldNamesActive = 'control[active]';
318
319 /**
320 * The name attribute of the form
321 *
322 * @var string
323 */
324 public $formName = 'editform';
325
326 /**
327 * Whitelist that allows TCA field configuration to be overridden by TSconfig
328 *
329 * @see overrideFieldConf()
330 * @var array
331 */
332 public $allowOverrideMatrix = array();
333
334 /**
335 * Set by readPerms() (caching)
336 *
337 * @var string
338 */
339 public $perms_clause = '';
340
341 /**
342 * Set by readPerms() (caching-flag)
343 *
344 * @var bool
345 */
346 public $perms_clause_set = FALSE;
347
348 /**
349 * Used to indicate the mode of CSH (Context Sensitive Help),
350 * whether it should be icons-only ('icon') or not at all (blank).
351 *
352 * @var bool
353 */
354 public $edit_showFieldHelp = FALSE;
355
356 /**
357 * @var bool
358 */
359 public $edit_docModuleUpload = FALSE;
360
361 /**
362 * Loaded with info about the browser when class is instantiated
363 *
364 * @var array
365 */
366 public $clientInfo = array();
367
368 /**
369 * TRUE, if RTE is possible for the current user (based on result from BE_USER->isRTE())
370 *
371 * @var bool
372 */
373 public $RTEenabled = FALSE;
374
375 /**
376 * If $this->RTEenabled was FALSE, you can find the reasons listed in this array
377 * which is filled with reasons why the RTE could not be loaded)
378 *
379 * @var string
380 */
381 public $RTEenabled_notReasons = '';
382
383 /**
384 * Counter that is incremented before an RTE is created. Can be used for unique ids etc.
385 *
386 * @var int
387 */
388 public $RTEcounter = 0;
389
390 /**
391 * Contains current color scheme
392 *
393 * @var array
394 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
395 */
396 public $colorScheme = array();
397
398 /**
399 * Contains current class scheme
400 *
401 * @var array
402 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
403 */
404 public $classScheme = array();
405
406 /**
407 * Contains the default color scheme
408 *
409 * @var array
410 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
411 */
412 public $defColorScheme = array();
413
414 /**
415 * Contains the default class scheme
416 *
417 * @var array
418 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
419 */
420 public $defClassScheme = array();
421
422 /**
423 * Contains field style values
424 *
425 * @var array|NULL
426 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
427 */
428 public $fieldStyle = NULL;
429
430 /**
431 * Contains border style values
432 *
433 * @var array|NULL
434 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
435 */
436 public $borderStyle = NULL;
437
438 /**
439 * An accumulation of messages from the class
440 *
441 * @var array
442 */
443 public $commentMessages = array();
444
445 /**
446 * Total wrapping for the table rows
447 *
448 * @var string
449 */
450 public $totalWrap = '<hr />|<hr />';
451
452 /**
453 * Field template
454 *
455 * @var string
456 */
457 public $fieldTemplate = '<strong>###FIELD_NAME###</strong><br />###FIELD_ITEM###<hr />';
458
459 /**
460 * Template subpart for palette fields
461 *
462 * @var string
463 */
464 protected $paletteFieldTemplate = '';
465
466 /**
467 * Wrapping template code for a section
468 *
469 * @var string
470 * @deprecatd since TYPO3 CMS 7, will be removed in CMS 8
471 */
472 public $sectionWrap = '';
473
474 /**
475 * Template for palette headers
476 *
477 * @var string
478 */
479 public $palFieldTemplateHeader = '';
480
481 /**
482 * Template for palettes
483 *
484 * @var string
485 */
486 public $palFieldTemplate = '';
487
488 /**
489 * Set to the fields NOT to display, if any
490 *
491 * @var array|NULL
492 */
493 public $excludeElements = NULL;
494
495 /**
496 * During rendering of forms this will keep track of which palettes
497 * has already been rendered (so they are not rendered twice by mistake)
498 *
499 * @var array
500 */
501 public $palettesRendered = array();
502
503 /**
504 * This array of fields will be set as hidden-fields instead of rendered normally!
505 * For instance palette fields edited in the top frame are set as hidden fields
506 * since the main form has to submit the values.
507 * The top frame actually just sets the value in the main form!
508 *
509 * @var array
510 */
511 public $hiddenFieldListArr = array();
512
513 /**
514 * Used to register input-field names, which are required. (Done during rendering of the fields).
515 * This information is then used later when the JavaScript is made.
516 *
517 * @var array
518 */
519 public $requiredFields = array();
520
521 /**
522 * Used to register input-field names, which are required an have additional requirements.
523 * (e.g. like a date/time must be positive integer)
524 * The information of this array is merged with $this->requiredFields later.
525 *
526 * @var array
527 */
528 public $requiredAdditional = array();
529
530 /**
531 * Used to register the min and max number of elements
532 * for selector boxes where that apply (in the "group" type for instance)
533 *
534 * @var array
535 */
536 public $requiredElements = array();
537
538 /**
539 * Used to determine where $requiredFields or $requiredElements are nested (in Tabs or IRRE)
540 *
541 * @var array
542 */
543 public $requiredNested = array();
544
545 /**
546 * Keeps track of the rendering depth of nested records
547 *
548 * @var int
549 */
550 public $renderDepth = 0;
551
552 /**
553 * Color scheme buffer
554 *
555 * @var array
556 */
557 public $savedSchemes = array();
558
559 /**
560 * holds the path an element is nested in (e.g. required for RTEhtmlarea)
561 *
562 * @var array
563 */
564 public $dynNestedStack = array();
565
566 // Internal, registers for user defined functions etc.
567 /**
568 * Additional HTML code, printed before the form
569 *
570 * @var array
571 */
572 public $additionalCode_pre = array();
573
574 /**
575 * Additional JavaScript, printed before the form
576 *
577 * @var array
578 */
579 public $additionalJS_pre = array();
580
581 /**
582 * Additional JavaScript printed after the form
583 *
584 * @var array
585 */
586 public $additionalJS_post = array();
587
588 /**
589 * Additional JavaScript executed on submit; If you set "OK" variable it will raise an error
590 * about RTEs not being loaded and offer to block further submission.
591 *
592 * @var array
593 */
594 public $additionalJS_submit = array();
595
596 /**
597 * Additional JavaScript executed when section element is deleted.
598 * This is necessary, for example, to correctly clean up HTMLArea RTE (bug #8232)
599 *
600 * @var array
601 */
602 public $additionalJS_delete = array();
603
604 /**
605 * @var \TYPO3\CMS\Backend\Form\Element\InlineElement
606 */
607 public $inline;
608
609 /**
610 * Array containing hook class instances called once for a form
611 *
612 * @var array
613 */
614 public $hookObjectsMainFields = array();
615
616 /**
617 * Array containing hook class instances called for each field
618 *
619 * @var array
620 */
621 public $hookObjectsSingleField = array();
622
623 /**
624 * Rows getting inserted into the alt_doc headers (when called from alt_doc.php)
625 *
626 * @var array
627 */
628 public $extraFormHeaders = array();
629
630 /**
631 * Form template, relative to typo3 directory
632 *
633 * @var string
634 */
635 public $templateFile = '';
636
637 /**
638 * @var \TYPO3\CMS\Backend\Form\Element\SuggestElement
639 */
640 protected $suggest;
641
642 /**
643 * protected properties which were public
644 * use old property name as key and new property name as value
645 * e.g. 'foo_BarName' => 'fooBarName'
646 *
647 * For each property a getter and setter method must be implemented!
648 * @see __set() and __get()
649 * @var array
650 */
651 protected $protectedProperties = array(
652 'renderReadonly' => 'renderReadonly'
653 );
654
655 /**
656 * Constructor function, setting internal variables, loading the styles used.
657 *
658 */
659 public function __construct() {
660 $this->clientInfo = GeneralUtility::clientInfo();
661 $this->RTEenabled = $this->getBackendUserAuthentication()->isRTE();
662 if (!$this->RTEenabled) {
663 $this->RTEenabled_notReasons = implode(LF, $this->getBackendUserAuthentication()->RTE_errors);
664 $this->commentMessages[] = 'RTE NOT ENABLED IN SYSTEM due to:' . LF . $this->RTEenabled_notReasons;
665 }
666 // Define whitelist that allows TCA field configuration to be overridden by TSconfig, @see overrideFieldConf():
667 $this->allowOverrideMatrix = array(
668 'input' => array('size', 'max', 'readOnly'),
669 'text' => array('cols', 'rows', 'wrap', 'readOnly'),
670 'check' => array('cols', 'showIfRTE', 'readOnly'),
671 'select' => array('size', 'autoSizeMax', 'maxitems', 'minitems', 'readOnly', 'treeConfig'),
672 'group' => array('size', 'autoSizeMax', 'max_size', 'show_thumbs', 'maxitems', 'minitems', 'disable_controls', 'readOnly'),
673 'inline' => array('appearance', 'behaviour', 'foreign_label', 'foreign_selector', 'foreign_unique', 'maxitems', 'minitems', 'size', 'autoSizeMax', 'symmetric_label', 'readOnly')
674 );
675 // Create instance of InlineElement only if this a non-IRRE-AJAX call:
676 if (!isset($GLOBALS['ajaxID']) || strpos($GLOBALS['ajaxID'], \TYPO3\CMS\Backend\Form\Element\InlineElement::class . '::') !== 0) {
677 $this->inline = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\InlineElement::class);
678 }
679 // Create instance of \TYPO3\CMS\Backend\Form\Element\SuggestElement only if this a non-Suggest-AJAX call:
680 if (!isset($GLOBALS['ajaxID']) || strpos($GLOBALS['ajaxID'], \TYPO3\CMS\Backend\Form\Element\SuggestElement::class . '::') !== 0) {
681 $this->suggest = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\SuggestElement::class);
682 }
683 // Prepare user defined objects (if any) for hooks which extend this function:
684 $this->hookObjectsMainFields = array();
685 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getMainFieldsClass'])) {
686 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getMainFieldsClass'] as $classRef) {
687 $this->hookObjectsMainFields[] = GeneralUtility::getUserObj($classRef);
688 }
689 }
690 $this->hookObjectsSingleField = array();
691 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getSingleFieldClass'])) {
692 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getSingleFieldClass'] as $classRef) {
693 $this->hookObjectsSingleField[] = GeneralUtility::getUserObj($classRef);
694 }
695 }
696 $this->templateFile = 'sysext/backend/Resources/Private/Templates/FormEngine.html';
697 }
698
699 /**
700 * Fallback method to protect public properties
701 * This is only a temporary solution and will be removed in TYPO3 CMS 8
702 *
703 * @param string $name name of the property
704 * @param mixed $value value of the property
705 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
706 */
707 public function __set($name, $value) {
708 if (array_key_exists($name, $this->protectedProperties)) {
709 $method = 'set' . ucfirst($this->protectedProperties[$name]);
710 if (is_callable(array($this, $method))) {
711 GeneralUtility::deprecationLog('direct access to "FormEngine::$' . $name . '" is deprecated, use "FormEngine::' . $method . '()" instead.');
712 call_user_func_array(array($this, $method), array($value));
713 }
714 }
715 }
716
717 /**
718 * Fallback method to protect public properties
719 * This is only a temporary solution and will be removed in TYPO3 CMS 8
720 *
721 * @param string $name name of the property
722 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
723 */
724 public function __get($name) {
725 if (array_key_exists($name, $this->protectedProperties)) {
726 $method = 'get' . ucfirst($this->protectedProperties[$name]);
727 if (is_callable(array($this, $method))) {
728 GeneralUtility::deprecationLog('direct access to "FormEngine::$' . $name . '" is deprecated, use "FormEngine::' . $method . '()" instead.');
729 call_user_func(array($this, $method));
730 }
731 }
732 }
733
734 /**
735 * Set render read only flag
736 *
737 * @param bool $value
738 */
739 public function setRenderReadonly($value) {
740 $this->renderReadonly = (bool)$value;
741 }
742
743 /**
744 * Get render readonly flag
745 *
746 * @return bool
747 */
748 public function getRenderReadonly() {
749 return $this->renderReadonly;
750 }
751
752 /**
753 * Initialize various internal variables.
754 *
755 * @return void
756 */
757 public function initDefaultBEmode() {
758 $this->prependFormFieldNames = 'data';
759 $this->formName = 'editform';
760 $this->setNewBEDesign();
761 $this->edit_showFieldHelp = (bool)$this->getBackendUserAuthentication()->uc['edit_showFieldHelp'];
762 $this->edit_docModuleUpload = (bool)$this->getBackendUserAuthentication()->uc['edit_docModuleUpload'];
763 $this->inline->init($this);
764 $this->suggest->init($this);
765 }
766
767 /*******************************************************
768 *
769 * Rendering the forms, fields etc
770 *
771 *******************************************************/
772 /**
773 * Will return the TCEform element for just a single field from a record.
774 * The field must be listed in the currently displayed fields (as found in [types][showitem]) for the record.
775 * This also means that the $table/$row supplied must be complete so the list of fields to show can be found correctly
776 *
777 * @param string $table The table name
778 * @param array $row The record from the table for which to render a field.
779 * @param string $theFieldToReturn The field name to return the TCEform element for.
780 * @return string HTML output
781 * @see getMainFields()
782 */
783 public function getSoloField($table, $row, $theFieldToReturn) {
784 if (!isset($GLOBALS['TCA'][$table])) {
785 return '';
786 }
787 $typeNum = $this->getRTypeNum($table, $row);
788 if (isset($GLOBALS['TCA'][$table]['types'][$typeNum])) {
789 $itemList = $GLOBALS['TCA'][$table]['types'][$typeNum]['showitem'];
790 if ($itemList) {
791 $fields = GeneralUtility::trimExplode(',', $itemList, TRUE);
792 $excludeElements = ($this->excludeElements = $this->getExcludeElements($table, $row, $typeNum));
793 foreach ($fields as $fieldInfo) {
794 $parts = explode(';', $fieldInfo);
795 $theField = trim($parts[0]);
796 if (!in_array($theField, $excludeElements) && (string)$theField === (string)$theFieldToReturn) {
797 if ($GLOBALS['TCA'][$table]['columns'][$theField]) {
798 $sField = $this->getSingleField($table, $theField, $row, $parts[1], 1, $parts[3], $parts[2]);
799 return $sField['ITEM'];
800 }
801 }
802 }
803 }
804 }
805 return '';
806 }
807
808 /**
809 * Based on the $table and $row of content, this displays the complete TCEform for the record.
810 * The input-$row is required to be preprocessed if necessary by eg.
811 * the \TYPO3\CMS\Backend\Form\DataPreprocessor class. For instance the RTE content
812 * should be transformed through this class first.
813 *
814 * @param string $table The table name
815 * @param array $row The record from the table for which to render a field.
816 * @param int $depth Depth level
817 * @param array $overruleTypesArray Overrule types array. Can be used to override the showitem etc. configuration for the TCA types of the table. Can contain all settings which are possible in the TCA 'types' section. See e.g. $TCA['tt_content']['types'].
818 * @return string HTML output
819 * @see getSoloField()
820 */
821 public function getMainFields($table, array $row, $depth = 0, array $overruleTypesArray = array()) {
822 $languageService = $this->getLanguageService();
823 $this->renderDepth = $depth;
824 // Init vars:
825 $out_array = array(array());
826 $out_array_meta = array(
827 array(
828 'title' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.generalTab'),
829 ),
830 );
831 $out_pointer = 0;
832 $out_sheet = 0;
833 $this->palettesRendered = array();
834 $this->palettesRendered[$this->renderDepth][$table] = array();
835 // Hook: getMainFields_preProcess (requested by Thomas Hempel for use with the "dynaflex" extension)
836 foreach ($this->hookObjectsMainFields as $hookObj) {
837 if (method_exists($hookObj, 'getMainFields_preProcess')) {
838 $hookObj->getMainFields_preProcess($table, $row, $this);
839 }
840 }
841 $tabIdentString = '';
842 $tabIdentStringMD5 = '';
843 if ($GLOBALS['TCA'][$table]) {
844 // Load the description content for the table.
845 if ($this->edit_showFieldHelp || $this->doLoadTableDescr($table)) {
846 $languageService->loadSingleTableDescription($table);
847 }
848 // Get the current "type" value for the record.
849 $typeNum = $this->getRTypeNum($table, $row);
850 // Find the list of fields to display:
851 if ($GLOBALS['TCA'][$table]['types'][$typeNum]) {
852 $itemList = $GLOBALS['TCA'][$table]['types'][$typeNum]['showitem'];
853 if (is_array($overruleTypesArray) && isset($overruleTypesArray[$typeNum]['showitem'])) {
854 $itemList = $overruleTypesArray[$typeNum]['showitem'];
855 }
856 // If such a list existed...
857 if ($itemList) {
858 // Explode the field list and possibly rearrange the order of the fields, if configured for
859 $fields = GeneralUtility::trimExplode(',', $itemList, TRUE);
860 if ($this->fieldOrder) {
861 $fields = $this->rearrange($fields);
862 }
863 // Get excluded fields, added fiels and put it together:
864 $excludeElements = ($this->excludeElements = $this->getExcludeElements($table, $row, $typeNum));
865 $fields = $this->mergeFieldsWithAddedFields($fields, $this->getFieldsToAdd($table, $row, $typeNum), $table);
866 // If TCEforms will render a tab menu in the next step, push the name to the tab stack:
867 if (strstr($itemList, '--div--') !== FALSE && $this->enableTabMenu) {
868 $tabIdentString = 'TCEforms:' . $table . ':' . $row['uid'];
869 $tabIdentStringMD5 = $this->getDocumentTemplate()->getDynTabMenuId($tabIdentString);
870 // Remember that were currently working on the general tab:
871 if (isset($fields[0]) && strpos($fields[0], '--div--') !== 0) {
872 $this->pushToDynNestedStack('tab', $tabIdentStringMD5 . '-1');
873 }
874 }
875 // Traverse the fields to render:
876 $cc = 0;
877 foreach ($fields as $fieldInfo) {
878 // Exploding subparts of the field configuration:
879 // this is documented as this:
880 // fieldname;fieldlabel;paletteidorlinebreaktodisplay;extradata;colorscheme
881 // fieldname can also be "--div--" or "--palette--"
882 // the last option colorscheme was dropped with TYPO3 CMS 7
883
884 list($theField, $fieldLabel, $additionalPalette, $extraFieldProcessingData) = explode(';', $fieldInfo);
885
886 // Render the field:
887 if (!in_array($theField, $excludeElements)) {
888 if ($GLOBALS['TCA'][$table]['columns'][$theField]) {
889 $sFieldPal = '';
890 if ($additionalPalette && !isset($this->palettesRendered[$this->renderDepth][$table][$additionalPalette])) {
891 $sFieldPal = $this->getPaletteFields($table, $row, $additionalPalette);
892 $this->palettesRendered[$this->renderDepth][$table][$additionalPalette] = 1;
893 }
894 $sField = $this->getSingleField($table, $theField, $row, $fieldLabel, 0, $extraFieldProcessingData, $additionalPalette);
895 if ($sField) {
896 $sField .= $sFieldPal;
897 }
898 $out_array[$out_sheet][$out_pointer] .= $sField;
899 } elseif ($theField == '--div--') {
900 if ($cc > 0) {
901 if ($this->enableTabMenu) {
902 // Remove last tab entry from the dynNestedStack:
903 $out_sheet++;
904 // Remove the previous sheet from stack (if any):
905 $this->popFromDynNestedStack('tab', $tabIdentStringMD5 . '-' . $out_sheet);
906 // Remember on which sheet we're currently working:
907 $this->pushToDynNestedStack('tab', $tabIdentStringMD5 . '-' . ($out_sheet + 1));
908 $out_array[$out_sheet] = array();
909 $out_array_meta[$out_sheet]['title'] = $languageService->sL($fieldLabel);
910 // Register newline for Tab
911 $out_array_meta[$out_sheet]['newline'] = $additionalPalette == 'newline';
912 }
913 } else {
914 // Setting alternative title for "General" tab if "--div--" is the very first element.
915 $out_array_meta[$out_sheet]['title'] = $languageService->sL($fieldLabel);
916 // Only add the first tab to the dynNestedStack if there are more tabs:
917 if ($tabIdentString && strpos($itemList, '--div--', strlen($fieldInfo))) {
918 $this->pushToDynNestedStack('tab', $tabIdentStringMD5 . '-1');
919 }
920 }
921 } elseif ($theField == '--palette--') {
922 if ($additionalPalette && !isset($this->palettesRendered[$this->renderDepth][$table][$additionalPalette])) {
923 // Render a 'header' if not collapsed
924 if ($GLOBALS['TCA'][$table]['palettes'][$additionalPalette]['canNotCollapse'] && $fieldLabel) {
925 $out_array[$out_sheet][$out_pointer] .= $this->getPaletteFields($table, $row, $additionalPalette, $languageService->sL($fieldLabel));
926 } else {
927 $out_array[$out_sheet][$out_pointer] .= $this->getPaletteFields($table, $row, $additionalPalette, '', '', $languageService->sL($fieldLabel));
928 }
929 $this->palettesRendered[$this->renderDepth][$table][$additionalPalette] = 1;
930 }
931 }
932 }
933 $cc++;
934 }
935 }
936 }
937 }
938 // Hook: getMainFields_postProcess (requested by Thomas Hempel for use with the "dynaflex" extension)
939 foreach ($this->hookObjectsMainFields as $hookObj) {
940 if (method_exists($hookObj, 'getMainFields_postProcess')) {
941 $hookObj->getMainFields_postProcess($table, $row, $this);
942 }
943 }
944 // Rendering Main palettes, if any
945 $mParr = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['mainpalette']);
946 $i = 0;
947 if (count($mParr)) {
948 foreach ($mParr as $mP) {
949 if (!isset($this->palettesRendered[$this->renderDepth][$table][$mP])) {
950 $temp_palettesCollapsed = $this->palettesCollapsed;
951 $this->palettesCollapsed = FALSE;
952 $label = $i == 0
953 ? $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.generalOptions')
954 : $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.generalOptions_more');
955 $out_array[$out_sheet][$out_pointer] .= $this->getPaletteFields($table, $row, $mP, $label);
956 $this->palettesCollapsed = $temp_palettesCollapsed;
957 $this->palettesRendered[$this->renderDepth][$table][$mP] = 1;
958 }
959 $i++;
960 if ($this->renderDepth) {
961 $this->renderDepth--;
962 }
963 }
964 }
965 // Return the imploded $out_array:
966 // Create parts array for the tab menu:
967 $parts = array();
968 foreach ($out_array as $idx => $sheetContent) {
969 $content = implode('', $sheetContent);
970 if ($content) {
971 // Wrap content (row) with table-tag, otherwise tab/sheet will be disabled (see getdynTabMenu() )
972 $content = '<table border="0" cellspacing="0" cellpadding="0" width="100%">' . $content . '</table>';
973 }
974 $parts[$idx] = array(
975 'label' => $out_array_meta[$idx]['title'],
976 'content' => $content,
977 'newline' => $out_array_meta[$idx]['newline']
978 );
979 }
980 if (count($parts) > 1) {
981 // Unset the current level of tab menus:
982 $this->popFromDynNestedStack('tab', $tabIdentStringMD5 . '-' . ($out_sheet + 1));
983 $output = $this->getDynTabMenu($parts, $tabIdentString);
984 } else {
985 // If there is only one tab/part there is no need to wrap it into the dynTab code
986 $output = isset($parts[0]) ? trim($parts[0]['content']) : '';
987 }
988 // Only one tab, so just implode and wrap the background image (= tab container) around:
989 if ($out_sheet === 0) {
990 $output = '<div class="typo3-dyntabmenu-divs">' . $output . '</div>';
991 }
992 $output = '
993 <tr>
994 <td colspan="2">
995 ' . $output . '
996 </td>
997 </tr>';
998
999 return $output;
1000 }
1001
1002 /**
1003 * Will return the TCEform elements for a pre-defined list of fields.
1004 * Notice that this will STILL use the configuration found in the list [types][showitem] for those fields which are found there. So ideally the list of fields given as argument to this function should also be in the current [types][showitem] list of the record.
1005 * Used for displaying forms for the frontend edit icons for instance.
1006 *
1007 * @param string $table The table name
1008 * @param array $row The record array.
1009 * @param string $list Commalist of fields from the table. These will be shown in the specified order in a form.
1010 * @return string TCEform elements in a string.
1011 */
1012 public function getListedFields($table, $row, $list) {
1013 if ($this->edit_showFieldHelp || $this->doLoadTableDescr($table)) {
1014 $this->getLanguageService()->loadSingleTableDescription($table);
1015 }
1016 $out = '';
1017 $types_fieldConfig = BackendUtility::getTCAtypes($table, $row, 1);
1018 $editFieldList = array_unique(GeneralUtility::trimExplode(',', $list, TRUE));
1019 foreach ($editFieldList as $theFieldC) {
1020 list($theField, $palFields) = preg_split('/\\[|\\]/', $theFieldC);
1021 $theField = trim($theField);
1022 $palFields = trim($palFields);
1023 if ($GLOBALS['TCA'][$table]['columns'][$theField]) {
1024 $parts = GeneralUtility::trimExplode(';', $types_fieldConfig[$theField]['origString']);
1025 // Don't sent palette pointer - there are no options anyways for a field-list.
1026 $sField = $this->getSingleField($table, $theField, $row, $parts[1], 0, $parts[3], 0);
1027 $out .= $sField;
1028 }
1029 if ($palFields) {
1030 $out .= $this->getPaletteFields($table, $row, '', '', implode(',', GeneralUtility::trimExplode('|', $palFields, TRUE)));
1031 }
1032 }
1033 return $out;
1034 }
1035
1036 /**
1037 * Creates a palette (collection of secondary options).
1038 *
1039 * @param string $table The table name
1040 * @param array $row The row array
1041 * @param string $palette The palette number/pointer
1042 * @param string $header Header string for the palette (used when in-form). If not set, no header item is made.
1043 * @param string $itemList Optional alternative list of fields for the palette
1044 * @param string $collapsedHeader Optional Link text for activating a palette (when palettes does not have another form element to belong to).
1045 * @return string HTML code.
1046 */
1047 public function getPaletteFields($table, $row, $palette, $header = '', $itemList = '', $collapsedHeader = NULL) {
1048 if (!$this->doPrintPalette) {
1049 return '';
1050 }
1051 $out = '';
1052 $parts = $this->loadPaletteElements($table, $row, $palette, $itemList);
1053 // Put palette together if there are fields in it:
1054 if (count($parts)) {
1055 $realFields = 0;
1056 foreach ($parts as $part) {
1057 if ($part['NAME'] !== '--linebreak--') {
1058 $realFields++;
1059 }
1060 }
1061 if ($realFields > 0) {
1062 if ($header) {
1063 $out .= $this->intoTemplate(array('HEADER' => htmlspecialchars($header)), $this->palFieldTemplateHeader);
1064 }
1065 $collapsed = $this->isPalettesCollapsed($table, $palette);
1066 // Check if the palette is a hidden palette
1067 $isHiddenPalette = !empty($GLOBALS['TCA'][$table]['palettes'][$palette]['isHiddenPalette']);
1068 $thePalIcon = '';
1069 if ($collapsed && $collapsedHeader !== NULL && !$isHiddenPalette) {
1070 list($thePalIcon, ) = $this->wrapOpenPalette(
1071 IconUtility::getSpriteIcon(
1072 'actions-system-options-view',
1073 array('title' => htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.moreOptions')))
1074 ),
1075 $table,
1076 $row,
1077 $palette,
1078 1
1079 );
1080 $thePalIcon = '<span style="margin-left: 20px;">' . $thePalIcon . $collapsedHeader . '</span>';
1081 }
1082 $paletteHtml = $this->wrapPaletteField($this->printPalette($parts), $table, $row, $palette, $collapsed);
1083 $out .= $this->intoTemplate(array('PALETTE' => $thePalIcon . $paletteHtml), $this->palFieldTemplate);
1084 }
1085 }
1086 return $out;
1087 }
1088
1089 /**
1090 * Returns the form HTML code for a database table field.
1091 *
1092 * @param string $table The table name
1093 * @param string $field The field name
1094 * @param array $row The record to edit from the database table.
1095 * @param string $altName Alternative field name label to show.
1096 * @param bool $palette Set this if the field is on a palette (in top frame), otherwise not. (if set, field will render as a hidden field).
1097 * @param string $extra The "extra" options from "Part 4" of the field configurations found in the "types" "showitem" list. Typically parsed by $this->getSpecConfFromString() in order to get the options as an associative array.
1098 * @param int $pal The palette pointer.
1099 * @return mixed String (normal) or array (palettes)
1100 */
1101 public function getSingleField($table, $field, $row, $altName = '', $palette = FALSE, $extra = '', $pal = 0) {
1102 // Hook: getSingleField_preProcess
1103 foreach ($this->hookObjectsSingleField as $hookObj) {
1104 if (method_exists($hookObj, 'getSingleField_preProcess')) {
1105 $hookObj->getSingleField_preProcess($table, $field, $row, $altName, $palette, $extra, $pal, $this);
1106 }
1107 }
1108 $out = '';
1109 $PA = array();
1110 $PA['altName'] = $altName;
1111 $PA['palette'] = $palette;
1112 $PA['extra'] = $extra;
1113 $PA['pal'] = $pal;
1114 // Get the TCA configuration for the current field:
1115 $PA['fieldConf'] = $GLOBALS['TCA'][$table]['columns'][$field];
1116 $PA['fieldConf']['config']['form_type'] = $PA['fieldConf']['config']['form_type'] ?: $PA['fieldConf']['config']['type'];
1117
1118 // Using "form_type" locally in this script
1119 $skipThisField = $this->inline->skipField($table, $field, $row, $PA['fieldConf']['config']);
1120
1121 // Evaluate display condition
1122 $displayConditionResult = TRUE;
1123 if (is_array($PA['fieldConf']) && $PA['fieldConf']['displayCond'] && is_array($row)) {
1124 /** @var $elementConditionMatcher \TYPO3\CMS\Backend\Form\ElementConditionMatcher */
1125 $elementConditionMatcher = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\ElementConditionMatcher::class);
1126 $displayConditionResult = $elementConditionMatcher->match($PA['fieldConf']['displayCond'], $row);
1127 }
1128 // Check if this field is configured and editable (according to excludefields + other configuration)
1129 if (
1130 is_array($PA['fieldConf'])
1131 && !$skipThisField
1132 && (!$PA['fieldConf']['exclude'] || $this->getBackendUserAuthentication()->check('non_exclude_fields', $table . ':' . $field))
1133 && $PA['fieldConf']['config']['form_type'] != 'passthrough'
1134 && ($this->RTEenabled || !$PA['fieldConf']['config']['showIfRTE'])
1135 && $displayConditionResult
1136 && (!$GLOBALS['TCA'][$table]['ctrl']['languageField'] || $PA['fieldConf']['l10n_display'] || ($PA['fieldConf']['l10n_mode'] !== 'exclude') || $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] <= 0)
1137 && (!$GLOBALS['TCA'][$table]['ctrl']['languageField'] || !$this->localizationMode || $this->localizationMode === $PA['fieldConf']['l10n_cat'])
1138 ) {
1139 // Fetching the TSconfig for the current table/field. This includes the $row which means that
1140 $PA['fieldTSConfig'] = $this->setTSconfig($table, $row, $field);
1141 // If the field is NOT disabled from TSconfig (which it could have been) then render it
1142 if (!$PA['fieldTSConfig']['disabled']) {
1143 // Override fieldConf by fieldTSconfig:
1144 $PA['fieldConf']['config'] = $this->overrideFieldConf($PA['fieldConf']['config'], $PA['fieldTSConfig']);
1145 // Init variables:
1146 $PA['itemFormElName'] = $this->prependFormFieldNames . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
1147 // Form field name, in case of file uploads
1148 $PA['itemFormElName_file'] = $this->prependFormFieldNames_file . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
1149 // Form field name, to activate elements
1150 // If the "eval" list contains "null", elements can be deactivated which results in storing NULL to database
1151 $PA['itemFormElNameActive'] = $this->prependFormFieldNamesActive . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
1152 // The value to show in the form field.
1153 $PA['itemFormElValue'] = $row[$field];
1154 $PA['itemFormElID'] = $this->prependFormFieldNames . '_' . $table . '_' . $row['uid'] . '_' . $field;
1155 // Set field to read-only if configured for translated records to show default language content as readonly
1156 if ($PA['fieldConf']['l10n_display'] && GeneralUtility::inList($PA['fieldConf']['l10n_display'], 'defaultAsReadonly') && $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0) {
1157 $PA['fieldConf']['config']['readOnly'] = TRUE;
1158 $PA['itemFormElValue'] = $this->defaultLanguageData[$table . ':' . $row['uid']][$field];
1159 }
1160 if (strpos($GLOBALS['TCA'][$table]['ctrl']['type'], ':') === FALSE) {
1161 $typeField = $GLOBALS['TCA'][$table]['ctrl']['type'];
1162 } else {
1163 $typeField = substr($GLOBALS['TCA'][$table]['ctrl']['type'], 0, strpos($GLOBALS['TCA'][$table]['ctrl']['type'], ':'));
1164 }
1165 // Create a JavaScript code line which will ask the user to save/update the form due to changing the element. This is used for eg. "type" fields and others configured with "requestUpdate"
1166 if (
1167 !empty($GLOBALS['TCA'][$table]['ctrl']['type'])
1168 && $field === $typeField
1169 || !empty($GLOBALS['TCA'][$table]['ctrl']['requestUpdate'])
1170 && GeneralUtility::inList(str_replace(' ', '', $GLOBALS['TCA'][$table]['ctrl']['requestUpdate']), $field)
1171 ) {
1172 if ($this->getBackendUserAuthentication()->jsConfirmation(1)) {
1173 $alertMsgOnChange = 'if (confirm(TBE_EDITOR.labels.onChangeAlert) && TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
1174 } else {
1175 $alertMsgOnChange = 'if (TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
1176 }
1177 } else {
1178 $alertMsgOnChange = '';
1179 }
1180 // Render as a hidden field?
1181 if (in_array($field, $this->hiddenFieldListArr)) {
1182 $this->hiddenFieldAccum[] = '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
1183 } else {
1184 $languageService = $this->getLanguageService();
1185 // Render as a normal field:
1186 // If the field is NOT a palette field, then we might create an icon which links to a palette for the field, if one exists.
1187 $palJSfunc = '';
1188 $thePalIcon = '';
1189 if (!$PA['palette']) {
1190 $paletteFields = $this->loadPaletteElements($table, $row, $PA['pal']);
1191 if ($PA['pal'] && $this->isPalettesCollapsed($table, $PA['pal']) && count($paletteFields)) {
1192 list($thePalIcon, $palJSfunc) = $this->wrapOpenPalette(
1193 IconUtility::getSpriteIcon(
1194 'actions-system-options-view',
1195 array('title' => htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.moreOptions')))
1196 ),
1197 $table,
1198 $row,
1199 $PA['pal'],
1200 1
1201 );
1202 }
1203 }
1204 // onFocus attribute to add to the field:
1205 $PA['onFocus'] = $palJSfunc && !$this->getBackendUserAuthentication()->uc['dontShowPalettesOnFocusInAB'] ? ' onfocus="' . htmlspecialchars($palJSfunc) . '"' : '';
1206 $PA['label'] = $PA['altName'] ?: $PA['fieldConf']['label'];
1207 $PA['label'] = $PA['fieldTSConfig']['label'] ?: $PA['label'];
1208 $PA['label'] = $PA['fieldTSConfig']['label.'][$languageService->lang] ?: $PA['label'];
1209 $PA['label'] = $languageService->sL($PA['label']);
1210 // JavaScript code for event handlers:
1211 $PA['fieldChangeFunc'] = array();
1212 $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'TBE_EDITOR.fieldChanged(\'' . $table . '\',\'' . $row['uid'] . '\',\'' . $field . '\',\'' . $PA['itemFormElName'] . '\');';
1213 $PA['fieldChangeFunc']['alert'] = $alertMsgOnChange;
1214 // If this is the child of an inline type and it is the field creating the label
1215 if ($this->inline->isInlineChildAndLabelField($table, $field)) {
1216 $inlineObjectId = implode(InlineElement::Structure_Separator, array(
1217 $this->inline->inlineNames['object'],
1218 $table,
1219 $row['uid']
1220 ));
1221 $PA['fieldChangeFunc']['inline'] = 'inline.handleChangedField(\'' . $PA['itemFormElName'] . '\',\'' . $inlineObjectId . '\');';
1222 }
1223 // Based on the type of the item, call a render function:
1224 $item = $this->getSingleField_SW($table, $field, $row, $PA);
1225 // Add language + diff
1226 if ($PA['fieldConf']['l10n_display'] && (GeneralUtility::inList($PA['fieldConf']['l10n_display'], 'hideDiff') || GeneralUtility::inList($PA['fieldConf']['l10n_display'], 'defaultAsReadonly'))) {
1227 $renderLanguageDiff = FALSE;
1228 } else {
1229 $renderLanguageDiff = TRUE;
1230 }
1231 if ($renderLanguageDiff) {
1232 $item = $this->renderDefaultLanguageContent($table, $field, $row, $item);
1233 $item = $this->renderDefaultLanguageDiff($table, $field, $row, $item);
1234 }
1235 // If the record has been saved and the "linkTitleToSelf" is set, we make the field name into a link, which will load ONLY this field in alt_doc.php
1236 $label = htmlspecialchars($PA['label'], ENT_COMPAT, 'UTF-8', FALSE);
1237 if (MathUtility::canBeInterpretedAsInteger($row['uid']) && $PA['fieldTSConfig']['linkTitleToSelf'] && !GeneralUtility::_GP('columnsOnly')) {
1238 $lTTS_url = $this->backPath . 'alt_doc.php?edit[' . $table . '][' . $row['uid'] . ']=edit&columnsOnly=' . $field . '&returnUrl=' . rawurlencode($this->thisReturnUrl());
1239 $label = '<a href="' . htmlspecialchars($lTTS_url) . '">' . $label . '</a>';
1240 }
1241
1242 if (isset($PA['fieldConf']['config']['mode']) && $PA['fieldConf']['config']['mode'] == 'useOrOverridePlaceholder') {
1243 $placeholder = $this->getPlaceholderValue($table, $field, $PA['fieldConf']['config'], $row);
1244 $onChange = 'typo3form.fieldTogglePlaceholder(' . GeneralUtility::quoteJSvalue($PA['itemFormElName']) . ', !this.checked)';
1245 $checked = $PA['itemFormElValue'] === NULL ? '' : ' checked="checked"';
1246
1247 $this->additionalJS_post[] = 'typo3form.fieldTogglePlaceholder('
1248 . GeneralUtility::quoteJSvalue($PA['itemFormElName']) . ', ' . ($checked ? 'false' : 'true') . ');';
1249
1250 $item = '<div class="t3-form-field-placeholder-override">'
1251 . '<span class="t3-tceforms-placeholder-override-checkbox">' .
1252 '<input type="hidden" name="' . htmlspecialchars($PA['itemFormElNameActive']) . '" value="0" />' .
1253 '<input type="checkbox" name="' . htmlspecialchars($PA['itemFormElNameActive']) . '" value="1" id="tce-forms-textfield-use-override-' . $field . '-' . $row['uid'] . '" onchange="' . htmlspecialchars($onChange) . '"' . $checked . ' />' .
1254 '<label for="tce-forms-textfield-use-override-' . $field . '-' . $row['uid'] . '">' .
1255 sprintf($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.placeholder.override'),
1256 BackendUtility::getRecordTitlePrep($placeholder, 20)) . '</label>' .
1257 '</span>'
1258 . '<div class="t3-form-placeholder-placeholder">' . $this->getSingleField_typeNone_render(
1259 $PA['fieldConf']['config'], GeneralUtility::fixed_lgd_cs($placeholder, 30)
1260 ) . '</div>'
1261 . '<div class="t3-form-placeholder-formfield">' . $item . '</div>'
1262 . '</div>';
1263 }
1264
1265 // Wrap the label with help text
1266 $PA['label'] = ($label = BackendUtility::wrapInHelp($table, $field, $label));
1267 // Create output value:
1268 if ($PA['fieldConf']['config']['form_type'] == 'user' && $PA['fieldConf']['config']['noTableWrapping']) {
1269 $out = $item;
1270 } elseif ($PA['palette']) {
1271 // Array:
1272 $out = array(
1273 'NAME' => $label,
1274 'ID' => $row['uid'],
1275 'FIELD' => $field,
1276 'TABLE' => $table,
1277 'ITEM' => $item,
1278 'ITEM_DISABLED' => ($this->isDisabledNullValueField($table, $field, $row, $PA) ? ' disabled' : ''),
1279 'ITEM_NULLVALUE' => $this->renderNullValueWidget($table, $field, $row, $PA),
1280 );
1281 $out = $this->addUserTemplateMarkers($out, $table, $field, $row, $PA);
1282 } else {
1283 // String:
1284 $out = array(
1285 'NAME' => $label,
1286 'ITEM' => $item,
1287 'TABLE' => $table,
1288 'ID' => $row['uid'],
1289 'PAL_LINK_ICON' => $thePalIcon,
1290 'FIELD' => $field,
1291 'ITEM_DISABLED' => ($this->isDisabledNullValueField($table, $field, $row, $PA) ? ' disabled' : ''),
1292 'ITEM_NULLVALUE' => $this->renderNullValueWidget($table, $field, $row, $PA),
1293 );
1294 $out = $this->addUserTemplateMarkers($out, $table, $field, $row, $PA);
1295 // String:
1296 $out = $this->intoTemplate($out);
1297 }
1298 }
1299 } else {
1300 $this->commentMessages[] = $this->prependFormFieldNames . '[' . $table . '][' . $row['uid'] . '][' . $field . ']: Disabled by TSconfig';
1301 }
1302 }
1303 // Hook: getSingleField_postProcess
1304 foreach ($this->hookObjectsSingleField as $hookObj) {
1305 if (method_exists($hookObj, 'getSingleField_postProcess')) {
1306 $hookObj->getSingleField_postProcess($table, $field, $row, $out, $PA, $this);
1307 }
1308 }
1309 // Return value (string or array)
1310 return $out;
1311 }
1312
1313 /**
1314 * Rendering a single item for the form
1315 *
1316 * @param string $table Table name of record
1317 * @param string $field Fieldname to render
1318 * @param array $row The record
1319 * @param array $PA Parameters array containing a lot of stuff. Value by Reference!
1320 * @return string Returns the item as HTML code to insert
1321 * @access private
1322 * @see getSingleField(), getSingleField_typeFlex_draw()
1323 */
1324 public function getSingleField_SW($table, $field, $row, &$PA) {
1325 $PA['fieldConf']['config']['form_type'] = $PA['fieldConf']['config']['form_type'] ?: $PA['fieldConf']['config']['type'];
1326 // Using "form_type" locally in this script
1327 // Hook: getSingleField_beforeRender
1328 foreach ($this->hookObjectsSingleField as $hookObject) {
1329 if (method_exists($hookObject, 'getSingleField_beforeRender')) {
1330 $hookObject->getSingleField_beforeRender($table, $field, $row, $PA);
1331 }
1332 }
1333 $type = $PA['fieldConf']['config']['form_type'];
1334 if ($type === 'inline') {
1335 $item = $this->inline->getSingleField_typeInline($table, $field, $row, $PA);
1336 } else {
1337 $typeClassNameMapping = array(
1338 'input' => 'InputElement',
1339 'text' => 'TextElement',
1340 'check' => 'CheckboxElement',
1341 'radio' => 'RadioElement',
1342 'select' => 'SelectElement',
1343 'group' => 'GroupElement',
1344 'none' => 'NoneElement',
1345 'user' => 'UserElement',
1346 'flex' => 'FlexElement',
1347 'unknown' => 'UnknownElement',
1348 );
1349 if (!isset($typeClassNameMapping[$type])) {
1350 $type = 'unknown';
1351 }
1352 $formElement = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\Element\\' . $typeClassNameMapping[$type], $this);
1353 if ($formElement instanceof AbstractFormElement) {
1354 $formElement->setRenderReadonly($this->getRenderReadonly());
1355 }
1356 $item = $formElement->render($table, $field, $row, $PA);
1357 }
1358 return $item;
1359 }
1360
1361 /**********************************************************
1362 *
1363 * Rendering of each TCEform field type
1364 *
1365 ************************************************************/
1366 /**
1367 * Generation of TCEform elements of the type "input"
1368 * This will render a single-line input form field, possibly with various control/validation features
1369 *
1370 * @param string $table The table name of the record
1371 * @param string $field The field name which this element is supposed to edit
1372 * @param array $row The record data array where the value(s) for the field can be found
1373 * @param array $PA An array with additional configuration options.
1374 * @return string The HTML code for the TCEform field
1375 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\InputElement
1376 */
1377 public function getSingleField_typeInput($table, $field, $row, &$PA) {
1378 GeneralUtility::logDeprecatedFunction();
1379 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\InputElement::class, $this)
1380 ->render($table, $field, $row, $PA);
1381 }
1382
1383 /**
1384 * Renders a view widget to handle and activate NULL values.
1385 * The widget is enabled by using 'null' in the 'eval' TCA definition.
1386 *
1387 * @param string $table Name of the table
1388 * @param string $field Name of the field
1389 * @param array $row Accordant data of the record row
1390 * @param array $PA Parameters array with rendering instructions
1391 * @return string Widget (if any).
1392 */
1393 protected function renderNullValueWidget($table, $field, array $row, array $PA) {
1394 $widget = '';
1395
1396 $config = $PA['fieldConf']['config'];
1397 if (
1398 !empty($config['eval']) && GeneralUtility::inList($config['eval'], 'null')
1399 && (empty($config['mode']) || $config['mode'] !== 'useOrOverridePlaceholder')
1400 ) {
1401 $checked = $PA['itemFormElValue'] === NULL ? '' : ' checked="checked"';
1402 $onChange = htmlspecialchars(
1403 'typo3form.fieldSetNull(\'' . $PA['itemFormElName'] . '\', !this.checked)'
1404 );
1405
1406 $widget = '<span class="t3-tceforms-widget-null-wrapper">' .
1407 '<input type="hidden" name="' . $PA['itemFormElNameActive'] . '" value="0" />' .
1408 '<input type="checkbox" name="' . $PA['itemFormElNameActive'] . '" value="1" onchange="' . $onChange . '"' . $checked . ' />' .
1409 '</span>';
1410 }
1411
1412 return $widget;
1413 }
1414
1415 /**
1416 * Determines whether the current field value is considered as NULL value.
1417 * Using NULL values is enabled by using 'null' in the 'eval' TCA definition.
1418 *
1419 * @param string $table Name of the table
1420 * @param string $field Name of the field
1421 * @param array $row Accordant data
1422 * @param array $PA Parameters array with rendering instructions
1423 * @return bool
1424 */
1425 protected function isDisabledNullValueField($table, $field, array $row, array $PA) {
1426 $result = FALSE;
1427
1428 $config = $PA['fieldConf']['config'];
1429 if ($PA['itemFormElValue'] === NULL && !empty($config['eval'])
1430 && GeneralUtility::inList($config['eval'], 'null')
1431 && (empty($config['mode']) || $config['mode'] !== 'useOrOverridePlaceholder')) {
1432
1433 $result = TRUE;
1434 }
1435
1436 return $result;
1437 }
1438
1439 /**
1440 * Generation of TCEform elements of the type "text"
1441 * This will render a <textarea> OR RTE area form field, possibly with various control/validation features
1442 *
1443 * @param string $table The table name of the record
1444 * @param string $field The field name which this element is supposed to edit
1445 * @param array $row The record data array where the value(s) for the field can be found
1446 * @param array $PA An array with additional configuration options.
1447 * @return string The HTML code for the TCEform field
1448 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\TextElement
1449 */
1450 public function getSingleField_typeText($table, $field, $row, &$PA) {
1451 GeneralUtility::logDeprecatedFunction();
1452 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\TextElement::class, $this)
1453 ->setRenderReadonly($this->getRenderReadonly())
1454 ->render($table, $field, $row, $PA);
1455 }
1456
1457 /**
1458 * Generation of TCEform elements of the type "check"
1459 * This will render a check-box OR an array of checkboxes
1460 *
1461 * @param string $table The table name of the record
1462 * @param string $field The field name which this element is supposed to edit
1463 * @param array $row The record data array where the value(s) for the field can be found
1464 * @param array $PA An array with additional configuration options.
1465 * @return string The HTML code for the TCEform field
1466 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\CheckboxElement
1467 */
1468 public function getSingleField_typeCheck($table, $field, $row, &$PA) {
1469 GeneralUtility::logDeprecatedFunction();
1470 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\CheckboxElement::class, $this)
1471 ->setRenderReadonly($this->getRenderReadonly())
1472 ->render($table, $field, $row, $PA);
1473 }
1474
1475 /**
1476 * Generation of TCEform elements of the type "radio"
1477 * This will render a series of radio buttons.
1478 *
1479 * @param string $table The table name of the record
1480 * @param string $field The field name which this element is supposed to edit
1481 * @param array $row The record data array where the value(s) for the field can be found
1482 * @param array $PA An array with additional configuration options.
1483 * @return string The HTML code for the TCEform field
1484 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\RadioElement
1485 */
1486 public function getSingleField_typeRadio($table, $field, $row, &$PA) {
1487 GeneralUtility::logDeprecatedFunction();
1488 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\RadioElement::class, $this)
1489 ->setRenderReadonly($this->getRenderReadonly())
1490 ->render($table, $field, $row, $PA);
1491 }
1492
1493 /**
1494 * Generation of TCEform elements of the type "select"
1495 * This will render a selector box element, or possibly a special construction with two selector boxes.
1496 * That depends on configuration.
1497 *
1498 * @param string $table The table name of the record
1499 * @param string $field The field name which this element is supposed to edit
1500 * @param array $row The record data array where the value(s) for the field can be found
1501 * @param array $PA An array with additional configuration options.
1502 * @return string The HTML code for the TCEform field
1503 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\SelectElement
1504 */
1505 public function getSingleField_typeSelect($table, $field, $row, &$PA) {
1506 GeneralUtility::logDeprecatedFunction();
1507 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\SelectElement::class, $this)
1508 ->setRenderReadonly($this->getRenderReadonly())
1509 ->render($table, $field, $row, $PA);
1510 }
1511
1512 /**
1513 * Generation of TCEform elements of the type "group"
1514 * This will render a selectorbox into which elements from either the file system or database can be inserted. Relations.
1515 *
1516 * @param string $table The table name of the record
1517 * @param string $field The field name which this element is supposed to edit
1518 * @param array $row The record data array where the value(s) for the field can be found
1519 * @param array $PA An array with additional configuration options.
1520 * @return string The HTML code for the TCEform field
1521 * @deprecated since 7.0 - will be removed two versions later; Use \TYPO3\CMS\Backend\Form\Element\GroupElement
1522 */
1523 public function getSingleField_typeGroup($table, $field, $row, &$PA) {
1524 GeneralUtility::logDeprecatedFunction();
1525 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\GroupElement::class, $this)
1526 ->setRenderReadonly($this->getRenderReadonly())
1527 ->render($table, $field, $row, $PA);
1528 }
1529
1530 /**
1531 * Generation of TCEform elements of the type "none"
1532 * This will render a non-editable display of the content of the field.
1533 *
1534 * @param string $table The table name of the record
1535 * @param string $field The field name which this element is supposed to edit
1536 * @param array $row The record data array where the value(s) for the field can be found
1537 * @param array $PA An array with additional configuration options.
1538 * @return string The HTML code for the TCEform field
1539 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\NoneElement
1540 */
1541 public function getSingleField_typeNone($table, $field, $row, &$PA) {
1542 GeneralUtility::logDeprecatedFunction();
1543 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\NoneElement::class, $this)
1544 ->setRenderReadonly($this->getRenderReadonly())
1545 ->render($table, $field, $row, $PA);
1546 }
1547
1548 /**
1549 * HTML rendering of a value which is not editable.
1550 *
1551 * @param array $config Configuration for the display
1552 * @param string $itemValue The value to display
1553 * @return string The HTML code for the display
1554 * @see getSingleField_typeNone();
1555 */
1556 public function getSingleField_typeNone_render($config, $itemValue) {
1557 if ($config['format']) {
1558 $itemValue = $this->formatValue($config, $itemValue);
1559 }
1560 if (!$config['pass_content']) {
1561 $itemValue = htmlspecialchars($itemValue);
1562 }
1563
1564 $rows = (int)$config['rows'];
1565 // Render as textarea
1566 if ($rows > 1) {
1567 if (!$config['pass_content']) {
1568 $itemValue = nl2br($itemValue);
1569 }
1570 $cols = round($config['cols'] * $this->form_largeComp);
1571 $width = ceil($cols * $this->form_rowsToStylewidth);
1572 $item = '<textarea class="form-control" style="width:' . $width . 'px;" cols="' . $cols . '" rows="' . $rows . '" disabled>' . $itemValue . '</textarea>';
1573 } else {
1574 $cols = $config['cols'] ?: ($config['size'] ?: $this->maxInputWidth);
1575 $cols = round($cols * $this->form_largeComp);
1576 $width = ceil($cols * $this->form_rowsToStylewidth);
1577 $item = '
1578 <input class="form-control" value="'. $itemValue .'" style="width:' . $width . 'px;" type="text" disabled>'
1579 . '<span class="nobr">' . ((string)$itemValue !== '' ? $itemValue : '&nbsp;') . '</span>';
1580 }
1581 return $item;
1582 }
1583
1584 /**
1585 * Handler for Flex Forms
1586 *
1587 * @param string $table The table name of the record
1588 * @param string $field The field name which this element is supposed to edit
1589 * @param array $row The record data array where the value(s) for the field can be found
1590 * @param array $PA An array with additional configuration options.
1591 * @return string The HTML code for the TCEform field
1592 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\FlexElement
1593 */
1594 public function getSingleField_typeFlex($table, $field, $row, &$PA) {
1595 GeneralUtility::logDeprecatedFunction();
1596 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\FlexElement::class, $this)
1597 ->setRenderReadonly($this->getRenderReadonly())
1598 ->render($table, $field, $row, $PA);
1599 }
1600
1601 /**
1602 * Creates the language menu for FlexForms:
1603 *
1604 * @param array $languages
1605 * @param string $elName
1606 * @param array $selectedLanguage
1607 * @param bool $multi
1608 * @return string HTML for menu
1609 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
1610 */
1611 public function getSingleField_typeFlex_langMenu($languages, $elName, $selectedLanguage, $multi = TRUE) {
1612 GeneralUtility::logDeprecatedFunction();
1613 $opt = array();
1614 foreach ($languages as $lArr) {
1615 $opt[] = '<option value="' . htmlspecialchars($lArr['ISOcode']) . '"'
1616 . (in_array($lArr['ISOcode'], $selectedLanguage) ? ' selected="selected"' : '') . '>'
1617 . htmlspecialchars($lArr['title']) . '</option>';
1618 }
1619 $output = '<select id="' . str_replace('.', '', uniqid('tceforms-multiselect-', TRUE))
1620 . ' class="tceforms-select tceforms-multiselect tceforms-flexlangmenu" name="' . $elName . '[]"'
1621 . ($multi ? ' multiple="multiple" size="' . count($languages) . '"' : '') . '>' . implode('', $opt)
1622 . '</select>';
1623 return $output;
1624 }
1625
1626 /**
1627 * Creates the menu for selection of the sheets:
1628 *
1629 * @param array $sArr Sheet array for which to render the menu
1630 * @param string $elName Form element name of the field containing the sheet pointer
1631 * @param string $sheetKey Current sheet key
1632 * @return string HTML for menu
1633 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
1634 */
1635 public function getSingleField_typeFlex_sheetMenu($sArr, $elName, $sheetKey) {
1636 GeneralUtility::logDeprecatedFunction();
1637 $tCells = array();
1638 $pct = round(100 / count($sArr));
1639 foreach ($sArr as $sKey => $sheetCfg) {
1640 if ($this->getBackendUserAuthentication()->jsConfirmation(1)) {
1641 $onClick = 'if (confirm(TBE_EDITOR.labels.onChangeAlert) && TBE_EDITOR.checkSubmit(-1)){'
1642 . $this->elName($elName) . '.value=\'' . $sKey . '\'; TBE_EDITOR.submitForm()};';
1643 } else {
1644 $onClick = 'if(TBE_EDITOR.checkSubmit(-1)){ ' . $this->elName($elName) . '.value=\'' . $sKey . '\'; TBE_EDITOR.submitForm();}';
1645 }
1646 $tCells[] = '<td width="' . $pct . '%" style="'
1647 . ($sKey == $sheetKey ? 'background-color: #9999cc; font-weight: bold;' : 'background-color: #aaaaaa;')
1648 . ' cursor: hand;" onclick="' . htmlspecialchars($onClick) . '" align="center">'
1649 . ($sheetCfg['ROOT']['TCEforms']['sheetTitle'] ? $this->getLanguageService()->sL($sheetCfg['ROOT']['TCEforms']['sheetTitle']) : $sKey)
1650 . '</td>';
1651 }
1652 return '<table border="0" cellpadding="0" cellspacing="2" class="typo3-TCEforms-flexForm-sheetMenu"><tr>' . implode('', $tCells) . '</tr></table>';
1653 }
1654
1655 /**
1656 * Handler for unknown types.
1657 *
1658 * @param string $table The table name of the record
1659 * @param string $field The field name which this element is supposed to edit
1660 * @param array $row The record data array where the value(s) for the field can be found
1661 * @param array $PA An array with additional configuration options.
1662 * @return string The HTML code for the TCEform field
1663 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\UnknownElement
1664 */
1665 public function getSingleField_typeUnknown($table, $field, $row, &$PA) {
1666 GeneralUtility::logDeprecatedFunction();
1667 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\UnknownElement::class, $this)
1668 ->setRenderReadonly($this->getRenderReadonly())
1669 ->render($table, $field, $row, $PA);
1670 }
1671
1672 /**
1673 * User defined field type
1674 *
1675 * @param string $table The table name of the record
1676 * @param string $field The field name which this element is supposed to edit
1677 * @param array $row The record data array where the value(s) for the field can be found
1678 * @param array $PA An array with additional configuration options.
1679 * @return string The HTML code for the TCEform field
1680 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\UserElement
1681 */
1682 public function getSingleField_typeUser($table, $field, $row, &$PA) {
1683 GeneralUtility::logDeprecatedFunction();
1684 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\UserElement::class, $this)
1685 ->setRenderReadonly($this->getRenderReadonly())
1686 ->render($table, $field, $row, $PA);
1687 }
1688
1689 /************************************************************
1690 *
1691 * Field content processing
1692 *
1693 ************************************************************/
1694 /**
1695 * Format field content of various types if $config['format'] is set to date, filesize, ..., user
1696 * This is primarily for the field type none but can be used for user field types for example
1697 *
1698 * @param array $config Configuration for the display
1699 * @param string $itemValue The value to display
1700 * @return string Formatted Field content
1701 */
1702 public function formatValue($config, $itemValue) {
1703 $format = trim($config['format']);
1704 switch ($format) {
1705 case 'date':
1706 if ($itemValue) {
1707 $option = trim($config['format.']['option']);
1708 if ($option) {
1709 if ($config['format.']['strftime']) {
1710 $value = strftime($option, $itemValue);
1711 } else {
1712 $value = date($option, $itemValue);
1713 }
1714 } else {
1715 $value = date('d-m-Y', $itemValue);
1716 }
1717 } else {
1718 $value = '';
1719 }
1720 if ($config['format.']['appendAge']) {
1721 $age = BackendUtility::calcAge(
1722 $GLOBALS['EXEC_TIME'] - $itemValue,
1723 $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')
1724 );
1725 $value .= ' (' . $age . ')';
1726 }
1727 $itemValue = $value;
1728 break;
1729 case 'datetime':
1730 // compatibility with "eval" (type "input")
1731 if ($itemValue !== '') {
1732 $itemValue = date('H:i d-m-Y', (int)$itemValue);
1733 }
1734 break;
1735 case 'time':
1736 // compatibility with "eval" (type "input")
1737 if ($itemValue !== '') {
1738 $itemValue = date('H:i', (int)$itemValue);
1739 }
1740 break;
1741 case 'timesec':
1742 // compatibility with "eval" (type "input")
1743 if ($itemValue !== '') {
1744 $itemValue = date('H:i:s', (int)$itemValue);
1745 }
1746 break;
1747 case 'year':
1748 // compatibility with "eval" (type "input")
1749 if ($itemValue !== '') {
1750 $itemValue = date('Y', (int)$itemValue);
1751 }
1752 break;
1753 case 'int':
1754 $baseArr = array('dec' => 'd', 'hex' => 'x', 'HEX' => 'X', 'oct' => 'o', 'bin' => 'b');
1755 $base = trim($config['format.']['base']);
1756 $format = $baseArr[$base] ?: 'd';
1757 $itemValue = sprintf('%' . $format, $itemValue);
1758 break;
1759 case 'float':
1760 $precision = MathUtility::forceIntegerInRange($config['format.']['precision'], 1, 10, 2);
1761 $itemValue = sprintf('%.' . $precision . 'f', $itemValue);
1762 break;
1763 case 'number':
1764 $format = trim($config['format.']['option']);
1765 $itemValue = sprintf('%' . $format, $itemValue);
1766 break;
1767 case 'md5':
1768 $itemValue = md5($itemValue);
1769 break;
1770 case 'filesize':
1771 // We need to cast to int here, otherwise empty values result in empty output,
1772 // but we expect zero.
1773 $value = GeneralUtility::formatSize((int)$itemValue);
1774 if ($config['format.']['appendByteSize']) {
1775 $value .= ' (' . $itemValue . ')';
1776 }
1777 $itemValue = $value;
1778 break;
1779 case 'user':
1780 $func = trim($config['format.']['userFunc']);
1781 if ($func) {
1782 $params = array(
1783 'value' => $itemValue,
1784 'args' => $config['format.']['userFunc'],
1785 'config' => $config,
1786 'pObj' => &$this
1787 );
1788 $itemValue = GeneralUtility::callUserFunction($func, $params, $this);
1789 }
1790 break;
1791 default:
1792 // Do nothing e.g. when $format === ''
1793 }
1794 return $itemValue;
1795 }
1796
1797 /************************************************************
1798 *
1799 * "Configuration" fetching/processing functions
1800 *
1801 ************************************************************/
1802 /**
1803 * Calculate and return the current "types" pointer value for a record
1804 *
1805 * @param string $table The table name. MUST be in $GLOBALS['TCA']
1806 * @param array $row The row from the table, should contain at least the "type" field, if applicable.
1807 * @return string Return the "type" value for this record, ready to pick a "types" configuration from the $GLOBALS['TCA'] array.
1808 * @throws \RuntimeException
1809 */
1810 public function getRTypeNum($table, $row) {
1811 $typeNum = 0;
1812 $field = $GLOBALS['TCA'][$table]['ctrl']['type'];
1813 if ($field) {
1814 if (strpos($field, ':') !== FALSE) {
1815 list($pointerField, $foreignTypeField) = explode(':', $field);
1816 $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$pointerField]['config'];
1817 $relationType = $fieldConfig['type'];
1818 if ($relationType === 'select') {
1819 $foreignUid = $row[$pointerField];
1820 $foreignTable = $fieldConfig['foreign_table'];
1821 } elseif ($relationType === 'group') {
1822 $values = $this->extractValuesOnlyFromValueLabelList($row[$pointerField]);
1823 list(, $foreignUid) = GeneralUtility::revExplode('_', $values[0], 2);
1824 $allowedTables = explode(',', $fieldConfig['allowed']);
1825 // Always take the first configured table.
1826 $foreignTable = $allowedTables[0];
1827 } else {
1828 throw new \RuntimeException('TCA Foreign field pointer fields are only allowed to be used with group or select field types.', 1325861239);
1829 }
1830 if ($foreignUid) {
1831 $foreignRow = BackendUtility::getRecord($foreignTable, $foreignUid, $foreignTypeField);
1832 $this->registerDefaultLanguageData($foreignTable, $foreignRow);
1833 if ($foreignRow[$foreignTypeField]) {
1834 $foreignTypeFieldConfig = $GLOBALS['TCA'][$table]['columns'][$field];
1835 $typeNum = $this->getLanguageOverlayRawValue($foreignTable, $foreignRow, $foreignTypeField, $foreignTypeFieldConfig);
1836 }
1837 }
1838 } else {
1839 $typeFieldConfig = $GLOBALS['TCA'][$table]['columns'][$field];
1840 $typeNum = $this->getLanguageOverlayRawValue($table, $row, $field, $typeFieldConfig);
1841 }
1842 }
1843 if (empty($typeNum)) {
1844 // If that value is an empty string, set it to "0" (zero)
1845 $typeNum = 0;
1846 }
1847 // If current typeNum doesn't exist, set it to 0 (or to 1 for historical reasons, if 0 doesn't exist)
1848 if (!$GLOBALS['TCA'][$table]['types'][$typeNum]) {
1849 $typeNum = $GLOBALS['TCA'][$table]['types']['0'] ? 0 : 1;
1850 }
1851 // Force to string. Necessary for eg '-1' to be recognized as a type value.
1852 $typeNum = (string)$typeNum;
1853 return $typeNum;
1854 }
1855
1856 /**
1857 * Used to adhoc-rearrange the field order normally set in the [types][showitem] list
1858 *
1859 * @param array $fields A [types][showitem] list of fields, exploded by ",
1860 * @return array Returns rearranged version (keys are changed around as well.)
1861 * @see getMainFields()
1862 */
1863 public function rearrange($fields) {
1864 $fO = array_flip(GeneralUtility::trimExplode(',', $this->fieldOrder, TRUE));
1865 $newFields = array();
1866 foreach ($fields as $cc => $content) {
1867 $cP = GeneralUtility::trimExplode(';', $content);
1868 if (isset($fO[$cP[0]])) {
1869 $newFields[$fO[$cP[0]]] = $content;
1870 unset($fields[$cc]);
1871 }
1872 }
1873 ksort($newFields);
1874 // Candidate for GeneralUtility::array_merge() if integer-keys will some day make trouble...
1875 $fields = array_merge($newFields, $fields);
1876 return $fields;
1877 }
1878
1879 /**
1880 * Producing an array of field names NOT to display in the form,
1881 * based on settings from subtype_value_field, bitmask_excludelist_bits etc.
1882 * Notice, this list is in NO way related to the "excludeField" flag
1883 *
1884 * @param string $table Table name, MUST be in $GLOBALS['TCA']
1885 * @param array $row A record from table.
1886 * @param string $typeNum A "type" pointer value, probably the one calculated based on the record array.
1887 * @return array Array with fieldnames as values. The fieldnames are those which should NOT be displayed "anyways
1888 * @see getMainFields()
1889 */
1890 public function getExcludeElements($table, $row, $typeNum) {
1891 // Init:
1892 $excludeElements = array();
1893 // If a subtype field is defined for the type
1894 if ($GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field']) {
1895 $sTfield = $GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field'];
1896 if (trim($GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_excludelist'][$row[$sTfield]])) {
1897 $excludeElements = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_excludelist'][$row[$sTfield]], TRUE);
1898 }
1899 }
1900 // If a bitmask-value field has been configured, then find possible fields to exclude based on that:
1901 if ($GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_value_field']) {
1902 $sTfield = $GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_value_field'];
1903 $sTValue = MathUtility::forceIntegerInRange($row[$sTfield], 0);
1904 if (is_array($GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_excludelist_bits'])) {
1905 foreach ($GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_excludelist_bits'] as $bitKey => $eList) {
1906 $bit = substr($bitKey, 1);
1907 if (MathUtility::canBeInterpretedAsInteger($bit)) {
1908 $bit = MathUtility::forceIntegerInRange($bit, 0, 30);
1909 if ($bitKey[0] === '-' && !($sTValue & pow(2, $bit)) || $bitKey[0] === '+' && $sTValue & pow(2, $bit)) {
1910 $excludeElements = array_merge($excludeElements, GeneralUtility::trimExplode(',', $eList, TRUE));
1911 }
1912 }
1913 }
1914 }
1915 }
1916 // Return the array of elements:
1917 return $excludeElements;
1918 }
1919
1920 /**
1921 * Finds possible field to add to the form, based on subtype fields.
1922 *
1923 * @param string $table Table name, MUST be in $GLOBALS['TCA']
1924 * @param array $row A record from table.
1925 * @param string $typeNum A "type" pointer value, probably the one calculated based on the record array.
1926 * @return array An array containing two values: 1) Another array containing field names to add and 2) the subtype value field.
1927 * @see getMainFields()
1928 */
1929 public function getFieldsToAdd($table, $row, $typeNum) {
1930 // Init:
1931 $addElements = array();
1932 // If a subtype field is defined for the type
1933 $sTfield = '';
1934 if ($GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field']) {
1935 $sTfield = $GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field'];
1936 if (trim($GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_addlist'][$row[$sTfield]])) {
1937 $addElements = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_addlist'][$row[$sTfield]], TRUE);
1938 }
1939 }
1940 // Return the return
1941 return array($addElements, $sTfield);
1942 }
1943
1944 /**
1945 * Merges the current [types][showitem] array with the array of fields to add for the current subtype field of the "type" value.
1946 *
1947 * @param array $fields A [types][showitem] list of fields, exploded by ",
1948 * @param array $fieldsToAdd The output from getFieldsToAdd()
1949 * @param string $table The table name, if we want to consider it's palettes when positioning the new elements
1950 * @return array Return the modified $fields array.
1951 * @see getMainFields(),getFieldsToAdd()
1952 */
1953 public function mergeFieldsWithAddedFields($fields, $fieldsToAdd, $table = '') {
1954 if (count($fieldsToAdd[0])) {
1955 $c = 0;
1956 $found = FALSE;
1957 foreach ($fields as $fieldInfo) {
1958 list($fieldName, $label, $paletteName) = GeneralUtility::trimExplode(';', $fieldInfo);
1959 if ($fieldName === $fieldsToAdd[1]) {
1960 $found = TRUE;
1961 } elseif ($fieldName === '--palette--' && $paletteName && $table !== '') {
1962 // Look inside the palette
1963 if (is_array($GLOBALS['TCA'][$table]['palettes'][$paletteName])) {
1964 $itemList = $GLOBALS['TCA'][$table]['palettes'][$paletteName]['showitem'];
1965 if ($itemList) {
1966 $paletteFields = GeneralUtility::trimExplode(',', $itemList, TRUE);
1967 foreach ($paletteFields as $info) {
1968 $fieldParts = GeneralUtility::trimExplode(';', $info);
1969 $theField = $fieldParts[0];
1970 if ($theField === $fieldsToAdd[1]) {
1971 $found = TRUE;
1972 break 1;
1973 }
1974 }
1975 }
1976 }
1977 }
1978 if ($found) {
1979 array_splice($fields, $c + 1, 0, $fieldsToAdd[0]);
1980 break;
1981 }
1982 $c++;
1983 }
1984 }
1985 return $fields;
1986 }
1987
1988 /**
1989 * Returns TSconfig for table/row
1990 * Multiple requests to this function will return cached content so there is no performance loss in calling
1991 * this many times since the information is looked up only once.
1992 *
1993 * @param string $table The table name
1994 * @param array $row The table row (Should at least contain the "uid" value, even if "NEW..." string. The "pid" field is important as well, and negative values will be intepreted as pointing to a record from the same table.)
1995 * @param string $field Optionally you can specify the field name as well. In that case the TSconfig for the field is returned.
1996 * @return mixed The TSconfig values (probably in an array)
1997 * @see BackendUtility::getTCEFORM_TSconfig()
1998 */
1999 public function setTSconfig($table, $row, $field = '') {
2000 $mainKey = $table . ':' . $row['uid'];
2001 if (!isset($this->cachedTSconfig[$mainKey])) {
2002 $this->cachedTSconfig[$mainKey] = BackendUtility::getTCEFORM_TSconfig($table, $row);
2003 }
2004 if ($field) {
2005 return $this->cachedTSconfig[$mainKey][$field];
2006 } else {
2007 return $this->cachedTSconfig[$mainKey];
2008 }
2009 }
2010
2011 /**
2012 * Overrides the TCA field configuration by TSconfig settings.
2013 *
2014 * Example TSconfig: TCEform.<table>.<field>.config.appearance.useSortable = 1
2015 * This overrides the setting in $GLOBALS['TCA'][<table>]['columns'][<field>]['config']['appearance']['useSortable'].
2016 *
2017 * @param array $fieldConfig $GLOBALS['TCA'] field configuration
2018 * @param array $TSconfig TSconfig
2019 * @return array Changed TCA field configuration
2020 */
2021 public function overrideFieldConf($fieldConfig, $TSconfig) {
2022 if (is_array($TSconfig)) {
2023 $TSconfig = GeneralUtility::removeDotsFromTS($TSconfig);
2024 $type = $fieldConfig['type'];
2025 if (is_array($TSconfig['config']) && is_array($this->allowOverrideMatrix[$type])) {
2026 // Check if the keys in TSconfig['config'] are allowed to override TCA field config:
2027 foreach ($TSconfig['config'] as $key => $_) {
2028 if (!in_array($key, $this->allowOverrideMatrix[$type], TRUE)) {
2029 unset($TSconfig['config'][$key]);
2030 }
2031 }
2032 // Override $GLOBALS['TCA'] field config by remaining TSconfig['config']:
2033 if (count($TSconfig['config'])) {
2034 ArrayUtility::mergeRecursiveWithOverrule($fieldConfig, $TSconfig['config']);
2035 }
2036 }
2037 }
2038 return $fieldConfig;
2039 }
2040
2041 /**
2042 * Returns the "special" configuration (from the "types" "showitem" list) for a fieldname based on input table/record
2043 * (Not used anywhere...?)
2044 *
2045 * @param string $table The table name
2046 * @param array $row The table row (Should at least contain the "uid" value, even if "NEW..." string. The "pid" field is important as well, and negative values will be intepreted as pointing to a record from the same table.)
2047 * @param string $field Specify the field name.
2048 * @return array|NULL
2049 * @see getSpecConfFromString(), BackendUtility::getTCAtypes()
2050 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2051 */
2052 public function getSpecConfForField($table, $row, $field) {
2053 GeneralUtility::logDeprecatedFunction();
2054 // Finds the current "types" configuration for the table/row:
2055 $types_fieldConfig = BackendUtility::getTCAtypes($table, $row);
2056 // If this is an array, then traverse it:
2057 if (is_array($types_fieldConfig)) {
2058 foreach ($types_fieldConfig as $vconf) {
2059 // If the input field name matches one found in the 'types' list, then return the 'special' configuration.
2060 if ($vconf['field'] == $field) {
2061 return $vconf['spec'];
2062 }
2063 }
2064 }
2065 return NULL;
2066 }
2067
2068 /**
2069 * Returns the "special" configuration of an "extra" string (non-parsed)
2070 *
2071 * @param string $extraString The "Part 4" of the fields configuration in "types" "showitem" lists.
2072 * @param string $defaultExtras The ['defaultExtras'] value from field configuration
2073 * @return array An array with the special options in.
2074 * @see getSpecConfForField(), BackendUtility::getSpecConfParts()
2075 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2076 */
2077 public function getSpecConfFromString($extraString, $defaultExtras) {
2078 GeneralUtility::logDeprecatedFunction();
2079 return BackendUtility::getSpecConfParts($extraString, $defaultExtras);
2080 }
2081
2082 /**
2083 * Loads the elements of a palette (collection of secondary options) in an array.
2084 *
2085 * @param string $table The table name
2086 * @param array $row The row array
2087 * @param string $palette The palette number/pointer
2088 * @param string $itemList Optional alternative list of fields for the palette
2089 * @return array The palette elements
2090 */
2091 public function loadPaletteElements($table, $row, $palette, $itemList = '') {
2092 $parts = array();
2093 // Getting excludeElements, if any.
2094 if (!is_array($this->excludeElements)) {
2095 $this->excludeElements = $this->getExcludeElements($table, $row, $this->getRTypeNum($table, $row));
2096 }
2097 // Load the palette TCEform elements
2098 if ($GLOBALS['TCA'][$table] && (is_array($GLOBALS['TCA'][$table]['palettes'][$palette]) || $itemList)) {
2099 $itemList = $itemList ? $itemList : $GLOBALS['TCA'][$table]['palettes'][$palette]['showitem'];
2100 if ($itemList) {
2101 $fields = GeneralUtility::trimExplode(',', $itemList, TRUE);
2102 foreach ($fields as $info) {
2103 $fieldParts = GeneralUtility::trimExplode(';', $info);
2104 $theField = $fieldParts[0];
2105 if ($theField === '--linebreak--') {
2106 $parts[]['NAME'] = '--linebreak--';
2107 } elseif (!in_array($theField, $this->excludeElements) && $GLOBALS['TCA'][$table]['columns'][$theField]) {
2108 $this->palFieldArr[$palette][] = $theField;
2109 $elem = $this->getSingleField($table, $theField, $row, $fieldParts[1], 1, '', $fieldParts[2]);
2110 if (is_array($elem)) {
2111 $parts[] = $elem;
2112 }
2113 }
2114 }
2115 }
2116 }
2117 return $parts;
2118 }
2119
2120 /************************************************************
2121 *
2122 * Display of localized content etc.
2123 *
2124 ************************************************************/
2125 /**
2126 * Will register data from original language records if the current record is a translation of another.
2127 * The original data is shown with the edited record in the form.
2128 * The information also includes possibly diff-views of what changed in the original record.
2129 * Function called from outside (see alt_doc.php + quick edit) before rendering a form for a record
2130 *
2131 * @param string $table Table name of the record being edited
2132 * @param array $rec Record array of the record being edited
2133 * @return void
2134 */
2135 public function registerDefaultLanguageData($table, $rec) {
2136 // Add default language:
2137 if (
2138 $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $rec[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0
2139 && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']
2140 && (int)$rec[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] > 0
2141 ) {
2142 $lookUpTable = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']
2143 ? $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']
2144 : $table;
2145 // Get data formatted:
2146 $this->defaultLanguageData[$table . ':' . $rec['uid']] = BackendUtility::getRecordWSOL(
2147 $lookUpTable,
2148 (int)$rec[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']]
2149 );
2150 // Get data for diff:
2151 if ($GLOBALS['TCA'][$table]['ctrl']['transOrigDiffSourceField']) {
2152 $this->defaultLanguageData_diff[$table . ':' . $rec['uid']] = unserialize($rec[$GLOBALS['TCA'][$table]['ctrl']['transOrigDiffSourceField']]);
2153 }
2154 // If there are additional preview languages, load information for them also:
2155 $prLang = $this->getAdditionalPreviewLanguages();
2156 foreach ($prLang as $prL) {
2157 /** @var $t8Tools \TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider */
2158 $t8Tools = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider::class);
2159 $tInfo = $t8Tools->translationInfo($lookUpTable, (int)$rec[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']], $prL['uid']);
2160 if (is_array($tInfo['translations']) && is_array($tInfo['translations'][$prL['uid']])) {
2161 $this->additionalPreviewLanguageData[$table . ':' . $rec['uid']][$prL['uid']] = BackendUtility::getRecordWSOL($table, (int)$tInfo['translations'][$prL['uid']]['uid']);
2162 }
2163 }
2164 }
2165 }
2166
2167 /**
2168 * Creates language-overlay for a field value
2169 * This means the requested field value will be overridden with the data from the default language.
2170 * Can be used to render read only fields for example.
2171 *
2172 * @param string $table Table name of the record being edited
2173 * @param array $row Record array of the record being edited in current language
2174 * @param string $field Field name represented by $item
2175 * @param array $fieldConf Content of $PA['fieldConf']
2176 * @return string Unprocessed field value merged with default language data if needed
2177 */
2178 public function getLanguageOverlayRawValue($table, $row, $field, $fieldConf) {
2179 $value = $row[$field];
2180 if (is_array($this->defaultLanguageData[$table . ':' . $row['uid']])) {
2181 if (
2182 $fieldConf['l10n_mode'] == 'exclude'
2183 || $fieldConf['l10n_mode'] == 'mergeIfNotBlank' && trim($this->defaultLanguageData[$table . ':' . $row['uid']][$field]) !== ''
2184 ) {
2185 $value = $this->defaultLanguageData[$table . ':' . $row['uid']][$field];
2186 }
2187 }
2188 return $value;
2189 }
2190
2191 /**
2192 * Renders the display of default language record content around current field.
2193 * Will render content if any is found in the internal array, $this->defaultLanguageData,
2194 * depending on registerDefaultLanguageData() being called prior to this.
2195 *
2196 * @param string $table Table name of the record being edited
2197 * @param string $field Field name represented by $item
2198 * @param array $row Record array of the record being edited
2199 * @param string $item HTML of the form field. This is what we add the content to.
2200 * @return string Item string returned again, possibly with the original value added to.
2201 * @see getSingleField(), registerDefaultLanguageData()
2202 */
2203 public function renderDefaultLanguageContent($table, $field, $row, $item) {
2204 if (is_array($this->defaultLanguageData[$table . ':' . $row['uid']])) {
2205 $defaultLanguageValue = BackendUtility::getProcessedValue($table, $field, $this->defaultLanguageData[$table . ':' . $row['uid']][$field], 0, 1, FALSE, $this->defaultLanguageData[$table . ':' . $row['uid']]['uid']);
2206 $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$field];
2207 // Don't show content if it's for IRRE child records:
2208 if ($fieldConfig['config']['type'] != 'inline') {
2209 if ($defaultLanguageValue !== '') {
2210 $item .= '<div class="t3-form-original-language">' . $this->getLanguageIcon($table, $row, 0)
2211 . $this->getMergeBehaviourIcon($fieldConfig['l10n_mode'])
2212 . $this->previewFieldValue($defaultLanguageValue, $fieldConfig, $field) . '</div>';
2213 }
2214 $previewLanguages = $this->getAdditionalPreviewLanguages();
2215 foreach ($previewLanguages as $previewLanguage) {
2216 $defaultLanguageValue = BackendUtility::getProcessedValue($table, $field, $this->additionalPreviewLanguageData[$table . ':' . $row['uid']][$previewLanguage['uid']][$field], 0, 1);
2217 if ($defaultLanguageValue !== '') {
2218 $item .= '<div class="t3-form-original-language">'
2219 . $this->getLanguageIcon($table, $row, ('v' . $previewLanguage['ISOcode']))
2220 . $this->getMergeBehaviourIcon($fieldConfig['l10n_mode'])
2221 . $this->previewFieldValue($defaultLanguageValue, $fieldConfig, $field) . '</div>';
2222 }
2223 }
2224 }
2225 }
2226 return $item;
2227 }
2228
2229 /**
2230 * Renders the diff-view of default language record content compared with what the record was originally translated from.
2231 * Will render content if any is found in the internal array, $this->defaultLanguageData,
2232 * depending on registerDefaultLanguageData() being called prior to this.
2233 *
2234 * @param string $table Table name of the record being edited
2235 * @param string $field Field name represented by $item
2236 * @param array $row Record array of the record being edited
2237 * @param string $item HTML of the form field. This is what we add the content to.
2238 * @return string Item string returned again, possibly with the original value added to.
2239 * @see getSingleField(), registerDefaultLanguageData()
2240 */
2241 public function renderDefaultLanguageDiff($table, $field, $row, $item) {
2242 if (is_array($this->defaultLanguageData_diff[$table . ':' . $row['uid']])) {
2243 // Initialize:
2244 $dLVal = array(
2245 'old' => $this->defaultLanguageData_diff[$table . ':' . $row['uid']],
2246 'new' => $this->defaultLanguageData[$table . ':' . $row['uid']]
2247 );
2248 // There must be diff-data:
2249 if (isset($dLVal['old'][$field])) {
2250 if ((string)$dLVal['old'][$field] !== (string)$dLVal['new'][$field]) {
2251 // Create diff-result:
2252 $t3lib_diff_Obj = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Utility\DiffUtility::class);
2253 $diffres = $t3lib_diff_Obj->makeDiffDisplay(
2254 BackendUtility::getProcessedValue($table, $field, $dLVal['old'][$field], 0, 1),
2255 BackendUtility::getProcessedValue($table, $field, $dLVal['new'][$field], 0, 1)
2256 );
2257 $item .= '<div class="t3-form-original-language-diff">
2258 <div class="t3-form-original-language-diffheader">' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.changeInOrig')) . '</div>
2259 <div class="t3-form-original-language-diffcontent">' . $diffres . '</div>
2260 </div>';
2261 }
2262 }
2263 }
2264 return $item;
2265 }
2266
2267 /**
2268 * Renders the diff-view of vDEF fields in flexforms
2269 *
2270 * @param array $vArray Record array of the record being edited
2271 * @param string $vDEFkey HTML of the form field. This is what we add the content to.
2272 * @return string Item string returned again, possibly with the original value added to.
2273 * @see getSingleField(), registerDefaultLanguageData()
2274 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2275 */
2276 public function renderVDEFDiff($vArray, $vDEFkey) {
2277 GeneralUtility::logDeprecatedFunction();
2278 $item = NULL;
2279 if (
2280 $GLOBALS['TYPO3_CONF_VARS']['BE']['flexFormXMLincludeDiffBase'] && isset($vArray[$vDEFkey . '.vDEFbase'])
2281 && (string)$vArray[$vDEFkey . '.vDEFbase'] !== (string)$vArray['vDEF']
2282 ) {
2283 // Create diff-result:
2284 $t3lib_diff_Obj = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Utility\DiffUtility::class);
2285 $diffres = $t3lib_diff_Obj->makeDiffDisplay($vArray[$vDEFkey . '.vDEFbase'], $vArray['vDEF']);
2286 $item = '<div class="typo3-TCEforms-diffBox">' . '<div class="typo3-TCEforms-diffBox-header">'
2287 . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.changeInOrig')) . ':</div>' . $diffres . '</div>';
2288 }
2289 return $item;
2290 }
2291
2292 /************************************************************
2293 *
2294 * Form element helper functions
2295 *
2296 ************************************************************/
2297 /**
2298 * Prints the selector box form-field for the db/file/select elements (multiple)
2299 *
2300 * @param string $fName Form element name
2301 * @param string $mode Mode "db", "file" (internal_type for the "group" type) OR blank (then for the "select" type)
2302 * @param string $allowed Commalist of "allowed
2303 * @param array $itemArray The array of items. For "select" and "group"/"file" this is just a set of value. For "db" its an array of arrays with table/uid pairs.
2304 * @param string $selector Alternative selector box.
2305 * @param array $params An array of additional parameters, eg: "size", "info", "headers" (array with "selector" and "items"), "noBrowser", "thumbnails
2306 * @param string $onFocus On focus attribute string
2307 * @param string $table (optional) Table name processing for
2308 * @param string $field (optional) Field of table name processing for
2309 * @param string $uid (optional) uid of table record processing for
2310 * @param array $config (optional) The TCA field config
2311 * @return string The form fields for the selection.
2312 * @throws \UnexpectedValueException
2313 */
2314 public function dbFileIcons($fName, $mode, $allowed, $itemArray, $selector = '', $params = array(), $onFocus = '', $table = '', $field = '', $uid = '', $config = array()) {
2315 $languageService = $this->getLanguageService();
2316 $disabled = '';
2317 if ($this->getRenderReadonly() || $params['readOnly']) {
2318 $disabled = ' disabled="disabled"';
2319 }
2320 // Sets a flag which means some JavaScript is included on the page to support this element.
2321 $this->printNeededJS['dbFileIcons'] = 1;
2322 // INIT
2323 $uidList = array();
2324 $opt = array();
2325 $itemArrayC = 0;
2326 // Creating <option> elements:
2327 if (is_array($itemArray)) {
2328 $itemArrayC = count($itemArray);
2329 switch ($mode) {
2330 case 'db':
2331 foreach ($itemArray as $pp) {
2332 $pRec = BackendUtility::getRecordWSOL($pp['table'], $pp['id']);
2333 if (is_array($pRec)) {
2334 $pTitle = BackendUtility::getRecordTitle($pp['table'], $pRec, FALSE, TRUE);
2335 $pUid = $pp['table'] . '_' . $pp['id'];
2336 $uidList[] = $pUid;
2337 $title = htmlspecialchars($pTitle);
2338 $opt[] = '<option value="' . htmlspecialchars($pUid) . '" title="' . $title . '">' . $title . '</option>';
2339 }
2340 }
2341 break;
2342 case 'file_reference':
2343
2344 case 'file':
2345 foreach ($itemArray as $item) {
2346 $itemParts = explode('|', $item);
2347 $uidList[] = ($pUid = ($pTitle = $itemParts[0]));
2348 $title = htmlspecialchars(rawurldecode($itemParts[1]));
2349 $opt[] = '<option value="' . htmlspecialchars(rawurldecode($itemParts[0])) . '" title="' . $title . '">' . $title . '</option>';
2350 }
2351 break;
2352 case 'folder':
2353 foreach ($itemArray as $pp) {
2354 $pParts = explode('|', $pp);
2355 $uidList[] = ($pUid = ($pTitle = $pParts[0]));
2356 $title = htmlspecialchars(rawurldecode($pParts[0]));
2357 $opt[] = '<option value="' . htmlspecialchars(rawurldecode($pParts[0])) . '" title="' . $title . '">' . $title . '</option>';
2358 }
2359 break;
2360 default:
2361 foreach ($itemArray as $pp) {
2362 $pParts = explode('|', $pp, 2);
2363 $uidList[] = ($pUid = $pParts[0]);
2364 $pTitle = $pParts[1];
2365 $title = htmlspecialchars(rawurldecode($pTitle));
2366 $opt[] = '<option value="' . htmlspecialchars(rawurldecode($pUid)) . '" title="' . $title . '">' . $title . '</option>';
2367 }
2368 }
2369 }
2370 // Create selector box of the options
2371 $sSize = $params['autoSizeMax']
2372 ? MathUtility::forceIntegerInRange($itemArrayC + 1, MathUtility::forceIntegerInRange($params['size'], 1), $params['autoSizeMax'])
2373 : $params['size'];
2374 if (!$selector) {
2375 $isMultiple = $params['maxitems'] != 1 && $params['size'] != 1;
2376 $selector = '<select id="' . str_replace('.', '', uniqid('tceforms-multiselect-', TRUE)) . '" '
2377 . ($params['noList'] ? 'style="display: none"' : 'size="' . $sSize . '" class="' . $this->cssClassTypeElementPrefix . 'group tceforms-multiselect"')
2378 . ($isMultiple ? ' multiple="multiple"' : '')
2379 . ' name="' . $fName . '_list" ' . $onFocus . $params['style'] . $disabled . '>' . implode('', $opt)
2380 . '</select>';
2381 }
2382 $icons = array(
2383 'L' => array(),
2384 'R' => array()
2385 );
2386 $rOnClickInline = '';
2387 if (!$params['readOnly'] && !$params['noList']) {
2388 if (!$params['noBrowser']) {
2389 // Check against inline uniqueness
2390 $inlineParent = $this->inline->getStructureLevel(-1);
2391 $aOnClickInline = '';
2392 if (is_array($inlineParent) && $inlineParent['uid']) {
2393 if ($inlineParent['config']['foreign_table'] == $table && $inlineParent['config']['foreign_unique'] == $field) {
2394 $objectPrefix = $this->inline->inlineNames['object'] . InlineElement::Structure_Separator . $table;
2395 $aOnClickInline = $objectPrefix . '|inline.checkUniqueElement|inline.setUniqueElement';
2396 $rOnClickInline = 'inline.revertUnique(\'' . $objectPrefix . '\',null,\'' . $uid . '\');';
2397 }
2398 }
2399 if (is_array($config['appearance']) && isset($config['appearance']['elementBrowserType'])) {
2400 $elementBrowserType = $config['appearance']['elementBrowserType'];
2401 } else {
2402 $elementBrowserType = $mode;
2403 }
2404 if (is_array($config['appearance']) && isset($config['appearance']['elementBrowserAllowed'])) {
2405 $elementBrowserAllowed = $config['appearance']['elementBrowserAllowed'];
2406 } else {
2407 $elementBrowserAllowed = $allowed;
2408 }
2409 $aOnClick = 'setFormValueOpenBrowser(\'' . $elementBrowserType . '\',\''
2410 . ($fName . '|||' . $elementBrowserAllowed . '|' . $aOnClickInline) . '\'); return false;';
2411 $spriteIcon = IconUtility::getSpriteIcon('actions-insert-record', array(
2412 'title' => htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.browse_' . ($mode == 'db' ? 'db' : 'file')))
2413 ));
2414 $icons['R'][] = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '" class="btn btn-default">' . $spriteIcon . '</a>';
2415 }
2416 if (!$params['dontShowMoveIcons']) {
2417 if ($sSize >= 5) {
2418 $icons['L'][] = IconUtility::getSpriteIcon('actions-move-to-top', array(
2419 'data-fieldname' => $fName,
2420 'class' => 't3-btn t3-btn-moveoption-top',
2421 'title' => htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.move_to_top'))
2422 ));
2423 }
2424 $icons['L'][] = IconUtility::getSpriteIcon('actions-move-up', array(
2425 'data-fieldname' => $fName,
2426 'class' => 't3-btn t3-btn-moveoption-up',
2427 'title' => htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.move_up'))
2428 ));
2429 $icons['L'][] = IconUtility::getSpriteIcon('actions-move-down', array(
2430 'data-fieldname' => $fName,
2431 'class' => 't3-btn t3-btn-moveoption-down',
2432 'title' => htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.move_down'))
2433 ));
2434 if ($sSize >= 5) {
2435 $icons['L'][] = IconUtility::getSpriteIcon('actions-move-to-bottom', array(
2436 'data-fieldname' => $fName,
2437 'class' => 't3-btn t3-btn-moveoption-bottom',
2438 'title' => htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.move_to_bottom'))
2439 ));
2440 }
2441 }
2442 $clipElements = $this->getClipboardElements($allowed, $mode);
2443 if (count($clipElements)) {
2444 $aOnClick = '';
2445 foreach ($clipElements as $elValue) {
2446 if ($mode == 'db') {
2447 list($itemTable, $itemUid) = explode('|', $elValue);
2448 $recordTitle = BackendUtility::getRecordTitle($itemTable, BackendUtility::getRecordWSOL($itemTable, $itemUid));
2449 $itemTitle = GeneralUtility::quoteJSvalue($recordTitle);
2450 $elValue = $itemTable . '_' . $itemUid;
2451 } else {
2452 // 'file', 'file_reference' and 'folder' mode
2453 $itemTitle = 'unescape(\'' . rawurlencode(basename($elValue)) . '\')';
2454 }
2455 $aOnClick .= 'setFormValueFromBrowseWin(\'' . $fName . '\',unescape(\''
2456 . rawurlencode(str_replace('%20', ' ', $elValue)) . '\'),' . $itemTitle . ',' . $itemTitle . ');';
2457 }
2458 $aOnClick .= 'return false;';
2459 $spriteIcon1 = IconUtility::getSpriteIcon('actions-document-paste-into', array(
2460 'title' => htmlspecialchars(sprintf($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.clipInsert_' . ($mode == 'db' ? 'db' : 'file')), count($clipElements)))
2461 ));
2462 $icons['R'][] = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . $spriteIcon1 . '</a>';
2463 }
2464 }
2465 if (!$params['readOnly'] && !$params['noDelete']) {
2466 $icons['L'][] = IconUtility::getSpriteIcon('actions-selection-delete', array(
2467 'onclick' => $rOnClickInline,
2468 'data-fieldname' => $fName,
2469 'class' => 't3-btn t3-btn-removeoption',
2470 'title' => htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.remove_selected'))
2471
2472 ));
2473 }
2474 $imagesOnly = FALSE;
2475 if ($params['thumbnails'] && $params['info']) {
2476 // In case we have thumbnails, check if only images are allowed.
2477 // In this case, render them below the field, instead of to the right
2478 $allowedExtensionList = GeneralUtility::trimExplode(' ', strtolower($params['info']), TRUE);
2479 $imageExtensionList = GeneralUtility::trimExplode(',', strtolower($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']), TRUE);
2480 $imagesOnly = TRUE;
2481 foreach ($allowedExtensionList as $allowedExtension) {
2482 if (!GeneralUtility::inArray($imageExtensionList, $allowedExtension)) {
2483 $imagesOnly = FALSE;
2484 break;
2485 }
2486 }
2487 }
2488 if ($imagesOnly) {
2489 $rightbox = '';
2490 $thumbnails = '<div class="imagethumbs">' . $params['thumbnails'] . '</div>';
2491 } else {
2492 $rightbox = $params['thumbnails'];
2493 $thumbnails = '';
2494 }
2495 // Hook: dbFileIcons_postProcess (requested by FAL-team for use with the "fal" extension)
2496 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['dbFileIcons'])) {
2497 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['dbFileIcons'] as $classRef) {
2498 $hookObject = GeneralUtility::getUserObj($classRef);
2499 if (!$hookObject instanceof DatabaseFileIconsHookInterface) {
2500 throw new \UnexpectedValueException('$hookObject must implement interface ' . \TYPO3\CMS\Backend\Form\DatabaseFileIconsHookInterface::class, 1290167704);
2501 }
2502 $additionalParams = array(
2503 'mode' => $mode,
2504 'allowed' => $allowed,
2505 'itemArray' => $itemArray,
2506 'onFocus' => $onFocus,
2507 'table' => $table,
2508 'field' => $field,
2509 'uid' => $uid,
2510 'config' => $GLOBALS['TCA'][$table]['columns'][$field]
2511 );
2512 $hookObject->dbFileIcons_postProcess($params, $selector, $thumbnails, $icons, $rightbox, $fName, $uidList, $additionalParams, $this);
2513 }
2514 }
2515 $str = '<table border="0" cellpadding="0" cellspacing="0" width="1" class="t3-form-field-group-file">
2516 ' . ($params['headers'] ? '
2517 <tr>
2518 <td>' . $params['headers']['selector'] . '</td>
2519 <td></td>
2520 <td></td>
2521 <td>' . ($params['thumbnails'] ? $params['headers']['items'] : '') . '</td>
2522 </tr>' : '') . '
2523 <tr>
2524 <td>' . $selector . $thumbnails;
2525 if (!$params['noList'] && $params['info'] !== '') {
2526 $str .= '<span class="filetypes">' . $params['info'] . '</span>';
2527 }
2528 $str .= '</td>
2529 <td class="icons">' . implode('<br />', $icons['L']) . '</td>
2530 <td class="icons">' . implode('<br />', $icons['R']) . '</td>
2531 <td>' . $rightbox . '</td>
2532 </tr>
2533 </table>';
2534 // Creating the hidden field which contains the actual value as a comma list.
2535 $str .= '<input type="hidden" name="' . $fName . '" value="' . htmlspecialchars(implode(',', $uidList)) . '" />';
2536 return $str;
2537 }
2538
2539 /**
2540 * Returns array of elements from clipboard to insert into GROUP element box.
2541 *
2542 * @param string $allowed Allowed elements, Eg "pages,tt_content", "gif,jpg,jpeg,png
2543 * @param string $mode Mode of relations: "db" or "file
2544 * @return array Array of elements in values (keys are insignificant), if none found, empty array.
2545 */
2546 public function getClipboardElements($allowed, $mode) {
2547 $output = array();
2548 if (is_object($this->clipObj)) {
2549 switch ($mode) {
2550 case 'file_reference':
2551
2552 case 'file':
2553 $elFromTable = $this->clipObj->elFromTable('_FILE');
2554 $allowedExts = GeneralUtility::trimExplode(',', $allowed, TRUE);
2555 // If there are a set of allowed extensions, filter the content:
2556 if ($allowedExts) {
2557 foreach ($elFromTable as $elValue) {
2558 $pI = pathinfo($elValue);
2559 $ext = strtolower($pI['extension']);
2560 if (in_array($ext, $allowedExts)) {
2561 $output[] = $elValue;
2562 }
2563 }
2564 } else {
2565 // If all is allowed, insert all: (This does NOT respect any disallowed extensions,
2566 // but those will be filtered away by the backend TCEmain)
2567 $output = $elFromTable;
2568 }
2569 break;
2570 case 'db':
2571 $allowedTables = GeneralUtility::trimExplode(',', $allowed, TRUE);
2572 // All tables allowed for relation:
2573 if (trim($allowedTables[0]) === '*') {
2574 $output = $this->clipObj->elFromTable('');
2575 } else {
2576 // Only some tables, filter them:
2577 foreach ($allowedTables as $tablename) {
2578 $elFromTable = $this->clipObj->elFromTable($tablename);
2579 $output = array_merge($output, $elFromTable);
2580 }
2581 }
2582 $output = array_keys($output);
2583 break;
2584 }
2585 }
2586 return $output;
2587 }
2588
2589 /**
2590 * Wraps the icon of a relation item (database record or file) in a link opening the context menu for the item.
2591 * Icons will be wrapped only if $this->enableClickMenu is set. This must be done only if a global SOBE object
2592 * exists and if the necessary JavaScript for displaying the context menus has been added to the page properties.
2593 *
2594 * @param string $str The icon HTML to wrap
2595 * @param string $table Table name (eg. "pages" or "tt_content") OR the absolute path to the file
2596 * @param int $uid The uid of the record OR if file, just blank value.
2597 * @return string HTML
2598 */
2599 public function getClickMenu($str, $table, $uid = 0) {
2600 if ($this->enableClickMenu) {
2601 return $this->getControllerDocumentTemplate()->wrapClickMenuOnIcon($str, $table, $uid, 1, '', '+copy,info,edit,view');
2602 }
2603 return '';
2604 }
2605
2606 /**
2607 * Rendering wizards for form fields.
2608 *
2609 * @param array $itemKinds Array with the real item in the first value, and an alternative item in the second value.
2610 * @param array $wizConf The "wizard" key from the config array for the field (from TCA)
2611 * @param string $table Table name
2612 * @param array $row The record array
2613 * @param string $field The field name
2614 * @param array $PA Additional configuration array. (passed by reference!)
2615 * @param string $itemName The field name
2616 * @param array $specConf Special configuration if available.
2617 * @param bool $RTE Whether the RTE could have been loaded.
2618 * @return string The new item value.
2619 */
2620 public function renderWizards($itemKinds, $wizConf, $table, $row, $field, &$PA, $itemName, $specConf, $RTE = FALSE) {
2621 // Init:
2622 $fieldChangeFunc = $PA['fieldChangeFunc'];
2623 $item = $itemKinds[0];
2624 $outArr = array();
2625 $colorBoxLinks = array();
2626 $fName = '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
2627 $md5ID = 'ID' . GeneralUtility::shortmd5($itemName);
2628 $listFlag = '_list';
2629 $fieldConfig = $PA['fieldConf']['config'];
2630 $prefixOfFormElName = 'data[' . $table . '][' . $row['uid'] . '][' . $field . ']';
2631 $flexFormPath = '';
2632 if (GeneralUtility::isFirstPartOfStr($PA['itemFormElName'], $prefixOfFormElName)) {
2633 $flexFormPath = str_replace('][', '/', substr($PA['itemFormElName'], strlen($prefixOfFormElName) + 1, -1));
2634 }
2635 // Manipulate the field name (to be the TRUE form field name) and remove
2636 // a suffix-value if the item is a selector box with renderMode "singlebox":
2637 if ($PA['fieldConf']['config']['form_type'] == 'select') {
2638 // Single select situation:
2639 if ($PA['fieldConf']['config']['maxitems'] <= 1) {
2640 $listFlag = '';
2641 } elseif ($PA['fieldConf']['config']['renderMode'] == 'singlebox') {
2642 $itemName .= '[]';
2643 $listFlag = '';
2644 }
2645 }
2646 // Traverse wizards:
2647 if (is_array($wizConf) && !$this->disableWizards) {
2648 $parametersOfWizards = &$specConf['wizards']['parameters'];
2649 foreach ($wizConf as $wid => $wConf) {
2650 if (
2651 $wid[0] !== '_' && (!$wConf['enableByTypeConfig']
2652 || is_array($parametersOfWizards) && in_array($wid, $parametersOfWizards)) && ($RTE || !$wConf['RTEonly'])
2653 ) {
2654 // Title / icon:
2655 $iTitle = htmlspecialchars($this->getLanguageService()->sL($wConf['title']));
2656 if ($wConf['icon']) {
2657 $icon = $this->getIconHtml($wConf['icon'], $iTitle, $iTitle);
2658 } else {
2659 $icon = $iTitle;
2660 }
2661 switch ((string)$wConf['type']) {
2662 case 'userFunc':
2663
2664 case 'script':
2665
2666 case 'popup':
2667
2668 case 'colorbox':
2669
2670 case 'slider':
2671 if (!$wConf['notNewRecords'] || MathUtility::canBeInterpretedAsInteger($row['uid'])) {
2672 // Setting &P array contents:
2673 $params = array();
2674 // Including the full fieldConfig from TCA may produce too long an URL
2675 if ($wid != 'RTE') {
2676 $params['fieldConfig'] = $fieldConfig;
2677 }
2678 $params['params'] = $wConf['params'];
2679 $params['exampleImg'] = $wConf['exampleImg'];
2680 $params['table'] = $table;
2681 $params['uid'] = $row['uid'];
2682 $params['pid'] = $row['pid'];
2683 $params['field'] = $field;
2684 $params['flexFormPath'] = $flexFormPath;
2685 $params['md5ID'] = $md5ID;
2686 $params['returnUrl'] = $this->thisReturnUrl();
2687
2688 $wScript = '';
2689 // Resolving script filename and setting URL.
2690 if (isset($wConf['module']['name'])) {
2691 $urlParameters = array();
2692 if (isset($wConf['module']['urlParameters']) && is_array($wConf['module']['urlParameters'])) {
2693 $urlParameters = $wConf['module']['urlParameters'];
2694 }
2695 $wScript = BackendUtility::getModuleUrl($wConf['module']['name'], $urlParameters, $this->backPath);
2696 } elseif (in_array($wConf['type'], array('script', 'colorbox', 'popup'), TRUE)) {
2697 // Illegal configuration, fail silently
2698 break;
2699 }
2700 $url = ($wScript ?: $this->backPath) . (strstr($wScript, '?') ? '' : '?');
2701 // If "script" type, create the links around the icon:
2702 if ((string)$wConf['type'] === 'script') {
2703 $aUrl = $url . GeneralUtility::implodeArrayForUrl('', array('P' => $params));
2704 $outArr[] = '<a href="' . htmlspecialchars($aUrl) . '" onclick="this.blur(); return !TBE_EDITOR.isFormChanged();">' . $icon . '</a>';
2705 } else {
2706 // ... else types "popup", "colorbox" and "userFunc" will need additional parameters:
2707 $params['formName'] = $this->formName;
2708 $params['itemName'] = $itemName;
2709 $params['hmac'] = GeneralUtility::hmac($params['formName'] . $params['itemName'], 'wizard_js');
2710 $params['fieldChangeFunc'] = $fieldChangeFunc;
2711 $params['fieldChangeFuncHash'] = GeneralUtility::hmac(serialize($fieldChangeFunc));
2712 switch ((string)$wConf['type']) {
2713 case 'popup':
2714 case 'colorbox':
2715 // Current form value is passed as P[currentValue]!
2716 $addJS = $wConf['popup_onlyOpenIfSelected']
2717 ? 'if (!TBE_EDITOR.curSelected(\'' . $itemName . $listFlag . '\')){alert('
2718 . GeneralUtility::quoteJSvalue($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:mess.noSelItemForEdit'))
2719 . '); return false;}'
2720 : '';
2721 $curSelectedValues = '+\'&P[currentSelectedValues]=\'+TBE_EDITOR.curSelected(\'' . $itemName . $listFlag . '\')';
2722 $aOnClick = 'this.blur();' . $addJS . 'vHWin=window.open(\'' . $url
2723 . GeneralUtility::implodeArrayForUrl('', array('P' => $params))
2724 . '\'+\'&P[currentValue]=\'+TBE_EDITOR.rawurlencode('
2725 . $this->elName($itemName) . '.value,200)' . $curSelectedValues
2726 . ',\'popUp' . $md5ID . '\',\'' . $wConf['JSopenParams'] . '\');'
2727 . 'vHWin.focus();return false;';
2728 // Setting "colorBoxLinks" - user LATER to wrap around the color box as well:
2729 $colorBoxLinks = array('<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">', '</a>');
2730 if ((string)$wConf['type'] == 'popup') {
2731 $outArr[] = $colorBoxLinks[0] . $icon . $colorBoxLinks[1];
2732 }
2733 break;
2734 case 'userFunc':
2735 // Reference set!
2736 $params['item'] = &$item;
2737 $params['icon'] = $icon;
2738 $params['iTitle'] = $iTitle;
2739 $params['wConf'] = $wConf;
2740 $params['row'] = $row;
2741 $outArr[] = GeneralUtility::callUserFunction($wConf['userFunc'], $params, $this);
2742 break;
2743 case 'slider':
2744 // Reference set!
2745 $params['item'] = &$item;
2746 $params['icon'] = $icon;
2747 $params['iTitle'] = $iTitle;
2748 $params['wConf'] = $wConf;
2749 $params['row'] = $row;
2750 $wizard = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\ValueSlider::class);
2751 $outArr[] = call_user_func_array(array(&$wizard, 'renderWizard'), array(&$params, &$this));
2752 break;
2753 }
2754 }
2755 // Hide the real form element?
2756 if (is_array($wConf['hideParent']) || $wConf['hideParent']) {
2757 // Setting the item to a hidden-field.
2758 $item = $itemKinds[1];
2759 if (is_array($wConf['hideParent'])) {
2760 $item .=