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