TYPO3  7.6
BrowseLinksController.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Rtehtmlarea\Controller;
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 
23 
28 {
47  protected $bparams;
48 
52  protected $editorNo;
53 
60 
67 
71  protected $buttonConfig = [];
72 
76  protected $thisConfig = [];
77 
83  protected $RTEProperties = [];
84 
91  protected $RTEtsConfigParams;
92 
96  protected $classesAnchorDefault = array();
97 
101  protected $classesAnchorDefaultTitle = array();
102 
106  protected $classesAnchorClassTitle = array();
107 
111  protected $classesAnchorDefaultTarget = array();
112 
116  protected $classesAnchorJSOptions = array();
117 
121  protected $defaultLinkTarget = '';
122 
126  protected $additionalAttributes = array();
127 
131  protected $siteUrl = '';
132 
136  protected function init()
137  {
138  parent::init();
139 
140  $lang = $this->getLanguageService();
141  $lang->includeLLFile('EXT:rtehtmlarea/Resources/Private/Language/locallang_browselinkscontroller.xlf');
142  $lang->includeLLFile('EXT:rtehtmlarea/Resources/Private/Language/locallang_dialogs.xlf');
143 
144  $this->contentLanguageService = GeneralUtility::makeInstance(LanguageService::class);
145  }
146 
150  protected function initVariables(ServerRequestInterface $request)
151  {
152  parent::initVariables($request);
153 
154  $queryParameters = $request->getQueryParams();
155  $this->bparams = isset($queryParameters['bparams']) ? $queryParameters['bparams'] : '';
156 
157  $this->siteUrl = GeneralUtility::getIndpEnv('TYPO3_SITE_URL');
158 
159  $currentLinkParts = isset($queryParameters['curUrl']) ? $queryParameters['curUrl'] : [];
160  if (isset($currentLinkParts['all'])) {
161  $currentLinkParts = GeneralUtility::get_tag_attributes($queryParameters['curUrl']['all']);
162  $currentLinkParts['url'] = htmlspecialchars_decode($currentLinkParts['href']);
163  unset($currentLinkParts['href']);
164  }
165  $this->currentLinkParts = $currentLinkParts;
166 
167  // Process bparams
168  $pArr = explode('|', $this->bparams);
169  $pRteArr = explode(':', $pArr[1]);
170  $this->editorNo = $pRteArr[0];
171  $this->contentTypo3Language = $pRteArr[1];
172  $this->RTEtsConfigParams = $pArr[2];
173  if (!$this->editorNo) {
174  $this->editorNo = GeneralUtility::_GP('editorNo');
175  $this->contentTypo3Language = GeneralUtility::_GP('contentTypo3Language');
176  $this->RTEtsConfigParams = GeneralUtility::_GP('RTEtsConfigParams');
177  }
178  $pArr[1] = implode(':', array($this->editorNo, $this->contentTypo3Language));
179  $pArr[2] = $this->RTEtsConfigParams;
180  $this->bparams = implode('|', $pArr);
181 
182  $this->contentLanguageService->init($this->contentTypo3Language);
183  $this->buttonConfig = isset($this->RTEProperties['default.']['buttons.']['link.'])
184  ? $this->RTEProperties['default.']['buttons.']['link.']
185  : [];
186 
187  $RTEtsConfigParts = explode(':', $this->RTEtsConfigParams);
188  $RTEsetup = $this->getBackendUser()->getTSConfig('RTE', BackendUtility::getPagesTSconfig($RTEtsConfigParts[5]));
189  $this->thisConfig = BackendUtility::RTEsetup($RTEsetup['properties'], $RTEtsConfigParts[0], $RTEtsConfigParts[2], $RTEtsConfigParts[4]);
190  }
191 
197  protected function initDocumentTemplate()
198  {
199  parent::initDocumentTemplate();
200 
201  $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
202  $pageRenderer->loadRequireJsModule('TYPO3/CMS/Rtehtmlarea/RteLinkBrowser');
203  }
204 
210  protected function initCurrentUrl()
211  {
212  if (empty($this->currentLinkParts)) {
213  return;
214  }
215 
216  if (empty($this->currentLinkParts['data-htmlarea-external'])) {
217  // strip siteUrl prefix except for external and mail links
218  if (strpos($this->currentLinkParts['url'], 'mailto:') === false) {
219  $paramsPosition = strpos($this->currentLinkParts['url'], '?');
220  if ($paramsPosition !== false) {
221  $this->currentLinkParts['url'] = substr($this->currentLinkParts['url'], $paramsPosition + 1);
222  }
223  }
224  // special treatment for page links, remove the id= part
225  $idPosition = strpos($this->currentLinkParts['url'], 'id=');
226  if ($idPosition !== false) {
227  $this->currentLinkParts['url'] = substr($this->currentLinkParts['url'], $idPosition + 3);
228  }
229 
230  // in RTE the additional params are encoded directly at the end of the href part
231  // we need to split this again into dedicated fields
232  $additionalParamsPosition = strpos($this->currentLinkParts['url'], '?');
233  if ($additionalParamsPosition === false) {
234  $additionalParamsPosition = strpos($this->currentLinkParts['url'], '&');
235  }
236  if ($additionalParamsPosition !== false) {
237  $this->currentLinkParts['params'] = substr($this->currentLinkParts['url'], $additionalParamsPosition);
238  $this->currentLinkParts['url'] = substr($this->currentLinkParts['url'], 0, $additionalParamsPosition);
239  // in case the first sign was an ? override it with &
240  $this->currentLinkParts['params'][0] = '&';
241  }
242  }
243 
244  parent::initCurrentUrl();
245  }
246 
252  public function renderLinkAttributeFields()
253  {
254  // Processing the classes configuration
255  if (!empty($this->buttonConfig['properties.']['class.']['allowedClasses'])) {
256  $classesAnchorArray = GeneralUtility::trimExplode(',', $this->buttonConfig['properties.']['class.']['allowedClasses'], true);
257  // Collecting allowed classes and configured default values
258  $classesAnchor = [
259  'all' => []
260  ];
261  $titleReadOnly = $this->buttonConfig['properties.']['title.']['readOnly']
262  || $this->buttonConfig[$this->currentLinkHandlerId . '.']['properties.']['title.']['readOnly'];
263  if (is_array($this->RTEProperties['classesAnchor.'])) {
264  foreach ($this->RTEProperties['classesAnchor.'] as $label => $conf) {
265  if (in_array($conf['class'], $classesAnchorArray)) {
266  $classesAnchor['all'][] = $conf['class'];
267  if ($conf['type'] === $this->displayedLinkHandlerId) {
268  $classesAnchor[$conf['type']][] = $conf['class'];
269  if ($this->buttonConfig[$conf['type'] . '.']['properties.']['class.']['default'] == $conf['class']) {
270  $this->classesAnchorDefault[$conf['type']] = $conf['class'];
271  if ($conf['titleText']) {
272  $this->classesAnchorDefaultTitle[$conf['type']] = $this->contentLanguageService->sL(trim($conf['titleText']));
273  }
274  if (isset($conf['target'])) {
275  $this->classesAnchorDefaultTarget[$conf['type']] = trim($conf['target']);
276  }
277  }
278  }
279  if ($titleReadOnly && $conf['titleText']) {
280  $this->classesAnchorClassTitle[$conf['class']] = ($this->classesAnchorDefaultTitle[$conf['type']] = $this->contentLanguageService->sL(trim($conf['titleText'])));
281  }
282  }
283  }
284  }
285  // Constructing the class selector options
286  foreach ($classesAnchorArray as $class) {
287  if (!in_array($class, $classesAnchor['all']) || in_array($class, $classesAnchor['all']) && is_array($classesAnchor[$this->displayedLinkHandlerId]) && in_array($class, $classesAnchor[$this->displayedLinkHandlerId])) {
288  $selected = '';
289  if ($this->linkAttributeValues['class'] === $class || !$this->linkAttributeValues['class'] && $this->classesAnchorDefault[$this->displayedLinkHandlerId] == $class) {
290  $selected = 'selected="selected"';
291  }
292  $classLabel = !empty($this->RTEProperties['classes.'][$class . '.']['name'])
293  ? $this->getPageConfigLabel($this->RTEProperties['classes.'][$class . '.']['name'], 0)
294  : $class;
295  $classStyle = !empty($this->RTEProperties['classes.'][$class . '.']['value'])
296  ? $this->RTEProperties['classes.'][$class . '.']['value']
297  : '';
298  $this->classesAnchorJSOptions[$this->displayedLinkHandlerId] .= '<option ' . $selected . ' value="' . $class . '"' . ($classStyle ? ' style="' . $classStyle . '"' : '') . '>' . $classLabel . '</option>';
299  }
300  }
301  if ($this->classesAnchorJSOptions[$this->displayedLinkHandlerId] && !($this->buttonConfig['properties.']['class.']['required'] || $this->buttonConfig[$this->currentLinkHandlerId . '.']['properties.']['class.']['required'])) {
302  $selected = '';
303  if (!$this->linkAttributeValues['class'] && !$this->classesAnchorDefault[$this->displayedLinkHandlerId]) {
304  $selected = 'selected="selected"';
305  }
306  $this->classesAnchorJSOptions[$this->displayedLinkHandlerId] = '<option ' . $selected . ' value=""></option>' . $this->classesAnchorJSOptions[$this->displayedLinkHandlerId];
307  }
308  }
309  // Default target
310  $this->defaultLinkTarget = $this->classesAnchorDefault[$this->currentLinkHandlerId] && $this->classesAnchorDefaultTarget[$this->currentLinkHandlerId]
311  ? $this->classesAnchorDefaultTarget[$this->currentLinkHandlerId]
312  : (isset($this->buttonConfig[$this->currentLinkHandlerId . '.']['properties.']['target.']['default'])
313  ? $this->buttonConfig[$this->currentLinkHandlerId . '.']['properties.']['target.']['default']
314  : (isset($this->buttonConfig['properties.']['target.']['default'])
315  ? $this->buttonConfig['properties.']['target.']['default']
316  : ''));
317  // Initializing additional attributes
318  if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['plugins']['TYPO3Link']['additionalAttributes']) {
319  $addAttributes = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['plugins']['TYPO3Link']['additionalAttributes'], true);
320  foreach ($addAttributes as $attribute) {
321  $this->additionalAttributes[$attribute] = isset($this->linkAttributeValues[$attribute]) ? $this->linkAttributeValues[$attribute] : '';
322  }
323  }
324  return parent::renderLinkAttributeFields();
325  }
326 
334  public function getPageConfigLabel($string, $JScharCode = true)
335  {
336  if (substr($string, 0, 4) !== 'LLL:') {
337  $label = $string;
338  } else {
339  $label = $this->getLanguageService()->sL(trim($string));
340  }
341  $label = str_replace('"', '\\"', str_replace('\\\'', '\'', $label));
342  return $JScharCode ? GeneralUtility::quoteJSvalue($label) : $label;
343  }
344 
348  protected function renderCurrentUrl()
349  {
350  $removeLink = '<a href="#" class="btn btn-default t3js-removeCurrentLink">' . $this->getLanguageService()->getLL('removeLink', true) . '</a>';
351  return '
352  <table border="0" cellpadding="0" cellspacing="0" id="typo3-curUrl">
353  <tr>
354  <td>' . $this->getLanguageService()->getLL('currentLink', true) . ': ' . htmlspecialchars($this->currentLinkHandler->formatCurrentUrl()) . $removeLink . '</td>
355  </tr>
356  </table>';
357  }
358 
364  protected function getAllowedItems()
365  {
366  $allowedItems = parent::getAllowedItems();
367 
368  $blindLinkOptions = isset($this->RTEProperties['default.']['blindLinkOptions'])
369  ? GeneralUtility::trimExplode(',', $this->RTEProperties['default.']['blindLinkOptions'], true)
370  : [];
371  $allowedItems = array_diff($allowedItems, $blindLinkOptions);
372 
373  if (is_array($this->buttonConfig['options.']) && $this->buttonConfig['options.']['removeItems']) {
374  $allowedItems = array_diff($allowedItems, GeneralUtility::trimExplode(',', $this->buttonConfig['options.']['removeItems'], true));
375  }
376 
377  return $allowedItems;
378  }
379 
385  protected function getAllowedLinkAttributes()
386  {
387  $allowedLinkAttributes = parent::getAllowedLinkAttributes();
388 
389  $blindLinkFields = isset($this->RTEProperties['default.']['blindLinkFields'])
390  ? GeneralUtility::trimExplode(',', $this->RTEProperties['default.']['blindLinkFields'], true)
391  : [];
392  $allowedLinkAttributes = array_diff($allowedLinkAttributes, $blindLinkFields);
393 
394  return $allowedLinkAttributes;
395  }
396 
402  protected function getLinkAttributeFieldDefinitions()
403  {
404  $fieldRenderingDefinitions = parent::getLinkAttributeFieldDefinitions();
405  $fieldRenderingDefinitions['title'] = $this->getTitleField();
406  $fieldRenderingDefinitions['class'] = $this->getClassField();
407  $fieldRenderingDefinitions['target'] = $this->getTargetField();
408  $fieldRenderingDefinitions['rel'] = $this->getRelField();
409  if (
410  isset($this->buttonConfig['queryParametersSelector.']['enabled'])
411  && !$this->buttonConfig['queryParametersSelector.']['enabled']
412  ) {
413  unset($fieldRenderingDefinitions['params']);
414  }
415  return $fieldRenderingDefinitions;
416  }
417 
423  protected function getRelField()
424  {
425  if (empty($this->buttonConfig['relAttribute.']['enabled'])) {
426  return '';
427  }
428  // @todo add rel to attributes
429  $currentRel = $this->displayedLinkHandler === $this->currentLinkHandler && !empty($this->currentLinkParts)
430  ? $this->linkAttributeValues['rel']
431  : '';
432  // @todo define label "linkRelationship" below in xlf
433  return '
434  <form action="" name="lrelform" id="lrelform">
435  <table border="0" cellpadding="2" cellspacing="1" id="typo3-linkRel">
436  <tr>
437  <td><label>' . $this->getLanguageService()->getLL('linkRelationship', true) . ':</label></td>
438  <td colspan="3"><input type="text" name="lrel" value="' . $currentRel . '" /></td>
439  </tr>
440  </table>
441  </form>
442  ';
443  }
444 
450  protected function getTargetField()
451  {
452  $targetSelectorConfig = array();
453  if (is_array($this->buttonConfig['targetSelector.'])) {
454  $targetSelectorConfig = $this->buttonConfig['targetSelector.'];
455  }
456  $target = $this->linkAttributeValues['target'] ?: $this->defaultLinkTarget;
457  $lang = $this->getLanguageService();
458  $targetSelector = '';
459 
460  if (!$targetSelectorConfig['disabled']) {
461  $targetSelector = '
462  <select name="ltarget_type" class="t3js-targetPreselect">
463  <option value=""></option>
464  <option value="_top">' . $lang->getLL('top', true) . '</option>
465  <option value="_blank">' . $lang->getLL('newWindow', true) . '</option>
466  </select>
467  ';
468  }
469 
470  return '
471  <form action="" name="ltargetform" id="ltargetform">
472  <table border="0" cellpadding="2" cellspacing="1" id="typo3-linkTarget">
473  <tr' . ($targetSelectorConfig['disabled'] ? ' style="display: none;"' : '') . '>
474  <td style="width: 96px;">' . $lang->getLL('target', true) . ':</td>
475  <td>
476  <input type="text" name="ltarget" class="t3js-linkTarget" value="' . htmlspecialchars($target) . '" />
477  ' . $targetSelector . '
478  </td>
479  </tr>
480  </table>
481  </form>
482  ';
483  }
484 
490  protected function getTitleField()
491  {
492  if ($this->linkAttributeValues['title']) {
493  $title = $this->linkAttributeValues['title'];
494  } else {
495  $title = !$this->classesAnchorDefault[$this->currentLinkHandlerId] ? '' : $this->classesAnchorDefaultTitle[$this->currentLinkHandlerId];
496  }
497  if (isset($this->buttonConfig[$this->currentLinkHandlerId . '.']['properties.']['title.']['readOnly'])) {
498  $readOnly = (bool)$this->buttonConfig[$this->currentLinkHandlerId . '.']['properties.']['title.']['readOnly'];
499  } else {
500  $readOnly = isset($this->buttonConfig['properties.']['title.']['readOnly'])
501  ? (bool)$this->buttonConfig['properties.']['title.']['readOnly']
502  : false;
503  }
504 
505  if ($readOnly) {
506  $currentClass = $this->linkAttributeFields['class'];
507  if (!$currentClass) {
508  $currentClass = empty($this->classesAnchorDefault[$this->currentLinkHandlerId]) ? '' : $this->classesAnchorDefault[$this->currentLinkHandlerId];
509  }
510  $title = $currentClass
511  ? $this->classesAnchorClassTitle[$currentClass]
512  : $this->classesAnchorDefaultTitle[$this->currentLinkHandlerId];
513  }
514  return '
515  <form action="" name="ltitleform" id="ltitleform">
516  <table border="0" cellpadding="2" cellspacing="1" id="typo3-linkTitle">
517  <tr>
518  <td style="width: 96px;"><label for="rtehtmlarea-browse-links-anchor_title" id="rtehtmlarea-browse-links-title-label">' . $this->getLanguageService()->getLL('anchor_title', true) . '</label></td>
519  <td>
520  <span id="rtehtmlarea-browse-links-title-input" style="display: ' . ($readOnly ? 'none' : 'inline') . ';">
521  <input type="text" id="rtehtmlarea-browse-links-anchor_title" name="ltitle" value="' . htmlspecialchars($title) . '" />
522  </span>
523  <span id="rtehtmlarea-browse-links-title-readonly" style="display: ' . ($readOnly ? 'inline' : 'none') . ';">' . htmlspecialchars($title) . '</span>
524  </td>
525  </tr>
526  </table>
527  </form>
528  ';
529  }
530 
536  protected function getClassField()
537  {
538  $selectClass = '';
539  if ($this->classesAnchorJSOptions[$this->currentLinkHandlerId]) {
540  $selectClass = '
541  <form action="" name="lclassform" id="lclassform">
542  <table border="0" cellpadding="2" cellspacing="1" id="typo3-linkClass">
543  <tr>
544  <td style="width: 96px;">' . $this->getLanguageService()->getLL('anchor_class', true) . '</td>
545  <td><select name="lclass" class="t3js-class-selector">
546  ' . $this->classesAnchorJSOptions[$this->currentLinkHandlerId] . '
547  </select></td>
548  </tr>
549  </table>
550  </form>
551  ';
552  }
553  return $selectClass;
554  }
555 
561  protected function getCurrentPageId()
562  {
563  return explode(':', $this->RTEtsConfigParams)[5];
564  }
565 
573  public function getConfiguration() {
574  return $this->buttonConfig;
575  }
576 
582  protected function getBodyTagAttributes()
583  {
584  $parameters = parent::getBodyTagAttributes();
585  $parameters['data-site-url'] = $this->siteUrl;
586  return $parameters;
587  }
588 
594  public function getUrlParameters(array $overrides = null)
595  {
596  return [
597  'act' => isset($overrides['act']) ? $overrides['act'] : $this->displayedLinkHandlerId,
598  'bparams' => $this->bparams,
599  'editorNo' => $this->editorNo,
600  'contentTypo3Language' => $this->contentTypo3Language
601  ];
602  }
603 }