TYPO3 CMS  TYPO3_7-6
AbstractFormElement.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
36 
40 abstract class AbstractFormElement extends AbstractNode
41 {
47  protected $defaultInputWidth = 30;
48 
54  protected $minimumInputWidth = 10;
55 
61  protected $maxInputWidth = 50;
62 
66  protected $clipboard = null;
67 
74  public function __construct(NodeFactory $nodeFactory, array $data)
75  {
76  parent::__construct($nodeFactory, $data);
77  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
78  // @todo: this must vanish as soon as elements are clean
79  $this->nodeFactory = $nodeFactory;
80  }
81 
85  protected function isWizardsDisabled()
86  {
87  return !empty($this->data['disabledWizards']);
88  }
89 
96  protected function formMaxWidth($size = 48)
97  {
98  $compensationForLargeDocuments = 1.33;
99  $compensationForFormFields = 12;
100 
101  $size = round($size * $compensationForLargeDocuments);
102  return ceil($size * $compensationForFormFields);
103  }
104 
108  protected $iconFactory;
109 
126  protected function renderWizards($itemKinds, $wizConf, $table, $row, $field, $PA, $itemName, $specConf, $RTE = false)
127  {
128  // Return not changed main item directly if wizards are disabled
129  if (!is_array($wizConf) || $this->isWizardsDisabled()) {
130  return $itemKinds[0];
131  }
132 
133  $languageService = $this->getLanguageService();
134 
135  $fieldChangeFunc = $PA['fieldChangeFunc'];
136  $item = $itemKinds[0];
137  $md5ID = 'ID' . GeneralUtility::shortmd5($itemName);
138  $prefixOfFormElName = 'data[' . $table . '][' . $row['uid'] . '][' . $field . ']';
139  $flexFormPath = '';
140  if (GeneralUtility::isFirstPartOfStr($PA['itemFormElName'], $prefixOfFormElName)) {
141  $flexFormPath = str_replace('][', '/', substr($PA['itemFormElName'], strlen($prefixOfFormElName) + 1, -1));
142  }
143 
144  // Add a suffix-value if the item is a selector box with renderType "selectSingleBox":
145  if ($PA['fieldConf']['config']['type'] === 'select' && (int)$PA['fieldConf']['config']['maxitems'] > 1 && $PA['fieldConf']['config']['renderType'] === 'selectSingleBox') {
146  $itemName .= '[]';
147  }
148 
149  // Contains wizard identifiers enabled for this record type, see "special configuration" docs
150  $wizardsEnabledByType = $specConf['wizards']['parameters'];
151 
152  $buttonWizards = [];
153  $otherWizards = [];
154  foreach ($wizConf as $wizardIdentifier => $wizardConfiguration) {
155  if (!isset($wizardConfiguration['module']['name']) && isset($wizardConfiguration['script'])) {
156  throw new \InvalidArgumentException('The way registering a wizard in TCA has changed in 6.2 and was removed in CMS 7. '
157  . 'Please set module[name]=module_name instead of using script=path/to/script.php in your TCA. ', 1437750231);
158  }
159 
160  // If an identifier starts with "_", this is a configuration option like _POSITION and not a wizard
161  if ($wizardIdentifier[0] === '_') {
162  continue;
163  }
164 
165  // Sanitize wizard type
166  $wizardConfiguration['type'] = (string)$wizardConfiguration['type'];
167 
168  // Wizards can be shown based on selected "type" of record. If this is the case, the wizard configuration
169  // is set to enableByTypeConfig = 1, and the wizardIdentifier is found in $wizardsEnabledByType
170  $wizardIsEnabled = true;
171  if (
172  isset($wizardConfiguration['enableByTypeConfig'])
173  && (bool)$wizardConfiguration['enableByTypeConfig']
174  && (!is_array($wizardsEnabledByType) || !in_array($wizardIdentifier, $wizardsEnabledByType))
175  ) {
176  $wizardIsEnabled = false;
177  }
178  // Disable if wizard is for RTE fields only and the handled field is no RTE field or RTE can not be loaded
179  if (isset($wizardConfiguration['RTEonly']) && (bool)$wizardConfiguration['RTEonly'] && !$RTE) {
180  $wizardIsEnabled = false;
181  }
182  // Disable if wizard is for not-new records only and we're handling a new record
183  if (isset($wizardConfiguration['notNewRecords']) && $wizardConfiguration['notNewRecords'] && !MathUtility::canBeInterpretedAsInteger($row['uid'])) {
184  $wizardIsEnabled = false;
185  }
186  // Wizard types script, colorbox and popup must contain a module name configuration
187  if (!isset($wizardConfiguration['module']['name']) && in_array($wizardConfiguration['type'], ['script', 'colorbox', 'popup'], true)) {
188  $wizardIsEnabled = false;
189  }
190 
191  if (!$wizardIsEnabled) {
192  continue;
193  }
194 
195  // Title / icon:
196  $iTitle = htmlspecialchars($languageService->sL($wizardConfiguration['title']));
197  if (isset($wizardConfiguration['icon'])) {
198  $icon = FormEngineUtility::getIconHtml($wizardConfiguration['icon'], $iTitle, $iTitle);
199  } else {
200  $icon = $iTitle;
201  }
202 
203  switch ($wizardConfiguration['type']) {
204  case 'userFunc':
205  $params = [];
206  $params['params'] = $wizardConfiguration['params'];
207  $params['exampleImg'] = $wizardConfiguration['exampleImg'];
208  $params['table'] = $table;
209  $params['uid'] = $row['uid'];
210  $params['pid'] = $row['pid'];
211  $params['field'] = $field;
212  $params['flexFormPath'] = $flexFormPath;
213  $params['md5ID'] = $md5ID;
214  $params['returnUrl'] = $this->data['returnUrl'];
215 
216  $params['formName'] = 'editform';
217  $params['itemName'] = $itemName;
218  $params['hmac'] = GeneralUtility::hmac($params['formName'] . $params['itemName'], 'wizard_js');
219  $params['fieldChangeFunc'] = $fieldChangeFunc;
220  $params['fieldChangeFuncHash'] = GeneralUtility::hmac(serialize($fieldChangeFunc));
221 
222  $params['item'] = &$item;
223  $params['icon'] = $icon;
224  $params['iTitle'] = $iTitle;
225  $params['wConf'] = $wizardConfiguration;
226  $params['row'] = $row;
227  $otherWizards[] = GeneralUtility::callUserFunction($wizardConfiguration['userFunc'], $params, $this);
228  break;
229 
230  case 'script':
231  $params = [];
232  $params['params'] = $wizardConfiguration['params'];
233  $params['exampleImg'] = $wizardConfiguration['exampleImg'];
234  $params['table'] = $table;
235  $params['uid'] = $row['uid'];
236  $params['pid'] = $row['pid'];
237  $params['field'] = $field;
238  $params['flexFormPath'] = $flexFormPath;
239  $params['md5ID'] = $md5ID;
240  $params['returnUrl'] = $this->data['returnUrl'];
241 
242  // Resolving script filename and setting URL.
243  $urlParameters = [];
244  if (isset($wizardConfiguration['module']['urlParameters']) && is_array($wizardConfiguration['module']['urlParameters'])) {
245  $urlParameters = $wizardConfiguration['module']['urlParameters'];
246  }
247  $wScript = BackendUtility::getModuleUrl($wizardConfiguration['module']['name'], $urlParameters, '');
248  $url = $wScript . (strstr($wScript, '?') ? '' : '?') . GeneralUtility::implodeArrayForUrl('', ['P' => $params]);
249  $buttonWizards[] =
250  '<a class="btn btn-default" href="' . htmlspecialchars($url) . '" onclick="this.blur(); return !TBE_EDITOR.isFormChanged();">'
251  . $icon .
252  '</a>';
253  break;
254 
255  case 'popup':
256  $params = [];
257  $params['params'] = $wizardConfiguration['params'];
258  $params['exampleImg'] = $wizardConfiguration['exampleImg'];
259  $params['table'] = $table;
260  $params['uid'] = $row['uid'];
261  $params['pid'] = $row['pid'];
262  $params['field'] = $field;
263  $params['flexFormPath'] = $flexFormPath;
264  $params['md5ID'] = $md5ID;
265  $params['returnUrl'] = $this->data['returnUrl'];
266 
267  $params['formName'] = 'editform';
268  $params['itemName'] = $itemName;
269  $params['hmac'] = GeneralUtility::hmac($params['formName'] . $params['itemName'], 'wizard_js');
270  $params['fieldChangeFunc'] = $fieldChangeFunc;
271  $params['fieldChangeFuncHash'] = GeneralUtility::hmac(serialize($fieldChangeFunc));
272 
273  // Resolving script filename and setting URL.
274  $urlParameters = [];
275  if (isset($wizardConfiguration['module']['urlParameters']) && is_array($wizardConfiguration['module']['urlParameters'])) {
276  $urlParameters = $wizardConfiguration['module']['urlParameters'];
277  }
278  $wScript = BackendUtility::getModuleUrl($wizardConfiguration['module']['name'], $urlParameters, '');
279  $url = $wScript . (strstr($wScript, '?') ? '' : '?') . GeneralUtility::implodeArrayForUrl('', ['P' => $params]);
280 
281  $onlyIfSelectedJS = '';
282  if (isset($wizardConfiguration['popup_onlyOpenIfSelected']) && $wizardConfiguration['popup_onlyOpenIfSelected']) {
283  $notSelectedText = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:mess.noSelItemForEdit');
284  $onlyIfSelectedJS =
285  'if (!TBE_EDITOR.curSelected(' . GeneralUtility::quoteJSvalue($itemName) . ')){' .
286  'alert(' . GeneralUtility::quoteJSvalue($notSelectedText) . ');' .
287  'return false;' .
288  '}';
289  }
290  $aOnClick =
291  'this.blur();' .
292  $onlyIfSelectedJS .
293  'vHWin=window.open(' . GeneralUtility::quoteJSvalue($url) . '+\'&P[currentValue]=\'+TBE_EDITOR.rawurlencode(' .
294  'document.editform[' . GeneralUtility::quoteJSvalue($itemName) . '].value,300' .
295  ')' .
296  '+\'&P[currentSelectedValues]=\'+TBE_EDITOR.curSelected(' . GeneralUtility::quoteJSvalue($itemName) . '),' .
297  GeneralUtility::quoteJSvalue('popUp' . $md5ID) . ',' .
298  GeneralUtility::quoteJSvalue($wizardConfiguration['JSopenParams']) .
299  ');' .
300  'vHWin.focus();' .
301  'return false;';
302 
303  $buttonWizards[] =
304  '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars($aOnClick) . '">' .
305  $icon .
306  '</a>';
307  break;
308 
309  case 'colorbox':
310  $params = [];
311  $params['params'] = $wizardConfiguration['params'];
312  $params['exampleImg'] = $wizardConfiguration['exampleImg'];
313  $params['table'] = $table;
314  $params['uid'] = $row['uid'];
315  $params['pid'] = $row['pid'];
316  $params['field'] = $field;
317  $params['flexFormPath'] = $flexFormPath;
318  $params['md5ID'] = $md5ID;
319  $params['returnUrl'] = $this->data['returnUrl'];
320 
321  $params['formName'] = 'editform';
322  $params['itemName'] = $itemName;
323  $params['hmac'] = GeneralUtility::hmac($params['formName'] . $params['itemName'], 'wizard_js');
324  $params['fieldChangeFunc'] = $fieldChangeFunc;
325  $params['fieldChangeFuncHash'] = GeneralUtility::hmac(serialize($fieldChangeFunc));
326 
327  // Resolving script filename and setting URL.
328  $urlParameters = [];
329  if (isset($wizardConfiguration['module']['urlParameters']) && is_array($wizardConfiguration['module']['urlParameters'])) {
330  $urlParameters = $wizardConfiguration['module']['urlParameters'];
331  }
332  $wScript = BackendUtility::getModuleUrl($wizardConfiguration['module']['name'], $urlParameters, '');
333  $url = $wScript . (strstr($wScript, '?') ? '' : '?') . GeneralUtility::implodeArrayForUrl('', ['P' => $params]);
334 
335  $aOnClick =
336  'this.blur();' .
337  'vHWin=window.open(' . GeneralUtility::quoteJSvalue($url) . '+\'&P[currentValue]=\'+TBE_EDITOR.rawurlencode(' .
338  'document.editform[' . GeneralUtility::quoteJSvalue($itemName) . '].value,300' .
339  ')' .
340  '+\'&P[currentSelectedValues]=\'+TBE_EDITOR.curSelected(' . GeneralUtility::quoteJSvalue($itemName) . '),' .
341  GeneralUtility::quoteJSvalue('popUp' . $md5ID) . ',' .
342  GeneralUtility::quoteJSvalue($wizardConfiguration['JSopenParams']) .
343  ');' .
344  'vHWin.focus();' .
345  'return false;';
346 
347  $otherWizards[] = '<a id="' . $md5ID . '" class="btn btn-default" href="#" onclick="' . htmlspecialchars($aOnClick) . '"><span class="t3-icon fa fa-eyedropper"></span></a>';
348  break;
349  case 'slider':
350  $params = [];
351  $params['fieldConfig'] = $PA['fieldConf']['config'];
352  $params['field'] = $field;
353  $params['table'] = $table;
354  $params['flexFormPath'] = $flexFormPath;
355  $params['md5ID'] = $md5ID;
356  $params['itemName'] = $itemName;
357  $params['wConf'] = $wizardConfiguration;
358  $params['row'] = $row;
359 
361  $wizard = GeneralUtility::makeInstance(ValueSliderWizard::class);
362  $otherWizards[] = $wizard->renderWizard($params);
363  break;
364 
365  case 'select':
366  // The select wizard is a select drop down added to the main element. It provides all the functionality
367  // that select items can do for us, so we process this element via data processing.
368  // @todo: This should be embedded in an own provider called in the main data group to not handle this on the fly here
369 
370  // Select wizard page TS can be set in TCEFORM."table"."field".wizards."wizardName"
371  $pageTsConfig = [];
372  if (isset($this->data['pageTsConfig']['TCEFORM.'][$table . '.'][$field . '.']['wizards.'][$wizardIdentifier . '.'])
373  && is_array($this->data['pageTsConfig']['TCEFORM.'][$table . '.'][$field . '.']['wizards.'][$wizardIdentifier . '.'])
374  ) {
375  $pageTsConfig['TCEFORM.']['dummySelectWizard.'][$wizardIdentifier . '.'] = $this->data['pageTsConfig']['TCEFORM.'][$table . '.'][$field . '.']['wizards.'][$wizardIdentifier . '.'];
376  }
377  $selectWizardDataInput = [
378  'tableName' => 'dummySelectWizard',
379  'command' => 'edit',
380  'pageTsConfig' => $pageTsConfig,
381  'processedTca' => [
382  'ctrl' => [],
383  'columns' => [
384  $wizardIdentifier => [
385  'type' => 'select',
386  'renderType' => 'selectSingle',
387  'config' => $wizardConfiguration,
388  ],
389  ],
390  ],
391  ];
393  $formDataGroup = GeneralUtility::makeInstance(OnTheFly::class);
394  $formDataGroup->setProviderList([ TcaSelectItems::class ]);
396  $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
397  $compilerResult = $formDataCompiler->compile($selectWizardDataInput);
398  $selectWizardItems = $compilerResult['processedTca']['columns'][$wizardIdentifier]['config']['items'];
399 
400  $options = [];
401  $options[] = '<option>' . $iTitle . '</option>';
402  foreach ($selectWizardItems as $selectWizardItem) {
403  $options[] = '<option value="' . htmlspecialchars($selectWizardItem[1]) . '">' . htmlspecialchars($selectWizardItem[0]) . '</option>';
404  }
405  if ($wizardConfiguration['mode'] == 'append') {
406  $assignValue = 'document.querySelectorAll(' . GeneralUtility::quoteJSvalue('[data-formengine-input-name="' . $itemName . '"]') . ')[0].value+=\'\'+this.options[this.selectedIndex].value';
407  } elseif ($wizardConfiguration['mode'] == 'prepend') {
408  $assignValue = 'document.querySelectorAll(' . GeneralUtility::quoteJSvalue('[data-formengine-input-name="' . $itemName . '"]') . ')[0].value=\'\'+this.options[this.selectedIndex].value+document.editform[' . GeneralUtility::quoteJSvalue($itemName) . '].value';
409  } else {
410  $assignValue = 'document.querySelectorAll(' . GeneralUtility::quoteJSvalue('[data-formengine-input-name="' . $itemName . '"]') . ')[0].value=this.options[this.selectedIndex].value';
411  }
412  $otherWizards[] =
413  '<select' .
414  ' id="' . StringUtility::getUniqueId('tceforms-select-') . '"' .
415  ' class="form-control tceforms-select tceforms-wizardselect"' .
416  ' onchange="' . htmlspecialchars($assignValue . ';this.blur();this.selectedIndex=0;' . implode('', $fieldChangeFunc)) . '"' .
417  '>' .
418  implode('', $options) .
419  '</select>';
420  break;
421  case 'suggest':
422  if (!empty($PA['fieldTSConfig']['suggest.']['default.']['hide'])) {
423  break;
424  }
426  $suggestWizard = GeneralUtility::makeInstance(SuggestWizard::class);
427  $otherWizards[] = $suggestWizard->renderSuggestSelector($PA['itemFormElName'], $table, $field, $row, $PA);
428  break;
429  }
430  }
431 
432  // For each rendered wizard, put them together around the item.
433  if (!empty($buttonWizards) || !empty($otherWizards)) {
434  $innerContent = '';
435  if (!empty($buttonWizards)) {
436  $innerContent .= '<div class="btn-group' . ($wizConf['_VERTICAL'] ? ' btn-group-vertical' : '') . '">' . implode('', $buttonWizards) . '</div>';
437  }
438  $innerContent .= implode(' ', $otherWizards);
439 
440  // Position
441  $classes = ['form-wizards-wrap'];
442  if ($wizConf['_POSITION'] === 'left') {
443  $classes[] = 'form-wizards-aside';
444  $innerContent = '<div class="form-wizards-items">' . $innerContent . '</div><div class="form-wizards-element">' . $item . '</div>';
445  } elseif ($wizConf['_POSITION'] === 'top') {
446  $classes[] = 'form-wizards-top';
447  $innerContent = '<div class="form-wizards-items">' . $innerContent . '</div><div class="form-wizards-element">' . $item . '</div>';
448  } elseif ($wizConf['_POSITION'] === 'bottom') {
449  $classes[] = 'form-wizards-bottom';
450  $innerContent = '<div class="form-wizards-element">' . $item . '</div><div class="form-wizards-items">' . $innerContent . '</div>';
451  } else {
452  $classes[] = 'form-wizards-aside';
453  $innerContent = '<div class="form-wizards-element">' . $item . '</div><div class="form-wizards-items">' . $innerContent . '</div>';
454  }
455  $item = '
456  <div class="' . implode(' ', $classes) . '">
457  ' . $innerContent . '
458  </div>';
459  }
460 
461  return $item;
462  }
463 
482  protected function dbFileIcons($fName, $mode, $allowed, $itemArray, $selector = '', $params = [], $onFocus = '', $table = '', $field = '', $uid = '', $config = [])
483  {
484  $languageService = $this->getLanguageService();
485  $disabled = '';
486  if ($params['readOnly']) {
487  $disabled = ' disabled="disabled"';
488  }
489  // INIT
490  $uidList = [];
491  $opt = [];
492  $itemArrayC = 0;
493  // Creating <option> elements:
494  if (is_array($itemArray)) {
495  $itemArrayC = count($itemArray);
496  switch ($mode) {
497  case 'db':
498  foreach ($itemArray as $pp) {
499  $pRec = BackendUtility::getRecordWSOL($pp['table'], $pp['id']);
500  if (is_array($pRec)) {
501  $pTitle = BackendUtility::getRecordTitle($pp['table'], $pRec, false, true);
502  $pUid = $pp['table'] . '_' . $pp['id'];
503  $uidList[] = $pUid;
504  $title = htmlspecialchars($pTitle);
505  $opt[] = '<option value="' . htmlspecialchars($pUid) . '" title="' . $title . '">' . $title . '</option>';
506  }
507  }
508  break;
509  case 'file_reference':
510 
511  case 'file':
512  foreach ($itemArray as $item) {
513  $itemParts = explode('|', $item);
514  $uidList[] = ($pUid = ($pTitle = $itemParts[0]));
515  $title = htmlspecialchars(rawurldecode($itemParts[1]));
516  $opt[] = '<option value="' . htmlspecialchars(rawurldecode($itemParts[0])) . '" title="' . $title . '">' . $title . '</option>';
517  }
518  break;
519  case 'folder':
520  foreach ($itemArray as $pp) {
521  $pParts = explode('|', $pp);
522  $uidList[] = ($pUid = ($pTitle = $pParts[0]));
523  $title = htmlspecialchars(rawurldecode($pParts[0]));
524  $opt[] = '<option value="' . htmlspecialchars(rawurldecode($pParts[0])) . '" title="' . $title . '">' . $title . '</option>';
525  }
526  break;
527  default:
528  foreach ($itemArray as $pp) {
529  $pParts = explode('|', $pp, 2);
530  $uidList[] = ($pUid = $pParts[0]);
531  $pTitle = $pParts[1];
532  $title = htmlspecialchars(rawurldecode($pTitle));
533  $opt[] = '<option value="' . htmlspecialchars(rawurldecode($pUid)) . '" title="' . $title . '">' . $title . '</option>';
534  }
535  }
536  }
537  // Create selector box of the options
538  $sSize = $params['autoSizeMax']
539  ? MathUtility::forceIntegerInRange($itemArrayC + 1, MathUtility::forceIntegerInRange($params['size'], 1), $params['autoSizeMax'])
540  : $params['size'];
541  if (!$selector) {
542  $maxItems = isset($params['maxitems']) ? (int)$params['maxitems'] : 0;
543  $size = isset($params['size']) ? (int)$params['size'] : 0;
544  $classes = ['form-control', 'tceforms-multiselect'];
545  if ($maxItems === 1) {
546  $classes[] = 'form-select-no-siblings';
547  }
548  $isMultiple = $maxItems !== 1 && $size !== 1;
549  $selector = '<select id="' . StringUtility::getUniqueId('tceforms-multiselect-') . '" '
550  . ($params['noList'] ? 'style="display: none"' : 'size="' . $sSize . '" class="' . implode(' ', $classes) . '"')
551  . ($isMultiple ? ' multiple="multiple"' : '')
552  . ' data-formengine-input-name="' . htmlspecialchars($fName) . '" ' . $this->getValidationDataAsDataAttribute($config) . $onFocus . $params['style'] . $disabled . '>' . implode('', $opt)
553  . '</select>';
554  }
555  $icons = [
556  'L' => [],
557  'R' => []
558  ];
559  $rOnClickInline = '';
560  if (!$params['readOnly'] && !$params['noList']) {
561  if (!$params['noBrowser']) {
562  // Check against inline uniqueness
564  $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
565  $inlineStackProcessor->initializeByGivenStructure($this->data['inlineStructure']);
566  $aOnClickInline = '';
567  if ($this->data['isInlineChild'] && $this->data['inlineParentUid']) {
568  if ($this->data['inlineParentConfig']['foreign_table'] === $table
569  && $this->data['inlineParentConfig']['foreign_unique'] === $field
570  ) {
571  $objectPrefix = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']) . '-' . $table;
572  $aOnClickInline = $objectPrefix . '|inline.checkUniqueElement|inline.setUniqueElement';
573  $rOnClickInline = 'inline.revertUnique(' . GeneralUtility::quoteJSvalue($objectPrefix) . ',null,' . GeneralUtility::quoteJSvalue($uid) . ');';
574  }
575  }
576  if (is_array($config['appearance']) && isset($config['appearance']['elementBrowserType'])) {
577  $elementBrowserType = $config['appearance']['elementBrowserType'];
578  } else {
579  $elementBrowserType = $mode;
580  }
581  if (is_array($config['appearance']) && isset($config['appearance']['elementBrowserAllowed'])) {
582  $elementBrowserAllowed = $config['appearance']['elementBrowserAllowed'];
583  } else {
584  $elementBrowserAllowed = $allowed;
585  }
586  $aOnClick = 'setFormValueOpenBrowser(' . GeneralUtility::quoteJSvalue($elementBrowserType) . ','
587  . GeneralUtility::quoteJSvalue(($fName . '|||' . $elementBrowserAllowed . '|' . $aOnClickInline)) . '); return false;';
588  $icons['R'][] = '
589  <a href="#"
590  onclick="' . htmlspecialchars($aOnClick) . '"
591  class="btn btn-default"
592  title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.browse_' . ($mode == 'db' ? 'db' : 'file'))) . '">
593  ' . $this->iconFactory->getIcon('actions-insert-record', Icon::SIZE_SMALL)->render() . '
594  </a>';
595  }
596  if (!$params['dontShowMoveIcons']) {
597  if ($sSize >= 5) {
598  $icons['L'][] = '
599  <a href="#"
600  class="btn btn-default t3js-btn-moveoption-top"
601  data-fieldname="' . $fName . '"
602  title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.move_to_top')) . '">
603  ' . $this->iconFactory->getIcon('actions-move-to-top', Icon::SIZE_SMALL)->render() . '
604  </a>';
605  }
606  $icons['L'][] = '
607  <a href="#"
608  class="btn btn-default t3js-btn-moveoption-up"
609  data-fieldname="' . $fName . '"
610  title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.move_up')) . '">
611  ' . $this->iconFactory->getIcon('actions-move-up', Icon::SIZE_SMALL)->render() . '
612  </a>';
613  $icons['L'][] = '
614  <a href="#"
615  class="btn btn-default t3js-btn-moveoption-down"
616  data-fieldname="' . $fName . '"
617  title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.move_down')) . '">
618  ' . $this->iconFactory->getIcon('actions-move-down', Icon::SIZE_SMALL)->render() . '
619  </a>';
620  if ($sSize >= 5) {
621  $icons['L'][] = '
622  <a href="#"
623  class="btn btn-default t3js-btn-moveoption-bottom"
624  data-fieldname="' . $fName . '"
625  title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.move_to_bottom')) . '">
626  ' . $this->iconFactory->getIcon('actions-move-to-bottom', Icon::SIZE_SMALL)->render() . '
627  </a>';
628  }
629  }
630  $clipElements = $this->getClipboardElements($allowed, $mode);
631  if (!empty($clipElements)) {
632  $aOnClick = '';
633  foreach ($clipElements as $elValue) {
634  if ($mode == 'db') {
635  list($itemTable, $itemUid) = explode('|', $elValue);
636  $recordTitle = BackendUtility::getRecordTitle($itemTable, BackendUtility::getRecordWSOL($itemTable, $itemUid));
637  $itemTitle = GeneralUtility::quoteJSvalue($recordTitle);
638  $elValue = $itemTable . '_' . $itemUid;
639  } else {
640  // 'file', 'file_reference' and 'folder' mode
641  $itemTitle = 'unescape(' . GeneralUtility::quoteJSvalue(rawurlencode(basename($elValue))) . ')';
642  }
643  $aOnClick .= 'setFormValueFromBrowseWin(' . GeneralUtility::quoteJSvalue($fName) . ',unescape('
644  . GeneralUtility::quoteJSvalue(rawurlencode(str_replace('%20', ' ', $elValue))) . '),' . $itemTitle . ',' . $itemTitle . ');';
645  }
646  $aOnClick .= 'return false;';
647  $icons['R'][] = '
648  <a href="#"
649  class="btn btn-default"
650  onclick="' . htmlspecialchars($aOnClick) . '"
651  title="' . htmlspecialchars(sprintf($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.clipInsert_' . ($mode == 'db' ? 'db' : 'file')), count($clipElements))) . '">
652  ' . $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render() . '
653  </a>';
654  }
655  }
656  if (!$params['readOnly'] && !$params['noDelete']) {
657  $icons['L'][] = '
658  <a href="#"
659  class="btn btn-default t3js-btn-removeoption"
660  onClick="' . $rOnClickInline . '"
661  data-fieldname="' . $fName . '"
662  title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.remove_selected')) . '">
663  ' . $this->iconFactory->getIcon('actions-selection-delete', Icon::SIZE_SMALL)->render() . '
664  </a>';
665  }
666 
667  // Thumbnails
668  $imagesOnly = false;
669  if ($params['thumbnails'] && $params['allowed']) {
670  // In case we have thumbnails, check if only images are allowed.
671  // In this case, render them below the field, instead of to the right
672  $allowedExtensionList = $params['allowed'];
673  $imageExtensionList = GeneralUtility::trimExplode(',', strtolower($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']), true);
674  $imagesOnly = true;
675  foreach ($allowedExtensionList as $allowedExtension) {
676  if (!ArrayUtility::inArray($imageExtensionList, $allowedExtension)) {
677  $imagesOnly = false;
678  break;
679  }
680  }
681  }
682  $thumbnails = '';
683  if (is_array($params['thumbnails']) && !empty($params['thumbnails'])) {
684  if ($imagesOnly) {
685  $thumbnails .= '<ul class="list-inline">';
686  foreach ($params['thumbnails'] as $thumbnail) {
687  $thumbnails .= '<li><span class="thumbnail">' . $thumbnail['image'] . '</span></li>';
688  }
689  $thumbnails .= '</ul>';
690  } else {
691  $thumbnails .= '<div class="table-fit"><table class="table table-white"><tbody>';
692  foreach ($params['thumbnails'] as $thumbnail) {
693  $thumbnails .= '
694  <tr>
695  <td class="col-icon">
696  ' . ($config['internal_type'] === 'db'
697  ? BackendUtility::wrapClickMenuOnIcon($thumbnail['image'], $thumbnail['table'], $thumbnail['uid'], 1, '', '+copy,info,edit,view')
698  : $thumbnail['image']) . '
699  </td>
700  <td class="col-title">
701  ' . ($config['internal_type'] === 'db'
702  ? BackendUtility::wrapClickMenuOnIcon($thumbnail['name'], $thumbnail['table'], $thumbnail['uid'], 1, '', '+copy,info,edit,view')
703  : $thumbnail['name']) . '
704  ' . ($config['internal_type'] === 'db' ? ' <span class="text-muted">[' . $thumbnail['uid'] . ']</span>' : '') . '
705  </td>
706  </tr>
707  ';
708  }
709  $thumbnails .= '</tbody></table></div>';
710  }
711  }
712 
713  // Allowed Tables
714  $allowedTables = '';
715  if (is_array($params['allowedTables']) && !empty($params['allowedTables'])) {
716  $allowedTables .= '<div class="help-block">';
717  foreach ($params['allowedTables'] as $key => $item) {
718  if (is_array($item)) {
719  if (empty($params['readOnly'])) {
720  $allowedTables .= '<a href="#" onClick="' . htmlspecialchars($item['onClick']) . '" class="btn btn-default">' . $item['icon'] . ' ' . htmlspecialchars($item['name']) . '</a> ';
721  } else {
722  $allowedTables .= '<span>' . htmlspecialchars($item['name']) . '</span> ';
723  }
724  } elseif ($key === 'name') {
725  $allowedTables .= '<span>' . htmlspecialchars($item) . '</span> ';
726  }
727  }
728  $allowedTables .= '</div>';
729  }
730  // Allowed
731  $allowedList = '';
732  if (is_array($params['allowed']) && !empty($params['allowed'])) {
733  foreach ($params['allowed'] as $item) {
734  $allowedList .= '<span class="label label-success">' . strtoupper($item) . '</span> ';
735  }
736  }
737  // Disallowed
738  $disallowedList = '';
739  if (is_array($params['disallowed']) && !empty($params['disallowed'])) {
740  foreach ($params['disallowed'] as $item) {
741  $disallowedList .= '<span class="label label-danger">' . strtoupper($item) . '</span> ';
742  }
743  }
744  // Rightbox
745  $rightbox = ($params['rightbox'] ?: '');
746 
747  // Hook: dbFileIcons_postProcess (requested by FAL-team for use with the "fal" extension)
748  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['dbFileIcons'])) {
749  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['dbFileIcons'] as $classRef) {
750  $hookObject = GeneralUtility::getUserObj($classRef);
751  if (!$hookObject instanceof DatabaseFileIconsHookInterface) {
752  throw new \UnexpectedValueException($classRef . ' must implement interface ' . DatabaseFileIconsHookInterface::class, 1290167704);
753  }
754  $additionalParams = [
755  'mode' => $mode,
756  'allowed' => $allowed,
757  'itemArray' => $itemArray,
758  'onFocus' => $onFocus,
759  'table' => $table,
760  'field' => $field,
761  'uid' => $uid,
762  'config' => $GLOBALS['TCA'][$table]['columns'][$field]
763  ];
764  $hookObject->dbFileIcons_postProcess($params, $selector, $thumbnails, $icons, $rightbox, $fName, $uidList, $additionalParams, $this);
765  }
766  }
767 
768  // Output
769  $str = '
770  ' . ($params['headers']['selector'] ? '<label>' . $params['headers']['selector'] . '</label>' : '') . '
771  <div class="form-wizards-wrap form-wizards-aside">
772  <div class="form-wizards-element">
773  ' . $selector . '
774  ' . (!$params['noList'] && !empty($allowedTables) ? $allowedTables : '') . '
775  ' . (!$params['noList'] && (!empty($allowedList) || !empty($disallowedList))
776  ? '<div class="help-block">' . $allowedList . $disallowedList . ' </div>'
777  : '') . '
778  </div>
779  ' . (!empty($icons['L']) ? '<div class="form-wizards-items"><div class="btn-group-vertical">' . implode('', $icons['L']) . '</div></div>' : '') . '
780  ' . (!empty($icons['R']) ? '<div class="form-wizards-items"><div class="btn-group-vertical">' . implode('', $icons['R']) . '</div></div>' : '') . '
781  </div>
782  ';
783  if ($rightbox) {
784  $str = '
785  <div class="form-multigroup-wrap t3js-formengine-field-group">
786  <div class="form-multigroup-item form-multigroup-element">' . $str . '</div>
787  <div class="form-multigroup-item form-multigroup-element">
788  ' . ($params['headers']['items'] ? '<label>' . $params['headers']['items'] . '</label>' : '') . '
789  ' . ($params['headers']['selectorbox'] ? '<div class="form-multigroup-item-wizard">' . $params['headers']['selectorbox'] . '</div>' : '') . '
790  ' . $rightbox . '
791  </div>
792  </div>
793  ';
794  }
795  $str .= $thumbnails;
796 
797  // Creating the hidden field which contains the actual value as a comma list.
798  $str .= '<input type="hidden" name="' . $fName . '" value="' . htmlspecialchars(implode(',', $uidList)) . '" />';
799  return $str;
800  }
801 
809  protected function getClipboardElements($allowed, $mode)
810  {
811  if (!is_object($this->clipboard)) {
812  $this->clipboard = GeneralUtility::makeInstance(Clipboard::class);
813  $this->clipboard->initializeClipboard();
814  }
815 
816  $output = [];
817  switch ($mode) {
818  case 'file_reference':
819 
820  case 'file':
821  $elFromTable = $this->clipboard->elFromTable('_FILE');
822  $allowedExts = GeneralUtility::trimExplode(',', $allowed, true);
823  // If there are a set of allowed extensions, filter the content:
824  if ($allowedExts) {
825  foreach ($elFromTable as $elValue) {
826  $pI = pathinfo($elValue);
827  $ext = strtolower($pI['extension']);
828  if (in_array($ext, $allowedExts)) {
829  $output[] = $elValue;
830  }
831  }
832  } else {
833  // If all is allowed, insert all: (This does NOT respect any disallowed extensions,
834  // but those will be filtered away by the backend TCEmain)
835  $output = $elFromTable;
836  }
837  break;
838  case 'db':
839  $allowedTables = GeneralUtility::trimExplode(',', $allowed, true);
840  // All tables allowed for relation:
841  if (trim($allowedTables[0]) === '*') {
842  $output = $this->clipboard->elFromTable('');
843  } else {
844  // Only some tables, filter them:
845  foreach ($allowedTables as $tablename) {
846  $elFromTable = $this->clipboard->elFromTable($tablename);
847  $output = array_merge($output, $elFromTable);
848  }
849  }
850  $output = array_keys($output);
851  break;
852  }
853 
854  return $output;
855  }
856 
860  protected function getLanguageService()
861  {
862  return $GLOBALS['LANG'];
863  }
864 }
static isFirstPartOfStr($str, $partStr)
static forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:31
static getIconHtml($icon, $alt='', $title='')
static hmac($input, $additionalSecret='')
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static callUserFunction($funcName, &$params, &$ref, $checkPrefix='', $errorMode=0)
static inArray(array $in_array, $item)
static implodeArrayForUrl($name, array $theArray, $str='', $skipBlank=false, $rawurlencodeParamName=false)
getValidationDataAsDataAttribute(array $config)
static getRecordTitle($table, $row, $prep=false, $forceResult=true)
$uid
Definition: server.php:38
__construct(NodeFactory $nodeFactory, array $data)
static wrapClickMenuOnIcon( $content, $table, $uid=0, $listFrame=true, $addParams='', $enDisItems='', $returnTagParameters=false)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static getRecordWSOL($table, $uid, $fields=' *', $where='', $useDeleteClause=true, $unsetMovePointers=false)