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