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