[TASK] Improve UI of readOnly in TCEforms
[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 neceessary, 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 if (t3lib_div::hasValidClassPrefix($func)) {
1077 // Pair hook to the one in t3lib_TCEmain::checkValue_input_Eval()
1078 $evalObj = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func] . ':&' . $func);
1079 if (is_object($evalObj) && method_exists($evalObj, 'deevaluateFieldValue')) {
1080 $_params = array(
1081 'value' => $PA['itemFormElValue']
1082 );
1083 $PA['itemFormElValue'] = $evalObj->deevaluateFieldValue($_params);
1084 }
1085 }
1086 break;
1087 }
1088 }
1089
1090 $paramsList = "'" . $PA['itemFormElName'] . "','" . implode(',', $evalList) . "','" . trim($config['is_in']) . "'," . (isset($config['checkbox']) ? 1 : 0) . ",'" . $config['checkbox'] . "'";
1091 if ((in_array('date', $evalList) || in_array('datetime', $evalList))) {
1092 $item .= '<span class="t3-tceforms-input-wrapper-datetime" onmouseOver="if (document.getElementById(\'' .
1093 $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\';">';
1094
1095 // Add server timezone offset to UTC to our stored date
1096 if ($PA['itemFormElValue'] > 0) {
1097 $PA['itemFormElValue'] += date('Z', $PA['itemFormElValue']);
1098 }
1099 } else {
1100 $item .= '<span class="t3-tceforms-input-wrapper" onmouseOver="if (document.getElementById(\'' . $inputId .
1101 '\').value) {this.className=\'t3-tceforms-input-wrapper-hover\';} else {this.className=\'t3-tceforms-input-wrapper\';};" onmouseOut="this.className=\'t3-tceforms-input-wrapper\';">';
1102 }
1103
1104 $PA['fieldChangeFunc'] = array_merge(
1105 array('typo3form.fieldGet' => 'typo3form.fieldGet(' . $paramsList . ');'),
1106 $PA['fieldChangeFunc']
1107 );
1108 // Old function "checkbox" now the option to set the date / remove the date
1109 if (isset($config['checkbox'])) {
1110 $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'])));
1111 }
1112 $mLgd = ($config['max'] ? $config['max'] : 256);
1113 $iOnChange = implode('', $PA['fieldChangeFunc']);
1114
1115 $cssClasses[] = 'hasDefaultValue';
1116 $item .= '<input type="text" ' .
1117 $this->getPlaceholderAttribute($table, $field, $config, $row) .
1118 'id="' . $inputId . '" ' .
1119 'class="' . implode(' ', $cssClasses) . '" ' .
1120 'name="' . $PA['itemFormElName'] . '_hr" ' .
1121 'value=""' .
1122 'style="' . $cssStyle . '" ' .
1123 'maxlength="' . $mLgd . '" ' .
1124 'onchange="' . htmlspecialchars($iOnChange) . '"' .
1125 $PA['onFocus'] .
1126 ' />'; // This is the EDITABLE form field.
1127 $item .= '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' .
1128 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.
1129 $item .= $fieldAppendix . '</span><div style="clear:both;"></div>';
1130 $this->extJSCODE .= 'typo3form.fieldSet(' . $paramsList . ');';
1131
1132 // Going through all custom evaluations configured for this field
1133 foreach ($evalList as $evalData) {
1134 if (t3lib_div::hasValidClassPrefix($evalData)) {
1135 $evalObj = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$evalData] . ':&' . $evalData);
1136 if (is_object($evalObj) && method_exists($evalObj, 'returnFieldJS')) {
1137 $this->extJSCODE .= "\n\nfunction " . $evalData . "(value) {\n" . $evalObj->returnFieldJS() . "\n}\n";
1138 }
1139 }
1140 }
1141
1142 // Creating an alternative item without the JavaScript handlers.
1143 $altItem = '<input type="hidden" name="' . $PA['itemFormElName'] . '_hr" value="" />';
1144 $altItem .= '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
1145
1146 // Wrap a wizard around the item?
1147 $item = $this->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $PA, $PA['itemFormElName'] . '_hr', $specConf);
1148
1149 return $item;
1150 }
1151
1152 /**
1153 * Generation of TCEform elements of the type "text"
1154 * This will render a <textarea> OR RTE area form field, possibly with various control/validation features
1155 *
1156 * @param string $table The table name of the record
1157 * @param string $field The field name which this element is supposed to edit
1158 * @param array $row The record data array where the value(s) for the field can be found
1159 * @param array $PA An array with additional configuration options.
1160 * @return string The HTML code for the TCEform field
1161 */
1162 function getSingleField_typeText($table, $field, $row, &$PA) {
1163
1164 // Init config:
1165 $config = $PA['fieldConf']['config'];
1166 $evalList = t3lib_div::trimExplode(',', $config['eval'], 1);
1167
1168 if ($this->renderReadonly || $config['readOnly']) {
1169 return $this->getSingleField_typeNone_render($config, $PA['itemFormElValue']);
1170 }
1171
1172 // Setting columns number:
1173 $cols = t3lib_utility_Math::forceIntegerInRange($config['cols'] ? $config['cols'] : 30, 5, $this->maxTextareaWidth);
1174
1175 // Setting number of rows:
1176 $origRows = $rows = t3lib_utility_Math::forceIntegerInRange($config['rows'] ? $config['rows'] : 5, 1, 20);
1177 if (strlen($PA['itemFormElValue']) > $this->charsPerRow * 2) {
1178 $cols = $this->maxTextareaWidth;
1179 $rows = t3lib_utility_Math::forceIntegerInRange(round(strlen($PA['itemFormElValue']) / $this->charsPerRow), count(explode(LF, $PA['itemFormElValue'])), 20);
1180 if ($rows < $origRows) {
1181 $rows = $origRows;
1182 }
1183 }
1184
1185 if (in_array('required', $evalList)) {
1186 $this->requiredFields[$table . '_' . $row['uid'] . '_' . $field] = $PA['itemFormElName'];
1187 }
1188
1189 // Init RTE vars:
1190 // Set TRUE, if the RTE is loaded; If not a normal textarea is shown.
1191 $RTEwasLoaded = 0;
1192 // Set TRUE, if the RTE would have been loaded if it wasn't for the disable-RTE flag in the bottom of the page...
1193 $RTEwouldHaveBeenLoaded = 0;
1194
1195 // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist. Traditionally, this is where RTE configuration has been found.
1196 $specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);
1197
1198 // Setting up the altItem form field, which is a hidden field containing the value
1199 $altItem = '<input type="hidden" name="' . htmlspecialchars($PA['itemFormElName']) . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
1200
1201 // If RTE is generally enabled (TYPO3_CONF_VARS and user settings)
1202 if ($this->RTEenabled) {
1203 $p = t3lib_BEfunc::getSpecConfParametersFromArray($specConf['rte_transform']['parameters']);
1204 // If the field is configured for RTE and if any flag-field is not set to disable it.
1205 if (isset($specConf['richtext']) && (!$p['flag'] || !$row[$p['flag']])) {
1206 t3lib_BEfunc::fixVersioningPid($table, $row);
1207 list($tscPID, $thePidValue) = $this->getTSCpid($table, $row['uid'], $row['pid']);
1208
1209 // If the pid-value is not negative (that is, a pid could NOT be fetched)
1210 if ($thePidValue >= 0) {
1211 $RTEsetup = $GLOBALS['BE_USER']->getTSConfig('RTE', t3lib_BEfunc::getPagesTSconfig($tscPID));
1212 $RTEtypeVal = t3lib_BEfunc::getTCAtypeValue($table, $row);
1213 $thisConfig = t3lib_BEfunc::RTEsetup($RTEsetup['properties'], $table, $field, $RTEtypeVal);
1214
1215 if (!$thisConfig['disabled']) {
1216 if (!$this->disableRTE) {
1217 $this->RTEcounter++;
1218
1219 // Find alternative relative path for RTE images/links:
1220 $eFile = t3lib_parsehtml_proc::evalWriteFile($specConf['static_write'], $row);
1221 $RTErelPath = is_array($eFile) ? dirname($eFile['relEditFile']) : '';
1222
1223 // Get RTE object, draw form and set flag:
1224 $RTEobj = t3lib_BEfunc::RTEgetObj();
1225 $item = $RTEobj->drawRTE($this, $table, $field, $row, $PA, $specConf, $thisConfig, $RTEtypeVal, $RTErelPath, $thePidValue);
1226
1227 // Wizard:
1228 $item = $this->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $PA, $PA['itemFormElName'], $specConf, 1);
1229
1230 $RTEwasLoaded = 1;
1231 } else {
1232 $RTEwouldHaveBeenLoaded = 1;
1233 $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!)';
1234 }
1235 } else {
1236 $this->commentMessages[] = $PA['itemFormElName'] . ': RTE is disabled by the Page TSconfig, "RTE"-key (eg. by RTE.default.disabled=0 or such)';
1237 }
1238 } else {
1239 $this->commentMessages[] = $PA['itemFormElName'] . ': PID value could NOT be fetched. Rare error, normally with new records.';
1240 }
1241 } else {
1242 if (!isset($specConf['richtext'])) {
1243 $this->commentMessages[] = $PA['itemFormElName'] . ': RTE was not configured for this field in TCA-types';
1244 }
1245 if (!(!$p['flag'] || !$row[$p['flag']])) {
1246 $this->commentMessages[] = $PA['itemFormElName'] . ': Field-flag (' . $PA['flag'] . ') has been set to disable RTE!';
1247 }
1248 }
1249 }
1250
1251 // Display ordinary field if RTE was not loaded.
1252 if (!$RTEwasLoaded) {
1253 // Show message, if no RTE (field can only be edited with RTE!)
1254 if ($specConf['rte_only']) {
1255 $item = '<p><em>' . htmlspecialchars($this->getLL('l_noRTEfound')) . '</em></p>';
1256 } else {
1257 if ($specConf['nowrap']) {
1258 $wrap = 'off';
1259 } else {
1260 $wrap = ($config['wrap'] ? $config['wrap'] : 'virtual');
1261 }
1262
1263 $classes = array();
1264 if ($specConf['fixed-font']) {
1265 $classes[] = 'fixed-font';
1266 }
1267 if ($specConf['enable-tab']) {
1268 $classes[] = 'enable-tab';
1269 }
1270
1271 $formWidthText = $this->formWidthText($cols, $wrap);
1272
1273 // Extract class attributes from $formWidthText (otherwise it would be added twice to the output)
1274 $res = array();
1275 if (preg_match('/ class="(.+?)"/', $formWidthText, $res)) {
1276 $formWidthText = str_replace(' class="' . $res[1] . '"', '', $formWidthText);
1277 $classes = array_merge($classes, explode(' ', $res[1]));
1278 }
1279
1280 if (count($classes)) {
1281 $class = ' class="tceforms-textarea ' . implode(' ', $classes) . '"';
1282 } else {
1283 $class = 'tceforms-textarea';
1284 }
1285
1286 $evalList = t3lib_div::trimExplode(',', $config['eval'], 1);
1287 foreach ($evalList as $func) {
1288 switch ($func) {
1289 case 'required':
1290 $this->registerRequiredProperty('field', $table . '_' . $row['uid'] . '_' . $field, $PA['itemFormElName']);
1291 break;
1292 default:
1293 if (t3lib_div::hasValidClassPrefix($func)) {
1294 // Pair hook to the one in t3lib_TCEmain::checkValue_input_Eval() and t3lib_TCEmain::checkValue_text_Eval()
1295 $evalObj = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func] . ':&' . $func);
1296 if (is_object($evalObj) && method_exists($evalObj, 'deevaluateFieldValue')) {
1297 $_params = array(
1298 'value' => $PA['itemFormElValue']
1299 );
1300 $PA['itemFormElValue'] = $evalObj->deevaluateFieldValue($_params);
1301 }
1302 }
1303 break;
1304 }
1305 }
1306
1307 $iOnChange = implode('', $PA['fieldChangeFunc']);
1308 $item .= '
1309 <textarea ' .
1310 'id="' . uniqid('tceforms-textarea-') . '" ' .
1311 'name="' . $PA['itemFormElName'] . '"' .
1312 $formWidthText .
1313 $class . ' ' .
1314 'rows="' . $rows . '" ' .
1315 'wrap="' . $wrap . '" ' .
1316 'onchange="' . htmlspecialchars($iOnChange) . '"' .
1317 $this->getPlaceholderAttribute($table, $field, $config, $row) .
1318 $PA['onFocus'] . '>' .
1319 t3lib_div::formatForTextarea($PA['itemFormElValue']) .
1320 '</textarea>';
1321 $item = $this->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $PA, $PA['itemFormElName'], $specConf, $RTEwouldHaveBeenLoaded);
1322 }
1323 }
1324
1325 // Return field HTML:
1326 return $item;
1327 }
1328
1329 /**
1330 * Generation of TCEform elements of the type "check"
1331 * This will render a check-box OR an array of checkboxes
1332 *
1333 * @param string $table The table name of the record
1334 * @param string $field The field name which this element is supposed to edit
1335 * @param array $row The record data array where the value(s) for the field can be found
1336 * @param array $PA An array with additional configuration options.
1337 * @return string The HTML code for the TCEform field
1338 */
1339 function getSingleField_typeCheck($table, $field, $row, &$PA) {
1340 $config = $PA['fieldConf']['config'];
1341
1342 $item = '';
1343 $disabled = '';
1344 if ($this->renderReadonly || $config['readOnly']) {
1345 $disabled = ' disabled="disabled"';
1346 }
1347
1348 // Traversing the array of items:
1349 $selItems = $this->initItemArray($PA['fieldConf']);
1350 if ($config['itemsProcFunc']) {
1351 $selItems = $this->procItems($selItems, $PA['fieldTSConfig']['itemsProcFunc.'], $config, $table, $row, $field);
1352 }
1353
1354 if (!count($selItems)) {
1355 $selItems[] = array('', '');
1356 }
1357 $thisValue = intval($PA['itemFormElValue']);
1358
1359 $cols = intval($config['cols']);
1360 if ($cols > 1) {
1361 $item .= '<table border="0" cellspacing="0" cellpadding="0" class="typo3-TCEforms-checkboxArray">';
1362 for ($c = 0; $c < count($selItems); $c++) {
1363 $p = $selItems[$c];
1364 if (!($c % $cols)) {
1365 $item .= '<tr>';
1366 }
1367 $cBP = $this->checkBoxParams($PA['itemFormElName'], $thisValue, $c, count($selItems), implode('', $PA['fieldChangeFunc']));
1368 $cBName = $PA['itemFormElName'] . '_' . $c;
1369 $cBID = $PA['itemFormElID'] . '_' . $c;
1370 $item .= '<td nowrap="nowrap">' .
1371 '<input type="checkbox"' . $this->insertDefStyle('check') . ' value="1" name="' . $cBName . '"' . $cBP . $disabled . ' id="' . $cBID . '" />' .
1372 $this->wrapLabels('<label for="' . $cBID . '">' . htmlspecialchars($p[0]) . '</label>&nbsp;') .
1373 '</td>';
1374 if (($c % $cols) + 1 == $cols) {
1375 $item .= '</tr>';
1376 }
1377 }
1378 if ($c % $cols) {
1379 $rest = $cols - ($c % $cols);
1380 for ($c = 0; $c < $rest; $c++) {
1381 $item .= '<td></td>';
1382 }
1383 if ($c > 0) {
1384 $item .= '</tr>';
1385 }
1386 }
1387 $item .= '</table>';
1388 } else {
1389 for ($c = 0; $c < count($selItems); $c++) {
1390 $p = $selItems[$c];
1391 $cBP = $this->checkBoxParams($PA['itemFormElName'], $thisValue, $c, count($selItems), implode('', $PA['fieldChangeFunc']));
1392 $cBName = $PA['itemFormElName'] . '_' . $c;
1393 $cBID = $PA['itemFormElID'] . '_' . $c;
1394 $item .= ($c > 0 ? '<br />' : '') .
1395 '<input type="checkbox"' . $this->insertDefStyle('check') . ' value="1" name="' . $cBName . '"' . $cBP . $PA['onFocus'] . $disabled . ' id="' . $cBID . '" />' .
1396 $this->wrapLabels('<label for="' . $cBID . '">' . htmlspecialchars($p[0]) . '</label>');
1397 }
1398 }
1399 if (!$disabled) {
1400 $item .= '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($thisValue) . '" />';
1401 }
1402
1403 return $item;
1404 }
1405
1406 /**
1407 * Generation of TCEform elements of the type "radio"
1408 * This will render a series of radio buttons.
1409 *
1410 * @param string $table The table name of the record
1411 * @param string $field The field name which this element is supposed to edit
1412 * @param array $row The record data array where the value(s) for the field can be found
1413 * @param array $PA An array with additional configuration options.
1414 * @return string The HTML code for the TCEform field
1415 */
1416 function getSingleField_typeRadio($table, $field, $row, &$PA) {
1417 $config = $PA['fieldConf']['config'];
1418
1419 $item = '';
1420 $disabled = '';
1421 if ($this->renderReadonly || $config['readOnly']) {
1422 $disabled = ' disabled="disabled"';
1423 }
1424
1425 // Get items for the array:
1426 $selItems = $this->initItemArray($PA['fieldConf']);
1427 if ($config['itemsProcFunc']) {
1428 $selItems = $this->procItems($selItems, $PA['fieldTSConfig']['itemsProcFunc.'], $config, $table, $row, $field);
1429 }
1430
1431 // Traverse the items, making the form elements:
1432 for ($c = 0; $c < count($selItems); $c++) {
1433 $p = $selItems[$c];
1434 $rID = $PA['itemFormElID'] . '_' . $c;
1435 $rOnClick = implode('', $PA['fieldChangeFunc']);
1436 $rChecked = (!strcmp($p[1], $PA['itemFormElValue']) ? ' checked="checked"' : '');
1437 $item .= '<input type="radio"' . $this->insertDefStyle('radio') . ' name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($p[1]) . '" onclick="' . htmlspecialchars($rOnClick) . '"' . $rChecked . $PA['onFocus'] . $disabled . ' id="' . $rID . '" />
1438 <label for="' . $rID . '">' . htmlspecialchars($p[0]) . '</label>
1439 <br />';
1440 }
1441
1442 return $item;
1443 }
1444
1445 /**
1446 * Generation of TCEform elements of the type "select"
1447 * This will render a selector box element, or possibly a special construction with two selector boxes. That depends on configuration.
1448 *
1449 * @param string $table The table name of the record
1450 * @param string $field The field name which this element is supposed to edit
1451 * @param array $row The record data array where the value(s) for the field can be found
1452 * @param array $PA An array with additional configuration options.
1453 * @return string The HTML code for the TCEform field
1454 */
1455 function getSingleField_typeSelect($table, $field, $row, &$PA) {
1456
1457 // Field configuration from TCA:
1458 $config = $PA['fieldConf']['config'];
1459
1460 $disabled = '';
1461 if ($this->renderReadonly || $config['readOnly']) {
1462 $disabled = ' disabled="disabled"';
1463 }
1464
1465 // "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/.
1466 $specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);
1467
1468 // Getting the selector box items from the system
1469 $selItems = $this->addSelectOptionsToItemArray(
1470 $this->initItemArray($PA['fieldConf']),
1471 $PA['fieldConf'],
1472 $this->setTSconfig($table, $row),
1473 $field
1474 );
1475 // Possibly filter some items:
1476 $keepItemsFunc = create_function('$value', 'return $value[1];');
1477 $selItems = t3lib_div::keepItemsInArray($selItems, $PA['fieldTSConfig']['keepItems'], $keepItemsFunc);
1478 // Possibly add some items:
1479 $selItems = $this->addItems($selItems, $PA['fieldTSConfig']['addItems.']);
1480 // Process items by a user function:
1481 if (isset($config['itemsProcFunc']) && $config['itemsProcFunc']) {
1482 $selItems = $this->procItems($selItems, $PA['fieldTSConfig']['itemsProcFunc.'], $config, $table, $row, $field);
1483 }
1484
1485 // Possibly remove some items:
1486 $removeItems = t3lib_div::trimExplode(',', $PA['fieldTSConfig']['removeItems'], 1);
1487 foreach ($selItems as $tk => $p) {
1488
1489 // Checking languages and authMode:
1490 $languageDeny = $GLOBALS['TCA'][$table]['ctrl']['languageField']
1491 && !strcmp($GLOBALS['TCA'][$table]['ctrl']['languageField'], $field)
1492 && !$GLOBALS['BE_USER']->checkLanguageAccess($p[1]);
1493 $authModeDeny = $config['form_type'] == 'select' && $config['authMode'] && !$GLOBALS['BE_USER']->checkAuthMode($table, $field, $p[1], $config['authMode']);
1494 if (in_array($p[1], $removeItems) || $languageDeny || $authModeDeny) {
1495 unset($selItems[$tk]);
1496 } elseif (isset($PA['fieldTSConfig']['altLabels.'][$p[1]])) {
1497 $selItems[$tk][0] = $this->sL($PA['fieldTSConfig']['altLabels.'][$p[1]]);
1498 }
1499
1500 // Removing doktypes with no access:
1501 if (($table === 'pages' || $table === 'pages_language_overlay') && $field === 'doktype') {
1502 if (!($GLOBALS['BE_USER']->isAdmin() || t3lib_div::inList($GLOBALS['BE_USER']->groupData['pagetypes_select'], $p[1]))) {
1503 unset($selItems[$tk]);
1504 }
1505 }
1506 }
1507
1508 // Creating the label for the "No Matching Value" entry.
1509 $nMV_label = isset($PA['fieldTSConfig']['noMatchingValue_label']) ? $this->sL($PA['fieldTSConfig']['noMatchingValue_label']) : '[ ' . $this->getLL('l_noMatchingValue') . ' ]';
1510
1511 // Prepare some values:
1512 $maxitems = intval($config['maxitems']);
1513
1514 // If a SINGLE selector box...
1515 if ($maxitems <= 1 && $config['renderMode'] !== 'tree') {
1516 $item = $this->getSingleField_typeSelect_single($table, $field, $row, $PA, $config, $selItems, $nMV_label);
1517 } elseif (!strcmp($config['renderMode'], 'checkbox')) { // Checkbox renderMode
1518 $item = $this->getSingleField_typeSelect_checkbox($table, $field, $row, $PA, $config, $selItems, $nMV_label);
1519 } elseif (!strcmp($config['renderMode'], 'singlebox')) { // Single selector box renderMode
1520 $item = $this->getSingleField_typeSelect_singlebox($table, $field, $row, $PA, $config, $selItems, $nMV_label);
1521 } elseif (!strcmp($config['renderMode'], 'tree')) { // Tree renderMode
1522 $treeClass = t3lib_div::makeInstance('t3lib_TCEforms_Tree', $this);
1523 $item = $treeClass->renderField($table, $field, $row, $PA, $config, $selItems, $nMV_label);
1524
1525 // Register the required number of elements
1526 $minitems = t3lib_utility_Math::forceIntegerInRange($config['minitems'], 0);
1527 $this->registerRequiredProperty('range', $PA['itemFormElName'], array($minitems, $maxitems, 'imgName' => $table . '_' . $row['uid'] . '_' . $field));
1528 } else { // Traditional multiple selector box:
1529 $item = $this->getSingleField_typeSelect_multiple($table, $field, $row, $PA, $config, $selItems, $nMV_label);
1530 }
1531
1532 // Wizards:
1533 if (!$disabled) {
1534 $altItem = '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
1535 $item = $this->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $PA, $PA['itemFormElName'], $specConf);
1536 }
1537
1538 return $item;
1539 }
1540
1541 /**
1542 * Creates a single-selector box
1543 * (Render function for getSingleField_typeSelect())
1544 *
1545 * @param string $table See getSingleField_typeSelect()
1546 * @param string $field See getSingleField_typeSelect()
1547 * @param array $row See getSingleField_typeSelect()
1548 * @param array $PA See getSingleField_typeSelect()
1549 * @param array $config (Redundant) content of $PA['fieldConf']['config'] (for convenience)
1550 * @param array $selItems Items available for selection
1551 * @param string $nMV_label Label for no-matching-value
1552 * @return string The HTML code for the item
1553 * @see getSingleField_typeSelect()
1554 */
1555 function getSingleField_typeSelect_single($table, $field, $row, &$PA, $config, $selItems, $nMV_label) {
1556 // check against inline uniqueness
1557 $inlineParent = $this->inline->getStructureLevel(-1);
1558 if (is_array($inlineParent) && $inlineParent['uid']) {
1559 if ($inlineParent['config']['foreign_table'] == $table && $inlineParent['config']['foreign_unique'] == $field) {
1560 $uniqueIds = $this->inline->inlineData['unique'][$this->inline->inlineNames['object'] . t3lib_TCEforms_inline::Structure_Separator . $table]['used'];
1561 $PA['fieldChangeFunc']['inlineUnique'] = "inline.updateUnique(this,'" . $this->inline->inlineNames['object'] . t3lib_TCEforms_inline::Structure_Separator . $table . "','" . $this->inline->inlineNames['form'] . "','" . $row['uid'] . "');";
1562 }
1563 // hide uid of parent record for symmetric relations
1564 if ($inlineParent['config']['foreign_table'] == $table && ($inlineParent['config']['foreign_field'] == $field || $inlineParent['config']['symmetric_field'] == $field)) {
1565 $uniqueIds[] = $inlineParent['uid'];
1566 }
1567 }
1568
1569 // Initialization:
1570 $c = 0;
1571 $sI = 0;
1572 $noMatchingValue = 1;
1573 $opt = array();
1574 $selicons = array();
1575 $onlySelectedIconShown = 0;
1576 $size = intval($config['size']);
1577 // Style set on <select/>
1578 $selectedStyle = '';
1579
1580 $item = '';
1581 $disabled = '';
1582 // TODO: icon is used but never assigned
1583 $onChangeIcon = '';
1584
1585 if ($this->renderReadonly || $config['readOnly']) {
1586 $disabled = ' disabled="disabled"';
1587 $onlySelectedIconShown = 1;
1588 }
1589
1590 // Icon configuration:
1591 if ($config['suppress_icons'] == 'IF_VALUE_FALSE') {
1592 $suppressIcons = !$PA['itemFormElValue'] ? 1 : 0;
1593 } elseif ($config['suppress_icons'] == 'ONLY_SELECTED') {
1594 $suppressIcons = 0;
1595 $onlySelectedIconShown = 1;
1596 } elseif ($config['suppress_icons']) {
1597 $suppressIcons = 1;
1598 } else {
1599 $suppressIcons = 0;
1600 }
1601
1602 // Traverse the Array of selector box items:
1603 $optGroupStart = array();
1604 $optGroupOpen = FALSE;
1605 $classesForSelectTag = array();
1606 foreach ($selItems as $p) {
1607 $sM = (!strcmp($PA['itemFormElValue'], $p[1]) ? ' selected="selected"' : '');
1608 if ($sM) {
1609 $sI = $c;
1610 $noMatchingValue = 0;
1611 }
1612
1613 // Getting style attribute value (for icons):
1614 if ($config['iconsInOptionTags']) {
1615 $styleAttrValue = $this->optionTagStyle($p[2]);
1616 if ($sM) {
1617 list($selectIconFile, $selectIconInfo) = $this->getIcon($p[2]);
1618 if (!empty($selectIconInfo)) {
1619 $selectedStyle = ' style="background-image:url(' . $selectIconFile . ');"';
1620 $classesForSelectTag[] = 'typo3-TCEforms-select-selectedItemWithBackgroundImage';
1621 }
1622 }
1623 }
1624
1625 // Compiling the <option> tag:
1626 if (!($p[1] != $PA['itemFormElValue'] && is_array($uniqueIds) && in_array($p[1], $uniqueIds))) {
1627 if (!strcmp($p[1], '--div--')) {
1628 $optGroupStart[0] = $p[0];
1629 if ($config['iconsInOptionTags']) {
1630 $optGroupStart[1] = $this->optgroupTagStyle($p[2]);
1631 } else {
1632 $optGroupStart[1] = $styleAttrValue;
1633 }
1634
1635 } else {
1636 if (count($optGroupStart)) {
1637 // Closing last optgroup before next one starts
1638 if ($optGroupOpen) {
1639 $opt[] = '</optgroup>' . LF;
1640 }
1641 $opt[] = '<optgroup label="' . t3lib_div::deHSCentities(htmlspecialchars($optGroupStart[0])) . '"' .
1642 ($optGroupStart[1] ? ' style="' . htmlspecialchars($optGroupStart[1]) . '"' : '') .
1643 ' class="c-divider">' . LF;
1644 $optGroupOpen = TRUE;
1645 $c--;
1646 $optGroupStart = array();
1647 }
1648 $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' .
1649 $sM .
1650 ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '') .
1651 '>' . t3lib_div::deHSCentities(($p[0])) . '</option>' . LF;
1652 }
1653 }
1654
1655 // If there is an icon for the selector box (rendered in selicon-table below)...:
1656 // if there is an icon ($p[2]), icons should be shown, and, if only selected are visible, is it selected
1657 if ($p[2] && !$suppressIcons && (!$onlySelectedIconShown || $sM)) {
1658 list($selIconFile, $selIconInfo) = $this->getIcon($p[2]);
1659 if (!empty($selIconInfo)) {
1660 $iOnClick = $this->elName($PA['itemFormElName']) . '.selectedIndex=' . $c . '; ' .
1661 $this->elName($PA['itemFormElName']) . '.style.backgroundImage=' . $this->elName($PA['itemFormElName']) . '.options[' . $c . '].style.backgroundImage; ' .
1662 implode('', $PA['fieldChangeFunc']) . $this->blur() . 'return false;';
1663 } else {
1664 $iOnClick = $this->elName($PA['itemFormElName']) . '.selectedIndex=' . $c . '; ' .
1665 $this->elName($PA['itemFormElName']) . '.className=' . $this->elName($PA['itemFormElName']) . '.options[' . $c . '].className; ' .
1666 implode('', $PA['fieldChangeFunc']) . $this->blur() . 'return false;';
1667 }
1668 $selicons[] = array(
1669 (!$onlySelectedIconShown ? '<a href="#" onclick="' . htmlspecialchars($iOnClick) . '">' : '') .
1670 $this->getIconHtml($p[2], htmlspecialchars($p[0]), htmlspecialchars($p[0])) .
1671 (!$onlySelectedIconShown ? '</a>' : ''),
1672 $c, $sM);
1673 }
1674 $c++;
1675 }
1676
1677 // Closing optgroup if open
1678 if ($optGroupOpen) {
1679 $opt[] = '</optgroup>';
1680 $optGroupOpen = FALSE;
1681 }
1682
1683 // No-matching-value:
1684 if ($PA['itemFormElValue'] && $noMatchingValue && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
1685 $nMV_label = @sprintf($nMV_label, $PA['itemFormElValue']);
1686 $opt[] = '<option value="' . htmlspecialchars($PA['itemFormElValue']) . '" selected="selected">' . htmlspecialchars($nMV_label) . '</option>';
1687 }
1688
1689 // Create item form fields:
1690 $sOnChange = 'if (this.options[this.selectedIndex].value==\'--div--\') {this.selectedIndex=' . $sI . ';} ' . implode('', $PA['fieldChangeFunc']);
1691 if (!$disabled) {
1692 // MUST be inserted before the selector - else is the value of the hiddenfield here mysteriously submitted...
1693 $item .= '<input type="hidden" name="' . $PA['itemFormElName'] . '_selIconVal" value="' . htmlspecialchars($sI) . '" />';
1694 }
1695 if ($config['iconsInOptionTags']) {
1696 $classesForSelectTag[] = 'icon-select';
1697 }
1698 $item .= '<select' . $selectedStyle . ' id="' . uniqid('tceforms-select-') . '" name="' . $PA['itemFormElName'] . '"' .
1699 $this->insertDefStyle('select', implode(' ', $classesForSelectTag)) .
1700 ($size ? ' size="' . $size . '"' : '') .
1701 ' onchange="' . htmlspecialchars($onChangeIcon . $sOnChange) . '"' .
1702 $PA['onFocus'] . $disabled . '>';
1703 $item .= implode('', $opt);
1704 $item .= '</select>';
1705
1706 // Create icon table:
1707 if (count($selicons) && !$config['noIconsBelowSelect']) {
1708 $item .= '<table border="0" cellpadding="0" cellspacing="0" class="typo3-TCEforms-selectIcons">';
1709 $selicon_cols = intval($config['selicon_cols']);
1710 if (!$selicon_cols) {
1711 $selicon_cols = count($selicons);
1712 }
1713 $sR = ceil(count($selicons) / $selicon_cols);
1714 $selicons = array_pad($selicons, $sR * $selicon_cols, '');
1715 for ($sa = 0; $sa < $sR; $sa++) {
1716 $item .= '<tr>';
1717 for ($sb = 0; $sb < $selicon_cols; $sb++) {
1718 $sk = ($sa * $selicon_cols + $sb);
1719 $imgN = 'selIcon_' . $table . '_' . $row['uid'] . '_' . $field . '_' . $selicons[$sk][1];
1720 $imgS = ($selicons[$sk][2] ? $this->backPath . 'gfx/content_selected.gif' : 'clear.gif');
1721 $item .= '<td><img name="' . htmlspecialchars($imgN) . '" src="' . $imgS . '" width="7" height="10" alt="" /></td>';
1722 $item .= '<td>' . $selicons[$sk][0] . '</td>';
1723 }
1724 $item .= '</tr>';
1725 }
1726 $item .= '</table>';
1727 }
1728
1729 return $item;
1730 }
1731
1732 /**
1733 * Creates a checkbox list (renderMode = "checkbox")
1734 * (Render function for getSingleField_typeSelect())
1735 *
1736 * @param string $table See getSingleField_typeSelect()
1737 * @param string $field See getSingleField_typeSelect()
1738 * @param array $row See getSingleField_typeSelect()
1739 * @param array $PA See getSingleField_typeSelect()
1740 * @param array $config (Redundant) content of $PA['fieldConf']['config'] (for convenience)
1741 * @param array $selItems Items available for selection
1742 * @param string $nMV_label Label for no-matching-value
1743 * @return string The HTML code for the item
1744 * @see getSingleField_typeSelect()
1745 */
1746 function getSingleField_typeSelect_checkbox($table, $field, $row, &$PA, $config, $selItems, $nMV_label) {
1747
1748 if (empty($selItems)) {
1749 return '';
1750 }
1751
1752 // Get values in an array (and make unique, which is fine because there can be no duplicates anyway):
1753 $itemArray = array_flip($this->extractValuesOnlyFromValueLabelList($PA['itemFormElValue']));
1754
1755 $item = '';
1756 $disabled = '';
1757 if ($this->renderReadonly || $config['readOnly']) {
1758 $disabled = ' disabled="disabled"';
1759 }
1760
1761 // Traverse the Array of selector box items:
1762 $tRows = array();
1763 $c = 0;
1764 if (!$disabled) {
1765 $sOnChange = implode('', $PA['fieldChangeFunc']);
1766 // Used to accumulate the JS needed to restore the original selection.
1767 $setAll = array();
1768 $unSetAll = array();
1769 foreach ($selItems as $p) {
1770 // Non-selectable element:
1771 if (!strcmp($p[1], '--div--')) {
1772 $selIcon = '';
1773 if (isset($p[2]) && $p[2] != 'empty-emtpy') {
1774 $selIcon = $this->getIconHtml($p[2]);
1775 }
1776 $tRows[] = '
1777 <tr class="c-header">
1778 <td colspan="3">' . $selIcon . htmlspecialchars($p[0]) . '</td>
1779 </tr>';
1780 } else {
1781 // Selected or not by default:
1782 $sM = '';
1783 if (isset($itemArray[$p[1]])) {
1784 $sM = ' checked="checked"';
1785 unset($itemArray[$p[1]]);
1786 }
1787
1788 // Icon:
1789 if ($p[2]) {
1790 $selIcon = $p[2];
1791 } else {
1792 $selIcon = t3lib_iconWorks::getSpriteIcon('empty-empty');
1793 }
1794
1795 // Compile row:
1796 $rowId = uniqid('select_checkbox_row_');
1797 $onClickCell = $this->elName($PA['itemFormElName'] . '[' . $c . ']') . '.checked=!' . $this->elName($PA['itemFormElName'] . '[' . $c . ']') . '.checked;';
1798 $onClick = 'this.attributes.getNamedItem("class").nodeValue = ' . $this->elName($PA['itemFormElName'] . '[' . $c . ']') . '.checked ? "c-selectedItem" : "c-unselectedItem";';
1799 $setAll[] = $this->elName($PA['itemFormElName'] . '[' . $c . ']') . '.checked=1;';
1800 $setAll[] .= '$(\'' . $rowId . '\').removeClassName(\'c-unselectedItem\');$(\'' . $rowId . '\').addClassName(\'c-selectedItem\');';
1801 $unSetAll[] = $this->elName($PA['itemFormElName'] . '[' . $c . ']') . '.checked=0;';
1802 $unSetAll[] .= '$(\'' . $rowId . '\').removeClassName(\'c-selectedItem\');$(\'' . $rowId . '\').addClassName(\'c-unselectedItem\');';
1803 $restoreCmd[] = $this->elName($PA['itemFormElName'] . '[' . $c . ']') . '.checked=' . ($sM ? 1 : 0) . ';' .
1804 '$(\'' . $rowId . '\').removeClassName(\'c-selectedItem\');$(\'' . $rowId . '\').removeClassName(\'c-unselectedItem\');' .
1805 '$(\'' . $rowId . '\').addClassName(\'c-' . ($sM ? '' : 'un') . 'selectedItem\');';
1806
1807 // Check if some help text is available
1808 // Since TYPO3 4.5 help text is expected to be an associative array
1809 // with two key, "title" and "description"
1810 // For the sake of backwards compatibility, we test if the help text
1811 // is a string and use it as a description (this could happen if items
1812 // are modified with an itemProcFunc)
1813 $hasHelp = FALSE;
1814 $help = '';
1815 $helpArray = array();
1816 if ((is_array($p[3]) && count($p[3]) > 0) || !empty($p[3])) {
1817 $hasHelp = TRUE;
1818 if (is_array($p[3])) {
1819 $helpArray = $p[3];
1820 } else {
1821 $helpArray['description'] = $p[3];
1822 }
1823 }
1824
1825 $label = t3lib_div::deHSCentities(htmlspecialchars($p[0]));
1826 if ($hasHelp) {
1827 $help = t3lib_BEfunc::wrapInHelp('', '', '', $helpArray);
1828 }
1829
1830 $tRows[] = '
1831 <tr id="' . $rowId . '" class="' . ($sM ? 'c-selectedItem' : 'c-unselectedItem') . '" onclick="' . htmlspecialchars($onClick) . '" style="cursor: pointer;">
1832 <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>
1833 <td class="c-labelCell" onclick="' . htmlspecialchars($onClickCell) . '">' .
1834 $this->getIconHtml($selIcon) .
1835 $label .
1836 '</td>
1837 <td class="c-descr" onclick="' . htmlspecialchars($onClickCell) . '">' . ((empty($help)) ? '' : $help) . '</td>
1838 </tr>';
1839 $c++;
1840 }
1841 }
1842 }
1843
1844 // Remaining values (invalid):
1845 if (count($itemArray) && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
1846 foreach ($itemArray as $theNoMatchValue => $temp) {
1847 // Compile <checkboxes> tag:
1848 array_unshift($tRows, '
1849 <tr class="c-invalidItem">
1850 <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>
1851 <td class="c-labelCell">' .
1852 t3lib_div::deHSCentities(htmlspecialchars(@sprintf($nMV_label, $theNoMatchValue))) .
1853 '</td><td>&nbsp;</td>
1854 </tr>');
1855 $c++;
1856 }
1857 }
1858
1859 // Add an empty hidden field which will send a blank value if all items are unselected.
1860 $item .= '<input type="hidden" name="' . htmlspecialchars($PA['itemFormElName']) . '" value="" />';
1861
1862 // Remaining checkboxes will get their set-all link:
1863 if (count($setAll)) {
1864 $tableHead = '<thead>
1865 <tr class="c-header-checkbox-controls t3-row-header">
1866 <td class="c-checkbox">
1867 <input type="checkbox" class="checkbox" onclick="if (checked) {' . htmlspecialchars(implode('', $setAll) . '} else {' . implode('', $unSetAll) . '}') . '">
1868 </td>
1869 <td colspan="2">
1870 </td>
1871 </tr></thead>';
1872 }
1873 // Implode rows in table:
1874 $item .= '
1875 <table border="0" cellpadding="0" cellspacing="0" class="typo3-TCEforms-select-checkbox">' .
1876 $tableHead .
1877 '<tbody>' . implode('', $tRows) . '</tbody>
1878 </table>
1879 ';
1880
1881 // Add revert icon
1882 if (is_array($restoreCmd)) {
1883 $item .= '<a href="#" onclick="' . implode('', $restoreCmd) . ' return false;' . '">' .
1884 t3lib_iconWorks::getSpriteIcon('actions-edit-undo', array('title' => htmlspecialchars($this->getLL('l_revertSelection')))) . '</a>';
1885 }
1886
1887 return $item;
1888 }
1889
1890 /**
1891 * Creates a selectorbox list (renderMode = "singlebox")
1892 * (Render function for getSingleField_typeSelect())
1893 *
1894 * @param string $table See getSingleField_typeSelect()
1895 * @param string $field See getSingleField_typeSelect()
1896 * @param array $row See getSingleField_typeSelect()
1897 * @param array $PA See getSingleField_typeSelect()
1898 * @param array $config (Redundant) content of $PA['fieldConf']['config'] (for convenience)
1899 * @param array $selItems Items available for selection
1900 * @param string $nMV_label Label for no-matching-value
1901 * @return string The HTML code for the item
1902 * @see getSingleField_typeSelect()
1903 */
1904 function getSingleField_typeSelect_singlebox($table, $field, $row, &$PA, $config, $selItems, $nMV_label) {
1905
1906 // Get values in an array (and make unique, which is fine because there can be no duplicates anyway):
1907 $itemArray = array_flip($this->extractValuesOnlyFromValueLabelList($PA['itemFormElValue']));
1908
1909 $item = '';
1910 $disabled = '';
1911 if ($this->renderReadonly || $config['readOnly']) {
1912 $disabled = ' disabled="disabled"';
1913 }
1914
1915 // Traverse the Array of selector box items:
1916 $opt = array();
1917 // Used to accumulate the JS needed to restore the original selection.
1918 $restoreCmd = array();
1919 $c = 0;
1920 foreach ($selItems as $p) {
1921 // Selected or not by default:
1922 $sM = '';
1923 if (isset($itemArray[$p[1]])) {
1924 $sM = ' selected="selected"';
1925 $restoreCmd[] = $this->elName($PA['itemFormElName'] . '[]') . '.options[' . $c . '].selected=1;';
1926 unset($itemArray[$p[1]]);
1927 }
1928
1929 // Non-selectable element:
1930 $nonSel = '';
1931 if (!strcmp($p[1], '--div--')) {
1932 $nonSel = ' onclick="this.selected=0;" class="c-divider"';
1933 }
1934
1935 // Icon style for option tag:
1936 if ($config['iconsInOptionTags']) {
1937 $styleAttrValue = $this->optionTagStyle($p[2]);
1938 }
1939
1940 // Compile <option> tag:
1941 $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' .
1942 $sM .
1943 $nonSel .
1944 ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '') .
1945 '>' . t3lib_div::deHSCentities(htmlspecialchars($p[0])) . '</option>';
1946 $c++;
1947 }
1948
1949 // Remaining values:
1950 if (count($itemArray) && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
1951 foreach ($itemArray as $theNoMatchValue => $temp) {
1952 // Compile <option> tag:
1953 array_unshift($opt, '<option value="' . htmlspecialchars($theNoMatchValue) . '" selected="selected">' . t3lib_div::deHSCentities(htmlspecialchars(@sprintf($nMV_label, $theNoMatchValue))) . '</option>');
1954 }
1955 }
1956
1957 // Compile selector box:
1958 $sOnChange = implode('', $PA['fieldChangeFunc']);
1959 $selector_itemListStyle = isset($config['itemListStyle']) ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"' : ' style="' . $this->defaultMultipleSelectorStyle . '"';
1960 $size = intval($config['size']);
1961 $cssPrefix = ($size === 1) ? 'tceforms-select' : 'tceforms-multiselect';
1962 $size = $config['autoSizeMax'] ? t3lib_utility_Math::forceIntegerInRange(count($selItems) + 1, t3lib_utility_Math::forceIntegerInRange($size, 1), $config['autoSizeMax']) : $size;
1963 $selectBox = '<select id="' . uniqid($cssPrefix) . '" name="' . $PA['itemFormElName'] . '[]"' .
1964 $this->insertDefStyle('select', $cssPrefix) .
1965 ($size ? ' size="' . $size . '"' : '') .
1966 ' multiple="multiple" onchange="' . htmlspecialchars($sOnChange) . '"' .
1967 $PA['onFocus'] .
1968 $selector_itemListStyle .
1969 $disabled . '>
1970 ' .
1971 implode('
1972 ', $opt) . '
1973 </select>';
1974
1975 // Add an empty hidden field which will send a blank value if all items are unselected.
1976 if (!$disabled) {
1977 $item .= '<input type="hidden" name="' . htmlspecialchars($PA['itemFormElName']) . '" value="" />';
1978 }
1979
1980 // Put it all into a table:
1981 $item .= '
1982 <table border="0" cellspacing="0" cellpadding="0" width="1" class="typo3-TCEforms-select-singlebox">
1983 <tr>
1984 <td>
1985 ' . $selectBox . '
1986 <br/>
1987 <em>' .
1988 htmlspecialchars($this->getLL('l_holdDownCTRL')) .
1989 '</em>
1990 </td>
1991 <td valign="top">
1992 <a href="#" onclick="' . htmlspecialchars($this->elName($PA['itemFormElName'] . '[]') . '.selectedIndex=-1;' . implode('', $restoreCmd) . ' return false;') . '" title="' . htmlspecialchars($this->getLL('l_revertSelection')) . '">' .
1993 t3lib_iconWorks::getSpriteIcon('actions-edit-undo') .
1994 '</a>
1995 </td>
1996 </tr>
1997 </table>
1998 ';
1999
2000 return $item;
2001 }
2002
2003 /**
2004 * Creates a multiple-selector box (two boxes, side-by-side)
2005 * (Render function for getSingleField_typeSelect())
2006 *
2007 * @param string $table See getSingleField_typeSelect()
2008 * @param string $field See getSingleField_typeSelect()
2009 * @param array $row See getSingleField_typeSelect()
2010 * @param array $PA See getSingleField_typeSelect()
2011 * @param array $config (Redundant) content of $PA['fieldConf']['config'] (for convenience)
2012 * @param array $selItems Items available for selection
2013 * @param string $nMV_label Label for no-matching-value
2014 * @return string The HTML code for the item
2015 * @see getSingleField_typeSelect()
2016 */
2017 function getSingleField_typeSelect_multiple($table, $field, $row, &$PA, $config, $selItems, $nMV_label) {
2018
2019 $item = '';
2020 $disabled = '';
2021 if ($this->renderReadonly || $config['readOnly']) {
2022 $disabled = ' disabled="disabled"';
2023 }
2024
2025 // Setting this hidden field (as a flag that JavaScript can read out)
2026 if (!$disabled) {
2027 $item .= '<input type="hidden" name="' . $PA['itemFormElName'] . '_mul" value="' . ($config['multiple'] ? 1 : 0) . '" />';
2028 }
2029
2030 // Set max and min items:
2031 $maxitems = t3lib_utility_Math::forceIntegerInRange($config['maxitems'], 0);
2032 if (!$maxitems) {
2033 $maxitems = 100000;
2034 }
2035 $minitems = t3lib_utility_Math::forceIntegerInRange($config['minitems'], 0);
2036
2037 // Register the required number of elements:
2038 $this->registerRequiredProperty('range', $PA['itemFormElName'], array($minitems, $maxitems, 'imgName' => $table . '_' . $row['uid'] . '_' . $field));
2039
2040 // Get "removeItems":
2041 $removeItems = t3lib_div::trimExplode(',', $PA['fieldTSConfig']['removeItems'], 1);
2042
2043 // Get the array with selected items:
2044 $itemArray = t3lib_div::trimExplode(',', $PA['itemFormElValue'], 1);
2045
2046 // Possibly filter some items:
2047 $keepItemsFunc = create_function('$value', '$parts=explode(\'|\',$value,2); return rawurldecode($parts[0]);');
2048 $itemArray = t3lib_div::keepItemsInArray($itemArray, $PA['fieldTSConfig']['keepItems'], $keepItemsFunc);
2049
2050 // Perform modification of the selected items array:
2051 foreach ($itemArray as $tk => $tv) {
2052 $tvP = explode('|', $tv, 2);
2053 $evalValue = $tvP[0];
2054 $isRemoved = in_array($evalValue, $removeItems) || ($config['form_type'] == 'select' && $config['authMode'] && !$GLOBALS['BE_USER']->checkAuthMode($table, $field, $evalValue, $config['authMode']));
2055 if ($isRemoved && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
2056 $tvP[1] = rawurlencode(@sprintf($nMV_label, $evalValue));
2057 } elseif (isset($PA['fieldTSConfig']['altLabels.'][$evalValue])) {
2058 $tvP[1] = rawurlencode($this->sL($PA['fieldTSConfig']['altLabels.'][$evalValue]));
2059 }
2060 if ($tvP[1] == '') {
2061 // Case: flexform, default values supplied, no label provided (bug #9795)
2062 foreach ($selItems as $selItem) {
2063 if ($selItem[1] == $tvP[0]) {
2064 $tvP[1] = html_entity_decode($selItem[0]);
2065 break;
2066 }
2067 }
2068 }
2069 $itemArray[$tk] = implode('|', $tvP);
2070 }
2071 $itemsToSelect = '';
2072
2073 if (!$disabled) {
2074 // Create option tags:
2075 $opt = array();
2076 $styleAttrValue = '';
2077 foreach ($selItems as $p) {
2078 if ($config['iconsInOptionTags']) {
2079 $styleAttrValue = $this->optionTagStyle($p[2]);
2080 }
2081 $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' .
2082 ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '') .
2083 ' title="' . $p[0] . '">' . $p[0] . '</option>';
2084 }
2085
2086 // Put together the selector box:
2087 $selector_itemListStyle = isset($config['itemListStyle']) ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"' : ' style="' . $this->defaultMultipleSelectorStyle . '"';
2088 $size = intval($config['size']);
2089 $size = $config['autoSizeMax'] ? t3lib_utility_Math::forceIntegerInRange(count($itemArray) + 1, t3lib_utility_Math::forceIntegerInRange($size, 1), $config['autoSizeMax']) : $size;
2090 if ($config['exclusiveKeys']) {
2091 $sOnChange = 'setFormValueFromBrowseWin(\'' . $PA['itemFormElName']
2092 . '\',this.options[this.selectedIndex].value, this.options[this.selectedIndex].text, this.options[this.selectedIndex].title,\''
2093 . $config['exclusiveKeys'] . '\'); ';
2094 } else {
2095 $sOnChange = 'setFormValueFromBrowseWin(\'' . $PA['itemFormElName']
2096 . '\',this.options[this.selectedIndex].value, this.options[this.selectedIndex].text, this.options[this.selectedIndex].title); ';
2097 }
2098 $sOnChange .= implode('', $PA['fieldChangeFunc']);
2099 $itemsToSelect = '
2100 <select id="' . uniqid('tceforms-multiselect-') . '" name="' . $PA['itemFormElName'] . '_sel"' .
2101 $this->insertDefStyle('select', 'tceforms-multiselect tceforms-itemstoselect') .
2102 ($size ? ' size="' . $size . '"' : '') .
2103 ' onchange="' . htmlspecialchars($sOnChange) . '"' .
2104 $PA['onFocus'] .
2105 $selector_itemListStyle . '>
2106 ' . implode('
2107 ', $opt) . '
2108 </select>';
2109 }
2110
2111 // Pass to "dbFileIcons" function:
2112 $params = array(
2113 'size' => $size,
2114 'autoSizeMax' => t3lib_utility_Math::forceIntegerInRange($config['autoSizeMax'], 0),
2115 'style' => isset($config['selectedListStyle']) ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"' : ' style="' . $this->defaultMultipleSelectorStyle . '"',
2116 'dontShowMoveIcons' => ($maxitems <= 1),
2117 'maxitems' => $maxitems,
2118 'info' => '',
2119 'headers' => array(
2120 'selector' => $this->getLL('l_selected') . ':<br />',
2121 'items' => $this->getLL('l_items') . ':<br />'
2122 ),
2123 'noBrowser' => 1,
2124 'thumbnails' => $itemsToSelect,
2125 'readOnly' => $disabled
2126 );
2127 $item .= $this->dbFileIcons($PA['itemFormElName'], '', '', $itemArray, '', $params, $PA['onFocus']);
2128
2129 return $item;
2130 }
2131
2132 /**
2133 * Generation of TCEform elements of the type "group"
2134 * This will render a selectorbox into which elements from either the file system or database can be inserted. Relations.
2135 *
2136 * @param string $table The table name of the record
2137 * @param string $field The field name which this element is supposed to edit
2138 * @param array $row The record data array where the value(s) for the field can be found
2139 * @param array $PA An array with additional configuration options.
2140 * @return string The HTML code for the TCEform field
2141 */
2142 function getSingleField_typeGroup($table, $field, $row, &$PA) {
2143 // Init:
2144 $config = $PA['fieldConf']['config'];
2145 $internal_type = $config['internal_type'];
2146 $show_thumbs = $config['show_thumbs'];
2147 $size = intval($config['size']);
2148 $maxitems = t3lib_utility_Math::forceIntegerInRange($config['maxitems'], 0);
2149 if (!$maxitems) {
2150 $maxitems = 100000;
2151 }
2152 $minitems = t3lib_utility_Math::forceIntegerInRange($config['minitems'], 0);
2153 $allowed = trim($config['allowed']);
2154 $disallowed = trim($config['disallowed']);
2155
2156 $item = '';
2157 $disabled = '';
2158 if ($this->renderReadonly || $config['readOnly']) {
2159 $disabled = ' disabled="disabled"';
2160 }
2161
2162 $item .= '<input type="hidden" name="' . $PA['itemFormElName'] . '_mul" value="' . ($config['multiple'] ? 1 : 0) . '"' . $disabled . ' />';
2163 $this->registerRequiredProperty('range', $PA['itemFormElName'], array($minitems, $maxitems, 'imgName' => $table . '_' . $row['uid'] . '_' . $field));
2164 $info = '';
2165
2166 // "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/.
2167 $specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);
2168
2169 $PA['itemFormElID_file'] = $PA['itemFormElID'] . '_files';
2170
2171 // whether the list and delete controls should be disabled
2172 $noList = isset($config['disable_controls']) && t3lib_div::inList($config['disable_controls'], 'list');
2173 $noDelete = isset($config['disable_controls']) && t3lib_div::inList($config['disable_controls'], 'delete');
2174
2175 // if maxitems==1 then automatically replace the current item (in list and file selector)
2176 if ($maxitems === 1) {
2177 $this->additionalJS_post[] = "TBE_EDITOR.clearBeforeSettingFormValueFromBrowseWin['" . $PA['itemFormElName'] . "'] = {
2178 itemFormElID_file: '" . $PA['itemFormElID_file'] . "'
2179 }";
2180 $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = "setFormValueManipulate('" . $PA['itemFormElName'] . "', 'Remove'); " . $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'];
2181 } elseif ($noList) {
2182 // If the list controls have been removed and the maximum number is reached, remove the first entry to avoid "write once" field
2183 $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = "setFormValueManipulate('" . $PA['itemFormElName'] . "', 'RemoveFirstIfFull', '" . $maxitems . "'); " . $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'];
2184 }
2185
2186 // Acting according to either "file" or "db" type:
2187 switch ((string) $config['internal_type']) {
2188 case 'file_reference':
2189 $config['uploadfolder'] = '';
2190 // Fall through
2191 // If the element is of the internal type "file":
2192 case 'file':
2193 // Creating string showing allowed types:
2194 $tempFT = t3lib_div::trimExplode(',', $allowed, TRUE);
2195 if (!count($tempFT)) {
2196 $info .= '*';
2197 }
2198 foreach ($tempFT as $ext) {
2199 if ($ext) {
2200 $info .= strtoupper($ext) . ' ';
2201 }
2202 }
2203 // Creating string, showing disallowed types:
2204 $tempFT_dis = t3lib_div::trimExplode(',', $disallowed, TRUE);
2205 if (count($tempFT_dis)) {
2206 $info .= '<br />';
2207 }
2208 foreach ($tempFT_dis as $ext) {
2209 if ($ext) {
2210 $info .= '-' . strtoupper($ext) . ' ';
2211 }
2212 }
2213
2214 // Making the array of file items:
2215 $itemArray = t3lib_div::trimExplode(',', $PA['itemFormElValue'], TRUE);
2216
2217 $fileFactory = t3lib_file_Factory::getInstance();
2218
2219 // Correct the filename for the FAL items
2220 foreach ($itemArray as &$fileItem) {
2221 list($fileUid, $fileLabel) = explode('|', $fileItem);
2222 if (t3lib_utility_Math::canBeInterpretedAsInteger($fileUid)) {
2223 $fileObject = $fileFactory->getFileObject($fileUid);
2224 $fileLabel = $fileObject->getName();
2225 }
2226
2227 $fileItem = $fileUid . '|' . $fileLabel;
2228 }
2229
2230 // Showing thumbnails:
2231 $thumbsnail = '';
2232 if ($show_thumbs) {
2233 $imgs = array();
2234 foreach ($itemArray as $imgRead) {
2235 $imgP = explode('|', $imgRead);
2236 $imgPath = rawurldecode($imgP[0]);
2237
2238 // FAL icon production
2239 if (t3lib_utility_Math::canBeInterpretedAsInteger($imgP[0])) {
2240 $fileObject = $fileFactory->getFileObject($imgP[0]);
2241
2242 if (t3lib_div::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileObject->getExtension())) {
2243 $imageUrl = $fileObject->process(t3lib_file_ProcessedFile::CONTEXT_IMAGEPREVIEW, array())->getPublicUrl(TRUE);
2244 $imgTag = '<img src="' . $imageUrl . '" alt="' . htmlspecialchars($fileObject->getName()) . '" />';
2245 } else {
2246 // Icon
2247 $imgTag = t3lib_iconWorks::getSpriteIconForFile(
2248 strtolower($fileObject->getExtension()),
2249 array('title' => $fileObject->getName())
2250 );
2251 }
2252
2253 $imgs[] = '<span class="nobr">' . $imgTag . htmlspecialchars($fileObject->getName()) . '</span>';
2254 } else {
2255 $rowCopy = array();
2256 $rowCopy[$field] = $imgPath;
2257
2258 $thumbnailCode = t3lib_BEfunc::thumbCode(
2259 $rowCopy,
2260 $table,
2261 $field,
2262 $this->backPath,
2263 'thumbs.php',
2264 $config['uploadfolder'],
2265 0,
2266 ' align="middle"'
2267 );
2268 $imgs[] = '<span class="nobr">' . $thumbnailCode . $imgPath . '</span>';
2269 }
2270
2271 }
2272 $thumbsnail = implode('<br />', $imgs);
2273 }
2274
2275 // Creating the element:
2276 $params = array(
2277 'size' => $size,
2278 'dontShowMoveIcons' => ($maxitems <= 1),
2279 'autoSizeMax' => t3lib_utility_Math::forceIntegerInRange($config['autoSizeMax'], 0),
2280 'maxitems' => $maxitems,
2281 'style' => isset($config['selectedListStyle']) ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"' : ' style="' . $this->defaultMultipleSelectorStyle . '"',
2282 'info' => $info,
2283 'thumbnails' => $thumbsnail,
2284 'readOnly' => $disabled,
2285 'noBrowser' => $noList || (isset($config['disable_controls']) && t3lib_div::inList($config['disable_controls'], 'browser')),
2286 'noList' => $noList,
2287 'noDelete' => $noDelete,
2288 );
2289 $item .= $this->dbFileIcons($PA['itemFormElName'], 'file', implode(',', $tempFT), $itemArray, '', $params, $PA['onFocus'], '', '', '', $config);
2290
2291 if (!$disabled && !(isset($config['disable_controls']) && t3lib_div::inList($config['disable_controls'], 'upload'))) {
2292 // Adding the upload field:
2293 if ($this->edit_docModuleUpload && $config['uploadfolder']) {
2294
2295 // Insert the multiple attribute to enable HTML5 multiple file upload
2296 $multipleAttribute = '';
2297 $multipleFilenameSuffix = '';
2298 if (isset($config['maxitems']) && $config['maxitems'] > 1) {
2299 $multipleAttribute = ' multiple="multiple"';
2300 $multipleFilenameSuffix = '[]';
2301 }
2302
2303 $item .= '<div id="' . $PA['itemFormElID_file'] . '"><input type="file"'. $multipleAttribute .' name="' . $PA['itemFormElName_file'] . $multipleFilenameSuffix . '" size="35" onchange="' . implode('', $PA['fieldChangeFunc']) . '" /></div>';
2304
2305 }
2306 }
2307 break;
2308 case 'folder': // If the element is of the internal type "folder":
2309
2310 // Array of folder items:
2311 $itemArray = t3lib_div::trimExplode(',', $PA['itemFormElValue'], 1);
2312
2313 // Creating the element:
2314 $params = array(
2315 'size' => $size,
2316 'dontShowMoveIcons' => ($maxitems <= 1),
2317 'autoSizeMax' => t3lib_utility_Math::forceIntegerInRange($config['autoSizeMax'], 0),
2318 'maxitems' => $maxitems,
2319 'style' => isset($config['selectedListStyle']) ?
2320 ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
2321 : ' style="' . $this->defaultMultipleSelectorStyle . '"',
2322 'info' => $info,
2323 'readOnly' => $disabled,
2324 'noBrowser' => $noList || (isset($config['disable_controls']) && t3lib_div::inList($config['disable_controls'], 'browser')),
2325 'noList' => $noList,
2326 );
2327
2328 $item .= $this->dbFileIcons(
2329 $PA['itemFormElName'],
2330 'folder',
2331 '',
2332 $itemArray,
2333 '',
2334 $params,
2335 $PA['onFocus']
2336 );
2337 break;
2338 case 'db': // If the element is of the internal type "db":
2339
2340 // Creating string showing allowed types:
2341 $tempFT = t3lib_div::trimExplode(',', $allowed, TRUE);
2342 if (!strcmp(trim($tempFT[0]), '*')) {
2343 $onlySingleTableAllowed = FALSE;
2344 $info .= '<span class="nobr">' .
2345 htmlspecialchars($this->getLL('l_allTables')) .
2346 '</span><br />';
2347 } elseif ($tempFT) {
2348 $onlySingleTableAllowed = (count($tempFT) == 1);
2349 foreach ($tempFT as $theT) {
2350 $info .= '<span class="nobr">' .
2351 t3lib_iconWorks::getSpriteIconForRecord($theT, array()) .
2352 htmlspecialchars($this->sL($GLOBALS['TCA'][$theT]['ctrl']['title'])) .
2353 '</span><br />';
2354 }
2355 }
2356
2357 $perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
2358 $itemArray = array();
2359 $imgs = array();
2360
2361 // Thumbnails:
2362 $temp_itemArray = t3lib_div::trimExplode(',', $PA['itemFormElValue'], 1);
2363 foreach ($temp_itemArray as $dbRead) {
2364 $recordParts = explode('|', $dbRead);
2365 list($this_table, $this_uid) = t3lib_BEfunc::splitTable_Uid($recordParts[0]);
2366 // For the case that no table was found and only a single table is defined to be allowed, use that one:
2367 if (!$this_table && $onlySingleTableAllowed) {
2368 $this_table = $allowed;
2369 }
2370 $itemArray[] = array('table' => $this_table, 'id' => $this_uid);
2371 if (!$disabled && $show_thumbs) {
2372 $rr = t3lib_BEfunc::getRecordWSOL($this_table, $this_uid);
2373 $imgs[] = '<span class="nobr">' .
2374 $this->getClickMenu(
2375 t3lib_iconWorks::getSpriteIconForRecord(
2376 $this_table,
2377 $rr,
2378 array(
2379 'style' => 'vertical-align:top',
2380 'title' => htmlspecialchars(t3lib_BEfunc::getRecordPath($rr['pid'], $perms_clause, 15) . ' [UID: ' . $rr['uid'] . ']')
2381 )
2382 ),
2383 $this_table,
2384 $this_uid
2385 ) .
2386 '&nbsp;' .
2387 t3lib_BEfunc::getRecordTitle($this_table, $rr, TRUE) . ' <span class="typo3-dimmed"><em>[' . $rr['uid'] . ']</em></span>' .
2388 '</span>';
2389 }
2390 }
2391 $thumbsnail = '';
2392 if (!$disabled && $show_thumbs) {
2393 $thumbsnail = implode('<br />', $imgs);
2394 }
2395
2396 // Creating the element:
2397 $params = array(
2398 'size' => $size,
2399 'dontShowMoveIcons' => ($maxitems <= 1),
2400 'autoSizeMax' => t3lib_utility_Math::forceIntegerInRange($config['autoSizeMax'], 0),
2401 'maxitems' => $maxitems,
2402 'style' => isset($config['selectedListStyle']) ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"' : ' style="' . $this->defaultMultipleSelectorStyle . '"',
2403 'info' => $info,
2404 'thumbnails' => $thumbsnail,
2405 'readOnly' => $disabled,
2406 'noBrowser' => $noList || (isset($config['disable_controls']) && t3lib_div::inList($config['disable_controls'], 'browser')),
2407 'noList' => $noList,
2408 );
2409 $item .= $this->dbFileIcons($PA['itemFormElName'], 'db', implode(',', $tempFT), $itemArray, '', $params, $PA['onFocus'], $table, $field, $row['uid'], $config);
2410
2411 break;
2412 }
2413
2414 // Wizards:
2415 $altItem = '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
2416 if (!$disabled) {
2417 $item = $this->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $PA, $PA['itemFormElName'], $specConf);
2418 }
2419
2420 return $item;
2421 }
2422
2423 /**
2424 * Generation of TCEform elements of the type "none"
2425 * This will render a non-editable display of the content of the field.
2426 *
2427 * @param string $table The table name of the record
2428 * @param string $field The field name which this element is supposed to edit
2429 * @param array $row The record data array where the value(s) for the field can be found
2430 * @param array $PA An array with additional configuration options.
2431 * @return string The HTML code for the TCEform field
2432 */
2433 function getSingleField_typeNone($table, $field, $row, &$PA) {
2434 // Init:
2435 $config = $PA['fieldConf']['config'];
2436 $itemValue = $PA['itemFormElValue'];
2437
2438 return $this->getSingleField_typeNone_render($config, $itemValue);
2439 }
2440
2441 /**
2442 * HTML rendering of a value which is not editable.
2443 *
2444 * @param array $config Configuration for the display
2445 * @param string $itemValue The value to display
2446 * @return string The HTML code for the display
2447 * @see getSingleField_typeNone();
2448 */
2449 function getSingleField_typeNone_render($config, $itemValue) {
2450
2451 if ($config['format']) {
2452 $itemValue = $this->formatValue($config, $itemValue);
2453 }
2454
2455 $rows = intval($config['rows']);
2456 if ($rows > 1) {
2457 if (!$config['pass_content']) {
2458 $itemValue = nl2br(htmlspecialchars($itemValue));
2459 }
2460 // Like textarea
2461 $cols = t3lib_utility_Math::forceIntegerInRange($config['cols'] ? $config['cols'] : 30, 5, $this->maxTextareaWidth);
2462 if (!$config['fixedRows']) {
2463 $origRows = $rows = t3lib_utility_Math::forceIntegerInRange($rows, 1, 20);
2464 if (strlen($itemValue) > $this->charsPerRow * 2) {
2465 $cols = $this->maxTextareaWidth;
2466 $rows = t3lib_utility_Math::forceIntegerInRange(round(strlen($itemValue) / $this->charsPerRow), count(explode(LF, $itemValue)), 20);
2467 if ($rows < $origRows) {
2468 $rows = $origRows;
2469 }
2470 }
2471 }
2472
2473 if ($this->docLarge) {
2474 $cols = round($cols * $this->form_largeComp);
2475 }
2476 $width = ceil($cols * $this->form_rowsToStylewidth);
2477 // Hardcoded: 12 is the height of the font
2478 $height = $rows * 12;
2479
2480 $item = '
2481 <div style="overflow:auto; height:' . $height . 'px; width:' . $width . 'px;" class="t3-tceforms-fieldReadOnly">' .
2482 $itemValue .
2483 t3lib_iconWorks::getSpriteIcon('status-status-readonly') .
2484 '</div>';
2485 } else {
2486 if (!$config['pass_content']) {
2487 $itemValue = htmlspecialchars($itemValue);
2488 }
2489
2490 $cols = $config['cols'] ? $config['cols'] : ($config['size'] ? $config['size'] : $this->maxInputWidth);
2491 if ($this->docLarge) {
2492 $cols = round($cols * $this->form_largeComp);
2493 }
2494 $width = ceil($cols * $this->form_rowsToStylewidth);
2495
2496 // Overflow:auto crashes mozilla here. Title tag is usefull when text is longer than the div box (overflow:hidden).
2497 $item = '
2498 <div style="overflow:hidden; width:' . $width . 'px;" class="t3-tceforms-fieldReadOnly" title="' . $itemValue . '">' .
2499 '<span class="nobr">' . (strcmp($itemValue, '') ? $itemValue : '&nbsp;') . '</span>' .
2500 t3lib_iconWorks::getSpriteIcon('status-status-readonly') .
2501 '</div>';
2502 }
2503
2504 return $item;
2505 }
2506
2507 /**
2508 * Handler for Flex Forms
2509 *
2510 * @param string $table The table name of the record
2511 * @param string $field The field name which this element is supposed to edit
2512 * @param array $row The record data array where the value(s) for the field can be found
2513 * @param array $PA An array with additional configuration options.
2514 * @return string The HTML code for the TCEform field
2515 */
2516 function getSingleField_typeFlex($table, $field, $row, &$PA) {
2517
2518 // Data Structure:
2519 $dataStructArray = t3lib_BEfunc::getFlexFormDS($PA['fieldConf']['config'], $row, $table);
2520 $item = '';
2521
2522 // Manipulate Flexform DS via TSConfig and group access lists
2523 if (is_array($dataStructArray)) {
2524 $flexFormHelper = t3lib_div::makeInstance('t3lib_TCEforms_Flexforms');
2525 $dataStructArray = $flexFormHelper->modifyFlexFormDS($dataStructArray, $table, $field, $row, $PA['fieldConf']);
2526 unset($flexFormHelper);
2527 }
2528
2529 // Get data structure:
2530 if (is_array($dataStructArray)) {
2531
2532 // Get data:
2533 $xmlData = $PA['itemFormElValue'];
2534 $xmlHeaderAttributes = t3lib_div::xmlGetHeaderAttribs($xmlData);
2535 $storeInCharset = strtolower($xmlHeaderAttributes['encoding']);
2536 if ($storeInCharset) {
2537 $currentCharset = $GLOBALS['LANG']->charSet;
2538 $xmlData = $GLOBALS['LANG']->csConvObj->conv($xmlData, $storeInCharset, $currentCharset, 1);
2539 }
2540 $editData = t3lib_div::xml2array($xmlData);
2541 // Must be XML parsing error...
2542 if (!is_array($editData)) {
2543 $editData = array();
2544 } elseif (!isset($editData['meta']) || !is_array($editData['meta'])) {
2545 $editData['meta'] = array();
2546 }
2547
2548 // Find the data structure if sheets are found:
2549 $sheet = $editData['meta']['currentSheetId'] ? $editData['meta']['currentSheetId'] : 'sDEF'; // Sheet to display
2550
2551 // Create language menu:
2552 $langChildren = $dataStructArray['meta']['langChildren'] ? 1 : 0;
2553 $langDisabled = $dataStructArray['meta']['langDisable'] ? 1 : 0;
2554
2555 $editData['meta']['currentLangId'] = array();
2556
2557 // Look up page overlays:
2558 $checkPageLanguageOverlay = $GLOBALS['BE_USER']->getTSConfigVal('options.checkPageLanguageOverlay') ? TRUE : FALSE;
2559 if ($checkPageLanguageOverlay) {
2560 $pageOverlays = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
2561 '*',
2562 'pages_language_overlay',
2563 'pid=' . intval($row['pid']) .
2564 t3lib_BEfunc::deleteClause('pages_language_overlay') .
2565 t3lib_BEfunc::versioningPlaceholderClause('pages_language_overlay'),
2566 '',
2567 '',
2568 '',
2569 'sys_language_uid'
2570 );
2571 }
2572 $languages = $this->getAvailableLanguages();
2573
2574 foreach ($languages as $lInfo) {
2575 if ($GLOBALS['BE_USER']->checkLanguageAccess($lInfo['uid']) && (!$checkPageLanguageOverlay || $lInfo['uid'] <= 0 || is_array($pageOverlays[$lInfo['uid']]))) {
2576 $editData['meta']['currentLangId'][] = $lInfo['ISOcode'];
2577 }
2578 }
2579 if (!is_array($editData['meta']['currentLangId']) || !count($editData['meta']['currentLangId'])) {
2580 $editData['meta']['currentLangId'] = array('DEF');
2581 }
2582
2583 $editData['meta']['currentLangId'] = array_unique($editData['meta']['currentLangId']);
2584
2585 $PA['_noEditDEF'] = FALSE;
2586 if ($langChildren || $langDisabled) {
2587 $rotateLang = array('DEF');
2588 } else {
2589 if (!in_array('DEF', $editData['meta']['currentLangId'])) {
2590 array_unshift($editData['meta']['currentLangId'], 'DEF');
2591 $PA['_noEditDEF'] = TRUE;
2592 }
2593 $rotateLang = $editData['meta']['currentLangId'];
2594 }
2595
2596 // Tabs sheets
2597 if (is_array($dataStructArray['sheets'])) {
2598 $tabsToTraverse = array_keys($dataStructArray['sheets']);
2599 } else {
2600 $tabsToTraverse = array($sheet);
2601 }
2602
2603 foreach ($rotateLang as $lKey) {
2604 if (!$langChildren && !$langDisabled) {
2605 $item .= '<strong>' . $this->getLanguageIcon($table, $row, 'v' . $lKey) . $lKey . ':</strong>';
2606 }
2607 // Default language, other options are "lUK" or whatever country code (independant of system!!!)
2608 $lang = 'l' . $lKey;
2609
2610 $tabParts = array();
2611 foreach ($tabsToTraverse as $sheet) {
2612 list ($dataStruct, $sheet) = t3lib_div::resolveSheetDefInDS($dataStructArray, $sheet);
2613
2614 // If sheet has displayCond
2615 if ($dataStruct['ROOT']['TCEforms']['displayCond']) {
2616 $splittedCondition = t3lib_div::trimExplode(':', $dataStruct['ROOT']['TCEforms']['displayCond']);
2617 $skipCondition = FALSE;
2618 $fakeRow = array();
2619 switch ($splittedCondition[0]) {
2620 case 'FIELD':
2621 list($sheetName, $fieldName) = t3lib_div::trimExplode('.', $splittedCondition[1]);
2622 $fieldValue = $editData['data'][$sheetName][$lang][$fieldName];
2623 $splittedCondition[1] = $fieldName;
2624 $dataStruct['ROOT']['TCEforms']['displayCond'] = join(':', $splittedCondition);
2625 $fakeRow = array($fieldName => $fieldValue);
2626 break;
2627 case 'HIDE_FOR_NON_ADMINS':
2628 case 'VERSION':
2629 case 'HIDE_L10N_SIBLINGS':
2630 case 'EXT':
2631 break;
2632 case 'REC':
2633 $fakeRow = array('uid' => $row['uid']);
2634 break;
2635 default:
2636 $skipCondition = TRUE;
2637 break;
2638 }
2639
2640 // If sheets displayCond leads to false
2641 if (!$skipCondition && !$this->isDisplayCondition($dataStruct['ROOT']['TCEforms']['displayCond'], $fakeRow, 'vDEF')) {
2642 // Don't create this sheet
2643 continue;
2644 }
2645 }
2646
2647 // Render sheet:
2648 if (is_array($dataStruct['ROOT']) && is_array($dataStruct['ROOT']['el'])) {
2649 // Default language, other options are "lUK" or whatever country code (independant of system!!!)
2650 $PA['_valLang'] = $langChildren && !$langDisabled ? $editData['meta']['currentLangId'] : 'DEF';
2651 $PA['_lang'] = $lang;
2652 // Assemble key for loading the correct CSH file
2653 $dsPointerFields = t3lib_div::trimExplode(',', $GLOBALS['TCA'][$table]['columns'][$field]['config']['ds_pointerField'], TRUE);
2654 $PA['_cshKey'] = $table . '.' . $field;
2655 foreach ($dsPointerFields as $key) {
2656 $PA['_cshKey'] .= '.' . $row[$key];
2657 }
2658
2659 // Push the sheet level tab to DynNestedStack
2660 if (is_array($dataStructArray['sheets'])) {
2661 $tabIdentString = $GLOBALS['TBE_TEMPLATE']->getDynTabMenuId('TCEFORMS:flexform:' . $PA['itemFormElName'] . $PA['_lang']);
2662 $this->pushToDynNestedStack('tab', $tabIdentString . '-' . (count($tabParts) + 1));
2663 }
2664 // Render flexform:
2665 $tRows = $this->getSingleField_typeFlex_draw(
2666 $dataStruct['ROOT']['el'],
2667 $editData['data'][$sheet][$lang],
2668 $table,
2669 $field,
2670 $row,
2671 $PA,
2672 '[data][' . $sheet . '][' . $lang . ']'
2673 );
2674 $sheetContent = '<div class="typo3-TCEforms-flexForm">' . $tRows . '</div>';
2675
2676 // Pop the sheet level tab from DynNestedStack
2677 if (is_array($dataStructArray['sheets'])) {
2678 $this->popFromDynNestedStack('tab', $tabIdentString . '-' . (count($tabParts) + 1));
2679 }
2680 } else {
2681 $sheetContent = 'Data Structure ERROR: No ROOT element found for sheet "' . $sheet . '".';
2682 }
2683
2684 // Add to tab:
2685 $tabParts[] = array