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