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