‪TYPO3CMS  9.5
FrontendEditPanel.php
Go to the documentation of this file.
1 <?php
2 namespace ‪TYPO3\CMS\Feedit;
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  */
26 
33 {
39  protected ‪$cObj;
40 
46  protected ‪$frontendController;
47 
51  protected ‪$backendUser;
52 
56  protected ‪$iconFactory;
57 
66  {
67  $this->frontendController = ‪$frontendController ?: ‪$GLOBALS['TSFE'];
68  $this->backendUser = ‪$backendUser ?: ‪$GLOBALS['BE_USER'];
69  $this->cObj = GeneralUtility::makeInstance(\‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class);
70  $this->cObj->start([]);
71  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
72  }
73 
89  public function ‪editPanel($content, array $conf, $currentRecord = '', array $dataArr = [], $table = '', array $allow = [], $newUID = 0, array $hiddenFields = [])
90  {
91  $hiddenFieldString = '';
92 
93  // Special content is about to be shown, so the cache must be disabled.
94  $this->frontendController->set_no_cache('Frontend edit panel is shown', true);
95 
96  $formName = 'TSFE_EDIT_FORM_' . substr($this->frontendController->uniqueHash(), 0, 4);
97  $formTag = '<form name="' . $formName . '" id ="' . $formName . '" action="' . htmlspecialchars(GeneralUtility::getIndpEnv('REQUEST_URI')) . '" method="post" enctype="multipart/form-data" onsubmit="return TBE_EDITOR.checkSubmit(1);">';
98  $sortField = ‪$GLOBALS['TCA'][$table]['ctrl']['sortby'];
99  $labelField = ‪$GLOBALS['TCA'][$table]['ctrl']['label'];
100  $hideField = ‪$GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'];
101 
102  $panel = '';
103  if (isset($allow['toolbar'])) {
104  $editToolbarService = GeneralUtility::makeInstance(EditToolbarService::class);
105  $panel .= $editToolbarService->createToolbar();
106  }
107  if (isset($allow['edit'])) {
108  $icon = '<span title="' . $this->‪getLabel('p_editRecord') . '">' . $this->iconFactory->getIcon('actions-document-open', ‪Icon::SIZE_SMALL)->render('inline') . '</span>';
109  $panel .= $this->‪editPanelLinkWrap($icon, $formName, 'edit', $dataArr['_LOCALIZED_UID'] ? $table . ':' . $dataArr['_LOCALIZED_UID'] : $currentRecord);
110  }
111  // Hiding in workspaces because implementation is incomplete
112  if (isset($allow['move']) && $sortField && $this->backendUser->workspace === 0) {
113  $icon = '<span title="' . $this->‪getLabel('p_moveUp') . '">' . $this->iconFactory->getIcon('actions-move-up', ‪Icon::SIZE_SMALL)->render('inline') . '</span>';
114  $panel .= $this->‪editPanelLinkWrap($icon, $formName, 'up');
115  $icon = '<span title="' . $this->‪getLabel('p_moveDown') . '">' . $this->iconFactory->getIcon('actions-move-down', ‪Icon::SIZE_SMALL)->render('inline') . '</span>';
116  $panel .= $this->‪editPanelLinkWrap($icon, $formName, 'down');
117  }
118  // Hiding in workspaces because implementation is incomplete
119  // Hiding for localizations because it is unknown what should be the function in that case
120  if (isset($allow['hide']) && $hideField && $this->backendUser->workspace === 0 && !$dataArr['_LOCALIZED_UID']) {
121  if ($dataArr[$hideField]) {
122  $icon = $this->iconFactory->getIcon('actions-edit-unhide', ‪Icon::SIZE_SMALL)->render('inline');
123  $panel .= $this->‪editPanelLinkWrap($icon, $formName, 'unhide');
124  } else {
125  $icon = $this->iconFactory->getIcon('actions-edit-hide', ‪Icon::SIZE_SMALL)->render('inline');
126  $panel .= $this->‪editPanelLinkWrap($icon, $formName, 'hide', '', $this->‪getLabel('p_hideConfirm'));
127  }
128  }
129  if (isset($allow['new'])) {
130  if ($table === 'pages') {
131  $icon = '<span title="' . $this->‪getLabel('p_newSubpage') . '">'
132  . $this->iconFactory->getIcon('actions-page-new', ‪Icon::SIZE_SMALL)->render('inline')
133  . '</span>';
134  $panel .= $this->‪editPanelLinkWrap($icon, $formName, 'new', $currentRecord, '');
135  } else {
136  $icon = '<span title="' . $this->‪getLabel('p_newRecordAfter') . '">'
137  . $this->iconFactory->getIcon('actions-document-new', ‪Icon::SIZE_SMALL)->render('inline')
138  . '</span>';
139  $panel .= $this->‪editPanelLinkWrap($icon, $formName, 'new', $currentRecord, '', $newUID);
140  }
141  }
142  // Hiding in workspaces because implementation is incomplete
143  // Hiding for localizations because it is unknown what should be the function in that case
144  if (isset($allow['delete']) && $this->backendUser->workspace === 0 && !$dataArr['_LOCALIZED_UID']) {
145  $icon = '<span title="' . $this->‪getLabel('p_delete') . '">'
146  . $this->iconFactory->getIcon('actions-edit-delete', ‪Icon::SIZE_SMALL)->render('inline')
147  . '</span>';
148  $panel .= $this->‪editPanelLinkWrap($icon, $formName, 'delete', '', $this->‪getLabel('p_deleteConfirm'));
149  }
150  // Final
151  $labelTxt = $this->cObj->stdWrap($conf['label'], $conf['label.']);
152  foreach ((array)$hiddenFields as $name => $value) {
153  $hiddenFieldString .= '<input type="hidden" name="TSFE_EDIT[' . htmlspecialchars($name) . ']" value="' . htmlspecialchars($value) . '"/>' . LF;
154  }
155 
156  $panel = '<!-- BE_USER Edit Panel: -->
157  ' . $formTag . $hiddenFieldString . '
158  <input type="hidden" name="TSFE_EDIT[cmd]" value="" />
159  <input type="hidden" name="TSFE_EDIT[record]" value="' . $currentRecord . '" />
160  <div class="typo3-editPanel">'
161  . '<div class="typo3-editPanel-btn-group">'
162  . $panel
163  . '</div>' .
164  ($labelTxt ? '<div class="typo3-editPanel-label">' . sprintf($labelTxt, htmlspecialchars(GeneralUtility::fixed_lgd_cs($dataArr[$labelField], 50))) . '</div>' : '') . '
165  </div>
166  </form>';
167 
168  // Wrap the panel
169  if ($conf['innerWrap']) {
170  $panel = $this->cObj->wrap($panel, $conf['innerWrap']);
171  }
172  if ($conf['innerWrap.']) {
173  $panel = $this->cObj->stdWrap($panel, $conf['innerWrap.']);
174  }
175 
176  // Wrap the complete panel
177  if ($conf['outerWrap']) {
178  $panel = $this->cObj->wrap($panel, $conf['outerWrap']);
179  }
180  if ($conf['outerWrap.']) {
181  $panel = $this->cObj->stdWrap($panel, $conf['outerWrap.']);
182  }
183  if ($conf['printBeforeContent']) {
184  $finalOut = $panel . $content;
185  } else {
186  $finalOut = $content . $panel;
187  }
188 
189  $hidden = $this->‪isDisabled($table, $dataArr) ? ' typo3-feedit-element-hidden' : '';
190  $outerWrapConfig = $conf['stdWrap.'] ?? ['wrap' => '<div class="typo3-feedit-element' . $hidden . '">|</div>'];
191  $finalOut = $this->cObj->stdWrap($finalOut, $outerWrapConfig);
192 
193  return $finalOut;
194  }
195 
211  public function ‪editIcons($content, $params, array $conf = [], $currentRecord = '', array $dataArr = [], $addUrlParamStr = '', $table, $editUid, $fieldList)
212  {
213  // Special content is about to be shown, so the cache must be disabled.
214  $this->frontendController->set_no_cache('Display frontend edit icons', true);
215  $iconTitle = $this->cObj->stdWrap($conf['iconTitle'], $conf['iconTitle.']);
216  $iconImg = '<span title="' . htmlspecialchars($iconTitle, ENT_COMPAT, 'UTF-8', false) . '" style="' . ($conf['styleAttribute'] ? htmlspecialchars($conf['styleAttribute']) : '') . '">'
217  . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render('inline')
218  . '</span>';
219  $noView = GeneralUtility::_GP('ADMCMD_view') ? 1 : 0;
220 
221  $uriBuilder = GeneralUtility::makeInstance(\‪TYPO3\CMS\Backend\Routing\UriBuilder::class);
222  $url = (string)$uriBuilder->buildUriFromRoute(
223  'record_edit',
224  [
225  'edit[' . $table . '][' . $editUid . ']' => 'edit',
226  'columnsOnly' => $fieldList,
227  'noView' => $noView,
228  'feEdit' => 1
229  ]
230  ) . $addUrlParamStr;
231  $icon = $this->‪editPanelLinkWrap_doWrap($iconImg, $url, 'content-link');
232  if ($conf['beforeLastTag'] < 0) {
233  $content = $icon . $content;
234  } elseif ($conf['beforeLastTag'] > 0) {
235  $cBuf = rtrim($content);
236  $secureCount = 30;
237  while ($secureCount && substr($cBuf, -1) === '>' && substr($cBuf, -4) !== '</a>') {
238  $cBuf = rtrim(preg_replace('/<[^<]*>$/', '', $cBuf));
239  $secureCount--;
240  }
241  $content = strlen($cBuf) && $secureCount ? substr($content, 0, strlen($cBuf)) . $icon . substr($content, strlen($cBuf)) : ($content = $icon . $content);
242  } else {
243  $content .= $icon;
244  }
245  return $content;
246  }
247 
260  protected function ‪editPanelLinkWrap($string, $formName, $cmd, $currentRecord = '', $confirm = '', $nPid = '')
261  {
262  $noView = GeneralUtility::_GP('ADMCMD_view') ? 1 : 0;
264  $uriBuilder = GeneralUtility::makeInstance(\‪TYPO3\CMS\Backend\Routing\UriBuilder::class);
265  if ($cmd === 'edit') {
266  $rParts = explode(':', $currentRecord);
267  $out = $this->‪editPanelLinkWrap_doWrap($string, (string)$uriBuilder->buildUriFromRoute('record_edit', ['edit[' . $rParts[0] . '][' . $rParts[1] . ']' => 'edit', 'noView' => $noView, 'feEdit' => 1]), $currentRecord);
268  } elseif ($cmd === 'new') {
269  $rParts = explode(':', $currentRecord);
270  if ($rParts[0] === 'pages') {
271  $out = $this->‪editPanelLinkWrap_doWrap($string, (string)$uriBuilder->buildUriFromRoute('db_new', ['id' => $rParts[1], 'pagesOnly' => 1]), $currentRecord);
272  } else {
273  if (!(int)$nPid) {
274  $nPid = ‪MathUtility::canBeInterpretedAsInteger($rParts[1]) ? -$rParts[1] : $this->frontendController->id;
275  }
276  $out = $this->‪editPanelLinkWrap_doWrap($string, (string)$uriBuilder->buildUriFromRoute('record_edit', ['edit[' . $rParts[0] . '][' . $nPid . ']' => 'new', 'noView' => $noView]), $currentRecord);
277  }
278  } else {
279  if ($confirm && $this->backendUser->jsConfirmation(‪JsConfirmation::FE_EDIT)) {
280  // Gets htmlspecialchared later
281  $cf1 = 'if (confirm(' . GeneralUtility::quoteJSvalue($confirm) . ')) {';
282  $cf2 = '}';
283  } else {
284  $cf1 = ($cf2 = '');
285  }
286  $out = '<a href="#" class="typo3-editPanel-btn typo3-editPanel-btn-default" onclick="' . htmlspecialchars($cf1 . 'document.' . $formName . '[\'TSFE_EDIT[cmd]\'].value=\'' . $cmd . '\'; document.' . $formName . '.submit();' . $cf2 . ' return false;') . '">' . $string . '</a>';
287  }
288  return $out;
289  }
290 
300  protected function editPanelLinkWrap_doWrap($string, $url, $additionalClasses = '')
301  {
302  $width = MathUtility::forceIntegerInRange($this->backendUser->getTSConfig()['options.']['feedit.']['popupWidth'] ?? 690, 690, 5000, 690);
303  $height = MathUtility::forceIntegerInRange($this->backendUser->getTSConfig()['options.']['feedit.']['popupHeight'] ?? 500, 500, 5000, 500);
304  $onclick = 'vHWin=window.open(' . GeneralUtility::quoteJSvalue($url . '&returnUrl=' . rawurlencode(PathUtility::getAbsoluteWebPath(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Public/Html/Close.html')))) . ',\'FEquickEditWindow\',\'width=' . $width . ',height=' . $height . ',status=0,menubar=0,scrollbars=1,resizable=1\');vHWin.focus();return false;';
305  return '<a href="#" class="typo3-‪editPanel-btn typo3-‪editPanel-btn-default frontEndEditIconLinks ' . htmlspecialchars($additionalClasses) . '" onclick="' . htmlspecialchars($onclick) . '">' . $string . '</a>';
306  }
307 
315  protected function isDisabled($table, array $row)
316  {
317  $status = false;
318  if (
319  $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'] &&
320  $row[$GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']] ||
321  $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['fe_group'] &&
322  $this->frontendController->simUserGroup &&
323  $row[$GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['fe_group']] == $this->frontendController->simUserGroup ||
324  $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['starttime'] &&
325  $row[$GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['starttime']] > $GLOBALS['EXEC_TIME'] ||
326  $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['endtime'] &&
327  $row[$GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['endtime']] &&
328  $row[$GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['endtime']] < $GLOBALS['EXEC_TIME']
329  ) {
330  $status = true;
331  }
332 
333  return $status;
334  }
335 
346  protected function getLabel(string $key): string
347  {
348  if (!is_array($GLOBALS['LOCAL_LANG'])) {
349  $this->getLanguageService()->includeLLFile('EXT:core/Resources/Private/Language/locallang_tsfe.xlf');
350  if (!is_array($GLOBALS['LOCAL_LANG'])) {
351  $GLOBALS['LOCAL_LANG'] = [];
352  }
353  }
354  return htmlspecialchars($this->getLanguageService()->getLL($key));
355  }
356 
360  protected function getLanguageService(): LanguageService
361  {
362  return $GLOBALS['LANG'];
363  }
364 }
‪TYPO3\CMS\Core\Imaging\Icon\SIZE_SMALL
‪const SIZE_SMALL
Definition: Icon.php:29
‪TYPO3\CMS\Feedit\FrontendEditPanel\$frontendController
‪TypoScriptFrontendController $frontendController
Definition: FrontendEditPanel.php:44
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:23
‪TYPO3\CMS\Feedit\FrontendEditPanel\$backendUser
‪FrontendBackendUserAuthentication $backendUser
Definition: FrontendEditPanel.php:48
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger($var)
Definition: MathUtility.php:73
‪TYPO3\CMS\Adminpanel\Service\EditToolbarService
Definition: EditToolbarService.php:39
‪TYPO3\CMS\Backend\FrontendBackendUserAuthentication
Definition: FrontendBackendUserAuthentication.php:35
‪TYPO3\CMS\Core\Imaging\Icon
Definition: Icon.php:25
‪TYPO3\CMS\Feedit\FrontendEditPanel\editPanelLinkWrap_doWrap
‪string editPanelLinkWrap_doWrap($string, $url, $additionalClasses='')
Definition: FrontendEditPanel.php:296
‪TYPO3\CMS\Feedit\FrontendEditPanel\getLabel
‪string getLabel(string $key)
Definition: FrontendEditPanel.php:342
‪TYPO3
‪TYPO3\CMS\Feedit\FrontendEditPanel\$cObj
‪TYPO3 CMS Frontend ContentObject ContentObjectRenderer $cObj
Definition: FrontendEditPanel.php:38
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:31
‪TYPO3\CMS\Core\Type\Bitmask\JsConfirmation\FE_EDIT
‪const FE_EDIT
Definition: JsConfirmation.php:43
‪TYPO3\CMS\Feedit\FrontendEditPanel\$iconFactory
‪TYPO3 CMS Core Imaging IconFactory $iconFactory
Definition: FrontendEditPanel.php:52
‪TYPO3\CMS\Feedit\FrontendEditPanel\editPanelLinkWrap
‪string editPanelLinkWrap($string, $formName, $cmd, $currentRecord='', $confirm='', $nPid='')
Definition: FrontendEditPanel.php:256
‪TYPO3\CMS\Feedit
‪TYPO3\CMS\Feedit\FrontendEditPanel\__construct
‪__construct($_=null, TypoScriptFrontendController $frontendController=null, FrontendBackendUserAuthentication $backendUser=null)
Definition: FrontendEditPanel.php:61
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:97
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:21
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:29
‪TYPO3\CMS\Feedit\FrontendEditPanel\editPanel
‪string editPanel($content, array $conf, $currentRecord='', array $dataArr=[], $table='', array $allow=[], $newUID=0, array $hiddenFields=[])
Definition: FrontendEditPanel.php:85
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Core\Type\Bitmask\JsConfirmation
Definition: JsConfirmation.php:24
‪TYPO3\CMS\Feedit\FrontendEditPanel\isDisabled
‪bool isDisabled($table, array $row)
Definition: FrontendEditPanel.php:311
‪TYPO3\CMS\Feedit\FrontendEditPanel
Definition: FrontendEditPanel.php:33
‪TYPO3\CMS\Feedit\FrontendEditPanel\editIcons
‪string editIcons($content, $params, array $conf=[], $currentRecord='', array $dataArr=[], $addUrlParamStr='', $table, $editUid, $fieldList)
Definition: FrontendEditPanel.php:207