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