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