[BUGFIX] Get suggest wizard working with renderMode=checkbox
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / FormEngine.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 1999-2013 Kasper Skårhøj (kasperYYYY@typo3.com)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the text file GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29
30 use TYPO3\CMS\Backend\Form\Element\InlineElement;
31 use TYPO3\CMS\Backend\Utility\BackendUtility;
32 use TYPO3\CMS\Backend\Utility\IconUtility;
33 use TYPO3\CMS\Core\Html\HtmlParser;
34 use TYPO3\CMS\Core\Messaging\FlashMessage;
35 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
36 use TYPO3\CMS\Core\Utility\GeneralUtility;
37 use TYPO3\CMS\Core\Utility\MathUtility;
38
39 /**
40 * 'TCEforms' - Class for creating the backend editing forms.
41 *
42 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
43 * @coauthor René Fritz <r.fritz@colorcube.de>
44 */
45 class FormEngine {
46
47 // variables not commented yet.... (do so...)
48 /**
49 * @todo Define visibility
50 */
51 public $palFieldArr = array();
52
53 /**
54 * @todo Define visibility
55 */
56 public $disableWizards = 0;
57
58 /**
59 * @todo Define visibility
60 */
61 public $isPalettedoc = 0;
62
63 /**
64 * @todo Define visibility
65 */
66 public $paletteMargin = 1;
67
68 /**
69 * @todo Define visibility
70 */
71 public $defStyle = '';
72
73 /**
74 * @todo Define visibility
75 */
76 public $cachedTSconfig = array();
77
78 /**
79 * @todo Define visibility
80 */
81 public $cachedTSconfig_fieldLevel = array();
82
83 /**
84 * @todo Define visibility
85 */
86 public $cachedLanguageFlag = array();
87
88 /**
89 * @todo Define visibility
90 */
91 public $cachedAdditionalPreviewLanguages = NULL;
92
93 /**
94 * @todo Define visibility
95 */
96 public $transformedRow = array();
97
98 /**
99 * @todo Define visibility
100 */
101 public $extJSCODE = '';
102
103 /**
104 * @todo Define visibility
105 */
106 public $printNeededJS = array();
107
108 /**
109 * @todo Define visibility
110 */
111 public $hiddenFieldAccum = array();
112
113 /**
114 * @todo Define visibility
115 */
116 public $TBE_EDITOR_fieldChanged_func = '';
117
118 /**
119 * @todo Define visibility
120 */
121 public $loadMD5_JS = 1;
122
123 // Something unique...
124 /**
125 * @todo Define visibility
126 */
127 public $prevBorderStyle = '[nothing here...]';
128
129 // If set direct upload fields will be shown
130 /**
131 * @todo Define visibility
132 */
133 public $allowUpload = 0;
134
135 // Array where records in the default language is stored. (processed by transferdata)
136 /**
137 * @todo Define visibility
138 */
139 public $defaultLanguageData = array();
140
141 // Array where records in the default language is stored (raw without any processing. used for making diff)
142 /**
143 * @todo Define visibility
144 */
145 public $defaultLanguageData_diff = array();
146
147 /**
148 * @todo Define visibility
149 */
150 public $additionalPreviewLanguageData = array();
151
152 // EXTERNAL, static
153 // Set this to the 'backPath' pointing back to the typo3 admin directory from the script where this form is displayed.
154 /**
155 * @todo Define visibility
156 */
157 public $backPath = '';
158
159 // Alternative return URL path (default is \TYPO3\CMS\Core\Utility\GeneralUtility::linkThisScript())
160 /**
161 * @todo Define visibility
162 */
163 public $returnUrl = '';
164
165 // Can be set to point to a field name in the form which will be set to '1' when the form is submitted with a *save* button. This way the recipient script can determine that the form was submitted for save and not "close" for example.
166 /**
167 * @todo Define visibility
168 */
169 public $doSaveFieldName = '';
170
171 // Can be set TRUE/FALSE to whether palettes (secondary options) are in the topframe or in form. TRUE means they are NOT IN-form. So a collapsed palette is one, which is shown in the top frame, not in the page.
172 /**
173 * @todo Define visibility
174 */
175 public $palettesCollapsed = 0;
176
177 // If set, the RTE is disabled (from form display, eg. by checkbox in the bottom of the page!)
178 /**
179 * @todo Define visibility
180 */
181 public $disableRTE = 0;
182
183 // If FALSE, then all CSH will be disabled, regardless of settings in $this->edit_showFieldHelp
184 /**
185 * @todo Define visibility
186 */
187 public $globalShowHelp = 1;
188
189 // If TRUE, the forms are rendering only localization relevant fields of the records.
190 /**
191 * @todo Define visibility
192 */
193 public $localizationMode = '';
194
195 // Overrule the field order set in TCA[types][showitem], eg for tt_content this value, 'bodytext,image', would make first the 'bodytext' field, then the 'image' field (if set for display)... and then the rest in the old order.
196 /**
197 * @todo Define visibility
198 */
199 public $fieldOrder = '';
200
201 // If set to FALSE, palettes will NEVER be rendered.
202 /**
203 * @todo Define visibility
204 */
205 public $doPrintPalette = 1;
206
207 /**
208 * Set to initialized clipboard object; Then the element browser will offer a link to paste in records from clipboard.
209 *
210 * @var \TYPO3\CMS\Backend\Clipboard\Clipboard
211 * @todo Define visibility
212 */
213 public $clipObj = FALSE;
214
215 // Enable click menu on reference icons.
216 /**
217 * @todo Define visibility
218 */
219 public $enableClickMenu = FALSE;
220
221 // Enable Tab Menus.
222 /**
223 * @todo Define visibility
224 */
225 public $enableTabMenu = FALSE;
226
227 // When enabled all fields are rendered non-editable.
228 /**
229 * @todo Define visibility
230 */
231 public $renderReadonly = FALSE;
232
233 // Form field width compensation: Factor from NN4 form field widths to style-aware browsers (like NN6+ and MSIE, with the $GLOBALS['CLIENT']['FORMSTYLE'] value set)
234 /**
235 * @todo Define visibility
236 */
237 public $form_rowsToStylewidth = 9.58;
238
239 /**
240 * Value that gets added for style="width: ...px" for textareas compared to input fields.
241 *
242 * @var integer
243 */
244 protected $form_additionalTextareaStyleWidth = 23;
245
246 // Form field width compensation: Compensation for large documents, doc-tab (editing)
247 /**
248 * @todo Define visibility
249 */
250 public $form_largeComp = 1.33;
251
252 // The number of chars expected per row when the height of a text area field is automatically calculated based on the number of characters found in the field content.
253 /**
254 * @todo Define visibility
255 */
256 public $charsPerRow = 40;
257
258 // The maximum abstract value for textareas
259 /**
260 * @todo Define visibility
261 */
262 public $maxTextareaWidth = 48;
263
264 // The maximum abstract value for input fields
265 /**
266 * @todo Define visibility
267 */
268 public $maxInputWidth = 48;
269
270 // Default style for the selector boxes used for multiple items in "select" and "group" types.
271 /**
272 * @todo Define visibility
273 */
274 public $defaultMultipleSelectorStyle = 'width:310px;';
275
276 // INTERNAL, static
277 // The string to prepend formfield names with.
278 /**
279 * @todo Define visibility
280 */
281 public $prependFormFieldNames = 'data';
282
283 // The string to prepend commands for tcemain::process_cmdmap with.
284 /**
285 * @todo Define visibility
286 */
287 public $prependCmdFieldNames = 'cmd';
288
289 // The string to prepend FILE form field names with.
290 /**
291 * @todo Define visibility
292 */
293 public $prependFormFieldNames_file = 'data_files';
294
295 /**
296 * The string to prepend form field names that are active (not NULL).
297 *
298 * @var string
299 */
300 protected $prependFormFieldNamesActive = 'control[active]';
301
302 // The name attribute of the form.
303 /**
304 * @todo Define visibility
305 */
306 public $formName = 'editform';
307
308 // Whitelist that allows TCA field configuration to be overridden by TSconfig, @see overrideFieldConf()
309 /**
310 * @todo Define visibility
311 */
312 public $allowOverrideMatrix = array();
313
314 // INTERNAL, dynamic
315 // Set by readPerms() (caching)
316 /**
317 * @todo Define visibility
318 */
319 public $perms_clause = '';
320
321 // Set by readPerms() (caching-flag)
322 /**
323 * @todo Define visibility
324 */
325 public $perms_clause_set = 0;
326
327 // Used to indicate the mode of CSH (Context Sensitive Help), whether it should be icons-only ('icon') or not at all (blank).
328 /**
329 * @todo Define visibility
330 */
331 public $edit_showFieldHelp = '';
332
333 // If set, the forms will be rendered a little wider, more precisely with a factor of $this->form_largeComp.
334 /**
335 * @todo Define visibility
336 */
337 public $docLarge = 0;
338
339 // Loaded with info about the browser when class is instantiated.
340 /**
341 * @todo Define visibility
342 */
343 public $clientInfo = array();
344
345 // TRUE, if RTE is possible for the current user (based on result from BE_USER->isRTE())
346 /**
347 * @todo Define visibility
348 */
349 public $RTEenabled = 0;
350
351 // If $this->RTEenabled was FALSE, you can find the reasons listed in this array which is filled with reasons why the RTE could not be loaded)
352 /**
353 * @todo Define visibility
354 */
355 public $RTEenabled_notReasons = '';
356
357 // Counter that is incremented before an RTE is created. Can be used for unique ids etc.
358 /**
359 * @todo Define visibility
360 */
361 public $RTEcounter = 0;
362
363 // Contains current color scheme
364 /**
365 * @todo Define visibility
366 */
367 public $colorScheme;
368
369 // Contains current class scheme
370 /**
371 * @todo Define visibility
372 */
373 public $classScheme;
374
375 // Contains the default color scheme
376 /**
377 * @todo Define visibility
378 */
379 public $defColorScheme;
380
381 // Contains the default class scheme
382 /**
383 * @todo Define visibility
384 */
385 public $defClassScheme;
386
387 // Contains field style values
388 /**
389 * @todo Define visibility
390 */
391 public $fieldStyle;
392
393 // Contains border style values.
394 /**
395 * @todo Define visibility
396 */
397 public $borderStyle;
398
399 // An accumulation of messages from the class.
400 /**
401 * @todo Define visibility
402 */
403 public $commentMessages = array();
404
405 // INTERNAL, templates
406 // Total wrapping for the table rows.
407 /**
408 * @todo Define visibility
409 */
410 public $totalWrap = '<hr />|<hr />';
411
412 // Field template
413 /**
414 * @todo Define visibility
415 */
416 public $fieldTemplate = '<strong>###FIELD_NAME###</strong><br />###FIELD_ITEM###<hr />';
417
418 /**
419 * Template subpart for palette fields.
420 *
421 * @var string
422 */
423 protected $paletteFieldTemplate;
424
425 // Wrapping template code for a section
426 /**
427 * @todo Define visibility
428 */
429 public $sectionWrap = '';
430
431 // Template for palette headers
432 /**
433 * @todo Define visibility
434 */
435 public $palFieldTemplateHeader = '';
436
437 // Template for palettes
438 /**
439 * @todo Define visibility
440 */
441 public $palFieldTemplate = '';
442
443 // INTERNAL, working memory
444 // Set to the fields NOT to display, if any.
445 /**
446 * @todo Define visibility
447 */
448 public $excludeElements = '';
449
450 // During rendering of forms this will keep track of which palettes has already been rendered (so they are not rendered twice by mistake)
451 /**
452 * @todo Define visibility
453 */
454 public $palettesRendered = array();
455
456 // This array of fields will be set as hidden-fields instead of rendered normally! For instance palette fields edited in the top frame are set as hidden fields since the main form has to submit the values. The top frame actually just sets the value in the main form!
457 /**
458 * @todo Define visibility
459 */
460 public $hiddenFieldListArr = array();
461
462 // Used to register input-field names, which are required. (Done during rendering of the fields). This information is then used later when the JavaScript is made.
463 /**
464 * @todo Define visibility
465 */
466 public $requiredFields = array();
467
468 // Used to register input-field names, which are required an have additional requirements (e.g. like a date/time must be positive integer). The information of this array is merged with $this->requiredFields later.
469 /**
470 * @todo Define visibility
471 */
472 public $requiredAdditional = array();
473
474 // Used to register the min and max number of elements for selectorboxes where that apply (in the "group" type for instance)
475 /**
476 * @todo Define visibility
477 */
478 public $requiredElements = array();
479
480 // Used to determine where $requiredFields or $requiredElements are nested (in Tabs or IRRE)
481 /**
482 * @todo Define visibility
483 */
484 public $requiredNested = array();
485
486 // Keeps track of the rendering depth of nested records.
487 /**
488 * @todo Define visibility
489 */
490 public $renderDepth = 0;
491
492 // Color scheme buffer.
493 /**
494 * @todo Define visibility
495 */
496 public $savedSchemes = array();
497
498 // holds the path an element is nested in (e.g. required for RTEhtmlarea)
499 /**
500 * @todo Define visibility
501 */
502 public $dynNestedStack = array();
503
504 // Internal, registers for user defined functions etc.
505 // Additional HTML code, printed before the form.
506 /**
507 * @todo Define visibility
508 */
509 public $additionalCode_pre = array();
510
511 // Additional JavaScript, printed before the form
512 /**
513 * @todo Define visibility
514 */
515 public $additionalJS_pre = array();
516
517 // Additional JavaScript printed after the form
518 /**
519 * @todo Define visibility
520 */
521 public $additionalJS_post = array();
522
523 // Additional JavaScript executed on submit; If you set "OK" variable it will raise an error about RTEs not being loaded and offer to block further submission.
524 /**
525 * @todo Define visibility
526 */
527 public $additionalJS_submit = array();
528
529 // Additional JavaScript executed when section element is deleted. This is necessary, for example, to correctly clean up HTMLArea RTE (bug #8232)
530 /**
531 * @todo Define visibility
532 */
533 public $additionalJS_delete = array();
534
535 /**
536 * @var \TYPO3\CMS\Backend\Form\Element\InlineElement
537 * @todo Define visibility
538 */
539 public $inline;
540
541 // Array containing hook class instances called once for a form
542 /**
543 * @todo Define visibility
544 */
545 public $hookObjectsMainFields = array();
546
547 // Array containing hook class instances called for each field
548 /**
549 * @todo Define visibility
550 */
551 public $hookObjectsSingleField = array();
552
553 // Rows gettings inserted into the alt_doc headers (when called from alt_doc.php)
554 /**
555 * @todo Define visibility
556 */
557 public $extraFormHeaders = array();
558
559 public $templateFile = '';
560
561 /**
562 * @var integer
563 */
564 protected $multiSelectFilterCount = 0;
565
566 /**
567 * @var \TYPO3\CMS\Backend\Form\Element\SuggestElement
568 */
569 protected $suggest;
570
571 // Form templates, relative to typo3 directory
572 /**
573 * Constructor function, setting internal variables, loading the styles used.
574 *
575 * @return void
576 * @todo Define visibility
577 */
578 public function __construct() {
579 $this->clientInfo = GeneralUtility::clientInfo();
580 $this->RTEenabled = $GLOBALS['BE_USER']->isRTE();
581 if (!$this->RTEenabled) {
582 $this->RTEenabled_notReasons = implode(LF, $GLOBALS['BE_USER']->RTE_errors);
583 $this->commentMessages[] = 'RTE NOT ENABLED IN SYSTEM due to:' . LF . $this->RTEenabled_notReasons;
584 }
585 // Default color+class scheme
586 $this->defColorScheme = array(
587 $GLOBALS['SOBE']->doc->bgColor,
588 // Background for the field AND palette
589 GeneralUtility::modifyHTMLColorAll($GLOBALS['SOBE']->doc->bgColor, -20),
590 // Background for the field header
591 GeneralUtility::modifyHTMLColorAll($GLOBALS['SOBE']->doc->bgColor, -10),
592 // Background for the palette field header
593 'black',
594 // Field header font color
595 '#666666'
596 );
597 $this->defColorScheme = array();
598 // Override / Setting defaults from TBE_STYLES array
599 $this->resetSchemes();
600 // Setting the current colorScheme to default.
601 $this->defColorScheme = $this->colorScheme;
602 $this->defClassScheme = $this->classScheme;
603 // Define whitelist that allows TCA field configuration to be overridden by TSconfig, @see overrideFieldConf():
604 $this->allowOverrideMatrix = array(
605 'input' => array('size', 'max', 'readOnly'),
606 'text' => array('cols', 'rows', 'wrap', 'readOnly'),
607 'check' => array('cols', 'showIfRTE', 'readOnly'),
608 'select' => array('size', 'autoSizeMax', 'maxitems', 'minitems', 'readOnly', 'treeConfig'),
609 'group' => array('size', 'autoSizeMax', 'max_size', 'show_thumbs', 'maxitems', 'minitems', 'disable_controls', 'readOnly'),
610 'inline' => array('appearance', 'behaviour', 'foreign_label', 'foreign_selector', 'foreign_unique', 'maxitems', 'minitems', 'size', 'autoSizeMax', 'symmetric_label', 'readOnly')
611 );
612 // Create instance of InlineElement only if this a non-IRRE-AJAX call:
613 if (!isset($GLOBALS['ajaxID']) || strpos($GLOBALS['ajaxID'], 'TYPO3\\CMS\\Backend\\Form\\Element\\InlineElement::') !== 0) {
614 $this->inline = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\Element\\InlineElement');
615 }
616 // Create instance of \TYPO3\CMS\Backend\Form\Element\SuggestElement only if this a non-Suggest-AJAX call:
617 if (!isset($GLOBALS['ajaxID']) || strpos($GLOBALS['ajaxID'], 'TYPO3\\CMS\\Backend\\Form\\Element\\SuggestElement::') !== 0) {
618 $this->suggest = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\Element\\SuggestElement');
619 }
620 // Prepare user defined objects (if any) for hooks which extend this function:
621 $this->hookObjectsMainFields = array();
622 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getMainFieldsClass'])) {
623 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getMainFieldsClass'] as $classRef) {
624 $this->hookObjectsMainFields[] = GeneralUtility::getUserObj($classRef);
625 }
626 }
627 $this->hookObjectsSingleField = array();
628 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getSingleFieldClass'])) {
629 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getSingleFieldClass'] as $classRef) {
630 $this->hookObjectsSingleField[] = GeneralUtility::getUserObj($classRef);
631 }
632 }
633 $this->templateFile = 'sysext/backend/Resources/Private/Templates/FormEngine.html';
634 }
635
636 /**
637 * Initialize various internal variables.
638 *
639 * @return void
640 * @todo Define visibility
641 */
642 public function initDefaultBEmode() {
643 $this->prependFormFieldNames = 'data';
644 $this->formName = 'editform';
645 $this->setNewBEDesign();
646 $this->docLarge = $GLOBALS['BE_USER']->uc['edit_wideDocument'] ? 1 : 0;
647 $this->edit_showFieldHelp = $GLOBALS['BE_USER']->uc['edit_showFieldHelp'];
648 $this->edit_docModuleUpload = $GLOBALS['BE_USER']->uc['edit_docModuleUpload'];
649 $this->inline->init($this);
650 $this->suggest->init($this);
651 }
652
653 /*******************************************************
654 *
655 * Rendering the forms, fields etc
656 *
657 *******************************************************/
658 /**
659 * Will return the TCEform element for just a single field from a record.
660 * The field must be listed in the currently displayed fields (as found in [types][showitem]) for the record.
661 * This also means that the $table/$row supplied must be complete so the list of fields to show can be found correctly
662 *
663 * @param string $table The table name
664 * @param array $row The record from the table for which to render a field.
665 * @param string $theFieldToReturn The field name to return the TCEform element for.
666 * @return string HTML output
667 * @see getMainFields()
668 * @todo Define visibility
669 */
670 public function getSoloField($table, $row, $theFieldToReturn) {
671 if ($GLOBALS['TCA'][$table]) {
672 $typeNum = $this->getRTypeNum($table, $row);
673 if ($GLOBALS['TCA'][$table]['types'][$typeNum]) {
674 $itemList = $GLOBALS['TCA'][$table]['types'][$typeNum]['showitem'];
675 if ($itemList) {
676 $fields = GeneralUtility::trimExplode(',', $itemList, TRUE);
677 $excludeElements = ($this->excludeElements = $this->getExcludeElements($table, $row, $typeNum));
678 foreach ($fields as $fieldInfo) {
679 $parts = explode(';', $fieldInfo);
680 $theField = trim($parts[0]);
681 if (!in_array($theField, $excludeElements) && (string)$theField === (string)$theFieldToReturn) {
682 if ($GLOBALS['TCA'][$table]['columns'][$theField]) {
683 $sField = $this->getSingleField($table, $theField, $row, $parts[1], 1, $parts[3], $parts[2]);
684 return $sField['ITEM'];
685 }
686 }
687 }
688 }
689 }
690 }
691 }
692
693 /**
694 * Based on the $table and $row of content, this displays the complete TCEform for the record.
695 * The input-$row is required to be preprocessed if necessary by eg.
696 * the \TYPO3\CMS\Backend\Form\DataPreprocessor class. For instance the RTE content
697 * should be transformed through this class first.
698 *
699 * @param string $table The table name
700 * @param array $row The record from the table for which to render a field.
701 * @param integer $depth Depth level
702 * @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'].
703 * @return string HTML output
704 * @see getSoloField()
705 * @todo Define visibility
706 */
707 public function getMainFields($table, array $row, $depth = 0, array $overruleTypesArray = array()) {
708 $this->renderDepth = $depth;
709 // Init vars:
710 $out_array = array(array());
711 $out_array_meta = array(
712 array(
713 'title' => $this->getLL('l_generalTab')
714 )
715 );
716 $out_pointer = 0;
717 $out_sheet = 0;
718 $this->palettesRendered = array();
719 $this->palettesRendered[$this->renderDepth][$table] = array();
720 // Hook: getMainFields_preProcess (requested by Thomas Hempel for use with the "dynaflex" extension)
721 foreach ($this->hookObjectsMainFields as $hookObj) {
722 if (method_exists($hookObj, 'getMainFields_preProcess')) {
723 $hookObj->getMainFields_preProcess($table, $row, $this);
724 }
725 }
726 if ($GLOBALS['TCA'][$table]) {
727 // Get dividers2tabs setting from TCA of the current table:
728 $dividers2tabs = &$GLOBALS['TCA'][$table]['ctrl']['dividers2tabs'];
729 // Load the description content for the table.
730 if ($this->edit_showFieldHelp || $this->doLoadTableDescr($table)) {
731 $GLOBALS['LANG']->loadSingleTableDescription($table);
732 }
733 // Get the current "type" value for the record.
734 $typeNum = $this->getRTypeNum($table, $row);
735 // Find the list of fields to display:
736 if ($GLOBALS['TCA'][$table]['types'][$typeNum]) {
737 $itemList = $GLOBALS['TCA'][$table]['types'][$typeNum]['showitem'];
738 if (is_array($overruleTypesArray) && isset($overruleTypesArray[$typeNum]['showitem'])) {
739 $itemList = $overruleTypesArray[$typeNum]['showitem'];
740 }
741 // If such a list existed...
742 if ($itemList) {
743 // Explode the field list and possibly rearrange the order of the fields, if configured for
744 $fields = GeneralUtility::trimExplode(',', $itemList, TRUE);
745 if ($this->fieldOrder) {
746 $fields = $this->rearrange($fields);
747 }
748 // Get excluded fields, added fiels and put it together:
749 $excludeElements = ($this->excludeElements = $this->getExcludeElements($table, $row, $typeNum));
750 $fields = $this->mergeFieldsWithAddedFields($fields, $this->getFieldsToAdd($table, $row, $typeNum), $table);
751 // If TCEforms will render a tab menu in the next step, push the name to the tab stack:
752 $tabIdentString = '';
753 $tabIdentStringMD5 = '';
754 if (strstr($itemList, '--div--') !== FALSE && $this->enableTabMenu && $dividers2tabs) {
755 $tabIdentString = 'TCEforms:' . $table . ':' . $row['uid'];
756 $tabIdentStringMD5 = $GLOBALS['TBE_TEMPLATE']->getDynTabMenuId($tabIdentString);
757 // Remember that were currently working on the general tab:
758 if (isset($fields[0]) && strpos($fields[0], '--div--') !== 0) {
759 $this->pushToDynNestedStack('tab', $tabIdentStringMD5 . '-1');
760 }
761 }
762 // Traverse the fields to render:
763 $cc = 0;
764 foreach ($fields as $fieldInfo) {
765 // Exploding subparts of the field configuration:
766 $parts = explode(';', $fieldInfo);
767 // Getting the style information out:
768 $color_style_parts = GeneralUtility::trimExplode('-', $parts[4]);
769 if ($color_style_parts[0] !== '') {
770 $this->setColorScheme($GLOBALS['TBE_STYLES']['colorschemes'][intval($color_style_parts[0])]);
771 }
772 if ($color_style_parts[1] !== '') {
773 $this->fieldStyle = $GLOBALS['TBE_STYLES']['styleschemes'][intval($color_style_parts[1])];
774 if (!isset($this->fieldStyle)) {
775 $this->fieldStyle = $GLOBALS['TBE_STYLES']['styleschemes'][0];
776 }
777 }
778 if ($color_style_parts[2] !== '') {
779 $this->wrapBorder($out_array[$out_sheet], $out_pointer);
780 $this->borderStyle = $GLOBALS['TBE_STYLES']['borderschemes'][intval($color_style_parts[2])];
781 if (!isset($this->borderStyle)) {
782 $this->borderStyle = $GLOBALS['TBE_STYLES']['borderschemes'][0];
783 }
784 }
785 // Render the field:
786 $theField = $parts[0];
787 if (!in_array($theField, $excludeElements)) {
788 if ($GLOBALS['TCA'][$table]['columns'][$theField]) {
789 $sFieldPal = '';
790 if ($parts[2] && !isset($this->palettesRendered[$this->renderDepth][$table][$parts[2]])) {
791 $sFieldPal = $this->getPaletteFields($table, $row, $parts[2]);
792 $this->palettesRendered[$this->renderDepth][$table][$parts[2]] = 1;
793 }
794 $sField = $this->getSingleField($table, $theField, $row, $parts[1], 0, $parts[3], $parts[2]);
795 if ($sField) {
796 $sField .= $sFieldPal;
797 }
798 $out_array[$out_sheet][$out_pointer] .= $sField;
799 } elseif ($theField == '--div--') {
800 if ($cc > 0) {
801 $out_array[$out_sheet][$out_pointer] .= $this->getDivider();
802 if ($this->enableTabMenu && $dividers2tabs) {
803 $this->wrapBorder($out_array[$out_sheet], $out_pointer);
804 // Remove last tab entry from the dynNestedStack:
805 $out_sheet++;
806 // Remove the previous sheet from stack (if any):
807 $this->popFromDynNestedStack('tab', $tabIdentStringMD5 . '-' . $out_sheet);
808 // Remember on which sheet we're currently working:
809 $this->pushToDynNestedStack('tab', $tabIdentStringMD5 . '-' . ($out_sheet + 1));
810 $out_array[$out_sheet] = array();
811 $out_array_meta[$out_sheet]['title'] = $this->sL($parts[1]);
812 // Register newline for Tab
813 $out_array_meta[$out_sheet]['newline'] = $parts[2] == 'newline';
814 }
815 } else {
816 // Setting alternative title for "General" tab if "--div--" is the very first element.
817 $out_array_meta[$out_sheet]['title'] = $this->sL($parts[1]);
818 // Only add the first tab to the dynNestedStack if there are more tabs:
819 if ($tabIdentString && strpos($itemList, '--div--', strlen($fieldInfo))) {
820 $this->pushToDynNestedStack('tab', $tabIdentStringMD5 . '-1');
821 }
822 }
823 } elseif ($theField == '--palette--') {
824 if ($parts[2] && !isset($this->palettesRendered[$this->renderDepth][$table][$parts[2]])) {
825 // Render a 'header' if not collapsed
826 if ($GLOBALS['TCA'][$table]['palettes'][$parts[2]]['canNotCollapse'] && $parts[1]) {
827 $out_array[$out_sheet][$out_pointer] .= $this->getPaletteFields($table, $row, $parts[2], $this->sL($parts[1]));
828 } else {
829 $out_array[$out_sheet][$out_pointer] .= $this->getPaletteFields($table, $row, $parts[2], '', '', $this->sL($parts[1]));
830 }
831 $this->palettesRendered[$this->renderDepth][$table][$parts[2]] = 1;
832 }
833 }
834 }
835 $cc++;
836 }
837 }
838 }
839 }
840 // Hook: getMainFields_postProcess (requested by Thomas Hempel for use with the "dynaflex" extension)
841 foreach ($this->hookObjectsMainFields as $hookObj) {
842 if (method_exists($hookObj, 'getMainFields_postProcess')) {
843 $hookObj->getMainFields_postProcess($table, $row, $this);
844 }
845 }
846 // Wrapping a border around it all:
847 $this->wrapBorder($out_array[$out_sheet], $out_pointer);
848 // Resetting styles:
849 $this->resetSchemes();
850 // Rendering Main palettes, if any
851 $mParr = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['mainpalette']);
852 $i = 0;
853 if (count($mParr)) {
854 foreach ($mParr as $mP) {
855 if (!isset($this->palettesRendered[$this->renderDepth][$table][$mP])) {
856 $temp_palettesCollapsed = $this->palettesCollapsed;
857 $this->palettesCollapsed = 0;
858 $label = $i == 0 ? $this->getLL('l_generalOptions') : $this->getLL('l_generalOptions_more');
859 $out_array[$out_sheet][$out_pointer] .= $this->getPaletteFields($table, $row, $mP, $label);
860 $this->palettesCollapsed = $temp_palettesCollapsed;
861 $this->palettesRendered[$this->renderDepth][$table][$mP] = 1;
862 }
863 $this->wrapBorder($out_array[$out_sheet], $out_pointer);
864 $i++;
865 if ($this->renderDepth) {
866 $this->renderDepth--;
867 }
868 }
869 }
870 // Return the imploded $out_array:
871 // There were --div-- dividers around...
872 if ($out_sheet > 0) {
873 // Create parts array for the tab menu:
874 $parts = array();
875 foreach ($out_array as $idx => $sheetContent) {
876 $content = implode('', $sheetContent);
877 if ($content) {
878 // Wrap content (row) with table-tag, otherwise tab/sheet will be disabled (see getdynTabMenu() )
879 $content = '<table border="0" cellspacing="0" cellpadding="0" width="100%">' . $content . '</table>';
880 }
881 $parts[$idx] = array(
882 'label' => $out_array_meta[$idx]['title'],
883 'content' => $content,
884 'newline' => $out_array_meta[$idx]['newline']
885 );
886 }
887 if (count($parts) > 1) {
888 // Unset the current level of tab menus:
889 $this->popFromDynNestedStack('tab', $tabIdentStringMD5 . '-' . ($out_sheet + 1));
890 $dividersToTabsBehaviour = isset($GLOBALS['TCA'][$table]['ctrl']['dividers2tabs']) ? $GLOBALS['TCA'][$table]['ctrl']['dividers2tabs'] : 1;
891 $output = $this->getDynTabMenu($parts, $tabIdentString, $dividersToTabsBehaviour);
892 } else {
893 // If there is only one tab/part there is no need to wrap it into the dynTab code
894 $output = isset($parts[0]) ? trim($parts[0]['content']) : '';
895 }
896 $output = '
897 <tr>
898 <td colspan="2">
899 ' . $output . '
900 </td>
901 </tr>';
902 } else {
903 // Only one tab, so just implode and wrap the background image (= tab container) around:
904 $output = implode('', $out_array[$out_sheet]);
905 if ($this->inline->inlineCount == 0) {
906 $output = '<div class="typo3-dyntabmenu-divs">' . $output . '</div>';
907 }
908 }
909
910 return $output;
911 }
912
913 /**
914 * Will return the TCEform elements for a pre-defined list of fields.
915 * 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.
916 * Used for displaying forms for the frontend edit icons for instance.
917 *
918 * @param string $table The table name
919 * @param array $row The record array.
920 * @param string $list Commalist of fields from the table. These will be shown in the specified order in a form.
921 * @return string TCEform elements in a string.
922 * @todo Define visibility
923 */
924 public function getListedFields($table, $row, $list) {
925 if ($this->edit_showFieldHelp || $this->doLoadTableDescr($table)) {
926 $GLOBALS['LANG']->loadSingleTableDescription($table);
927 }
928 $out = '';
929 $types_fieldConfig = BackendUtility::getTCAtypes($table, $row, 1);
930 $editFieldList = array_unique(GeneralUtility::trimExplode(',', $list, TRUE));
931 foreach ($editFieldList as $theFieldC) {
932 list($theField, $palFields) = preg_split('/\\[|\\]/', $theFieldC);
933 $theField = trim($theField);
934 $palFields = trim($palFields);
935 if ($GLOBALS['TCA'][$table]['columns'][$theField]) {
936 $parts = GeneralUtility::trimExplode(';', $types_fieldConfig[$theField]['origString']);
937 // Don't sent palette pointer - there are no options anyways for a field-list.
938 $sField = $this->getSingleField($table, $theField, $row, $parts[1], 0, $parts[3], 0);
939 $out .= $sField;
940 } elseif ($theField == '--div--') {
941 $out .= $this->getDivider();
942 }
943 if ($palFields) {
944 $out .= $this->getPaletteFields($table, $row, '', '', implode(',', GeneralUtility::trimExplode('|', $palFields, TRUE)));
945 }
946 }
947 return $out;
948 }
949
950 /**
951 * Creates a palette (collection of secondary options).
952 *
953 * @param string $table The table name
954 * @param array $row The row array
955 * @param string $palette The palette number/pointer
956 * @param string $header Header string for the palette (used when in-form). If not set, no header item is made.
957 * @param string $itemList Optional alternative list of fields for the palette
958 * @param string $collapsedHeader Optional Link text for activating a palette (when palettes does not have another form element to belong to).
959 * @return string HTML code.
960 * @todo Define visibility
961 */
962 public function getPaletteFields($table, $row, $palette, $header = '', $itemList = '', $collapsedHeader = NULL) {
963 if (!$this->doPrintPalette) {
964 return '';
965 }
966 $out = '';
967 $parts = $this->loadPaletteElements($table, $row, $palette, $itemList);
968 // Put palette together if there are fields in it:
969 if (count($parts)) {
970 $realFields = 0;
971 foreach ($parts as $part) {
972 if ($part['NAME'] !== '--linebreak--') {
973 $realFields++;
974 }
975 }
976 if ($realFields > 0) {
977 if ($header) {
978 $out .= $this->intoTemplate(array('HEADER' => htmlspecialchars($header)), $this->palFieldTemplateHeader);
979 }
980 $collapsed = $this->isPalettesCollapsed($table, $palette);
981 // Check if the palette is a hidden palette
982 $isHiddenPalette = !empty($GLOBALS['TCA'][$table]['palettes'][$palette]['isHiddenPalette']);
983 $thePalIcon = '';
984 if ($collapsed && $collapsedHeader !== NULL && !$isHiddenPalette) {
985 list($thePalIcon, ) = $this->wrapOpenPalette(IconUtility::getSpriteIcon('actions-system-options-view', array('title' => htmlspecialchars($this->getLL('l_moreOptions')))), $table, $row, $palette, 1);
986 $thePalIcon = '<span style="margin-left: 20px;">' . $thePalIcon . $collapsedHeader . '</span>';
987 }
988 $paletteHtml = $this->wrapPaletteField($this->printPalette($parts), $table, $row, $palette, $collapsed);
989 $out .= $this->intoTemplate(array('PALETTE' => $thePalIcon . $paletteHtml), $this->palFieldTemplate);
990 }
991 }
992 return $out;
993 }
994
995 /**
996 * Returns the form HTML code for a database table field.
997 *
998 * @param string $table The table name
999 * @param string $field The field name
1000 * @param array $row The record to edit from the database table.
1001 * @param string $altName Alternative field name label to show.
1002 * @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).
1003 * @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.
1004 * @param integer $pal The palette pointer.
1005 * @return mixed String (normal) or array (palettes)
1006 * @todo Define visibility
1007 */
1008 public function getSingleField($table, $field, $row, $altName = '', $palette = 0, $extra = '', $pal = 0) {
1009 // Hook: getSingleField_preProcess
1010 foreach ($this->hookObjectsSingleField as $hookObj) {
1011 if (method_exists($hookObj, 'getSingleField_preProcess')) {
1012 $hookObj->getSingleField_preProcess($table, $field, $row, $altName, $palette, $extra, $pal, $this);
1013 }
1014 }
1015 $out = '';
1016 $PA = array();
1017 $PA['altName'] = $altName;
1018 $PA['palette'] = $palette;
1019 $PA['extra'] = $extra;
1020 $PA['pal'] = $pal;
1021 // Get the TCA configuration for the current field:
1022 $PA['fieldConf'] = $GLOBALS['TCA'][$table]['columns'][$field];
1023 $PA['fieldConf']['config']['form_type'] = $PA['fieldConf']['config']['form_type'] ? $PA['fieldConf']['config']['form_type'] : $PA['fieldConf']['config']['type'];
1024
1025 // Using "form_type" locally in this script
1026 $skipThisField = $this->inline->skipField($table, $field, $row, $PA['fieldConf']['config']);
1027
1028 // Evaluate display condition
1029 $displayConditionResult = TRUE;
1030 if (is_array($PA['fieldConf']) && $PA['fieldConf']['displayCond'] && is_array($row)) {
1031 /** @var $elementConditionMatcher \TYPO3\CMS\Backend\Form\ElementConditionMatcher */
1032 $elementConditionMatcher = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\ElementConditionMatcher');
1033 $displayConditionResult = $elementConditionMatcher->match($PA['fieldConf']['displayCond'], $row);
1034 }
1035 // Check if this field is configured and editable (according to excludefields + other configuration)
1036 if (
1037 is_array($PA['fieldConf'])
1038 && !$skipThisField
1039 && (!$PA['fieldConf']['exclude'] || $GLOBALS['BE_USER']->check('non_exclude_fields', $table . ':' . $field))
1040 && $PA['fieldConf']['config']['form_type'] != 'passthrough'
1041 && ($this->RTEenabled || !$PA['fieldConf']['config']['showIfRTE'])
1042 && $displayConditionResult
1043 && (!$GLOBALS['TCA'][$table]['ctrl']['languageField'] || $PA['fieldConf']['l10n_display'] || ($PA['fieldConf']['l10n_mode'] !== 'exclude') || $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] <= 0)
1044 && (!$GLOBALS['TCA'][$table]['ctrl']['languageField'] || !$this->localizationMode || $this->localizationMode === $PA['fieldConf']['l10n_cat'])
1045 ) {
1046 // Fetching the TSconfig for the current table/field. This includes the $row which means that
1047 $PA['fieldTSConfig'] = $this->setTSconfig($table, $row, $field);
1048 // If the field is NOT disabled from TSconfig (which it could have been) then render it
1049 if (!$PA['fieldTSConfig']['disabled']) {
1050 // Override fieldConf by fieldTSconfig:
1051 $PA['fieldConf']['config'] = $this->overrideFieldConf($PA['fieldConf']['config'], $PA['fieldTSConfig']);
1052 // Init variables:
1053 $PA['itemFormElName'] = $this->prependFormFieldNames . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
1054 // Form field name, in case of file uploads
1055 $PA['itemFormElName_file'] = $this->prependFormFieldNames_file . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
1056 // Form field name, to activate elements
1057 // If the "eval" list contains "null", elements can be deactivated which results in storing NULL to database
1058 $PA['itemFormElNameActive'] = $this->prependFormFieldNamesActive . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
1059 // The value to show in the form field.
1060 $PA['itemFormElValue'] = $row[$field];
1061 $PA['itemFormElID'] = $this->prependFormFieldNames . '_' . $table . '_' . $row['uid'] . '_' . $field;
1062 // Set field to read-only if configured for translated records to show default language content as readonly
1063 if ($PA['fieldConf']['l10n_display'] && GeneralUtility::inList($PA['fieldConf']['l10n_display'], 'defaultAsReadonly') && $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0) {
1064 $PA['fieldConf']['config']['readOnly'] = TRUE;
1065 $PA['itemFormElValue'] = $this->defaultLanguageData[$table . ':' . $row['uid']][$field];
1066 }
1067 if (strpos($GLOBALS['TCA'][$table]['ctrl']['type'], ':') === FALSE) {
1068 $typeField = $GLOBALS['TCA'][$table]['ctrl']['type'];
1069 } else {
1070 $typeField = substr($GLOBALS['TCA'][$table]['ctrl']['type'], 0, strpos($GLOBALS['TCA'][$table]['ctrl']['type'], ':'));
1071 }
1072 // 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"
1073 if (
1074 !empty($GLOBALS['TCA'][$table]['ctrl']['type'])
1075 && $field === $typeField
1076 || !empty($GLOBALS['TCA'][$table]['ctrl']['requestUpdate'])
1077 && GeneralUtility::inList(str_replace(' ', '', $GLOBALS['TCA'][$table]['ctrl']['requestUpdate']), $field)
1078 ) {
1079 if ($GLOBALS['BE_USER']->jsConfirmation(1)) {
1080 $alertMsgOnChange = 'if (confirm(TBE_EDITOR.labels.onChangeAlert) && TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
1081 } else {
1082 $alertMsgOnChange = 'if (TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
1083 }
1084 } else {
1085 $alertMsgOnChange = '';
1086 }
1087 // Render as a hidden field?
1088 if (in_array($field, $this->hiddenFieldListArr)) {
1089 $this->hiddenFieldAccum[] = '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
1090 } else {
1091 // Render as a normal field:
1092 // 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.
1093 if (!$PA['palette']) {
1094 $paletteFields = $this->loadPaletteElements($table, $row, $PA['pal']);
1095 if ($PA['pal'] && $this->isPalettesCollapsed($table, $PA['pal']) && count($paletteFields)) {
1096 list($thePalIcon, $palJSfunc) = $this->wrapOpenPalette(IconUtility::getSpriteIcon('actions-system-options-view', array('title' => htmlspecialchars($this->getLL('l_moreOptions')))), $table, $row, $PA['pal'], 1);
1097 } else {
1098 $thePalIcon = '';
1099 $palJSfunc = '';
1100 }
1101 }
1102 // onFocus attribute to add to the field:
1103 $PA['onFocus'] = $palJSfunc && !$GLOBALS['BE_USER']->uc['dontShowPalettesOnFocusInAB'] ? ' onfocus="' . htmlspecialchars($palJSfunc) . '"' : '';
1104 // Find item
1105 $item = '';
1106 $PA['label'] = $PA['altName'] ? $PA['altName'] : $PA['fieldConf']['label'];
1107 $PA['label'] = $PA['fieldTSConfig']['label'] ? $PA['fieldTSConfig']['label'] : $PA['label'];
1108 $PA['label'] = $PA['fieldTSConfig']['label.'][$GLOBALS['LANG']->lang] ? $PA['fieldTSConfig']['label.'][$GLOBALS['LANG']->lang] : $PA['label'];
1109 $PA['label'] = $this->sL($PA['label']);
1110 // JavaScript code for event handlers:
1111 $PA['fieldChangeFunc'] = array();
1112 $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'TBE_EDITOR.fieldChanged(\'' . $table . '\',\'' . $row['uid'] . '\',\'' . $field . '\',\'' . $PA['itemFormElName'] . '\');';
1113 $PA['fieldChangeFunc']['alert'] = $alertMsgOnChange;
1114 // If this is the child of an inline type and it is the field creating the label
1115 if ($this->inline->isInlineChildAndLabelField($table, $field)) {
1116 $inlineObjectId = implode(InlineElement::Structure_Separator, array(
1117 $this->inline->inlineNames['object'],
1118 $table,
1119 $row['uid']
1120 ));
1121 $PA['fieldChangeFunc']['inline'] = 'inline.handleChangedField(\'' . $PA['itemFormElName'] . '\',\'' . $inlineObjectId . '\');';
1122 }
1123 // Based on the type of the item, call a render function:
1124 $item = $this->getSingleField_SW($table, $field, $row, $PA);
1125 // Add language + diff
1126 if ($PA['fieldConf']['l10n_display'] && (GeneralUtility::inList($PA['fieldConf']['l10n_display'], 'hideDiff') || GeneralUtility::inList($PA['fieldConf']['l10n_display'], 'defaultAsReadonly'))) {
1127 $renderLanguageDiff = FALSE;
1128 } else {
1129 $renderLanguageDiff = TRUE;
1130 }
1131 if ($renderLanguageDiff) {
1132 $item = $this->renderDefaultLanguageContent($table, $field, $row, $item);
1133 $item = $this->renderDefaultLanguageDiff($table, $field, $row, $item);
1134 }
1135 // 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
1136 $label = GeneralUtility::deHSCentities(htmlspecialchars($PA['label']));
1137 if (MathUtility::canBeInterpretedAsInteger($row['uid']) && $PA['fieldTSConfig']['linkTitleToSelf'] && !GeneralUtility::_GP('columnsOnly')) {
1138 $lTTS_url = $this->backPath . 'alt_doc.php?edit[' . $table . '][' . $row['uid'] . ']=edit&columnsOnly=' . $field . '&returnUrl=' . rawurlencode($this->thisReturnUrl());
1139 $label = '<a href="' . htmlspecialchars($lTTS_url) . '">' . $label . '</a>';
1140 }
1141
1142 if (isset($PA['fieldConf']['config']['mode']) && $PA['fieldConf']['config']['mode'] == 'useOrOverridePlaceholder') {
1143 $placeholder = $this->getPlaceholderValue($table, $field, $PA['fieldConf']['config'], $row);
1144 $onChange = 'typo3form.fieldTogglePlaceholder(' . GeneralUtility::quoteJSvalue($PA['itemFormElName']) . ', !this.checked)';
1145
1146
1147 $isNull = ($PA['itemFormElValue'] === NULL);
1148 $checked = (($isNull || $this->isNewRecord($table, $row)) ? '' : ' checked="checked"');
1149
1150 $this->additionalJS_post[] = 'typo3form.fieldTogglePlaceholder('
1151 . GeneralUtility::quoteJSvalue($PA['itemFormElName']) . ', ' . ($checked ? 'false' : 'true') . ');';
1152
1153 $item = '<div class="t3-form-field-placeholder-override">'
1154 . '<span class="t3-tceforms-placeholder-override-checkbox">' .
1155 '<input type="hidden" name="' . htmlspecialchars($PA['itemFormElNameActive']) . '" value="0" />' .
1156 '<input type="checkbox" name="' . htmlspecialchars($PA['itemFormElNameActive']) . '" value="1" id="tce-forms-textfield-use-override-' . $field . '-' . $row['uid'] . '" onchange="' . htmlspecialchars($onChange) . '"' . $checked . ' />' .
1157 '<label for="tce-forms-textfield-use-override-' . $field . '-' . $row['uid'] . '">' . htmlspecialchars(sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.placeholder.override'), $placeholder)) . '</label>' .
1158 '</span>'
1159 . '<div class="t3-form-placeholder-placeholder">' . $this->getSingleField_typeNone_render($PA['fieldConf']['config'], $placeholder) . '</div>'
1160 . '<div class="t3-form-placeholder-formfield">' . $item . '</div>'
1161 . '</div>';
1162 }
1163
1164 // Wrap the label with help text
1165 $PA['label'] = ($label = BackendUtility::wrapInHelp($table, $field, $label));
1166 // Create output value:
1167 if ($PA['fieldConf']['config']['form_type'] == 'user' && $PA['fieldConf']['config']['noTableWrapping']) {
1168 $out = $item;
1169 } elseif ($PA['palette']) {
1170 // Array:
1171 $out = array(
1172 'NAME' => $label,
1173 'ID' => $row['uid'],
1174 'FIELD' => $field,
1175 'TABLE' => $table,
1176 'ITEM' => $item,
1177 'ITEM_DISABLED' => ($this->isDisabledNullValueField($table, $field, $row, $PA) ? ' disabled' : ''),
1178 'ITEM_NULLVALUE' => $this->renderNullValueWidget($table, $field, $row, $PA),
1179 );
1180 $out = $this->addUserTemplateMarkers($out, $table, $field, $row, $PA);
1181 } else {
1182 // String:
1183 $out = array(
1184 'NAME' => $label,
1185 'ITEM' => $item,
1186 'TABLE' => $table,
1187 'ID' => $row['uid'],
1188 'PAL_LINK_ICON' => $thePalIcon,
1189 'FIELD' => $field,
1190 'ITEM_DISABLED' => ($this->isDisabledNullValueField($table, $field, $row, $PA) ? ' disabled' : ''),
1191 'ITEM_NULLVALUE' => $this->renderNullValueWidget($table, $field, $row, $PA),
1192 );
1193 $out = $this->addUserTemplateMarkers($out, $table, $field, $row, $PA);
1194 // String:
1195 $out = $this->intoTemplate($out);
1196 }
1197 }
1198 } else {
1199 $this->commentMessages[] = $this->prependFormFieldNames . '[' . $table . '][' . $row['uid'] . '][' . $field . ']: Disabled by TSconfig';
1200 }
1201 }
1202 // Hook: getSingleField_postProcess
1203 foreach ($this->hookObjectsSingleField as $hookObj) {
1204 if (method_exists($hookObj, 'getSingleField_postProcess')) {
1205 $hookObj->getSingleField_postProcess($table, $field, $row, $out, $PA, $this);
1206 }
1207 }
1208 // Return value (string or array)
1209 return $out;
1210 }
1211
1212 /**
1213 * Rendering a single item for the form
1214 *
1215 * @param string $table Table name of record
1216 * @param string $field Fieldname to render
1217 * @param array $row The record
1218 * @param array $PA Parameters array containing a lot of stuff. Value by Reference!
1219 * @return string Returns the item as HTML code to insert
1220 * @access private
1221 * @see getSingleField(), getSingleField_typeFlex_draw()
1222 * @todo Define visibility
1223 */
1224 public function getSingleField_SW($table, $field, $row, &$PA) {
1225 $PA['fieldConf']['config']['form_type'] = $PA['fieldConf']['config']['form_type'] ? $PA['fieldConf']['config']['form_type'] : $PA['fieldConf']['config']['type'];
1226 // Using "form_type" locally in this script
1227 // Hook: getSingleField_beforeRender
1228 foreach ($this->hookObjectsSingleField as $hookObject) {
1229 if (method_exists($hookObject, 'getSingleField_beforeRender')) {
1230 $hookObject->getSingleField_beforeRender($table, $field, $row, $PA);
1231 }
1232 }
1233 switch ($PA['fieldConf']['config']['form_type']) {
1234 case 'input':
1235 $item = $this->getSingleField_typeInput($table, $field, $row, $PA);
1236 break;
1237 case 'text':
1238 $item = $this->getSingleField_typeText($table, $field, $row, $PA);
1239 break;
1240 case 'check':
1241 $item = $this->getSingleField_typeCheck($table, $field, $row, $PA);
1242 break;
1243 case 'radio':
1244 $item = $this->getSingleField_typeRadio($table, $field, $row, $PA);
1245 break;
1246 case 'select':
1247 $item = $this->getSingleField_typeSelect($table, $field, $row, $PA);
1248 break;
1249 case 'group':
1250 $item = $this->getSingleField_typeGroup($table, $field, $row, $PA);
1251 break;
1252 case 'inline':
1253 $item = $this->inline->getSingleField_typeInline($table, $field, $row, $PA);
1254 break;
1255 case 'none':
1256 $item = $this->getSingleField_typeNone($table, $field, $row, $PA);
1257 break;
1258 case 'user':
1259 $item = $this->getSingleField_typeUser($table, $field, $row, $PA);
1260 break;
1261 case 'flex':
1262 $item = $this->getSingleField_typeFlex($table, $field, $row, $PA);
1263 break;
1264 default:
1265 $item = $this->getSingleField_typeUnknown($table, $field, $row, $PA);
1266 }
1267 return $item;
1268 }
1269
1270 /**********************************************************
1271 *
1272 * Rendering of each TCEform field type
1273 *
1274 ************************************************************/
1275 /**
1276 * Generation of TCEform elements of the type "input"
1277 * This will render a single-line input form field, possibly with various control/validation features
1278 *
1279 * @param string $table The table name of the record
1280 * @param string $field The field name which this element is supposed to edit
1281 * @param array $row The record data array where the value(s) for the field can be found
1282 * @param array $PA An array with additional configuration options.
1283 * @return string The HTML code for the TCEform field
1284 * @todo Define visibility
1285 */
1286 public function getSingleField_typeInput($table, $field, $row, &$PA) {
1287 $config = $PA['fieldConf']['config'];
1288 $specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);
1289 $size = MathUtility::forceIntegerInRange($config['size'] ? $config['size'] : 30, 5, $this->maxInputWidth);
1290 $evalList = GeneralUtility::trimExplode(',', $config['eval'], TRUE);
1291 $classAndStyleAttributes = $this->formWidthAsArray($size);
1292 $fieldAppendix = '';
1293 $item = '';
1294 $cssClasses = array($classAndStyleAttributes['class']);
1295 $cssStyle = $classAndStyleAttributes['style'];
1296 if (!isset($config['checkbox'])) {
1297 $config['checkbox'] = '0';
1298 $checkboxIsset = FALSE;
1299 } else {
1300 $checkboxIsset = TRUE;
1301 }
1302 if (in_array('date', $evalList) || in_array('datetime', $evalList)) {
1303 if (in_array('datetime', $evalList)) {
1304 $class = 'datetime';
1305 } else {
1306 $class = 'date';
1307 }
1308 $dateRange = '';
1309 if (isset($config['range']['lower'])) {
1310 $dateRange .= ' lower-' . intval($config['range']['lower']);
1311 }
1312 if (isset($config['range']['upper'])) {
1313 $dateRange .= ' upper-' . intval($config['range']['upper']);
1314 }
1315 $inputId = uniqid('tceforms-' . $class . 'field-');
1316 $cssClasses[] = 'tceforms-textfield tceforms-' . $class . 'field' . $dateRange;
1317 $fieldAppendix = IconUtility::getSpriteIcon('actions-edit-pick-date', array(
1318 'style' => 'cursor:pointer;',
1319 'id' => 'picker-' . $inputId
1320 ));
1321 } elseif (in_array('timesec', $evalList)) {
1322 $inputId = uniqid('tceforms-timesecfield-');
1323 $cssClasses[] = 'tceforms-textfield tceforms-timesecfield';
1324 } elseif (in_array('year', $evalList)) {
1325 $inputId = uniqid('tceforms-yearfield-');
1326 $cssClasses[] = 'tceforms-textfield tceforms-yearfield';
1327 } elseif (in_array('time', $evalList)) {
1328 $inputId = uniqid('tceforms-timefield-');
1329 $cssClasses[] = 'tceforms-textfield tceforms-timefield';
1330 } elseif (in_array('int', $evalList)) {
1331 $inputId = uniqid('tceforms-intfield-');
1332 $cssClasses[] = 'tceforms-textfield tceforms-intfield';
1333 } elseif (in_array('double2', $evalList)) {
1334 $inputId = uniqid('tceforms-double2field-');
1335 $cssClasses[] = 'tceforms-textfield tceforms-double2field';
1336 } else {
1337 $inputId = uniqid('tceforms-textfield-');
1338 $cssClasses[] = 'tceforms-textfield';
1339 if ($checkboxIsset === FALSE) {
1340 $config['checkbox'] = '';
1341 }
1342 }
1343 if (isset($config['wizards']['link'])) {
1344 $inputId = uniqid('tceforms-linkfield-');
1345 $cssClasses[] = 'tceforms-textfield tceforms-linkfield';
1346 } elseif (isset($config['wizards']['color'])) {
1347 $inputId = uniqid('tceforms-colorfield-');
1348 $cssClasses[] = 'tceforms-textfield tceforms-colorfield';
1349 }
1350 if ($this->renderReadonly || $config['readOnly']) {
1351 $itemFormElValue = $PA['itemFormElValue'];
1352 if (in_array('date', $evalList)) {
1353 $config['format'] = 'date';
1354 } elseif (in_array('datetime', $evalList)) {
1355 $config['format'] = 'datetime';
1356 } elseif (in_array('time', $evalList)) {
1357 $config['format'] = 'time';
1358 }
1359 if (in_array('password', $evalList)) {
1360 $itemFormElValue = $itemFormElValue ? '*********' : '';
1361 }
1362 return $this->getSingleField_typeNone_render($config, $itemFormElValue);
1363 }
1364 foreach ($evalList as $func) {
1365 switch ($func) {
1366 case 'required':
1367 $this->registerRequiredProperty('field', $table . '_' . $row['uid'] . '_' . $field, $PA['itemFormElName']);
1368 // Mark this field for date/time disposal:
1369 if (array_intersect($evalList, array('date', 'datetime', 'time'))) {
1370 $this->requiredAdditional[$PA['itemFormElName']]['isPositiveNumber'] = TRUE;
1371 }
1372 break;
1373 default:
1374 // Pair hook to the one in \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_input_Eval()
1375 $evalObj = GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func] . ':&' . $func);
1376 if (is_object($evalObj) && method_exists($evalObj, 'deevaluateFieldValue')) {
1377 $_params = array(
1378 'value' => $PA['itemFormElValue']
1379 );
1380 $PA['itemFormElValue'] = $evalObj->deevaluateFieldValue($_params);
1381 }
1382 }
1383 }
1384 $paramsList = '\'' . $PA['itemFormElName'] . '\',\'' . implode(',', $evalList) . '\',\'' . trim($config['is_in']) . '\',' . (isset($config['checkbox']) ? 1 : 0) . ',\'' . $config['checkbox'] . '\'';
1385 if (in_array('date', $evalList) || in_array('datetime', $evalList)) {
1386 $item .= '<span class="t3-tceforms-input-wrapper-datetime" onmouseOver="if (document.getElementById(\'' . $inputId . '\').value) {this.className=\'t3-tceforms-input-wrapper-datetime-hover\';} else {this.className=\'t3-tceforms-input-wrapper-datetime\';};" onmouseOut="this.className=\'t3-tceforms-input-wrapper-datetime\';">';
1387 // Add server timezone offset to UTC to our stored date
1388 if ($PA['itemFormElValue'] > 0) {
1389 $PA['itemFormElValue'] += date('Z', $PA['itemFormElValue']);
1390 }
1391 } else {
1392 $item .= '<span class="t3-tceforms-input-wrapper" onmouseOver="if (document.getElementById(\'' . $inputId . '\').value) {this.className=\'t3-tceforms-input-wrapper-hover\';} else {this.className=\'t3-tceforms-input-wrapper\';};" onmouseOut="this.className=\'t3-tceforms-input-wrapper\';">';
1393 }
1394 $PA['fieldChangeFunc'] = array_merge(array('typo3form.fieldGet' => 'typo3form.fieldGet(' . $paramsList . ');'), $PA['fieldChangeFunc']);
1395 // Old function "checkbox" now the option to set the date / remove the date
1396 if (isset($config['checkbox'])) {
1397 $item .= IconUtility::getSpriteIcon('actions-input-clear', array('tag' => 'a', 'class' => 't3-tceforms-input-clearer', 'onclick' => 'document.getElementById(\'' . $inputId . '\').value=\'\';document.getElementById(\'' . $inputId . '\').focus();' . implode('', $PA['fieldChangeFunc'])));
1398 }
1399 $mLgd = $config['max'] ? $config['max'] : 256;
1400 $iOnChange = implode('', $PA['fieldChangeFunc']);
1401 $cssClasses[] = 'hasDefaultValue';
1402 $item .= '<input type="text" ' . $this->getPlaceholderAttribute($table, $field, $config, $row) . 'id="' . $inputId . '" ' . 'class="' . implode(' ', $cssClasses) . '" ' . 'name="' . $PA['itemFormElName'] . '_hr" ' . 'value=""' . 'style="' . $cssStyle . '" ' . 'maxlength="' . $mLgd . '" ' . 'onchange="' . htmlspecialchars($iOnChange) . '"' . $PA['onFocus'] . ' />';
1403 // This is the EDITABLE form field.
1404 $item .= '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
1405 // This is the ACTUAL form field - values from the EDITABLE field must be transferred to this field which is the one that is written to the database.
1406 $item .= $fieldAppendix . '</span><div style="clear:both;"></div>';
1407 $this->extJSCODE .= 'typo3form.fieldSet(' . $paramsList . ');';
1408 // Going through all custom evaluations configured for this field
1409 foreach ($evalList as $evalData) {
1410 $evalObj = GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$evalData] . ':&' . $evalData);
1411 if (is_object($evalObj) && method_exists($evalObj, 'returnFieldJS')) {
1412 $this->extJSCODE .= '
1413 TBE_EDITOR.customEvalFunctions[\'' . $evalData . '\'] = function(value) {
1414 ' . $evalObj->returnFieldJS() . '
1415 }
1416 ';
1417 }
1418 }
1419 // Creating an alternative item without the JavaScript handlers.
1420 $altItem = '<input type="hidden" name="' . $PA['itemFormElName'] . '_hr" value="" />';
1421 $altItem .= '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
1422 // Wrap a wizard around the item?
1423 $item = $this->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $PA, $PA['itemFormElName'] . '_hr', $specConf);
1424
1425 return $item;
1426 }
1427
1428 /**
1429 * Renders a view widget to handle and activate NULL values.
1430 * The widget is enabled by using 'null' in the 'eval' TCA definition.
1431 *
1432 * @param string $table Name of the table
1433 * @param string $field Name of the field
1434 * @param array $row Accordant data of the record row
1435 * @param array $PA Parameters array with rendering instructions
1436 * @return string Widget (if any).
1437 */
1438 protected function renderNullValueWidget($table, $field, array $row, array $PA) {
1439 $widget = '';
1440
1441 $config = $PA['fieldConf']['config'];
1442 if (!empty($config['eval']) && GeneralUtility::inList($config['eval'], 'null') && (empty($config['mode']) || $config['mode'] !== 'useOrOverridePlaceholder')) {
1443 $isNull = ($PA['itemFormElValue'] === NULL);
1444
1445 $checked = ($isNull ? '' : ' checked="checked"');
1446 $onChange = htmlspecialchars(
1447 'typo3form.fieldSetNull(\'' . $PA['itemFormElName'] . '\', !this.checked)'
1448 );
1449
1450 $widget = '<span class="t3-tceforms-widget-null-wrapper">' .
1451 '<input type="hidden" name="' . $PA['itemFormElNameActive'] . '" value="0" />' .
1452 '<input type="checkbox" name="' . $PA['itemFormElNameActive'] . '" value="1" onchange="' . $onChange . '"' . $checked . ' />' .
1453 '</span>';
1454 }
1455
1456 return $widget;
1457 }
1458
1459 /**
1460 * Determines whether the current field value is considered as NULL value.
1461 * Using NULL values is enabled by using 'null' in the 'eval' TCA definition.
1462 *
1463 * @param string $table Name of the table
1464 * @param string $field Name of the field
1465 * @param array $row Accordant data
1466 * @param array $PA Parameters array with rendering instructions
1467 * @return boolean
1468 */
1469 protected function isDisabledNullValueField($table, $field, array $row, array $PA) {
1470 $result = FALSE;
1471
1472 $config = $PA['fieldConf']['config'];
1473 if ($PA['itemFormElValue'] === NULL && !empty($config['eval'])
1474 && GeneralUtility::inList($config['eval'], 'null')
1475 && (empty($config['mode']) || $config['mode'] !== 'useOrOverridePlaceholder')) {
1476
1477 $result = TRUE;
1478 }
1479
1480 return $result;
1481 }
1482
1483 /**
1484 * Generation of TCEform elements of the type "text"
1485 * This will render a <textarea> OR RTE area form field, possibly with various control/validation features
1486 *
1487 * @param string $table The table name of the record
1488 * @param string $field The field name which this element is supposed to edit
1489 * @param array $row The record data array where the value(s) for the field can be found
1490 * @param array $PA An array with additional configuration options.
1491 * @return string The HTML code for the TCEform field
1492 * @todo Define visibility
1493 */
1494 public function getSingleField_typeText($table, $field, $row, &$PA) {
1495 // Init config:
1496 $config = $PA['fieldConf']['config'];
1497 $evalList = GeneralUtility::trimExplode(',', $config['eval'], TRUE);
1498 if ($this->renderReadonly || $config['readOnly']) {
1499 return $this->getSingleField_typeNone_render($config, $PA['itemFormElValue']);
1500 }
1501 // Setting columns number:
1502 $cols = MathUtility::forceIntegerInRange($config['cols'] ? $config['cols'] : 30, 5, $this->maxTextareaWidth);
1503 // Setting number of rows:
1504 $origRows = ($rows = MathUtility::forceIntegerInRange($config['rows'] ? $config['rows'] : 5, 1, 20));
1505 if (strlen($PA['itemFormElValue']) > $this->charsPerRow * 2) {
1506 $cols = $this->maxTextareaWidth;
1507 $rows = MathUtility::forceIntegerInRange(round(strlen($PA['itemFormElValue']) / $this->charsPerRow), count(explode(LF, $PA['itemFormElValue'])), 20);
1508 if ($rows < $origRows) {
1509 $rows = $origRows;
1510 }
1511 }
1512 if (in_array('required', $evalList)) {
1513 $this->requiredFields[$table . '_' . $row['uid'] . '_' . $field] = $PA['itemFormElName'];
1514 }
1515 // Init RTE vars:
1516 // Set TRUE, if the RTE is loaded; If not a normal textarea is shown.
1517 $RTEwasLoaded = 0;
1518 // Set TRUE, if the RTE would have been loaded if it wasn't for the disable-RTE flag in the bottom of the page...
1519 $RTEwouldHaveBeenLoaded = 0;
1520 // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist. Traditionally, this is where RTE configuration has been found.
1521 $specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);
1522 // Setting up the altItem form field, which is a hidden field containing the value
1523 $altItem = '<input type="hidden" name="' . htmlspecialchars($PA['itemFormElName']) . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
1524 // If RTE is generally enabled (TYPO3_CONF_VARS and user settings)
1525 if ($this->RTEenabled) {
1526 $p = BackendUtility::getSpecConfParametersFromArray($specConf['rte_transform']['parameters']);
1527 // If the field is configured for RTE and if any flag-field is not set to disable it.
1528 if (isset($specConf['richtext']) && (!$p['flag'] || !$row[$p['flag']])) {
1529 BackendUtility::fixVersioningPid($table, $row);
1530 list($tscPID, $thePidValue) = $this->getTSCpid($table, $row['uid'], $row['pid']);
1531 // If the pid-value is not negative (that is, a pid could NOT be fetched)
1532 if ($thePidValue >= 0) {
1533 $RTEsetup = $GLOBALS['BE_USER']->getTSConfig('RTE', BackendUtility::getPagesTSconfig($tscPID));
1534 $RTEtypeVal = BackendUtility::getTCAtypeValue($table, $row);
1535 $thisConfig = BackendUtility::RTEsetup($RTEsetup['properties'], $table, $field, $RTEtypeVal);
1536 if (!$thisConfig['disabled']) {
1537 if (!$this->disableRTE) {
1538 $this->RTEcounter++;
1539 // Find alternative relative path for RTE images/links:
1540 $eFile = \TYPO3\CMS\Core\Html\RteHtmlParser::evalWriteFile($specConf['static_write'], $row);
1541 $RTErelPath = is_array($eFile) ? dirname($eFile['relEditFile']) : '';
1542 // Get RTE object, draw form and set flag:
1543 $RTEobj = BackendUtility::RTEgetObj();
1544 $item = $RTEobj->drawRTE($this, $table, $field, $row, $PA, $specConf, $thisConfig, $RTEtypeVal, $RTErelPath, $thePidValue);
1545 // Wizard:
1546 $item = $this->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $PA, $PA['itemFormElName'], $specConf, 1);
1547 $RTEwasLoaded = 1;
1548 } else {
1549 $RTEwouldHaveBeenLoaded = 1;
1550 $this->commentMessages[] = $PA['itemFormElName'] . ': RTE is disabled by the on-page RTE-flag (probably you can enable it by the check-box in the bottom of this page!)';
1551 }
1552 } else {
1553 $this->commentMessages[] = $PA['itemFormElName'] . ': RTE is disabled by the Page TSconfig, "RTE"-key (eg. by RTE.default.disabled=0 or such)';
1554 }
1555 } else {
1556 $this->commentMessages[] = $PA['itemFormElName'] . ': PID value could NOT be fetched. Rare error, normally with new records.';
1557 }
1558 } else {
1559 if (!isset($specConf['richtext'])) {
1560 $this->commentMessages[] = $PA['itemFormElName'] . ': RTE was not configured for this field in TCA-types';
1561 }
1562 if (!(!$p['flag'] || !$row[$p['flag']])) {
1563 $this->commentMessages[] = $PA['itemFormElName'] . ': Field-flag (' . $PA['flag'] . ') has been set to disable RTE!';
1564 }
1565 }
1566 }
1567 // Display ordinary field if RTE was not loaded.
1568 if (!$RTEwasLoaded) {
1569 // Show message, if no RTE (field can only be edited with RTE!)
1570 if ($specConf['rte_only']) {
1571 $item = '<p><em>' . htmlspecialchars($this->getLL('l_noRTEfound')) . '</em></p>';
1572 } else {
1573 if ($specConf['nowrap']) {
1574 $wrap = 'off';
1575 } else {
1576 $wrap = $config['wrap'] ? $config['wrap'] : 'virtual';
1577 }
1578 $classes = array();
1579 if ($specConf['fixed-font']) {
1580 $classes[] = 'fixed-font';
1581 }
1582 if ($specConf['enable-tab']) {
1583 $classes[] = 'enable-tab';
1584 }
1585 $formWidthText = $this->formWidthText($cols, $wrap);
1586 // Extract class attributes from $formWidthText (otherwise it would be added twice to the output)
1587 $res = array();
1588 if (preg_match('/ class="(.+?)"/', $formWidthText, $res)) {
1589 $formWidthText = str_replace(' class="' . $res[1] . '"', '', $formWidthText);
1590 $classes = array_merge($classes, explode(' ', $res[1]));
1591 }
1592 if (count($classes)) {
1593 $class = ' class="tceforms-textarea ' . implode(' ', $classes) . '"';
1594 } else {
1595 $class = 'tceforms-textarea';
1596 }
1597 $evalList = GeneralUtility::trimExplode(',', $config['eval'], TRUE);
1598 foreach ($evalList as $func) {
1599 switch ($func) {
1600 case 'required':
1601 $this->registerRequiredProperty('field', $table . '_' . $row['uid'] . '_' . $field, $PA['itemFormElName']);
1602 break;
1603 default:
1604 // Pair hook to the one in \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_input_Eval() and \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_text_Eval()
1605 $evalObj = GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func] . ':&' . $func);
1606 if (is_object($evalObj) && method_exists($evalObj, 'deevaluateFieldValue')) {
1607 $_params = array(
1608 'value' => $PA['itemFormElValue']
1609 );
1610 $PA['itemFormElValue'] = $evalObj->deevaluateFieldValue($_params);
1611 }
1612 }
1613 }
1614 $iOnChange = implode('', $PA['fieldChangeFunc']);
1615 $item .= '
1616 <textarea ' . 'id="' . uniqid('tceforms-textarea-') . '" ' . 'name="' . $PA['itemFormElName'] . '"' . $formWidthText . $class . ' ' . 'rows="' . $rows . '" ' . 'wrap="' . $wrap . '" ' . 'onchange="' . htmlspecialchars($iOnChange) . '"' . $this->getPlaceholderAttribute($table, $field, $config, $row) . $PA['onFocus'] . '>' . GeneralUtility::formatForTextarea($PA['itemFormElValue']) . '</textarea>';
1617 $item = $this->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $PA, $PA['itemFormElName'], $specConf, $RTEwouldHaveBeenLoaded);
1618 }
1619 }
1620 // Return field HTML:
1621 return $item;
1622 }
1623
1624 /**
1625 * Generation of TCEform elements of the type "check"
1626 * This will render a check-box OR an array of checkboxes
1627 *
1628 * @param string $table The table name of the record
1629 * @param string $field The field name which this element is supposed to edit
1630 * @param array $row The record data array where the value(s) for the field can be found
1631 * @param array $PA An array with additional configuration options.
1632 * @return string The HTML code for the TCEform field
1633 * @todo Define visibility
1634 */
1635 public function getSingleField_typeCheck($table, $field, $row, &$PA) {
1636 $config = $PA['fieldConf']['config'];
1637 $item = '';
1638 $disabled = '';
1639 if ($this->renderReadonly || $config['readOnly']) {
1640 $disabled = ' disabled="disabled"';
1641 }
1642 // Traversing the array of items:
1643 $selItems = $this->initItemArray($PA['fieldConf']);
1644 if ($config['itemsProcFunc']) {
1645 $selItems = $this->procItems($selItems, $PA['fieldTSConfig']['itemsProcFunc.'], $config, $table, $row, $field);
1646 }
1647 if (!count($selItems)) {
1648 $selItems[] = array('', '');
1649 }
1650 $thisValue = intval($PA['itemFormElValue']);
1651 $cols = intval($config['cols']);
1652 $selItemsCount = count($selItems);
1653 if ($cols > 1) {
1654 $item .= '<table border="0" cellspacing="0" cellpadding="0" class="typo3-TCEforms-checkboxArray">';
1655 for ($c = 0; $c < $selItemsCount; $c++) {
1656 $p = $selItems[$c];
1657 if (!($c % $cols)) {
1658 $item .= '<tr>';
1659 }
1660 $cBP = $this->checkBoxParams($PA['itemFormElName'], $thisValue, $c, count($selItems), implode('', $PA['fieldChangeFunc']));
1661 $cBName = $PA['itemFormElName'] . '_' . $c;
1662 $cBID = $PA['itemFormElID'] . '_' . $c;
1663 $item .= '<td nowrap="nowrap">' . '<input type="checkbox"' . $this->insertDefStyle('check') . ' value="1" name="' . $cBName . '"' . $cBP . $disabled . ' id="' . $cBID . '" />' . $this->wrapLabels(('<label for="' . $cBID . '">' . htmlspecialchars($p[0]) . '</label>&nbsp;')) . '</td>';
1664 if ($c % $cols + 1 == $cols) {
1665 $item .= '</tr>';
1666 }
1667 }
1668 if ($c % $cols) {
1669 $rest = $cols - $c % $cols;
1670 for ($c = 0; $c < $rest; $c++) {
1671 $item .= '<td></td>';
1672 }
1673 if ($c > 0) {
1674 $item .= '</tr>';
1675 }
1676 }
1677 $item .= '</table>';
1678 } else {
1679 for ($c = 0; $c < $selItemsCount; $c++) {
1680 $p = $selItems[$c];
1681 $cBP = $this->checkBoxParams($PA['itemFormElName'], $thisValue, $c, count($selItems), implode('', $PA['fieldChangeFunc']));
1682 $cBName = $PA['itemFormElName'] . '_' . $c;
1683 $cBID = $PA['itemFormElID'] . '_' . $c;
1684 $item .= ($c > 0 ? '<br />' : '') . '<input type="checkbox"' . $this->insertDefStyle('check') . ' value="1" name="' . $cBName . '"' . $cBP . $PA['onFocus'] . $disabled . ' id="' . $cBID . '" />' . $this->wrapLabels(('<label for="' . $cBID . '">' . htmlspecialchars($p[0]) . '</label>'));
1685 }
1686 }
1687 if (!$disabled) {
1688 $item .= '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($thisValue) . '" />';
1689 }
1690 return $item;
1691 }
1692
1693 /**
1694 * Generation of TCEform elements of the type "radio"
1695 * This will render a series of radio buttons.
1696 *
1697 * @param string $table The table name of the record
1698 * @param string $field The field name which this element is supposed to edit
1699 * @param array $row The record data array where the value(s) for the field can be found
1700 * @param array $PA An array with additional configuration options.
1701 * @return string The HTML code for the TCEform field
1702 * @todo Define visibility
1703 */
1704 public function getSingleField_typeRadio($table, $field, $row, &$PA) {
1705 $config = $PA['fieldConf']['config'];
1706 $item = '';
1707 $disabled = '';
1708 if ($this->renderReadonly || $config['readOnly']) {
1709 $disabled = ' disabled="disabled"';
1710 }
1711 // Get items for the array:
1712 $selItems = $this->initItemArray($PA['fieldConf']);
1713 if ($config['itemsProcFunc']) {
1714 $selItems = $this->procItems($selItems, $PA['fieldTSConfig']['itemsProcFunc.'], $config, $table, $row, $field);
1715 }
1716 // Traverse the items, making the form elements:
1717 $selItemsCount = count($selItems);
1718 for ($c = 0; $c < $selItemsCount; $c++) {
1719 $p = $selItems[$c];
1720 $rID = $PA['itemFormElID'] . '_' . $c;
1721 $rOnClick = implode('', $PA['fieldChangeFunc']);
1722 $rChecked = (string)$p[1] === (string)$PA['itemFormElValue'] ? ' checked="checked"' : '';
1723 $item .= '<input type="radio"' . $this->insertDefStyle('radio') . ' name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($p[1]) . '" onclick="' . htmlspecialchars($rOnClick) . '"' . $rChecked . $PA['onFocus'] . $disabled . ' id="' . $rID . '" />
1724 <label for="' . $rID . '">' . htmlspecialchars($p[0]) . '</label>
1725 <br />';
1726 }
1727 return $item;
1728 }
1729
1730 /**
1731 * Generation of TCEform elements of the type "select"
1732 * This will render a selector box element, or possibly a special construction with two selector boxes. That depends on configuration.
1733 *
1734 * @param string $table The table name of the record
1735 * @param string $field The field name which this element is supposed to edit
1736 * @param array $row The record data array where the value(s) for the field can be found
1737 * @param array $PA An array with additional configuration options.
1738 * @return string The HTML code for the TCEform field
1739 * @todo Define visibility
1740 */
1741 public function getSingleField_typeSelect($table, $field, $row, &$PA) {
1742 // Field configuration from TCA:
1743 $config = $PA['fieldConf']['config'];
1744 $disabled = '';
1745 if ($this->renderReadonly || $config['readOnly']) {
1746 $disabled = ' disabled="disabled"';
1747 }
1748 // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist. See http://typo3.org/documentation/document-library/doc_core_api/Wizards_Configuratio/.
1749 $specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);
1750 $selItems = $this->getSelectItems($table, $field, $row, $PA);
1751
1752 // Creating the label for the "No Matching Value" entry.
1753 $nMV_label = isset($PA['fieldTSConfig']['noMatchingValue_label']) ? $this->sL($PA['fieldTSConfig']['noMatchingValue_label']) : '[ ' . $this->getLL('l_noMatchingValue') . ' ]';
1754 // Prepare some values:
1755 $maxitems = intval($config['maxitems']);
1756 // If a SINGLE selector box...
1757 if ($maxitems <= 1 && $config['renderMode'] !== 'tree') {
1758 $item = $this->getSingleField_typeSelect_single($table, $field, $row, $PA, $config, $selItems, $nMV_label);
1759 } elseif ($config['renderMode'] === 'checkbox') {
1760 // Checkbox renderMode
1761 $item = $this->getSingleField_typeSelect_checkbox($table, $field, $row, $PA, $config, $selItems, $nMV_label);
1762 } elseif ($config['renderMode'] === 'singlebox') {
1763 // Single selector box renderMode
1764 $item = $this->getSingleField_typeSelect_singlebox($table, $field, $row, $PA, $config, $selItems, $nMV_label);
1765 } elseif ($config['renderMode'] === 'tree') {
1766 // Tree renderMode
1767 $treeClass = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\Element\\TreeElement', $this);
1768 $item = $treeClass->renderField($table, $field, $row, $PA, $config, $selItems, $nMV_label);
1769 // Register the required number of elements
1770 $minitems = MathUtility::forceIntegerInRange($config['minitems'], 0);
1771 $this->registerRequiredProperty('range', $PA['itemFormElName'], array($minitems, $maxitems, 'imgName' => $table . '_' . $row['uid'] . '_' . $field));
1772 } else {
1773 // Traditional multiple selector box:
1774 $item = $this->getSingleField_typeSelect_multiple($table, $field, $row, $PA, $config, $selItems, $nMV_label);
1775 }
1776 // Wizards:
1777 if (!$disabled) {
1778 $altItem = '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
1779 $item = $this->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $PA, $PA['itemFormElName'], $specConf);
1780 }
1781 return $item;
1782 }
1783
1784 /**
1785 * Collects the items for a select field by reading the configured
1786 * select items from the configuration and / or by collecting them
1787 * from a foreign table.
1788 *
1789 * @param string $table The table name of the record
1790 * @param string $fieldName The select field name
1791 * @param array $row The record data array where the value(s) for the field can be found
1792 * @param array $PA An array with additional configuration options.
1793 * @return array
1794 */
1795 public function getSelectItems($table, $fieldName, array $row, array $PA) {
1796 $config = $PA['fieldConf']['config'];
1797
1798 // Getting the selector box items from the system
1799 $selectItems = $this->addSelectOptionsToItemArray(
1800 $this->initItemArray($PA['fieldConf']),
1801 $PA['fieldConf'],
1802 $this->setTSconfig($table, $row),
1803 $fieldName
1804 );
1805
1806 // Possibly filter some items:
1807 $selectItems = GeneralUtility::keepItemsInArray(
1808 $selectItems,
1809 $PA['fieldTSConfig']['keepItems'],
1810 function ($value) {
1811 return $value[1];
1812 }
1813 );
1814
1815 // Possibly add some items:
1816 $selectItems = $this->addItems($selectItems, $PA['fieldTSConfig']['addItems.']);
1817
1818 // Process items by a user function:
1819 if (isset($config['itemsProcFunc']) && $config['itemsProcFunc']) {
1820 $selectItems = $this->procItems($selectItems, $PA['fieldTSConfig']['itemsProcFunc.'], $config, $table, $row, $fieldName);
1821 }
1822
1823 // Possibly remove some items:
1824 $removeItems = GeneralUtility::trimExplode(',', $PA['fieldTSConfig']['removeItems'], TRUE);
1825 foreach ($selectItems as $selectItemIndex => $selectItem) {
1826
1827 // Checking languages and authMode:
1828 $languageDeny = FALSE;
1829 if (
1830 !empty($GLOBALS['TCA'][$table]['ctrl']['languageField'])
1831 && $GLOBALS['TCA'][$table]['ctrl']['languageField'] === $fieldName
1832 && !$GLOBALS['BE_USER']->checkLanguageAccess($selectItem[1])
1833 ) {
1834 $languageDeny = TRUE;
1835 }
1836
1837 $authModeDeny = FALSE;
1838 if (
1839 ($config['form_type'] === 'select')
1840 && $config['authMode']
1841 && !$GLOBALS['BE_USER']->checkAuthMode($table, $fieldName, $selectItem[1], $config['authMode'])
1842 ) {
1843 $authModeDeny = TRUE;
1844 }
1845
1846 if (in_array($selectItem[1], $removeItems) || $languageDeny || $authModeDeny) {
1847 unset($selectItems[$selectItemIndex]);
1848 } elseif (isset($PA['fieldTSConfig']['altLabels.'][$selectItem[1]])) {
1849 $selectItems[$selectItemIndex][0] = htmlspecialchars($this->sL($PA['fieldTSConfig']['altLabels.'][$selectItem[1]]));
1850 }
1851
1852 // Removing doktypes with no access:
1853 if (($table === 'pages' || $table === 'pages_language_overlay') && $fieldName === 'doktype') {
1854 if (!($GLOBALS['BE_USER']->isAdmin() || GeneralUtility::inList($GLOBALS['BE_USER']->groupData['pagetypes_select'], $selectItem[1]))) {
1855 unset($selectItems[$selectItemIndex]);
1856 }
1857 }
1858 }
1859
1860 return $selectItems;
1861 }
1862
1863 /**
1864 * Creates a single-selector box
1865 * (Render function for getSingleField_typeSelect())
1866 *
1867 * @param string $table See getSingleField_typeSelect()
1868 * @param string $field See getSingleField_typeSelect()
1869 * @param array $row See getSingleField_typeSelect()
1870 * @param array $PA See getSingleField_typeSelect()
1871 * @param array $config (Redundant) content of $PA['fieldConf']['config'] (for convenience)
1872 * @param array $selItems Items available for selection
1873 * @param string $nMV_label Label for no-matching-value
1874 * @return string The HTML code for the item
1875 * @see getSingleField_typeSelect()
1876 * @todo Define visibility
1877 */
1878 public function getSingleField_typeSelect_single($table, $field, $row, &$PA, $config, $selItems, $nMV_label) {
1879 // check against inline uniqueness
1880 $inlineParent = $this->inline->getStructureLevel(-1);
1881 if (is_array($inlineParent) && $inlineParent['uid']) {
1882 if ($inlineParent['config']['foreign_table'] == $table && $inlineParent['config']['foreign_unique'] == $field) {
1883 $uniqueIds = $this->inline->inlineData['unique'][$this->inline->inlineNames['object'] . InlineElement::Structure_Separator . $table]['used'];
1884 $PA['fieldChangeFunc']['inlineUnique'] = 'inline.updateUnique(this,\'' . $this->inline->inlineNames['object'] . InlineElement::Structure_Separator . $table . '\',\'' . $this->inline->inlineNames['form'] . '\',\'' . $row['uid'] . '\');';
1885 }
1886 // hide uid of parent record for symmetric relations
1887 if ($inlineParent['config']['foreign_table'] == $table && ($inlineParent['config']['foreign_field'] == $field || $inlineParent['config']['symmetric_field'] == $field)) {
1888 $uniqueIds[] = $inlineParent['uid'];
1889 }
1890 }
1891 // Initialization:
1892 $c = 0;
1893 $sI = 0;
1894 $noMatchingValue = 1;
1895 $opt = array();
1896 $selicons = array();
1897 $onlySelectedIconShown = 0;
1898 $size = intval($config['size']);
1899 // Style set on <select/>
1900 $selectedStyle = '';
1901 $item = '';
1902 $disabled = '';
1903 // TODO: icon is used but never assigned
1904 $onChangeIcon = '';
1905 if ($this->renderReadonly || $config['readOnly']) {
1906 $disabled = ' disabled="disabled"';
1907 $onlySelectedIconShown = 1;
1908 }
1909 // Icon configuration:
1910 if ($config['suppress_icons'] == 'IF_VALUE_FALSE') {
1911 $suppressIcons = !$PA['itemFormElValue'] ? 1 : 0;
1912 } elseif ($config['suppress_icons'] == 'ONLY_SELECTED') {
1913 $suppressIcons = 0;
1914 $onlySelectedIconShown = 1;
1915 } elseif ($config['suppress_icons']) {
1916 $suppressIcons = 1;
1917 } else {
1918 $suppressIcons = 0;
1919 }
1920 // Traverse the Array of selector box items:
1921 $optGroupStart = array();
1922 $optGroupOpen = FALSE;
1923 $classesForSelectTag = array();
1924 foreach ($selItems as $p) {
1925 $sM = (string)$PA['itemFormElValue'] === (string)$p[1] ? ' selected="selected"' : '';
1926 if ($sM) {
1927 $sI = $c;
1928 $noMatchingValue = 0;
1929 }
1930 // Getting style attribute value (for icons):
1931 if ($config['iconsInOptionTags']) {
1932 $styleAttrValue = $this->optionTagStyle($p[2]);
1933 if ($sM) {
1934 list($selectIconFile, $selectIconInfo) = $this->getIcon($p[2]);
1935 if (!empty($selectIconInfo)) {
1936 $selectedStyle = ' style="background-image:url(' . $selectIconFile . ');"';
1937 $classesForSelectTag[] = 'typo3-TCEforms-select-selectedItemWithBackgroundImage';
1938 }
1939 }
1940 }
1941 // Compiling the <option> tag:
1942 if (!($p[1] != $PA['itemFormElValue'] && is_array($uniqueIds) && in_array($p[1], $uniqueIds))) {
1943 if ($p[1] === '--div--') {
1944 $optGroupStart[0] = $p[0];
1945 if ($config['iconsInOptionTags']) {
1946 $optGroupStart[1] = $this->optgroupTagStyle($p[2]);
1947 } else {
1948 $optGroupStart[1] = $styleAttrValue;
1949 }
1950 } else {
1951 if (count($optGroupStart)) {
1952 // Closing last optgroup before next one starts
1953 if ($optGroupOpen) {
1954 $opt[] = '</optgroup>' . LF;
1955 }
1956 $opt[] = '<optgroup label="' . GeneralUtility::deHSCentities(htmlspecialchars($optGroupStart[0])) . '"' . ($optGroupStart[1] ? ' style="' . htmlspecialchars($optGroupStart[1]) . '"' : '') . ' class="c-divider">' . LF;
1957 $optGroupOpen = TRUE;
1958 $c--;
1959 $optGroupStart = array();
1960 }
1961 $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' . $sM . ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '') . '>' . GeneralUtility::deHSCentities($p[0]) . '</option>' . LF;
1962 }
1963 }
1964 // If there is an icon for the selector box (rendered in selicon-table below)...:
1965 // if there is an icon ($p[2]), icons should be shown, and, if only selected are visible, is it selected
1966 if ($p[2] && !$suppressIcons && (!$onlySelectedIconShown || $sM)) {
1967 list($selIconFile, $selIconInfo) = $this->getIcon($p[2]);
1968 if (!empty($selIconInfo)) {
1969 $iOnClick = $this->elName($PA['itemFormElName']) . '.selectedIndex=' . $c . '; ' . $this->elName($PA['itemFormElName']) . '.style.backgroundImage=' . $this->elName($PA['itemFormElName']) . '.options[' . $c . '].style.backgroundImage; ' . implode('', $PA['fieldChangeFunc']) . $this->blur() . 'return false;';
1970 } else {
1971 $iOnClick = $this->elName($PA['itemFormElName']) . '.selectedIndex=' . $c . '; ' . $this->elName($PA['itemFormElName']) . '.className=' . $this->elName($PA['itemFormElName']) . '.options[' . $c . '].className; ' . implode('', $PA['fieldChangeFunc']) . $this->blur() . 'return false;';
1972 }
1973 $selicons[] = array(
1974 (!$onlySelectedIconShown ? '<a href="#" onclick="' . htmlspecialchars($iOnClick) . '">' : '') . $this->getIconHtml($p[2], htmlspecialchars($p[0]), htmlspecialchars($p[0])) . (!$onlySelectedIconShown ? '</a>' : ''),
1975 $c,
1976 $sM
1977 );
1978 }
1979 $c++;
1980 }
1981 // Closing optgroup if open
1982 if ($optGroupOpen) {
1983 $opt[] = '</optgroup>';
1984 $optGroupOpen = FALSE;
1985 }
1986 // No-matching-value:
1987 if ($PA['itemFormElValue'] && $noMatchingValue && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
1988 $nMV_label = @sprintf($nMV_label, $PA['itemFormElValue']);
1989 $opt[] = '<option value="' . htmlspecialchars($PA['itemFormElValue']) . '" selected="selected">' . htmlspecialchars($nMV_label) . '</option>';
1990 }
1991 // Create item form fields:
1992 $sOnChange = 'if (this.options[this.selectedIndex].value==\'--div--\') {this.selectedIndex=' . $sI . ';} ' . implode('', $PA['fieldChangeFunc']);
1993 if (!$disabled) {
1994 // MUST be inserted before the selector - else is the value of the hiddenfield here mysteriously submitted...
1995 $item .= '<input type="hidden" name="' . $PA['itemFormElName'] . '_selIconVal" value="' . htmlspecialchars($sI) . '" />';
1996 }
1997 if ($config['iconsInOptionTags']) {
1998 $classesForSelectTag[] = 'icon-select';
1999 }
2000 $item .= '<select' . $selectedStyle . ' id="' . uniqid('tceforms-select-') . '" name="' . $PA['itemFormElName'] . '"' . $this->insertDefStyle('select', implode(' ', $classesForSelectTag)) . ($size ? ' size="' . $size . '"' : '') . ' onchange="' . htmlspecialchars(($onChangeIcon . $sOnChange)) . '"' . $PA['onFocus'] . $disabled . '>';
2001 $item .= implode('', $opt);
2002 $item .= '</select>';
2003 // Create icon table:
2004 if (count($selicons) && !$config['noIconsBelowSelect']) {
2005 $item .= '<table border="0" cellpadding="0" cellspacing="0" class="typo3-TCEforms-selectIcons">';
2006 $selicon_cols = intval($config['selicon_cols']);
2007 if (!$selicon_cols) {
2008 $selicon_cols = count($selicons);
2009 }
2010 $sR = ceil(count($selicons) / $selicon_cols);
2011 $selicons = array_pad($selicons, $sR * $selicon_cols, '');
2012 for ($sa = 0; $sa < $sR; $sa++) {
2013 $item .= '<tr>';
2014 for ($sb = 0; $sb < $selicon_cols; $sb++) {
2015 $sk = $sa * $selicon_cols + $sb;
2016 $imgN = 'selIcon_' . $table . '_' . $row['uid'] . '_' . $field . '_' . $selicons[$sk][1];
2017 $imgS = $selicons[$sk][2] ? $this->backPath . 'gfx/content_selected.gif' : 'clear.gif';
2018 $item .= '<td><img name="' . htmlspecialchars($imgN) . '" src="' . $imgS . '" width="7" height="10" alt="" /></td>';
2019 $item .= '<td>' . $selicons[$sk][0] . '</td>';
2020 }
2021 $item .= '</tr>';
2022 }
2023 $item .= '</table>';
2024 }
2025 return $item;
2026 }
2027
2028 /**
2029 * Creates a checkbox list (renderMode = "checkbox")
2030 * (Render function for getSingleField_typeSelect())
2031 *
2032 * @param string $table See getSingleField_typeSelect()
2033 * @param string $field See getSingleField_typeSelect()
2034 * @param array $row See getSingleField_typeSelect()
2035 * @param array $PA See getSingleField_typeSelect()
2036 * @param array $config (Redundant) content of $PA['fieldConf']['config'] (for convenience)
2037 * @param array $selItems Items available for selection
2038 * @param string $nMV_label Label for no-matching-value
2039 * @return string The HTML code for the item
2040 * @see getSingleField_typeSelect()
2041 * @todo Define visibility
2042 */
2043 public function getSingleField_typeSelect_checkbox($table, $field, $row, &$PA, $config, $selItems, $nMV_label) {
2044 if (empty($selItems)) {
2045 return '';
2046 }
2047 // Get values in an array (and make unique, which is fine because there can be no duplicates anyway):
2048 $itemArray = array_flip($this->extractValuesOnlyFromValueLabelList($PA['itemFormElValue']));
2049 $item = '';
2050 $disabled = '';
2051 if ($this->renderReadonly || $config['readOnly']) {
2052 $disabled = ' disabled="disabled"';
2053 }
2054 // Traverse the Array of selector box items:
2055 $tRows = array();
2056 $c = 0;
2057 if (!$disabled) {
2058 $sOnChange = implode('', $PA['fieldChangeFunc']);
2059 // Used to accumulate the JS needed to restore the original selection.
2060 $setAll = array();
2061 $unSetAll = array();
2062 foreach ($selItems as $p) {
2063 // Non-selectable element:
2064 if ($p[1] === '--div--') {
2065 $selIcon = '';
2066 if (isset($p[2]) && $p[2] != 'empty-emtpy') {
2067 $selIcon = $this->getIconHtml($p[2]);
2068 }
2069 $tRows[] = '
2070 <tr class="c-header">
2071 <td colspan="3">' . $selIcon . htmlspecialchars($p[0]) . '</td>
2072 </tr>';
2073 } else {
2074 // Selected or not by default:
2075 $sM = '';
2076 if (isset($itemArray[$p[1]])) {
2077 $sM = ' checked="checked"';
2078 unset($itemArray[$p[1]]);
2079 }
2080 // Icon:
2081 if ($p[2]) {
2082 $selIcon = $p[2];
2083 } else {
2084 $selIcon = IconUtility::getSpriteIcon('empty-empty');
2085 }
2086 // Compile row:
2087 $rowId = uniqid('select_checkbox_row_');
2088 $onClickCell = $this->elName(($PA['itemFormElName'] . '[' . $c . ']')) . '.checked=!' . $this->elName(($PA['itemFormElName'] . '[' . $c . ']')) . '.checked;';
2089 $onClick = 'this.attributes.getNamedItem("class").nodeValue = ' . $this->elName(($PA['itemFormElName'] . '[' . $c . ']')) . '.checked ? "c-selectedItem" : "c-unselectedItem";';
2090 $setAll[] = $this->elName(($PA['itemFormElName'] . '[' . $c . ']')) . '.checked=1;';
2091 $setAll[] .= '$(\'' . $rowId . '\').removeClassName(\'c-unselectedItem\');$(\'' . $rowId . '\').addClassName(\'c-selectedItem\');';
2092 $unSetAll[] = $this->elName(($PA['itemFormElName'] . '[' . $c . ']')) . '.checked=0;';
2093 $unSetAll[] .= '$(\'' . $rowId . '\').removeClassName(\'c-selectedItem\');$(\'' . $rowId . '\').addClassName(\'c-unselectedItem\');';
2094 $restoreCmd[] = $this->elName(($PA['itemFormElName'] . '[' . $c . ']')) . '.checked=' . ($sM ? 1 : 0) . ';' . '$(\'' . $rowId . '\').removeClassName(\'c-selectedItem\');$(\'' . $rowId . '\').removeClassName(\'c-unselectedItem\');' . '$(\'' . $rowId . '\').addClassName(\'c-' . ($sM ? '' : 'un') . 'selectedItem\');';
2095 // Check if some help text is available
2096 // Since TYPO3 4.5 help text is expected to be an associative array
2097 // with two key, "title" and "description"
2098 // For the sake of backwards compatibility, we test if the help text
2099 // is a string and use it as a description (this could happen if items
2100 // are modified with an itemProcFunc)
2101 $hasHelp = FALSE;
2102 $help = '';
2103 $helpArray = array();
2104 if (is_array($p[3]) && count($p[3]) > 0 || !empty($p[3])) {
2105 $hasHelp = TRUE;
2106 if (is_array($p[3])) {
2107 $helpArray = $p[3];
2108 } else {
2109 $helpArray['description'] = $p[3];
2110 }
2111 }
2112 $label = GeneralUtility::deHSCentities(htmlspecialchars($p[0]));
2113 if ($hasHelp) {
2114 $help = BackendUtility::wrapInHelp('', '', '', $helpArray);
2115 }
2116 $tRows[] = '
2117 <tr id="' . $rowId . '" class="' . ($sM ? 'c-selectedItem' : 'c-unselectedItem') . '" onclick="' . htmlspecialchars($onClick) . '" style="cursor: pointer;">
2118 <td class="c-checkbox"><input type="checkbox"' . $this->insertDefStyle('check') . ' name="' . htmlspecialchars(($PA['itemFormElName'] . '[' . $c . ']')) . '" value="' . htmlspecialchars($p[1]) . '"' . $sM . ' onclick="' . htmlspecialchars($sOnChange) . '"' . $PA['onFocus'] . ' /></td>
2119 <td class="c-labelCell" onclick="' . htmlspecialchars($onClickCell) . '">' . $this->getIconHtml($selIcon) . $label . '</td>
2120 <td class="c-descr" onclick="' . htmlspecialchars($onClickCell) . '">' . (empty($help) ? '' : $help) . '</td>
2121 </tr>';
2122 $c++;
2123 }
2124 }
2125 }
2126 // Remaining values (invalid):
2127 if (count($itemArray) && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
2128 foreach ($itemArray as $theNoMatchValue => $temp) {
2129 // Compile <checkboxes> tag:
2130 array_unshift($tRows, '
2131 <tr class="c-invalidItem">
2132 <td class="c-checkbox"><input type="checkbox"' . $this->insertDefStyle('check') . ' name="' . htmlspecialchars(($PA['itemFormElName'] . '[' . $c . ']')) . '" value="' . htmlspecialchars($theNoMatchValue) . '" checked="checked" onclick="' . htmlspecialchars($sOnChange) . '"' . $PA['onFocus'] . $disabled . ' /></td>
2133 <td class="c-labelCell">' . GeneralUtility::deHSCentities(htmlspecialchars(@sprintf($nMV_label, $theNoMatchValue))) . '</td><td>&nbsp;</td>
2134 </tr>');
2135 $c++;
2136 }
2137 }
2138 // Add an empty hidden field which will send a blank value if all items are unselected.
2139 $item .= '<input type="hidden" class="select-checkbox" name="' . htmlspecialchars($PA['itemFormElName']) . '" value="" />';
2140 // Remaining checkboxes will get their set-all link:
2141 if (count($setAll)) {
2142 $tableHead = '<thead>
2143 <tr class="c-header-checkbox-controls t3-row-header">
2144 <td class="c-checkbox">
2145 <input type="checkbox" class="checkbox" onclick="if (checked) {' . htmlspecialchars((implode('', $setAll) . '} else {' . implode('', $unSetAll) . '}')) . '">
2146 </td>
2147 <td colspan="2">
2148 </td>
2149 </tr></thead>';
2150 }
2151 // Implode rows in table:
2152 $item .= '
2153 <table border="0" cellpadding="0" cellspacing="0" class="typo3-TCEforms-select-checkbox">' . $tableHead . '<tbody>' . implode('', $tRows) . '</tbody>
2154 </table>
2155 ';
2156 // Add revert icon
2157 if (is_array($restoreCmd)) {
2158 $item .= '<a href="#" onclick="' . implode('', $restoreCmd) . ' return false;' . '">' . IconUtility::getSpriteIcon('actions-edit-undo', array('title' => htmlspecialchars($this->getLL('l_revertSelection')))) . '</a>';
2159 }
2160 return $item;
2161 }
2162
2163 /**
2164 * Creates a selectorbox list (renderMode = "singlebox")
2165 * (Render function for getSingleField_typeSelect())
2166 *
2167 * @param string $table See getSingleField_typeSelect()
2168 * @param string $field See getSingleField_typeSelect()
2169 * @param array $row See getSingleField_typeSelect()
2170 * @param array $PA See getSingleField_typeSelect()
2171 * @param array $config (Redundant) content of $PA['fieldConf']['config'] (for convenience)
2172 * @param array $selItems Items available for selection
2173 * @param string $nMV_label Label for no-matching-value
2174 * @return string The HTML code for the item
2175 * @see getSingleField_typeSelect()
2176 * @todo Define visibility
2177 */
2178 public function getSingleField_typeSelect_singlebox($table, $field, $row, &$PA, $config, $selItems, $nMV_label) {
2179 // Get values in an array (and make unique, which is fine because there can be no duplicates anyway):
2180 $itemArray = array_flip($this->extractValuesOnlyFromValueLabelList($PA['itemFormElValue']));
2181 $item = '';
2182 $disabled = '';
2183 if ($this->renderReadonly || $config['readOnly']) {
2184 $disabled = ' disabled="disabled"';
2185 }
2186 // Traverse the Array of selector box items:
2187 $opt = array();
2188 // Used to accumulate the JS needed to restore the original selection.
2189 $restoreCmd = array();
2190 $c = 0;
2191 foreach ($selItems as $p) {
2192 // Selected or not by default:
2193 $sM = '';
2194 if (isset($itemArray[$p[1]])) {
2195 $sM = ' selected="selected"';
2196 $restoreCmd[] = $this->elName(($PA['itemFormElName'] . '[]')) . '.options[' . $c . '].selected=1;';
2197 unset($itemArray[$p[1]]);
2198 }
2199 // Non-selectable element:
2200 $nonSel = '';
2201 if ((string) $p[1] === '--div--') {
2202 $nonSel = ' onclick="this.selected=0;" class="c-divider"';
2203 }
2204 // Icon style for option tag:
2205 if ($config['iconsInOptionTags']) {
2206 $styleAttrValue = $this->optionTagStyle($p[2]);
2207 }
2208 // Compile <option> tag:
2209 $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' . $sM . $nonSel . ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '') . '>' . GeneralUtility::deHSCentities(htmlspecialchars($p[0])) . '</option>';
2210 $c++;
2211 }
2212 // Remaining values:
2213 if (count($itemArray) && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
2214 foreach ($itemArray as $theNoMatchValue => $temp) {
2215 // Compile <option> tag:
2216 array_unshift($opt, '<option value="' . htmlspecialchars($theNoMatchValue) . '" selected="selected">' . GeneralUtility::deHSCentities(htmlspecialchars(@sprintf($nMV_label, $theNoMatchValue))) . '</option>');
2217 }
2218 }
2219 // Compile selector box:
2220 $sOnChange = implode('', $PA['fieldChangeFunc']);
2221 $selector_itemListStyle = isset($config['itemListStyle']) ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"' : ' style="' . $this->defaultMultipleSelectorStyle . '"';
2222 $size = intval($config['size']);
2223 $cssPrefix = $size === 1 ? 'tceforms-select' : 'tceforms-multiselect';
2224 $size = $config['autoSizeMax'] ? MathUtility::forceIntegerInRange(count($selItems) + 1, MathUtility::forceIntegerInRange($size, 1), $config['autoSizeMax']) : $size;
2225 $selectBox = '<select id="' . uniqid($cssPrefix) . '" name="' . $PA['itemFormElName'] . '[]"' . $this->insertDefStyle('select', $cssPrefix) . ($size ? ' size="' . $size . '"' : '') . ' multiple="multiple" onchange="' . htmlspecialchars($sOnChange) . '"' . $PA['onFocus'] . $selector_itemListStyle . $disabled . '>
2226 ' . implode('
2227 ', $opt) . '
2228 </select>';
2229 // Add an empty hidden field which will send a blank value if all items are unselected.
2230 if (!$disabled) {
2231 $item .= '<input type="hidden" name="' . htmlspecialchars($PA['itemFormElName']) . '" value="" />';
2232 }
2233 // Put it all into a table:
2234 $item .= '
2235 <table border="0" cellspacing="0" cellpadding="0" width="1" class="typo3-TCEforms-select-singlebox">
2236 <tr>
2237 <td>
2238 ' . $selectBox . '
2239 <br/>
2240 <em>' . htmlspecialchars($this->getLL('l_holdDownCTRL')) . '</em>
2241 </td>
2242 <td valign="top">
2243 <a href="#" onclick="' . htmlspecialchars(($this->elName(($PA['itemFormElName'] . '[]')) . '.selectedIndex=-1;' . implode('', $restoreCmd) . ' return false;')) . '" title="' . htmlspecialchars($this->getLL('l_revertSelection')) . '">' . IconUtility::getSpriteIcon('actions-edit-undo') . '</a>
2244 </td>
2245 </tr>
2246 </table>
2247 ';
2248 return $item;
2249 }
2250
2251 /**
2252 * Creates a multiple-selector box (two boxes, side-by-side)
2253 * (Render function for getSingleField_typeSelect())
2254 *
2255 * @param string $table See getSingleField_typeSelect()
2256 * @param string $field See getSingleField_typeSelect()
2257 * @param array $row See getSingleField_typeSelect()
2258 * @param array $PA See getSingleField_typeSelect()
2259 * @param array $config (Redundant) content of $PA['fieldConf']['config'] (for convenience)
2260 * @param array $selItems Items available for selection
2261 * @param string $nMV_label Label for no-matching-value
2262 * @return string The HTML code for the item
2263 * @see getSingleField_typeSelect()
2264 * @todo Define visibility
2265 */
2266 public function getSingleField_typeSelect_multiple($table, $field, $row, &$PA, $config, $selItems, $nMV_label) {
2267 $item = '';
2268 $disabled = '';
2269 if ($this->renderReadonly || $config['readOnly']) {
2270 $disabled = ' disabled="disabled"';
2271 }
2272 // Setting this hidden field (as a flag that JavaScript can read out)
2273 if (!$disabled) {
2274 $item .= '<input type="hidden" name="' . $PA['itemFormElName'] . '_mul" value="' . ($config['multiple'] ? 1 : 0) . '" />';
2275 }
2276 // Set max and min items:
2277 $maxitems = MathUtility::forceIntegerInRange($config['maxitems'], 0);
2278 if (!$maxitems) {
2279 $maxitems = 100000;
2280 }
2281 $minitems = MathUtility::forceIntegerInRange($config['minitems'], 0);
2282 // Register the required number of elements:
2283 $this->registerRequiredProperty('range', $PA['itemFormElName'], array($minitems, $maxitems, 'imgName' => $table . '_' . $row['uid'] . '_' . $field));
2284 // Get "removeItems":
2285 $removeItems = GeneralUtility::trimExplode(',', $PA['fieldTSConfig']['removeItems'], TRUE);
2286 // Get the array with selected items:
2287 $itemArray = GeneralUtility::trimExplode(',', $PA['itemFormElValue'], TRUE);
2288
2289 // Possibly filter some items:
2290 $itemArray = GeneralUtility::keepItemsInArray(
2291 $itemArray,
2292 $PA['fieldTSConfig']['keepItems'],
2293 function ($value) {
2294 $parts = explode('|', $value, 2);
2295 return rawurldecode($parts[0]);
2296 }
2297 );
2298
2299 // Perform modification of the selected items array:
2300 foreach ($itemArray as $tk => $tv) {
2301 $tvP = explode('|', $tv, 2);
2302 $evalValue = $tvP[0];
2303 $isRemoved = in_array($evalValue, $removeItems) || $config['form_type'] == 'select' && $config['authMode'] && !$GLOBALS['BE_USER']->checkAuthMode($table, $field, $evalValue, $config['authMode']);
2304 if ($isRemoved && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
2305 $tvP[1] = rawurlencode(@sprintf($nMV_label, $evalValue));
2306 } elseif (isset($PA['fieldTSConfig']['altLabels.'][$evalValue])) {
2307 $tvP[1] = rawurlencode($this->sL($PA['fieldTSConfig']['altLabels.'][$evalValue]));
2308 }
2309 if ($tvP[1] == '') {
2310 // Case: flexform, default values supplied, no label provided (bug #9795)
2311 foreach ($selItems as $selItem) {
2312 if ($selItem[1] == $tvP[0]) {
2313 $tvP[1] = html_entity_decode($selItem[0]);
2314 break;
2315 }
2316 }
2317 }
2318 $itemArray[$tk] = implode('|', $tvP);
2319 }
2320 $itemsToSelect = '';
2321 $filterTextfield = '';
2322 $filterSelectbox = '';
2323 if (!$disabled) {
2324 // Create option tags:
2325 $opt = array();
2326 $styleAttrValue = '';
2327 foreach ($selItems as $p) {
2328 if ($config['iconsInOptionTags']) {
2329 $styleAttrValue = $this->optionTagStyle($p[2]);
2330 }
2331 $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' . ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '') . ' title="' . $p[0] . '">' . $p[0] . '</option>';
2332 }
2333 // Put together the selector box:
2334 $selector_itemListStyle = isset($config['itemListStyle']) ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"' : ' style="' . $this->defaultMultipleSelectorStyle . '"';
2335 $size = intval($config['size']);
2336 $size = $config['autoSizeMax'] ? MathUtility::forceIntegerInRange(count($itemArray) + 1, MathUtility::forceIntegerInRange($size, 1), $config['autoSizeMax']) : $size;
2337 if ($config['exclusiveKeys']) {
2338 $sOnChange = 'setFormValueFromBrowseWin(\'' . $PA['itemFormElName'] . '\',this.options[this.selectedIndex].value, this.options[this.selectedIndex].text, this.options[this.selectedIndex].title,\'' . $config['exclusiveKeys'] . '\'); ';
2339 } else {
2340 $sOnChange = 'setFormValueFromBrowseWin(\'' . $PA['itemFormElName'] . '\',this.options[this.selectedIndex].value, this.options[this.selectedIndex].text, this.options[this.selectedIndex].title); ';
2341 }
2342 $sOnChange .= implode('', $PA['fieldChangeFunc']);
2343 $multiSelectId = uniqid('tceforms-multiselect-');
2344 $itemsToSelect = '
2345 <select id="' . $multiSelectId . '" name="' . $PA['itemFormElName'] . '_sel"' . $this->insertDefStyle('select', 'tceforms-multiselect tceforms-itemstoselect') . ($size ? ' size="' . $size . '"' : '') . ' onchange="' . htmlspecialchars($sOnChange) . '"' . $PA['onFocus'] . $selector_itemListStyle . '>
2346 ' . implode('
2347 ', $opt) . '
2348 </select>';
2349
2350 if ($config['enableMultiSelectFilterTextfield'] || $config['multiSelectFilterItems']) {
2351 $this->multiSelectFilterCount++;
2352 $jsSelectBoxFilterName = str_replace(' ', '', ucwords(str_replace('-', ' ', GeneralUtility::strtolower($multiSelectId))));
2353 $this->additionalJS_post[] = '
2354 var '. $jsSelectBoxFilterName . ' = new TCEForms.SelectBoxFilter("' . $multiSelectId . '");
2355 ';
2356 }
2357
2358 if ($config['enableMultiSelectFilterTextfield']) {
2359 // add input field for filter
2360 $filterTextfield = '<input class="typo3-TCEforms-suggest-search typo3-TCEforms-multiselect-filter" id="' . $multiSelectId . '_filtertextfield" value="" style="width: 104px;" />';
2361 }
2362
2363 if (isset($config['multiSelectFilterItems']) && is_array($config['multiSelectFilterItems']) && count($config['multiSelectFilterItems']) > 1) {
2364 $filterDropDownOptions = array();
2365 foreach ($config['multiSelectFilterItems'] as $optionElement) {
2366 $filterDropDownOptions[] = '<option value="' . htmlspecialchars($this->sL($optionElement[0])) . '">' . htmlspecialchars((isset($optionElement[1]) && $optionElement[1] != '') ? $this->sL($optionElement[1]) : $this->sL($optionElement[0])) . '</option>';
2367 }
2368 $filterSelectbox = '
2369 <select id="' . $multiSelectId . '_filterdropdown">
2370 ' . implode('
2371 ', $filterDropDownOptions) . '
2372 </select>';
2373 }
2374 }
2375 // Pass to "dbFileIcons" function:
2376 $params = array(
2377 'size' => $size,
2378 'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
2379 'style' => isset($config['selectedListStyle']) ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"' : ' style="' . $this->defaultMultipleSelectorStyle . '"',
2380 'dontShowMoveIcons' => $maxitems <= 1,
2381 'maxitems' => $maxitems,
2382 'info' => '',
2383 'headers' => array(
2384 'selector' => $this->getLL('l_selected') . ':<br />',
2385 'items' => $this->getLL('l_items') . ': ' . $filterSelectbox . $filterTextfield . '<br />'
2386 ),
2387 'noBrowser' => 1,
2388 'thumbnails' => $itemsToSelect,
2389 'readOnly' => $disabled
2390 );
2391 $item .= $this->dbFileIcons($PA['itemFormElName'], '', '', $itemArray, '', $params, $PA['onFocus']);
2392 return $item;
2393 }
2394
2395 /**
2396 * Generation of TCEform elements of the type "group"
2397 * This will render a selectorbox into which elements from either the file system or database can be inserted. Relations.
2398 *
2399 * @param string $table The table name of the record
2400 * @param string $field The field name which this element is supposed to edit
2401 * @param array $row The record data array where the value(s) for the field can be found
2402 * @param array $PA An array with additional configuration options.
2403 * @return string The HTML code for the TCEform field
2404 * @todo Define visibility
2405 */
2406 public function getSingleField_typeGroup($table, $field, $row, &$PA) {
2407 // Init:
2408 $config = $PA['fieldConf']['config'];
2409 $internal_type = $config['internal_type'];
2410 $show_thumbs = $config['show_thumbs'];
2411 $size = intval($config['size']);
2412 $maxitems = MathUtility::forceIntegerInRange($config['maxitems'], 0);
2413 if (!$maxitems) {
2414 $maxitems = 100000;
2415 }
2416 $minitems = MathUtility::forceIntegerInRange($config['minitems'], 0);
2417 $allowed = trim($config['allowed']);
2418 $disallowed = trim($config['disallowed']);
2419 $item = '';
2420 $disabled = '';
2421 if ($this->renderReadonly || $config['readOnly']) {
2422 $disabled = ' disabled="disabled"';
2423 }
2424 $item .= '<input type="hidden" name="' . $PA['itemFormElName'] . '_mul" value="' . ($config['multiple'] ? 1 : 0) . '"' . $disabled . ' />';
2425 $this->registerRequiredProperty('range', $PA['itemFormElName'], array($minitems, $maxitems, 'imgName' => $table . '_' . $row['uid'] . '_' . $field));
2426 $info = '';
2427 // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist. See http://typo3.org/documentation/document-library/doc_core_api/Wizards_Configuratio/.
2428 $specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);
2429 $PA['itemFormElID_file'] = $PA['itemFormElID'] . '_files';
2430 // whether the list and delete controls should be disabled
2431 $noList = isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'list');
2432 $noDelete = isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'delete');
2433 // if maxitems==1 then automatically replace the current item (in list and file selector)
2434 if ($maxitems === 1) {
2435 $this->additionalJS_post[] = 'TBE_EDITOR.clearBeforeSettingFormValueFromBrowseWin[\'' . $PA['itemFormElName'] . '\'] = {
2436 itemFormElID_file: \'' . $PA['itemFormElID_file'] . '\'
2437 }';
2438 $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'setFormValueManipulate(\'' . $PA['itemFormElName'] . '\', \'Remove\'); ' . $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'];
2439 } elseif ($noList) {
2440 // If the list controls have been removed and the maximum number is reached, remove the first entry to avoid "write once" field
2441 $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'setFormValueManipulate(\'' . $PA['itemFormElName'] . '\', \'RemoveFirstIfFull\', \'' . $maxitems . '\'); ' . $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'];
2442 }
2443 // Acting according to either "file" or "db" type:
2444 switch ((string) $config['internal_type']) {
2445 case 'file_reference':
2446 $config['uploadfolder'] = '';
2447 // Fall through
2448 case 'file':
2449 // Creating string showing allowed types:
2450 $tempFT = GeneralUtility::trimExplode(',', $allowed, TRUE);
2451 if (!count($tempFT)) {
2452 $info .= '*';
2453 }
2454 foreach ($tempFT as $ext) {
2455 if ($ext) {
2456 $info .= strtoupper($ext) . ' ';
2457 }
2458 }
2459 // Creating string, showing disallowed types:
2460 $tempFT_dis = GeneralUtility::trimExplode(',', $disallowed, TRUE);
2461 if (count($tempFT_dis)) {
2462 $info .= '<br />';
2463 }
2464 foreach ($tempFT_dis as $ext) {
2465 if ($ext) {
2466 $info .= '-' . strtoupper($ext) . ' ';
2467 }
2468 }
2469 // Making the array of file items:
2470 $itemArray = GeneralUtility::trimExplode(',', $PA['itemFormElValue'], TRUE);
2471 $fileFactory = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance();
2472 // Correct the filename for the FAL items
2473 foreach ($itemArray as &$fileItem) {
2474 list($fileUid, $fileLabel) = explode('|', $fileItem);
2475 if (MathUtility::canBeInterpretedAsInteger($fileUid)) {
2476 $fileObject = $fileFactory->getFileObject($fileUid);
2477 $fileLabel = $fileObject->getName();
2478 }
2479 $fileItem = $fileUid . '|' . $fileLabel;
2480 }
2481 // Showing thumbnails:
2482 $thumbsnail = '';
2483 if ($show_thumbs) {
2484 $imgs = array();
2485 foreach ($itemArray as $imgRead) {
2486 $imgP = explode('|', $imgRead);
2487 $imgPath = rawurldecode($imgP[0]);
2488 // FAL icon production
2489 if (MathUtility::canBeInterpretedAsInteger($imgP[0])) {
2490 $fileObject = $fileFactory->getFileObject($imgP[0]);
2491
2492 if ($fileObject->isMissing()) {
2493 $flashMessage = \TYPO3\CMS\Core\Resource\Utility\BackendUtility::getFlashMessageForMissingFile($fileObject);
2494 $imgs[] = $flashMessage->render();
2495 } elseif (GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileObject->getExtension())) {
2496 $imageUrl = $fileObject->process(\TYPO3\CMS\Core\Resource\ProcessedFile::CONTEXT_IMAGEPREVIEW, array())->getPublicUrl(TRUE);
2497 $imgTag = '<img src="' . $imageUrl . '" alt="' . htmlspecialchars($fileObject->getName()) . '" />';
2498 $imgs[] = '<span class="nobr">' . $imgTag . htmlspecialchars($fileObject->getName()) . '</span>';
2499 } else {
2500 // Icon
2501 $imgTag = IconUtility::getSpriteIconForFile(strtolower($fileObject->getExtension()), array('title' => $fileObject->getName()));
2502 $imgs[] = '<span class="nobr">' . $imgTag . htmlspecialchars($fileObject->getName()) . '</span>';
2503 }
2504 } else {
2505 $rowCopy = array();
2506 $rowCopy[$field] = $imgPath;
2507 $thumbnailCode = '';
2508 try {
2509 $thumbnailCode = BackendUtility::thumbCode(
2510 $rowCopy, $table, $field, $this->backPath, 'thumbs.php',
2511 $config['uploadfolder'], 0, ' align="middle"'
2512 );
2513 $thumbnailCode = '<span class="nobr">' . $thumbnailCode . $imgPath . '</span>';
2514
2515 } catch (\Exception $exception) {
2516 /** @var $flashMessage FlashMessage */
2517 $message = $exception->getMessage();
2518 $flashMessage = GeneralUtility::makeInstance(
2519 'TYPO3\\CMS\\Core\\Messaging\\FlashMessage',
2520 htmlspecialchars($message), '', FlashMessage::ERROR, TRUE
2521 );
2522 $class = 'TYPO3\\CMS\\Core\\Messaging\\FlashMessageService';
2523 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
2524 $flashMessageService = GeneralUtility::makeInstance($class);
2525 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
2526 $defaultFlashMessageQueue->enqueue($flashMessage);
2527
2528 $logMessage = $message . ' (' . $table . ':' . $row['uid'] . ')';
2529 GeneralUtility::sysLog($logMessage, 'core', GeneralUtility::SYSLOG_SEVERITY_WARNING);
2530 }
2531
2532 $imgs[] = $thumbnailCode;
2533 }