TYPO3 CMS  TYPO3_6-2
FormEngine.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Backend\Form;
3 
36 
43 class FormEngine {
44 
49  public $palFieldArr = array();
50 
55  public $disableWizards = FALSE;
56 
61  public $isPalettedoc = FALSE;
62 
67  public $paletteMargin = 1;
68 
73  public $defStyle = '';
74 
79  public $cachedTSconfig = array();
80 
85  public $cachedTSconfig_fieldLevel = array();
86 
91  public $cachedLanguageFlag = array();
92 
98 
105  protected $cache_getTSCpid = array();
106 
111  public $transformedRow = array();
112 
117  public $extJSCODE = '';
118 
123  public $printNeededJS = array();
124 
129  public $hiddenFieldAccum = array();
130 
136 
141  public $loadMD5_JS = TRUE;
142 
149  public $defaultLanguageData = array();
150 
157  public $defaultLanguageData_diff = array();
158 
164 
165  // EXTERNAL, static
173  public $backPath = '';
174 
181  public $returnUrl = '';
182 
191  public $doSaveFieldName = '';
192 
200  public $palettesCollapsed = FALSE;
201 
208  public $disableRTE = FALSE;
209 
216  public $globalShowHelp = TRUE;
217 
224  public $localizationMode = '';
225 
234  public $fieldOrder = '';
235 
242  public $doPrintPalette = TRUE;
243 
251  public $clipObj = NULL;
252 
259  public $enableClickMenu = FALSE;
260 
265  public $enableTabMenu = FALSE;
266 
273  public $renderReadonly = FALSE;
274 
282  public $form_rowsToStylewidth = 9.58;
283 
290 
297  public $form_largeComp = 1.33;
298 
306  public $charsPerRow = 40;
307 
314  public $maxTextareaWidth = 48;
315 
322  public $maxInputWidth = 48;
323 
330  public $defaultMultipleSelectorStyle = 'width:310px;';
331 
332  // INTERNAL, static
339  public $prependFormFieldNames = 'data';
340 
347  public $prependCmdFieldNames = 'cmd';
348 
355  public $prependFormFieldNames_file = 'data_files';
356 
362  protected $prependFormFieldNamesActive = 'control[active]';
363 
370  public $formName = 'editform';
371 
379  public $allowOverrideMatrix = array();
380 
381  // INTERNAL, dynamic
388  public $perms_clause = '';
389 
396  public $perms_clause_set = FALSE;
397 
405  public $edit_showFieldHelp = FALSE;
406 
410  public $edit_docModuleUpload = FALSE;
411 
418  public $clientInfo = array();
419 
426  public $RTEenabled = FALSE;
427 
436 
443  public $RTEcounter = 0;
444 
451  public $colorScheme = array();
452 
459  public $classScheme = array();
460 
467  public $defColorScheme = array();
468 
475  public $defClassScheme = array();
476 
483  public $fieldStyle = NULL;
484 
491  public $borderStyle = NULL;
492 
499  public $commentMessages = array();
500 
501  // INTERNAL, templates
508  public $totalWrap = '<hr />|<hr />';
509 
516  public $fieldTemplate = '<strong>###FIELD_NAME###</strong><br />###FIELD_ITEM###<hr />';
517 
523  protected $paletteFieldTemplate = '';
524 
531  public $sectionWrap = '';
532 
540 
547  public $palFieldTemplate = '';
548 
556  public $palettesRendered = array();
557 
567  public $hiddenFieldListArr = array();
568 
576  public $requiredFields = array();
577 
586  public $requiredAdditional = array();
587 
595  public $requiredElements = array();
596 
603  public $requiredNested = array();
604 
611  public $renderDepth = 0;
612 
619  public $savedSchemes = array();
620 
627  public $dynNestedStack = array();
628 
629  // Internal, registers for user defined functions etc.
636  public $additionalCode_pre = array();
637 
644  public $additionalJS_pre = array();
645 
652  public $additionalJS_post = array();
653 
661  public $additionalJS_submit = array();
662 
670  public $additionalJS_delete = array();
671 
676  public $inline;
677 
684  public $hookObjectsMainFields = array();
685 
692  public $hookObjectsSingleField = array();
693 
700  public $extraFormHeaders = array();
701 
707  public $templateFile = '';
708 
712  protected $multiSelectFilterCount = 0;
713 
717  protected $suggest;
718 
724  public function __construct() {
725  $this->clientInfo = GeneralUtility::clientInfo();
726  $this->RTEenabled = $this->getBackendUserAuthentication()->isRTE();
727  if (!$this->RTEenabled) {
728  $this->RTEenabled_notReasons = implode(LF, $this->getBackendUserAuthentication()->RTE_errors);
729  $this->commentMessages[] = 'RTE NOT ENABLED IN SYSTEM due to:' . LF . $this->RTEenabled_notReasons;
730  }
731  // Default color+class scheme
732  $docTemplate = $this->getControllerDocumentTemplate();
733  $this->defColorScheme = array(
734  $docTemplate->bgColor,
735  // Background for the field AND palette
736  GeneralUtility::modifyHTMLColorAll($docTemplate->bgColor, -20),
737  // Background for the field header
738  GeneralUtility::modifyHTMLColorAll($docTemplate->bgColor, -10),
739  // Background for the palette field header
740  'black',
741  // Field header font color
742  '#666666'
743  );
744  $this->defColorScheme = array();
745  // Override / Setting defaults from TBE_STYLES array
746  $this->resetSchemes();
747  // Setting the current colorScheme to default.
748  $this->defColorScheme = $this->colorScheme;
749  $this->defClassScheme = $this->classScheme;
750  // Define whitelist that allows TCA field configuration to be overridden by TSconfig, @see overrideFieldConf():
751  $this->allowOverrideMatrix = array(
752  'input' => array('size', 'max', 'readOnly'),
753  'text' => array('cols', 'rows', 'wrap', 'readOnly'),
754  'check' => array('cols', 'showIfRTE', 'readOnly'),
755  'select' => array('size', 'autoSizeMax', 'maxitems', 'minitems', 'readOnly', 'treeConfig'),
756  'group' => array('size', 'autoSizeMax', 'max_size', 'show_thumbs', 'maxitems', 'minitems', 'disable_controls', 'readOnly'),
757  'inline' => array('appearance', 'behaviour', 'foreign_label', 'foreign_selector', 'foreign_unique', 'maxitems', 'minitems', 'size', 'autoSizeMax', 'symmetric_label', 'readOnly')
758  );
759  // Create instance of InlineElement only if this a non-IRRE-AJAX call:
760  if (!isset($GLOBALS['ajaxID']) || strpos($GLOBALS['ajaxID'], 'TYPO3\\CMS\\Backend\\Form\\Element\\InlineElement::') !== 0) {
761  $this->inline = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\Element\\InlineElement');
762  }
763  // Create instance of \TYPO3\CMS\Backend\Form\Element\SuggestElement only if this a non-Suggest-AJAX call:
764  if (!isset($GLOBALS['ajaxID']) || strpos($GLOBALS['ajaxID'], 'TYPO3\\CMS\\Backend\\Form\\Element\\SuggestElement::') !== 0) {
765  $this->suggest = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\Element\\SuggestElement');
766  }
767  // Prepare user defined objects (if any) for hooks which extend this function:
768  $this->hookObjectsMainFields = array();
769  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getMainFieldsClass'])) {
770  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getMainFieldsClass'] as $classRef) {
771  $this->hookObjectsMainFields[] = GeneralUtility::getUserObj($classRef);
772  }
773  }
774  $this->hookObjectsSingleField = array();
775  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getSingleFieldClass'])) {
776  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getSingleFieldClass'] as $classRef) {
777  $this->hookObjectsSingleField[] = GeneralUtility::getUserObj($classRef);
778  }
779  }
780  $this->templateFile = 'sysext/backend/Resources/Private/Templates/FormEngine.html';
781  }
782 
789  public function initDefaultBEmode() {
790  $this->prependFormFieldNames = 'data';
791  $this->formName = 'editform';
792  $this->setNewBEDesign();
793  $this->edit_showFieldHelp = (bool)$this->getBackendUserAuthentication()->uc['edit_showFieldHelp'];
794  $this->edit_docModuleUpload = (bool)$this->getBackendUserAuthentication()->uc['edit_docModuleUpload'];
795  $this->inline->init($this);
796  $this->suggest->init($this);
797  }
798 
799  /*******************************************************
800  *
801  * Rendering the forms, fields etc
802  *
803  *******************************************************/
816  public function getSoloField($table, $row, $theFieldToReturn) {
817  if (!isset($GLOBALS['TCA'][$table])) {
818  return NULL;
819  }
820  $typeNum = $this->getRTypeNum($table, $row);
821  if (isset($GLOBALS['TCA'][$table]['types'][$typeNum])) {
822  $itemList = $GLOBALS['TCA'][$table]['types'][$typeNum]['showitem'];
823  if ($itemList) {
824  $fields = GeneralUtility::trimExplode(',', $itemList, TRUE);
825  $excludeElements = $this->getExcludeElements($table, $row, $typeNum);
826  foreach ($fields as $fieldInfo) {
827  $parts = explode(';', $fieldInfo);
828  $theField = trim($parts[0]);
829  if (!in_array($theField, $excludeElements) && (string)$theField === (string)$theFieldToReturn) {
830  if ($GLOBALS['TCA'][$table]['columns'][$theField]) {
831  $sField = $this->getSingleField($table, $theField, $row, $parts[1], 1, $parts[3], $parts[2]);
832  return $sField['ITEM'];
833  }
834  }
835  }
836  }
837  }
838  return NULL;
839  }
840 
855  public function getMainFields($table, array $row, $depth = 0, array $overruleTypesArray = array()) {
856  $this->renderDepth = $depth;
857  // Init vars:
858  $out_array = array(array());
859  $out_array_meta = array(
860  array(
861  'title' => $this->getLL('l_generalTab')
862  )
863  );
864  $out_pointer = 0;
865  $out_sheet = 0;
866  $this->palettesRendered = array();
867  $this->palettesRendered[$this->renderDepth][$table] = array();
868  // Hook: getMainFields_preProcess (requested by Thomas Hempel for use with the "dynaflex" extension)
869  foreach ($this->hookObjectsMainFields as $hookObj) {
870  if (method_exists($hookObj, 'getMainFields_preProcess')) {
871  $hookObj->getMainFields_preProcess($table, $row, $this);
872  }
873  }
874  $tabIdentString = '';
875  $tabIdentStringMD5 = '';
876  if ($GLOBALS['TCA'][$table]) {
877  // Get dividers2tabs setting from TCA of the current table:
878  $dividers2tabs = &$GLOBALS['TCA'][$table]['ctrl']['dividers2tabs'];
879  // Load the description content for the table.
880  if ($this->edit_showFieldHelp || $this->doLoadTableDescr($table)) {
881  $this->getLanguageService()->loadSingleTableDescription($table);
882  }
883  // Get the current "type" value for the record.
884  $typeNum = $this->getRTypeNum($table, $row);
885  // Find the list of fields to display:
886  if ($GLOBALS['TCA'][$table]['types'][$typeNum]) {
887  $itemList = $GLOBALS['TCA'][$table]['types'][$typeNum]['showitem'];
888  if (is_array($overruleTypesArray) && isset($overruleTypesArray[$typeNum]['showitem'])) {
889  $itemList = $overruleTypesArray[$typeNum]['showitem'];
890  }
891  // If such a list existed...
892  if ($itemList) {
893  // Explode the field list and possibly rearrange the order of the fields, if configured for
894  $fields = GeneralUtility::trimExplode(',', $itemList, TRUE);
895  if ($this->fieldOrder) {
896  $fields = $this->rearrange($fields);
897  }
898  // Get excluded fields, added fiels and put it together:
899  $excludeElements = $this->getExcludeElements($table, $row, $typeNum);
900  $fields = $this->mergeFieldsWithAddedFields($fields, $this->getFieldsToAdd($table, $row, $typeNum), $table);
901  // If TCEforms will render a tab menu in the next step, push the name to the tab stack:
902  if (strstr($itemList, '--div--') !== FALSE && $this->enableTabMenu && $dividers2tabs) {
903  $tabIdentString = 'TCEforms:' . $table . ':' . $row['uid'];
904  $tabIdentStringMD5 = $this->getDocumentTemplate()->getDynTabMenuId($tabIdentString);
905  // Remember that were currently working on the general tab:
906  if (isset($fields[0]) && strpos($fields[0], '--div--') !== 0) {
907  $this->pushToDynNestedStack('tab', $tabIdentStringMD5 . '-1');
908  }
909  }
910  // Traverse the fields to render:
911  $cc = 0;
912  foreach ($fields as $fieldInfo) {
913  // Exploding subparts of the field configuration:
914  $parts = explode(';', $fieldInfo);
915  // Getting the style information out:
916  $color_style_parts = GeneralUtility::trimExplode('-', $parts[4]);
917  if ($color_style_parts[0] !== '') {
918  $this->setColorScheme($GLOBALS['TBE_STYLES']['colorschemes'][(int)$color_style_parts[0]]);
919  }
920  if ($color_style_parts[1] !== '') {
921  $this->fieldStyle = $GLOBALS['TBE_STYLES']['styleschemes'][(int)$color_style_parts[1]];
922  if (!isset($this->fieldStyle)) {
923  $this->fieldStyle = $GLOBALS['TBE_STYLES']['styleschemes'][0];
924  }
925  }
926  if ($color_style_parts[2] !== '') {
927  $this->wrapBorder($out_array[$out_sheet], $out_pointer);
928  $this->borderStyle = $GLOBALS['TBE_STYLES']['borderschemes'][(int)$color_style_parts[2]];
929  if (!isset($this->borderStyle)) {
930  $this->borderStyle = $GLOBALS['TBE_STYLES']['borderschemes'][0];
931  }
932  }
933  // Render the field:
934  $theField = $parts[0];
935  if (!in_array($theField, $excludeElements)) {
936  if ($GLOBALS['TCA'][$table]['columns'][$theField]) {
937  $sFieldPal = '';
938  if ($parts[2] && !isset($this->palettesRendered[$this->renderDepth][$table][$parts[2]])) {
939  $sFieldPal = $this->getPaletteFields($table, $row, $parts[2]);
940  $this->palettesRendered[$this->renderDepth][$table][$parts[2]] = 1;
941  }
942  $sField = $this->getSingleField($table, $theField, $row, $parts[1], 0, $parts[3], $parts[2]);
943  if ($sField) {
944  $sField .= $sFieldPal;
945  }
946  $out_array[$out_sheet][$out_pointer] .= $sField;
947  } elseif ($theField == '--div--') {
948  if ($cc > 0) {
949  $out_array[$out_sheet][$out_pointer] .= $this->getDivider();
950  if ($this->enableTabMenu && $dividers2tabs) {
951  $this->wrapBorder($out_array[$out_sheet], $out_pointer);
952  // Remove last tab entry from the dynNestedStack:
953  $out_sheet++;
954  // Remove the previous sheet from stack (if any):
955  $this->popFromDynNestedStack('tab', $tabIdentStringMD5 . '-' . $out_sheet);
956  // Remember on which sheet we're currently working:
957  $this->pushToDynNestedStack('tab', $tabIdentStringMD5 . '-' . ($out_sheet + 1));
958  $out_array[$out_sheet] = array();
959  $out_array_meta[$out_sheet]['title'] = $this->sL($parts[1]);
960  // Register newline for Tab
961  $out_array_meta[$out_sheet]['newline'] = $parts[2] == 'newline';
962  }
963  } else {
964  // Setting alternative title for "General" tab if "--div--" is the very first element.
965  $out_array_meta[$out_sheet]['title'] = $this->sL($parts[1]);
966  // Only add the first tab to the dynNestedStack if there are more tabs:
967  if ($tabIdentString && strpos($itemList, '--div--', strlen($fieldInfo))) {
968  $this->pushToDynNestedStack('tab', $tabIdentStringMD5 . '-1');
969  }
970  }
971  } elseif ($theField == '--palette--') {
972  if ($parts[2] && !isset($this->palettesRendered[$this->renderDepth][$table][$parts[2]])) {
973  // Render a 'header' if not collapsed
974  if ($GLOBALS['TCA'][$table]['palettes'][$parts[2]]['canNotCollapse'] && $parts[1]) {
975  $out_array[$out_sheet][$out_pointer] .= $this->getPaletteFields($table, $row, $parts[2], $this->sL($parts[1]));
976  } else {
977  $out_array[$out_sheet][$out_pointer] .= $this->getPaletteFields($table, $row, $parts[2], '', '', $this->sL($parts[1]));
978  }
979  $this->palettesRendered[$this->renderDepth][$table][$parts[2]] = 1;
980  }
981  }
982  }
983  $cc++;
984  }
985  }
986  }
987  }
988  // Hook: getMainFields_postProcess (requested by Thomas Hempel for use with the "dynaflex" extension)
989  foreach ($this->hookObjectsMainFields as $hookObj) {
990  if (method_exists($hookObj, 'getMainFields_postProcess')) {
991  $hookObj->getMainFields_postProcess($table, $row, $this);
992  }
993  }
994  // Wrapping a border around it all:
995  $this->wrapBorder($out_array[$out_sheet], $out_pointer);
996  // Resetting styles:
997  $this->resetSchemes();
998  // Rendering Main palettes, if any
999  $mParr = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['mainpalette']);
1000  $i = 0;
1001  if (count($mParr)) {
1002  foreach ($mParr as $mP) {
1003  if (!isset($this->palettesRendered[$this->renderDepth][$table][$mP])) {
1004  $temp_palettesCollapsed = $this->palettesCollapsed;
1005  $this->palettesCollapsed = FALSE;
1006  $label = $i == 0 ? $this->getLL('l_generalOptions') : $this->getLL('l_generalOptions_more');
1007  $out_array[$out_sheet][$out_pointer] .= $this->getPaletteFields($table, $row, $mP, $label);
1008  $this->palettesCollapsed = $temp_palettesCollapsed;
1009  $this->palettesRendered[$this->renderDepth][$table][$mP] = 1;
1010  }
1011  $this->wrapBorder($out_array[$out_sheet], $out_pointer);
1012  $i++;
1013  if ($this->renderDepth) {
1014  $this->renderDepth--;
1015  }
1016  }
1017  }
1018  // Return the imploded $out_array:
1019  // There were --div-- dividers around...
1020  if ($out_sheet > 0) {
1021  // Create parts array for the tab menu:
1022  $parts = array();
1023  foreach ($out_array as $idx => $sheetContent) {
1024  $content = implode('', $sheetContent);
1025  if ($content) {
1026  // Wrap content (row) with table-tag, otherwise tab/sheet will be disabled (see getdynTabMenu() )
1027  $content = '<table border="0" cellspacing="0" cellpadding="0" width="100%">' . $content . '</table>';
1028  }
1029  $parts[$idx] = array(
1030  'label' => $out_array_meta[$idx]['title'],
1031  'content' => $content,
1032  'newline' => $out_array_meta[$idx]['newline']
1033  );
1034  }
1035  if (count($parts) > 1) {
1036  // Unset the current level of tab menus:
1037  $this->popFromDynNestedStack('tab', $tabIdentStringMD5 . '-' . ($out_sheet + 1));
1038  $dividersToTabsBehaviour = isset($GLOBALS['TCA'][$table]['ctrl']['dividers2tabs']) ? $GLOBALS['TCA'][$table]['ctrl']['dividers2tabs'] : 1;
1039  $output = $this->getDynTabMenu($parts, $tabIdentString, $dividersToTabsBehaviour);
1040  } else {
1041  // If there is only one tab/part there is no need to wrap it into the dynTab code
1042  $output = isset($parts[0]) ? trim($parts[0]['content']) : '';
1043  }
1044  $output = '
1045  <tr>
1046  <td colspan="2">
1047  ' . $output . '
1048  </td>
1049  </tr>';
1050  } else {
1051  // Only one tab, so just implode and wrap the background image (= tab container) around:
1052  $output = implode('', $out_array[$out_sheet]);
1053  $output = '<div class="typo3-dyntabmenu-divs">' . $output . '</div>';
1054  }
1055 
1056  return $output;
1057  }
1058 
1070  public function getListedFields($table, $row, $list) {
1071  if ($this->edit_showFieldHelp || $this->doLoadTableDescr($table)) {
1072  $this->getLanguageService()->loadSingleTableDescription($table);
1073  }
1074  $out = '';
1075  $types_fieldConfig = BackendUtility::getTCAtypes($table, $row, 1);
1076  $editFieldList = array_unique(GeneralUtility::trimExplode(',', $list, TRUE));
1077  foreach ($editFieldList as $theFieldC) {
1078  list($theField, $palFields) = preg_split('/\\[|\\]/', $theFieldC);
1079  $theField = trim($theField);
1080  $palFields = trim($palFields);
1081  if ($GLOBALS['TCA'][$table]['columns'][$theField]) {
1082  $parts = GeneralUtility::trimExplode(';', $types_fieldConfig[$theField]['origString']);
1083  // Don't sent palette pointer - there are no options anyways for a field-list.
1084  $sField = $this->getSingleField($table, $theField, $row, $parts[1], 0, $parts[3], 0);
1085  $out .= $sField;
1086  } elseif ($theField == '--div--') {
1087  $out .= $this->getDivider();
1088  }
1089  if ($palFields) {
1090  $out .= $this->getPaletteFields($table, $row, '', '', implode(',', GeneralUtility::trimExplode('|', $palFields, TRUE)));
1091  }
1092  }
1093  return $out;
1094  }
1095 
1108  public function getPaletteFields($table, $row, $palette, $header = '', $itemList = '', $collapsedHeader = NULL) {
1109  if (!$this->doPrintPalette) {
1110  return '';
1111  }
1112  $out = '';
1113  $parts = $this->loadPaletteElements($table, $row, $palette, $itemList);
1114  // Put palette together if there are fields in it:
1115  if (count($parts)) {
1116  $realFields = 0;
1117  foreach ($parts as $part) {
1118  if ($part['NAME'] !== '--linebreak--') {
1119  $realFields++;
1120  }
1121  }
1122  if ($realFields > 0) {
1123  if ($header) {
1124  $out .= $this->intoTemplate(array('HEADER' => htmlspecialchars($header)), $this->palFieldTemplateHeader);
1125  }
1126  $collapsed = $this->isPalettesCollapsed($table, $palette);
1127  // Check if the palette is a hidden palette
1128  $isHiddenPalette = !empty($GLOBALS['TCA'][$table]['palettes'][$palette]['isHiddenPalette']);
1129  $thePalIcon = '';
1130  if ($collapsed && $collapsedHeader !== NULL && !$isHiddenPalette) {
1131  list($thePalIcon, ) = $this->wrapOpenPalette(IconUtility::getSpriteIcon('actions-system-options-view', array('title' => htmlspecialchars($this->getLL('l_moreOptions')))), $table, $row, $palette, 1);
1132  $thePalIcon = '<span style="margin-left: 20px;">' . $thePalIcon . $collapsedHeader . '</span>';
1133  }
1134  $paletteHtml = $this->wrapPaletteField($this->printPalette($parts), $table, $row, $palette, $collapsed);
1135  $out .= $this->intoTemplate(array('PALETTE' => $thePalIcon . $paletteHtml), $this->palFieldTemplate);
1136  }
1137  }
1138  return $out;
1139  }
1140 
1154  public function getSingleField($table, $field, $row, $altName = '', $palette = FALSE, $extra = '', $pal = 0) {
1155  // Hook: getSingleField_preProcess
1156  foreach ($this->hookObjectsSingleField as $hookObj) {
1157  if (method_exists($hookObj, 'getSingleField_preProcess')) {
1158  $hookObj->getSingleField_preProcess($table, $field, $row, $altName, $palette, $extra, $pal, $this);
1159  }
1160  }
1161  $out = '';
1162  $PA = array();
1163  $PA['altName'] = $altName;
1164  $PA['palette'] = $palette;
1165  $PA['extra'] = $extra;
1166  $PA['pal'] = $pal;
1167  // Get the TCA configuration for the current field:
1168  $PA['fieldConf'] = $GLOBALS['TCA'][$table]['columns'][$field];
1169  $PA['fieldConf']['config']['form_type'] = $PA['fieldConf']['config']['form_type'] ?: $PA['fieldConf']['config']['type'];
1170 
1171  // Using "form_type" locally in this script
1172  $skipThisField = $this->inline->skipField($table, $field, $row, $PA['fieldConf']['config']);
1173 
1174  // Evaluate display condition
1175  $displayConditionResult = TRUE;
1176  if (is_array($PA['fieldConf']) && $PA['fieldConf']['displayCond'] && is_array($row)) {
1178  $elementConditionMatcher = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\ElementConditionMatcher');
1179  $displayConditionResult = $elementConditionMatcher->match($PA['fieldConf']['displayCond'], $row);
1180  }
1181  // Check if this field is configured and editable (according to excludefields + other configuration)
1182  if (
1183  is_array($PA['fieldConf'])
1184  && !$skipThisField
1185  && (!$PA['fieldConf']['exclude'] || $this->getBackendUserAuthentication()->check('non_exclude_fields', $table . ':' . $field))
1186  && $PA['fieldConf']['config']['form_type'] != 'passthrough'
1187  && ($this->RTEenabled || !$PA['fieldConf']['config']['showIfRTE'])
1188  && $displayConditionResult
1189  && (!$GLOBALS['TCA'][$table]['ctrl']['languageField'] || $PA['fieldConf']['l10n_display'] || ($PA['fieldConf']['l10n_mode'] !== 'exclude') || $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] <= 0)
1190  && (!$GLOBALS['TCA'][$table]['ctrl']['languageField'] || !$this->localizationMode || $this->localizationMode === $PA['fieldConf']['l10n_cat'])
1191  ) {
1192  // Fetching the TSconfig for the current table/field. This includes the $row which means that
1193  $PA['fieldTSConfig'] = $this->setTSconfig($table, $row, $field);
1194  // If the field is NOT disabled from TSconfig (which it could have been) then render it
1195  if (!$PA['fieldTSConfig']['disabled']) {
1196  // Override fieldConf by fieldTSconfig:
1197  $PA['fieldConf']['config'] = $this->overrideFieldConf($PA['fieldConf']['config'], $PA['fieldTSConfig']);
1198  // Init variables:
1199  $PA['itemFormElName'] = $this->prependFormFieldNames . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
1200  // Form field name, in case of file uploads
1201  $PA['itemFormElName_file'] = $this->prependFormFieldNames_file . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
1202  // Form field name, to activate elements
1203  // If the "eval" list contains "null", elements can be deactivated which results in storing NULL to database
1204  $PA['itemFormElNameActive'] = $this->prependFormFieldNamesActive . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
1205  // The value to show in the form field.
1206  $PA['itemFormElValue'] = $row[$field];
1207  $PA['itemFormElID'] = $this->prependFormFieldNames . '_' . $table . '_' . $row['uid'] . '_' . $field;
1208  // Set field to read-only if configured for translated records to show default language content as readonly
1209  if ($PA['fieldConf']['l10n_display'] && GeneralUtility::inList($PA['fieldConf']['l10n_display'], 'defaultAsReadonly') && $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0) {
1210  $PA['fieldConf']['config']['readOnly'] = TRUE;
1211  $PA['itemFormElValue'] = $this->defaultLanguageData[$table . ':' . $row['uid']][$field];
1212  }
1213  if (strpos($GLOBALS['TCA'][$table]['ctrl']['type'], ':') === FALSE) {
1214  $typeField = $GLOBALS['TCA'][$table]['ctrl']['type'];
1215  } else {
1216  $typeField = substr($GLOBALS['TCA'][$table]['ctrl']['type'], 0, strpos($GLOBALS['TCA'][$table]['ctrl']['type'], ':'));
1217  }
1218  // 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"
1219  if (
1220  !empty($GLOBALS['TCA'][$table]['ctrl']['type'])
1221  && $field === $typeField
1222  || !empty($GLOBALS['TCA'][$table]['ctrl']['requestUpdate'])
1223  && GeneralUtility::inList(str_replace(' ', '', $GLOBALS['TCA'][$table]['ctrl']['requestUpdate']), $field)
1224  ) {
1225  if ($this->getBackendUserAuthentication()->jsConfirmation(1)) {
1226  $alertMsgOnChange = 'if (confirm(TBE_EDITOR.labels.onChangeAlert) && TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
1227  } else {
1228  $alertMsgOnChange = 'if (TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
1229  }
1230  } else {
1231  $alertMsgOnChange = '';
1232  }
1233  // Render as a hidden field?
1234  if (in_array($field, $this->hiddenFieldListArr)) {
1235  $this->hiddenFieldAccum[] = '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
1236  } else {
1237  // Render as a normal field:
1238  // 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.
1239  $palJSfunc = '';
1240  $thePalIcon = '';
1241  if (!$PA['palette']) {
1242  $paletteFields = $this->loadPaletteElements($table, $row, $PA['pal']);
1243  if ($PA['pal'] && $this->isPalettesCollapsed($table, $PA['pal']) && count($paletteFields)) {
1244  list($thePalIcon, $palJSfunc) = $this->wrapOpenPalette(IconUtility::getSpriteIcon('actions-system-options-view', array('title' => htmlspecialchars($this->getLL('l_moreOptions')))), $table, $row, $PA['pal'], 1);
1245  }
1246  }
1247  // onFocus attribute to add to the field:
1248  $PA['onFocus'] = $palJSfunc && !$this->getBackendUserAuthentication()->uc['dontShowPalettesOnFocusInAB'] ? ' onfocus="' . htmlspecialchars($palJSfunc) . '"' : '';
1249  $PA['label'] = $PA['altName'] ?: $PA['fieldConf']['label'];
1250  $PA['label'] = $PA['fieldTSConfig']['label'] ?: $PA['label'];
1251  $PA['label'] = $PA['fieldTSConfig']['label.'][$this->getLanguageService()->lang] ?: $PA['label'];
1252  $PA['label'] = $this->sL($PA['label']);
1253  // JavaScript code for event handlers:
1254  $PA['fieldChangeFunc'] = array();
1255  $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'TBE_EDITOR.fieldChanged(\'' . $table . '\',\'' . $row['uid'] . '\',\'' . $field . '\',\'' . $PA['itemFormElName'] . '\');';
1256  $PA['fieldChangeFunc']['alert'] = $alertMsgOnChange;
1257  // If this is the child of an inline type and it is the field creating the label
1258  if ($this->inline->isInlineChildAndLabelField($table, $field)) {
1259  $inlineObjectId = implode(InlineElement::Structure_Separator, array(
1260  $this->inline->inlineNames['object'],
1261  $table,
1262  $row['uid']
1263  ));
1264  $PA['fieldChangeFunc']['inline'] = 'inline.handleChangedField(\'' . $PA['itemFormElName'] . '\',\'' . $inlineObjectId . '\');';
1265  }
1266  // Based on the type of the item, call a render function:
1267  $item = $this->getSingleField_SW($table, $field, $row, $PA);
1268  // Add language + diff
1269  if ($PA['fieldConf']['l10n_display'] && (GeneralUtility::inList($PA['fieldConf']['l10n_display'], 'hideDiff') || GeneralUtility::inList($PA['fieldConf']['l10n_display'], 'defaultAsReadonly'))) {
1270  $renderLanguageDiff = FALSE;
1271  } else {
1272  $renderLanguageDiff = TRUE;
1273  }
1274  if ($renderLanguageDiff) {
1275  $item = $this->renderDefaultLanguageContent($table, $field, $row, $item);
1276  $item = $this->renderDefaultLanguageDiff($table, $field, $row, $item);
1277  }
1278  // 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
1279  $label = htmlspecialchars($PA['label'], ENT_COMPAT, 'UTF-8', FALSE);
1280  if (MathUtility::canBeInterpretedAsInteger($row['uid']) && $PA['fieldTSConfig']['linkTitleToSelf'] && !GeneralUtility::_GP('columnsOnly')) {
1281  $lTTS_url = $this->backPath . 'alt_doc.php?edit[' . $table . '][' . $row['uid'] . ']=edit&columnsOnly=' . $field . '&returnUrl=' . rawurlencode($this->thisReturnUrl());
1282  $label = '<a href="' . htmlspecialchars($lTTS_url) . '">' . $label . '</a>';
1283  }
1284 
1285  if (isset($PA['fieldConf']['config']['mode']) && $PA['fieldConf']['config']['mode'] == 'useOrOverridePlaceholder') {
1286  $placeholder = $this->getPlaceholderValue($table, $field, $PA['fieldConf']['config'], $row);
1287  $onChange = 'typo3form.fieldTogglePlaceholder(' . GeneralUtility::quoteJSvalue($PA['itemFormElName']) . ', !this.checked)';
1288  $checked = $PA['itemFormElValue'] === NULL ? '' : ' checked="checked"';
1289 
1290  $this->additionalJS_post[] = 'typo3form.fieldTogglePlaceholder('
1291  . GeneralUtility::quoteJSvalue($PA['itemFormElName']) . ', ' . ($checked ? 'false' : 'true') . ');';
1292 
1293  $item = '<div class="t3-form-field-placeholder-override">'
1294  . '<span class="t3-tceforms-placeholder-override-checkbox">' .
1295  '<input type="hidden" name="' . htmlspecialchars($PA['itemFormElNameActive']) . '" value="0" />' .
1296  '<input type="checkbox" name="' . htmlspecialchars($PA['itemFormElNameActive']) . '" value="1" id="tce-forms-textfield-use-override-' . $field . '-' . $row['uid'] . '" onchange="' . htmlspecialchars($onChange) . '"' . $checked . ' />' .
1297  '<label for="tce-forms-textfield-use-override-' . $field . '-' . $row['uid'] . '">' .
1298  sprintf($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.placeholder.override'),
1299  BackendUtility::getRecordTitlePrep($placeholder, 20)) . '</label>' .
1300  '</span>'
1301  . '<div class="t3-form-placeholder-placeholder">' . $this->getSingleField_typeNone_render(
1302  $PA['fieldConf']['config'], GeneralUtility::fixed_lgd_cs($placeholder, 30)
1303  ) . '</div>'
1304  . '<div class="t3-form-placeholder-formfield">' . $item . '</div>'
1305  . '</div>';
1306  }
1307 
1308  // Wrap the label with help text
1309  $PA['label'] = ($label = BackendUtility::wrapInHelp($table, $field, $label));
1310  // Create output value:
1311  if ($PA['fieldConf']['config']['form_type'] == 'user' && $PA['fieldConf']['config']['noTableWrapping']) {
1312  $out = $item;
1313  } elseif ($PA['palette']) {
1314  // Array:
1315  $out = array(
1316  'NAME' => $label,
1317  'ID' => $row['uid'],
1318  'FIELD' => $field,
1319  'TABLE' => $table,
1320  'ITEM' => $item,
1321  'ITEM_DISABLED' => ($this->isDisabledNullValueField($table, $field, $row, $PA) ? ' disabled' : ''),
1322  'ITEM_NULLVALUE' => $this->renderNullValueWidget($table, $field, $row, $PA),
1323  );
1324  $out = $this->addUserTemplateMarkers($out, $table, $field, $row, $PA);
1325  } else {
1326  // String:
1327  $out = array(
1328  'NAME' => $label,
1329  'ITEM' => $item,
1330  'TABLE' => $table,
1331  'ID' => $row['uid'],
1332  'PAL_LINK_ICON' => $thePalIcon,
1333  'FIELD' => $field,
1334  'ITEM_DISABLED' => ($this->isDisabledNullValueField($table, $field, $row, $PA) ? ' disabled' : ''),
1335  'ITEM_NULLVALUE' => $this->renderNullValueWidget($table, $field, $row, $PA),
1336  );
1337  $out = $this->addUserTemplateMarkers($out, $table, $field, $row, $PA);
1338  // String:
1339  $out = $this->intoTemplate($out);
1340  }
1341  }
1342  } else {
1343  $this->commentMessages[] = $this->prependFormFieldNames . '[' . $table . '][' . $row['uid'] . '][' . $field . ']: Disabled by TSconfig';
1344  }
1345  }
1346  // Hook: getSingleField_postProcess
1347  foreach ($this->hookObjectsSingleField as $hookObj) {
1348  if (method_exists($hookObj, 'getSingleField_postProcess')) {
1349  $hookObj->getSingleField_postProcess($table, $field, $row, $out, $PA, $this);
1350  }
1351  }
1352  // Return value (string or array)
1353  return $out;
1354  }
1355 
1368  public function getSingleField_SW($table, $field, $row, &$PA) {
1369  $PA['fieldConf']['config']['form_type'] = $PA['fieldConf']['config']['form_type'] ?: $PA['fieldConf']['config']['type'];
1370  // Using "form_type" locally in this script
1371  // Hook: getSingleField_beforeRender
1372  foreach ($this->hookObjectsSingleField as $hookObject) {
1373  if (method_exists($hookObject, 'getSingleField_beforeRender')) {
1374  $hookObject->getSingleField_beforeRender($table, $field, $row, $PA);
1375  }
1376  }
1377  switch ($PA['fieldConf']['config']['form_type']) {
1378  case 'input':
1379  $item = $this->getSingleField_typeInput($table, $field, $row, $PA);
1380  break;
1381  case 'text':
1382  $item = $this->getSingleField_typeText($table, $field, $row, $PA);
1383  break;
1384  case 'check':
1385  $item = $this->getSingleField_typeCheck($table, $field, $row, $PA);
1386  break;
1387  case 'radio':
1388  $item = $this->getSingleField_typeRadio($table, $field, $row, $PA);
1389  break;
1390  case 'select':
1391  $item = $this->getSingleField_typeSelect($table, $field, $row, $PA);
1392  break;
1393  case 'group':
1394  $item = $this->getSingleField_typeGroup($table, $field, $row, $PA);
1395  break;
1396  case 'inline':
1397  $item = $this->inline->getSingleField_typeInline($table, $field, $row, $PA);
1398  break;
1399  case 'none':
1400  $item = $this->getSingleField_typeNone($table, $field, $row, $PA);
1401  break;
1402  case 'user':
1403  $item = $this->getSingleField_typeUser($table, $field, $row, $PA);
1404  break;
1405  case 'flex':
1406  $item = $this->getSingleField_typeFlex($table, $field, $row, $PA);
1407  break;
1408  default:
1409  $item = $this->getSingleField_typeUnknown($table, $field, $row, $PA);
1410  }
1411  return $item;
1412  }
1413 
1414  /**********************************************************
1415  *
1416  * Rendering of each TCEform field type
1417  *
1418  ************************************************************/
1430  public function getSingleField_typeInput($table, $field, $row, &$PA) {
1431  $config = $PA['fieldConf']['config'];
1432  $specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);
1433  $size = MathUtility::forceIntegerInRange($config['size'] ? $config['size'] : 30, 5, $this->maxInputWidth);
1434  $evalList = GeneralUtility::trimExplode(',', $config['eval'], TRUE);
1435  $classAndStyleAttributes = $this->formWidthAsArray($size);
1436  $fieldAppendix = '';
1437  $item = '';
1438  $cssClasses = array($classAndStyleAttributes['class']);
1439  $cssStyle = $classAndStyleAttributes['style'];
1440  if (!isset($config['checkbox'])) {
1441  $config['checkbox'] = '0';
1442  $checkboxIsset = FALSE;
1443  } else {
1444  $checkboxIsset = TRUE;
1445  }
1446  if (in_array('date', $evalList) || in_array('datetime', $evalList)) {
1447  if (in_array('datetime', $evalList)) {
1448  $class = 'datetime';
1449  } else {
1450  $class = 'date';
1451  }
1452  $dateRange = '';
1453  if (isset($config['range']['lower'])) {
1454  $dateRange .= ' lower-' . (int)$config['range']['lower'];
1455  }
1456  if (isset($config['range']['upper'])) {
1457  $dateRange .= ' upper-' . (int)$config['range']['upper'];
1458  }
1459  $inputId = uniqid('tceforms-' . $class . 'field-', TRUE);
1460  $cssClasses[] = 'tceforms-textfield tceforms-' . $class . 'field' . $dateRange;
1461  $fieldAppendix = IconUtility::getSpriteIcon('actions-edit-pick-date', array(
1462  'style' => 'cursor:pointer;',
1463  'id' => 'picker-' . $inputId
1464  ));
1465  } elseif (in_array('timesec', $evalList)) {
1466  $inputId = uniqid('tceforms-timesecfield-', TRUE);
1467  $cssClasses[] = 'tceforms-textfield tceforms-timesecfield';
1468  } elseif (in_array('year', $evalList)) {
1469  $inputId = uniqid('tceforms-yearfield-', TRUE);
1470  $cssClasses[] = 'tceforms-textfield tceforms-yearfield';
1471  } elseif (in_array('time', $evalList)) {
1472  $inputId = uniqid('tceforms-timefield-', TRUE);
1473  $cssClasses[] = 'tceforms-textfield tceforms-timefield';
1474  } elseif (in_array('int', $evalList)) {
1475  $inputId = uniqid('tceforms-intfield-', TRUE);
1476  $cssClasses[] = 'tceforms-textfield tceforms-intfield';
1477  } elseif (in_array('double2', $evalList)) {
1478  $inputId = uniqid('tceforms-double2field-', TRUE);
1479  $cssClasses[] = 'tceforms-textfield tceforms-double2field';
1480  } else {
1481  $inputId = uniqid('tceforms-textfield-', TRUE);
1482  $cssClasses[] = 'tceforms-textfield';
1483  if ($checkboxIsset === FALSE) {
1484  $config['checkbox'] = '';
1485  }
1486  }
1487  if (isset($config['wizards']['link'])) {
1488  $inputId = uniqid('tceforms-linkfield-', TRUE);
1489  $cssClasses[] = 'tceforms-textfield tceforms-linkfield';
1490  } elseif (isset($config['wizards']['color'])) {
1491  $inputId = uniqid('tceforms-colorfield-', TRUE);
1492  $cssClasses[] = 'tceforms-textfield tceforms-colorfield';
1493  }
1494  $inputId = str_replace('.', '', $inputId);
1495  if ($this->renderReadonly || $config['readOnly']) {
1496  $itemFormElValue = $PA['itemFormElValue'];
1497  if (in_array('date', $evalList)) {
1498  $config['format'] = 'date';
1499  } elseif (in_array('datetime', $evalList)) {
1500  $config['format'] = 'datetime';
1501  } elseif (in_array('time', $evalList)) {
1502  $config['format'] = 'time';
1503  }
1504  if (in_array('password', $evalList)) {
1505  $itemFormElValue = $itemFormElValue ? '*********' : '';
1506  }
1507  return $this->getSingleField_typeNone_render($config, $itemFormElValue);
1508  }
1509  foreach ($evalList as $func) {
1510  switch ($func) {
1511  case 'required':
1512  $this->registerRequiredProperty('field', $table . '_' . $row['uid'] . '_' . $field, $PA['itemFormElName']);
1513  // Mark this field for date/time disposal:
1514  if (array_intersect($evalList, array('date', 'datetime', 'time'))) {
1515  $this->requiredAdditional[$PA['itemFormElName']]['isPositiveNumber'] = TRUE;
1516  }
1517  break;
1518  default:
1519  // Pair hook to the one in \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_input_Eval()
1520  $evalObj = GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func] . ':&' . $func);
1521  if (is_object($evalObj) && method_exists($evalObj, 'deevaluateFieldValue')) {
1522  $_params = array(
1523  'value' => $PA['itemFormElValue']
1524  );
1525  $PA['itemFormElValue'] = $evalObj->deevaluateFieldValue($_params);
1526  }
1527  }
1528  }
1529  $paramsList = '\'' . $PA['itemFormElName'] . '\',\'' . implode(',', $evalList) . '\',\'' . trim($config['is_in']) . '\',' . ($checkboxIsset ? 1 : 0) . ',\'' . $config['checkbox'] . '\'';
1530  if (in_array('date', $evalList) || in_array('datetime', $evalList)) {
1531  $item .= '<span class="t3-tceforms-input-wrapper-datetime" onmouseOver="if (document.getElementById(\'' . $inputId . '\').value) {this.className=\'t3-tceforms-input-wrapper-datetime-hover\';} else {this.className=\'t3-tceforms-input-wrapper-datetime\';};" onmouseOut="this.className=\'t3-tceforms-input-wrapper-datetime\';">';
1532  // Add server timezone offset to UTC to our stored date
1533  if ($PA['itemFormElValue'] > 0) {
1534  $PA['itemFormElValue'] += date('Z', $PA['itemFormElValue']);
1535  }
1536  } else {
1537  $item .= '<span class="t3-tceforms-input-wrapper" onmouseOver="if (document.getElementById(\'' . $inputId . '\').value) {this.className=\'t3-tceforms-input-wrapper-hover\';} else {this.className=\'t3-tceforms-input-wrapper\';};" onmouseOut="this.className=\'t3-tceforms-input-wrapper\';">';
1538  }
1539  $PA['fieldChangeFunc'] = array_merge(array('typo3form.fieldGet' => 'typo3form.fieldGet(' . $paramsList . ');'), $PA['fieldChangeFunc']);
1540  // Old function "checkbox" now the option to set the date / remove the date
1541  if (isset($config['checkbox'])) {
1542  $item .= IconUtility::getSpriteIcon('actions-input-clear', array('tag' => 'a', 'class' => 't3-tceforms-input-clearer', 'onclick' => 'document.getElementById(\'' . $inputId . '\').value=\'\';document.getElementById(\'' . $inputId . '\').focus();' . implode('', $PA['fieldChangeFunc'])));
1543  }
1544  $mLgd = $config['max'] ?: 256;
1545  $iOnChange = implode('', $PA['fieldChangeFunc']);
1546  $cssClasses[] = 'hasDefaultValue';
1547  $item .= '<input type="text" ' . $this->getPlaceholderAttribute($table, $field, $config, $row) . 'id="' . $inputId . '" ' . 'class="' . implode(' ', $cssClasses) . '" ' . 'name="' . $PA['itemFormElName'] . '_hr" ' . 'value=""' . 'style="' . $cssStyle . '" ' . 'maxlength="' . $mLgd . '" ' . 'onchange="' . htmlspecialchars($iOnChange) . '"' . $PA['onFocus'] . ' />';
1548  // This is the EDITABLE form field.
1549  $item .= '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
1550  // 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.
1551  $item .= $fieldAppendix . '</span><div style="clear:both;"></div>';
1552  $this->extJSCODE .= 'typo3form.fieldSet(' . $paramsList . ');';
1553  // Going through all custom evaluations configured for this field
1554  foreach ($evalList as $evalData) {
1555  $evalObj = GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$evalData] . ':&' . $evalData);
1556  if (is_object($evalObj) && method_exists($evalObj, 'returnFieldJS')) {
1557  $this->extJSCODE .= '
1558 TBE_EDITOR.customEvalFunctions[\'' . $evalData . '\'] = function(value) {
1559 ' . $evalObj->returnFieldJS() . '
1560 }
1561 ';
1562  }
1563  }
1564  // Creating an alternative item without the JavaScript handlers.
1565  $altItem = '<input type="hidden" name="' . $PA['itemFormElName'] . '_hr" value="" />';
1566  $altItem .= '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
1567  // Wrap a wizard around the item?
1568  $item = $this->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $PA, $PA['itemFormElName'] . '_hr', $specConf);
1569 
1570  return $item;
1571  }
1572 
1583  protected function renderNullValueWidget($table, $field, array $row, array $PA) {
1584  $widget = '';
1585 
1586  $config = $PA['fieldConf']['config'];
1587  if (
1588  !empty($config['eval']) && GeneralUtility::inList($config['eval'], 'null')
1589  && (empty($config['mode']) || $config['mode'] !== 'useOrOverridePlaceholder')
1590  ) {
1591  $checked = $PA['itemFormElValue'] === NULL ? '' : ' checked="checked"';
1592  $onChange = htmlspecialchars(
1593  'typo3form.fieldSetNull(\'' . $PA['itemFormElName'] . '\', !this.checked)'
1594  );
1595 
1596  $widget = '<span class="t3-tceforms-widget-null-wrapper">' .
1597  '<input type="hidden" name="' . $PA['itemFormElNameActive'] . '" value="0" />' .
1598  '<input type="checkbox" name="' . $PA['itemFormElNameActive'] . '" value="1" onchange="' . $onChange . '"' . $checked . ' />' .
1599  '</span>';
1600  }
1601 
1602  return $widget;
1603  }
1604 
1615  protected function isDisabledNullValueField($table, $field, array $row, array $PA) {
1616  $result = FALSE;
1617 
1618  $config = $PA['fieldConf']['config'];
1619  if ($PA['itemFormElValue'] === NULL && !empty($config['eval'])
1620  && GeneralUtility::inList($config['eval'], 'null')
1621  && (empty($config['mode']) || $config['mode'] !== 'useOrOverridePlaceholder')) {
1622 
1623  $result = TRUE;
1624  }
1625 
1626  return $result;
1627  }
1628 
1640  public function getSingleField_typeText($table, $field, $row, &$PA) {
1641  // Init config:
1642  $config = $PA['fieldConf']['config'];
1643  $evalList = GeneralUtility::trimExplode(',', $config['eval'], TRUE);
1644  if ($this->renderReadonly || $config['readOnly']) {
1645  return $this->getSingleField_typeNone_render($config, $PA['itemFormElValue']);
1646  }
1647  // Setting columns number:
1648  $cols = MathUtility::forceIntegerInRange($config['cols'] ? $config['cols'] : 30, 5, $this->maxTextareaWidth);
1649  // Setting number of rows:
1650  $origRows = ($rows = MathUtility::forceIntegerInRange($config['rows'] ? $config['rows'] : 5, 1, 20));
1651  if (strlen($PA['itemFormElValue']) > $this->charsPerRow * 2) {
1652  $cols = $this->maxTextareaWidth;
1653  $rows = MathUtility::forceIntegerInRange(round(strlen($PA['itemFormElValue']) / $this->charsPerRow), count(explode(LF, $PA['itemFormElValue'])), 20);
1654  if ($rows < $origRows) {
1655  $rows = $origRows;
1656  }
1657  }
1658  if (in_array('required', $evalList)) {
1659  $this->requiredFields[$table . '_' . $row['uid'] . '_' . $field] = $PA['itemFormElName'];
1660  }
1661  // Init RTE vars:
1662  // Set TRUE, if the RTE is loaded; If not a normal textarea is shown.
1663  $RTEwasLoaded = 0;
1664  // Set TRUE, if the RTE would have been loaded if it wasn't for the disable-RTE flag in the bottom of the page...
1665  $RTEwouldHaveBeenLoaded = 0;
1666  // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist. Traditionally, this is where RTE configuration has been found.
1667  $specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);
1668  // Setting up the altItem form field, which is a hidden field containing the value
1669  $altItem = '<input type="hidden" name="' . htmlspecialchars($PA['itemFormElName']) . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
1670  $item = '';
1671  // If RTE is generally enabled (TYPO3_CONF_VARS and user settings)
1672  if ($this->RTEenabled) {
1673  $p = BackendUtility::getSpecConfParametersFromArray($specConf['rte_transform']['parameters']);
1674  // If the field is configured for RTE and if any flag-field is not set to disable it.
1675  if (isset($specConf['richtext']) && (!$p['flag'] || !$row[$p['flag']])) {
1676  BackendUtility::fixVersioningPid($table, $row);
1677  list($tscPID, $thePidValue) = $this->getTSCpid($table, $row['uid'], $row['pid']);
1678  // If the pid-value is not negative (that is, a pid could NOT be fetched)
1679  if ($thePidValue >= 0) {
1680  $RTEsetup = $this->getBackendUserAuthentication()->getTSConfig('RTE', BackendUtility::getPagesTSconfig($tscPID));
1681  $RTEtypeVal = BackendUtility::getTCAtypeValue($table, $row);
1682  $thisConfig = BackendUtility::RTEsetup($RTEsetup['properties'], $table, $field, $RTEtypeVal);
1683  if (!$thisConfig['disabled']) {
1684  if (!$this->disableRTE) {
1685  $this->RTEcounter++;
1686  // Find alternative relative path for RTE images/links:
1687  $eFile = RteHtmlParser::evalWriteFile($specConf['static_write'], $row);
1688  $RTErelPath = is_array($eFile) ? dirname($eFile['relEditFile']) : '';
1689  // Get RTE object, draw form and set flag:
1690  $RTEobj = BackendUtility::RTEgetObj();
1691  $item = $RTEobj->drawRTE($this, $table, $field, $row, $PA, $specConf, $thisConfig, $RTEtypeVal, $RTErelPath, $thePidValue);
1692  // Wizard:
1693  $item = $this->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $PA, $PA['itemFormElName'], $specConf, 1);
1694  $RTEwasLoaded = 1;
1695  } else {
1696  $RTEwouldHaveBeenLoaded = 1;
1697  $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!)';
1698  }
1699  } else {
1700  $this->commentMessages[] = $PA['itemFormElName'] . ': RTE is disabled by the Page TSconfig, "RTE"-key (eg. by RTE.default.disabled=0 or such)';
1701  }
1702  } else {
1703  $this->commentMessages[] = $PA['itemFormElName'] . ': PID value could NOT be fetched. Rare error, normally with new records.';
1704  }
1705  } else {
1706  if (!isset($specConf['richtext'])) {
1707  $this->commentMessages[] = $PA['itemFormElName'] . ': RTE was not configured for this field in TCA-types';
1708  }
1709  if (!(!$p['flag'] || !$row[$p['flag']])) {
1710  $this->commentMessages[] = $PA['itemFormElName'] . ': Field-flag (' . $PA['flag'] . ') has been set to disable RTE!';
1711  }
1712  }
1713  }
1714  // Display ordinary field if RTE was not loaded.
1715  if (!$RTEwasLoaded) {
1716  // Show message, if no RTE (field can only be edited with RTE!)
1717  if ($specConf['rte_only']) {
1718  $item = '<p><em>' . htmlspecialchars($this->getLL('l_noRTEfound')) . '</em></p>';
1719  } else {
1720  if ($specConf['nowrap']) {
1721  $wrap = 'off';
1722  } else {
1723  $wrap = $config['wrap'] ?: 'virtual';
1724  }
1725  $classes = array();
1726  if ($specConf['fixed-font']) {
1727  $classes[] = 'fixed-font';
1728  }
1729  if ($specConf['enable-tab']) {
1730  $classes[] = 'enable-tab';
1731  }
1732  $formWidthText = $this->formWidthText($cols, $wrap);
1733  // Extract class attributes from $formWidthText (otherwise it would be added twice to the output)
1734  $res = array();
1735  if (preg_match('/ class="(.+?)"/', $formWidthText, $res)) {
1736  $formWidthText = str_replace(' class="' . $res[1] . '"', '', $formWidthText);
1737  $classes = array_merge($classes, explode(' ', $res[1]));
1738  }
1739  if (count($classes)) {
1740  $class = ' class="tceforms-textarea ' . implode(' ', $classes) . '"';
1741  } else {
1742  $class = 'tceforms-textarea';
1743  }
1744  $evalList = GeneralUtility::trimExplode(',', $config['eval'], TRUE);
1745  foreach ($evalList as $func) {
1746  switch ($func) {
1747  case 'required':
1748  $this->registerRequiredProperty('field', $table . '_' . $row['uid'] . '_' . $field, $PA['itemFormElName']);
1749  break;
1750  default:
1751  // Pair hook to the one in \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_input_Eval()
1752  // and \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_text_Eval()
1753  $evalObj = GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func] . ':&' . $func);
1754  if (is_object($evalObj) && method_exists($evalObj, 'deevaluateFieldValue')) {
1755  $_params = array(
1756  'value' => $PA['itemFormElValue']
1757  );
1758  $PA['itemFormElValue'] = $evalObj->deevaluateFieldValue($_params);
1759  }
1760  }
1761  }
1762  $iOnChange = implode('', $PA['fieldChangeFunc']);
1763  $item .= '
1764  <textarea ' . 'id="' . str_replace('.', '', uniqid('tceforms-textarea-', TRUE)) . '" ' . 'name="' . $PA['itemFormElName']
1765  . '"' . $formWidthText . $class . ' ' . 'rows="' . $rows . '" ' . 'wrap="' . $wrap . '" ' . 'onchange="'
1766  . htmlspecialchars($iOnChange) . '"' . $this->getPlaceholderAttribute($table, $field, $config, $row)
1767  . $PA['onFocus'] . '>' . GeneralUtility::formatForTextarea($PA['itemFormElValue']) . '</textarea>';
1768  $item = $this->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $PA,
1769  $PA['itemFormElName'], $specConf, $RTEwouldHaveBeenLoaded);
1770  }
1771  }
1772  // Return field HTML:
1773  return $item;
1774  }
1775 
1787  public function getSingleField_typeCheck($table, $field, $row, &$PA) {
1788  $config = $PA['fieldConf']['config'];
1789  $item = '';
1790  $disabled = '';
1791  if ($this->renderReadonly || $config['readOnly']) {
1792  $disabled = ' disabled="disabled"';
1793  }
1794  // Traversing the array of items:
1795  $selItems = $this->initItemArray($PA['fieldConf']);
1796  if ($config['itemsProcFunc']) {
1797  $selItems = $this->procItems($selItems, $PA['fieldTSConfig']['itemsProcFunc.'], $config, $table, $row, $field);
1798  }
1799  if (!count($selItems)) {
1800  $selItems[] = array('', '');
1801  }
1802  $thisValue = (int)$PA['itemFormElValue'];
1803  $cols = (int)$config['cols'];
1804  $selItemsCount = count($selItems);
1805  if ($cols > 1) {
1806  $item .= '<table border="0" cellspacing="0" cellpadding="0" class="typo3-TCEforms-checkboxArray">';
1807  for ($c = 0; $c < $selItemsCount; $c++) {
1808  $p = $selItems[$c];
1809  if (!($c % $cols)) {
1810  $item .= '<tr>';
1811  }
1812  $cBP = $this->checkBoxParams($PA['itemFormElName'], $thisValue, $c, count($selItems), implode('', $PA['fieldChangeFunc']));
1813  $cBName = $PA['itemFormElName'] . '_' . $c;
1814  $cBID = $PA['itemFormElID'] . '_' . $c;
1815  $item .= '<td nowrap="nowrap">' . '<input type="checkbox"' . $this->insertDefStyle('check')
1816  . ' value="1" name="' . $cBName . '"' . $cBP . $disabled . ' id="' . $cBID . '" />'
1817  . $this->wrapLabels(('<label for="' . $cBID . '">' . htmlspecialchars($p[0]) . '</label>&nbsp;'))
1818  . '</td>';
1819  if ($c % $cols + 1 == $cols) {
1820  $item .= '</tr>';
1821  }
1822  }
1823  if ($c % $cols) {
1824  $rest = $cols - $c % $cols;
1825  for ($c = 0; $c < $rest; $c++) {
1826  $item .= '<td></td>';
1827  }
1828  if ($c > 0) {
1829  $item .= '</tr>';
1830  }
1831  }
1832  $item .= '</table>';
1833  } else {
1834  for ($c = 0; $c < $selItemsCount; $c++) {
1835  $p = $selItems[$c];
1836  $cBP = $this->checkBoxParams($PA['itemFormElName'], $thisValue, $c, count($selItems), implode('', $PA['fieldChangeFunc']));
1837  $cBName = $PA['itemFormElName'] . '_' . $c;
1838  $cBID = $PA['itemFormElID'] . '_' . $c;
1839  $item .= ($c > 0 ? '<br />' : '') . '<input type="checkbox"' . $this->insertDefStyle('check')
1840  . ' value="1" name="' . $cBName . '"' . $cBP . $PA['onFocus'] . $disabled . ' id="' . $cBID . '" />'
1841  . $this->wrapLabels('<label for="' . $cBID . '">' . htmlspecialchars($p[0]) . '</label>');
1842  }
1843  }
1844  if (!$disabled) {
1845  $item .= '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($thisValue) . '" />';
1846  }
1847  return $item;
1848  }
1849 
1861  public function getSingleField_typeRadio($table, $field, $row, &$PA) {
1862  $config = $PA['fieldConf']['config'];
1863  $item = '';
1864  $disabled = '';
1865  if ($this->renderReadonly || $config['readOnly']) {
1866  $disabled = ' disabled="disabled"';
1867  }
1868  // Get items for the array:
1869  $selItems = $this->initItemArray($PA['fieldConf']);
1870  if ($config['itemsProcFunc']) {
1871  $selItems = $this->procItems($selItems, $PA['fieldTSConfig']['itemsProcFunc.'], $config, $table, $row, $field);
1872  }
1873  // Traverse the items, making the form elements:
1874  $selItemsCount = count($selItems);
1875  for ($c = 0; $c < $selItemsCount; $c++) {
1876  $p = $selItems[$c];
1877  $rID = $PA['itemFormElID'] . '_' . $c;
1878  $rOnClick = implode('', $PA['fieldChangeFunc']);
1879  $rChecked = (string)$p[1] === (string)$PA['itemFormElValue'] ? ' checked="checked"' : '';
1880  $item .= '<input type="radio"' . $this->insertDefStyle('radio') . ' name="' . $PA['itemFormElName']
1881  . '" value="' . htmlspecialchars($p[1]) . '" onclick="' . htmlspecialchars($rOnClick) . '"' . $rChecked
1882  . $PA['onFocus'] . $disabled . ' id="' . $rID . '" />
1883  <label for="' . $rID . '">' . htmlspecialchars($p[0]) . '</label>
1884  <br />';
1885  }
1886  return $item;
1887  }
1888 
1901  public function getSingleField_typeSelect($table, $field, $row, &$PA) {
1902  // Field configuration from TCA:
1903  $config = $PA['fieldConf']['config'];
1904  $disabled = '';
1905  if ($this->renderReadonly || $config['readOnly']) {
1906  $disabled = ' disabled="disabled"';
1907  }
1908  // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist.
1909  $specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);
1910  $selItems = $this->getSelectItems($table, $field, $row, $PA);
1911 
1912  // Creating the label for the "No Matching Value" entry.
1913  $nMV_label = isset($PA['fieldTSConfig']['noMatchingValue_label'])
1914  ? $this->sL($PA['fieldTSConfig']['noMatchingValue_label'])
1915  : '[ ' . $this->getLL('l_noMatchingValue') . ' ]';
1916  // Prepare some values:
1917  $maxitems = (int)$config['maxitems'];
1918  // If a SINGLE selector box...
1919  if ($maxitems <= 1 && $config['renderMode'] !== 'tree') {
1920  $item = $this->getSingleField_typeSelect_single($table, $field, $row, $PA, $config, $selItems, $nMV_label);
1921  } elseif ($config['renderMode'] === 'checkbox') {
1922  // Checkbox renderMode
1923  $item = $this->getSingleField_typeSelect_checkbox($table, $field, $row, $PA, $config, $selItems, $nMV_label);
1924  } elseif ($config['renderMode'] === 'singlebox') {
1925  // Single selector box renderMode
1926  $item = $this->getSingleField_typeSelect_singlebox($table, $field, $row, $PA, $config, $selItems, $nMV_label);
1927  } elseif ($config['renderMode'] === 'tree') {
1928  // Tree renderMode
1929  $treeClass = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\Element\\TreeElement', $this);
1930  $item = $treeClass->renderField($table, $field, $row, $PA, $config, $selItems, $nMV_label);
1931  // Register the required number of elements
1932  $minitems = MathUtility::forceIntegerInRange($config['minitems'], 0);
1933  $this->registerRequiredProperty('range', $PA['itemFormElName'], array($minitems, $maxitems, 'imgName' => $table . '_' . $row['uid'] . '_' . $field));
1934  } else {
1935  // Traditional multiple selector box:
1936  $item = $this->getSingleField_typeSelect_multiple($table, $field, $row, $PA, $config, $selItems, $nMV_label);
1937  }
1938  // Wizards:
1939  if (!$disabled) {
1940  $altItem = '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
1941  $item = $this->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $PA, $PA['itemFormElName'], $specConf);
1942  }
1943  return $item;
1944  }
1945 
1957  public function getSelectItems($table, $fieldName, array $row, array $PA) {
1958  $config = $PA['fieldConf']['config'];
1959 
1960  // Getting the selector box items from the system
1961  $selectItems = $this->addSelectOptionsToItemArray(
1962  $this->initItemArray($PA['fieldConf']),
1963  $PA['fieldConf'],
1964  $this->setTSconfig($table, $row),
1965  $fieldName
1966  );
1967 
1968  // Possibly filter some items:
1969  $selectItems = GeneralUtility::keepItemsInArray(
1970  $selectItems,
1971  $PA['fieldTSConfig']['keepItems'],
1972  function ($value) {
1973  return $value[1];
1974  }
1975  );
1976 
1977  // Possibly add some items:
1978  $selectItems = $this->addItems($selectItems, $PA['fieldTSConfig']['addItems.']);
1979 
1980  // Process items by a user function:
1981  if (isset($config['itemsProcFunc']) && $config['itemsProcFunc']) {
1982  $selectItems = $this->procItems($selectItems, $PA['fieldTSConfig']['itemsProcFunc.'], $config, $table, $row, $fieldName);
1983  }
1984 
1985  // Possibly remove some items:
1986  $removeItems = GeneralUtility::trimExplode(',', $PA['fieldTSConfig']['removeItems'], TRUE);
1987  foreach ($selectItems as $selectItemIndex => $selectItem) {
1988 
1989  // Checking languages and authMode:
1990  $languageDeny = FALSE;
1991  $beUserAuth = $this->getBackendUserAuthentication();
1992  if (
1993  !empty($GLOBALS['TCA'][$table]['ctrl']['languageField'])
1994  && $GLOBALS['TCA'][$table]['ctrl']['languageField'] === $fieldName
1995  && !$beUserAuth->checkLanguageAccess($selectItem[1])
1996  ) {
1997  $languageDeny = TRUE;
1998  }
1999 
2000  $authModeDeny = FALSE;
2001  if (
2002  ($config['form_type'] === 'select')
2003  && $config['authMode']
2004  && !$beUserAuth->checkAuthMode($table, $fieldName, $selectItem[1], $config['authMode'])
2005  ) {
2006  $authModeDeny = TRUE;
2007  }
2008 
2009  if (in_array($selectItem[1], $removeItems) || $languageDeny || $authModeDeny) {
2010  unset($selectItems[$selectItemIndex]);
2011  } elseif (isset($PA['fieldTSConfig']['altLabels.'][$selectItem[1]])) {
2012  $selectItems[$selectItemIndex][0] = htmlspecialchars($this->sL($PA['fieldTSConfig']['altLabels.'][$selectItem[1]]));
2013  }
2014 
2015  // Removing doktypes with no access:
2016  if (($table === 'pages' || $table === 'pages_language_overlay') && $fieldName === 'doktype') {
2017  if (!($beUserAuth->isAdmin() || GeneralUtility::inList($beUserAuth->groupData['pagetypes_select'], $selectItem[1]))) {
2018  unset($selectItems[$selectItemIndex]);
2019  }
2020  }
2021  }
2022 
2023  return $selectItems;
2024  }
2025 
2041  public function getSingleField_typeSelect_single($table, $field, $row, &$PA, $config, $selItems, $nMV_label) {
2042  // check against inline uniqueness
2043  $inlineParent = $this->inline->getStructureLevel(-1);
2044  $uniqueIds = NULL;
2045  if (is_array($inlineParent) && $inlineParent['uid']) {
2046  if ($inlineParent['config']['foreign_table'] == $table && $inlineParent['config']['foreign_unique'] == $field) {
2047  $uniqueIds = $this->inline->inlineData['unique'][$this->inline->inlineNames['object']
2048  . InlineElement::Structure_Separator . $table]['used'];
2049  $PA['fieldChangeFunc']['inlineUnique'] = 'inline.updateUnique(this,\'' . $this->inline->inlineNames['object']
2050  . InlineElement::Structure_Separator . $table . '\',\'' . $this->inline->inlineNames['form']
2051  . '\',\'' . $row['uid'] . '\');';
2052  }
2053  // hide uid of parent record for symmetric relations
2054  if (
2055  $inlineParent['config']['foreign_table'] == $table
2056  && ($inlineParent['config']['foreign_field'] == $field || $inlineParent['config']['symmetric_field'] == $field)
2057  ) {
2058  $uniqueIds[] = $inlineParent['uid'];
2059  }
2060  }
2061  // Initialization:
2062  $c = 0;
2063  $sI = 0;
2064  $noMatchingValue = 1;
2065  $opt = array();
2066  $selicons = array();
2067  $onlySelectedIconShown = 0;
2068  $size = (int)$config['size'];
2069  // Style set on <select/>
2070  $selectedStyle = '';
2071  $item = '';
2072  $disabled = '';
2073  if ($this->renderReadonly || $config['readOnly']) {
2074  $disabled = ' disabled="disabled"';
2075  $onlySelectedIconShown = 1;
2076  }
2077  // Register as required if minitems is greater than zero
2078  if (($minItems = MathUtility::forceIntegerInRange($config['minitems'], 0)) > 0) {
2079  $this->registerRequiredProperty('field', $table . '_' . $row['uid'] . '_' . $field, $PA['itemFormElName']);
2080  }
2081 
2082  // Icon configuration:
2083  if ($config['suppress_icons'] == 'IF_VALUE_FALSE') {
2084  $suppressIcons = !$PA['itemFormElValue'] ? 1 : 0;
2085  } elseif ($config['suppress_icons'] == 'ONLY_SELECTED') {
2086  $suppressIcons = 0;
2087  $onlySelectedIconShown = 1;
2088  } elseif ($config['suppress_icons']) {
2089  $suppressIcons = 1;
2090  } else {
2091  $suppressIcons = 0;
2092  }
2093  // Traverse the Array of selector box items:
2094  $optGroupStart = array();
2095  $optGroupOpen = FALSE;
2096  $classesForSelectTag = array();
2097  foreach ($selItems as $p) {
2098  $sM = (string)$PA['itemFormElValue'] === (string)$p[1] ? ' selected="selected"' : '';
2099  if ($sM) {
2100  $sI = $c;
2101  $noMatchingValue = 0;
2102  }
2103  // Getting style attribute value (for icons):
2104  $styleAttrValue = '';
2105  if ($config['iconsInOptionTags']) {
2106  $styleAttrValue = $this->optionTagStyle($p[2]);
2107  if ($sM) {
2108  list($selectIconFile, $selectIconInfo) = $this->getIcon($p[2]);
2109  if (!empty($selectIconInfo)) {
2110  $selectedStyle = ' style="background-image:url(' . $selectIconFile . ');"';
2111  $classesForSelectTag[] = 'typo3-TCEforms-select-selectedItemWithBackgroundImage';
2112  }
2113  }
2114  }
2115  // Compiling the <option> tag:
2116  if (!($p[1] != $PA['itemFormElValue'] && is_array($uniqueIds) && in_array($p[1], $uniqueIds))) {
2117  if ($p[1] === '--div--') {
2118  $optGroupStart[0] = $p[0];
2119  if ($config['iconsInOptionTags']) {
2120  $optGroupStart[1] = $this->optgroupTagStyle($p[2]);
2121  } else {
2122  $optGroupStart[1] = $styleAttrValue;
2123  }
2124  } else {
2125  if (count($optGroupStart)) {
2126  // Closing last optgroup before next one starts
2127  if ($optGroupOpen) {
2128  $opt[] = '</optgroup>' . LF;
2129  }
2130  $opt[] = '<optgroup label="' . htmlspecialchars($optGroupStart[0], ENT_COMPAT, 'UTF-8', FALSE)
2131  . '"' . ($optGroupStart[1] ? ' style="' . htmlspecialchars($optGroupStart[1]) . '"' : '')
2132  . ' class="c-divider">' . LF;
2133  $optGroupOpen = TRUE;
2134  $c--;
2135  $optGroupStart = array();
2136  }
2137  $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' . $sM
2138  . ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '') . '>'
2139  . htmlspecialchars($p[0], ENT_COMPAT, 'UTF-8', FALSE) . '</option>' . LF;
2140  }
2141  }
2142  // If there is an icon for the selector box (rendered in selicon-table below)...:
2143  // if there is an icon ($p[2]), icons should be shown, and, if only selected are visible, is it selected
2144  if ($p[2] && !$suppressIcons && (!$onlySelectedIconShown || $sM)) {
2145  list($selIconFile, $selIconInfo) = $this->getIcon($p[2]);
2146  $iOnClick = $this->elName($PA['itemFormElName']) . '.selectedIndex=' . $c . '; '. $this->elName($PA['itemFormElName']);
2147  $iOnClickOptions = $this->elName($PA['itemFormElName']) . '.options[' . $c . ']';
2148  if (empty($selIconInfo)) {
2149  $iOnClick .= '.className=' . $iOnClickOptions . '.className; ';
2150  } else {
2151  $iOnClick .= '.style.backgroundImage=' . $iOnClickOptions . '.style.backgroundImage; ';
2152  }
2153  $iOnClick .= implode('', $PA['fieldChangeFunc']) . 'this.blur(); return false;';
2154  $selicons[] = array(
2155  (!$onlySelectedIconShown ? '<a href="#" onclick="' . htmlspecialchars($iOnClick) . '">' : '')
2156  . $this->getIconHtml($p[2], htmlspecialchars($p[0]), htmlspecialchars($p[0]))
2157  . (!$onlySelectedIconShown ? '</a>' : ''),
2158  $c,
2159  $sM
2160  );
2161  }
2162  $c++;
2163  }
2164  // Closing optgroup if open
2165  if ($optGroupOpen) {
2166  $opt[] = '</optgroup>';
2167  }
2168  // No-matching-value:
2169  if ($PA['itemFormElValue'] && $noMatchingValue && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
2170  $nMV_label = @sprintf($nMV_label, $PA['itemFormElValue']);
2171  $opt[] = '<option value="' . htmlspecialchars($PA['itemFormElValue']) . '" selected="selected">' . htmlspecialchars($nMV_label) . '</option>';
2172  }
2173  // Create item form fields:
2174  $sOnChange = 'if (this.options[this.selectedIndex].value==\'--div--\') {this.selectedIndex=' . $sI . ';} ' . implode('', $PA['fieldChangeFunc']);
2175  if (!$disabled) {
2176  // MUST be inserted before the selector - else is the value of the hiddenfield here mysteriously submitted...
2177  $item .= '<input type="hidden" name="' . $PA['itemFormElName'] . '_selIconVal" value="' . htmlspecialchars($sI) . '" />';
2178  }
2179  if ($config['iconsInOptionTags']) {
2180  $classesForSelectTag[] = 'icon-select';
2181  }
2182  $item .= '<select' . $selectedStyle . ' id="' . str_replace('.', '', uniqid('tceforms-select-', TRUE)) . '" name="' . $PA['itemFormElName'] . '"' . $this->insertDefStyle('select', implode(' ', $classesForSelectTag)) . ($size ? ' size="' . $size . '"' : '') . ' onchange="' . htmlspecialchars($sOnChange) . '"' . $PA['onFocus'] . $disabled . '>';
2183  $item .= implode('', $opt);
2184  $item .= '</select>';
2185  // Create icon table:
2186  if (count($selicons) && !$config['noIconsBelowSelect']) {
2187  $item .= '<table border="0" cellpadding="0" cellspacing="0" class="typo3-TCEforms-selectIcons">';
2188  $selicon_cols = (int)$config['selicon_cols'];
2189  if (!$selicon_cols) {
2190  $selicon_cols = count($selicons);
2191  }
2192  $sR = ceil(count($selicons) / $selicon_cols);
2193  $selicons = array_pad($selicons, $sR * $selicon_cols, '');
2194  for ($sa = 0; $sa < $sR; $sa++) {
2195  $item .= '<tr>';
2196  for ($sb = 0; $sb < $selicon_cols; $sb++) {
2197  $sk = $sa * $selicon_cols + $sb;
2198  $imgN = 'selIcon_' . $table . '_' . $row['uid'] . '_' . $field . '_' . $selicons[$sk][1];
2199  $imgS = $selicons[$sk][2] ? $this->backPath . 'gfx/content_selected.gif' : 'clear.gif';
2200  $item .= '<td><img name="' . htmlspecialchars($imgN) . '" src="' . $imgS . '" width="7" height="10" alt="" /></td>';
2201  $item .= '<td>' . $selicons[$sk][0] . '</td>';
2202  }
2203  $item .= '</tr>';
2204  }
2205  $item .= '</table>';
2206  }
2207  return $item;
2208  }
2209 
2225  public function getSingleField_typeSelect_checkbox($table, $field, $row, &$PA, $config, $selItems, $nMV_label) {
2226  if (empty($selItems)) {
2227  return '';
2228  }
2229  // Get values in an array (and make unique, which is fine because there can be no duplicates anyway):
2230  $itemArray = array_flip($this->extractValuesOnlyFromValueLabelList($PA['itemFormElValue']));
2231  $item = '';
2232  $disabled = '';
2233  if ($this->renderReadonly || $config['readOnly']) {
2234  $disabled = ' disabled="disabled"';
2235  }
2236  // Traverse the Array of selector box items:
2237  $tRows = array();
2238  $c = 0;
2239  $setAll = array();
2240  $unSetAll = array();
2241  $restoreCmd = array();
2242  $sOnChange = '';
2243  if (!$disabled) {
2244  $sOnChange = implode('', $PA['fieldChangeFunc']);
2245  // Used to accumulate the JS needed to restore the original selection.
2246  foreach ($selItems as $p) {
2247  // Non-selectable element:
2248  if ($p[1] === '--div--') {
2249  $selIcon = '';
2250  if (isset($p[2]) && $p[2] != 'empty-emtpy') {
2251  $selIcon = $this->getIconHtml($p[2]);
2252  }
2253  $tRows[] = '
2254  <tr class="c-header">
2255  <td colspan="3">' . $selIcon . htmlspecialchars($p[0]) . '</td>
2256  </tr>';
2257  } else {
2258  // Selected or not by default:
2259  $sM = '';
2260  if (isset($itemArray[$p[1]])) {
2261  $sM = ' checked="checked"';
2262  unset($itemArray[$p[1]]);
2263  }
2264  // Icon:
2265  if (!empty($p[2])) {
2266  $selIcon = $this->getIconHtml($p[2]);
2267  } else {
2268  $selIcon = IconUtility::getSpriteIcon('empty-empty');
2269  }
2270  // Compile row:
2271  $rowId = str_replace('.', '', uniqid('select_checkbox_row_', TRUE));
2272  $onClickCell = $this->elName(($PA['itemFormElName'] . '[' . $c . ']')) . '.checked=!' . $this->elName(($PA['itemFormElName'] . '[' . $c . ']')) . '.checked;';
2273  $onClick = 'this.attributes.getNamedItem("class").nodeValue = ' . $this->elName(($PA['itemFormElName'] . '[' . $c . ']')) . '.checked ? "c-selectedItem" : "c-unselectedItem";';
2274  $setAll[] = $this->elName(($PA['itemFormElName'] . '[' . $c . ']')) . '.checked=1;';
2275  $setAll[] .= '$(\'' . $rowId . '\').removeClassName(\'c-unselectedItem\');$(\'' . $rowId . '\').addClassName(\'c-selectedItem\');';
2276  $unSetAll[] = $this->elName(($PA['itemFormElName'] . '[' . $c . ']')) . '.checked=0;';
2277  $unSetAll[] .= '$(\'' . $rowId . '\').removeClassName(\'c-selectedItem\');$(\'' . $rowId . '\').addClassName(\'c-unselectedItem\');';
2278  $restoreCmd[] = $this->elName(($PA['itemFormElName'] . '[' . $c . ']')) . '.checked=' . ($sM ? 1 : 0) . ';' . '$(\'' . $rowId . '\').removeClassName(\'c-selectedItem\');$(\'' . $rowId . '\').removeClassName(\'c-unselectedItem\');' . '$(\'' . $rowId . '\').addClassName(\'c-' . ($sM ? '' : 'un') . 'selectedItem\');';
2279  // Check if some help text is available
2280  // Since TYPO3 4.5 help text is expected to be an associative array
2281  // with two key, "title" and "description"
2282  // For the sake of backwards compatibility, we test if the help text
2283  // is a string and use it as a description (this could happen if items
2284  // are modified with an itemProcFunc)
2285  $hasHelp = FALSE;
2286  $help = '';
2287  $helpArray = array();
2288  if (is_array($p[3]) && count($p[3]) > 0 || !empty($p[3])) {
2289  $hasHelp = TRUE;
2290  if (is_array($p[3])) {
2291  $helpArray = $p[3];
2292  } else {
2293  $helpArray['description'] = $p[3];
2294  }
2295  }
2296  $label = htmlspecialchars($p[0], ENT_COMPAT, 'UTF-8', FALSE);
2297  if ($hasHelp) {
2298  $help = BackendUtility::wrapInHelp('', '', '', $helpArray);
2299  }
2300  $tRows[] = '
2301  <tr id="' . $rowId . '" class="' . ($sM ? 'c-selectedItem' : 'c-unselectedItem')
2302  . '" onclick="' . htmlspecialchars($onClick) . '" style="cursor: pointer;">
2303  <td class="c-checkbox"><input type="checkbox"' . $this->insertDefStyle('check')
2304  . ' name="' . htmlspecialchars(($PA['itemFormElName'] . '[' . $c . ']'))
2305  . '" value="' . htmlspecialchars($p[1]) . '"' . $sM . ' onclick="' . htmlspecialchars($sOnChange)
2306  . '"' . $PA['onFocus'] . ' /></td>
2307  <td class="c-labelCell" onclick="' . htmlspecialchars($onClickCell) . '">' . $selIcon . $label . '</td>
2308  <td class="c-descr" onclick="' . htmlspecialchars($onClickCell) . '">' . (empty($help) ? '' : $help) . '</td>
2309  </tr>';
2310  $c++;
2311  }
2312  }
2313  }
2314  // Remaining values (invalid):
2315  if (count($itemArray) && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
2316  foreach ($itemArray as $theNoMatchValue => $temp) {
2317  // Compile <checkboxes> tag:
2318  array_unshift($tRows, '
2319  <tr class="c-invalidItem">
2320  <td class="c-checkbox"><input type="checkbox"' . $this->insertDefStyle('check')
2321  . ' name="' . htmlspecialchars(($PA['itemFormElName'] . '[' . $c . ']'))
2322  . '" value="' . htmlspecialchars($theNoMatchValue) . '" checked="checked" onclick="' . htmlspecialchars($sOnChange) . '"'
2323  . $PA['onFocus'] . $disabled . ' /></td>
2324  <td class="c-labelCell">' . htmlspecialchars(@sprintf($nMV_label, $theNoMatchValue), ENT_COMPAT, 'UTF-8', FALSE) . '</td><td>&nbsp;</td>
2325  </tr>');
2326  $c++;
2327  }
2328  }
2329  // Add an empty hidden field which will send a blank value if all items are unselected.
2330  $item .= '<input type="hidden" class="select-checkbox" name="' . htmlspecialchars($PA['itemFormElName']) . '" value="" />';
2331  // Remaining checkboxes will get their set-all link:
2332  $tableHead = '';
2333  if (count($setAll)) {
2334  $tableHead = '<thead>
2335  <tr class="c-header-checkbox-controls t3-row-header">
2336  <td class="c-checkbox">
2337  <input type="checkbox" class="checkbox" onclick="if (checked) {' . htmlspecialchars(implode('', $setAll) . '} else {' . implode('', $unSetAll) . '}') . '">
2338  </td>
2339  <td colspan="2">
2340  </td>
2341  </tr></thead>';
2342  }
2343  // Implode rows in table:
2344  $item .= '
2345  <table border="0" cellpadding="0" cellspacing="0" class="typo3-TCEforms-select-checkbox">' . $tableHead . '<tbody>' . implode('', $tRows) . '</tbody>
2346  </table>
2347  ';
2348  // Add revert icon
2349  if (!empty($restoreCmd)) {
2350  $item .= '<a href="#" onclick="' . implode('', $restoreCmd) . ' return false;' . '">'
2351  . IconUtility::getSpriteIcon('actions-edit-undo', array('title' => htmlspecialchars($this->getLL('l_revertSelection')))) . '</a>';
2352  }
2353  return $item;
2354  }
2355 
2371  public function getSingleField_typeSelect_singlebox($table, $field, $row, &$PA, $config, $selItems, $nMV_label) {
2372  // Get values in an array (and make unique, which is fine because there can be no duplicates anyway):
2373  $itemArray = array_flip($this->extractValuesOnlyFromValueLabelList($PA['itemFormElValue']));
2374  $item = '';
2375  $disabled = '';
2376  if ($this->renderReadonly || $config['readOnly']) {
2377  $disabled = ' disabled="disabled"';
2378  }
2379  // Traverse the Array of selector box items:
2380  $opt = array();
2381  // Used to accumulate the JS needed to restore the original selection.
2382  $restoreCmd = array();
2383  $c = 0;
2384  foreach ($selItems as $p) {
2385  // Selected or not by default:
2386  $sM = '';
2387  if (isset($itemArray[$p[1]])) {
2388  $sM = ' selected="selected"';
2389  $restoreCmd[] = $this->elName(($PA['itemFormElName'] . '[]')) . '.options[' . $c . '].selected=1;';
2390  unset($itemArray[$p[1]]);
2391  }
2392  // Non-selectable element:
2393  $nonSel = '';
2394  if ((string) $p[1] === '--div--') {
2395  $nonSel = ' onclick="this.selected=0;" class="c-divider"';
2396  }
2397  // Icon style for option tag:
2398  $styleAttrValue = '';
2399  if ($config['iconsInOptionTags']) {
2400  $styleAttrValue = $this->optionTagStyle($p[2]);
2401  }
2402  // Compile <option> tag:
2403  $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' . $sM . $nonSel
2404  . ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '') . '>'
2405  . htmlspecialchars($p[0], ENT_COMPAT, 'UTF-8', FALSE) . '</option>';
2406  $c++;
2407  }
2408  // Remaining values:
2409  if (count($itemArray) && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
2410  foreach ($itemArray as $theNoMatchValue => $temp) {
2411  // Compile <option> tag:
2412  array_unshift($opt, '<option value="' . htmlspecialchars($theNoMatchValue) . '" selected="selected">'
2413  . htmlspecialchars(@sprintf($nMV_label, $theNoMatchValue), ENT_COMPAT, 'UTF-8', FALSE) . '</option>');
2414  }
2415  }
2416  // Compile selector box:
2417  $sOnChange = implode('', $PA['fieldChangeFunc']);
2418  $selector_itemListStyle = isset($config['itemListStyle'])
2419  ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"'
2420  : ' style="' . $this->defaultMultipleSelectorStyle . '"';
2421  $size = (int)$config['size'];
2422  $cssPrefix = $size === 1 ? 'tceforms-select' : 'tceforms-multiselect';
2423  $size = $config['autoSizeMax']
2424  ? MathUtility::forceIntegerInRange(count($selItems) + 1, MathUtility::forceIntegerInRange($size, 1), $config['autoSizeMax'])
2425  : $size;
2426  $selectBox = '<select id="' . str_replace('.', '', uniqid($cssPrefix, TRUE)) . '" name="' . $PA['itemFormElName'] . '[]"'
2427  . $this->insertDefStyle('select', $cssPrefix) . ($size ? ' size="' . $size . '"' : '')
2428  . ' multiple="multiple" onchange="' . htmlspecialchars($sOnChange) . '"' . $PA['onFocus']
2429  . $selector_itemListStyle . $disabled . '>
2430  ' . implode('
2431  ', $opt) . '
2432  </select>';
2433  // Add an empty hidden field which will send a blank value if all items are unselected.
2434  if (!$disabled) {
2435  $item .= '<input type="hidden" name="' . htmlspecialchars($PA['itemFormElName']) . '" value="" />';
2436  }
2437  // Put it all into a table:
2438  $onClick = htmlspecialchars($this->elName(($PA['itemFormElName'] . '[]')) . '.selectedIndex=-1;' . implode('', $restoreCmd) . ' return false;');
2439  $item .= '
2440  <table border="0" cellspacing="0" cellpadding="0" width="1" class="typo3-TCEforms-select-singlebox">
2441  <tr>
2442  <td>
2443  ' . $selectBox . '
2444  <br/>
2445  <em>' . htmlspecialchars($this->getLL('l_holdDownCTRL')) . '</em>
2446  </td>
2447  <td valign="top">
2448  <a href="#" onclick="' . $onClick . '" title="' . htmlspecialchars($this->getLL('l_revertSelection')) . '">'
2449  . IconUtility::getSpriteIcon('actions-edit-undo') . '</a>
2450  </td>
2451  </tr>
2452  </table>
2453  ';
2454  return $item;
2455  }
2456 
2472  public function getSingleField_typeSelect_multiple($table, $field, $row, &$PA, $config, $selItems, $nMV_label) {
2473  $item = '';
2474  $disabled = '';
2475  if ($this->renderReadonly || $config['readOnly']) {
2476  $disabled = ' disabled="disabled"';
2477  }
2478  // Setting this hidden field (as a flag that JavaScript can read out)
2479  if (!$disabled) {
2480  $item .= '<input type="hidden" name="' . $PA['itemFormElName'] . '_mul" value="' . ($config['multiple'] ? 1 : 0) . '" />';
2481  }
2482  // Set max and min items:
2483  $maxitems = MathUtility::forceIntegerInRange($config['maxitems'], 0);
2484  if (!$maxitems) {
2485  $maxitems = 100000;
2486  }
2487  $minitems = MathUtility::forceIntegerInRange($config['minitems'], 0);
2488  // Register the required number of elements:
2489  $this->registerRequiredProperty('range', $PA['itemFormElName'], array($minitems, $maxitems, 'imgName' => $table . '_' . $row['uid'] . '_' . $field));
2490  // Get "removeItems":
2491  $removeItems = GeneralUtility::trimExplode(',', $PA['fieldTSConfig']['removeItems'], TRUE);
2492  // Get the array with selected items:
2493  $itemArray = GeneralUtility::trimExplode(',', $PA['itemFormElValue'], TRUE);
2494 
2495  // Possibly filter some items:
2496  $itemArray = GeneralUtility::keepItemsInArray(
2497  $itemArray,
2498  $PA['fieldTSConfig']['keepItems'],
2499  function ($value) {
2500  $parts = explode('|', $value, 2);
2501  return rawurldecode($parts[0]);
2502  }
2503  );
2504 
2505  // Perform modification of the selected items array:
2506  foreach ($itemArray as $tk => $tv) {
2507  $tvP = explode('|', $tv, 2);
2508  $evalValue = $tvP[0];
2509  $isRemoved = in_array($evalValue, $removeItems)
2510  || $config['form_type'] == 'select' && $config['authMode']
2511  && !$this->getBackendUserAuthentication()->checkAuthMode($table, $field, $evalValue, $config['authMode']);
2512  if ($isRemoved && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
2513  $tvP[1] = rawurlencode(@sprintf($nMV_label, $evalValue));
2514  } elseif (isset($PA['fieldTSConfig']['altLabels.'][$evalValue])) {
2515  $tvP[1] = rawurlencode($this->sL($PA['fieldTSConfig']['altLabels.'][$evalValue]));
2516  }
2517  if ($tvP[1] == '') {
2518  // Case: flexform, default values supplied, no label provided (bug #9795)
2519  foreach ($selItems as $selItem) {
2520  if ($selItem[1] == $tvP[0]) {
2521  $tvP[1] = html_entity_decode($selItem[0]);
2522  break;
2523  }
2524  }
2525  }
2526  $itemArray[$tk] = implode('|', $tvP);
2527  }
2528  $itemsToSelect = '';
2529  $filterTextfield = '';
2530  $filterSelectbox = '';
2531  $size = 0;
2532  if (!$disabled) {
2533  // Create option tags:
2534  $opt = array();
2535  $styleAttrValue = '';
2536  foreach ($selItems as $p) {
2537  if ($config['iconsInOptionTags']) {
2538  $styleAttrValue = $this->optionTagStyle($p[2]);
2539  }
2540  $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"'
2541  . ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '')
2542  . ' title="' . $p[0] . '">' . $p[0] . '</option>';
2543  }
2544  // Put together the selector box:
2545  $selector_itemListStyle = isset($config['itemListStyle'])
2546  ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"'
2547  : ' style="' . $this->defaultMultipleSelectorStyle . '"';
2548  $size = (int)$config['size'];
2549  $size = $config['autoSizeMax']
2550  ? MathUtility::forceIntegerInRange(count($itemArray) + 1, MathUtility::forceIntegerInRange($size, 1), $config['autoSizeMax'])
2551  : $size;
2552  $sOnChange = implode('', $PA['fieldChangeFunc']);
2553 
2554  $multiSelectId = str_replace('.', '', uniqid('tceforms-multiselect-', TRUE));
2555  $itemsToSelect = '
2556  <select data-relatedfieldname="' . htmlspecialchars($PA['itemFormElName']) . '" data-exclusivevalues="'
2557  . htmlspecialchars($config['exclusiveKeys']) . '" id="' . $multiSelectId . '" name="' . $PA['itemFormElName'] . '_sel"'
2558  . $this->insertDefStyle('select', 'tceforms-multiselect tceforms-itemstoselect t3-form-select-itemstoselect')
2559  . ($size ? ' size="' . $size . '"' : '') . ' onchange="' . htmlspecialchars($sOnChange) . '"'
2560  . $PA['onFocus'] . $selector_itemListStyle . '>
2561  ' . implode('
2562  ', $opt) . '
2563  </select>';
2564 
2565  if ($config['enableMultiSelectFilterTextfield'] || $config['multiSelectFilterItems']) {
2566  $this->multiSelectFilterCount++;
2567  $jsSelectBoxFilterName = str_replace(' ', '', ucwords(str_replace('-', ' ', GeneralUtility::strtolower($multiSelectId))));
2568  $this->additionalJS_post[] = '
2569  var '. $jsSelectBoxFilterName . ' = new TCEForms.SelectBoxFilter("' . $multiSelectId . '");
2570  ';
2571  }
2572 
2573  if ($config['enableMultiSelectFilterTextfield']) {
2574  // add input field for filter
2575  $filterTextfield = '<input class="typo3-TCEforms-suggest-search typo3-TCEforms-multiselect-filter" id="'
2576  . $multiSelectId . '_filtertextfield" value="" style="width: 104px;" />';
2577  }
2578 
2579  if (isset($config['multiSelectFilterItems']) && is_array($config['multiSelectFilterItems']) && count($config['multiSelectFilterItems']) > 1) {
2580  $filterDropDownOptions = array();
2581  foreach ($config['multiSelectFilterItems'] as $optionElement) {
2582  $optionValue = $this->sL(isset($optionElement[1]) && $optionElement[1] != '' ? $optionElement[1]
2583  : $optionElement[0]);
2584  $filterDropDownOptions[] = '<option value="' . htmlspecialchars($this->sL($optionElement[0])) . '">'
2585  . htmlspecialchars($optionValue) . '</option>';
2586  }
2587  $filterSelectbox = '
2588  <select id="' . $multiSelectId . '_filterdropdown">
2589  ' . implode('
2590  ', $filterDropDownOptions) . '
2591  </select>';
2592  }
2593  }
2594  // Pass to "dbFileIcons" function:
2595  $params = array(
2596  'size' => $size,
2597  'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
2598  'style' => isset($config['selectedListStyle'])
2599  ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
2600  : ' style="' . $this->defaultMultipleSelectorStyle . '"',
2601  'dontShowMoveIcons' => $maxitems <= 1,
2602  'maxitems' => $maxitems,
2603  'info' => '',
2604  'headers' => array(
2605  'selector' => $this->getLL('l_selected') . ':<br />',
2606  'items' => $this->getLL('l_items') . ': ' . $filterSelectbox . $filterTextfield . '<br />'
2607  ),
2608  'noBrowser' => 1,
2609  'thumbnails' => $itemsToSelect,
2610  'readOnly' => $disabled
2611  );
2612  $item .= $this->dbFileIcons($PA['itemFormElName'], '', '', $itemArray, '', $params, $PA['onFocus']);
2613  return $item;
2614  }
2615 
2627  public function getSingleField_typeGroup($table, $field, $row, &$PA) {
2628  // Init:
2629  $config = $PA['fieldConf']['config'];
2630  $show_thumbs = $config['show_thumbs'];
2631  $size = isset($config['size']) ? (int)$config['size'] : 5;
2632  $maxitems = MathUtility::forceIntegerInRange($config['maxitems'], 0);
2633  if (!$maxitems) {
2634  $maxitems = 100000;
2635  }
2636  $minitems = MathUtility::forceIntegerInRange($config['minitems'], 0);
2637  $allowed = trim($config['allowed']);
2638  $disallowed = trim($config['disallowed']);
2639  $item = '';
2640  $disabled = '';
2641  if ($this->renderReadonly || $config['readOnly']) {
2642  $disabled = ' disabled="disabled"';
2643  }
2644  $item .= '<input type="hidden" name="' . $PA['itemFormElName'] . '_mul" value="' . ($config['multiple'] ? 1 : 0) . '"' . $disabled . ' />';
2645  $this->registerRequiredProperty('range', $PA['itemFormElName'], array($minitems, $maxitems, 'imgName' => $table . '_' . $row['uid'] . '_' . $field));
2646  $info = '';
2647  // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist.
2648  $specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);
2649  $PA['itemFormElID_file'] = $PA['itemFormElID'] . '_files';
2650  // whether the list and delete controls should be disabled
2651  $noList = isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'list');
2652  $noDelete = isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'delete');
2653  // if maxitems==1 then automatically replace the current item (in list and file selector)
2654  if ($maxitems === 1) {
2655  $this->additionalJS_post[] = 'TBE_EDITOR.clearBeforeSettingFormValueFromBrowseWin[\'' . $PA['itemFormElName'] . '\'] = {
2656  itemFormElID_file: \'' . $PA['itemFormElID_file'] . '\'
2657  }';
2658  $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'setFormValueManipulate(\'' . $PA['itemFormElName']
2659  . '\', \'Remove\'); ' . $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'];
2660  } elseif ($noList) {
2661  // If the list controls have been removed and the maximum number is reached, remove the first entry to avoid "write once" field
2662  $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'setFormValueManipulate(\'' . $PA['itemFormElName']
2663  . '\', \'RemoveFirstIfFull\', \'' . $maxitems . '\'); ' . $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'];
2664  }
2665  // Acting according to either "file" or "db" type:
2666  switch ((string) $config['internal_type']) {
2667  case 'file_reference':
2668  $config['uploadfolder'] = '';
2669  // Fall through
2670  case 'file':
2671  // Creating string showing allowed types:
2672  $tempFT = GeneralUtility::trimExplode(',', $allowed, TRUE);
2673  if (!count($tempFT)) {
2674  $info .= '*';
2675  }
2676  foreach ($tempFT as $ext) {
2677  if ($ext) {
2678  $info .= strtoupper($ext) . ' ';
2679  }
2680  }
2681  // Creating string, showing disallowed types:
2682  $tempFT_dis = GeneralUtility::trimExplode(',', $disallowed, TRUE);
2683  if (count($tempFT_dis)) {
2684  $info .= '<br />';
2685  }
2686  foreach ($tempFT_dis as $ext) {
2687  if ($ext) {
2688  $info .= '-' . strtoupper($ext) . ' ';
2689  }
2690  }
2691  // Making the array of file items:
2692  $itemArray = GeneralUtility::trimExplode(',', $PA['itemFormElValue'], TRUE);
2693  $fileFactory = ResourceFactory::getInstance();
2694  // Correct the filename for the FAL items
2695  foreach ($itemArray as &$fileItem) {
2696  list($fileUid, $fileLabel) = explode('|', $fileItem);
2697  if (MathUtility::canBeInterpretedAsInteger($fileUid)) {
2698  $fileObject = $fileFactory->getFileObject($fileUid);
2699  $fileLabel = $fileObject->getName();
2700  }
2701  $fileItem = $fileUid . '|' . $fileLabel;
2702  }
2703  // Showing thumbnails:
2704  $thumbsnail = '';
2705  if ($show_thumbs) {
2706  $imgs = array();
2707  foreach ($itemArray as $imgRead) {
2708  $imgP = explode('|', $imgRead);
2709  $imgPath = rawurldecode($imgP[0]);
2710  // FAL icon production
2711  if (MathUtility::canBeInterpretedAsInteger($imgP[0])) {
2712  $fileObject = $fileFactory->getFileObject($imgP[0]);
2713 
2714  if ($fileObject->isMissing()) {
2715  $flashMessage = \TYPO3\CMS\Core\Resource\Utility\BackendUtility::getFlashMessageForMissingFile($fileObject);
2716  $imgs[] = $flashMessage->render();
2717  } elseif (GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileObject->getExtension())) {
2718  $imageUrl = $fileObject->process(ProcessedFile::CONTEXT_IMAGEPREVIEW, array())->getPublicUrl(TRUE);
2719  $imgTag = '<img src="' . $imageUrl . '" alt="' . htmlspecialchars($fileObject->getName()) . '" />';
2720  $imgs[] = '<span class="nobr">' . $imgTag . htmlspecialchars($fileObject->getName()) . '</span>';
2721  } else {
2722  // Icon
2723  $imgTag = IconUtility::getSpriteIconForResource($fileObject, array('title' => $fileObject->getName()));
2724  $imgs[] = '<span class="nobr">' . $imgTag . htmlspecialchars($fileObject->getName()) . '</span>';
2725  }
2726  } else {
2727  $rowCopy = array();
2728  $rowCopy[$field] = $imgPath;
2729  $thumbnailCode = '';
2730  try {
2731  $thumbnailCode = BackendUtility::thumbCode(
2732  $rowCopy, $table, $field, $this->backPath, 'thumbs.php',
2733  $config['uploadfolder'], 0, ' align="middle"'
2734  );
2735  $thumbnailCode = '<span class="nobr">' . $thumbnailCode . $imgPath . '</span>';
2736 
2737  } catch (\Exception $exception) {
2739  $message = $exception->getMessage();
2740  $flashMessage = GeneralUtility::makeInstance(
2741  'TYPO3\\CMS\\Core\\Messaging\\FlashMessage',
2742  htmlspecialchars($message), '', FlashMessage::ERROR, TRUE
2743  );
2744  $class = 'TYPO3\\CMS\\Core\\Messaging\\FlashMessageService';
2746  $flashMessageService = GeneralUtility::makeInstance($class);
2747  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
2748  $defaultFlashMessageQueue->enqueue($flashMessage);
2749 
2750  $logMessage = $message . ' (' . $table . ':' . $row['uid'] . ')';
2751  GeneralUtility::sysLog($logMessage, 'core', GeneralUtility::SYSLOG_SEVERITY_WARNING);
2752  }
2753 
2754  $imgs[] = $thumbnailCode;
2755  }
2756  }
2757  $thumbsnail = implode('<br />', $imgs);
2758  }
2759  // Creating the element:
2760  $params = array(
2761  'size' => $size,
2762  'dontShowMoveIcons' => $maxitems <= 1,
2763  'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
2764  'maxitems' => $maxitems,
2765  'style' => isset($config['selectedListStyle'])
2766  ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
2767  : ' style="' . $this->defaultMultipleSelectorStyle . '"',
2768  'info' => $info,
2769  'thumbnails' => $thumbsnail,
2770  'readOnly' => $disabled,
2771  'noBrowser' => $noList || isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'browser'),
2772  'noList' => $noList,
2773  'noDelete' => $noDelete
2774  );
2775  $item .= $this->dbFileIcons($PA['itemFormElName'], 'file', implode(',', $tempFT), $itemArray, '', $params, $PA['onFocus'], '', '', '', $config);
2776  if (!$disabled && !(isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'upload'))) {
2777  // Adding the upload field:
2778  if ($this->edit_docModuleUpload && $config['uploadfolder']) {
2779  // Insert the multiple attribute to enable HTML5 multiple file upload
2780  $multipleAttribute = '';
2781  $multipleFilenameSuffix = '';
2782  if (isset($config['maxitems']) && $config['maxitems'] > 1) {
2783  $multipleAttribute = ' multiple="multiple"';
2784  $multipleFilenameSuffix = '[]';
2785  }
2786  $item .= '<div id="' . $PA['itemFormElID_file'] . '"><input type="file"' . $multipleAttribute
2787  . ' name="' . $PA['itemFormElName_file'] . $multipleFilenameSuffix . '" size="35" onchange="'
2788  . implode('', $PA['fieldChangeFunc']) . '" /></div>';
2789  }
2790  }
2791  break;
2792  case 'folder':
2793  // If the element is of the internal type "folder":
2794  // Array of folder items:
2795  $itemArray = GeneralUtility::trimExplode(',', $PA['itemFormElValue'], TRUE);
2796  // Creating the element:
2797  $params = array(
2798  'size' => $size,
2799  'dontShowMoveIcons' => $maxitems <= 1,
2800  'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
2801  'maxitems' => $maxitems,
2802  'style' => isset($config['selectedListStyle'])
2803  ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
2804  : ' style="' . $this->defaultMultipleSelectorStyle . '"',
2805  'info' => $info,
2806  'readOnly' => $disabled,
2807  'noBrowser' => $noList || isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'browser'),
2808  'noList' => $noList
2809  );
2810  $item .= $this->dbFileIcons($PA['itemFormElName'], 'folder', '', $itemArray, '', $params, $PA['onFocus']);
2811  break;
2812  case 'db':
2813  // If the element is of the internal type "db":
2814  // Creating string showing allowed types:
2815  $tempFT = GeneralUtility::trimExplode(',', $allowed, TRUE);
2816  $onlySingleTableAllowed = FALSE;
2817  if (trim($tempFT[0]) === '*') {
2818  $info .= '<span class="nobr">' . htmlspecialchars($this->getLL('l_allTables')) . '</span><br />';
2819  } elseif ($tempFT) {
2820  $onlySingleTableAllowed = count($tempFT) == 1;
2821  foreach ($tempFT as $theT) {
2822  $label = IconUtility::getSpriteIconForRecord($theT, array())
2823  . htmlspecialchars($this->sL($GLOBALS['TCA'][$theT]['ctrl']['title']));
2824  if (empty($config['readOnly'])) {
2825  $aOnClick = 'setFormValueOpenBrowser(\'db\', \'' . ($PA['itemFormElName'] . '|||' . $theT) . '\'); return false;';
2826  $info .= '<span class="nobr"><a href="#" onclick="' . htmlspecialchars($aOnClick) . '">'
2827  . $label . '</a></span>';
2828  } else {
2829  $info .= '<span class="nobr">' . $label . '</span>';
2830  }
2831  $info .= '<br />';
2832  }
2833  }
2834  $perms_clause = $this->getBackendUserAuthentication()->getPagePermsClause(1);
2835  $itemArray = array();
2836  $imgs = array();
2837  // Thumbnails:
2838  $temp_itemArray = GeneralUtility::trimExplode(',', $PA['itemFormElValue'], TRUE);
2839  foreach ($temp_itemArray as $dbRead) {
2840  $recordParts = explode('|', $dbRead);
2841  list($this_table, $this_uid) = BackendUtility::splitTable_Uid($recordParts[0]);
2842  // For the case that no table was found and only a single table is defined to be allowed, use that one:
2843  if (!$this_table && $onlySingleTableAllowed) {
2844  $this_table = $allowed;
2845  }
2846  $itemArray[] = array('table' => $this_table, 'id' => $this_uid);
2847  if (!$disabled && $show_thumbs) {
2848  $rr = BackendUtility::getRecordWSOL($this_table, $this_uid);
2849  $imgs[] = '<span class="nobr">' . $this->getClickMenu(IconUtility::getSpriteIconForRecord($this_table, $rr, array(
2850  'style' => 'vertical-align:top',
2851  'title' => htmlspecialchars((BackendUtility::getRecordPath($rr['pid'], $perms_clause, 15) . ' [UID: ' . $rr['uid'] . ']'))
2852  )), $this_table, $this_uid) . '&nbsp;' . BackendUtility::getRecordTitle($this_table, $rr, TRUE)
2853  . ' <span class="typo3-dimmed"><em>[' . $rr['uid'] . ']</em></span>' . '</span>';
2854  }
2855  }
2856  $thumbsnail = '';
2857  if (!$disabled && $show_thumbs) {
2858  $thumbsnail = implode('<br />', $imgs);
2859  }
2860  // Creating the element:
2861  $params = array(
2862  'size' => $size,
2863  'dontShowMoveIcons' => $maxitems <= 1,
2864  'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
2865  'maxitems' => $maxitems,
2866  'style' => isset($config['selectedListStyle'])
2867  ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
2868  : ' style="' . $this->defaultMultipleSelectorStyle . '"',
2869  'info' => $info,
2870  'thumbnails' => $thumbsnail,
2871  'readOnly' => $disabled,
2872  'noBrowser' => $noList || isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'browser'),
2873  'noList' => $noList
2874  );
2875  $item .= $this->dbFileIcons($PA['itemFormElName'], 'db', implode(',', $tempFT), $itemArray, '', $params, $PA['onFocus'], $table, $field, $row['uid'], $config);
2876  break;
2877  }
2878  // Wizards:
2879  $altItem = '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
2880  if (!$disabled) {
2881  $item = $this->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $PA, $PA['itemFormElName'], $specConf);
2882  }
2883  return $item;
2884  }
2885 
2897  public function getSingleField_typeNone($table, $field, $row, &$PA) {
2898  // Init:
2899  $config = $PA['fieldConf']['config'];
2900  $itemValue = $PA['itemFormElValue'];
2901  return $this->getSingleField_typeNone_render($config, $itemValue);
2902  }
2903 
2913  public function getSingleField_typeNone_render($config, $itemValue) {
2914  if ($config['format']) {
2915  $itemValue = $this->formatValue($config, $itemValue);
2916  }
2917  $rows = (int)$config['rows'];
2918  if ($rows > 1) {
2919  if (!$config['pass_content']) {
2920  $itemValue = nl2br(htmlspecialchars($itemValue));
2921  }
2922  // Like textarea
2923  $cols = MathUtility::forceIntegerInRange($config['cols'] ? $config['cols'] : 30, 5, $this->maxTextareaWidth);
2924  if (!$config['fixedRows']) {
2925  $origRows = ($rows = MathUtility::forceIntegerInRange($rows, 1, 20));
2926  if (strlen($itemValue) > $this->charsPerRow * 2) {
2927  $cols = $this->maxTextareaWidth;
2928  $rows = MathUtility::forceIntegerInRange(round(strlen($itemValue) / $this->charsPerRow), count(explode(LF, $itemValue)), 20);
2929  if ($rows < $origRows) {
2930  $rows = $origRows;
2931  }
2932  }
2933  }
2934 
2935  $cols = round($cols * $this->form_largeComp);
2936  $width = ceil($cols * $this->form_rowsToStylewidth);
2937  // Hardcoded: 12 is the height of the font
2938  $height = $rows * 12;
2939  $item = '
2940  <div style="overflow:auto; height:' . $height . 'px; width:' . $width . 'px;" class="t3-tceforms-fieldReadOnly">'
2941  . $itemValue . IconUtility::getSpriteIcon('status-status-readonly') . '</div>';
2942  } else {
2943  if (!$config['pass_content']) {
2944  $itemValue = htmlspecialchars($itemValue);
2945  }
2946  $cols = $config['cols'] ? $config['cols'] : ($config['size'] ? $config['size'] : $this->maxInputWidth);
2947  $cols = round($cols * $this->form_largeComp);
2948  $width = ceil($cols * $this->form_rowsToStylewidth);
2949  // Overflow:auto crashes mozilla here. Title tag is useful when text is longer than the div box (overflow:hidden).
2950  $item = '
2951  <div style="overflow:hidden; width:' . $width . 'px;" class="t3-tceforms-fieldReadOnly" title="' . $itemValue . '">'
2952  . '<span class="nobr">' . ((string)$itemValue !== '' ? $itemValue : '&nbsp;') . '</span>'
2953  . IconUtility::getSpriteIcon('status-status-readonly') . '</div>';
2954  }
2955  return $item;
2956  }
2957 
2968  public function getSingleField_typeFlex($table, $field, $row, &$PA) {
2969  // Data Structure:
2970  $dataStructArray = BackendUtility::getFlexFormDS($PA['fieldConf']['config'], $row, $table, $field);
2971  $item = '';
2972  // Manipulate Flexform DS via TSConfig and group access lists
2973  if (is_array($dataStructArray)) {
2974  $flexFormHelper = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\FlexFormsHelper');
2975  $dataStructArray = $flexFormHelper->modifyFlexFormDS($dataStructArray, $table, $field, $row, $PA['fieldConf']);
2976  unset($flexFormHelper);
2977  }
2978  // Get data structure:
2979  if (is_array($dataStructArray)) {
2980  // Get data:
2981  $xmlData = $PA['itemFormElValue'];
2982  $xmlHeaderAttributes = GeneralUtility::xmlGetHeaderAttribs($xmlData);
2983  $storeInCharset = strtolower($xmlHeaderAttributes['encoding']);
2984  if ($storeInCharset) {
2985  $currentCharset = $this->getLanguageService()->charSet;
2986  $xmlData = $this->getLanguageService()->csConvObj->conv($xmlData, $storeInCharset, $currentCharset, 1);
2987  }
2988  $editData = GeneralUtility::xml2array($xmlData);
2989  // Must be XML parsing error...
2990  if (!is_array($editData)) {
2991  $editData = array();
2992  } elseif (!isset($editData['meta']) || !is_array($editData['meta'])) {
2993  $editData['meta'] = array();
2994  }
2995  // Find the data structure if sheets are found:
2996  $sheet = $editData['meta']['currentSheetId'] ? $editData['meta']['currentSheetId'] : 'sDEF';
2997  // Sheet to display
2998  // Create language menu:
2999  $langChildren = $dataStructArray['meta']['langChildren'] ? 1 : 0;
3000  $langDisabled = $dataStructArray['meta']['langDisable'] ? 1 : 0;
3001  $editData['meta']['currentLangId'] = array();
3002  // Look up page overlays:
3003  $checkPageLanguageOverlay = $this->getBackendUserAuthentication()->getTSConfigVal('options.checkPageLanguageOverlay') ? TRUE : FALSE;
3004  if ($checkPageLanguageOverlay) {
3005  $where_clause = 'pid=' . (int)$row['pid'] . BackendUtility::deleteClause('pages_language_overlay')
3006  . BackendUtility::versioningPlaceholderClause('pages_language_overlay');
3007  $pageOverlays = $this->getDatabaseConnection()->exec_SELECTgetRows('*', 'pages_language_overlay', $where_clause, '', '', '', 'sys_language_uid');
3008  }
3009  $languages = $this->getAvailableLanguages();
3010  foreach ($languages as $lInfo) {
3011  if (
3012  $this->getBackendUserAuthentication()->checkLanguageAccess($lInfo['uid'])
3013  && (!$checkPageLanguageOverlay || $lInfo['uid'] <= 0 || is_array($pageOverlays[$lInfo['uid']]))
3014  ) {
3015  $editData['meta']['currentLangId'][] = $lInfo['ISOcode'];
3016  }
3017  }
3018  if (!is_array($editData['meta']['currentLangId']) || !count($editData['meta']['currentLangId'])) {
3019  $editData['meta']['currentLangId'] = array('DEF');
3020  }
3021  $editData['meta']['currentLangId'] = array_unique($editData['meta']['currentLangId']);
3022  $PA['_noEditDEF'] = FALSE;
3023  if ($langChildren || $langDisabled) {
3024  $rotateLang = array('DEF');
3025  } else {
3026  if (!in_array('DEF', $editData['meta']['currentLangId'])) {
3027  array_unshift($editData['meta']['currentLangId'], 'DEF');
3028  $PA['_noEditDEF'] = TRUE;
3029  }
3030  $rotateLang = $editData['meta']['currentLangId'];
3031  }
3032  // Tabs sheets
3033  if (is_array($dataStructArray['sheets'])) {
3034  $tabsToTraverse = array_keys($dataStructArray['sheets']);
3035  } else {
3036  $tabsToTraverse = array($sheet);
3037  }
3038 
3040  $elementConditionMatcher = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\ElementConditionMatcher');
3041 
3042  foreach ($rotateLang as $lKey) {
3043  if (!$langChildren && !$langDisabled) {
3044  $item .= '<strong>' . $this->getLanguageIcon($table, $row, ('v' . $lKey)) . $lKey . ':</strong>';
3045  }
3046  // Default language, other options are "lUK" or whatever country code (independent of system!!!)
3047  $lang = 'l' . $lKey;
3048  $tabParts = array();
3049  $sheetContent = '';
3050  foreach ($tabsToTraverse as $sheet) {
3051  list($dataStruct, $sheet) = GeneralUtility::resolveSheetDefInDS($dataStructArray, $sheet);
3052  // If sheet has displayCond
3053  if ($dataStruct['ROOT']['TCEforms']['displayCond']) {
3054  $splitCondition = GeneralUtility::trimExplode(':', $dataStruct['ROOT']['TCEforms']['displayCond']);
3055  $skipCondition = FALSE;
3056  $fakeRow = array();
3057  switch ($splitCondition[0]) {
3058  case 'FIELD':
3059  list($sheetName, $fieldName) = GeneralUtility::trimExplode('.', $splitCondition[1], FALSE, 2);
3060  $fieldValue = $editData['data'][$sheetName][$lang][$fieldName];
3061  $splitCondition[1] = $fieldName;
3062  $dataStruct['ROOT']['TCEforms']['displayCond'] = join(':', $splitCondition);
3063  $fakeRow = array($fieldName => $fieldValue);
3064  break;
3065  case 'HIDE_FOR_NON_ADMINS':
3066 
3067  case 'VERSION':
3068 
3069  case 'HIDE_L10N_SIBLINGS':
3070 
3071  case 'EXT':
3072  break;
3073  case 'REC':
3074  $fakeRow = array('uid' => $row['uid']);
3075  break;
3076  default:
3077  $skipCondition = TRUE;
3078  }
3079  $displayConditionResult = TRUE;
3080  if ($dataStruct['ROOT']['TCEforms']['displayCond']) {
3081  $displayConditionResult = $elementConditionMatcher->match($dataStruct['ROOT']['TCEforms']['displayCond'], $fakeRow, 'vDEF');
3082  }
3083  // If sheets displayCond leads to false
3084  if (!$skipCondition && !$displayConditionResult) {
3085  // Don't create this sheet
3086  continue;
3087  }
3088  }
3089  // Render sheet:
3090  if (is_array($dataStruct['ROOT']) && is_array($dataStruct['ROOT']['el'])) {
3091  // Default language, other options are "lUK" or whatever country code (independent of system!!!)
3092  $PA['_valLang'] = $langChildren && !$langDisabled ? $editData['meta']['currentLangId'] : 'DEF';
3093  $PA['_lang'] = $lang;
3094  // Assemble key for loading the correct CSH file
3095  $dsPointerFields = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['columns'][$field]['config']['ds_pointerField'], TRUE);
3096  $PA['_cshKey'] = $table . '.' . $field;
3097  foreach ($dsPointerFields as $key) {
3098  $PA['_cshKey'] .= '.' . $row[$key];
3099  }
3100  // Push the sheet level tab to DynNestedStack
3101  $tabIdentString = '';
3102  if (is_array($dataStructArray['sheets'])) {
3103  $tabIdentString = $this->getDocumentTemplate()->getDynTabMenuId('TCEFORMS:flexform:' . $PA['itemFormElName'] . $PA['_lang']);
3104  $this->pushToDynNestedStack('tab', $tabIdentString . '-' . (count($tabParts) + 1));
3105  }
3106  // Render flexform:
3107  $tRows = $this->getSingleField_typeFlex_draw($dataStruct['ROOT']['el'], $editData['data'][$sheet][$lang], $table, $field, $row, $PA, '[data][' . $sheet . '][' . $lang . ']');
3108  $sheetContent = '<div class="typo3-TCEforms-flexForm">' . $tRows . '</div>';
3109  // Pop the sheet level tab from DynNestedStack
3110  if (is_array($dataStructArray['sheets'])) {
3111  $this->popFromDynNestedStack('tab', $tabIdentString . '-' . (count($tabParts) + 1));
3112  }
3113  } else {
3114  $sheetContent = 'Data Structure ERROR: No ROOT element found for sheet "' . $sheet . '".';
3115  }
3116  // Add to tab:
3117  $tabParts[] = array(
3118  'label' => $dataStruct['ROOT']['TCEforms']['sheetTitle'] ? $this->sL($dataStruct['ROOT']['TCEforms']['sheetTitle']) : $sheet,
3119  'description' => $dataStruct['ROOT']['TCEforms']['sheetDescription'] ? $this->sL($dataStruct['ROOT']['TCEforms']['sheetDescription']) : '',
3120  'linkTitle' => $dataStruct['ROOT']['TCEforms']['sheetShortDescr'] ? $this->sL($dataStruct['ROOT']['TCEforms']['sheetShortDescr']) : '',
3121  'content' => $sheetContent
3122  );
3123  }
3124  if (is_array($dataStructArray['sheets'])) {
3125  $dividersToTabsBehaviour = isset($GLOBALS['TCA'][$table]['ctrl']['dividers2tabs']) ? $GLOBALS['TCA'][$table]['ctrl']['dividers2tabs'] : 1;
3126  $item .= $this->getDynTabMenu($tabParts, 'TCEFORMS:flexform:' . $PA['itemFormElName'] . $PA['_lang'], $dividersToTabsBehaviour);
3127  } else {
3128  $item .= $sheetContent;
3129  }
3130  }
3131  } else {
3132  $item = 'Data Structure ERROR: ' . $dataStructArray;
3133  }
3134  return $item;
3135  }
3136 
3147  public function getSingleField_typeFlex_langMenu($languages, $elName, $selectedLanguage, $multi = TRUE) {
3148  $opt = array();
3149  foreach ($languages as $lArr) {
3150  $opt[] = '<option value="' . htmlspecialchars($lArr['ISOcode']) . '"'
3151  . (in_array($lArr['ISOcode'], $selectedLanguage) ? ' selected="selected"' : '') . '>'
3152  . htmlspecialchars($lArr['title']) . '</option>';
3153  }
3154  $output = '<select id="' . str_replace('.', '', uniqid('tceforms-multiselect-', TRUE))
3155  . ' class="tceforms-select tceforms-multiselect tceforms-flexlangmenu" name="' . $elName . '[]"'
3156  . ($multi ? ' multiple="multiple" size="' . count($languages) . '"' : '') . '>' . implode('', $opt)
3157  . '</select>';
3158  return $output;
3159  }
3160 
3170  public function getSingleField_typeFlex_sheetMenu($sArr, $elName, $sheetKey) {
3171  $tCells = array();
3172  $pct = round(100 / count($sArr));
3173  foreach ($sArr as $sKey => $sheetCfg) {
3174  if ($this->getBackendUserAuthentication()->jsConfirmation(1)) {
3175  $onClick = 'if (confirm(TBE_EDITOR.labels.onChangeAlert) && TBE_EDITOR.checkSubmit(-1)){'
3176  . $this->elName($elName) . '.value=\'' . $sKey . '\'; TBE_EDITOR.submitForm()};';
3177  } else {
3178  $onClick = 'if(TBE_EDITOR.checkSubmit(-1)){ ' . $this->elName($elName) . '.value=\'' . $sKey . '\'; TBE_EDITOR.submitForm();}';
3179  }
3180  $tCells[] = '<td width="' . $pct . '%" style="'
3181  . ($sKey == $sheetKey ? 'background-color: #9999cc; font-weight: bold;' : 'background-color: #aaaaaa;')
3182  . ' cursor: hand;" onclick="' . htmlspecialchars($onClick) . '" align="center">'
3183  . ($sheetCfg['ROOT']['TCEforms']['sheetTitle'] ? $this->sL($sheetCfg['ROOT']['TCEforms']['sheetTitle']) : $sKey)
3184  . '</td>';
3185  }
3186  return '<table border="0" cellpadding="0" cellspacing="2" class="typo3-TCEforms-flexForm-sheetMenu"><tr>' . implode('', $tCells) . '</tr></table>';
3187  }
3188 
3205  public function getSingleField_typeFlex_draw($dataStruct, $editData, $table, $field, $row, &$PA, $formPrefix = '', $level = 0, $idPrefix = 'ID', $toggleClosed = FALSE) {
3206  $output = '';
3207  $mayRestructureFlexforms = $this->getBackendUserAuthentication()->checkLanguageAccess(0);
3208  // Data Structure array must be ... and array of course...
3209  if (is_array($dataStruct)) {
3210  foreach ($dataStruct as $key => $value) {
3211  // Traversing fields in structure:
3212  if (is_array($value)) {
3213  // The value of each entry must be an array.
3214  // ********************
3215  // Making the row:
3216  // ********************
3217  // Title of field:
3218  // <title>LLL:EXT:cms/locallang_ttc.xml:media.sources</title>
3219  $theTitle = $value['title'];
3220 
3221  // If there is a title, check for LLL label
3222  if (strlen($theTitle) > 0) {
3223  $theTitle = htmlspecialchars(GeneralUtility::fixed_lgd_cs($this->sL($theTitle),
3224  (int)$this->getBackendUserAuthentication()->uc['titleLen']));
3225  }
3226  // If it's a "section" or "container":
3227  if ($value['type'] == 'array') {
3228  // Creating IDs for form fields:
3229  // It's important that the IDs "cascade" - otherwise we can't dynamically expand the flex form
3230  // because this relies on simple string substitution of the first parts of the id values.
3231  // This is a suffix used for forms on this level
3232  $thisId = GeneralUtility::shortMd5(uniqid('id', TRUE));
3233  // $idPrefix is the prefix for elements on lower levels in the hierarchy and we combine this
3234  // with the thisId value to form a new ID on this level.
3235  $idTagPrefix = $idPrefix . '-' . $thisId;
3236  // If it's a "section" containing other elements:
3237  if ($value['section']) {
3238  // Load script.aculo.us if flexform sections can be moved by drag'n'drop:
3239  $this->getControllerDocumentTemplate()->getPageRenderer()->loadScriptaculous();
3240  // Render header of section:
3241  $output .= '<div class="t3-form-field-label-flexsection"><strong>' . $theTitle . '</strong></div>';
3242  // Render elements in data array for section:
3243  $tRows = array();
3244  if (is_array($editData[$key]['el'])) {
3245  foreach ($editData[$key]['el'] as $k3 => $v3) {
3246  $cc = $k3;
3247  if (is_array($v3)) {
3248  $theType = key($v3);
3249  $theDat = $v3[$theType];
3250  $newSectionEl = $value['el'][$theType];
3251  if (is_array($newSectionEl)) {
3252  $tRows[] = $this->getSingleField_typeFlex_draw(array($theType => $newSectionEl),
3253  array($theType => $theDat), $table, $field, $row, $PA,
3254  $formPrefix . '[' . $key . '][el][' . $cc . ']', $level + 1,
3255  $idTagPrefix, $v3['_TOGGLE']);
3256  }
3257  }
3258  }
3259  }
3260  // Now, we generate "templates" for new elements that could be added to this section
3261  // by traversing all possible types of content inside the section:
3262  // We have to handle the fact that requiredElements and such may be set during this
3263  // rendering process and therefore we save and reset the state of some internal variables
3264  // ... little crude, but works...
3265  // Preserving internal variables we don't want to change:
3266  $TEMP_requiredElements = $this->requiredElements;
3267  // Traversing possible types of new content in the section:
3268  $newElementsLinks = array();
3269  foreach ($value['el'] as $nnKey => $nCfg) {
3270  $additionalJS_post_saved = $this->additionalJS_post;
3271  $this->additionalJS_post = array();
3272  $additionalJS_submit_saved = $this->additionalJS_submit;
3273  $this->additionalJS_submit = array();
3274  $newElementTemplate = $this->getSingleField_typeFlex_draw(array($nnKey => $nCfg),
3275  array(), $table, $field, $row, $PA,
3276  $formPrefix . '[' . $key . '][el][' . $idTagPrefix . '-form]', $level + 1,
3277  $idTagPrefix);
3278  // Makes a "Add new" link:
3279  $var = str_replace('.', '', uniqid('idvar', TRUE));
3280  $replace = 'replace(/' . $idTagPrefix . '-/g,"' . $idTagPrefix . '-"+' . $var . '+"-")';
3281  $replace .= '.replace(/(tceforms-(datetime|date)field-)/g,"$1" + (new Date()).getTime())';
3282  $onClickInsert = 'var ' . $var . ' = "' . 'idx"+(new Date()).getTime();'
3283  // Do not replace $isTagPrefix in setActionStatus() because it needs section id!
3284  . 'new Insertion.Bottom($("' . $idTagPrefix . '"), ' . json_encode($newElementTemplate)
3285  . '.' . $replace . '); setActionStatus("' . $idTagPrefix . '");'
3286  . 'eval(unescape("' . rawurlencode(implode(';', $this->additionalJS_post)) . '").' . $replace . ');'
3287  . 'TBE_EDITOR.addActionChecks("submit", unescape("'
3288  . rawurlencode(implode(';', $this->additionalJS_submit)) . '").' . $replace . ');'
3289  . 'TYPO3.TCEFORMS.update();'
3290  . 'return false;';
3291  // Kasper's comment (kept for history):
3292  // Maybe there is a better way to do this than store the HTML for the new element
3293  // in rawurlencoded format - maybe it even breaks with certain charsets?
3294  // But for now this works...
3295  $this->additionalJS_post = $additionalJS_post_saved;
3296  $this->additionalJS_submit = $additionalJS_submit_saved;
3297  $title = '';
3298  if (isset($nCfg['title'])) {
3299  $title = $this->sL($nCfg['title']);
3300  } elseif (isset($nCfg['tx_templavoila']['title'])) {
3301  /* @deprecated since 4.7 will be removed two versions after 6.2 */
3303  'Flexform data for table ' . $table . ', field ' . $field
3304  . 'contains the <tx_templavoila><title>... construct deprecated since TYPO3 4.7. '
3305  . 'The <tx_templavoila> element has to be removed now. Support will be removed two versions after 6.2.'
3306  );
3307  $title = $this->sL($nCfg['tx_templavoila']['title']);
3308  }
3309  $newElementsLinks[] = '<a href="#" onclick="' . htmlspecialchars($onClickInsert) . '">'
3310  . IconUtility::getSpriteIcon('actions-document-new')
3311  . htmlspecialchars(GeneralUtility::fixed_lgd_cs($title, 30)) . '</a>';
3312  }
3313  // Reverting internal variables we don't want to change:
3314  $this->requiredElements = $TEMP_requiredElements;
3315  // Adding the sections:
3316  $toggleAll = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.toggleall', TRUE);
3317  $output .= '
3318  <div class="t3-form-field-toggle-flexsection">
3319  <a href="#" onclick="' . htmlspecialchars(('flexFormToggleSubs("' . $idTagPrefix
3320  . '"); return false;')) . '">'
3321  . IconUtility::getSpriteIcon('actions-move-right', array('title' => $toggleAll)) . $toggleAll . '
3322  </a>
3323  </div>
3324 
3325  <div id="' . $idTagPrefix . '" class="t3-form-field-container-flexsection">' . implode('', $tRows) . '</div>';
3326  $output .= $mayRestructureFlexforms ? '<div class="t3-form-field-add-flexsection"><strong>'
3327  . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.addnew', TRUE)
3328  . ':</strong> ' . implode(' | ', $newElementsLinks) . '</div>' : '';
3329  } else {
3330  // It is a container
3331  $toggleIcon_open = IconUtility::getSpriteIcon('actions-move-down');
3332  $toggleIcon_close = IconUtility::getSpriteIcon('actions-move-right');
3333  // Create on-click actions.
3334  $onClickRemove = 'if (confirm("Are you sure?")){/*###REMOVE###*/;$("' . $idTagPrefix
3335  . '").hide();setActionStatus("' . $idPrefix . '");} return false;';
3336  $onClickToggle = 'flexFormToggle("' . $idTagPrefix . '"); return false;';
3337  $onMove = 'flexFormSortable("' . $idPrefix . '")';
3338  // Notice: Creating "new" elements after others seemed to be too difficult to do
3339  // and since moving new elements created in the bottom is now so easy
3340  // with drag'n'drop I didn't see the need.
3341  // Putting together header of a section. Sections can be removed, copied, opened/closed, moved up and down:
3342  // I didn't know how to make something right-aligned without a table, so I put it in a table.
3343  // can be made into <div>'s if someone like to.
3344  // Notice: The fact that I make a "Sortable.create" right onmousedown is that if we
3345  // initialize this when rendering the form in PHP new and copied elements will not
3346  // be possible to move as a sortable. But this way a new sortable is initialized every time
3347  // someone tries to move and it will always work.
3348  $ctrlHeader = '
3349  <table class="t3-form-field-header-flexsection" onmousedown="' . ($mayRestructureFlexforms ? htmlspecialchars($onMove) : '') . '">
3350  <tr>
3351  <td>
3352  <a href="#" onclick="' . htmlspecialchars($onClickToggle) . '" id="' . $idTagPrefix . '-toggle">
3353  ' . ($toggleClosed ? $toggleIcon_close : $toggleIcon_open) . '
3354  </a>
3355  <strong>' . $theTitle . '</strong> <em><span id="' . $idTagPrefix . '-preview"></span></em>
3356  </td>
3357  <td align="right">'
3358  . ($mayRestructureFlexforms ? IconUtility::getSpriteIcon('actions-move-move', array('title' => 'Drag to Move')) : '')
3359  . ($mayRestructureFlexforms ? '<a href="#" onclick="' . htmlspecialchars($onClickRemove) . '">'
3360  . IconUtility::getSpriteIcon('actions-edit-delete', array('title' => 'Delete')) : '')
3361  . '</td>
3362  </tr>
3363  </table>';
3364  $s = GeneralUtility::revExplode('[]', $formPrefix, 2);
3365  $actionFieldName = '_ACTION_FLEX_FORM' . $PA['itemFormElName'] . $s[0] . '][_ACTION][' . $s[1];
3366  // Push the container to DynNestedStack as it may be toggled
3367  $this->pushToDynNestedStack('flex', $idTagPrefix);
3368  // Putting together the container:
3369  $this->additionalJS_delete = array();
3370  $singleField_typeFlex_draw = $this->getSingleField_typeFlex_draw($value['el'],
3371  $editData[$key]['el'], $table, $field, $row, $PA,
3372  ($formPrefix . '[' . $key . '][el]'), ($level + 1), $idTagPrefix);
3373  $output .= '
3374  <div id="' . $idTagPrefix . '" class="t3-form-field-container-flexsections">
3375  <input id="' . $idTagPrefix . '-action" type="hidden" name="' . htmlspecialchars($actionFieldName) . '" value=""/>
3376 
3377  ' . $ctrlHeader . '
3378  <div class="t3-form-field-record-flexsection" id="' . $idTagPrefix . '-content"'
3379  . ($toggleClosed ? ' style="display:none;"' : '') . '>' . $singleField_typeFlex_draw . '
3380  </div>
3381  <input id="' . $idTagPrefix . '-toggleClosed" type="hidden" name="'
3382  . htmlspecialchars('data[' . $table . '][' . $row['uid'] . '][' . $field . ']' . $formPrefix . '[_TOGGLE]')
3383  . '" value="' . ($toggleClosed ? 1 : 0) . '" />
3384  </div>';
3385  $output = str_replace('/*###REMOVE###*/', htmlspecialchars(implode('', $this->additionalJS_delete), ENT_QUOTES), $output);
3386  // NOTICE: We are saving the toggle-state directly in the flexForm XML and "unauthorized"
3387  // according to the data structure. It means that flexform XML will report unclean and
3388  // a cleaning operation will remove the recorded togglestates. This is not a fatal problem.
3389  // Ideally we should save the toggle states in meta-data but it is much harder to do that.
3390  // And this implementation was easy to make and with no really harmful impact.
3391  // Pop the container from DynNestedStack
3392  $this->popFromDynNestedStack('flex', $idTagPrefix);
3393  }
3394  } elseif (is_array($value['TCEforms']['config'])) {
3395  // Rendering a single form element:
3396  if (is_array($PA['_valLang'])) {
3397  $rotateLang = $PA['_valLang'];
3398  } else {
3399  $rotateLang = array($PA['_valLang']);
3400  }
3401  $conditionData = is_array($editData) ? $editData : array();
3402  // Add current $row to data processed by \TYPO3\CMS\Backend\Form\ElementConditionMatcher
3403  $conditionData['parentRec'] = $row;
3404  $tRows = array();
3405 
3407  $elementConditionMatcher = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\ElementConditionMatcher');
3408 
3409  foreach ($rotateLang as $vDEFkey) {
3410  $vDEFkey = 'v' . $vDEFkey;
3411  $displayConditionResult = TRUE;
3412  if ($value['TCEforms']['displayCond']) {
3413  $displayConditionResult = $elementConditionMatcher->match($value['TCEforms']['displayCond'], $conditionData, $vDEFkey);
3414  }
3415  if ($displayConditionResult) {
3416  $fakePA = array();
3417  $fakePA['fieldConf'] = array(
3418  'label' => $this->sL(trim($value['TCEforms']['label'])),
3419  'config' => $value['TCEforms']['config'],
3420  'defaultExtras' => $value['TCEforms']['defaultExtras'],
3421  'onChange' => $value['TCEforms']['onChange']
3422  );
3423  if ($PA['_noEditDEF'] && $PA['_lang'] === 'lDEF') {
3424  $fakePA['fieldConf']['config'] = array(
3425  'type' => 'none',
3426  'rows' => 2
3427  );
3428  }
3429  if (
3430  $fakePA['fieldConf']['onChange'] === 'reload'
3431  || !empty($GLOBALS['TCA'][$table]['ctrl']['type'])
3432  && (string)$key === $GLOBALS['TCA'][$table]['ctrl']['type']
3433  || !empty($GLOBALS['TCA'][$table]['ctrl']['requestUpdate'])
3434  && GeneralUtility::inList($GLOBALS['TCA'][$table]['ctrl']['requestUpdate'], $key)
3435  ) {
3436  if ($this->getBackendUserAuthentication()->jsConfirmation(1)) {
3437  $alertMsgOnChange = 'if (confirm(TBE_EDITOR.labels.onChangeAlert) && TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
3438  } else {
3439  $alertMsgOnChange = 'if(TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm();}';
3440  }
3441  } else {
3442  $alertMsgOnChange = '';
3443  }
3444  $fakePA['fieldChangeFunc'] = $PA['fieldChangeFunc'];
3445  if (strlen($alertMsgOnChange)) {
3446  $fakePA['fieldChangeFunc']['alert'] = $alertMsgOnChange;
3447  }
3448  $fakePA['onFocus'] = $PA['onFocus'];
3449  $fakePA['label'] = $PA['label'];
3450  $fakePA['itemFormElName'] = $PA['itemFormElName'] . $formPrefix . '[' . $key . '][' . $vDEFkey . ']';
3451  $fakePA['itemFormElName_file'] = $PA['itemFormElName_file'] . $formPrefix . '[' . $key . '][' . $vDEFkey . ']';
3452  $fakePA['itemFormElID'] = $fakePA['itemFormElName'];
3453  if (isset($editData[$key][$vDEFkey])) {
3454  $fakePA['itemFormElValue'] = $editData[$key][$vDEFkey];
3455  } else {
3456  $fakePA['itemFormElValue'] = $fakePA['fieldConf']['config']['default'];
3457  }
3458  $theFormEl = $this->getSingleField_SW($table, $field, $row, $fakePA);
3459  $theTitle = htmlspecialchars($fakePA['fieldConf']['label']);
3460  if (!in_array('DEF', $rotateLang)) {
3461  $defInfo = '<div class="typo3-TCEforms-originalLanguageValue">'
3462  . $this->getLanguageIcon($table, $row, 0)
3463  . $this->previewFieldValue($editData[$key]['vDEF'], $fakePA['fieldConf'], $field)
3464  . '&nbsp;</div>';
3465  } else {
3466  $defInfo = '';
3467  }
3468  if (!$PA['_noEditDEF']) {
3469  $prLang = $this->getAdditionalPreviewLanguages();
3470  foreach ($prLang as $prL) {
3471  $defInfo .= '<div class="typo3-TCEforms-originalLanguageValue">'
3472  . $this->getLanguageIcon($table, $row, ('v' . $prL['ISOcode']))
3473  . $this->previewFieldValue($editData[$key][('v' . $prL['ISOcode'])], $fakePA['fieldConf'], $field)
3474  . '&nbsp;</div>';
3475  }
3476  }
3477  $languageIcon = '';
3478  if ($vDEFkey != 'vDEF') {
3479  $languageIcon = $this->getLanguageIcon($table, $row, $vDEFkey);
3480  }
3481  // Put row together
3482  // possible linebreaks in the label through xml: \n => <br/>, usage of nl2br()
3483  // not possible, so it's done through str_replace
3484  $processedTitle = str_replace('\\n', '<br />', $theTitle);
3485  $tRows[] = '<div class="t3-form-field-container t3-form-field-container-flex">'
3486  . '<div class="t3-form-field-label t3-form-field-label-flex">' . $languageIcon
3487  . BackendUtility::wrapInHelp($PA['_cshKey'], $key, $processedTitle) . '</div>
3488  <div class="t3-form-field t3-form-field-flex">' . $theFormEl . $defInfo
3489  . $this->renderVDEFDiff($editData[$key], $vDEFkey) . '</div>
3490  </div>';
3491  }
3492  }
3493  if (count($tRows)) {
3494  $output .= implode('', $tRows);
3495  }
3496  }
3497  }
3498  }
3499  }
3500  return $output;
3501  }
3502 
3513  public function getSingleField_typeUnknown($table, $field, $row, &$PA) {
3514  $item = 'Unknown type: ' . $PA['fieldConf']['config']['form_type'] . '<br />';
3515  return $item;
3516  }
3517 
3528  public function getSingleField_typeUser($table, $field, $row, &$PA) {
3529  $PA['table'] = $table;
3530  $PA['field'] = $field;
3531  $PA['row'] = $row;
3532  $PA['parameters'] = isset($PA['fieldConf']['config']['parameters']) ? $PA['fieldConf']['config']['parameters'] : array();
3533  $PA['pObj'] = &$this;
3534  return GeneralUtility::callUserFunction($PA['fieldConf']['config']['userFunc'], $PA, $this);
3535  }
3536 
3537  /************************************************************
3538  *
3539  * Field content processing
3540  *
3541  ************************************************************/
3551  public function formatValue($config, $itemValue) {
3552  $format = trim($config['format']);
3553  switch ($format) {
3554  case 'date':
3555  if ($itemValue) {
3556  $option = trim($config['format.']['option']);
3557  if ($option) {
3558  if ($config['format.']['strftime']) {
3559  $value = strftime($option, $itemValue);
3560  } else {
3561  $value = date($option, $itemValue);
3562  }
3563  } else {
3564  $value = date('d-m-Y', $itemValue);
3565  }
3566  } else {
3567  $value = '';
3568  }
3569  if ($config['format.']['appendAge']) {
3570  $age = BackendUtility::calcAge(
3571  $GLOBALS['EXEC_TIME'] - $itemValue,
3572  $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')
3573  );
3574  $value .= ' (' . $age . ')';
3575  }
3576  $itemValue = $value;
3577  break;
3578  case 'datetime':
3579  // compatibility with "eval" (type "input")
3580  if ($itemValue !== '') {
3581  $itemValue = date('H:i d-m-Y', (int)$itemValue);
3582  }
3583  break;
3584  case 'time':
3585  // compatibility with "eval" (type "input")
3586  if ($itemValue !== '') {
3587  $itemValue = date('H:i', (int)$itemValue);
3588  }
3589  break;
3590  case 'timesec':
3591  // compatibility with "eval" (type "input")
3592  if ($itemValue !== '') {
3593  $itemValue = date('H:i:s', (int)$itemValue);
3594  }
3595  break;
3596  case 'year':
3597  // compatibility with "eval" (type "input")
3598  if ($itemValue !== '') {
3599  $itemValue = date('Y', (int)$itemValue);
3600  }
3601  break;
3602  case 'int':
3603  $baseArr = array('dec' => 'd', 'hex' => 'x', 'HEX' => 'X', 'oct' => 'o', 'bin' => 'b');
3604  $base = trim($config['format.']['base']);
3605  $format = $baseArr[$base] ?: 'd';
3606  $itemValue = sprintf('%' . $format, $itemValue);
3607  break;
3608  case 'float':
3609  $precision = MathUtility::forceIntegerInRange($config['format.']['precision'], 1, 10, 2);
3610  $itemValue = sprintf('%.' . $precision . 'f', $itemValue);
3611  break;
3612  case 'number':
3613  $format = trim($config['format.']['option']);
3614  $itemValue = sprintf('%' . $format, $itemValue);
3615  break;
3616  case 'md5':
3617  $itemValue = md5($itemValue);
3618  break;
3619  case 'filesize':
3620  // We need to cast to int here, otherwise empty values result in empty output,
3621  // but we expect zero.
3622  $value = GeneralUtility::formatSize((int)$itemValue);
3623  if ($config['format.']['appendByteSize']) {
3624  $value .= ' (' . $itemValue . ')';
3625  }
3626  $itemValue = $value;
3627  break;
3628  case 'user':
3629  $func = trim($config['format.']['userFunc']);
3630  if ($func) {
3631  $params = array(
3632  'value' => $itemValue,
3633  'args' => $config['format.']['userFunc'],
3634  'config' => $config,
3635  'pObj' => &$this
3636  );
3637  $itemValue = GeneralUtility::callUserFunction($func, $params, $this);
3638  }
3639  break;
3640  default:
3641  // Do nothing e.g. when $format === ''
3642  }
3643  return $itemValue;
3644  }
3645 
3646  /************************************************************
3647  *
3648  * "Configuration" fetching/processing functions
3649  *
3650  ************************************************************/
3660  public function getRTypeNum($table, $row) {
3661  $typeNum = 0;
3662  $field = $GLOBALS['TCA'][$table]['ctrl']['type'];
3663  if ($field) {
3664  if (strpos($field, ':') !== FALSE) {
3665  list($pointerField, $foreignTypeField) = explode(':', $field);
3666  $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$pointerField]['config'];
3667  $relationType = $fieldConfig['type'];
3668  if ($relationType === 'select') {
3669  $foreignUid = $row[$pointerField];
3670  $foreignTable = $fieldConfig['foreign_table'];
3671  } elseif ($relationType === 'group') {
3672  $values = $this->extractValuesOnlyFromValueLabelList($row[$pointerField]);
3673  list(, $foreignUid) = GeneralUtility::revExplode('_', $values[0], 2);
3674  $allowedTables = explode(',', $fieldConfig['allowed']);
3675  // Always take the first configured table.
3676  $foreignTable = $allowedTables[0];
3677  } else {
3678  throw new \RuntimeException('TCA Foreign field pointer fields are only allowed to be used with group or select field types.', 1325861239);
3679  }
3680  if ($foreignUid) {
3681  $foreignRow = BackendUtility::getRecord($foreignTable, $foreignUid, $foreignTypeField);
3682  $this->registerDefaultLanguageData($foreignTable, $foreignRow);
3683  if ($foreignRow[$foreignTypeField]) {
3684  $foreignTypeFieldConfig = $GLOBALS['TCA'][$table]['columns'][$field];
3685  $typeNum = $this->getLanguageOverlayRawValue($foreignTable, $foreignRow, $foreignTypeField, $foreignTypeFieldConfig);
3686  }
3687  }
3688  } else {
3689  $typeFieldConfig = $GLOBALS['TCA'][$table]['columns'][$field];
3690  $typeNum = $this->getLanguageOverlayRawValue($table, $row, $field, $typeFieldConfig);
3691  }
3692  }
3693  if (empty($typeNum)) {
3694  // If that value is an empty string, set it to "0" (zero)
3695  $typeNum = 0;
3696  }
3697  // If current typeNum doesn't exist, set it to 0 (or to 1 for historical reasons, if 0 doesn't exist)
3698  if (!$GLOBALS['TCA'][$table]['types'][$typeNum]) {
3699  $typeNum = $GLOBALS['TCA'][$table]['types']['0'] ? 0 : 1;
3700  }
3701  // Force to string. Necessary for eg '-1' to be recognized as a type value.
3702  $typeNum = (string) $typeNum;
3703  return $typeNum;
3704  }
3705 
3714  public function rearrange($fields) {
3715  $fO = array_flip(GeneralUtility::trimExplode(',', $this->fieldOrder, TRUE));
3716  $newFields = array();
3717  foreach ($fields as $cc => $content) {
3718  $cP = GeneralUtility::trimExplode(';', $content);
3719  if (isset($fO[$cP[0]])) {
3720  $newFields[$fO[$cP[0]]] = $content;
3721  unset($fields[$cc]);
3722  }
3723  }
3724  ksort($newFields);
3725  // Candidate for GeneralUtility::array_merge() if integer-keys will some day make trouble...
3726  $fields = array_merge($newFields, $fields);
3727  return $fields;
3728  }
3729 
3742  public function getExcludeElements($table, $row, $typeNum) {
3743  // Init:
3744  $excludeElements = array();
3745  // If a subtype field is defined for the type
3746  if ($GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field']) {
3747  $sTfield = $GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field'];
3748  if (trim($GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_excludelist'][$row[$sTfield]])) {
3749  $excludeElements = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_excludelist'][$row[$sTfield]], TRUE);
3750  }
3751  }
3752  // If a bitmask-value field has been configured, then find possible fields to exclude based on that:
3753  if ($GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_value_field']) {
3754  $sTfield = $GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_value_field'];
3755  $sTValue = MathUtility::forceIntegerInRange($row[$sTfield], 0);
3756  if (is_array($GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_excludelist_bits'])) {
3757  foreach ($GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_excludelist_bits'] as $bitKey => $eList) {
3758  $bit = substr($bitKey, 1);
3760  $bit = MathUtility::forceIntegerInRange($bit, 0, 30);
3761  if ($bitKey[0] === '-' && !($sTValue & pow(2, $bit)) || $bitKey[0] === '+' && $sTValue & pow(2, $bit)) {
3762  $excludeElements = array_merge($excludeElements, GeneralUtility::trimExplode(',', $eList, TRUE));
3763  }
3764  }
3765  }
3766  }
3767  }
3768  // Return the array of elements:
3769  return $excludeElements;
3770  }
3771 
3782  public function getFieldsToAdd($table, $row, $typeNum) {
3783  // Init:
3784  $addElements = array();
3785  // If a subtype field is defined for the type
3786  $sTfield = '';
3787  if ($GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field']) {
3788  $sTfield = $GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field'];
3789  if (trim($GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_addlist'][$row[$sTfield]])) {
3790  $addElements = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_addlist'][$row[$sTfield]], TRUE);
3791  }
3792  }
3793  // Return the return
3794  return array($addElements, $sTfield);
3795  }
3796 
3807  public function mergeFieldsWithAddedFields($fields, $fieldsToAdd, $table = '') {
3808  if (count($fieldsToAdd[0])) {
3809  $c = 0;
3810  $found = FALSE;
3811  foreach ($fields as $fieldInfo) {
3812  list($fieldName, $label, $paletteName) = GeneralUtility::trimExplode(';', $fieldInfo);
3813  if ($fieldName === $fieldsToAdd[1]) {
3814  $found = TRUE;
3815  } elseif ($fieldName === '--palette--' && $paletteName && $table !== '') {
3816  // Look inside the palette
3817  if (is_array($GLOBALS['TCA'][$table]['palettes'][$paletteName])) {
3818  $itemList = $GLOBALS['TCA'][$table]['palettes'][$paletteName]['showitem'];
3819  if ($itemList) {
3820  $paletteFields = GeneralUtility::trimExplode(',', $itemList, TRUE);
3821  foreach ($paletteFields as $info) {
3822  $fieldParts = GeneralUtility::trimExplode(';', $info);
3823  $theField = $fieldParts[0];
3824  if ($theField === $fieldsToAdd[1]) {
3825  $found = TRUE;
3826  break 1;
3827  }
3828  }
3829  }
3830  }
3831  }
3832  if ($found) {
3833  array_splice($fields, $c + 1, 0, $fieldsToAdd[0]);
3834  break;
3835  }
3836  $c++;
3837  }
3838  }
3839  return $fields;
3840  }
3841 
3854  public function setTSconfig($table, $row, $field = '') {
3855  $mainKey = $table . ':' . $row['uid'];
3856  if (!isset($this->cachedTSconfig[$mainKey])) {
3857  $this->cachedTSconfig[$mainKey] = BackendUtility::getTCEFORM_TSconfig($table, $row);
3858  }
3859  if ($field) {
3860  return $this->cachedTSconfig[$mainKey][$field];
3861  } else {
3862  return $this->cachedTSconfig[$mainKey];
3863  }
3864  }
3865 
3877  public function overrideFieldConf($fieldConfig, $TSconfig) {
3878  if (is_array($TSconfig)) {
3879  $TSconfig = GeneralUtility::removeDotsFromTS($TSconfig);
3880  $type = $fieldConfig['type'];
3881  if (is_array($TSconfig['config']) && is_array($this->allowOverrideMatrix[$type])) {
3882  // Check if the keys in TSconfig['config'] are allowed to override TCA field config:
3883  foreach ($TSconfig['config'] as $key => $_) {
3884  if (!in_array($key, $this->allowOverrideMatrix[$type], TRUE)) {
3885  unset($TSconfig['config'][$key]);
3886  }
3887  }
3888  // Override $GLOBALS['TCA'] field config by remaining TSconfig['config']:
3889  if (count($TSconfig['config'])) {
3890  ArrayUtility::mergeRecursiveWithOverrule($fieldConfig, $TSconfig['config']);
3891  }
3892  }
3893  }
3894  return $fieldConfig;
3895  }
3896 
3908  public function getSpecConfForField($table, $row, $field) {
3909  // Finds the current "types" configuration for the table/row:
3910  $types_fieldConfig = BackendUtility::getTCAtypes($table, $row);
3911  // If this is an array, then traverse it:
3912  if (is_array($types_fieldConfig)) {
3913  foreach ($types_fieldConfig as $vconf) {
3914  // If the input field name matches one found in the 'types' list, then return the 'special' configuration.
3915  if ($vconf['field'] == $field) {
3916  return $vconf['spec'];
3917  }
3918  }
3919  }
3920  return NULL;
3921  }
3922 
3932  public function getSpecConfFromString($extraString, $defaultExtras) {
3933  return BackendUtility::getSpecConfParts($extraString, $defaultExtras);
3934  }
3935 
3945  public function loadPaletteElements($table, $row, $palette, $itemList = '') {
3946  $parts = array();
3947  // Getting excludeElements, if any.
3948  $excludeElements = $this->getExcludeElements($table, $row, $this->getRTypeNum($table, $row));
3949  // Load the palette TCEform elements
3950  if ($GLOBALS['TCA'][$table] && (is_array($GLOBALS['TCA'][$table]['palettes'][$palette]) || $itemList)) {
3951  $itemList = $itemList ? $itemList : $GLOBALS['TCA'][$table]['palettes'][$palette]['showitem'];
3952  if ($itemList) {
3953  $fields = GeneralUtility::trimExplode(',', $itemList, TRUE);
3954  foreach ($fields as $info) {
3955  $fieldParts = GeneralUtility::trimExplode(';', $info);
3956  $theField = $fieldParts[0];
3957  if ($theField === '--linebreak--') {
3958  $parts[]['NAME'] = '--linebreak--';
3959  } elseif (!in_array($theField, $excludeElements) && $GLOBALS['TCA'][$table]['columns'][$theField]) {
3960  $this->palFieldArr[$palette][] = $theField;
3961  $elem = $this->getSingleField($table, $theField, $row, $fieldParts[1], 1, '', $fieldParts[2]);
3962  if (is_array($elem)) {
3963  $parts[] = $elem;
3964  }
3965  }
3966  }
3967  }
3968  }
3969  return $parts;
3970  }
3971 
3972  /************************************************************
3973  *
3974  * Display of localized content etc.
3975  *
3976  ************************************************************/
3988  public function registerDefaultLanguageData($table, $rec) {
3989  // Add default language:
3990  if (
3991  $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $rec[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0
3992  && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']
3993  && (int)$rec[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] > 0
3994  ) {
3995  $lookUpTable = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']
3996  ? $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']
3997  : $table;
3998  // Get data formatted:
3999  $this->defaultLanguageData[$table . ':' . $rec['uid']] = BackendUtility::getRecordWSOL(
4000  $lookUpTable,
4001  (int)$rec[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']]
4002  );
4003  // Get data for diff:
4004  if ($GLOBALS['TCA'][$table]['ctrl']['transOrigDiffSourceField']) {
4005  $this->defaultLanguageData_diff[$table . ':' . $rec['uid']] = unserialize($rec[$GLOBALS['TCA'][$table]['ctrl']['transOrigDiffSourceField']]);
4006  }
4007  // If there are additional preview languages, load information for them also:
4008  $prLang = $this->getAdditionalPreviewLanguages();
4009  foreach ($prLang as $prL) {
4011  $t8Tools = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Configuration\\TranslationConfigurationProvider');
4012  $tInfo = $t8Tools->translationInfo($lookUpTable, (int)$rec[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']], $prL['uid']);
4013  if (is_array($tInfo['translations']) && is_array($tInfo['translations'][$prL['uid']])) {
4014  $this->additionalPreviewLanguageData[$table . ':' . $rec['uid']][$prL['uid']] = BackendUtility::getRecordWSOL($table, (int)$tInfo['translations'][$prL['uid']]['uid']);
4015  }
4016  }
4017  }
4018  }
4019 
4032  public function getLanguageOverlayRawValue($table, $row, $field, $fieldConf) {
4033  $value = $row[$field];
4034  if (is_array($this->defaultLanguageData[$table . ':' . $row['uid']])) {
4035  if (
4036  $fieldConf['l10n_mode'] == 'exclude'
4037  || $fieldConf['l10n_mode'] == 'mergeIfNotBlank' && trim($this->defaultLanguageData[$table . ':' . $row['uid']][$field]) !== ''
4038  ) {
4039  $value = $this->defaultLanguageData[$table . ':' . $row['uid']][$field];
4040  }
4041  }
4042  return $value;
4043  }
4044 
4058  public function renderDefaultLanguageContent($table, $field, $row, $item) {
4059  if (is_array($this->defaultLanguageData[$table . ':' . $row['uid']])) {
4060  $defaultLanguageValue = BackendUtility::getProcessedValue($table, $field, $this->defaultLanguageData[$table . ':' . $row['uid']][$field], 0, 1, FALSE, $this->defaultLanguageData[$table . ':' . $row['uid']]['uid']);
4061  $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$field];
4062  // Don't show content if it's for IRRE child records:
4063  if ($fieldConfig['config']['type'] != 'inline') {
4064  if ($defaultLanguageValue !== '') {
4065  $item .= '<div class="typo3-TCEforms-originalLanguageValue">' . $this->getLanguageIcon($table, $row, 0)
4066  . $this->getMergeBehaviourIcon($fieldConfig['l10n_mode'])
4067  . $this->previewFieldValue($defaultLanguageValue, $fieldConfig, $field) . '&nbsp;</div>';
4068  }
4069  $previewLanguages = $this->getAdditionalPreviewLanguages();
4070  foreach ($previewLanguages as $previewLanguage) {
4071  $defaultLanguageValue = BackendUtility::getProcessedValue($table, $field, $this->additionalPreviewLanguageData[$table . ':' . $row['uid']][$previewLanguage['uid']][$field], 0, 1);
4072  if ($defaultLanguageValue !== '') {
4073  $item .= '<div class="typo3-TCEforms-originalLanguageValue">'
4074  . $this->getLanguageIcon($table, $row, ('v' . $previewLanguage['ISOcode']))
4075  . $this->getMergeBehaviourIcon($fieldConfig['l10n_mode'])
4076  . $this->previewFieldValue($defaultLanguageValue, $fieldConfig, $field) . '&nbsp;</div>';
4077  }
4078  }
4079  }
4080  }
4081  return $item;
4082  }
4083 
4097  public function renderDefaultLanguageDiff($table, $field, $row, $item) {
4098  if (is_array($this->defaultLanguageData_diff[$table . ':' . $row['uid']])) {
4099  // Initialize:
4100  $dLVal = array(
4101  'old' => $this->defaultLanguageData_diff[$table . ':' . $row['uid']],
4102  'new' => $this->defaultLanguageData[$table . ':' . $row['uid']]
4103  );
4104  // There must be diff-data:
4105  if (isset($dLVal['old'][$field])) {
4106  if ((string)$dLVal['old'][$field] !== (string)$dLVal['new'][$field]) {
4107  // Create diff-result:
4108  $t3lib_diff_Obj = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Utility\\DiffUtility');
4109  $diffres = $t3lib_diff_Obj->makeDiffDisplay(
4110  BackendUtility::getProcessedValue($table, $field, $dLVal['old'][$field], 0, 1),
4111  BackendUtility::getProcessedValue($table, $field, $dLVal['new'][$field], 0, 1)
4112  );
4113  $item .= '<div class="typo3-TCEforms-diffBox">' . '<div class="typo3-TCEforms-diffBox-header">'
4114  . htmlspecialchars($this->getLL('l_changeInOrig')) . ':</div>' . $diffres . '</div>';
4115  }
4116  }
4117  }
4118  return $item;
4119  }
4120 
4130  public function renderVDEFDiff($vArray, $vDEFkey) {
4131  $item = NULL;
4132  if (
4133  $GLOBALS['TYPO3_CONF_VARS']['BE']['flexFormXMLincludeDiffBase'] && isset($vArray[$vDEFkey . '.vDEFbase'])
4134  && (string)$vArray[$vDEFkey . '.vDEFbase'] !== (string)$vArray['vDEF']
4135  ) {
4136  // Create diff-result:
4137  $t3lib_diff_Obj = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Utility\\DiffUtility');
4138  $diffres = $t3lib_diff_Obj->makeDiffDisplay($vArray[$vDEFkey . '.vDEFbase'], $vArray['vDEF']);
4139  $item = '<div class="typo3-TCEforms-diffBox">' . '<div class="typo3-TCEforms-diffBox-header">'
4140  . htmlspecialchars($this->getLL('l_changeInOrig')) . ':</div>' . $diffres . '</div>';
4141  }
4142  return $item;
4143  }
4144 
4145  /************************************************************
4146  *
4147  * Form element helper functions
4148  *
4149  ************************************************************/
4168  public function dbFileIcons($fName, $mode, $allowed, $itemArray, $selector = '', $params = array(), $onFocus = '', $table = '', $field = '', $uid = '', $config = array()) {
4169  $disabled = '';
4170  if ($this->renderReadonly || $params['readOnly']) {
4171  $disabled = ' disabled="disabled"';
4172  }
4173  // Sets a flag which means some JavaScript is included on the page to support this element.
4174  $this->printNeededJS['dbFileIcons'] = 1;
4175  // INIT
4176  $uidList = array();
4177  $opt = array();
4178  $itemArrayC = 0;
4179  // Creating <option> elements:
4180  if (is_array($itemArray)) {
4181  $itemArrayC = count($itemArray);
4182  switch ($mode) {
4183  case 'db':
4184  foreach ($itemArray as $pp) {
4185  $pRec = BackendUtility::getRecordWSOL($pp['table'], $pp['id']);
4186  if (is_array($pRec)) {
4187  $pTitle = BackendUtility::getRecordTitle($pp['table'], $pRec, FALSE, TRUE);
4188  $pUid = $pp['table'] . '_' . $pp['id'];
4189  $uidList[] = $pUid;
4190  $title = htmlspecialchars($pTitle);
4191  $opt[] = '<option value="' . htmlspecialchars($pUid) . '" title="' . $title . '">' . $title . '</option>';
4192  }
4193  }
4194  break;
4195  case 'file_reference':
4196 
4197  case 'file':
4198  foreach ($itemArray as $item) {
4199  $itemParts = explode('|', $item);
4200  $uidList[] = ($pUid = ($pTitle = $itemParts[0]));
4201  $title = htmlspecialchars(rawurldecode($itemParts[1]));
4202  $opt[] = '<option value="' . htmlspecialchars(rawurldecode($itemParts[0])) . '" title="' . $title . '">' . $title . '</option>';
4203  }
4204  break;
4205  case 'folder':
4206  foreach ($itemArray as $pp) {
4207  $pParts = explode('|', $pp);
4208  $uidList[] = ($pUid = ($pTitle = $pParts[0]));
4209  $title = htmlspecialchars(rawurldecode($pParts[0]));
4210  $opt[] = '<option value="' . htmlspecialchars(rawurldecode($pParts[0])) . '" title="' . $title . '">' . $title . '</option>';
4211  }
4212  break;
4213  default:
4214  foreach ($itemArray as $pp) {
4215  $pParts = explode('|', $pp, 2);
4216  $uidList[] = ($pUid = $pParts[0]);
4217  $pTitle = $pParts[1];
4218  $title = htmlspecialchars(rawurldecode($pTitle));
4219  $opt[] = '<option value="' . htmlspecialchars(rawurldecode($pUid)) . '" title="' . $title . '">' . $title . '</option>';
4220  }
4221  }
4222  }
4223  // Create selector box of the options
4224  $sSize = $params['autoSizeMax']
4225  ? MathUtility::forceIntegerInRange($itemArrayC + 1, MathUtility::forceIntegerInRange($params['size'], 1), $params['autoSizeMax'])
4226  : $params['size'];
4227  if (!$selector) {
4228  $isMultiple = $params['maxitems'] != 1 && $params['size'] != 1;
4229  $selector = '<select id="' . str_replace('.', '', uniqid('tceforms-multiselect-', TRUE)) . '" '
4230  . ($params['noList'] ? 'style="display: none"' : 'size="' . $sSize . '"' . $this->insertDefStyle('group', 'tceforms-multiselect'))
4231  . ($isMultiple ? ' multiple="multiple"' : '')
4232  . ' name="' . $fName . '_list" ' . $onFocus . $params['style'] . $disabled . '>' . implode('', $opt)
4233  . '</select>';
4234  }
4235  $icons = array(
4236  'L' => array(),
4237  'R' => array()
4238  );
4239  $rOnClickInline = '';
4240  if (!$params['readOnly'] && !$params['noList']) {
4241  if (!$params['noBrowser']) {
4242  // Check against inline uniqueness
4243  $inlineParent = $this->inline->getStructureLevel(-1);
4244  $aOnClickInline = '';
4245  if (is_array($inlineParent) && $inlineParent['uid']) {
4246  if ($inlineParent['config']['foreign_table'] == $table && $inlineParent['config']['foreign_unique'] == $field) {
4247  $objectPrefix = $this->inline->inlineNames['object'] . InlineElement::Structure_Separator . $table;
4248  $aOnClickInline = $objectPrefix . '|inline.checkUniqueElement|inline.setUniqueElement';
4249  $rOnClickInline = 'inline.revertUnique(\'' . $objectPrefix . '\',null,\'' . $uid . '\');';
4250  }
4251  }
4252  if (is_array($config['appearance']) && isset($config['appearance']['elementBrowserType'])) {
4253  $elementBrowserType = $config['appearance']['elementBrowserType'];
4254  } else {
4255  $elementBrowserType = $mode;
4256  }
4257  if (is_array($config['appearance']) && isset($config['appearance']['elementBrowserAllowed'])) {
4258  $elementBrowserAllowed = $config['appearance']['elementBrowserAllowed'];
4259  } else {
4260  $elementBrowserAllowed = $allowed;
4261  }
4262  $aOnClick = 'setFormValueOpenBrowser(\'' . $elementBrowserType . '\',\''
4263  . ($fName . '|||' . $elementBrowserAllowed . '|' . $aOnClickInline) . '\'); return false;';
4264  $spriteIcon = IconUtility::getSpriteIcon('actions-insert-record', array(
4265  'title' => htmlspecialchars($this->getLL('l_browse_' . ($mode == 'db' ? 'db' : 'file')))
4266  ));
4267  $icons['R'][] = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . $spriteIcon . '</a>';
4268  }
4269  if (!$params['dontShowMoveIcons']) {
4270  if ($sSize >= 5) {
4271  $icons['L'][] = IconUtility::getSpriteIcon('actions-move-to-top', array(
4272  'data-fieldname' => $fName,
4273  'class' => 't3-btn t3-btn-moveoption-top',
4274  'title' => htmlspecialchars($this->getLL('l_move_to_top'))
4275  ));
4276  }
4277  $icons['L'][] = IconUtility::getSpriteIcon('actions-move-up', array(
4278  'data-fieldname' => $fName,
4279  'class' => 't3-btn t3-btn-moveoption-up',
4280  'title' => htmlspecialchars($this->getLL('l_move_up'))
4281  ));
4282  $icons['L'][] = IconUtility::getSpriteIcon('actions-move-down', array(
4283  'data-fieldname' => $fName,
4284  'class' => 't3-btn t3-btn-moveoption-down',
4285  'title' => htmlspecialchars($this->getLL('l_move_down'))
4286  ));
4287  if ($sSize >= 5) {
4288  $icons['L'][] = IconUtility::getSpriteIcon('actions-move-to-bottom', array(
4289  'data-fieldname' => $fName,
4290  'class' => 't3-btn t3-btn-moveoption-bottom',
4291  'title' => htmlspecialchars($this->getLL('l_move_to_bottom'))
4292  ));
4293  }
4294  }
4295  $clipElements = $this->getClipboardElements($allowed, $mode);
4296  if (count($clipElements)) {
4297  $aOnClick = '';
4298  foreach ($clipElements as $elValue) {
4299  if ($mode == 'db') {
4300  list($itemTable, $itemUid) = explode('|', $elValue);
4301  $recordTitle = BackendUtility::getRecordTitle($itemTable, BackendUtility::getRecordWSOL($itemTable, $itemUid));
4302  $itemTitle = GeneralUtility::quoteJSvalue($recordTitle);
4303  $elValue = $itemTable . '_' . $itemUid;
4304  } else {
4305  // 'file', 'file_reference' and 'folder' mode
4306  $itemTitle = 'unescape(\'' . rawurlencode(basename($elValue)) . '\')';
4307  }
4308  $aOnClick .= 'setFormValueFromBrowseWin(\'' . $fName . '\',unescape(\''
4309  . rawurlencode(str_replace('%20', ' ', $elValue)) . '\'),' . $itemTitle . ',' . $itemTitle . ');';
4310  }
4311  $aOnClick .= 'return false;';
4312  $spriteIcon1 = IconUtility::getSpriteIcon('actions-document-paste-into', array(
4313  'title' => htmlspecialchars(sprintf($this->getLL('l_clipInsert_' . ($mode == 'db' ? 'db' : 'file')), count($clipElements)))
4314  ));
4315  $icons['R'][] = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . $spriteIcon1 . '</a>';
4316  }
4317  }
4318  if (!$params['readOnly'] && !$params['noDelete']) {
4319  $icons['L'][] = IconUtility::getSpriteIcon('actions-selection-delete', array(
4320  'onclick' => $rOnClickInline,
4321  'data-fieldname' => $fName,
4322  'class' => 't3-btn t3-btn-removeoption',
4323  'title' => htmlspecialchars($this->getLL('l_remove_selected'))
4324 
4325  ));
4326  }
4327  $imagesOnly = FALSE;
4328  if ($params['thumbnails'] && $params['info']) {
4329  // In case we have thumbnails, check if only images are allowed.
4330  // In this case, render them below the field, instead of to the right
4331  $allowedExtensionList = GeneralUtility::trimExplode(' ', strtolower($params['info']), TRUE);
4332  $imageExtensionList = GeneralUtility::trimExplode(',', strtolower($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']), TRUE);
4333  $imagesOnly = TRUE;
4334  foreach ($allowedExtensionList as $allowedExtension) {
4335  if (!GeneralUtility::inArray($imageExtensionList, $allowedExtension)) {
4336  $imagesOnly = FALSE;
4337  break;
4338  }
4339  }
4340  }
4341  if ($imagesOnly) {
4342  $rightbox = '';
4343  $thumbnails = '<div class="imagethumbs">' . $this->wrapLabels($params['thumbnails']) . '</div>';
4344  } else {
4345  $rightbox = $this->wrapLabels($params['thumbnails']);
4346  $thumbnails = '';
4347  }
4348  // Hook: dbFileIcons_postProcess (requested by FAL-team for use with the "fal" extension)
4349  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['dbFileIcons'])) {
4350  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['dbFileIcons'] as $classRef) {
4351  $hookObject = GeneralUtility::getUserObj($classRef);
4352  if (!$hookObject instanceof DatabaseFileIconsHookInterface) {
4353  throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Backend\\Form\\DatabaseFileIconsHookInterface', 1290167704);
4354  }
4355  $additionalParams = array(
4356  'mode' => $mode,
4357  'allowed' => $allowed,
4358  'itemArray' => $itemArray,
4359  'onFocus' => $onFocus,
4360  'table' => $table,
4361  'field' => $field,
4362  'uid' => $uid,
4363  'config' => $GLOBALS['TCA'][$table]['columns'][$field]
4364  );
4365  $hookObject->dbFileIcons_postProcess($params, $selector, $thumbnails, $icons, $rightbox, $fName, $uidList, $additionalParams, $this);
4366  }
4367  }
4368  $str = '<table border="0" cellpadding="0" cellspacing="0" width="1">
4369  ' . ($params['headers'] ? '
4370  <tr>
4371  <td>' . $this->wrapLabels($params['headers']['selector']) . '</td>
4372  <td></td>
4373  <td></td>
4374  <td>' . ($params['thumbnails'] ? $this->wrapLabels($params['headers']['items']) : '') . '</td>
4375  </tr>' : '') . '
4376  <tr>
4377  <td valign="top">' . $selector . $thumbnails;
4378  if (!$params['noList'] && $params['info'] !== '') {
4379  $str .= '<span class="filetypes">' . $this->wrapLabels($params['info']) . '</span>';
4380  }
4381  $str .= '</td>
4382  <td valign="top" class="icons">' . implode('<br />', $icons['L']) . '</td>
4383  <td valign="top" class="icons">' . implode('<br />', $icons['R']) . '</td>
4384  <td valign="top">' . $rightbox . '</td>
4385  </tr>
4386  </table>';
4387  // Creating the hidden field which contains the actual value as a comma list.
4388  $str .= '<input type="hidden" name="' . $fName . '" value="' . htmlspecialchars(implode(',', $uidList)) . '" />';
4389  return $str;
4390  }
4391 
4400  public function getClipboardElements($allowed, $mode) {
4401  $output = array();
4402  if (is_object($this->clipObj)) {
4403  switch ($mode) {
4404  case 'file_reference':
4405 
4406  case 'file':
4407  $elFromTable = $this->clipObj->elFromTable('_FILE');
4408  $allowedExts = GeneralUtility::trimExplode(',', $allowed, TRUE);
4409  // If there are a set of allowed extensions, filter the content:
4410  if ($allowedExts) {
4411  foreach ($elFromTable as $elValue) {
4412  $pI = pathinfo($elValue);
4413  $ext = strtolower($pI['extension']);
4414  if (in_array($ext, $allowedExts)) {
4415  $output[] = $elValue;
4416  }
4417  }
4418  } else {
4419  // If all is allowed, insert all: (This does NOT respect any disallowed extensions,
4420  // but those will be filtered away by the backend TCEmain)
4421  $output = $elFromTable;
4422  }
4423  break;
4424  case 'db':
4425  $allowedTables = GeneralUtility::trimExplode(',', $allowed, TRUE);
4426  // All tables allowed for relation:
4427  if (trim($allowedTables[0]) === '*') {
4428  $output = $this->clipObj->elFromTable('');
4429  } else {
4430  // Only some tables, filter them:
4431  foreach ($allowedTables as $tablename) {
4432  $elFromTable = $this->clipObj->elFromTable($tablename);
4433  $output = array_merge($output, $elFromTable);
4434  }
4435  }
4436  $output = array_keys($output);
4437  break;
4438  }
4439  }
4440  return $output;
4441  }
4442 
4454  public function getClickMenu($str, $table, $uid = 0) {
4455  if ($this->enableClickMenu) {
4456  $onClick = $this->getControllerDocumentTemplate()->wrapClickMenuOnIcon($str, $table, $uid, 1, '', '+copy,info,edit,view', TRUE);
4457  return '<a href="#" onclick="' . htmlspecialchars($onClick) . '">' . $str . '</a>';
4458  }
4459  return NULL;
4460  }
4461 
4477  public function renderWizards($itemKinds, $wizConf, $table, $row, $field, &$PA, $itemName, $specConf, $RTE = FALSE) {
4478  // Init:
4479  $fieldChangeFunc = $PA['fieldChangeFunc'];
4480  $item = $itemKinds[0];
4481  $outArr = array();
4482  $colorBoxLinks = array();
4483  $fName = '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
4484  $md5ID = 'ID' . GeneralUtility::shortmd5($itemName);
4485  $listFlag = '_list';
4486  $fieldConfig = $PA['fieldConf']['config'];
4487  $prefixOfFormElName = 'data[' . $table . '][' . $row['uid'] . '][' . $field . ']';
4488  $flexFormPath = '';
4489  if (GeneralUtility::isFirstPartOfStr($PA['itemFormElName'], $prefixOfFormElName)) {
4490  $flexFormPath = str_replace('][', '/', substr($PA['itemFormElName'], strlen($prefixOfFormElName) + 1, -1));
4491  }
4492  // Manipulate the field name (to be the TRUE form field name) and remove
4493  // a suffix-value if the item is a selector box with renderMode "singlebox":
4494  if ($PA['fieldConf']['config']['form_type'] == 'select') {
4495  // Single select situation:
4496  if ($PA['fieldConf']['config']['maxitems'] <= 1) {
4497  $listFlag = '';
4498  } elseif ($PA['fieldConf']['config']['renderMode'] == 'singlebox') {
4499  $itemName .= '[]';
4500  $listFlag = '';
4501  }
4502  }
4503  // Traverse wizards:
4504  if (is_array($wizConf) && !$this->disableWizards) {
4505  $parametersOfWizards = &$specConf['wizards']['parameters'];
4506  foreach ($wizConf as $wid => $wConf) {
4507  if (
4508  $wid[0] !== '_' && (!$wConf['enableByTypeConfig']
4509  || is_array($parametersOfWizards) && in_array($wid, $parametersOfWizards)) && ($RTE || !$wConf['RTEonly'])
4510  ) {
4511  // Title / icon:
4512  $iTitle = htmlspecialchars($this->sL($wConf['title']));
4513  if ($wConf['icon']) {
4514  $icon = $this->getIconHtml($wConf['icon'], $iTitle, $iTitle);
4515  } else {
4516  $icon = $iTitle;
4517  }
4518  switch ((string) $wConf['type']) {
4519  case 'userFunc':
4520 
4521  case 'script':
4522 
4523  case 'popup':
4524 
4525  case 'colorbox':
4526 
4527  case 'slider':
4528  if (!$wConf['notNewRecords'] || MathUtility::canBeInterpretedAsInteger($row['uid'])) {
4529  // Setting &P array contents:
4530  $params = array();
4531  // Including the full fieldConfig from TCA may produce too long an URL
4532  if ($wid != 'RTE') {
4533  $params['fieldConfig'] = $fieldConfig;
4534  }
4535  $params['params'] = $wConf['params'];
4536  $params['exampleImg'] = $wConf['exampleImg'];
4537  $params['table'] = $table;
4538  $params['uid'] = $row['uid'];
4539  $params['pid'] = $row['pid'];
4540  $params['field'] = $field;
4541  $params['flexFormPath'] = $flexFormPath;
4542  $params['md5ID'] = $md5ID;
4543  $params['returnUrl'] = $this->thisReturnUrl();
4544 
4545  $wScript = '';
4546  // Resolving script filename and setting URL.
4547  if (isset($wConf['module']['name'])) {
4548  $urlParameters = array();
4549  if (isset($wConf['module']['urlParameters']) && is_array($wConf['module']['urlParameters'])) {
4550  $urlParameters = $wConf['module']['urlParameters'];
4551  }
4552  $wScript = BackendUtility::getModuleUrl($wConf['module']['name'], $urlParameters, $this->backPath);
4553  } elseif (isset($wConf['script'])) {
4555  'The way registering a wizard in TCA has changed in 6.2. '
4556  . 'Please set module[name]=module_name instead of using script=path/to/script.php in your TCA. '
4557  . 'The possibility to register wizards this way will be removed in TYPO3 CMS 7.'
4558  );
4559  if (substr($wConf['script'], 0, 4) === 'EXT:') {
4560  $wScript = GeneralUtility::getFileAbsFileName($wConf['script']);
4561  if ($wScript) {
4562  $wScript = $this->backPath . '../' . PathUtility::stripPathSitePrefix($wScript);
4563  } else {
4564  // Illeagal configuration, fail silently
4565  break;
4566  }
4567  } else {
4568  // Compatibility layer
4569  // @deprecated since 6.2, will be removed 2 versions later
4570  $parsedWizardUrl = parse_url($wConf['script']);
4571  if (in_array($parsedWizardUrl['path'], array(
4572  'wizard_add.php',
4573  'wizard_colorpicker.php',
4574  'wizard_edit.php',
4575  'wizard_forms.php',
4576  'wizard_list.php',
4577  'wizard_rte.php',
4578  'wizard_table.php',
4579  'browse_links.php',
4580  'sysext/cms/layout/wizard_backend_layout.php'
4581  ))
4582  ) {
4583  $urlParameters = array();
4584  if (isset($parsedWizardUrl['query'])) {
4585  parse_str($parsedWizardUrl['query'], $urlParameters);
4586  }
4587  $moduleName = str_replace(
4588  array('.php', 'browse_links', 'sysext/cms/layout/wizard_backend_layout'),
4589  array('', 'wizard_element_browser', 'wizard_backend_layout'),
4590  $parsedWizardUrl['path']
4591  );
4592  $wScript = BackendUtility::getModuleUrl($moduleName, $urlParameters, $this->backPath);
4593  unset($moduleName, $urlParameters, $parsedWizardUrl);
4594  } else {
4595  $wScript = $wConf['script'];
4596  }
4597  }
4598  } elseif (in_array($wConf['type'], array('script', 'colorbox', 'popup'), TRUE)) {
4599  // Illegal configuration, fail silently
4600  break;
4601  }
4602 
4603  $url = ($wScript ?: $this->backPath) . (strstr($wScript, '?') ? '' : '?');
4604  // If "script" type, create the links around the icon:
4605  if ((string) $wConf['type'] === 'script') {
4606  $aUrl = $url . GeneralUtility::implodeArrayForUrl('', array('P' => $params));
4607  $outArr[] = '<a href="' . htmlspecialchars($aUrl) . '" onclick="this.blur(); return !TBE_EDITOR.isFormChanged();">' . $icon . '</a>';
4608  } else {
4609  // ... else types "popup", "colorbox" and "userFunc" will need additional parameters:
4610  $params['formName'] = $this->formName;
4611  $params['itemName'] = $itemName;
4612  $params['hmac'] = GeneralUtility::hmac($params['formName'] . $params['itemName'], 'wizard_js');
4613  $params['fieldChangeFunc'] = $fieldChangeFunc;
4614  $params['fieldChangeFuncHash'] = GeneralUtility::hmac(serialize($fieldChangeFunc));
4615  switch ((string) $wConf['type']) {
4616  case 'popup':
4617  case 'colorbox':
4618  // Current form value is passed as P[currentValue]!
4619  $addJS = $wConf['popup_onlyOpenIfSelected']
4620  ? 'if (!TBE_EDITOR.curSelected(\'' . $itemName . $listFlag . '\')){alert('
4621  . GeneralUtility::quoteJSvalue($this->getLL('m_noSelItemForEdit'))
4622  . '); return false;}'
4623  : '';
4624  $curSelectedValues = '+\'&P[currentSelectedValues]=\'+TBE_EDITOR.curSelected(\'' . $itemName . $listFlag . '\')';
4625  $aOnClick = 'this.blur();' . $addJS . 'vHWin=window.open(\'' . $url
4626  . GeneralUtility::implodeArrayForUrl('', array('P' => $params))
4627  . '\'+\'&P[currentValue]=\'+TBE_EDITOR.rawurlencode('
4628  . $this->elName($itemName) . '.value,200)' . $curSelectedValues
4629  . ',\'popUp' . $md5ID . '\',\'' . $wConf['JSopenParams'] . '\');'
4630  . 'vHWin.focus();return false;';
4631  // Setting "colorBoxLinks" - user LATER to wrap around the color box as well:
4632  $colorBoxLinks = array('<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">', '</a>');
4633  if ((string) $wConf['type'] == 'popup') {
4634  $outArr[] = $colorBoxLinks[0] . $icon . $colorBoxLinks[1];
4635  }
4636  break;
4637  case 'userFunc':
4638  // Reference set!
4639  $params['item'] = &$item;
4640  $params['icon'] = $icon;
4641  $params['iTitle'] = $iTitle;
4642  $params['wConf'] = $wConf;
4643  $params['row'] = $row;
4644  $outArr[] = GeneralUtility::callUserFunction($wConf['userFunc'], $params, $this);
4645  break;
4646  case 'slider':
4647  // Reference set!
4648  $params['item'] = &$item;
4649  $params['icon'] = $icon;
4650  $params['iTitle'] = $iTitle;
4651  $params['wConf'] = $wConf;
4652  $params['row'] = $row;
4653  $wizard = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\Element\\ValueSlider');
4654  $outArr[] = call_user_func_array(array(&$wizard, 'renderWizard'), array(&$params, &$this));
4655  break;
4656  }
4657  }
4658  // Hide the real form element?
4659  if (is_array($wConf['hideParent']) || $wConf['hideParent']) {
4660  // Setting the item to a hidden-field.
4661  $item = $itemKinds[1];
4662  if (is_array($wConf['hideParent'])) {
4663  $item .= $this->getSingleField_typeNone_render($wConf['hideParent'], $PA['itemFormElValue']);
4664  }
4665  }
4666  }
4667  break;
4668  case 'select':
4669  $fieldValue = array('config' => $wConf);
4670  $TSconfig = $this->setTSconfig($table, $row);
4671  $TSconfig[$field] = $TSconfig[$field]['wizards.'][$wid . '.'];
4672  $selItems = $this->addSelectOptionsToItemArray($this->initItemArray($fieldValue), $fieldValue, $TSconfig, $field);
4673  // Process items by a user function:
4674  if (!empty($wConf['itemsProcFunc'])) {
4675  $funcConfig = !empty($wConf['itemsProcFunc.']) ? $wConf['itemsProcFunc.'] : array();
4676  $selItems = $this->procItems($selItems, $funcConfig, $wConf, $table, $row, $field);
4677  }
4678  $opt = array();
4679  $opt[] = '<option>' . $iTitle . '</option>';
4680  foreach ($selItems as $p) {
4681  $opt[] = '<option value="' . htmlspecialchars($p[1]) . '">' . htmlspecialchars($p[0]) . '</option>';
4682  }
4683  if ($wConf['mode'] == 'append') {
4684  $assignValue = $this->elName($itemName) . '.value=\'\'+this.options[this.selectedIndex].value+' . $this->elName($itemName) . '.value';
4685  } elseif ($wConf['mode'] == 'prepend') {
4686  $assignValue = $this->elName($itemName) . '.value+=\'\'+this.options[this.selectedIndex].value';
4687  } else {
4688  $assignValue = $this->elName($itemName) . '.value=this.options[this.selectedIndex].value';
4689  }
4690  $sOnChange = $assignValue . ';this.blur();this.selectedIndex=0;' . implode('', $fieldChangeFunc);
4691  $outArr[] = '<select id="' . str_replace('.', '', uniqid('tceforms-select-', TRUE))
4692  . '" class="tceforms-select tceforms-wizardselect" name="_WIZARD' . $fName . '" onchange="'
4693  . htmlspecialchars($sOnChange) . '">' . implode('', $opt) . '</select>';
4694  break;
4695  case 'suggest':
4696  if (!empty($PA['fieldTSConfig']['suggest.']['default.']['hide'])) {
4697  break;
4698  }
4699  $outArr[] = $this->suggest->renderSuggestSelector($PA['itemFormElName'], $table, $field, $row, $PA);
4700  break;
4701  }
4702  // Color wizard colorbox:
4703  if ((string) $wConf['type'] === 'colorbox') {
4704  $dim = GeneralUtility::intExplode('x', $wConf['dim']);
4705  $dX = MathUtility::forceIntegerInRange($dim[0], 1, 200, 20);
4706  $dY = MathUtility::forceIntegerInRange($dim[1], 1, 200, 20);
4707  $color = $PA['itemFormElValue'] ? ' bgcolor="' . htmlspecialchars($PA['itemFormElValue']) . '"' : '';
4708  $skinImg = IconUtility::skinImg(
4709  $this->backPath,
4710  $color === '' ? 'gfx/colorpicker_empty.png' : 'gfx/colorpicker.png',
4711  'width="' . $dX . '" height="' . $dY . '"' . BackendUtility::titleAltAttrib(trim($iTitle . ' ' . $PA['itemFormElValue'])) . ' border="0"'
4712  );
4713  $outArr[] = '<table border="0" cellpadding="0" cellspacing="0" id="' . $md5ID . '"' . $color
4714  . ' style="' . htmlspecialchars($wConf['tableStyle']) . '">
4715  <tr>
4716  <td>' . $colorBoxLinks[0] . '<img ' . $skinImg . '>' . $colorBoxLinks[1] . '</td>
4717  </tr>
4718  </table>';
4719  }
4720  }
4721  }
4722  // For each rendered wizard, put them together around the item.
4723  if (count($outArr)) {
4724  if ($wizConf['_HIDDENFIELD']) {
4725  $item = $itemKinds[1];
4726  }
4727  $vAlign = $wizConf['_VALIGN'] ? ' style="vertical-align:' . $wizConf['_VALIGN'] . '"' : '';
4728  if (count($outArr) > 1 || $wizConf['_PADDING']) {
4729  $dist = (int)$wizConf['_DISTANCE'];
4730  if ($wizConf['_VERTICAL']) {
4731  $dist = $dist ? '<tr><td><img src="clear.gif" width="1" height="' . $dist . '" alt="" /></td></tr>' : '';
4732  $outStr = '<tr><td>' . implode(('</td></tr>' . $dist . '<tr><td>'), $outArr) . '</td></tr>';
4733  } else {
4734  $dist = $dist ? '<td><img src="clear.gif" height="1" width="' . $dist . '" alt="" /></td>' : '';
4735  $outStr = '<tr><td' . $vAlign . '>' . implode(('</td>' . $dist . '<td' . $vAlign . '>'), $outArr) . '</td></tr>';
4736  }
4737  $outStr = '<table border="0" cellpadding="' . (int)$wizConf['_PADDING'] . '" cellspacing="' . (int)$wizConf['_PADDING'] . '">' . $outStr . '</table>';
4738  } else {
4739  $outStr = implode('', $outArr);
4740  }
4741  if ($wizConf['_POSITION'] === 'left') {
4742  $outStr = '<tr><td' . $vAlign . '>' . $outStr . '</td><td' . $vAlign . '>' . $item . '</td></tr>';
4743  } elseif ($wizConf['_POSITION'] === 'top') {
4744  $outStr = '<tr><td>' . $outStr . '</td></tr><tr><td>' . $item . '</td></tr>';
4745  } elseif ($wizConf['_POSITION'] === 'bottom') {
4746  $outStr = '<tr><td>' . $item . '</td></tr><tr><td>' . $outStr . '</td></tr>';
4747  } else {
4748  $outStr = '<tr><td' . $vAlign . '>' . $item . '</td><td' . $vAlign . '>' . $outStr . '</td></tr>';
4749  }
4750  $item = '<table border="0" cellpadding="0" cellspacing="0">' . $outStr . '</table>';
4751  }
4752  }
4753  return $item;
4754  }
4755 
4763  public function getIcon($icon) {
4764  $selIconInfo = FALSE;
4765  if (substr($icon, 0, 4) == 'EXT:') {
4766  $file = GeneralUtility::getFileAbsFileName($icon);
4767  if ($file) {
4768  $file = PathUtility::stripPathSitePrefix($file);
4769  $selIconFile = $this->backPath . '../' . $file;
4770  $selIconInfo = @getimagesize((PATH_site . $file));
4771  } else {
4772  $selIconFile = '';
4773  }
4774  } elseif (substr($icon, 0, 3) == '../') {
4775  $selIconFile = $this->backPath . GeneralUtility::resolveBackPath($icon);
4776  if (is_file(PATH_site . GeneralUtility::resolveBackPath(substr($icon, 3)))) {
4777  $selIconInfo = getimagesize((PATH_site . GeneralUtility::resolveBackPath(substr($icon, 3))));
4778  }
4779  } elseif (substr($icon, 0, 4) == 'ext/' || substr($icon, 0, 7) == 'sysext/') {
4780  $selIconFile = $this->backPath . $icon;
4781  if (is_file(PATH_typo3 . $icon)) {
4782  $selIconInfo = getimagesize(PATH_typo3 . $icon);
4783  }
4784  } else {
4785  $selIconFile = IconUtility::skinImg($this->backPath, 'gfx/' . $icon, '', 1);
4786  $iconPath = substr($selIconFile, strlen($this->backPath));
4787  if (is_file(PATH_typo3 . $iconPath)) {
4788  $selIconInfo = getimagesize(PATH_typo3 . $iconPath);
4789  }
4790  }
4791  if ($selIconInfo === FALSE) {
4792  // Unset to empty string if icon is not available
4793  $selIconFile = '';
4794  }
4795  return array($selIconFile, $selIconInfo);
4796  }
4797 
4806  protected function getIconHtml($icon, $alt = '', $title = '') {
4807  $iconArray = $this->getIcon($icon);
4808  if (!empty($iconArray[0]) && is_file(GeneralUtility::resolveBackPath(PATH_typo3 . PATH_typo3_mod . $iconArray[0]))) {
4809  return '<img src="' . $iconArray[0] . '" alt="' . $alt . '" ' . ($title ? 'title="' . $title . '"' : '') . ' />';
4810  } else {
4811  return IconUtility::getSpriteIcon($icon, array('alt' => $alt, 'title' => $title));
4812  }
4813  }
4814 
4823  public function optionTagStyle($iconString) {
4824  if (!$iconString) {
4825  return NULL;
4826  }
4827  list($selIconFile, $selIconInfo) = $this->getIcon($iconString);
4828  if (empty($selIconFile)) {
4829  // Skip background style if image is unavailable
4830  return '';
4831  }
4832  $padLeft = $selIconInfo[0] + 4;
4833  if ($padLeft >= 18 && $padLeft <= 24) {
4834  // In order to get the same padding for all option tags even if icon sizes differ a little,
4835  // set it to 22 if it was between 18 and 24 pixels
4836  $padLeft = 22;
4837  }
4838  $padTop = MathUtility::forceIntegerInRange(($selIconInfo[1] - 12) / 2, 0);
4839  $styleAttr = 'background: #fff url(' . $selIconFile . ') 0% 50% no-repeat; height: '
4840  . MathUtility::forceIntegerInRange(($selIconInfo[1] + 2 - $padTop), 0)
4841  . 'px; padding-top: ' . $padTop . 'px; padding-left: ' . $padLeft . 'px;';
4842  return $styleAttr;
4843  }
4844 
4853  public function optgroupTagStyle($iconString) {
4854  if (!$iconString) {
4855  return NULL;
4856  }
4857  list($selIconFile, $selIconInfo) = $this->getIcon($iconString);
4858  if (empty($selIconFile)) {
4859  // Skip background style if image is unavailable
4860  return '';
4861  }
4862  $padLeft = $selIconInfo[0] + 4;
4863  if ($padLeft >= 18 && $padLeft <= 24) {
4864  // In order to get the same padding for all option tags even if icon sizes differ a little,
4865  // set it to 22, if it was between 18 and 24 pixels.
4866  $padLeft = 22;
4867  }
4868  $padTop = MathUtility::forceIntegerInRange(($selIconInfo[1] - 12) / 2, 0);
4869  return 'background: #ffffff url(' . $selIconFile . ') 0 0 no-repeat; padding-top: ' . $padTop . 'px; padding-left: ' . $padLeft . 'px;';
4870  }
4871 
4879  public function extractValuesOnlyFromValueLabelList($itemFormElValue) {
4880  // Get values of selected items:
4881  $itemArray = GeneralUtility::trimExplode(',', $itemFormElValue, TRUE);
4882  foreach ($itemArray as $tk => $tv) {
4883  $tvP = explode('|', $tv, 2);
4884  $tvP[0] = rawurldecode($tvP[0]);
4885  $itemArray[$tk] = $tvP[0];
4886  }
4887  return $itemArray;
4888  }
4889 
4901  public function wrapOpenPalette($header, $table, $row, $palette, $retFunc) {
4902  $id = 'TCEFORMS_' . $table . '_' . $palette . '_' . $row['uid'];
4903  $res = '<a href="#" onclick="TBE_EDITOR.toggle_display_states(\'' . $id . '\',\'block\',\'none\'); return false;" >' . $header . '</a>';
4904  return array($res, '');
4905  }
4906 
4918  public function wrapPaletteField($code, $table, $row, $palette, $collapsed) {
4919  $display = $collapsed ? 'none' : 'block';
4920  $id = 'TCEFORMS_' . $table . '_' . $palette . '_' . $row['uid'];
4921  $code = '<div id="' . $id . '" style="display:' . $display . ';" >' . $code . '</div>';
4922  return $code;
4923  }
4924 
4936  public function checkBoxParams($itemName, $thisValue, $c, $iCount, $addFunc = '') {
4937  $onClick = $this->elName($itemName) . '.value=this.checked?(' . $this->elName($itemName) . '.value|' . pow(2, $c)
4938  . '):(' . $this->elName($itemName) . '.value&' . (pow(2, $iCount) - 1 - pow(2, $c)) . ');' . $addFunc;
4939  $str = ' onclick="' . htmlspecialchars($onClick) . '"' . ($thisValue & pow(2, $c) ? ' checked="checked"' : '');
4940  return $str;
4941  }
4942 
4950  public function elName($itemName) {
4951  return 'document.' . $this->formName . '[\'' . $itemName . '\']';
4952  }
4953 
4960  public function thisReturnUrl() {
4961  return $this->returnUrl ? $this->returnUrl : GeneralUtility::linkThisScript();
4962  }
4963 
4974  public function getSingleHiddenField($table, $field, $row) {
4975  $item = '';
4976  if ($GLOBALS['TCA'][$table]['columns'][$field]) {
4977  $uid = $row['uid'];
4978  $itemName = $this->prependFormFieldNames . '[' . $table . '][' . $uid . '][' . $field . ']';
4979  $itemValue = $row[$field];
4980  $item = '<input type="hidden" name="' . $itemName . '" value="' . htmlspecialchars($itemValue) . '" />';
4981  }
4982  return $item;
4983  }
4984 
4993  public function formWidth($size = 48, $textarea = FALSE) {
4994  $fieldWidthAndStyle = $this->formWidthAsArray($size, $textarea);
4995  // Setting width by style-attribute. 'cols' MUST be avoided with NN6+
4996  $widthAndStyleAttributes = ' style="' . htmlspecialchars($fieldWidthAndStyle['style']) . '"';
4997  if ($fieldWidthAndStyle['class']) {
4998  $widthAndStyleAttributes .= ' class="' . htmlspecialchars($fieldWidthAndStyle['class']) . '"';
4999  }
5000  return $widthAndStyleAttributes;
5001  }
5002 
5010  protected function formWidthAsArray($size = 48, $textarea = FALSE) {
5011  $fieldWidthAndStyle = array('style' => '', 'class' => '', 'width' => '');
5012  $size = round($size * $this->form_largeComp);
5013 
5014  // Setting width by style-attribute. 'cols' MUST be avoided with NN6+
5015  $widthInPixels = ceil($size * $this->form_rowsToStylewidth);
5016 
5017  if ($textarea) {
5018  $widthInPixels += $this->form_additionalTextareaStyleWidth;
5019  }
5020 
5021  $fieldWidthAndStyle['style'] = 'width: ' . $widthInPixels . 'px; ' . $this->defStyle . $this->formElStyle($textarea ? 'text' : 'input');
5022  $fieldWidthAndStyle['class'] = $this->formElClass($textarea ? 'text' : 'input');
5023  return $fieldWidthAndStyle;
5024  }
5025 
5035  public function formWidthText($size = 48, $wrap = '') {
5036  $wTags = $this->formWidth($size, TRUE);
5037  // Netscape 6+ seems to have this ODD problem where there WILL ALWAYS be wrapping
5038  // with the cols-attribute set and NEVER without the col-attribute...
5039  if (strtolower(trim($wrap)) != 'off' && $GLOBALS['CLIENT']['BROWSER'] == 'net' && $GLOBALS['CLIENT']['VERSION'] >= 5) {
5040  $wTags .= ' cols="' . $size . '"';
5041  }
5042  return $wTags;
5043  }
5044 
5053  public function formElStyle($type) {
5054  return $this->formElStyleClassValue($type);
5055  }
5056 
5065  public function formElClass($type) {
5066  return $this->formElStyleClassValue($type, TRUE);
5067  }
5068 
5077  public function formElStyleClassValue($type, $class = FALSE) {
5078  // Get value according to field:
5079  if (isset($this->fieldStyle[$type])) {
5080  $style = trim($this->fieldStyle[$type]);
5081  } else {
5082  $style = trim($this->fieldStyle['all']);
5083  }
5084  // Check class prefixed:
5085  if (substr($style, 0, 6) == 'CLASS:') {
5086  $out = $class ? trim(substr($style, 6)) : '';
5087  } else {
5088  $out = !$class ? $style : '';
5089  }
5090  return $out;
5091  }
5092 
5101  public function insertDefStyle($type, $additionalClass = '') {
5102  $out = '';
5103  $style = trim($this->defStyle . $this->formElStyle($type));
5104  $out .= $style ? ' style="' . htmlspecialchars($style) . '"' : '';
5105  $class = $this->formElClass($type);
5106  $classAttributeValue = join(' ', array_filter(array($class, $additionalClass)));
5107  $out .= $classAttributeValue ? ' class="' . htmlspecialchars($classAttributeValue) . '"' : '';
5108  return $out;
5109  }
5110 
5120  public function getDynTabMenu($parts, $idString, $dividersToTabsBehaviour = 1) {
5121  $docTemplate = $this->getDocumentTemplate();
5122  if (is_object($docTemplate)) {
5123  $docTemplate->backPath = $this->backPath;
5124  return $docTemplate->getDynTabMenu($parts, $idString, 0, FALSE, 1, FALSE, 1, $dividersToTabsBehaviour);
5125  } else {
5126  $output = '';
5127  foreach ($parts as $singlePad) {
5128  $output .= '
5129  <h3>' . htmlspecialchars($singlePad['label']) . '</h3>
5130  ' . ($singlePad['description'] ? '<p class="c-descr">' . nl2br(htmlspecialchars($singlePad['description'])) . '</p>' : '') . '
5131  ' . $singlePad['content'];
5132  }
5133  return '<div class="typo3-dyntabmenu-divs">' . $output . '</div>';
5134  }
5135  }
5136 
5137  /************************************************************
5138  *
5139  * Item-array manipulation functions (check/select/radio)
5140  *
5141  ************************************************************/
5150  public function initItemArray($fieldValue) {
5151  $items = array();
5152  if (is_array($fieldValue['config']['items'])) {
5153  foreach ($fieldValue['config']['items'] as $itemValue) {
5154  $items[] = array($this->sL($itemValue[0]), $itemValue[1], $itemValue[2]);
5155  }
5156  }
5157  return $items;
5158  }
5159 
5168  public function addItems($items, $iArray) {
5169  if (is_array($iArray)) {
5170  foreach ($iArray as $value => $label) {
5171  $items[] = array($this->sl($label), $value);
5172  }
5173  }
5174  return $items;
5175  }
5176 
5189  public function procItems($items, $iArray, $config, $table, $row, $field) {
5190  $params = array();
5191  $params['items'] = &$items;
5192  $params['config'] = $config;
5193  $params['TSconfig'] = $iArray;
5194  $params['table'] = $table;
5195  $params['row'] = $row;
5196  $params['field'] = $field;
5197  // The itemsProcFunc method may throw an exception.
5198  // If it does display an error message and return items unchanged.
5199  try {
5200  GeneralUtility::callUserFunction($config['itemsProcFunc'], $params, $this);
5201  } catch (\Exception $exception) {
5202  $fieldLabel = $field;
5203  if (isset($GLOBALS['TCA'][$table]['columns'][$field]['label'])) {
5204  $fieldLabel = $this->sL($GLOBALS['TCA'][$table]['columns'][$field]['label']);
5205  }
5206  $message = sprintf(
5207  $this->sL('LLL:EXT:lang/locallang_core.xlf:error.items_proc_func_error'),
5208  $fieldLabel,
5209  $exception->getMessage()
5210  );
5212  $flashMessage = GeneralUtility::makeInstance(
5213  'TYPO3\\CMS\\Core\\Messaging\\FlashMessage',
5214  htmlspecialchars($message),
5215  '',
5216  FlashMessage::ERROR,
5217  TRUE
5218  );
5219  $class = 'TYPO3\\CMS\\Core\\Messaging\\FlashMessageService';
5221  $flashMessageService = GeneralUtility::makeInstance($class);
5222  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
5223  $defaultFlashMessageQueue->enqueue($flashMessage);
5224  }
5225  return $items;
5226  }
5227 
5238  public function addSelectOptionsToItemArray($items, $fieldValue, $TSconfig, $field) {
5239  // Values from foreign tables:
5240  if ($fieldValue['config']['foreign_table']) {
5241  $items = $this->foreignTable($items, $fieldValue, $TSconfig, $field);
5242  if ($fieldValue['config']['neg_foreign_table']) {
5243  $items = $this->foreignTable($items, $fieldValue, $TSconfig, $field, 1);
5244  }
5245  }
5246  // Values from a file folder:
5247  if ($fieldValue['config']['fileFolder']) {
5248  $fileFolder = GeneralUtility::getFileAbsFileName($fieldValue['config']['fileFolder']);
5249  if (@is_dir($fileFolder)) {
5250  // Configurations:
5251  $extList = $fieldValue['config']['fileFolder_extList'];
5252  $recursivityLevels = isset($fieldValue['config']['fileFolder_recursions'])
5253  ? MathUtility::forceIntegerInRange($fieldValue['config']['fileFolder_recursions'], 0, 99)
5254  : 99;
5255  // Get files:
5256  $fileFolder = rtrim($fileFolder, '/') . '/';
5257  $fileArr = GeneralUtility::getAllFilesAndFoldersInPath(array(), $fileFolder, $extList, 0, $recursivityLevels);
5258  $fileArr = GeneralUtility::removePrefixPathFromList($fileArr, $fileFolder);
5259  foreach ($fileArr as $fileRef) {
5260  $fI = pathinfo($fileRef);
5261  $icon = GeneralUtility::inList('gif,png,jpeg,jpg', strtolower($fI['extension']))
5262  ? '../' . PathUtility::stripPathSitePrefix($fileFolder) . $fileRef
5263  : '';
5264  $items[] = array(
5265  $fileRef,
5266  $fileRef,
5267  $icon
5268  );
5269  }
5270  }
5271  }
5272  // If 'special' is configured:
5273  if ($fieldValue['config']['special']) {
5274  $lang = $this->getLanguageService();
5275  switch ($fieldValue['config']['special']) {
5276  case 'tables':
5277  foreach ($GLOBALS['TCA'] as $theTableNames => $_) {
5278  if (!$GLOBALS['TCA'][$theTableNames]['ctrl']['adminOnly']) {
5279  // Icon:
5280  $icon = IconUtility::mapRecordTypeToSpriteIconName($theTableNames, array());
5281  // Add help text
5282  $helpText = array();
5283  $lang->loadSingleTableDescription($theTableNames);
5284  $helpTextArray = $GLOBALS['TCA_DESCR'][$theTableNames]['columns'][''];
5285  if (!empty($helpTextArray['description'])) {
5286  $helpText['description'] = $helpTextArray['description'];
5287  }
5288  // Item configuration:
5289  $items[] = array(
5290  $this->sL($GLOBALS['TCA'][$theTableNames]['ctrl']['title']),
5291  $theTableNames,
5292  $icon,
5293  $helpText
5294  );
5295  }
5296  }
5297  break;
5298  case 'pagetypes':
5299  $theTypes = $GLOBALS['TCA']['pages']['columns']['doktype']['config']['items'];
5300  foreach ($theTypes as $theTypeArrays) {
5301  // Icon:
5302  $icon = 'empty-emtpy';
5303  if ($theTypeArrays[1] != '--div--') {
5304  $icon = IconUtility::mapRecordTypeToSpriteIconName('pages', array('doktype' => $theTypeArrays[1]));
5305  }
5306  // Item configuration:
5307  $items[] = array(
5308  $this->sL($theTypeArrays[0]),
5309  $theTypeArrays[1],
5310  $icon
5311  );
5312  }
5313  break;
5314  case 'exclude':
5315  $theTypes = BackendUtility::getExcludeFields();
5316  foreach ($theTypes as $theTypeArrays) {
5317  list($theTable, $theFullField) = explode(':', $theTypeArrays[1]);
5318  // If the field comes from a FlexForm, the syntax is more complex
5319  $theFieldParts = explode(';', $theFullField);
5320  $theField = array_pop($theFieldParts);
5321  // Add header if not yet set for table:
5322  if (!array_key_exists($theTable, $items)) {
5323  $icon = IconUtility::mapRecordTypeToSpriteIconName($theTable, array());
5324  $items[$theTable] = array(
5325  $this->sL($GLOBALS['TCA'][$theTable]['ctrl']['title']),
5326  '--div--',
5327  $icon
5328  );
5329  }
5330  // Add help text
5331  $helpText = array();
5332  $lang->loadSingleTableDescription($theTable);
5333  $helpTextArray = $GLOBALS['TCA_DESCR'][$theTable]['columns'][$theFullField];
5334  if (!empty($helpTextArray['description'])) {
5335  $helpText['description'] = $helpTextArray['description'];
5336  }
5337  // Item configuration:
5338  $items[] = array(
5339  rtrim($lang->sl($GLOBALS['TCA'][$theTable]['columns'][$theField]['label']), ':') . ' (' . $theField . ')',
5340  $theTypeArrays[1],
5341  'empty-empty',
5342  $helpText
5343  );
5344  }
5345  break;
5346  case 'explicitValues':
5347  $theTypes = BackendUtility::getExplicitAuthFieldValues();
5348  // Icons:
5349  $icons = array(
5350  'ALLOW' => 'status-status-permission-granted',
5351  'DENY' => 'status-status-permission-denied'
5352  );
5353  // Traverse types:
5354  foreach ($theTypes as $tableFieldKey => $theTypeArrays) {
5355  if (is_array($theTypeArrays['items'])) {
5356  // Add header:
5357  $items[] = array(
5358  $theTypeArrays['tableFieldLabel'],
5359  '--div--'
5360  );
5361  // Traverse options for this field:
5362  foreach ($theTypeArrays['items'] as $itemValue => $itemContent) {
5363  // Add item to be selected:
5364  $items[] = array(
5365  '[' . $itemContent[2] . '] ' . $itemContent[1],
5366  $tableFieldKey . ':' . preg_replace('/[:|,]/', '', $itemValue) . ':' . $itemContent[0],
5367  $icons[$itemContent[0]]
5368  );
5369  }
5370  }
5371  }
5372  break;
5373  case 'languages':
5374  $items = array_merge($items, BackendUtility::getSystemLanguages());
5375  break;
5376  case 'custom':
5377  // Initialize:
5378  $customOptions = $GLOBALS['TYPO3_CONF_VARS']['BE']['customPermOptions'];
5379  if (is_array($customOptions)) {
5380  foreach ($customOptions as $coKey => $coValue) {
5381  if (is_array($coValue['items'])) {
5382  // Add header:
5383  $items[] = array(
5384  $lang->sl($coValue['header']),
5385  '--div--'
5386  );
5387  // Traverse items:
5388  foreach ($coValue['items'] as $itemKey => $itemCfg) {
5389  // Icon:
5390  if ($itemCfg[1]) {
5391  list($icon) = $this->getIcon($itemCfg[1]);
5392  } else {
5393  $icon = 'empty-empty';
5394  }
5395  // Add help text
5396  $helpText = array();
5397  if (!empty($itemCfg[2])) {
5398  $helpText['description'] = $lang->sl($itemCfg[2]);
5399  }
5400  // Add item to be selected:
5401  $items[] = array(
5402  $lang->sl($itemCfg[0]),
5403  $coKey . ':' . preg_replace('/[:|,]/', '', $itemKey),
5404  $icon,
5405  $helpText
5406  );
5407  }
5408  }
5409  }
5410  }
5411  break;
5412  case 'modListGroup':
5413 
5414  case 'modListUser':
5415  $loadModules = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Module\\ModuleLoader');
5416  $loadModules->load($GLOBALS['TBE_MODULES']);
5417  $modList = $fieldValue['config']['special'] == 'modListUser' ? $loadModules->modListUser : $loadModules->modListGroup;
5418  if (is_array($modList)) {
5419  foreach ($modList as $theMod) {
5420  // Icon:
5421  $icon = $lang->moduleLabels['tabs_images'][$theMod . '_tab'];
5422  if ($icon) {
5423  $icon = '../' . PathUtility::stripPathSitePrefix($icon);
5424  }
5425  // Add help text
5426  $helpText = array(
5427  'title' => $lang->moduleLabels['labels'][$theMod . '_tablabel'],
5428  'description' => $lang->moduleLabels['labels'][$theMod . '_tabdescr']
5429  );
5430  // Item configuration:
5431  $items[] = array(
5432  $this->addSelectOptionsToItemArray_makeModuleData($theMod),
5433  $theMod,
5434  $icon,
5435  $helpText
5436  );
5437  }
5438  }
5439  break;
5440  }
5441  }
5442  // Return the items:
5443  return $items;
5444  }
5445 
5455  public function addSelectOptionsToItemArray_makeModuleData($value) {
5456  $label = '';
5457  // Add label for main module:
5458  $pp = explode('_', $value);
5459  if (count($pp) > 1) {
5460  $label .= $this->getLanguageService()->moduleLabels['tabs'][($pp[0] . '_tab')] . '>';
5461  }
5462  // Add modules own label now:
5463  $label .= $this->getLanguageService()->moduleLabels['tabs'][$value . '_tab'];
5464  return $label;
5465  }
5466 
5479  public function foreignTable($items, $fieldValue, $TSconfig, $field, $pFFlag = FALSE) {
5480  // Init:
5481  $pF = $pFFlag ? 'neg_' : '';
5482  $f_table = $fieldValue['config'][$pF . 'foreign_table'];
5483  $uidPre = $pFFlag ? '-' : '';
5484  // Exec query:
5485  $res = BackendUtility::exec_foreign_table_where_query($fieldValue, $field, $TSconfig, $pF);
5486  // Perform error test
5487  $db = $this->getDatabaseConnection();
5488  if ($db->sql_error()) {
5489  $msg = htmlspecialchars($db->sql_error());
5490  $msg .= '<br />' . LF;
5491  $msg .= $this->sL('LLL:EXT:lang/locallang_core.xlf:error.database_schema_mismatch');
5492  $msgTitle = $this->sL('LLL:EXT:lang/locallang_core.xlf:error.database_schema_mismatch_title');
5494  $flashMessage = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessage', $msg, $msgTitle, FlashMessage::ERROR, TRUE);
5496  $flashMessageService = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessageService');
5498  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
5499  $defaultFlashMessageQueue->enqueue($flashMessage);
5500  return array();
5501  }
5502  // Get label prefix.
5503  $lPrefix = $this->sL($fieldValue['config'][$pF . 'foreign_table_prefix']);
5504  // Get icon field + path if any:
5505  $iField = $GLOBALS['TCA'][$f_table]['ctrl']['selicon_field'];
5506  $iPath = trim($GLOBALS['TCA'][$f_table]['ctrl']['selicon_field_path']);
5507  // Traverse the selected rows to add them:
5508  while ($row = $db->sql_fetch_assoc($res)) {
5509  BackendUtility::workspaceOL($f_table, $row);
5510  if (is_array($row)) {
5511  // Prepare the icon if available:
5512  if ($iField && $iPath && $row[$iField]) {
5513  $iParts = GeneralUtility::trimExplode(',', $row[$iField], TRUE);
5514  $icon = '../' . $iPath . '/' . trim($iParts[0]);
5515  } elseif (GeneralUtility::inList('singlebox,checkbox', $fieldValue['config']['renderMode'])) {
5516  $icon = IconUtility::mapRecordTypeToSpriteIconName($f_table, $row);
5517  } else {
5518  $icon = '';
5519  }
5520  // Add the item:
5521  $items[] = array(
5522  $lPrefix . htmlspecialchars(BackendUtility::getRecordTitle($f_table, $row)),
5523  $uidPre . $row['uid'],
5524  $icon
5525  );
5526  }
5527  }
5528  $db->sql_free_result($res);
5529  return $items;
5530  }
5531 
5532  /********************************************
5533  *
5534  * Template functions
5535  *
5536  ********************************************/
5544  public function setNewBEDesign() {
5545  $template = GeneralUtility::getUrl(PATH_typo3 . $this->templateFile);
5546  // Wrapping all table rows for a particular record being edited:
5547  $this->totalWrap = HtmlParser::getSubpart($template, '###TOTALWRAP###');
5548  // Wrapping a single field:
5549  $this->fieldTemplate = HtmlParser::getSubpart($template, '###FIELDTEMPLATE###');
5550  $this->paletteFieldTemplate = HtmlParser::getSubpart($template, '###PALETTEFIELDTEMPLATE###');
5551  $this->palFieldTemplate = HtmlParser::getSubpart($template, '###PALETTE_FIELDTEMPLATE###');
5552  $this->palFieldTemplateHeader = HtmlParser::getSubpart($template, '###PALETTE_FIELDTEMPLATE_HEADER###');
5553  $this->sectionWrap = HtmlParser::getSubpart($template, '###SECTION_WRAP###');
5554  }
5555 
5564  public function intoTemplate($inArr, $altTemplate = '') {
5565  // Put into template_
5566  $fieldTemplateParts = explode('###FIELD_', $this->rplColorScheme($altTemplate ? $altTemplate : $this->fieldTemplate));
5567  $out = current($fieldTemplateParts);
5568  foreach ($fieldTemplateParts as $part) {
5569  list($key, $val) = explode('###', $part, 2);
5570  $out .= $inArr[$key];
5571  $out .= $val;
5572  }
5573  return $out;
5574  }
5575 
5588  public function addUserTemplateMarkers($marker, $table, $field, $row, &$PA) {
5589  return $marker;
5590  }
5591 
5600  public function wrapLabels($str) {
5601  return $str;
5602  }
5603 
5614  public function wrapTotal($c, $rec, $table) {
5615  $parts = $this->replaceTableWrap(explode('|', $this->totalWrap, 2), $rec, $table);
5616  return $parts[0] . $c . $parts[1] . implode('', $this->hiddenFieldAccum);
5617  }
5618 
5626  static public function getHiddenTokenField($formName = 'securityToken', $tokenName = 'formToken') {
5627  $formprotection = \TYPO3\CMS\Core\FormProtection\FormProtectionFactory::get();
5628  return '<input type="hidden" name="' . $tokenName . '" value="' . $formprotection->generateToken($formName) . '" />';
5629  }
5630 
5640  public function replaceTableWrap($arr, $rec, $table) {
5641  // Make "new"-label
5642  $lang = $this->getLanguageService();
5643  if (strstr($rec['uid'], 'NEW')) {
5644  $newLabel = ' <span class="typo3-TCEforms-newToken">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.new', TRUE) . '</span>';
5645  // BackendUtility::fixVersioningPid Should not be used here because NEW records are not offline workspace versions...
5646  $truePid = BackendUtility::getTSconfig_pidValue($table, $rec['uid'], $rec['pid']);
5647  $prec = BackendUtility::getRecordWSOL('pages', $truePid, 'title');
5648  $pageTitle = BackendUtility::getRecordTitle('pages', $prec, TRUE, FALSE);
5649  $rLabel = '<em>[PID: ' . $truePid . '] ' . $pageTitle . '</em>';
5650  // Fetch translated title of the table
5651  $tableTitle = $lang->sL($GLOBALS['TCA'][$table]['ctrl']['title']);
5652  if ($table === 'pages') {
5653  $label = $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.createNewPage', TRUE);
5654  $pageTitle = sprintf($label, $tableTitle);
5655  } else {
5656  $label = $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.createNewRecord', TRUE);
5657  if ($rec['pid'] == 0) {
5658  $label = $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.createNewRecordRootLevel', TRUE);
5659  }
5660  $pageTitle = sprintf($label, $tableTitle, $pageTitle);
5661  }
5662  } else {
5663  $newLabel = ' <span class="typo3-TCEforms-recUid">[' . $rec['uid'] . ']</span>';
5664  $rLabel = BackendUtility::getRecordTitle($table, $rec, TRUE, FALSE);
5665  $prec = BackendUtility::getRecordWSOL('pages', $rec['pid'], 'uid,title');
5666  // Fetch translated title of the table
5667  $tableTitle = $lang->sL($GLOBALS['TCA'][$table]['ctrl']['title']);
5668  if ($table === 'pages') {
5669  $label = $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.editPage', TRUE);
5670  // Just take the record title and prepend an edit label.
5671  $pageTitle = sprintf($label, $tableTitle, $rLabel);
5672  } else {
5673  $label = $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.editRecord', TRUE);
5674  $pageTitle = BackendUtility::getRecordTitle('pages', $prec, TRUE, FALSE);
5675  if ($rLabel === BackendUtility::getNoRecordTitle(TRUE)) {
5676  $label = $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.editRecordNoTitle', TRUE);
5677  }
5678  if ($rec['pid'] == 0) {
5679  $label = $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.editRecordRootLevel', TRUE);
5680  }
5681  if ($rLabel !== BackendUtility::getNoRecordTitle(TRUE)) {
5682  // Just take the record title and prepend an edit label.
5683  $pageTitle = sprintf($label, $tableTitle, $rLabel, $pageTitle);
5684  } else {
5685  // Leave out the record title since it is not set.
5686  $pageTitle = sprintf($label, $tableTitle, $pageTitle);
5687  }
5688  }
5689  }
5690  foreach ($arr as $k => $v) {
5691  // Make substitutions:
5692  $arr[$k] = str_replace(
5693  array(
5694  '###PAGE_TITLE###',
5695  '###ID_NEW_INDICATOR###',
5696  '###RECORD_LABEL###',
5697  '###TABLE_TITLE###',
5698  '###RECORD_ICON###'
5699  ),
5700  array(
5701  $pageTitle,
5702  $newLabel,
5703  $rLabel,
5704  htmlspecialchars($this->sL($GLOBALS['TCA'][$table]['ctrl']['title'])),
5705  IconUtility::getSpriteIconForRecord($table, $rec, array('title' => $this->getRecordPath($table, $rec)))
5706  ),
5707  $arr[$k]
5708  );
5709  }
5710  return $arr;
5711  }
5712 
5721  public function wrapBorder(&$out_array, &$out_pointer) {
5722  if ($this->sectionWrap && $out_array[$out_pointer]) {
5723  $tableAttribs = '';
5724  $tableAttribs .= $this->borderStyle[0] ? ' style="' . htmlspecialchars($this->borderStyle[0]) . '"' : '';
5725  $tableAttribs .= $this->borderStyle[2] ? ' background="' . htmlspecialchars(($this->backPath . $this->borderStyle[2])) . '"' : '';
5726  $tableAttribs .= $this->borderStyle[3] ? ' class="' . htmlspecialchars($this->borderStyle[3]) . '"' : '';
5727  if ($tableAttribs) {
5728  $tableAttribs = 'border="0" cellspacing="0" cellpadding="0" width="100%"' . $tableAttribs;
5729  $out_array[$out_pointer] = str_replace('###CONTENT###', $out_array[$out_pointer], str_replace('###TABLE_ATTRIBS###', $tableAttribs, $this->sectionWrap));
5730  }
5731  $out_pointer++;
5732  }
5733  }
5734 
5742  public function rplColorScheme($inTemplate) {
5743  return str_replace(
5744  array(
5745  // Colors:
5746  '###BGCOLOR###',
5747  '###BGCOLOR_HEAD###',
5748  '###FONTCOLOR_HEAD###',
5749  // Classes:
5750  '###CLASSATTR_1###',
5751  '###CLASSATTR_2###',
5752  '###CLASSATTR_4###'
5753  ),
5754  array(
5755  // Colors:
5756  $this->colorScheme[0] ? ' bgcolor="' . $this->colorScheme[0] . '"' : '',
5757  $this->colorScheme[1] ? ' bgcolor="' . $this->colorScheme[1] . '"' : '',
5758  $this->colorScheme[3],
5759  // Classes:
5760  $this->classScheme[0] ? ' class="' . $this->classScheme[0] . '"' : '',
5761  $this->classScheme[1] ? ' class="' . $this->classScheme[1] . '"' : '',
5762  $this->classScheme[3] ? ' class="' . $this->classScheme[3] . '"' : ''
5763  ),
5764  $inTemplate
5765  );
5766  }
5767 
5775  public function getDivider() {
5776  return '';
5777  }
5778 
5786  public function printPalette($palArr) {
5787  $fieldAttributes = ($labelAttributes = '');
5788  // Init color/class attributes:
5789  if ($this->colorScheme[2]) {
5790  $labelAttributes .= ' bgcolor="' . $this->colorScheme[2] . '"';
5791  }
5792  if ($this->classScheme[2]) {
5793  $labelAttributes .= ' class="t3-form-palette-field-label ' . $this->classScheme[2] . '"';
5794  } else {
5795  $labelAttributes .= ' class="t3-form-palette-field-label"';
5796  }
5797  if ($this->colorScheme[4]) {
5798  $fieldAttributes .= ' style="color: ' . $this->colorScheme[4] . '"';
5799  }
5800  if ($this->classScheme[4]) {
5801  $fieldAttributes .= ' class="t3-form-palette-field ' . $this->classScheme[4] . '"';
5802  }
5803  $row = 0;
5804  $iRow = array();
5805  $lastLineWasLinebreak = FALSE;
5806  // Traverse palette fields and render them into containers:
5807  foreach ($palArr as $content) {
5808  if ($content['NAME'] === '--linebreak--') {
5809  if (!$lastLineWasLinebreak) {
5810  $row++;
5811  $lastLineWasLinebreak = TRUE;
5812  }
5813  } else {
5814  $lastLineWasLinebreak = FALSE;
5815 
5816  $paletteMarkers = array(
5817  '###CONTENT_TABLE###' => $content['TABLE'],
5818  '###CONTENT_ID###' => $content['ID'],
5819  '###CONTENT_FIELD###' => $content['FIELD'],
5820  '###CONTENT_NAME###' => $content['NAME'],
5821  '###CONTENT_ITEM###' => $content['ITEM'],
5822  '###CONTENT_ITEM_NULLVALUE###' => $content['ITEM_NULLVALUE'],
5823  '###CONTENT_ITEM_DISABLED###' => $content['ITEM_DISABLED'],
5824  '###ATTRIBUTES_LABEL###' => $labelAttributes,
5825  '###ATTRIBUTES_FIELD###' => $fieldAttributes,
5826  );
5827  $iRow[$row][] = HtmlParser::substituteMarkerArray(
5828  $this->paletteFieldTemplate,
5829  $paletteMarkers,
5830  FALSE,
5831  TRUE
5832  );
5833  }
5834  }
5835  // Final wrapping into the fieldset:
5836  $out = '<fieldset class="t3-form-palette-fieldset">';
5837  for ($i = 0; $i <= $row; $i++) {
5838  if (isset($iRow[$i])) {
5839  $out .= implode('', $iRow[$i]);
5840  $out .= $i < $row ? '<br />' : '';
5841  }
5842  }
5843  $out .= '</fieldset>';
5844  return $out;
5845  }
5846 
5854  public function setColorScheme($scheme) {
5855  $this->colorScheme = $this->defColorScheme;
5856  $this->classScheme = $this->defClassScheme;
5857  $parts = GeneralUtility::trimExplode(',', $scheme);
5858  foreach ($parts as $key => $col) {
5859  // Split for color|class:
5860  list($color, $class) = GeneralUtility::trimExplode('|', $col);
5861  // Handle color values:
5862  if ($color) {
5863  $this->colorScheme[$key] = $color;
5864  }
5865  if ($color == '-') {
5866  $this->colorScheme[$key] = '';
5867  }
5868  // Handle class values:
5869  if ($class) {
5870  $this->classScheme[$key] = $class;
5871  }
5872  if ($class == '-') {
5873  $this->classScheme[$key] = '';
5874  }
5875  }
5876  }
5877 
5884  public function resetSchemes() {
5885  $this->setColorScheme($GLOBALS['TBE_STYLES']['colorschemes'][0]);
5886  $this->fieldStyle = $GLOBALS['TBE_STYLES']['styleschemes'][0];
5887  $this->borderStyle = $GLOBALS['TBE_STYLES']['borderschemes'][0];
5888  }
5889 
5896  public function storeSchemes() {
5897  $this->savedSchemes['classScheme'] = $this->classScheme;
5898  $this->savedSchemes['colorScheme'] = $this->colorScheme;
5899  $this->savedSchemes['fieldStyle'] = $this->fieldStyle;
5900  $this->savedSchemes['borderStyle'] = $this->borderStyle;
5901  }
5902 
5909  public function restoreSchemes() {
5910  $this->classScheme = $this->savedSchemes['classScheme'];
5911  $this->colorScheme = $this->savedSchemes['colorScheme'];
5912  $this->fieldStyle = $this->savedSchemes['fieldStyle'];
5913  $this->borderStyle = $this->savedSchemes['borderStyle'];
5914  }
5915 
5916  /********************************************
5917  *
5918  * JavaScript related functions
5919  *
5920  ********************************************/
5927  public function JStop() {
5928  $out = '';
5929  // Additional top HTML:
5930  if (count($this->additionalCode_pre)) {
5931  $out .= implode('
5932 
5933  <!-- NEXT: -->
5934  ', $this->additionalCode_pre);
5935  }
5936  // Additional top JavaScript
5937  if (count($this->additionalJS_pre)) {
5938  $out .= '
5939 
5940 
5941  <!--
5942  JavaScript in top of page (before form):
5943  -->
5944 
5945  <script type="text/javascript">
5946  /*<![CDATA[*/
5947 
5948  ' . implode('
5949 
5950  // NEXT:
5951  ', $this->additionalJS_pre) . '
5952 
5953  /*]]>*/
5954  </script>
5955  ';
5956  }
5957  // Return result:
5958  return $out;
5959  }
5960 
5979  public function JSbottom($formname = 'forms[0]', $update = FALSE) {
5980  $jsFile = array();
5981  $elements = array();
5982  $out = '';
5983  // Required:
5984  foreach ($this->requiredFields as $itemImgName => $itemName) {
5985  $match = array();
5986  if (preg_match('/^(.+)\\[((\\w|\\d|_)+)\\]$/', $itemName, $match)) {
5987  $record = $match[1];
5988  $field = $match[2];
5989  $elements[$record][$field]['required'] = 1;
5990  $elements[$record][$field]['requiredImg'] = $itemImgName;
5991  if (isset($this->requiredAdditional[$itemName]) && is_array($this->requiredAdditional[$itemName])) {
5992  $elements[$record][$field]['additional'] = $this->requiredAdditional[$itemName];
5993  }
5994  }
5995  }
5996  // Range:
5997  foreach ($this->requiredElements as $itemName => $range) {
5998  if (preg_match('/^(.+)\\[((\\w|\\d|_)+)\\]$/', $itemName, $match)) {
5999  $record = $match[1];
6000  $field = $match[2];
6001  $elements[$record][$field]['range'] = array($range[0], $range[1]);
6002  $elements[$record][$field]['rangeImg'] = $range['imgName'];
6003  }
6004  }
6005  $this->TBE_EDITOR_fieldChanged_func = 'TBE_EDITOR.fieldChanged_fName(fName,formObj[fName+"_list"]);';
6006  if (!$update) {
6007  if ($this->loadMD5_JS) {
6008  $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/md5.js');
6009  }
6010  $pageRenderer = $this->getPageRenderer();
6011  // load the main module for FormEngine with all important JS functions
6012  $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/FormEngine');
6013  $pageRenderer->loadPrototype();
6014  $pageRenderer->loadJquery();
6015  $pageRenderer->loadExtJS();
6016  // Make textareas resizable and flexible
6017  $beUserAuth = $this->getBackendUserAuthentication();
6018  if (!($beUserAuth->uc['resizeTextareas'] == '0' && $beUserAuth->uc['resizeTextareas_Flexible'] == '0')) {
6019  $pageRenderer->addCssFile($this->backPath . 'js/extjs/ux/resize.css');
6020  $this->loadJavascriptLib('js/extjs/ux/ext.resizable.js');
6021  }
6022  $resizableSettings = array(
6023  'textareaMaxHeight' => $beUserAuth->uc['resizeTextareas_MaxHeight'] > 0 ? $beUserAuth->uc['resizeTextareas_MaxHeight'] : '600',
6024  'textareaFlexible' => !$beUserAuth->uc['resizeTextareas_Flexible'] == '0',
6025  'textareaResize' => !$beUserAuth->uc['resizeTextareas'] == '0'
6026  );
6027  $pageRenderer->addInlineSettingArray('', $resizableSettings);
6028  $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.evalfield.js');
6029  $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.tbe_editor.js');
6030  $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.placeholder.js');
6031  // Needed for tceform manipulation (date picker)
6032  $typo3Settings = array(
6033  'datePickerUSmode' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? 1 : 0,
6034  'dateFormat' => array('j-n-Y', 'G:i j-n-Y'),
6035  'dateFormatUS' => array('n-j-Y', 'G:i n-j-Y')
6036  );
6037  $pageRenderer->addInlineSettingArray('', $typo3Settings);
6038  $this->loadJavascriptLib('js/extjs/ux/Ext.ux.DateTimePicker.js');
6039  $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/tceforms.js');
6040  // If IRRE fields were processed, add the JavaScript functions:
6041  if ($this->inline->inlineCount) {
6042  $pageRenderer->loadScriptaculous();
6043  // We want to load jQuery-ui inside our js. Enable this using requirejs.
6044  $pageRenderer->loadRequireJs();
6045  $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.inline.js');
6046  $out .= '
6047  inline.setPrependFormFieldNames("' . $this->inline->prependNaming . '");
6048  inline.setNoTitleString("' . addslashes(BackendUtility::getNoRecordTitle(TRUE)) . '");
6049  ';
6050  // Always include JS functions for Suggest fields as we don't know what will come
6051  $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.tceforms_suggest.js');
6052  $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.tceforms_selectboxfilter.js');
6053  } else {
6054  // If Suggest fields were processed, add the JS functions
6055  if ($this->suggest->suggestCount > 0) {
6056  $pageRenderer->loadScriptaculous();
6057  $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.tceforms_suggest.js');
6058  }
6059  if ($this->multiSelectFilterCount > 0) {
6060  $pageRenderer->loadScriptaculous();
6061  $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.tceforms_selectboxfilter.js');
6062  }
6063  }
6064  // Toggle icons:
6065  $toggleIcon_open = IconUtility::getSpriteIcon('actions-move-down', array('title' => 'Open'));
6066  $toggleIcon_close = IconUtility::getSpriteIcon('actions-move-right', array('title' => 'Close'));
6067  $out .= '
6068  function getOuterHTML(idTagPrefix) { // Function getting the outerHTML of an element with id
6069  var str=($(idTagPrefix).inspect()+$(idTagPrefix).innerHTML+"</"+$(idTagPrefix).tagName.toLowerCase()+">");
6070  return str;
6071  }
6072  function flexFormToggle(id) { // Toggling flexform elements on/off:
6073  Element.toggle(""+id+"-content");
6074 
6075  if (Element.visible(id+"-content")) {
6076  $(id+"-toggle").update(\'' . $toggleIcon_open . '\');
6077  $(id+"-toggleClosed").value = 0;
6078  } else {
6079  $(id+"-toggle").update(\'' . $toggleIcon_close . '\');
6080  $(id+"-toggleClosed").value = 1;
6081  }
6082 
6083  var previewContent = "";
6084  var children = $(id+"-content").getElementsByTagName("input");
6085  for (var i = 0, length = children.length; i < length; i++) {
6086  if (children[i].type=="text" && children[i].value) previewContent+= (previewContent?" / ":"")+children[i].value;
6087  }
6088  if (previewContent.length>80) {
6089  previewContent = previewContent.substring(0,67)+"...";
6090  }
6091  $(id+"-preview").update(previewContent);
6092  }
6093  function flexFormToggleSubs(id) { // Toggling sub flexform elements on/off:
6094  var descendants = $(id).immediateDescendants();
6095  var isOpen=0;
6096  var isClosed=0;
6097  // Traverse and find how many are open or closed:
6098  for (var i = 0, length = descendants.length; i < length; i++) {
6099  if (descendants[i].id) {
6100  if (Element.visible(descendants[i].id+"-content")) {isOpen++;} else {isClosed++;}
6101  }
6102  }
6103 
6104  // Traverse and toggle
6105  for (var i = 0, length = descendants.length; i < length; i++) {
6106  if (descendants[i].id) {
6107  if (isOpen!=0 && isClosed!=0) {
6108  if (Element.visible(descendants[i].id+"-content")) {flexFormToggle(descendants[i].id);}
6109  } else {
6110  flexFormToggle(descendants[i].id);
6111  }
6112  }
6113  }
6114  }
6115  function flexFormSortable(id) { // Create sortables for flexform sections
6116  Position.includeScrollOffsets = true;
6117  Sortable.create(id, {tag:\'div\',constraint: false, onChange:function(){
6118  setActionStatus(id);
6119  } });
6120  }
6121  function setActionStatus(id) { // Updates the "action"-status for a section. This is used to move and delete elements.
6122  var descendants = $(id).immediateDescendants();
6123 
6124  // Traverse and find how many are open or closed:
6125  for (var i = 0, length = descendants.length; i < length; i++) {
6126  if (descendants[i].id) {
6127  $(descendants[i].id+"-action").value = descendants[i].visible() ? i : "DELETE";
6128  }
6129  }
6130  }
6131 
6132  TBE_EDITOR.images.req.src = "' . IconUtility::skinImg($this->backPath, 'gfx/required_h.gif', '', 1) . '";
6133  TBE_EDITOR.images.cm.src = "' . IconUtility::skinImg($this->backPath, 'gfx/content_client.gif', '', 1) . '";
6134  TBE_EDITOR.images.sel.src = "' . IconUtility::skinImg($this->backPath, 'gfx/content_selected.gif', '', 1) . '";
6135  TBE_EDITOR.images.clear.src = "' . $this->backPath . 'clear.gif";
6136 
6137  TBE_EDITOR.auth_timeout_field = ' . (int)$beUserAuth->auth_timeout_field . ';
6138  TBE_EDITOR.formname = "' . $formname . '";
6139  TBE_EDITOR.formnameUENC = "' . rawurlencode($formname) . '";
6140  TBE_EDITOR.backPath = "' . addslashes($this->backPath) . '";
6141  TBE_EDITOR.prependFormFieldNames = "' . $this->prependFormFieldNames . '";
6142  TBE_EDITOR.prependFormFieldNamesUENC = "' . rawurlencode($this->prependFormFieldNames) . '";
6143  TBE_EDITOR.prependFormFieldNamesCnt = ' . substr_count($this->prependFormFieldNames, '[') . ';
6144  TBE_EDITOR.isPalettedoc = ' . ($this->isPalettedoc ? addslashes($this->isPalettedoc) : 'null') . ';
6145  TBE_EDITOR.doSaveFieldName = "' . ($this->doSaveFieldName ? addslashes($this->doSaveFieldName) : '') . '";
6146  TBE_EDITOR.labels.fieldsChanged = ' . GeneralUtility::quoteJSvalue($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.fieldsChanged')) . ';
6147  TBE_EDITOR.labels.fieldsMissing = ' . GeneralUtility::quoteJSvalue($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.fieldsMissing')) . ';
6148  TBE_EDITOR.labels.refresh_login = ' . GeneralUtility::quoteJSvalue($this->getLL('m_refresh_login')) . ';
6149  TBE_EDITOR.labels.onChangeAlert = ' . GeneralUtility::quoteJSvalue($this->getLL('m_onChangeAlert')) . ';
6150  evalFunc.USmode = ' . ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? '1' : '0') . ';
6151  TBE_EDITOR.backend_interface = "' . $beUserAuth->uc['interfaceSetup'] . '";
6152 
6153  TBE_EDITOR.customEvalFunctions = {};
6154 
6155  ';
6156  }
6157  // Add JS required for inline fields
6158  if (count($this->inline->inlineData)) {
6159  $out .= '
6160  inline.addToDataArray(' . json_encode($this->inline->inlineData) . ');
6161  ';
6162  }
6163  // Registered nested elements for tabs or inline levels:
6164  if (count($this->requiredNested)) {
6165  $out .= '
6166  TBE_EDITOR.addNested(' . json_encode($this->requiredNested) . ');
6167  ';
6168  }
6169  // Elements which are required or have a range definition:
6170  if (count($elements)) {
6171  $out .= '
6172  TBE_EDITOR.addElements(' . json_encode($elements) . ');
6173  TBE_EDITOR.initRequired();
6174  ';
6175  }
6176  // $this->additionalJS_submit:
6177  if ($this->additionalJS_submit) {
6178  $additionalJS_submit = implode('', $this->additionalJS_submit);
6179  $additionalJS_submit = str_replace(array(CR, LF), '', $additionalJS_submit);
6180  $out .= '
6181  TBE_EDITOR.addActionChecks("submit", "' . addslashes($additionalJS_submit) . '");
6182  ';
6183  }
6184  $out .= LF . implode(LF, $this->additionalJS_post) . LF . $this->extJSCODE;
6185  $out .= '
6186  TBE_EDITOR.loginRefreshed();
6187  ';
6188  // Regular direct output:
6189  if (!$update) {
6190  $spacer = LF . TAB;
6191  $out = $spacer . implode($spacer, $jsFile) . GeneralUtility::wrapJS($out);
6192  }
6193  return $out;
6194  }
6195 
6203  public function dbFileCon($formObj = 'document.forms[0]') {
6205  }
6206 
6215  public function printNeededJSFunctions() {
6217  $pageRenderer = $this->getControllerDocumentTemplate()->getPageRenderer();
6218 
6219  // set variables to be accessible for JS
6220  $pageRenderer->addInlineSetting('FormEngine', 'formName', $this->formName);
6221  $pageRenderer->addInlineSetting('FormEngine', 'backPath', $this->backPath);
6222 
6223  // Integrate JS functions for the element browser if such fields or IRRE fields were processed
6224  if ($this->printNeededJS['dbFileIcons'] || $this->inline->inlineCount > 0 || $this->suggest->suggestCount > 0) {
6225  $pageRenderer->addInlineSetting('FormEngine', 'legacyFieldChangedCb', 'function() { ' . $this->TBE_EDITOR_fieldChanged_func . ' };');
6226  }
6227 
6228  return $this->JSbottom($this->formName);
6229  }
6230 
6237  public function printNeededJSFunctions_top() {
6238  return $this->JStop($this->formName);
6239  }
6240 
6249  public function loadJavascriptLib($lib) {
6250  $this->getControllerDocumentTemplate()->loadJavascriptLib($lib);
6251  }
6252 
6258  protected function getPageRenderer() {
6259  return $this->getControllerDocumentTemplate()->getPageRenderer();
6260  }
6261 
6262  /********************************************
6263  *
6264  * Various helper functions
6265  *
6266  ********************************************/
6275  public function getDefaultRecord($table, $pid = 0) {
6276  if ($GLOBALS['TCA'][$table]) {
6277  $row = array();
6278  if ($pid < 0 && $GLOBALS['TCA'][$table]['ctrl']['useColumnsForDefaultValues']) {
6279  // Fetches the previous record:
6280  $db = $this->getDatabaseConnection();
6281  $res = $db->exec_SELECTquery('*', $table, 'uid=' . abs($pid) . BackendUtility::deleteClause($table));
6282  if ($drow = $db->sql_fetch_assoc($res)) {
6283  // Gets the list of fields to copy from the previous record.
6284  $fArr = explode(',', $GLOBALS['TCA'][$table]['ctrl']['useColumnsForDefaultValues']);
6285  foreach ($fArr as $theF) {
6286  if ($GLOBALS['TCA'][$table]['columns'][$theF]) {
6287  $row[$theF] = $drow[$theF];
6288  }
6289  }
6290  }
6291  $db->sql_free_result($res);
6292  }
6293  foreach ($GLOBALS['TCA'][$table]['columns'] as $field => $info) {
6294  if (isset($info['config']['default'])) {
6295  $row[$field] = $info['config']['default'];
6296  }
6297  }
6298  return $row;
6299  }
6300  return NULL;
6301  }
6302 
6310  protected function isNewRecord($table, $row) {
6311  return !MathUtility::canBeInterpretedAsInteger($row['uid']) && GeneralUtility::isFirstPartOfStr($row['uid'], 'NEW');
6312  }
6313 
6323  public function getRecordPath($table, $rec) {
6324  BackendUtility::fixVersioningPid($table, $rec);
6325  list($tscPID, $thePidValue) = $this->getTSCpid($table, $rec['uid'], $rec['pid']);
6326  if ($thePidValue >= 0) {
6327  return BackendUtility::getRecordPath($tscPID, $this->readPerms(), 15);
6328  }
6329  return NULL;
6330  }
6331 
6339  public function readPerms() {
6340  if (!$this->perms_clause_set) {
6341  $this->perms_clause = $this->getBackendUserAuthentication()->getPagePermsClause(1);
6342  $this->perms_clause_set = TRUE;
6343  }
6344  return $this->perms_clause;
6345  }
6346 
6354  public function sL($str) {
6355  return $this->getLanguageService()->sL($str);
6356  }
6357 
6368  public function getLL($str) {
6369  $content = '';
6370  switch (substr($str, 0, 2)) {
6371  case 'l_':
6372  $content = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.' . substr($str, 2));
6373  break;
6374  case 'm_':
6375  $content = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:mess.' . substr($str, 2));
6376  break;
6377  }
6378  return $content;
6379  }
6380 
6389  public function isPalettesCollapsed($table, $palette) {
6390  if (is_array($GLOBALS['TCA'][$table]['palettes'][$palette]) && $GLOBALS['TCA'][$table]['palettes'][$palette]['isHiddenPalette']) {
6391  return TRUE;
6392  }
6393  if ($GLOBALS['TCA'][$table]['ctrl']['canNotCollapse']) {
6394  return FALSE;
6395  }
6396  if (is_array($GLOBALS['TCA'][$table]['palettes'][$palette]) && $GLOBALS['TCA'][$table]['palettes'][$palette]['canNotCollapse']) {
6397  return FALSE;
6398  }
6399  return $this->palettesCollapsed;
6400  }
6401 
6412  public function isDisplayCondition($displayCond, $row, $ffValueKey = '') {
6415  $elementConditionMatcher = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\ElementConditionMatcher');
6416  return $elementConditionMatcher->match($displayCond, $row, $ffValueKey);
6417  }
6418 
6430  public function getTSCpid($table, $uid, $pid) {
6431  $key = $table . ':' . $uid . ':' . $pid;
6432  if (!isset($this->cache_getTSCpid[$key])) {
6433  $this->cache_getTSCpid[$key] = BackendUtility::getTSCpid($table, $uid, $pid);
6434  }
6435  return $this->cache_getTSCpid[$key];
6436  }
6437 
6445  public function doLoadTableDescr($table) {
6446  return $GLOBALS['TCA'][$table]['interface']['always_description'];
6447  }
6448 
6457  public function getAvailableLanguages($onlyIsoCoded = TRUE, $setDefault = TRUE) {
6458  $isL = ExtensionManagementUtility::isLoaded('static_info_tables');
6459  // Find all language records in the system:
6460  $db = $this->getDatabaseConnection();
6461  $res = $db->exec_SELECTquery('static_lang_isocode,title,uid', 'sys_language', 'pid=0 AND hidden=0' . BackendUtility::deleteClause('sys_language'), '', 'title');
6462  // Traverse them:
6463  $output = array();
6464  if ($setDefault) {
6465  $output[0] = array(
6466  'uid' => 0,
6467  'title' => 'Default language',
6468  'ISOcode' => 'DEF'
6469  );
6470  }
6471  while ($row = $db->sql_fetch_assoc($res)) {
6472  $output[$row['uid']] = $row;
6473  if ($isL && $row['static_lang_isocode']) {
6474  $rr = BackendUtility::getRecord('static_languages', $row['static_lang_isocode'], 'lg_iso_2');
6475  if ($rr['lg_iso_2']) {
6476  $output[$row['uid']]['ISOcode'] = $rr['lg_iso_2'];
6477  }
6478  }
6479  if ($onlyIsoCoded && !$output[$row['uid']]['ISOcode']) {
6480  unset($output[$row['uid']]);
6481  }
6482  }
6483  $db->sql_free_result($res);
6484  return $output;
6485  }
6486 
6496  public function getLanguageIcon($table, $row, $sys_language_uid) {
6497  $mainKey = $table . ':' . $row['uid'];
6498  if (!isset($this->cachedLanguageFlag[$mainKey])) {
6499  BackendUtility::fixVersioningPid($table, $row);
6500  list($tscPID) = $this->getTSCpid($table, $row['uid'], $row['pid']);
6502  $t8Tools = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Configuration\\TranslationConfigurationProvider');
6503  $this->cachedLanguageFlag[$mainKey] = $t8Tools->getSystemLanguages($tscPID, $this->backPath);
6504  }
6505  // Convert sys_language_uid to sys_language_uid if input was in fact a string (ISO code expected then)
6506  if (!MathUtility::canBeInterpretedAsInteger($sys_language_uid)) {
6507  foreach ($this->cachedLanguageFlag[$mainKey] as $rUid => $cD) {
6508  if ('v' . $cD['ISOcode'] === $sys_language_uid) {
6509  $sys_language_uid = $rUid;
6510  }
6511  }
6512  }
6513  $out = '';
6514  if ($this->cachedLanguageFlag[$mainKey][$sys_language_uid]['flagIcon']) {
6515  $out .= IconUtility::getSpriteIcon($this->cachedLanguageFlag[$mainKey][$sys_language_uid]['flagIcon']);
6516  $out .= '&nbsp;';
6517  } elseif ($this->cachedLanguageFlag[$mainKey][$sys_language_uid]['title']) {
6518  $out .= '[' . $this->cachedLanguageFlag[$mainKey][$sys_language_uid]['title'] . ']';
6519  $out .= '&nbsp;';
6520  }
6521  return $out;
6522  }
6523 
6533  protected function getMergeBehaviourIcon($l10nMode) {
6534  $icon = '';
6535  if ($l10nMode === 'mergeIfNotBlank') {
6536  $icon = IconUtility::getSpriteIcon('actions-edit-merge-localization', array('title' => $this->sL('LLL:EXT:lang/locallang_misc.xlf:localizeMergeIfNotBlank')));
6537  }
6538  return $icon;
6539  }
6540 
6550  public function previewFieldValue($value, $config, $field = '') {
6551  if ($config['config']['type'] === 'group' && ($config['config']['internal_type'] === 'file' || $config['config']['internal_type'] === 'file_reference')) {
6552  // Ignore uploadfolder if internal_type is file_reference
6553  if ($config['config']['internal_type'] === 'file_reference') {
6554  $config['config']['uploadfolder'] = '';
6555  }
6556  $show_thumbs = TRUE;
6557  $table = 'tt_content';
6558  // Making the array of file items:
6559  $itemArray = GeneralUtility::trimExplode(',', $value, TRUE);
6560  // Showing thumbnails:
6561  $thumbsnail = '';
6562  if ($show_thumbs) {
6563  $imgs = array();
6564  foreach ($itemArray as $imgRead) {
6565  $imgP = explode('|', $imgRead);
6566  $imgPath = rawurldecode($imgP[0]);
6567  $rowCopy = array();
6568  $rowCopy[$field] = $imgPath;
6569  // Icon + clickmenu:
6570  $absFilePath = GeneralUtility::getFileAbsFileName($config['config']['uploadfolder'] ? $config['config']['uploadfolder'] . '/' . $imgPath : $imgPath);
6571  $fileInformation = pathinfo($imgPath);
6572  $fileIcon = IconUtility::getSpriteIconForFile($imgPath, array('title' => htmlspecialchars($fileInformation['basename'] . ($absFilePath && @is_file($absFilePath) ? ' (' . GeneralUtility::formatSize(filesize($absFilePath)) . 'bytes)' : ' - FILE NOT FOUND!'))));
6573  $imgs[] = '<span class="nobr">' . BackendUtility::thumbCode($rowCopy, $table, $field, $this->backPath, 'thumbs.php', $config['config']['uploadfolder'], 0, ' align="middle"') . ($absFilePath ? $this->getClickMenu($fileIcon, $absFilePath) : $fileIcon) . $imgPath . '</span>';
6574  }
6575  $thumbsnail = implode('<br />', $imgs);
6576  }
6577  return $thumbsnail;
6578  } else {
6579  return nl2br(htmlspecialchars($value));
6580  }
6581  }
6582 
6589  public function getAdditionalPreviewLanguages() {
6590  if (!isset($this->cachedAdditionalPreviewLanguages)) {
6591  $this->cachedAdditionalPreviewLanguages = array();
6592  if ($this->getBackendUserAuthentication()->getTSConfigVal('options.additionalPreviewLanguages')) {
6593  $uids = GeneralUtility::intExplode(',', $this->getBackendUserAuthentication()->getTSConfigVal('options.additionalPreviewLanguages'));
6594  foreach ($uids as $uid) {
6595  if ($sys_language_rec = BackendUtility::getRecord('sys_language', $uid)) {
6596  $this->cachedAdditionalPreviewLanguages[$uid] = array('uid' => $uid);
6597  if ($sys_language_rec['static_lang_isocode'] && ExtensionManagementUtility::isLoaded('static_info_tables')) {
6598  $staticLangRow = BackendUtility::getRecord('static_languages', $sys_language_rec['static_lang_isocode'], 'lg_iso_2');
6599  if ($staticLangRow['lg_iso_2']) {
6600  $this->cachedAdditionalPreviewLanguages[$uid]['uid'] = $uid;
6601  $this->cachedAdditionalPreviewLanguages[$uid]['ISOcode'] = $staticLangRow['lg_iso_2'];
6602  }
6603  }
6604  }
6605  }
6606  }
6607  }
6609  }
6610 
6620  public function pushToDynNestedStack($type, $ident) {
6621  $this->dynNestedStack[] = array($type, $ident);
6622  }
6623 
6634  public function popFromDynNestedStack($type = NULL, $ident = NULL) {
6635  if ($type != NULL && $ident != NULL) {
6636  $last = end($this->dynNestedStack);
6637  if ($type == $last[0] && $ident == $last[1]) {
6638  array_pop($this->dynNestedStack);
6639  }
6640  } else {
6641  array_pop($this->dynNestedStack);
6642  }
6643  }
6644 
6654  public function getDynNestedStack($json = FALSE, $skipFirst = FALSE) {
6656  if ($skipFirst) {
6657  array_shift($result);
6658  }
6659  return $json ? json_encode($result) : $result;
6660  }
6661 
6673  protected function registerRequiredProperty($type, $name, $value) {
6674  if ($type == 'field' && is_string($value)) {
6675  $this->requiredFields[$name] = $value;
6676  // requiredFields have name/value swapped! For backward compatibility we keep this:
6677  $itemName = $value;
6678  } elseif ($type == 'range' && is_array($value)) {
6679  $this->requiredElements[$name] = $value;
6680  $itemName = $name;
6681  } else {
6682  $itemName = '';
6683  }
6684  // Set the situation of nesting for the current field:
6685  $this->registerNestedElement($itemName);
6686  }
6687 
6695  protected function registerNestedElement($itemName, $setLevel = TRUE) {
6697  if (count($dynNestedStack) && preg_match('/^(.+\\])\\[(\\w+)\\]$/', $itemName, $match)) {
6698  array_shift($match);
6699  $this->requiredNested[$itemName] = array(
6700  'parts' => $match,
6701  'level' => $dynNestedStack
6702  );
6703  }
6704  }
6705 
6715  protected function getPlaceholderAttribute($table, $field, array $config, array $row) {
6716  $value = $this->getPlaceholderValue($table, $field, $config, $row);
6717 
6718  // Cleanup the string and support 'LLL:'
6719  $value = htmlspecialchars(trim($this->sL($value)));
6720  return empty($value) ? '' : ' placeholder="' . $value . '" ';
6721  }
6722 
6732  protected function getPlaceholderValue($table, $field, array $config, array $row) {
6733  $value = trim($config['placeholder']);
6734  if (!$value) {
6735  return '';
6736  }
6737  // Check if we have a reference to another field value from the current record
6738  if (substr($value, 0, 6) === '__row|') {
6740  $traverseFields = GeneralUtility::trimExplode('|', substr($value, 6));
6741  $traverser = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\FormDataTraverser', $this);
6742  $value = $traverser->getTraversedFieldValue($traverseFields, $table, $row);
6743  }
6744 
6745  return $value;
6746  }
6747 
6757  public function addStyleSheet($key, $href, $title = '', $relation = 'stylesheet') {
6758  $this->getControllerDocumentTemplate()->addStyleSheet($key, $href, $title, $relation);
6759  }
6760 
6764  protected function getBackendUserAuthentication() {
6765  return $GLOBALS['BE_USER'];
6766  }
6767 
6771  protected function getControllerDocumentTemplate() {
6772  // $GLOBALS['SOBE'] might be any kind of PHP class (controller most of the times)
6773  // These class do not inherit from any common class, but they all seem to have a "doc" member
6774  return $GLOBALS['SOBE']->doc;
6775  }
6776 
6780  protected function getDatabaseConnection() {
6781  return $GLOBALS['TYPO3_DB'];
6782  }
6783 
6787  protected function getLanguageService() {
6788  return $GLOBALS['LANG'];
6789  }
6790 
6794  protected function getDocumentTemplate() {
6795  return $GLOBALS['TBE_TEMPLATE'];
6796  }
6797 }
getExcludeElements($table, $row, $typeNum)
getSingleField_typeFlex_langMenu($languages, $elName, $selectedLanguage, $multi=TRUE)
getDynTabMenu($parts, $idString, $dividersToTabsBehaviour=1)
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=TRUE, $includeEmptyValues=TRUE, $enableUnsetFeature=TRUE)
registerRequiredProperty($type, $name, $value)
getSingleField_typeFlex_sheetMenu($sArr, $elName, $sheetKey)
static skinImg($backPath, $src, $wHattribs='', $outputMode=0)
isPalettesCollapsed($table, $palette)
getSoloField($table, $row, $theFieldToReturn)
Definition: FormEngine.php:816
static getRecordWSOL($table, $uid, $fields=' *', $where='', $useDeleteClause=TRUE, $unsetMovePointers=FALSE)
dbFileCon($formObj='document.forms[0]')
getListedFields($table, $row, $list)
renderVDEFDiff($vArray, $vDEFkey)
getLanguageOverlayRawValue($table, $row, $field, $fieldConf)
getSelectItems($table, $fieldName, array $row, array $PA)
$moduleName
Definition: mod.php:22
intoTemplate($inArr, $altTemplate='')
getDynNestedStack($json=FALSE, $skipFirst=FALSE)
wrapPaletteField($code, $table, $row, $palette, $collapsed)
getSingleField_typeSelect_checkbox($table, $field, $row, &$PA, $config, $selItems, $nMV_label)
getClickMenu($str, $table, $uid=0)
static isFirstPartOfStr($str, $partStr)
getSpecConfFromString($extraString, $defaultExtras)
getSingleField_typeSelect($table, $field, $row, &$PA)
static forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:32
renderDefaultLanguageDiff($table, $field, $row, $item)
extractValuesOnlyFromValueLabelList($itemFormElValue)
static intExplode($delimiter, $string, $removeEmptyValues=FALSE, $limit=0)
$uid
Definition: server.php:36
static getUserObj($classRef, $checkPrefix='', $silent=FALSE)
overrideFieldConf($fieldConfig, $TSconfig)
getSingleField_typeSelect_multiple($table, $field, $row, &$PA, $config, $selItems, $nMV_label)
dbFileIcons($fName, $mode, $allowed, $itemArray, $selector='', $params=array(), $onFocus='', $table='', $field='', $uid='', $config=array())
getPaletteFields($table, $row, $palette, $header='', $itemList='', $collapsedHeader=NULL)
static hmac($input, $additionalSecret='')
getSingleField_typeCheck($table, $field, $row, &$PA)
static trimExplode($delim, $string, $removeEmptyValues=FALSE, $limit=0)
getSpecConfForField($table, $row, $field)
static callUserFunction($funcName, &$params, &$ref, $checkPrefix='', $errorMode=0)
static calcAge($seconds, $labels=' min|hrs|days|yrs|min|hour|day|year')
getPlaceholderAttribute($table, $field, array $config, array $row)
static getRecordTitle($table, $row, $prep=FALSE, $forceResult=TRUE)
static getModuleUrl($moduleName, $urlParameters=array(), $backPathOverride=FALSE, $returnAbsoluteUrl=FALSE)
renderDefaultLanguageContent($table, $field, $row, $item)
getSingleField_typeRadio($table, $field, $row, &$PA)
formatValue($config, $itemValue)
popFromDynNestedStack($type=NULL, $ident=NULL)
if(!defined('TYPO3_MODE')) if(TYPO3_MODE=='BE' &&!(TYPO3_REQUESTTYPE &TYPO3_REQUESTTYPE_INSTALL)) $icons
Definition: ext_tables.php:52
static wrapInHelp($table, $field, $text='', array $overloadHelpText=array())
registerNestedElement($itemName, $setLevel=TRUE)
loadPaletteElements($table, $row, $palette, $itemList='')
getSingleField_typeUnknown($table, $field, $row, &$PA)
renderWizards($itemKinds, $wizConf, $table, $row, $field, &$PA, $itemName, $specConf, $RTE=FALSE)
if($list_of_literals) if(!empty($literals)) if(!empty($literals)) $result
Analyse literals to prepend the N char to them if their contents aren&#39;t numeric.
getAvailableLanguages($onlyIsoCoded=TRUE, $setDefault=TRUE)
insertDefStyle($type, $additionalClass='')
setTSconfig($table, $row, $field='')
getIconHtml($icon, $alt='', $title='')
static getSpriteIcon($iconName, array $options=array(), array $overlays=array())
static getTCAtypes($table, $rec, $useFieldNameAsKey=0)
JSbottom($formname='forms[0]', $update=FALSE)
addSelectOptionsToItemArray($items, $fieldValue, $TSconfig, $field)
static RTEsetup($RTEprop, $table, $field, $type='')
getSingleField_typeUser($table, $field, $row, &$PA)
static implodeArrayForUrl($name, array $theArray, $str='', $skipBlank=FALSE, $rawurlencodeParamName=FALSE)
static formatSize($sizeInBytes, $labels='')
formWidthText($size=48, $wrap='')
getSingleField_SW($table, $field, $row, &$PA)
checkBoxParams($itemName, $thisValue, $c, $iCount, $addFunc='')
static fixed_lgd_cs($string, $chars, $appendString='...')
static fixVersioningPid($table, &$rr, $ignoreWorkspaceMatch=FALSE)
getMainFields($table, array $row, $depth=0, array $overruleTypesArray=array())
Definition: FormEngine.php:855
static getRecordPath($uid, $clause, $titleLimit, $fullTitleLimit=0)
static getSpecConfParts($str, $defaultExtras)
static getSpriteIconForFile($fileExtension, array $options=array())
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]
static revExplode($delimiter, $string, $count=0)
getClipboardElements($allowed, $mode)
getFieldsToAdd($table, $row, $typeNum)
static getFileAbsFileName($filename, $onlyRelative=TRUE, $relToTYPO3_mainDir=FALSE)
wrapOpenPalette($header, $table, $row, $palette, $retFunc)
wrapBorder(&$out_array, &$out_pointer)
mergeFieldsWithAddedFields($fields, $fieldsToAdd, $table='')
static evalWriteFile($pArr, $currentRecord)
static getPagesTSconfig($id, $rootLine=NULL, $returnPartArray=FALSE)
getSingleField_typeSelect_singlebox($table, $field, $row, &$PA, $config, $selItems, $nMV_label)
static deleteClause($table, $tableAlias='')
addStyleSheet($key, $href, $title='', $relation='stylesheet')
static wrapJS($string, $linebreak=TRUE)
getSingleField_typeSelect_single($table, $field, $row, &$PA, $config, $selItems, $nMV_label)
static keepItemsInArray(array $array, $keepItems, $getValueFunc=NULL)
previewFieldValue($value, $config, $field='')