Added feature #7122: IRRE - Implement TYPO3AJAX handler for Inline Relational Record...
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_tceforms.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2006 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 var $dividers2tabs=0; // Will be set to TCA[ctrl][dividers2tabs]
234
235 /**
236 * Set to initialized clipboard object; Then the element browser will offer a link to paste in records from clipboard.
237 *
238 * @var t3lib_clipboard
239 */
240 var $clipObj=FALSE;
241 var $enableClickMenu=FALSE; // Enable click menu on reference icons.
242 var $enableTabMenu = FALSE; // Enable Tab Menus. If set to true, the JavaScript content from template::getDynTabMenuJScode() must be included in the document.
243 var $renderReadonly = FALSE; // When enabled all fields are rendered non-editable.
244
245 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)
246 var $form_largeComp = 1.33; // Form field width compensation: Compensation for large documents, doc-tab (editing)
247 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.
248 var $maxTextareaWidth=48; // The maximum abstract value for textareas
249 var $maxInputWidth=48; // The maximum abstract value for input fields
250 var $defaultMultipleSelectorStyle='width:250px;'; // Default style for the selector boxes used for multiple items in "select" and "group" types.
251
252
253 // INTERNAL, static
254 var $prependFormFieldNames = 'data'; // The string to prepend formfield names with.
255 var $prependCmdFieldNames = 'cmd'; // The string to prepend commands for tcemain::process_cmdmap with.
256 var $prependFormFieldNames_file = 'data_files'; // The string to prepend FILE form field names with.
257 var $formName = 'editform'; // The name attribute of the form.
258 var $allowOverrideMatrix = array(); // Whitelist that allows TCA field configuration to be overridden by TSconfig, @see overrideFieldConf()
259
260
261
262 // INTERNAL, dynamic
263 var $perms_clause=''; // Set by readPerms() (caching)
264 var $perms_clause_set=0; // Set by readPerms() (caching-flag)
265 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).
266 var $docLarge=0; // If set, the forms will be rendered a little wider, more precisely with a factor of $this->form_largeComp.
267 var $clientInfo=array(); // Loaded with info about the browser when class is instantiated.
268 var $RTEenabled=0; // True, if RTE is possible for the current user (based on result from BE_USER->isRTE())
269 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)
270 var $RTEcounter = 0; // Counter that is incremented before an RTE is created. Can be used for unique ids etc.
271
272 var $colorScheme; // Contains current color scheme
273 var $classScheme; // Contains current class scheme
274 var $defColorScheme; // Contains the default color scheme
275 var $defClassScheme; // Contains the default class scheme
276 var $fieldStyle; // Contains field style values
277 var $borderStyle; // Contains border style values.
278
279 var $commentMessages=array(); // An accumulation of messages from the class.
280
281 // INTERNAL, templates
282 var $totalWrap='<hr />|<hr />'; // Total wrapping for the table rows.
283 var $fieldTemplate='<b>###FIELD_NAME###</b><br />###FIELD_ITEM###<hr />'; // Field template
284 var $sectionWrap=''; // Wrapping template code for a section
285 var $palFieldTemplateHeader=''; // Template for palette headers
286 var $palFieldTemplate=''; // Template for palettes
287
288 // INTERNAL, working memory
289 var $excludeElements=''; // Set to the fields NOT to display, if any.
290 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)
291 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!
292 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.
293 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.
294 var $requiredElements=array(); // Used to register the min and max number of elements for selectorboxes where that apply (in the "group" type for instance)
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'),
359 'inline' => array('appearance', '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 // Loads the dividers2tabs from the $TCA
503 $this->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 && $this->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 && $this->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
672 $output = $this->getDynTabMenu($parts, $tabIdentString);
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='') {
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 $collapsed = $this->isPalettesCollapsed($table,$palette);
763 $out .= $this->intoTemplate(
764 array('PALETTE' => $this->wrapPaletteField($this->printPalette($parts), $table, $row ,$palette, $collapsed)),
765 $this->palFieldTemplate
766 );
767 }
768 return $out;
769 }
770
771 /**
772 * Returns the form HTML code for a database table field.
773 *
774 * @param string The table name
775 * @param string The field name
776 * @param array The record to edit from the database table.
777 * @param string Alternative field name label to show.
778 * @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).
779 * @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.
780 * @param integer The palette pointer.
781 * @return mixed String (normal) or array (palettes)
782 */
783 function getSingleField($table,$field,$row,$altName='',$palette=0,$extra='',$pal=0) {
784 global $TCA,$BE_USER;
785
786 // Hook: getSingleField_preProcess
787 foreach ($this->hookObjectsSingleField as $hookObj) {
788 if (method_exists($hookObj,'getSingleField_preProcess')) {
789 $hookObj->getSingleField_preProcess($table, $field, $row, $altName, $palette, $extra, $pal, $this);
790 }
791 }
792
793 $out = '';
794 $PA = array();
795 $PA['altName'] = $altName;
796 $PA['palette'] = $palette;
797 $PA['extra'] = $extra;
798 $PA['pal'] = $pal;
799
800 // Make sure to load full $TCA array for the table:
801 t3lib_div::loadTCA($table);
802
803 // Get the TCA configuration for the current field:
804 $PA['fieldConf'] = $TCA[$table]['columns'][$field];
805 $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
806
807 $skipThisField = $this->inline->skipField($table, $field, $row, $PA['fieldConf']['config']);
808
809 // Now, check if this field is configured and editable (according to excludefields + other configuration)
810 if ( is_array($PA['fieldConf']) &&
811 !$skipThisField &&
812 (!$PA['fieldConf']['exclude'] || $BE_USER->check('non_exclude_fields',$table.':'.$field)) &&
813 $PA['fieldConf']['config']['form_type']!='passthrough' &&
814 ($this->RTEenabled || !$PA['fieldConf']['config']['showIfRTE']) &&
815 (!$PA['fieldConf']['displayCond'] || $this->isDisplayCondition($PA['fieldConf']['displayCond'],$row)) &&
816 (!$TCA[$table]['ctrl']['languageField'] || $PA['fieldConf']['l10n_display'] || strcmp($PA['fieldConf']['l10n_mode'],'exclude') || $row[$TCA[$table]['ctrl']['languageField']]<=0) &&
817 (!$TCA[$table]['ctrl']['languageField'] || !$this->localizationMode || $this->localizationMode===$PA['fieldConf']['l10n_cat'])
818 ) {
819
820
821
822 // Fetching the TSconfig for the current table/field. This includes the $row which means that
823 $PA['fieldTSConfig'] = $this->setTSconfig($table,$row,$field);
824
825 // If the field is NOT disabled from TSconfig (which it could have been) then render it
826 if (!$PA['fieldTSConfig']['disabled']) {
827 // Override fieldConf by fieldTSconfig:
828 $PA['fieldConf']['config'] = $this->overrideFieldConf($PA['fieldConf']['config'], $PA['fieldTSConfig']);
829
830 // Init variables:
831 $PA['itemFormElName']=$this->prependFormFieldNames.'['.$table.']['.$row['uid'].']['.$field.']'; // Form field name
832 $PA['itemFormElName_file']=$this->prependFormFieldNames_file.'['.$table.']['.$row['uid'].']['.$field.']'; // Form field name, in case of file uploads
833 $PA['itemFormElValue']=$row[$field]; // The value to show in the form field.
834 $PA['itemFormElID']=$this->prependFormFieldNames.'_'.$table.'_'.$row['uid'].'_'.$field;
835
836 // set field to read-only if configured for translated records to show default language content as readonly
837 if ($PA['fieldConf']['l10n_display'] AND t3lib_div::inList($PA['fieldConf']['l10n_display'], 'defaultAsReadonly') AND $row[$TCA[$table]['ctrl']['languageField']]) {
838 $PA['fieldConf']['config']['readOnly'] = true;
839 $PA['itemFormElValue'] = $this->defaultLanguageData[$table.':'.$row['uid']][$field];
840 }
841
842 // 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"
843 if (
844 ($TCA[$table]['ctrl']['type'] && !strcmp($field,$TCA[$table]['ctrl']['type'])) ||
845 ($TCA[$table]['ctrl']['requestUpdate'] && t3lib_div::inList($TCA[$table]['ctrl']['requestUpdate'],$field))) {
846 if($GLOBALS['BE_USER']->jsConfirmation(1)) {
847 $alertMsgOnChange = 'if (confirm(TBE_EDITOR.labels.onChangeAlert) && TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
848 } else {
849 $alertMsgOnChange = 'if (TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
850 }
851 } else {
852 $alertMsgOnChange = '';
853 }
854
855 // Render as a hidden field?
856 if (in_array($field,$this->hiddenFieldListArr)) {
857 $this->hiddenFieldAccum[]='<input type="hidden" name="'.$PA['itemFormElName'].'" value="'.htmlspecialchars($PA['itemFormElValue']).'" />';
858 } else { // Render as a normal field:
859
860 // 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.
861 if (!$PA['palette']) {
862 $paletteFields = $this->loadPaletteElements($table, $row, $PA['pal']);
863 if ($PA['pal'] && $this->isPalettesCollapsed($table,$PA['pal']) && count($paletteFields)) {
864 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);
865 } else {
866 $thePalIcon = '';
867 $palJSfunc = '';
868 }
869 }
870 // onFocus attribute to add to the field:
871 $PA['onFocus'] = ($palJSfunc && !$BE_USER->uc['dontShowPalettesOnFocusInAB']) ? ' onfocus="'.htmlspecialchars($palJSfunc).'"' : '';
872
873 // Find item
874 $item='';
875 $PA['label'] = ($PA['altName'] ? $PA['altName'] : $PA['fieldConf']['label']);
876 $PA['label'] = ($PA['fieldTSConfig']['label'] ? $PA['fieldTSConfig']['label'] : $PA['label']);
877 $PA['label'] = ($PA['fieldTSConfig']['label.'][$GLOBALS['LANG']->lang] ? $PA['fieldTSConfig']['label.'][$GLOBALS['LANG']->lang] : $PA['label']);
878 $PA['label'] = $this->sL($PA['label']);
879 // JavaScript code for event handlers:
880 $PA['fieldChangeFunc']=array();
881 $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = "TBE_EDITOR.fieldChanged('".$table."','".$row['uid']."','".$field."','".$PA['itemFormElName']."');";
882 $PA['fieldChangeFunc']['alert']=$alertMsgOnChange;
883 // if this is the child of an inline type and it is the field creating the label
884 if ($this->inline->isInlineChildAndLabelField($table, $field)) {
885 $PA['fieldChangeFunc']['inline'] = "inline.handleChangedField('".$PA['itemFormElName']."','".$this->inline->inlineNames['object']."[$table][".$row['uid']."]');";
886 }
887
888 // Based on the type of the item, call a render function:
889 $item = $this->getSingleField_SW($table,$field,$row,$PA);
890
891 // Add language + diff
892 if ($PA['fieldConf']['l10n_display'] && (t3lib_div::inList($PA['fieldConf']['l10n_display'], 'hideDiff') || t3lib_div::inList($PA['fieldConf']['l10n_display'], 'defaultAsReadonly'))) {
893 $renderLanguageDiff = false;
894 } else {
895 $renderLanguageDiff = true;
896 }
897
898 if ($renderLanguageDiff) {
899 $item = $this->renderDefaultLanguageContent($table,$field,$row,$item);
900 $item = $this->renderDefaultLanguageDiff($table,$field,$row,$item);
901 }
902
903 // 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
904 $PA['label'] = t3lib_div::deHSCentities(htmlspecialchars($PA['label']));
905 if (t3lib_div::testInt($row['uid']) && $PA['fieldTSConfig']['linkTitleToSelf'] && !t3lib_div::_GP('columnsOnly')) {
906 $lTTS_url = $this->backPath.'alt_doc.php?edit['.$table.']['.$row['uid'].']=edit&columnsOnly='.$field.'&returnUrl='.rawurlencode($this->thisReturnUrl());
907 $PA['label'] = '<a href="'.htmlspecialchars($lTTS_url).'">'.$PA['label'].'</a>';
908 }
909
910 // Create output value:
911 if ($PA['fieldConf']['config']['form_type']=='user' && $PA['fieldConf']['config']['noTableWrapping']) {
912 $out = $item;
913 } elseif ($PA['palette']) {
914 // Array:
915 $out=array(
916 'NAME'=>$PA['label'],
917 'ID'=>$row['uid'],
918 'FIELD'=>$field,
919 'TABLE'=>$table,
920 'ITEM'=>$item,
921 'HELP_ICON' => $this->helpTextIcon($table,$field,1)
922 );
923 $out = $this->addUserTemplateMarkers($out,$table,$field,$row,$PA);
924 } else {
925 // String:
926 $out=array(
927 'NAME'=>$PA['label'],
928 'ITEM'=>$item,
929 'TABLE'=>$table,
930 'ID'=>$row['uid'],
931 'HELP_ICON'=>$this->helpTextIcon($table,$field),
932 'HELP_TEXT'=>$this->helpText($table,$field),
933 'PAL_LINK_ICON'=>$thePalIcon,
934 'FIELD'=>$field
935 );
936 $out = $this->addUserTemplateMarkers($out,$table,$field,$row,$PA);
937 // String:
938 $out=$this->intoTemplate($out);
939 }
940 }
941 } else $this->commentMessages[]=$this->prependFormFieldNames.'['.$table.']['.$row['uid'].']['.$field.']: Disabled by TSconfig';
942 }
943 // Hook: getSingleField_postProcess
944 foreach ($this->hookObjectsSingleField as $hookObj) {
945 if (method_exists($hookObj,'getSingleField_postProcess')) {
946 $hookObj->getSingleField_postProcess($table, $field, $row, $out, $PA, $this);
947 }
948 }
949 // Return value (string or array)
950 return $out;
951 }
952
953 /**
954 * Rendering a single item for the form
955 *
956 * @param string Table name of record
957 * @param string Fieldname to render
958 * @param array The record
959 * @param array parameters array containing a lot of stuff. Value by Reference!
960 * @return string Returns the item as HTML code to insert
961 * @access private
962 * @see getSingleField(), getSingleField_typeFlex_draw()
963 */
964 function getSingleField_SW($table,$field,$row,&$PA) {
965 $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
966
967 switch($PA['fieldConf']['config']['form_type']) {
968 case 'input':
969 $item = $this->getSingleField_typeInput($table,$field,$row,$PA);
970 break;
971 case 'text':
972 $item = $this->getSingleField_typeText($table,$field,$row,$PA);
973 break;
974 case 'check':
975 $item = $this->getSingleField_typeCheck($table,$field,$row,$PA);
976 break;
977 case 'radio':
978 $item = $this->getSingleField_typeRadio($table,$field,$row,$PA);
979 break;
980 case 'select':
981 $item = $this->getSingleField_typeSelect($table,$field,$row,$PA);
982 break;
983 case 'group':
984 $item = $this->getSingleField_typeGroup($table,$field,$row,$PA);
985 break;
986 case 'inline':
987 $item = $this->inline->getSingleField_typeInline($table,$field,$row,$PA);
988 break;
989 case 'none':
990 $item = $this->getSingleField_typeNone($table,$field,$row,$PA);
991 break;
992 case 'user':
993 $item = $this->getSingleField_typeUser($table,$field,$row,$PA);
994 break;
995 case 'flex':
996 $item = $this->getSingleField_typeFlex($table,$field,$row,$PA);
997 break;
998 default:
999 $item = $this->getSingleField_typeUnknown($table,$field,$row,$PA);
1000 break;
1001 }
1002
1003 return $item;
1004 }
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024 /**********************************************************
1025 *
1026 * Rendering of each TCEform field type
1027 *
1028 ************************************************************/
1029
1030 /**
1031 * Generation of TCEform elements of the type "input"
1032 * This will render a single-line input form field, possibly with various control/validation features
1033 *
1034 * @param string The table name of the record
1035 * @param string The field name which this element is supposed to edit
1036 * @param array The record data array where the value(s) for the field can be found
1037 * @param array An array with additional configuration options.
1038 * @return string The HTML code for the TCEform field
1039 */
1040 function getSingleField_typeInput($table,$field,$row,&$PA) {
1041 // typo3FormFieldSet(theField, evallist, is_in, checkbox, checkboxValue)
1042 // typo3FormFieldGet(theField, evallist, is_in, checkbox, checkboxValue, checkbox_off)
1043
1044 $config = $PA['fieldConf']['config'];
1045
1046 # $specConf = $this->getSpecConfForField($table,$row,$field);
1047 $specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);
1048 $size = t3lib_div::intInRange($config['size']?$config['size']:30,5,$this->maxInputWidth);
1049 $evalList = t3lib_div::trimExplode(',',$config['eval'],1);
1050
1051 if($this->renderReadonly || $config['readOnly']) {
1052 $itemFormElValue = $PA['itemFormElValue'];
1053 if (in_array('date',$evalList)) {
1054 $config['format'] = 'date';
1055 } elseif (in_array('date',$evalList)) {
1056 $config['format'] = 'date';
1057 } elseif (in_array('datetime',$evalList)) {
1058 $config['format'] = 'datetime';
1059 } elseif (in_array('time',$evalList)) {
1060 $config['format'] = 'time';
1061 }
1062 if (in_array('password',$evalList)) {
1063 $itemFormElValue = $itemFormElValue ? '*********' : '';
1064 }
1065 return $this->getSingleField_typeNone_render($config, $itemFormElValue);
1066 }
1067
1068 foreach ($evalList as $func) {
1069 switch ($func) {
1070 case 'required':
1071 $this->requiredFields[$table.'_'.$row['uid'].'_'.$field]=$PA['itemFormElName'];
1072 // Mark this field for date/time disposal:
1073 if (array_intersect($evalList, array('date', 'datetime', 'time'))) {
1074 $this->requiredAdditional[$PA['itemFormElName']]['isPositiveNumber'] = true;
1075 }
1076 break;
1077 default:
1078 if (substr($func, 0, 3) == 'tx_') {
1079 // Pair hook to the one in t3lib_TCEmain::checkValue_input_Eval()
1080 $evalObj = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func].':&'.$func);
1081 if (is_object($evalObj) && method_exists($evalObj, 'deevaluateFieldValue')) {
1082 $_params = array(
1083 'value' => $PA['itemFormElValue']
1084 );
1085 $PA['itemFormElValue'] = $evalObj->deevaluateFieldValue($_params);
1086 }
1087 }
1088 break;
1089 }
1090 }
1091
1092 $paramsList = "'".$PA['itemFormElName']."','".implode(',',$evalList)."','".trim($config['is_in'])."',".(isset($config['checkbox'])?1:0).",'".$config['checkbox']."'";
1093 if (isset($config['checkbox'])) {
1094 // Setting default "click-checkbox" values for eval types "date" and "datetime":
1095 $thisMidnight = gmmktime(0,0,0);
1096 if (in_array('date',$evalList)) {
1097 $checkSetValue = $thisMidnight;
1098 } elseif (in_array('datetime',$evalList)) {
1099 $checkSetValue = time();
1100 } elseif (in_array('year',$evalList)) {
1101 $checkSetValue = gmdate('Y');
1102 }
1103 $cOnClick = 'typo3form.fieldGet('.$paramsList.',1,\''.$checkSetValue.'\');'.implode('',$PA['fieldChangeFunc']);
1104 $item.='<input type="checkbox"'.$this->insertDefStyle('check').' name="'.$PA['itemFormElName'].'_cb" onclick="'.htmlspecialchars($cOnClick).'" />';
1105 }
1106 if((in_array('date',$evalList) || in_array('datetime',$evalList)) && $PA['itemFormElValue']>0){
1107 // Add server timezone offset to UTC to our stored date
1108 $hoursOffset = date('O',$PA['itemFormElValue'])/100;
1109 $PA['itemFormElValue'] += ($hoursOffset*60*60);
1110 }
1111
1112 $PA['fieldChangeFunc'] = array_merge(array('typo3form.fieldGet'=>'typo3form.fieldGet('.$paramsList.');'), $PA['fieldChangeFunc']);
1113 $mLgd = ($config['max']?$config['max']:256);
1114 $iOnChange = implode('',$PA['fieldChangeFunc']);
1115 $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.
1116 $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.
1117 $this->extJSCODE.='typo3form.fieldSet('.$paramsList.');';
1118
1119 // going through all custom evaluations configured for this field
1120 foreach ($evalList as $evalData) {
1121 if (substr($evalData, 0, 3) == 'tx_') {
1122 $evalObj = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$evalData].':&'.$evalData);
1123 if(is_object($evalObj) && method_exists($evalObj, 'returnFieldJS')) {
1124 $this->extJSCODE .= "\n\nfunction ".$evalData."(value) {\n".$evalObj->returnFieldJS()."\n}\n";
1125 }
1126 }
1127 }
1128
1129 // Creating an alternative item without the JavaScript handlers.
1130 $altItem = '<input type="hidden" name="'.$PA['itemFormElName'].'_hr" value="" />';
1131 $altItem.= '<input type="hidden" name="'.$PA['itemFormElName'].'" value="'.htmlspecialchars($PA['itemFormElValue']).'" />';
1132
1133 // Wrap a wizard around the item?
1134 $item= $this->renderWizards(array($item,$altItem),$config['wizards'],$table,$row,$field,$PA,$PA['itemFormElName'].'_hr',$specConf);
1135
1136 return $item;
1137 }
1138
1139 /**
1140 * Generation of TCEform elements of the type "text"
1141 * This will render a <textarea> OR RTE area form field, possibly with various control/validation features
1142 *
1143 * @param string The table name of the record
1144 * @param string The field name which this element is supposed to edit
1145 * @param array The record data array where the value(s) for the field can be found
1146 * @param array An array with additional configuration options.
1147 * @return string The HTML code for the TCEform field
1148 */
1149 function getSingleField_typeText($table,$field,$row,&$PA) {
1150
1151 // Init config:
1152 $config = $PA['fieldConf']['config'];
1153
1154 if($this->renderReadonly || $config['readOnly']) {
1155 return $this->getSingleField_typeNone_render($config, $PA['itemFormElValue']);
1156 }
1157
1158 // Setting columns number:
1159 $cols = t3lib_div::intInRange($config['cols'] ? $config['cols'] : 30, 5, $this->maxTextareaWidth);
1160
1161 // Setting number of rows:
1162 $origRows = $rows = t3lib_div::intInRange($config['rows'] ? $config['rows'] : 5, 1, 20);
1163 if (strlen($PA['itemFormElValue']) > $this->charsPerRow*2) {
1164 $cols = $this->maxTextareaWidth;
1165 $rows = t3lib_div::intInRange(round(strlen($PA['itemFormElValue'])/$this->charsPerRow), count(explode(chr(10),$PA['itemFormElValue'])), 20);
1166 if ($rows<$origRows) $rows = $origRows;
1167 }
1168
1169 // Init RTE vars:
1170 $RTEwasLoaded = 0; // Set true, if the RTE is loaded; If not a normal textarea is shown.
1171 $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...
1172
1173 // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist. Traditionally, this is where RTE configuration has been found.
1174 $specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);
1175
1176 // Setting up the altItem form field, which is a hidden field containing the value
1177 $altItem = '<input type="hidden" name="'.htmlspecialchars($PA['itemFormElName']).'" value="'.htmlspecialchars($PA['itemFormElValue']).'" />';
1178
1179 // If RTE is generally enabled (TYPO3_CONF_VARS and user settings)
1180 if ($this->RTEenabled) {
1181 $p = t3lib_BEfunc::getSpecConfParametersFromArray($specConf['rte_transform']['parameters']);
1182 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.
1183 t3lib_BEfunc::fixVersioningPid($table,$row);
1184 list($tscPID,$thePidValue) = $this->getTSCpid($table,$row['uid'],$row['pid']);
1185
1186 // If the pid-value is not negative (that is, a pid could NOT be fetched)
1187 if ($thePidValue >= 0) {
1188 $RTEsetup = $GLOBALS['BE_USER']->getTSConfig('RTE',t3lib_BEfunc::getPagesTSconfig($tscPID));
1189 $RTEtypeVal = t3lib_BEfunc::getTCAtypeValue($table,$row);
1190 $thisConfig = t3lib_BEfunc::RTEsetup($RTEsetup['properties'],$table,$field,$RTEtypeVal);
1191
1192 if (!$thisConfig['disabled']) {
1193 if (!$this->disableRTE) {
1194 $this->RTEcounter++;
1195
1196 // Find alternative relative path for RTE images/links:
1197 $eFile = t3lib_parsehtml_proc::evalWriteFile($specConf['static_write'], $row);
1198 $RTErelPath = is_array($eFile) ? dirname($eFile['relEditFile']) : '';
1199
1200 // Get RTE object, draw form and set flag:
1201 $RTEobj = &t3lib_BEfunc::RTEgetObj();
1202 $item = $RTEobj->drawRTE($this,$table,$field,$row,$PA,$specConf,$thisConfig,$RTEtypeVal,$RTErelPath,$thePidValue);
1203
1204 // Wizard:
1205 $item = $this->renderWizards(array($item,$altItem),$config['wizards'],$table,$row,$field,$PA,$PA['itemFormElName'],$specConf,1);
1206
1207 $RTEwasLoaded = 1;
1208 } else {
1209 $RTEwouldHaveBeenLoaded = 1;
1210 $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!)';
1211 }
1212 } else $this->commentMessages[] = $PA['itemFormElName'].': RTE is disabled by the Page TSconfig, "RTE"-key (eg. by RTE.default.disabled=0 or such)';
1213 } else $this->commentMessages[] = $PA['itemFormElName'].': PID value could NOT be fetched. Rare error, normally with new records.';
1214 } else {
1215 if (!isset($specConf['richtext'])) $this->commentMessages[] = $PA['itemFormElName'].': RTE was not configured for this field in TCA-types';
1216 if (!(!$p['flag'] || !$row[$p['flag']])) $this->commentMessages[] = $PA['itemFormElName'].': Field-flag ('.$PA['flag'].') has been set to disable RTE!';
1217 }
1218 }
1219
1220 // Display ordinary field if RTE was not loaded.
1221 if (!$RTEwasLoaded) {
1222 if ($specConf['rte_only']) { // Show message, if no RTE (field can only be edited with RTE!)
1223 $item = '<p><em>'.htmlspecialchars($this->getLL('l_noRTEfound')).'</em></p>';
1224 } else {
1225 if ($specConf['nowrap']) {
1226 $wrap = 'off';
1227 } else {
1228 $wrap = ($config['wrap'] ? $config['wrap'] : 'virtual');
1229 }
1230
1231 $classes = array();
1232 if ($specConf['fixed-font']) { $classes[] = 'fixed-font'; }
1233 if ($specConf['enable-tab']) { $classes[] = 'enable-tab'; }
1234
1235 $formWidthText = $this->formWidthText($cols,$wrap);
1236
1237 // Extract class attributes from $formWidthText (otherwise it would be added twice to the output)
1238 $res = array();
1239 if (preg_match('/ class="(.+?)"/',$formWidthText,$res)) {
1240 $formWidthText = str_replace(' class="'.$res[1].'"','',$formWidthText);
1241 $classes = array_merge($classes, explode(' ',$res[1]));
1242 }
1243
1244 if (count($classes)) {
1245 $class = ' class="'.implode(' ',$classes).'"';
1246 } else $class='';
1247
1248 $iOnChange = implode('',$PA['fieldChangeFunc']);
1249 $item.= '
1250 <textarea name="'.$PA['itemFormElName'].'"'.$formWidthText.$class.' rows="'.$rows.'" wrap="'.$wrap.'" onchange="'.htmlspecialchars($iOnChange).'"'.$PA['onFocus'].'>'.
1251 t3lib_div::formatForTextarea($PA['itemFormElValue']).
1252 '</textarea>';
1253 $item = $this->renderWizards(array($item,$altItem),$config['wizards'],$table,$row,$field,$PA,$PA['itemFormElName'],$specConf,$RTEwouldHaveBeenLoaded);
1254 }
1255 }
1256
1257 // Return field HTML:
1258 return $item;
1259 }
1260
1261 /**
1262 * Generation of TCEform elements of the type "check"
1263 * This will render a check-box OR an array of checkboxes
1264 *
1265 * @param string The table name of the record
1266 * @param string The field name which this element is supposed to edit
1267 * @param array The record data array where the value(s) for the field can be found
1268 * @param array An array with additional configuration options.
1269 * @return string The HTML code for the TCEform field
1270 */
1271 function getSingleField_typeCheck($table,$field,$row,&$PA) {
1272 $config = $PA['fieldConf']['config'];
1273
1274 $disabled = '';
1275 if($this->renderReadonly || $config['readOnly']) {
1276 $disabled = ' disabled="disabled"';
1277 }
1278
1279 // Traversing the array of items:
1280 $selItems = $this->initItemArray($PA['fieldConf']);
1281 if ($config['itemsProcFunc']) $selItems = $this->procItems($selItems,$PA['fieldTSConfig']['itemsProcFunc.'],$config,$table,$row,$field);
1282
1283 if (!count($selItems)) {
1284 $selItems[]=array('','');
1285 }
1286 $thisValue = intval($PA['itemFormElValue']);
1287
1288 $cols = intval($config['cols']);
1289 if ($cols > 1) {
1290 $item.= '<table border="0" cellspacing="0" cellpadding="0" class="typo3-TCEforms-checkboxArray">';
1291 for ($c=0;$c<count($selItems);$c++) {
1292 $p = $selItems[$c];
1293 if(!($c%$cols)) { $item.='<tr>'; }
1294 $cBP = $this->checkBoxParams($PA['itemFormElName'],$thisValue,$c,count($selItems),implode('',$PA['fieldChangeFunc']));
1295 $cBName = $PA['itemFormElName'].'_'.$c;
1296 $cBID = $PA['itemFormElID'].'_'.$c;
1297 $item.= '<td nowrap="nowrap">'.
1298 '<input type="checkbox"'.$this->insertDefStyle('check').' value="1" name="'.$cBName.'"'.$cBP.$disabled.' id="'.$cBID.'" />'.
1299 $this->wrapLabels('<label for="'.$cBID.'">'.htmlspecialchars($p[0]).'</label>&nbsp;').
1300 '</td>';
1301 if(($c%$cols)+1==$cols) {$item.='</tr>';}
1302 }
1303 if ($c%$cols) {
1304 $rest=$cols-($c%$cols);
1305 for ($c=0;$c<$rest;$c++) {
1306 $item.= '<td></td>';
1307 }
1308 if ($c>0) { $item.= '</tr>'; }
1309 }
1310 $item.= '</table>';
1311 } else {
1312 for ($c=0;$c<count($selItems);$c++) {
1313 $p = $selItems[$c];
1314 $cBP = $this->checkBoxParams($PA['itemFormElName'],$thisValue,$c,count($selItems),implode('',$PA['fieldChangeFunc']));
1315 $cBName = $PA['itemFormElName'].'_'.$c;
1316 $cBID = $PA['itemFormElID'].'_'.$c;
1317 $item.= ($c>0?'<br />':'').
1318 '<input type="checkbox"'.$this->insertDefStyle('check').' value="1" name="'.$cBName.'"'.$cBP.$PA['onFocus'].$disabled.' id="'.$cBID.'" />'.
1319 htmlspecialchars($p[0]);
1320 }
1321 }
1322 if (!$disabled) {
1323 $item.= '<input type="hidden" name="'.$PA['itemFormElName'].'" value="'.htmlspecialchars($thisValue).'" />';
1324 }
1325
1326 return $item;
1327 }
1328
1329 /**
1330 * Generation of TCEform elements of the type "radio"
1331 * This will render a series of radio buttons.
1332 *
1333 * @param string The table name of the record
1334 * @param string The field name which this element is supposed to edit
1335 * @param array The record data array where the value(s) for the field can be found
1336 * @param array An array with additional configuration options.
1337 * @return string The HTML code for the TCEform field
1338 */
1339 function getSingleField_typeRadio($table,$field,$row,&$PA) {
1340 $config = $PA['fieldConf']['config'];
1341
1342 $disabled = '';
1343 if($this->renderReadonly || $config['readOnly']) {
1344 $disabled = ' disabled="disabled"';
1345 }
1346
1347 // Get items for the array:
1348 $selItems = $this->initItemArray($PA['fieldConf']);
1349 if ($config['itemsProcFunc']) $selItems = $this->procItems($selItems,$PA['fieldTSConfig']['itemsProcFunc.'],$config,$table,$row,$field);
1350
1351 // Traverse the items, making the form elements:
1352 for ($c=0;$c<count($selItems);$c++) {
1353 $p = $selItems[$c];
1354 $rID = $PA['itemFormElID'].'_'.$c;
1355 $rOnClick = implode('',$PA['fieldChangeFunc']);
1356 $rChecked = (!strcmp($p[1],$PA['itemFormElValue'])?' checked="checked"':'');
1357 $item.= '<input type="radio"'.$this->insertDefStyle('radio').' name="'.$PA['itemFormElName'].'" value="'.htmlspecialchars($p[1]).'" onclick="'.htmlspecialchars($rOnClick).'"'.$rChecked.$PA['onFocus'].$disabled.' id="'.$rID.'" />
1358 <label for="'.$rID.'">'.htmlspecialchars($p[0]).'</label>
1359 <br />';
1360 }
1361
1362 return $item;
1363 }
1364
1365 /**
1366 * Generation of TCEform elements of the type "select"
1367 * This will render a selector box element, or possibly a special construction with two selector boxes. That depends on configuration.
1368 *
1369 * @param string The table name of the record
1370 * @param string The field name which this element is supposed to edit
1371 * @param array The record data array where the value(s) for the field can be found
1372 * @param array An array with additional configuration options.
1373 * @return string The HTML code for the TCEform field
1374 */
1375 function getSingleField_typeSelect($table,$field,$row,&$PA) {
1376 global $TCA;
1377
1378 // Field configuration from TCA:
1379 $config = $PA['fieldConf']['config'];
1380
1381 $disabled = '';
1382 if($this->renderReadonly || $config['readOnly']) {
1383 $disabled = ' disabled="disabled"';
1384 }
1385
1386 // "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/.
1387 $specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);
1388
1389 // Getting the selector box items from the system
1390 $selItems = $this->addSelectOptionsToItemArray($this->initItemArray($PA['fieldConf']),$PA['fieldConf'],$this->setTSconfig($table,$row),$field);
1391 $selItems = $this->addItems($selItems,$PA['fieldTSConfig']['addItems.']);
1392 if ($config['itemsProcFunc']) $selItems = $this->procItems($selItems,$PA['fieldTSConfig']['itemsProcFunc.'],$config,$table,$row,$field);
1393
1394 // Possibly remove some items:
1395 $removeItems = t3lib_div::trimExplode(',',$PA['fieldTSConfig']['removeItems'],1);
1396 foreach($selItems as $tk => $p) {
1397
1398 // Checking languages and authMode:
1399 $languageDeny = $TCA[$table]['ctrl']['languageField'] && !strcmp($TCA[$table]['ctrl']['languageField'], $field) && !$GLOBALS['BE_USER']->checkLanguageAccess($p[1]);
1400 $authModeDeny = $config['form_type']=='select' && $config['authMode'] && !$GLOBALS['BE_USER']->checkAuthMode($table,$field,$p[1],$config['authMode']);
1401 if (in_array($p[1],$removeItems) || $languageDeny || $authModeDeny) {
1402 unset($selItems[$tk]);
1403 } elseif (isset($PA['fieldTSConfig']['altLabels.'][$p[1]])) {
1404 $selItems[$tk][0]=$this->sL($PA['fieldTSConfig']['altLabels.'][$p[1]]);
1405 }
1406
1407 // Removing doktypes with no access:
1408 if ($table.'.'.$field == 'pages.doktype') {
1409 if (!($GLOBALS['BE_USER']->isAdmin() || t3lib_div::inList($GLOBALS['BE_USER']->groupData['pagetypes_select'],$p[1]))) {
1410 unset($selItems[$tk]);
1411 }
1412 }
1413 }
1414
1415 // Creating the label for the "No Matching Value" entry.
1416 $nMV_label = isset($PA['fieldTSConfig']['noMatchingValue_label']) ? $this->sL($PA['fieldTSConfig']['noMatchingValue_label']) : '[ '.$this->getLL('l_noMatchingValue').' ]';
1417
1418 // Prepare some values:
1419 $maxitems = intval($config['maxitems']);
1420
1421 // If a SINGLE selector box...
1422 if ($maxitems<=1) {
1423 $item = $this->getSingleField_typeSelect_single($table,$field,$row,$PA,$config,$selItems,$nMV_label);
1424 } elseif (!strcmp($config['renderMode'],'checkbox')) { // Checkbox renderMode
1425 $item = $this->getSingleField_typeSelect_checkbox($table,$field,$row,$PA,$config,$selItems,$nMV_label);
1426 } elseif (!strcmp($config['renderMode'],'singlebox')) { // Single selector box renderMode
1427 $item = $this->getSingleField_typeSelect_singlebox($table,$field,$row,$PA,$config,$selItems,$nMV_label);
1428 } else { // Traditional multiple selector box:
1429 $item = $this->getSingleField_typeSelect_multiple($table,$field,$row,$PA,$config,$selItems,$nMV_label);
1430 }
1431
1432 // Wizards:
1433 if (!$disabled) {
1434 $altItem = '<input type="hidden" name="'.$PA['itemFormElName'].'" value="'.htmlspecialchars($PA['itemFormElValue']).'" />';
1435 $item = $this->renderWizards(array($item,$altItem),$config['wizards'],$table,$row,$field,$PA,$PA['itemFormElName'],$specConf);
1436 }
1437
1438 return $item;
1439 }
1440
1441 /**
1442 * Creates a single-selector box
1443 * (Render function for getSingleField_typeSelect())
1444 *
1445 * @param string See getSingleField_typeSelect()
1446 * @param string See getSingleField_typeSelect()
1447 * @param array See getSingleField_typeSelect()
1448 * @param array See getSingleField_typeSelect()
1449 * @param array (Redundant) content of $PA['fieldConf']['config'] (for convenience)
1450 * @param array Items available for selection
1451 * @param string Label for no-matching-value
1452 * @return string The HTML code for the item
1453 * @see getSingleField_typeSelect()
1454 */
1455 function getSingleField_typeSelect_single($table,$field,$row,&$PA,$config,$selItems,$nMV_label) {
1456 // check against inline uniqueness
1457 $inlineParent = $this->inline->getStructureLevel(-1);
1458 if(is_array($inlineParent) && $inlineParent['uid']) {
1459 if ($inlineParent['config']['foreign_table'] == $table && $inlineParent['config']['foreign_unique'] == $field) {
1460 $uniqueIds = $this->inline->inlineData['unique'][$this->inline->inlineNames['object'].'['.$table.']']['used'];
1461 $PA['fieldChangeFunc']['inlineUnique'] = "inline.updateUnique(this,'".$this->inline->inlineNames['object'].'['.$table."]','".$this->inline->inlineNames['form']."','".$row['uid']."');";
1462 }
1463 // hide uid of parent record for symmetric relations
1464 if ($inlineParent['config']['foreign_table'] == $table && ($inlineParent['config']['foreign_field'] == $field || $inlineParent['config']['symmetric_field'] == $field)) {
1465 $uniqueIds[] = $inlineParent['uid'];
1466 }
1467 }
1468
1469 // Initialization:
1470 $c = 0;
1471 $sI = 0;
1472 $noMatchingValue = 1;
1473 $opt = array();
1474 $selicons = array();
1475 $onlySelectedIconShown = 0;
1476 $size = intval($config['size']);
1477
1478 $disabled = '';
1479 if($this->renderReadonly || $config['readOnly']) {
1480 $disabled = ' disabled="disabled"';
1481 $onlySelectedIconShown = 1;
1482 }
1483
1484 // Icon configuration:
1485 if ($config['suppress_icons']=='IF_VALUE_FALSE') {
1486 $suppressIcons = !$PA['itemFormElValue'] ? 1 : 0;
1487 } elseif ($config['suppress_icons']=='ONLY_SELECTED') {
1488 $suppressIcons=0;
1489 $onlySelectedIconShown=1;
1490 } elseif ($config['suppress_icons']) {
1491 $suppressIcons = 1;
1492 } else $suppressIcons = 0;
1493
1494 // Traverse the Array of selector box items:
1495 foreach($selItems as $p) {
1496 $sM = (!strcmp($PA['itemFormElValue'],$p[1])?' selected="selected"':'');
1497 if ($sM) {
1498 $sI = $c;
1499 $noMatchingValue = 0;
1500 }
1501
1502 // Getting style attribute value (for icons):
1503 if ($config['iconsInOptionTags']) {
1504 $styleAttrValue = $this->optionTagStyle($p[2]);
1505 }
1506
1507 // Compiling the <option> tag:
1508 if (!($p[1] != $PA['itemFormElValue'] && is_array($uniqueIds) && in_array($p[1], $uniqueIds))) {
1509 if(!strcmp($p[1],'--div--')) {
1510 if($optGroupOpen) { // Closing last optgroup before next one starts
1511 $opt[]='</optgroup>';
1512 }
1513 $opt[]= '<optgroup label="'.t3lib_div::deHSCentities(htmlspecialchars($p[0])).'"'.
1514 ($styleAttrValue ? ' style="'.htmlspecialchars($styleAttrValue).'"' : '').
1515 ' class="c-divider">';
1516 $optGroupOpen = true;
1517 } else {
1518 $opt[]= '<option value="'.htmlspecialchars($p[1]).'"'.
1519 $sM.
1520 ($styleAttrValue ? ' style="'.htmlspecialchars($styleAttrValue).'"' : '').
1521 '>'.t3lib_div::deHSCentities(htmlspecialchars($p[0])).'</option>';
1522 }
1523 }
1524
1525 // If there is an icon for the selector box (rendered in table under)...:
1526 if ($p[2] && !$suppressIcons && (!$onlySelectedIconShown || $sM)) {
1527 list($selIconFile,$selIconInfo)=$this->getIcon($p[2]);
1528 $iOnClick = $this->elName($PA['itemFormElName']).'.selectedIndex='.$c.'; '.implode('',$PA['fieldChangeFunc']).$this->blur().'return false;';
1529 $selicons[]=array(
1530 (!$onlySelectedIconShown ? '<a href="#" onclick="'.htmlspecialchars($iOnClick).'">' : '').
1531 '<img src="'.$selIconFile.'" '.$selIconInfo[3].' vspace="2" border="0" title="'.htmlspecialchars($p[0]).'" alt="'.htmlspecialchars($p[0]).'" />'.
1532 (!$onlySelectedIconShown ? '</a>' : ''),
1533 $c,$sM);
1534 }
1535 $c++;
1536 }
1537
1538 if($optGroupOpen) { // Closing optgroup if open
1539 $opt[]='</optgroup>';
1540 $optGroupOpen = false;
1541 }
1542
1543 // No-matching-value:
1544 if ($PA['itemFormElValue'] && $noMatchingValue && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
1545 $nMV_label = @sprintf($nMV_label, $PA['itemFormElValue']);
1546 $opt[]= '<option value="'.htmlspecialchars($PA['itemFormElValue']).'" selected="selected">'.htmlspecialchars($nMV_label).'</option>';
1547 }
1548
1549 // Create item form fields:
1550 $sOnChange = 'if (this.options[this.selectedIndex].value==\'--div--\') {this.selectedIndex='.$sI.';} '.implode('',$PA['fieldChangeFunc']);
1551 if(!$disabled) {
1552 $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...
1553 }
1554 $item.= '<select name="'.$PA['itemFormElName'].'"'.
1555 $this->insertDefStyle('select').
1556 ($size?' size="'.$size.'"':'').
1557 ' onchange="'.htmlspecialchars($sOnChange).'"'.
1558 $PA['onFocus'].$disabled.'>';
1559 $item.= implode('',$opt);
1560 $item.= '</select>';
1561
1562 // Create icon table:
1563 if (count($selicons) && !$config['noIconsBelowSelect']) {
1564 $item.='<table border="0" cellpadding="0" cellspacing="0" class="typo3-TCEforms-selectIcons">';
1565 $selicon_cols = intval($config['selicon_cols']);
1566 if (!$selicon_cols) $selicon_cols=count($selicons);
1567 $sR = ceil(count($selicons)/$selicon_cols);
1568 $selicons = array_pad($selicons,$sR*$selicon_cols,'');
1569 for($sa=0;$sa<$sR;$sa++) {
1570 $item.='<tr>';
1571 for($sb=0;$sb<$selicon_cols;$sb++) {
1572 $sk=($sa*$selicon_cols+$sb);
1573 $imgN = 'selIcon_'.$table.'_'.$row['uid'].'_'.$field.'_'.$selicons[$sk][1];
1574 $imgS = ($selicons[$sk][2]?$this->backPath.'gfx/content_selected.gif':'clear.gif');
1575 $item.='<td><img name="'.htmlspecialchars($imgN).'" src="'.$imgS.'" width="7" height="10" alt="" /></td>';
1576 $item.='<td>'.$selicons[$sk][0].'</td>';
1577 }
1578 $item.='</tr>';
1579 }
1580 $item.='</table>';
1581 }
1582
1583 return $item;
1584 }
1585
1586 /**
1587 * Creates a checkbox list (renderMode = "checkbox")
1588 * (Render function for getSingleField_typeSelect())
1589 *
1590 * @param string See getSingleField_typeSelect()
1591 * @param string See getSingleField_typeSelect()
1592 * @param array See getSingleField_typeSelect()
1593 * @param array See getSingleField_typeSelect()
1594 * @param array (Redundant) content of $PA['fieldConf']['config'] (for convenience)
1595 * @param array Items available for selection
1596 * @param string Label for no-matching-value
1597 * @return string The HTML code for the item
1598 * @see getSingleField_typeSelect()
1599 */
1600 function getSingleField_typeSelect_checkbox($table,$field,$row,&$PA,$config,$selItems,$nMV_label) {
1601
1602 // Get values in an array (and make unique, which is fine because there can be no duplicates anyway):
1603 $itemArray = array_flip($this->extractValuesOnlyFromValueLabelList($PA['itemFormElValue']));
1604
1605 $disabled = '';
1606 if($this->renderReadonly || $config['readOnly']) {
1607 $disabled = ' disabled="disabled"';
1608 }
1609
1610 // Traverse the Array of selector box items:
1611 $tRows = array();
1612 $c=0;
1613 if (!$disabled) {
1614 $sOnChange = implode('',$PA['fieldChangeFunc']);
1615 $setAll = array(); // Used to accumulate the JS needed to restore the original selection.
1616 foreach($selItems as $p) {
1617 // Non-selectable element:
1618 if (!strcmp($p[1],'--div--')) {
1619 if (count($setAll)) {
1620 $tRows[] = '
1621 <tr>
1622 <td colspan="2">'.
1623 '<a href="#" onclick="'.htmlspecialchars(implode('',$setAll).' return false;').'">'.
1624 htmlspecialchars($this->getLL('l_setAllCheckboxes')).
1625 '</a></td>
1626 </tr>';
1627 $setAll = array();
1628 }
1629
1630 $tRows[] = '
1631 <tr class="c-header">
1632 <td colspan="2">'.htmlspecialchars($p[0]).'</td>
1633 </tr>';
1634 } else {
1635 // Selected or not by default:
1636 $sM = '';
1637 if (isset($itemArray[$p[1]])) {
1638 $sM = ' checked="checked"';
1639 unset($itemArray[$p[1]]);
1640 }
1641
1642 // Icon:
1643 $selIconFile = '';
1644 if ($p[2]) {
1645 list($selIconFile,$selIconInfo) = $this->getIcon($p[2]);
1646 }
1647
1648 // Compile row:
1649 $onClickCell = $this->elName($PA['itemFormElName'].'['.$c.']').'.checked=!'.$this->elName($PA['itemFormElName'].'['.$c.']').'.checked;';
1650 $onClick = 'this.attributes.getNamedItem("class").nodeValue = '.$this->elName($PA['itemFormElName'].'['.$c.']').'.checked ? "c-selectedItem" : "";';
1651 $setAll[] = $this->elName($PA['itemFormElName'].'['.$c.']').'.checked=1;';
1652 $tRows[] = '
1653 <tr class="'.($sM ? 'c-selectedItem' : '').'" onclick="'.htmlspecialchars($onClick).'" style="cursor: pointer;">
1654 <td><input type="checkbox"'.$this->insertDefStyle('check').' name="'.htmlspecialchars($PA['itemFormElName'].'['.$c.']').'" value="'.htmlspecialchars($p[1]).'"'.$sM.' onclick="'.htmlspecialchars($sOnChange).'"'.$PA['onFocus'].' /></td>
1655 <td class="c-labelCell" onclick="'.htmlspecialchars($onClickCell).'">'.
1656 ($selIconFile ? '<img src="'.$selIconFile.'" '.$selIconInfo[3].' vspace="2" border="0" class="absmiddle" style="margin-right: 4px;" alt="" />' : '').
1657 t3lib_div::deHSCentities(htmlspecialchars($p[0])).
1658 (strcmp($p[3],'') ? '<br/><p class="c-descr">'.nl2br(trim(htmlspecialchars($p[3]))).'</p>' : '').
1659 '</td>
1660 </tr>';
1661 $c++;
1662 }
1663 }
1664
1665 // Remaining checkboxes will get their set-all link:
1666 if (count($setAll)) {
1667 $tRows[] = '
1668 <tr>
1669 <td colspan="2">'.
1670 '<a href="#" onclick="'.htmlspecialchars(implode('',$setAll).' return false;').'">'.
1671 htmlspecialchars($this->getLL('l_setAllCheckboxes')).
1672 '</a></td>
1673 </tr>';
1674 }
1675 }
1676
1677 // Remaining values (invalid):
1678 if (count($itemArray) && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
1679 foreach($itemArray as $theNoMatchValue => $temp) {
1680 // Compile <checkboxes> tag:
1681 array_unshift($tRows,'
1682 <tr class="c-invalidItem">
1683 <td><input type="checkbox"'.$this->insertDefStyle('check').' name="'.htmlspecialchars($PA['itemFormElName'].'['.$c.']').'" value="'.htmlspecialchars($theNoMatchValue).'" checked="checked" onclick="'.htmlspecialchars($sOnChange).'"'.$PA['onFocus'].$disabled.' /></td>
1684 <td class="c-labelCell">'.
1685 t3lib_div::deHSCentities(htmlspecialchars(@sprintf($nMV_label, $theNoMatchValue))).
1686 '</td>
1687 </tr>');
1688 $c++;
1689 }
1690 }
1691
1692 // Add an empty hidden field which will send a blank value if all items are unselected.
1693 $item.='<input type="hidden" name="'.htmlspecialchars($PA['itemFormElName']).'" value="" />';
1694
1695 // Implode rows in table:
1696 $item.= '
1697 <table border="0" cellpadding="0" cellspacing="0" class="typo3-TCEforms-select-checkbox">'.
1698 implode('',$tRows).'
1699 </table>
1700 ';
1701
1702 return $item;
1703 }
1704
1705 /**
1706 * Creates a selectorbox list (renderMode = "singlebox")
1707 * (Render function for getSingleField_typeSelect())
1708 *
1709 * @param string See getSingleField_typeSelect()
1710 * @param string See getSingleField_typeSelect()
1711 * @param array See getSingleField_typeSelect()
1712 * @param array See getSingleField_typeSelect()
1713 * @param array (Redundant) content of $PA['fieldConf']['config'] (for convenience)
1714 * @param array Items available for selection
1715 * @param string Label for no-matching-value
1716 * @return string The HTML code for the item
1717 * @see getSingleField_typeSelect()
1718 */
1719 function getSingleField_typeSelect_singlebox($table,$field,$row,&$PA,$config,$selItems,$nMV_label) {
1720
1721 // Get values in an array (and make unique, which is fine because there can be no duplicates anyway):
1722 $itemArray = array_flip($this->extractValuesOnlyFromValueLabelList($PA['itemFormElValue']));
1723
1724 $disabled = '';
1725 if($this->renderReadonly || $config['readOnly']) {
1726 $disabled = ' disabled="disabled"';
1727 }
1728
1729 // Traverse the Array of selector box items:
1730 $opt = array();
1731 $restoreCmd = array(); // Used to accumulate the JS needed to restore the original selection.
1732 $c = 0;
1733 foreach($selItems as $p) {
1734 // Selected or not by default:
1735 $sM = '';
1736 if (isset($itemArray[$p[1]])) {
1737 $sM = ' selected="selected"';
1738 $restoreCmd[] = $this->elName($PA['itemFormElName'].'[]').'.options['.$c.'].selected=1;';
1739 unset($itemArray[$p[1]]);
1740 }
1741
1742 // Non-selectable element:
1743 $nonSel = '';
1744 if (!strcmp($p[1],'--div--')) {
1745 $nonSel = ' onclick="this.selected=0;" class="c-divider"';
1746 }
1747
1748 // Icon style for option tag:
1749 if ($config['iconsInOptionTags']) {
1750 $styleAttrValue = $this->optionTagStyle($p[2]);
1751 }
1752
1753 // Compile <option> tag:
1754 $opt[] = '<option value="'.htmlspecialchars($p[1]).'"'.
1755 $sM.
1756 $nonSel.
1757 ($styleAttrValue ? ' style="'.htmlspecialchars($styleAttrValue).'"' : '').
1758 '>'.t3lib_div::deHSCentities(htmlspecialchars($p[0])).'</option>';
1759 $c++;
1760 }
1761
1762 // Remaining values:
1763 if (count($itemArray) && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
1764 foreach($itemArray as $theNoMatchValue => $temp) {
1765 // Compile <option> tag:
1766 array_unshift($opt,'<option value="'.htmlspecialchars($theNoMatchValue).'" selected="selected">'.t3lib_div::deHSCentities(htmlspecialchars(@sprintf($nMV_label, $theNoMatchValue))).'</option>');
1767 }
1768 }
1769
1770 // Compile selector box:
1771 $sOnChange = implode('',$PA['fieldChangeFunc']);
1772 $selector_itemListStyle = isset($config['itemListStyle']) ? ' style="'.htmlspecialchars($config['itemListStyle']).'"' : ' style="'.$this->defaultMultipleSelectorStyle.'"';
1773 $size = intval($config['size']);
1774 $size = $config['autoSizeMax'] ? t3lib_div::intInRange(count($selItems)+1,t3lib_div::intInRange($size,1),$config['autoSizeMax']) : $size;
1775 $selectBox = '<select name="'.$PA['itemFormElName'].'[]"'.
1776 $this->insertDefStyle('select').
1777 ($size ? ' size="'.$size.'"' : '').
1778 ' multiple="multiple" onchange="'.htmlspecialchars($sOnChange).'"'.
1779 $PA['onFocus'].
1780 $selector_itemListStyle.
1781 $disabled.'>
1782 '.
1783 implode('
1784 ',$opt).'
1785 </select>';
1786
1787 // Add an empty hidden field which will send a blank value if all items are unselected.
1788 if (!$disabled) {
1789 $item.='<input type="hidden" name="'.htmlspecialchars($PA['itemFormElName']).'" value="" />';
1790 }
1791
1792 // Put it all into a table:
1793 $item.= '
1794 <table border="0" cellspacing="0" cellpadding="0" width="1" class="typo3-TCEforms-select-singlebox">
1795 <tr>
1796 <td>
1797 '.$selectBox.'
1798 <br/>
1799 <em>'.
1800 htmlspecialchars($this->getLL('l_holdDownCTRL')).
1801 '</em>
1802 </td>
1803 <td valign="top">
1804 <a href="#" onclick="'.htmlspecialchars($this->elName($PA['itemFormElName'].'[]').'.selectedIndex=-1;'.implode('',$restoreCmd).' return false;').'">'.
1805 '<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/history.gif','width="13" height="12"').' title="'.htmlspecialchars($this->getLL('l_revertSelection')).'" alt="" />'.
1806 '</a>
1807 </td>
1808 </tr>
1809 </table>
1810 ';
1811
1812 return $item;
1813 }
1814
1815 /**
1816 * Creates a multiple-selector box (two boxes, side-by-side)
1817 * (Render function for getSingleField_typeSelect())
1818 *
1819 * @param string See getSingleField_typeSelect()
1820 * @param string See getSingleField_typeSelect()
1821 * @param array See getSingleField_typeSelect()
1822 * @param array See getSingleField_typeSelect()
1823 * @param array (Redundant) content of $PA['fieldConf']['config'] (for convenience)
1824 * @param array Items available for selection
1825 * @param string Label for no-matching-value
1826 * @return string The HTML code for the item
1827 * @see getSingleField_typeSelect()
1828 */
1829 function getSingleField_typeSelect_multiple($table,$field,$row,&$PA,$config,$selItems,$nMV_label) {
1830
1831 $disabled = '';
1832 if($this->renderReadonly || $config['readOnly']) {
1833 $disabled = ' disabled="disabled"';
1834 }
1835
1836 // Setting this hidden field (as a flag that JavaScript can read out)
1837 if (!$disabled) {
1838 $item.= '<input type="hidden" name="'.$PA['itemFormElName'].'_mul" value="'.($config['multiple']?1:0).'" />';
1839 }
1840
1841 // Set max and min items:
1842 $maxitems = t3lib_div::intInRange($config['maxitems'],0);
1843 if (!$maxitems) $maxitems=100000;
1844 $minitems = t3lib_div::intInRange($config['minitems'],0);
1845
1846 // Register the required number of elements:
1847 $this->requiredElements[$PA['itemFormElName']] = array($minitems,$maxitems,'imgName'=>$table.'_'.$row['uid'].'_'.$field);
1848
1849 // Get "removeItems":
1850 $removeItems = t3lib_div::trimExplode(',',$PA['fieldTSConfig']['removeItems'],1);
1851
1852 // Perform modification of the selected items array:
1853 $itemArray = t3lib_div::trimExplode(',',$PA['itemFormElValue'],1);
1854 foreach($itemArray as $tk => $tv) {
1855 $tvP = explode('|',$tv,2);
1856 $evalValue = rawurldecode($tvP[0]);
1857 $isRemoved = in_array($evalValue,$removeItems) || ($config['form_type']=='select' && $config['authMode'] && !$GLOBALS['BE_USER']->checkAuthMode($table,$field,$evalValue,$config['authMode']));
1858 if ($isRemoved && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
1859 $tvP[1] = rawurlencode(@sprintf($nMV_label, $evalValue));
1860 } elseif (isset($PA['fieldTSConfig']['altLabels.'][$evalValue])) {
1861 $tvP[1] = rawurlencode($this->sL($PA['fieldTSConfig']['altLabels.'][$evalValue]));
1862 }
1863 $itemArray[$tk] = implode('|',$tvP);
1864 }
1865 $itemsToSelect = '';
1866
1867 if(!$disabled) {
1868 // Create option tags:
1869 $opt = array();
1870 $styleAttrValue = '';
1871 foreach($selItems as $p) {
1872 if ($config['iconsInOptionTags']) {
1873 $styleAttrValue = $this->optionTagStyle($p[2]);
1874 }
1875 $opt[]= '<option value="'.htmlspecialchars($p[1]).'"'.
1876 ($styleAttrValue ? ' style="'.htmlspecialchars($styleAttrValue).'"' : '').
1877 '>'.htmlspecialchars($p[0]).'</option>';
1878 }
1879
1880 // Put together the selector box:
1881 $selector_itemListStyle = isset($config['itemListStyle']) ? ' style="'.htmlspecialchars($config['itemListStyle']).'"' : ' style="'.$this->defaultMultipleSelectorStyle.'"';
1882 $size = intval($config['size']);
1883 $size = $config['autoSizeMax'] ? t3lib_div::intInRange(count($itemArray)+1,t3lib_div::intInRange($size,1),$config['autoSizeMax']) : $size;
1884 if ($config['exclusiveKeys']) {
1885 $sOnChange = 'setFormValueFromBrowseWin(\''.$PA['itemFormElName'].'\',this.options[this.selectedIndex].value,this.options[this.selectedIndex].text,\''.$config['exclusiveKeys'].'\'); ';
1886 } else {
1887 $sOnChange = 'setFormValueFromBrowseWin(\''.$PA['itemFormElName'].'\',this.options[this.selectedIndex].value,this.options[this.selectedIndex].text); ';
1888 }
1889 $sOnChange .= implode('',$PA['fieldChangeFunc']);
1890 $itemsToSelect = '
1891 <select name="'.$PA['itemFormElName'].'_sel"'.
1892 $this->insertDefStyle('select').
1893 ($size ? ' size="'.$size.'"' : '').
1894 ' onchange="'.htmlspecialchars($sOnChange).'"'.
1895 $PA['onFocus'].
1896 $selector_itemListStyle.'>
1897 '.implode('
1898 ',$opt).'
1899 </select>';
1900 }
1901
1902 // Pass to "dbFileIcons" function:
1903 $params = array(
1904 'size' => $size,
1905 'autoSizeMax' => t3lib_div::intInRange($config['autoSizeMax'],0),
1906 'style' => isset($config['selectedListStyle']) ? ' style="'.htmlspecialchars($config['selectedListStyle']).'"' : ' style="'.$this->defaultMultipleSelectorStyle.'"',
1907 'dontShowMoveIcons' => ($maxitems<=1),
1908 'maxitems' => $maxitems,
1909 'info' => '',
1910 'headers' => array(
1911 'selector' => $this->getLL('l_selected').':<br />',
1912 'items' => $this->getLL('l_items').':<br />'
1913 ),
1914 'noBrowser' => 1,
1915 'thumbnails' => $itemsToSelect,
1916 'readOnly' => $disabled
1917 );
1918 $item.= $this->dbFileIcons($PA['itemFormElName'],'','',$itemArray,'',$params,$PA['onFocus']);
1919
1920 return $item;
1921 }
1922
1923 /**
1924 * Generation of TCEform elements of the type "group"
1925 * This will render a selectorbox into which elements from either the file system or database can be inserted. Relations.
1926 *
1927 * @param string The table name of the record
1928 * @param string The field name which this element is supposed to edit
1929 * @param array The record data array where the value(s) for the field can be found
1930 * @param array An array with additional configuration options.
1931 * @return string The HTML code for the TCEform field
1932 */
1933 function getSingleField_typeGroup($table,$field,$row,&$PA) {
1934 // Init:
1935 $config = $PA['fieldConf']['config'];
1936 $internal_type = $config['internal_type'];
1937 $show_thumbs = $config['show_thumbs'];
1938 $size = intval($config['size']);
1939 $maxitems = t3lib_div::intInRange($config['maxitems'],0);
1940 if (!$maxitems) $maxitems=100000;
1941 $minitems = t3lib_div::intInRange($config['minitems'],0);
1942 $allowed = $config['allowed'];
1943 $disallowed = $config['disallowed'];
1944
1945 $disabled = '';
1946 if($this->renderReadonly || $config['readOnly']) {
1947 $disabled = ' disabled="disabled"';
1948 }
1949
1950 $item.= '<input type="hidden" name="'.$PA['itemFormElName'].'_mul" value="'.($config['multiple']?1:0).'"'.$disabled.' />';
1951 $this->requiredElements[$PA['itemFormElName']] = array($minitems,$maxitems,'imgName'=>$table.'_'.$row['uid'].'_'.$field);
1952 $info='';
1953
1954 // "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/.
1955 $specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);
1956
1957 // Acting according to either "file" or "db" type:
1958 switch((string)$config['internal_type']) {
1959 case 'file': // If the element is of the internal type "file":
1960
1961 // Creating string showing allowed types:
1962 $tempFT = t3lib_div::trimExplode(',',$allowed,1);
1963 if (!count($tempFT)) {$info.='*';}
1964 foreach($tempFT as $ext) {
1965 if ($ext) {
1966 $info.=strtoupper($ext).' ';
1967 }
1968 }
1969 // Creating string, showing disallowed types:
1970 $tempFT_dis = t3lib_div::trimExplode(',',$disallowed,1);
1971 if (count($tempFT_dis)) {$info.='<br />';}
1972 foreach($tempFT_dis as $ext) {
1973 if ($ext) {
1974 $info.='-'.strtoupper($ext).' ';
1975 }
1976 }
1977
1978 // Making the array of file items:
1979 $itemArray = t3lib_div::trimExplode(',',$PA['itemFormElValue'],1);
1980
1981 // Showing thumbnails:
1982 $thumbsnail = '';
1983 if ($show_thumbs) {
1984 $imgs = array();
1985 foreach($itemArray as $imgRead) {
1986 $imgP = explode('|',$imgRead);
1987 $imgPath = rawurldecode($imgP[0]);
1988
1989 $rowCopy = array();
1990 $rowCopy[$field] = $imgPath;
1991
1992 // Icon + clickmenu:
1993 $absFilePath = t3lib_div::getFileAbsFileName($config['uploadfolder'].'/'.$imgPath);
1994
1995 $fI = pathinfo($imgPath);
1996 $fileIcon = t3lib_BEfunc::getFileIcon(strtolower($fI['extension']));
1997 $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="" />';
1998
1999 $imgs[] = '<span class="nobr">'.t3lib_BEfunc::thumbCode($rowCopy,$table,$field,$this->backPath,'thumbs.php',$config['uploadfolder'],0,' align="middle"').
2000 ($absFilePath ? $this->getClickMenu($fileIcon, $absFilePath) : $fileIcon).
2001 $imgPath.
2002 '</span>';
2003 }
2004 $thumbsnail = implode('<br />',$imgs);
2005 }
2006
2007 // Creating the element:
2008 $noList = isset($config['disable_controls']) && t3lib_div::inList($config['disable_controls'], 'list');
2009 $params = array(
2010 'size' => $size,
2011 'dontShowMoveIcons' => ($maxitems<=1),
2012 'autoSizeMax' => t3lib_div::intInRange($config['autoSizeMax'],0),
2013 'maxitems' => $maxitems,
2014 'style' => isset($config['selectedListStyle']) ? ' style="'.htmlspecialchars($config['selectedListStyle']).'"' : ' style="'.$this->defaultMultipleSelectorStyle.'"',
2015 'info' => $info,
2016 'thumbnails' => $thumbsnail,
2017 'readOnly' => $disabled,
2018 'noBrowser' => $noList || isset($config['disable_controls']) && t3lib_div::inList($config['disable_controls'], 'browser'),
2019 'noList' => $noList,
2020 );
2021 $item.= $this->dbFileIcons($PA['itemFormElName'],'file',implode(',',$tempFT),$itemArray,'',$params,$PA['onFocus']);
2022
2023 if(!$disabled && !(isset($config['disable_controls']) && t3lib_div::inList($config['disable_controls'], 'upload'))) {
2024 // Adding the upload field:
2025 if ($this->edit_docModuleUpload) $item.='<input type="file" name="'.$PA['itemFormElName_file'].'"'.$this->formWidth().' size="60" />';
2026 }
2027 break;
2028 case 'db': // If the element is of the internal type "db":
2029
2030 // Creating string showing allowed types:
2031 $tempFT = t3lib_div::trimExplode(',',$allowed,1);
2032 if (!strcmp(trim($tempFT[0]),'*')) {
2033 $info.='<span class="nobr">&nbsp;&nbsp;&nbsp;&nbsp;'.
2034 htmlspecialchars($this->getLL('l_allTables')).
2035 '</span><br />';
2036 } else {
2037 while(list(,$theT)=each($tempFT)) {
2038 if ($theT) {
2039 $info.='<span class="nobr">&nbsp;&nbsp;&nbsp;&nbsp;'.
2040 t3lib_iconWorks::getIconImage($theT,array(),$this->backPath,'align="top"').
2041 htmlspecialchars($this->sL($GLOBALS['TCA'][$theT]['ctrl']['title'])).
2042 '</span><br />';
2043 }
2044 }
2045 }
2046
2047 $perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
2048 $itemArray = array();
2049 $imgs = array();
2050
2051 // Thumbnails:
2052 $temp_itemArray = t3lib_div::trimExplode(',',$PA['itemFormElValue'],1);
2053 foreach($temp_itemArray as $dbRead) {
2054 $recordParts = explode('|',$dbRead);
2055 list($this_table,$this_uid) = t3lib_BEfunc::splitTable_Uid($recordParts[0]);
2056 $itemArray[] = array('table'=>$this_table, 'id'=>$this_uid);
2057 if (!$disabled && $show_thumbs) {
2058 $rr = t3lib_BEfunc::getRecordWSOL($this_table,$this_uid);
2059 $imgs[] = '<span class="nobr">'.
2060 $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).
2061 '&nbsp;'.
2062 t3lib_BEfunc::getRecordTitle($this_table,$rr,TRUE).' <span class="typo3-dimmed"><em>['.$rr['uid'].']</em></span>'.
2063 '</span>';
2064 }
2065 }
2066 $thumbsnail='';
2067 if (!$disabled && $show_thumbs) {
2068 $thumbsnail = implode('<br />',$imgs);
2069 }
2070
2071 // Creating the element:
2072 $params = array(
2073 'size' => $size,
2074 'dontShowMoveIcons' => ($maxitems<=1),
2075 'autoSizeMax' => t3lib_div::intInRange($config['autoSizeMax'],0),
2076 'maxitems' => $maxitems,
2077 'style' => isset($config['selectedListStyle']) ? ' style="'.htmlspecialchars($config['selectedListStyle']).'"' : ' style="'.$this->defaultMultipleSelectorStyle.'"',
2078 'info' => $info,
2079 'thumbnails' => $thumbsnail,
2080 'readOnly' => $disabled
2081 );
2082 $item.= $this->dbFileIcons($PA['itemFormElName'],'db',implode(',',$tempFT),$itemArray,'',$params,$PA['onFocus'],$table,$field,$row['uid']);
2083
2084 break;
2085 }
2086
2087 // Wizards:
2088 $altItem = '<input type="hidden" name="'.$PA['itemFormElName'].'" value="'.htmlspecialchars($PA['itemFormElValue']).'" />';
2089 if (!$disabled) {
2090 $item = $this->renderWizards(array($item,$altItem),$config['wizards'],$table,$row,$field,$PA,$PA['itemFormElName'],$specConf);
2091 }
2092
2093 return $item;
2094 }
2095
2096 /**
2097 * Generation of TCEform elements of the type "none"
2098 * This will render a non-editable display of the content of the field.
2099 *
2100 * @param string The table name of the record
2101 * @param string The field name which this element is supposed to edit
2102 * @param array The record data array where the value(s) for the field can be found
2103 * @param array An array with additional configuration options.
2104 * @return string The HTML code for the TCEform field
2105 */
2106 function getSingleField_typeNone($table,$field,$row,&$PA) {
2107 // Init:
2108 $config = $PA['fieldConf']['config'];
2109 $itemValue = $PA['itemFormElValue'];
2110
2111 return $this->getSingleField_typeNone_render($config,$itemValue);
2112 }
2113
2114 /**
2115 * HTML rendering of a value which is not editable.
2116 *
2117 * @param array Configuration for the display
2118 * @param string The value to display
2119 * @return string The HTML code for the display
2120 * @see getSingleField_typeNone();
2121 */
2122 function getSingleField_typeNone_render($config,$itemValue) {
2123
2124 // is colorScheme[0] the right value?
2125 $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;';
2126
2127 if ($config['format']) {
2128 $itemValue = $this->formatValue($config, $itemValue);
2129 }
2130
2131 $rows = intval($config['rows']);
2132 if ($rows > 1) {
2133 if(!$config['pass_content']) {
2134 $itemValue = nl2br(htmlspecialchars($itemValue));
2135 }
2136 // like textarea
2137 $cols = t3lib_div::intInRange($config['cols'] ? $config['cols'] : 30, 5, $this->maxTextareaWidth);
2138 if (!$config['fixedRows']) {
2139 $origRows = $rows = t3lib_div::intInRange($rows, 1, 20);
2140 if (strlen($itemValue)>$this->charsPerRow*2) {
2141 $cols = $this->maxTextareaWidth;
2142 $rows = t3lib_div::intInRange(round(strlen($itemValue)/$this->charsPerRow),count(explode(chr(10),$itemValue)),20);
2143 if ($rows<$origRows) $rows=$origRows;
2144 }
2145 }
2146
2147 if ($this->docLarge) $cols = round($cols*$this->form_largeComp);
2148 $width = ceil($cols*$this->form_rowsToStylewidth);
2149 // hardcoded: 12 is the height of the font
2150 $height=$rows*12;
2151
2152 $item='
2153 <div style="'.htmlspecialchars($divStyle.' overflow:auto; height:'.$height.'px; width:'.$width.'px;').'" class="'.htmlspecialchars($this->formElClass('none')).'">'.
2154 $itemValue.
2155 '</div>';
2156 } else {
2157 if(!$config['pass_content']) {
2158 $itemValue = htmlspecialchars($itemValue);
2159 }
2160
2161 $cols = $config['cols']?$config['cols']:($config['size']?$config['size']:$this->maxInputWidth);
2162 if ($this->docLarge) $cols = round($cols*$this->form_largeComp);
2163 $width = ceil($cols*$this->form_rowsToStylewidth);
2164
2165 // overflow:auto crashes mozilla here. Title tag is usefull when text is longer than the div box (overflow:hidden).
2166 $item = '
2167 <div style="'.htmlspecialchars($divStyle.' overflow:hidden; width:'.$width.'px;').'" class="'.htmlspecialchars($this->formElClass('none')).'" title="'.$itemValue.'">'.
2168 '<span class="nobr">'.(strcmp($itemValue,'')?$itemValue:'&nbsp;').'</span>'.
2169 '</div>';
2170 }
2171
2172 return $item;
2173 }
2174
2175 /**
2176 * Handler for Flex Forms
2177 *
2178 * @param string The table name of the record
2179 * @param string The field name which this element is supposed to edit
2180 * @param array The record data array where the value(s) for the field can be found
2181 * @param array An array with additional configuration options.
2182 * @return string The HTML code for the TCEform field
2183 */
2184 function getSingleField_typeFlex($table,$field,$row,&$PA) {
2185
2186 // Data Structure:
2187 $dataStructArray = t3lib_BEfunc::getFlexFormDS($PA['fieldConf']['config'],$row,$table);
2188
2189 // Get data structure:
2190 if (is_array($dataStructArray)) {
2191
2192 // Get data:
2193 $xmlData = $PA['itemFormElValue'];
2194 $xmlHeaderAttributes = t3lib_div::xmlGetHeaderAttribs($xmlData);
2195 $storeInCharset = strtolower($xmlHeaderAttributes['encoding']);
2196 if ($storeInCharset) {
2197 $currentCharset=$GLOBALS['LANG']->charSet;
2198 $xmlData = $GLOBALS['LANG']->csConvObj->conv($xmlData,$storeInCharset,$currentCharset,1);
2199 }
2200 $editData=t3lib_div::xml2array($xmlData);
2201 if (!is_array($editData)) { // Must be XML parsing error...
2202 $editData=array();
2203 } elseif (!isset($editData['meta']) || !is_array($editData['meta'])) {
2204 $editData['meta'] = array();
2205 }
2206
2207 // Find the data structure if sheets are found:
2208 $sheet = $editData['meta']['currentSheetId'] ? $editData['meta']['currentSheetId'] : 'sDEF'; // Sheet to display
2209
2210 // Create sheet menu:
2211 // if (is_array($dataStructArray['sheets'])) {
2212 // #$item.=$this->getSingleField_typeFlex_sheetMenu($dataStructArray['sheets'], $PA['itemFormElName'].'[meta][currentSheetId]', $sheet).'<br />';
2213 // }
2214
2215 // Create language menu:
2216 $langChildren = $dataStructArray['meta']['langChildren'] ? 1 : 0;
2217 $langDisabled = $dataStructArray['meta']['langDisable'] ? 1 : 0;
2218
2219 $editData['meta']['currentLangId']=array();
2220 $languages = $this->getAvailableLanguages();
2221
2222 foreach($languages as $lInfo) {
2223 if ($GLOBALS['BE_USER']->checkLanguageAccess($lInfo['uid'])) {
2224 $editData['meta']['currentLangId'][] = $lInfo['ISOcode'];
2225 }
2226 }
2227 if (!is_array($editData['meta']['currentLangId']) || !count($editData['meta']['currentLangId'])) {
2228 $editData['meta']['currentLangId']=array('DEF');
2229 }
2230
2231 $editData['meta']['currentLangId'] = array_unique($editData['meta']['currentLangId']);
2232
2233
2234 // if (!$langDisabled && count($languages) > 1) {
2235 // $item.=$this->getSingleField_typeFlex_langMenu($languages, $PA['itemFormElName'].'[meta][currentLangId]', $editData['meta']['currentLangId']).'<br />';
2236 // }
2237
2238 $PA['_noEditDEF'] = FALSE;
2239 if ($langChildren || $langDisabled) {
2240 $rotateLang = array('DEF');
2241 } else {
2242 if (!in_array('DEF',$editData['meta']['currentLangId'])) {
2243 array_unshift($editData['meta']['currentLangId'],'DEF');
2244 $PA['_noEditDEF'] = TRUE;
2245 }
2246 $rotateLang = $editData['meta']['currentLangId'];
2247 }
2248
2249 // Tabs sheets
2250 if (is_array($dataStructArray['sheets'])) {
2251 $tabsToTraverse = array_keys($dataStructArray['sheets']);
2252 } else {
2253 $tabsToTraverse = array($sheet);
2254 }
2255
2256 foreach ($rotateLang as $lKey) {
2257 if (!$langChildren && !$langDisabled) {
2258 $item.= '<b>'.$this->getLanguageIcon($table,$row,'v'.$lKey).$lKey.':</b>';
2259 }
2260
2261 $tabParts = array();
2262 foreach ($tabsToTraverse as $sheet) {
2263 list ($dataStruct, $sheet) = t3lib_div::resolveSheetDefInDS($dataStructArray,$sheet);
2264
2265 // Render sheet:
2266 if (is_array($dataStruct['ROOT']) && is_array($dataStruct['ROOT']['el'])) {
2267 $lang = 'l'.$lKey; // Default language, other options are "lUK" or whatever country code (independant of system!!!)
2268 $PA['_valLang'] = $langChildren && !$langDisabled ? $editData['meta']['currentLangId'] : 'DEF'; // Default language, other options are "lUK" or whatever country code (independant of system!!!)
2269 $PA['_lang'] = $lang;
2270 $PA['_cshFile'] = ((isset($dataStruct['ROOT']['TCEforms']) && isset($dataStruct['ROOT']['TCEforms']['cshFile'])) ? $dataStruct['ROOT']['TCEforms']['cshFile'] : '');
2271
2272 // Render flexform:
2273 $tRows = $this->getSingleField_typeFlex_draw(
2274 $dataStruct['ROOT']['el'],
2275 $editData['data'][$sheet][$lang],
2276 $table,
2277 $field,
2278 $row,
2279 $PA,
2280 '[data]['.$sheet.']['.$lang.']'
2281 );
2282 #$sheetContent= '<table border="0" cellpadding="1" cellspacing="1" class="typo3-TCEforms-flexForm">'.implode('',$tRows).'</table>';
2283 $sheetContent = '<div class="typo3-TCEforms-flexForm">'.$tRows.'</div>';
2284
2285 # $item = '<div style=" position:absolute;">'.$item.'</div>';
2286 //visibility:hidden;
2287 } else $sheetContent='Data Structure ERROR: No ROOT element found for sheet "'.$sheet.'".';
2288
2289 // Add to tab:
2290 $tabParts[] = array(
2291 'label' => ($dataStruct['ROOT']['TCEforms']['sheetTitle'] ? $this->sL($dataStruct['ROOT']['TCEforms']['sheetTitle']) : $sheet),
2292 'description' => ($dataStruct['ROOT']['TCEforms']['sheetDescription'] ? $this->sL($dataStruct['ROOT']['TCEforms']['sheetDescription']) : ''),
2293 'linkTitle' => ($dataStruct['ROOT']['TCEforms']['sheetShortDescr'] ? $this->sL($dataStruct['ROOT']['TCEforms']['sheetShortDescr']) : ''),
2294 'content' => $sheetContent
2295 );
2296 }
2297
2298 if (is_array($dataStructArray['sheets'])) {
2299 $item.= $this->getDynTabMenu($tabParts,'TCEFORMS:flexform:'.$PA['itemFormElName'].$PA['_lang']);
2300 } else {
2301 $item.= $sheetContent;
2302 }
2303 }
2304 } else $item='Data Structure ERROR: '.$dataStructArray;
2305
2306 return $item;
2307 }
2308
2309 /**
2310 * Creates the language menu for FlexForms:
2311 *
2312 * @param [type] $languages: ...
2313 * @param [type] $elName: ...
2314 * @param [type] $selectedLanguage: ...
2315 * @param [type] $multi: ...
2316 * @return string HTML for menu
2317 */
2318 function getSingleField_typeFlex_langMenu($languages,$elName,$selectedLanguage,$multi=1) {
2319 $opt=array();
2320 foreach($languages as $lArr) {
2321 $opt[]='<option value="'.htmlspecialchars($lArr['ISOcode']).'"'.(in_array($lArr['ISOcode'],$selectedLanguage)?' selected="selected"':'').'>'.htmlspecialchars($lArr['title']).'</option>';
2322 }
2323
2324 $output = '<select name="'.$elName.'[]"'.($multi ? ' multiple="multiple" size="'.count($languages).'"' : '').'>'.implode('',$opt).'</select>';
2325
2326 return $output;
2327 }
2328
2329 /**
2330 * Creates the menu for selection of the sheets:
2331 *
2332 * @param array Sheet array for which to render the menu
2333 * @param string Form element name of the field containing the sheet pointer
2334 * @param string Current sheet key
2335 * @return string HTML for menu
2336 */
2337 function getSingleField_typeFlex_sheetMenu($sArr,$elName,$sheetKey) {
2338
2339 $tCells =array();
2340 $pct = round(100/count($sArr));
2341 foreach($sArr as $sKey => $sheetCfg) {
2342 if ($GLOBALS['BE_USER']->jsConfirmation(1)) {
2343 $onClick = 'if (confirm(TBE_EDITOR.labels.onChangeAlert) && TBE_EDITOR.checkSubmit(-1)){'.$this->elName($elName).".value='".$sKey."'; TBE_EDITOR.submitForm()};";
2344 } else {
2345 $onClick = 'if(TBE_EDITOR.checkSubmit(-1)){ '.$this->elName($elName).".value='".$sKey."'; TBE_EDITOR.submitForm();}";
2346 }
2347
2348
2349 $tCells[]='<td width="'.$pct.'%" style="'.($sKey==$sheetKey ? 'background-color: #9999cc; font-weight: bold;' : 'background-color: #aaaaaa;').' cursor: hand;" onclick="'.htmlspecialchars($onClick).'" align="center">'.
2350 ($sheetCfg['ROOT']['TCEforms']['sheetTitle'] ? $this->sL($sheetCfg['ROOT']['TCEforms']['sheetTitle']) : $sKey).
2351 '</td>';
2352 }
2353
2354 return '<table border="0" cellpadding="0" cellspacing="2" class="typo3-TCEforms-flexForm-sheetMenu"><tr>'.implode('',$tCells).'</tr></table>';
2355 }
2356
2357 /**
2358 * Recursive rendering of flexforms
2359 *
2360 * @param array (part of) Data Structure for which to render. Keys on first level is flex-form fields
2361 * @param array (part of) Data array of flexform corresponding to the input DS. Keys on first level is flex-form field names
2362 * @param string Table name, eg. tt_content
2363 * @param string Field name, eg. tx_templavoila_flex
2364 * @param array The particular record from $table in which the field $field is found
2365 * @param array Array of standard information for rendering of a form field in TCEforms, see other rendering functions too
2366 * @param string Form field prefix, eg. "[data][sDEF][lDEF][...][...]"
2367 * @param integer Indicates nesting level for the function call
2368 * @param string Prefix for ID-values
2369 * @param boolean Defines whether the next flexform level is open or closed. Comes from _TOGGLE pseudo field in FlexForm xml.
2370 * @return string HTMl code for form.
2371 */
2372 function getSingleField_typeFlex_draw($dataStruct,$editData,$table,$field,$row,&$PA,$formPrefix='',$level=0,$idPrefix='ID',$toggleClosed=FALSE) {
2373
2374 $output = '';
2375 $mayRestructureFlexforms = $GLOBALS['BE_USER']->checkLanguageAccess(0);
2376
2377 // Data Structure array must be ... and array of course...
2378 if (is_array($dataStruct)) {
2379 foreach($dataStruct as $key => $value) { // Traversing fields in structure:
2380 if (is_array($value)) { // The value of each entry must be an array.
2381
2382 // ********************
2383 // Making the row:
2384 // ********************
2385 // Title of field:
2386 $theTitle = htmlspecialchars(t3lib_div::fixed_lgd_cs($this->sL($value['tx_templavoila']['title']),30));
2387
2388 // If it's a "section" or "container":
2389 if ($value['type']=='array') {
2390
2391 // Creating IDs for form fields:
2392 // 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.
2393 $thisId = t3lib_div::shortMd5(uniqid('id',true)); // This is a suffix used for forms on this level
2394 $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.
2395
2396 // If it's a "section" containing other elements:
2397 if ($value['section']) {
2398
2399 // Render header of section:
2400 $output.= '<div class="bgColor2"><strong>'.$theTitle.'</strong></div>';
2401
2402 // Render elements in data array for section:
2403 $tRows = array();
2404 $cc=0;
2405 if (is_array($editData[$key]['el'])) {
2406 foreach ($editData[$key]['el'] as $k3 => $v3) {
2407 $cc=$k3;
2408 if (is_array($v3)) {
2409 $theType = key($v3);
2410 $theDat = $v3[$theType];
2411 $newSectionEl = $value['el'][$theType];
2412 if (is_array($newSectionEl)) {
2413 $tRows[]= $this->getSingleField_typeFlex_draw(
2414 array($theType => $newSectionEl),
2415 array($theType => $theDat),
2416 $table,
2417 $field,
2418 $row,
2419 $PA,
2420 $formPrefix.'['.$key.'][el]['.$cc.']',
2421 $level+1,
2422 $idTagPrefix,
2423 $v3['_TOGGLE']
2424 );
2425 }
2426 }
2427 }
2428 }
2429
2430 // Now, we generate "templates" for new elements that could be added to this section by traversing all possible types of content inside the section:
2431 // 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...
2432
2433 // Preserving internal variables we don't want to change:
2434 $TEMP_requiredElements = $this->requiredElements;
2435
2436 // Traversing possible types of new content in the section:
2437 $newElementsLinks = array();
2438 foreach($value['el'] as $nnKey => $nCfg) {
2439 $newElementTemplate = $this->getSingleField_typeFlex_draw(
2440 array($nnKey => $nCfg),
2441 array(),
2442 $table,
2443 $field,
2444 $row,
2445 $PA,
2446 $formPrefix.'['.$key.'][el]['.$idTagPrefix.'-form]',
2447 $level+1,
2448 $idTagPrefix
2449 );
2450
2451 // Makes a "Add new" link:
2452 $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...
2453 $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>';
2454 }
2455
2456 // Reverting internal variables we don't want to change:
2457 $this->requiredElements = $TEMP_requiredElements;
2458
2459 // Adding the sections:
2460 $output.= '
2461 <div style="padding: 2px 0px 2px 20px;">
2462 <a href="#" onclick="'.htmlspecialchars('flexFormToggleSubs("'.$idTagPrefix.'"); return false;').'">
2463 <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
2464 </a>
2465 </div>
2466
2467 <div id="'.$idTagPrefix.'" style="padding-left: 20px;">'.implode('',$tRows).'</div>';
2468 $output.= $mayRestructureFlexforms ? '<div style="padding: 10px 5px 5px 20px;"><b>Add new:</b> '.implode(' | ',$newElementsLinks).'</div>' : '';
2469 // If it's a container:
2470 } else {
2471
2472 $toggleIcon_open = '<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/pil2down.gif','width="12" height="7"').' hspace="2" alt="Open" title="Open" />';
2473 $toggleIcon_close = '<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/pil2right.gif','width="7" height="12"').' hspace="2" alt="Close" title="Close" />';
2474
2475 // Create on-click actions.
2476 # $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.
2477 $onClickRemove = 'if (confirm("Are you sure?")){$("'.$idTagPrefix.'").hide();setActionStatus("'.$idPrefix.'");} return false;';
2478 $onClickToggle = 'flexFormToggle("'.$idTagPrefix.'"); return false;';
2479
2480 $onMove = 'flexFormSortable("'.$idPrefix.'")';
2481 // 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.
2482
2483
2484 // Putting together header of a section. Sections can be removed, copied, opened/closed, moved up and down:
2485 // 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.
2486 // 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.
2487 $ctrlHeader= '
2488 <table border="0" cellpadding="0" cellspacing="0" width="100%" onmousedown="'.($mayRestructureFlexforms?htmlspecialchars($onMove):'').'">
2489 <tr>
2490 <td>
2491 <a href="#" onclick="'.htmlspecialchars($onClickToggle).'" id="'.$idTagPrefix.'-toggle">
2492 '.($toggleClosed?$toggleIcon_close:$toggleIcon_open).'
2493 </a>
2494 <strong>'.$theTitle.'</strong> <em><span id="'.$idTagPrefix.'-preview"></span></em>
2495 </td>
2496 <td align="right">'.
2497 ($mayRestructureFlexforms ? '<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/move.gif','width="16" height="16"').' alt="Drag to Move" title="Drag to Move" />' : '').
2498 # '<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
2499 ($mayRestructureFlexforms ? '<a href="#" onclick="'.htmlspecialchars($onClickRemove).'"><img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/garbage.gif','width="11" height="12"').' alt="Delete" title="Delete" /></a>' : '').
2500 '</td>
2501 </tr>
2502 </table>';
2503
2504 $s = t3lib_div::revExplode('[]',$formPrefix,2);
2505 $actionFieldName = '_ACTION_FLEX_FORM'.$PA['itemFormElName'].$s[0].'][_ACTION]['.$s[1];
2506
2507 // Putting together the container:
2508 $output.= '
2509 <div id="'.$idTagPrefix.'" class="bgColor2">
2510 <input id="'.$idTagPrefix.'-action" type="hidden" name="'.htmlspecialchars($actionFieldName).'" value=""/>
2511
2512 '.$ctrlHeader.'
2513 <div id="'.$idTagPrefix.'-content"'.($toggleClosed?' style="display:none;"':'').'>'.$this->getSingleField_typeFlex_draw(
2514 $value['el'],
2515 $editData[$key]['el'],
2516 $table,
2517 $field,
2518 $row,
2519 $PA,
2520 $formPrefix.'['.$key.'][el]',
2521 $level+1,
2522 $idTagPrefix
2523 ).'
2524 </div>
2525 <input id="'.$idTagPrefix.'-toggleClosed" type="hidden" name="'.htmlspecialchars('data['.$table.']['.$row['uid'].']['.$field.']'.$formPrefix.'[_TOGGLE]').'" value="'.($toggleClosed?1:0).'" />
2526 </div>';
2527 // 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.
2528 }
2529
2530 // If it's a "single form element":
2531 } elseif (is_array($value['TCEforms']['config'])) { // Rendering a single form element:
2532
2533 if (is_array($PA['_valLang'])) {
2534 $rotateLang = $PA['_valLang'];
2535 } else {
2536 $rotateLang = array($PA['_valLang']);
2537 }
2538
2539 $tRows = array();
2540 foreach($rotateLang as $vDEFkey) {
2541 $vDEFkey = 'v'.$vDEFkey;
2542
2543 if (!$value['TCEforms']['displayCond'] || $this->isDisplayCondition($value['TCEforms']['displayCond'],$editData,$vDEFkey)) {
2544 $fakePA=array();
2545 $fakePA['fieldConf']=array(
2546 'label' => $this->sL(trim($value['TCEforms']['label'])),
2547 'config' => $value['TCEforms']['config'],
2548 'defaultExtras' => $value['TCEforms']['defaultExtras'],
2549 'onChange' => $value['TCEforms']['onChange']
2550 );
2551 if ($PA['_noEditDEF'] && $PA['_lang']==='lDEF') {
2552 $fakePA['fieldConf']['config'] = array(
2553 'type' => 'none',
2554 'rows' => 2
2555 );
2556 }
2557
2558 if (
2559 $fakePA['fieldConf']['onChange'] == 'reload' ||
2560 ($GLOBALS['TCA'][$table]['ctrl']['type'] && !strcmp($key,$GLOBALS['TCA'][$table]['ctrl']['type'])) ||
2561 ($GLOBALS['TCA'][$table]['ctrl']['requestUpdate'] && t3lib_div::inList($GLOBALS['TCA'][$table]['ctrl']['requestUpdate'],$key))) {
2562 if ($GLOBALS['BE_USER']->jsConfirmation(1)) {
2563 $alertMsgOnChange = 'if (confirm(TBE_EDITOR.labels.onChangeAlert) && TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
2564 } else {
2565 $alertMsgOnChange = 'if(TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm();}';
2566 }
2567 } else {
2568 $alertMsgOnChange = '';
2569 }
2570
2571 $fakePA['fieldChangeFunc']=$PA['fieldChangeFunc'];
2572 if (strlen($alertMsgOnChange)) {
2573 $fakePA['fieldChangeFunc']['alert']=$alertMsgOnChange;
2574 }
2575 $fakePA['onFocus']=$PA['onFocus'];
2576 $fakePA['label']=$PA['label'];
2577
2578 $fakePA['itemFormElName']=$PA['itemFormElName'].$formPrefix.'['.$key.']['.$vDEFkey.']';
2579 $fakePA['itemFormElName_file']=$PA['itemFormElName_file'].$formPrefix.'['.$key.']['.$vDEFkey.']';
2580
2581 if(isset($editData[$key][$vDEFkey])) {
2582 $fakePA['itemFormElValue']=$editData[$key][$vDEFkey];
2583 } else {
2584 $fakePA['itemFormElValue']=$fakePA['fieldConf']['config']['default'];
2585 }
2586
2587 $theFormEl= $this->getSingleField_SW($table,$field,$row,$fakePA);
2588 $theTitle= htmlspecialchars($fakePA['fieldConf']['label']);
2589
2590 if (!in_array('DEF',$rotateLang)) {
2591 $defInfo = '<div class="typo3-TCEforms-originalLanguageValue">'.$this->getLanguageIcon($table,$row,0).$this->previewFieldValue($editData[$key]['vDEF'], $fakePA['fieldConf']).'&nbsp;</div>';
2592 } else {
2593 $defInfo = '';
2594 }
2595
2596 if (!$PA['_noEditDEF']) {
2597 $prLang = $this->getAdditionalPreviewLanguages();
2598 foreach($prLang as $prL) {
2599 $defInfo.= '<div class="typo3-TCEforms-originalLanguageValue">'.$this->getLanguageIcon($table,$row,'v'.$prL['ISOcode']).$this->previewFieldValue($editData[$key]['v'.$prL['ISOcode']], $fakePA['fieldConf']).'&nbsp;</div>';
2600 }
2601 }
2602
2603 // Put row together
2604 // possible linebreaks in the label through xml: \n => <br/>, usage of nl2br() not possible, so it's done through str_replace
2605 $processedTitle = str_replace('\n', '<br />', $theTitle);
2606 $helpText = $this->helpText_typeFlex($key, $processedTitle, $PA['_cshFile']);
2607 $tRows[]='<div>' .
2608 '<div class="bgColor5">' .
2609 ($helpText ?
2610 ($vDEFkey=='vDEF' ? '' : $this->getLanguageIcon($table, $row, $vDEFkey)) . '<strong>' . $processedTitle . '</strong>' . $helpText :
2611 $this->helpTextIcon_typeFlex($key, $processedTitle, $PA['_cshFile']) . ($vDEFkey == 'vDEF' ? '' : $this->getLanguageIcon($table, $row, $vDEFkey)) . $processedTitle
2612 ) .
2613 '</div>
2614 <div class="bgColor4">'.$theFormEl.$defInfo.$this->renderVDEFDiff($editData[$key],$vDEFkey).'</div>
2615 </div>';
2616 }
2617 }
2618 if (count($tRows)) $output.= implode('',$tRows);
2619 }
2620 }
2621 }
2622 }
2623
2624 return $output;
2625 }
2626
2627 /**
2628 * Handler for unknown types.
2629 *
2630 * @param string The table name of the record
2631 * @param string The field name which this element is supposed to edit
2632 * @param array The record data array where the value(s) for the field can be found
2633 * @param array An array with additional configuration options.
2634 * @return string The HTML code for the TCEform field
2635 */
2636 function getSingleField_typeUnknown($table,$field,$row,&$PA) {
2637 $item='Unknown type: '.$PA['fieldConf']['config']['form_type'].'<br />';
2638
2639 return $item;
2640 }
2641
2642 /**
2643 * User defined field type
2644 *
2645 * @param string The table name of the record
2646 * @param string The field name which this element is supposed to edit
2647 * @param array The record data array where the value(s) for the field can be found
2648 * @param array An array with additional configuration options.
2649 * @return string The HTML code for the TCEform field
2650 */
2651 function getSingleField_typeUser($table,$field,$row,&$PA) {
2652 $PA['table']=$table;
2653 $PA['field']=$field;
2654 $PA['row']=$row;
2655
2656 $PA['pObj']=&$this;
2657
2658 return t3lib_div::callUserFunction($PA['fieldConf']['config']['userFunc'],$PA,$this);
2659 }
2660
2661
2662
2663
2664
2665
2666 /************************************************************
2667 *
2668 * Field content processing
2669 *
2670 ************************************************************/
2671
2672 /**
2673 * Format field content of various types if $config['format'] is set to date, filesize, ..., user
2674 * This is primarily for the field type none but can be used for user field types for example
2675 *
2676 * @param array Configuration for the display
2677 * @param string The value to display
2678 * @return string Formatted Field content
2679 */
2680 function formatValue ($config, $itemValue) {
2681 $format = trim($config['format']);
2682 switch($format) {
2683 case 'date'