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