TYPO3  7.6
RichTextElement.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Rtehtmlarea\Form\Element;
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 
33 
38 {
44  protected $resultArray;
45 
52  protected $pidOfPageRecord;
53 
63 
82 
90 
96  protected $domIdentifier;
97 
103  protected $defaultExtras;
104 
110  protected $client;
111 
117  protected $language;
118 
125 
132 
139 
146 
153  'space' => 'space',
154  'bar' => 'separator',
155  'linebreak' => 'linebreak'
156  );
157 
163  protected $toolbar = array();
164 
170  protected $toolbarOrderArray = array();
171 
177  protected $pluginButton = array();
178 
184  protected $pluginLabel = array();
185 
191  protected $pluginEnabledArray = array();
192 
198  protected $pluginEnabledCumulativeArray = array();
199 
205  protected $registeredPlugins = array();
206 
213  public function render()
214  {
215  $table = $this->data['tableName'];
216  $fieldName = $this->data['fieldName'];
217  $row = $this->data['databaseRow'];
218  $parameterArray = $this->data['parameterArray'];
219 
220  $backendUser = $this->getBackendUserAuthentication();
221 
222  $this->resultArray = $this->initializeResultArray();
223  $this->defaultExtras = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
224  $this->pidOfPageRecord = $table === 'pages' && MathUtility::canBeInterpretedAsInteger($row['uid']) ? (int)$row['uid'] : (int)$row['pid'];
225  BackendUtility::fixVersioningPid($table, $row);
226  $this->pidOfVersionedMotherRecord = (int)$row['pid'];
227  $this->vanillaRteTsConfig = $backendUser->getTSConfig('RTE', BackendUtility::getPagesTSconfig($this->pidOfPageRecord));
228  $this->processedRteConfiguration = BackendUtility::RTEsetup(
229  $this->vanillaRteTsConfig['properties'],
230  $table,
231  $fieldName,
232  $this->data['recordTypeValue']
233  );
234  $this->client = $this->clientInfo();
235  $this->domIdentifier = preg_replace('/[^a-zA-Z0-9_:.-]/', '_', $parameterArray['itemFormElName']);
236  $this->domIdentifier = htmlspecialchars(preg_replace('/^[^a-zA-Z]/', 'x', $this->domIdentifier));
237 
238  $this->initializeLanguageRelatedProperties();
239 
240  // Get skin file name from Page TSConfig if any
241  $skinFilename = trim($this->processedRteConfiguration['skin']) ?: 'EXT:rtehtmlarea/Resources/Public/Css/Skin/htmlarea.css';
242  $skinFilename = $this->getFullFileName($skinFilename);
243  $skinDirectory = dirname($skinFilename);
244 
245  // jQuery UI Resizable style sheet and main skin stylesheet
246  $this->resultArray['stylesheetFiles'][] = $skinDirectory . '/jquery-ui-resizable.css';
247  $this->resultArray['stylesheetFiles'][] = $skinFilename;
248 
249  $this->enableRegisteredPlugins();
250 
251  // Configure toolbar
252  $this->setToolbar();
253 
254  // Check if some plugins need to be disabled
255  $this->setPlugins();
256 
257  // Merge the list of enabled plugins with the lists from the previous RTE editing areas on the same form
258  $this->pluginEnabledCumulativeArray = $this->pluginEnabledArray;
259 
260  $this->addInstanceJavaScriptRegistration();
261 
262  $this->addOnSubmitJavaScriptCode();
263 
264  // Add RTE JavaScript
265  $this->loadRequireModulesForRTE();
266 
267  // Create language labels
268  $this->createJavaScriptLanguageLabelsFromFiles();
269 
270  // Get RTE init JS code
271  $this->resultArray['additionalJavaScriptPost'][] = $this->getRteInitJsCode();
272 
273  $html = $this->getMainHtml();
274 
275  $this->resultArray['html'] = $this->renderWizards(
276  array($html),
277  $parameterArray['fieldConf']['config']['wizards'],
278  $table,
279  $row,
280  $fieldName,
281  $parameterArray,
282  $parameterArray['itemFormElName'],
283  $this->defaultExtras,
284  true
285  );
286 
287  return $this->resultArray;
288  }
289 
295  protected function getMainHtml()
296  {
297  $backendUser = $this->getBackendUserAuthentication();
298 
299  if ($this->isInFullScreenMode()) {
300  $width = '100%';
301  $height = '100%';
302  $paddingRight = '0px';
303  $editorWrapWidth = '100%';
304  } else {
305  $options = $backendUser->userTS['options.'];
306  $width = 530 + (isset($options['RTELargeWidthIncrement']) ? (int)$options['RTELargeWidthIncrement'] : 150);
308  $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
309  $inlineStackProcessor->initializeByGivenStructure($this->data['inlineStructure']);
310  $inlineStructureDepth = $inlineStackProcessor->getStructureDepth();
311  $width -= $inlineStructureDepth > 0 ? ($inlineStructureDepth + 1) * 12 : 0;
312  $widthOverride = isset($backendUser->uc['rteWidth']) && trim($backendUser->uc['rteWidth']) ?: trim($this->processedRteConfiguration['RTEWidthOverride']);
313  if ($widthOverride) {
314  if (strstr($widthOverride, '%')) {
315  if ($this->client['browser'] !== 'msie') {
316  $width = (int)$widthOverride > 0 ? (int)$widthOverride : '100%';
317  }
318  } else {
319  $width = (int)$widthOverride > 0 ? (int)$widthOverride : $width;
320  }
321  }
322  $width = strstr($width, '%') ? $width : $width . 'px';
323  $height = 380 + (isset($options['RTELargeHeightIncrement']) ? (int)$options['RTELargeHeightIncrement'] : 0);
324  $heightOverride = isset($backendUser->uc['rteHeight']) && (int)$backendUser->uc['rteHeight'] ?: (int)$this->processedRteConfiguration['RTEHeightOverride'];
325  $height = $heightOverride > 0 ? $heightOverride . 'px' : $height . 'px';
326  $paddingRight = '2';
327  $editorWrapWidth = '99%';
328  }
329  $rteDivStyle = 'position:relative; left:0px; top:0px; height:' . $height . '; width:' . $width . '; border: 1px solid black; padding: 2 ' . $paddingRight . ' 2 2;';
330 
331  $itemFormElementName = $this->data['parameterArray']['itemFormElName'];
332 
333  // This seems to result in:
334  // _TRANSFORM_bodytext (the handled field name) in case the field is a direct DB field
335  // _TRANSFORM_vDEF (constant string) in case the RTE is within a flex form
336  $triggerFieldName = preg_replace('/\\[([^]]+)\\]$/', '[_TRANSFORM_\\1]', $itemFormElementName);
337 
338  $value = $this->transformDatabaseContentToEditor($this->data['parameterArray']['itemFormElValue']);
339 
340  $result = array();
341  // The hidden field tells the DataHandler that processing should be done on this value.
342  $result[] = '<input type="hidden" name="' . htmlspecialchars($triggerFieldName) . '" value="RTE" />';
343  $result[] = '<div id="pleasewait' . $this->domIdentifier . '" class="pleasewait" style="display: block;" >';
344  $result[] = $this->getLanguageService()->sL('LLL:EXT:rtehtmlarea/Resources/Private/Language/locallang.xlf:Please wait');
345  $result[] = '</div>';
346  $result[] = '<div id="editorWrap' . $this->domIdentifier . '" class="editorWrap" style="visibility: hidden; width:' . $editorWrapWidth . '; height:100%;">';
347  $result[] = '<textarea id="RTEarea' . $this->domIdentifier . '" name="' . htmlspecialchars($itemFormElementName) . '" rows="0" cols="0" style="' . htmlspecialchars($rteDivStyle) . '">';
348  $result[] = htmlspecialchars($value);
349  $result[] = '</textarea>';
350  $result[] = '</div>';
351 
352  return implode(LF, $result);
353  }
354 
360  protected function enableRegisteredPlugins()
361  {
362  // Traverse registered plugins
363  if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['plugins'])) {
364  foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['plugins'] as $pluginId => $pluginObjectConfiguration) {
365  if (is_array($pluginObjectConfiguration) && isset($pluginObjectConfiguration['objectReference'])) {
367  $plugin = GeneralUtility::makeInstance($pluginObjectConfiguration['objectReference']);
368  $configuration = array(
369  'language' => $this->language,
370  'contentTypo3Language' => $this->contentTypo3Language,
371  'contentISOLanguage' => $this->contentISOLanguage,
372  'contentLanguageUid' => $this->contentLanguageUid,
373  'RTEsetup' => $this->vanillaRteTsConfig,
374  'client' => $this->client,
375  'thisConfig' => $this->processedRteConfiguration,
376  'specConf' => $this->defaultExtras,
377  );
378  if ($plugin->main($configuration)) {
379  $this->registeredPlugins[$pluginId] = $plugin;
380  // Override buttons from previously registered plugins
381  $pluginButtons = GeneralUtility::trimExplode(',', $plugin->getPluginButtons(), true);
382  foreach ($this->pluginButton as $previousPluginId => $buttonList) {
383  $this->pluginButton[$previousPluginId] = implode(',', array_diff(GeneralUtility::trimExplode(',', $this->pluginButton[$previousPluginId], true), $pluginButtons));
384  }
385  $this->pluginButton[$pluginId] = $plugin->getPluginButtons();
386  $pluginLabels = GeneralUtility::trimExplode(',', $plugin->getPluginLabels(), true);
387  foreach ($this->pluginLabel as $previousPluginId => $labelList) {
388  $this->pluginLabel[$previousPluginId] = implode(',', array_diff(GeneralUtility::trimExplode(',', $this->pluginLabel[$previousPluginId], true), $pluginLabels));
389  }
390  $this->pluginLabel[$pluginId] = $plugin->getPluginLabels();
391  $this->pluginEnabledArray[] = $pluginId;
392  }
393  }
394  }
395  }
396  // Process overrides
397  $hidePlugins = array();
398  foreach ($this->registeredPlugins as $pluginId => $plugin) {
400  if ($plugin->addsButtons() && !$this->pluginButton[$pluginId]) {
401  $hidePlugins[] = $pluginId;
402  }
403  }
404  $this->pluginEnabledArray = array_unique(array_diff($this->pluginEnabledArray, $hidePlugins));
405  }
406 
412  protected function setToolbar()
413  {
414  $backendUser = $this->getBackendUserAuthentication();
415 
416  if ($this->client['browser'] === 'msie' || $this->client['browser'] === 'opera') {
417  $this->processedRteConfiguration['keepButtonGroupTogether'] = 0;
418  }
419  $this->defaultToolbarOrder = 'bar, blockstylelabel, blockstyle, textstylelabel, textstyle, linebreak,
420  bar, formattext, bold, strong, italic, emphasis, big, small, insertedtext, deletedtext, citation, code,'
421  . 'definition, keyboard, monospaced, quotation, sample, variable, bidioverride, strikethrough, subscript, superscript, underline, span,
422  bar, fontstyle, fontsize, bar, formatblock, insertparagraphbefore, insertparagraphafter, blockquote, line,
423  bar, left, center, right, justifyfull,
424  bar, orderedlist, unorderedlist, definitionlist, definitionitem, outdent, indent,
425  bar, language, showlanguagemarks,lefttoright, righttoleft,
426  bar, textcolor, bgcolor, textindicator,
427  bar, editelement, showmicrodata,
428  bar, image, emoticon, insertcharacter, insertsofthyphen, abbreviation, user,
429  bar, link, unlink,
430  bar, table,'
431  . ($this->processedRteConfiguration['hideTableOperationsInToolbar']
432  && is_array($this->processedRteConfiguration['buttons.'])
433  && is_array($this->processedRteConfiguration['buttons.']['toggleborders.'])
434  && $this->processedRteConfiguration['buttons.']['toggleborders.']['keepInToolbar'] ? ' toggleborders,' : '')
435  . 'bar, findreplace, spellcheck,
436  bar, chMode, inserttag, removeformat, bar, copy, cut, paste, pastetoggle, pastebehaviour, bar, undo, redo, bar, about, linebreak,'
437  . ($this->processedRteConfiguration['hideTableOperationsInToolbar'] ? '' : 'bar, toggleborders,')
438  . ' bar, tableproperties, tablerestyle, bar, rowproperties, rowinsertabove, rowinsertunder, rowdelete, rowsplit, bar,
439  columnproperties, columninsertbefore, columninsertafter, columndelete, columnsplit, bar,
440  cellproperties, cellinsertbefore, cellinsertafter, celldelete, cellsplit, cellmerge';
441 
442  // Additional buttons from registered plugins
443  foreach ($this->registeredPlugins as $pluginId => $plugin) {
445  if ($this->isPluginEnabled($pluginId)) {
446  $pluginButtons = $plugin->getPluginButtons();
447  //Add only buttons not yet in the default toolbar order
448  $addButtons = implode(
449  ',',
450  array_diff(
451  GeneralUtility::trimExplode(',', $pluginButtons, true),
452  GeneralUtility::trimExplode(',', $this->defaultToolbarOrder, true)
453  )
454  );
455  $this->defaultToolbarOrder = ($addButtons ? 'bar,' . $addButtons . ',linebreak,' : '') . $this->defaultToolbarOrder;
456  }
457  }
458  $toolbarOrder = $this->processedRteConfiguration['toolbarOrder'] ?: $this->defaultToolbarOrder;
459  // Getting rid of undefined buttons
460  $this->toolbarOrderArray = array_intersect(GeneralUtility::trimExplode(',', $toolbarOrder, true), GeneralUtility::trimExplode(',', $this->defaultToolbarOrder, true));
461  $toolbarOrder = array_unique(array_values($this->toolbarOrderArray));
462  // Fetching specConf for field from backend
463  $pList = is_array($this->defaultExtras['richtext']['parameters']) ? implode(',', $this->defaultExtras['richtext']['parameters']) : '';
464  if ($pList !== '*') {
465  // If not all
466  $show = is_array($this->defaultExtras['richtext']['parameters']) ? $this->defaultExtras['richtext']['parameters'] : array();
467  if ($this->processedRteConfiguration['showButtons']) {
468  if (!GeneralUtility::inList($this->processedRteConfiguration['showButtons'], '*')) {
469  $show = array_unique(array_merge($show, GeneralUtility::trimExplode(',', $this->processedRteConfiguration['showButtons'], true)));
470  } else {
471  $show = array_unique(array_merge($show, $toolbarOrder));
472  }
473  }
474  if (is_array($this->processedRteConfiguration['showButtons.'])) {
475  foreach ($this->processedRteConfiguration['showButtons.'] as $buttonId => $value) {
476  if ($value) {
477  $show[] = $buttonId;
478  }
479  }
480  $show = array_unique($show);
481  }
482  } else {
483  $show = $toolbarOrder;
484  }
485  $RTEkeyList = isset($backendUser->userTS['options.']['RTEkeyList']) ? $backendUser->userTS['options.']['RTEkeyList'] : '*';
486  if ($RTEkeyList !== '*') {
487  // If not all
488  $show = array_intersect($show, GeneralUtility::trimExplode(',', $RTEkeyList, true));
489  }
490  // Hiding buttons of disabled plugins
491  $hideButtons = array('space', 'bar', 'linebreak');
492  foreach ($this->pluginButton as $pluginId => $buttonList) {
493  if (!$this->isPluginEnabled($pluginId)) {
494  $buttonArray = GeneralUtility::trimExplode(',', $buttonList, true);
495  foreach ($buttonArray as $button) {
496  $hideButtons[] = $button;
497  }
498  }
499  }
500  // Hiding labels of disabled plugins
501  foreach ($this->pluginLabel as $pluginId => $label) {
502  if (!$this->isPluginEnabled($pluginId)) {
503  $hideButtons[] = $label;
504  }
505  }
506  // Hiding buttons
507  $show = array_diff($show, GeneralUtility::trimExplode(',', $this->processedRteConfiguration['hideButtons'], true));
508  // Apply toolbar constraints from registered plugins
509  foreach ($this->registeredPlugins as $pluginId => $plugin) {
510  if ($this->isPluginEnabled($pluginId) && method_exists($plugin, 'applyToolbarConstraints')) {
511  $show = $plugin->applyToolbarConstraints($show);
512  }
513  }
514  // Getting rid of the buttons for which we have no position
515  $show = array_intersect($show, $toolbarOrder);
516  foreach ($this->registeredPlugins as $pluginId => $plugin) {
518  $plugin->setToolbar($show);
519  }
520  $this->toolbar = $show;
521  }
522 
528  protected function setPlugins()
529  {
530  // Disabling a plugin that adds buttons if none of its buttons is in the toolbar
531  $hidePlugins = array();
532  foreach ($this->pluginButton as $pluginId => $buttonList) {
534  $plugin = $this->registeredPlugins[$pluginId];
535  if ($plugin->addsButtons()) {
536  $showPlugin = false;
537  $buttonArray = GeneralUtility::trimExplode(',', $buttonList, true);
538  foreach ($buttonArray as $button) {
539  if (in_array($button, $this->toolbar)) {
540  $showPlugin = true;
541  }
542  }
543  if (!$showPlugin) {
544  $hidePlugins[] = $pluginId;
545  }
546  }
547  }
548  $this->pluginEnabledArray = array_diff($this->pluginEnabledArray, $hidePlugins);
549  // Hiding labels of disabled plugins
550  $hideLabels = array();
551  foreach ($this->pluginLabel as $pluginId => $label) {
552  if (!$this->isPluginEnabled($pluginId)) {
553  $hideLabels[] = $label;
554  }
555  }
556  $this->toolbar = array_diff($this->toolbar, $hideLabels);
557  // Adding plugins declared as prerequisites by enabled plugins
558  $requiredPlugins = array();
559  foreach ($this->registeredPlugins as $pluginId => $plugin) {
561  if ($this->isPluginEnabled($pluginId)) {
562  $requiredPlugins = array_merge($requiredPlugins, GeneralUtility::trimExplode(',', $plugin->getRequiredPlugins(), true));
563  }
564  }
565  $requiredPlugins = array_unique($requiredPlugins);
566  foreach ($requiredPlugins as $pluginId) {
567  if (is_object($this->registeredPlugins[$pluginId]) && !$this->isPluginEnabled($pluginId)) {
568  $this->pluginEnabledArray[] = $pluginId;
569  }
570  }
571  $this->pluginEnabledArray = array_unique($this->pluginEnabledArray);
572  // Completing the toolbar conversion array for htmlArea
573  foreach ($this->registeredPlugins as $pluginId => $plugin) {
575  if ($this->isPluginEnabled($pluginId)) {
576  $this->convertToolbarForHtmlAreaArray = array_unique(array_merge($this->convertToolbarForHtmlAreaArray, $plugin->getConvertToolbarForHtmlAreaArray()));
577  }
578  }
579  }
580 
586  protected function loadRequireModulesForRTE()
587  {
588  $this->resultArray['requireJsModules'] = array();
589  $this->resultArray['requireJsModules'][] = 'TYPO3/CMS/Rtehtmlarea/HTMLArea/HTMLArea';
590  foreach ($this->pluginEnabledCumulativeArray as $pluginId) {
592  $plugin = $this->registeredPlugins[$pluginId];
593  $extensionKey = is_object($plugin) ? $plugin->getExtensionKey() : 'rtehtmlarea';
594  $requirePath = 'TYPO3/CMS/' . GeneralUtility::underscoredToUpperCamelCase($extensionKey);
595  $this->resultArray['requireJsModules'][] = $requirePath . '/Plugins/' . $pluginId;
596  }
597  }
598 
604  protected function getRteInitJsCode()
605  {
606  $skinFilename = trim($this->processedRteConfiguration['skin']) ?: 'EXT:rtehtmlarea/Resources/Public/Css/Skin/htmlarea.css';
607  $skinFilename = $this->getFullFileName($skinFilename);
608  $skinDirectory = dirname($skinFilename);
609  // Editing area style sheet
610  $editedContentCSS = GeneralUtility::createVersionNumberedFilename($skinDirectory . '/htmlarea-edited-content.css');
611 
612  return 'require(["TYPO3/CMS/Rtehtmlarea/HTMLArea/HTMLArea"], function (HTMLArea) {
613  if (typeof RTEarea === "undefined") {
614  RTEarea = new Object();
615  RTEarea[0] = new Object();
616  RTEarea[0].version = "' . $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['version'] . '";
617  RTEarea[0].editorUrl = "' . ExtensionManagementUtility::extRelPath('rtehtmlarea') . '";
618  RTEarea[0].editorSkin = "' . $skinDirectory . '/";
619  RTEarea[0].editedContentCSS = "' . $editedContentCSS . '";
620  RTEarea.init = function() {
621  if (typeof HTMLArea === "undefined" || !Ext.isReady) {
622  window.setTimeout(function () {
623  RTEarea.init();
624  }, 10);
625  } else {
626  HTMLArea.init();
627  }
628  };
629  RTEarea.initEditor = function(editorNumber) {
630  if (typeof HTMLArea === "undefined" || !HTMLArea.isReady) {
631  window.setTimeout(function () {
632  RTEarea.initEditor(editorNumber);
633  }, 40);
634  } else {
635  HTMLArea.initEditor(editorNumber);
636  }
637  };
638  }
639  RTEarea.init();
640  });';
641  }
642 
648  protected function addInstanceJavaScriptRegistration()
649  {
650  $backendUser = $this->getBackendUserAuthentication();
651 
652  $jsArray = array();
653  $jsArray[] = 'if (typeof configureEditorInstance === "undefined") {';
654  $jsArray[] = ' configureEditorInstance = new Object();';
655  $jsArray[] = '}';
656  $jsArray[] = 'configureEditorInstance["' . $this->domIdentifier . '"] = function() {';
657  $jsArray[] = 'if (typeof RTEarea === "undefined" || typeof HTMLArea === "undefined") {';
658  $jsArray[] = ' window.setTimeout("configureEditorInstance[\'' . $this->domIdentifier . '\']();", 40);';
659  $jsArray[] = '} else {';
660  $jsArray[] = 'editornumber = "' . $this->domIdentifier . '";';
661  $jsArray[] = 'RTEarea[editornumber] = new Object();';
662  $jsArray[] = 'RTEarea[editornumber].RTEtsConfigParams = "&RTEtsConfigParams=' . rawurlencode($this->RTEtsConfigParams()) . '";';
663  $jsArray[] = 'RTEarea[editornumber].number = editornumber;';
664  $jsArray[] = 'RTEarea[editornumber].deleted = false;';
665  $jsArray[] = 'RTEarea[editornumber].textAreaId = "' . $this->domIdentifier . '";';
666  $jsArray[] = 'RTEarea[editornumber].id = "RTEarea" + editornumber;';
667  $jsArray[] = 'RTEarea[editornumber].RTEWidthOverride = "'
668  . (isset($backendUser->uc['rteWidth']) && trim($backendUser->uc['rteWidth'])
669  ? trim($backendUser->uc['rteWidth'])
670  : trim($this->processedRteConfiguration['RTEWidthOverride'])) . '";';
671  $jsArray[] = 'RTEarea[editornumber].RTEHeightOverride = "'
672  . (isset($backendUser->uc['rteHeight']) && (int)$backendUser->uc['rteHeight']
673  ? (int)$backendUser->uc['rteHeight']
674  : (int)$this->processedRteConfiguration['RTEHeightOverride']) . '";';
675  $jsArray[] = 'RTEarea[editornumber].resizable = '
676  . (isset($backendUser->uc['rteResize']) && $backendUser->uc['rteResize']
677  ? 'true;'
678  : (trim($this->processedRteConfiguration['rteResize']) ? 'true;' : 'false;'));
679  $jsArray[] = 'RTEarea[editornumber].maxHeight = "'
680  . (isset($backendUser->uc['rteMaxHeight']) && (int)$backendUser->uc['rteMaxHeight']
681  ? trim($backendUser->uc['rteMaxHeight'])
682  : ((int)$this->processedRteConfiguration['rteMaxHeight'] ?: '2000')) . '";';
683  $jsArray[] = 'RTEarea[editornumber].fullScreen = ' . ($this->isInFullScreenMode() ? 'true;' : 'false;');
684  $jsArray[] = 'RTEarea[editornumber].showStatusBar = ' . (trim($this->processedRteConfiguration['showStatusBar']) ? 'true;' : 'false;');
685  $jsArray[] = 'RTEarea[editornumber].enableWordClean = ' . (trim($this->processedRteConfiguration['enableWordClean']) ? 'true;' : 'false;');
686  $jsArray[] = 'RTEarea[editornumber].htmlRemoveComments = ' . (trim($this->processedRteConfiguration['removeComments']) ? 'true;' : 'false;');
687  $jsArray[] = 'RTEarea[editornumber].disableEnterParagraphs = ' . (trim($this->processedRteConfiguration['disableEnterParagraphs']) ? 'true;' : 'false;');
688  $jsArray[] = 'RTEarea[editornumber].disableObjectResizing = ' . (trim($this->processedRteConfiguration['disableObjectResizing']) ? 'true;' : 'false;');
689  $jsArray[] = 'RTEarea[editornumber].removeTrailingBR = ' . (trim($this->processedRteConfiguration['removeTrailingBR']) ? 'true;' : 'false;');
690  $jsArray[] = 'RTEarea[editornumber].useCSS = ' . (trim($this->processedRteConfiguration['useCSS']) ? 'true' : 'false') . ';';
691  $jsArray[] = 'RTEarea[editornumber].keepButtonGroupTogether = ' . (trim($this->processedRteConfiguration['keepButtonGroupTogether']) ? 'true;' : 'false;');
692  $jsArray[] = 'RTEarea[editornumber].disablePCexamples = ' . (trim($this->processedRteConfiguration['disablePCexamples']) ? 'true;' : 'false;');
693  $jsArray[] = 'RTEarea[editornumber].showTagFreeClasses = ' . (trim($this->processedRteConfiguration['showTagFreeClasses']) ? 'true;' : 'false;');
694  $jsArray[] = 'RTEarea[editornumber].tceformsNested = ' . (!empty($this->data) ? json_encode($this->data['tabAndInlineStack']) : '[]') . ';';
695  $jsArray[] = 'RTEarea[editornumber].dialogueWindows = new Object();';
696  if (isset($this->processedRteConfiguration['dialogueWindows.']['defaultPositionFromTop'])) {
697  $jsArray[] = 'RTEarea[editornumber].dialogueWindows.positionFromTop = ' . (int)$this->processedRteConfiguration['dialogueWindows.']['defaultPositionFromTop'] . ';';
698  }
699  if (isset($this->processedRteConfiguration['dialogueWindows.']['defaultPositionFromLeft'])) {
700  $jsArray[] = 'RTEarea[editornumber].dialogueWindows.positionFromLeft = ' . (int)$this->processedRteConfiguration['dialogueWindows.']['defaultPositionFromLeft'] . ';';
701  }
702  $jsArray[] = 'RTEarea[editornumber].sys_language_content = "' . $this->contentLanguageUid . '";';
703  $jsArray[] = 'RTEarea[editornumber].typo3ContentLanguage = "' . $this->contentTypo3Language . '";';
704  $jsArray[] = 'RTEarea[editornumber].userUid = "' . 'BE_' . $backendUser->user['uid'] . '";';
705 
706  // Setting the plugin flags
707  $jsArray[] = 'RTEarea[editornumber].plugin = new Object();';
708  foreach ($this->pluginEnabledArray as $pluginId) {
709  $jsArray[] = 'RTEarea[editornumber].plugin.' . $pluginId . ' = true;';
710  }
711 
712  // Setting the buttons configuration
713  $jsArray[] = 'RTEarea[editornumber].buttons = new Object();';
714  if (is_array($this->processedRteConfiguration['buttons.'])) {
715  foreach ($this->processedRteConfiguration['buttons.'] as $buttonIndex => $conf) {
716  $button = substr($buttonIndex, 0, -1);
717  if (is_array($conf)) {
718  $jsArray[] = 'RTEarea[editornumber].buttons.' . $button . ' = ' . $this->buildNestedJSArray($conf) . ';';
719  }
720  }
721  }
722 
723  // Setting the list of tags to be removed if specified in the RTE config
724  if (trim($this->processedRteConfiguration['removeTags'])) {
725  $jsArray[] = 'RTEarea[editornumber].htmlRemoveTags = /^(' . implode('|', GeneralUtility::trimExplode(',', $this->processedRteConfiguration['removeTags'], true)) . ')$/i;';
726  }
727 
728  // Setting the list of tags to be removed with their contents if specified in the RTE config
729  if (trim($this->processedRteConfiguration['removeTagsAndContents'])) {
730  $jsArray[] = 'RTEarea[editornumber].htmlRemoveTagsAndContents = /^(' . implode('|', GeneralUtility::trimExplode(',', $this->processedRteConfiguration['removeTagsAndContents'], true)) . ')$/i;';
731  }
732 
733  // Setting array of custom tags if specified in the RTE config
734  if (!empty($this->processedRteConfiguration['customTags'])) {
735  $customTags = GeneralUtility::trimExplode(',', $this->processedRteConfiguration['customTags'], true);
736  if (!empty($customTags)) {
737  $jsArray[] = 'RTEarea[editornumber].customTags= ' . json_encode($customTags) . ';';
738  }
739  }
740 
741  // Setting array of content css files if specified in the RTE config
742  $versionNumberedFileNames = array();
743  $contentCssFileNames = $this->getContentCssFileNames();
744  foreach ($contentCssFileNames as $contentCssFileName) {
745  $versionNumberedFileNames[] = GeneralUtility::createVersionNumberedFilename($contentCssFileName);
746  }
747  $jsArray[] = 'RTEarea[editornumber].pageStyle = ["' . implode('","', $versionNumberedFileNames) . '"];';
748 
749  $jsArray[] = 'RTEarea[editornumber].classesUrl = "' . $this->writeTemporaryFile(('classes_' . $this->language), 'js', $this->buildJSClassesArray()) . '";';
750 
751  // Add Javascript configuration for registered plugins
752  foreach ($this->registeredPlugins as $pluginId => $plugin) {
754  if ($this->isPluginEnabled($pluginId)) {
755  $jsPluginString = $plugin->buildJavascriptConfiguration();
756  if ($jsPluginString) {
757  $jsArray[] = $plugin->buildJavascriptConfiguration();
758  }
759  }
760  }
761 
762  // Avoid premature reference to HTMLArea when being initially loaded by IRRE Ajax call
763  $jsArray[] = 'RTEarea[editornumber].toolbar = ' . $this->getJSToolbarArray() . ';';
764  $jsArray[] = 'RTEarea[editornumber].convertButtonId = ' . json_encode(array_flip($this->convertToolbarForHtmlAreaArray)) . ';';
765  $jsArray[] = 'RTEarea.initEditor(editornumber);';
766  $jsArray[] = '}';
767  $jsArray[] = '}';
768  $jsArray[] = 'configureEditorInstance["' . $this->domIdentifier . '"]();';
769 
770  $this->resultArray['additionalJavaScriptPost'][] = implode(LF, $jsArray);
771  }
772 
778  protected function getContentCssFileNames()
779  {
780  $contentCss = is_array($this->processedRteConfiguration['contentCSS.']) ? $this->processedRteConfiguration['contentCSS.'] : array();
781  if (isset($this->processedRteConfiguration['contentCSS'])) {
782  $contentCss[] = trim($this->processedRteConfiguration['contentCSS']);
783  }
784  $contentCssFiles = array();
785  if (!empty($contentCss)) {
786  foreach ($contentCss as $contentCssKey => $contentCssfile) {
787  $fileName = trim($contentCssfile);
788  $absolutePath = GeneralUtility::getFileAbsFileName($fileName);
789  if (file_exists($absolutePath) && filesize($absolutePath)) {
790  $contentCssFiles[$contentCssKey] = $this->getFullFileName($fileName);
791  }
792  }
793  } else {
794  // Fallback to default content css file if none of the configured files exists and is not empty
795  $contentCssFiles['default'] = $this->getFullFileName('EXT:rtehtmlarea/Resources/Public/Css/ContentCss/Default.css');
796  }
797  return array_unique($contentCssFiles);
798  }
799 
806  protected function isPluginEnabled($pluginId)
807  {
808  return in_array($pluginId, $this->pluginEnabledArray);
809  }
810 
816  protected function buildJSClassesArray()
817  {
818  $RTEProperties = $this->vanillaRteTsConfig['properties'];
819  // Declare sub-arrays
820  $classesArray = array(
821  'labels' => array(),
822  'values' => array(),
823  'noShow' => array(),
824  'alternating' => array(),
825  'counting' => array(),
826  'selectable' => array(),
827  'requires' => array(),
828  'requiredBy' => array(),
829  'XOR' => array()
830  );
831  $JSClassesArray = '';
832  // Scanning the list of classes if specified in the RTE config
833  if (is_array($RTEProperties['classes.'])) {
834  foreach ($RTEProperties['classes.'] as $className => $conf) {
835  $className = rtrim($className, '.');
836 
837  $label = '';
838  if (!empty($conf['name'])) {
839  $label = $this->getLanguageService()->sL(trim($conf['name']));
840  $label = str_replace('"', '\\"', str_replace('\\\'', '\'', $label));
841  }
842  $classesArray['labels'][$className] = $label;
843  $classesArray['values'][$className] = str_replace('\\\'', '\'', $conf['value']);
844  if (isset($conf['noShow'])) {
845  $classesArray['noShow'][$className] = $conf['noShow'];
846  }
847  if (is_array($conf['alternating.'])) {
848  $classesArray['alternating'][$className] = $conf['alternating.'];
849  }
850  if (is_array($conf['counting.'])) {
851  $classesArray['counting'][$className] = $conf['counting.'];
852  }
853  if (isset($conf['selectable'])) {
854  $classesArray['selectable'][$className] = $conf['selectable'];
855  }
856  if (isset($conf['requires'])) {
857  $classesArray['requires'][$className] = explode(',', GeneralUtility::rmFromList($className, $this->cleanList($conf['requires'])));
858  }
859  }
860  // Remove circularities from classes dependencies
861  $requiringClasses = array_keys($classesArray['requires']);
862  foreach ($requiringClasses as $requiringClass) {
863  if ($this->hasCircularDependency($classesArray, $requiringClass, $requiringClass)) {
864  unset($classesArray['requires'][$requiringClass]);
865  }
866  }
867  // Reverse relationship for the dependency checks when removing styles
868  $requiringClasses = array_keys($classesArray['requires']);
869  foreach ($requiringClasses as $className) {
870  foreach ($classesArray['requires'][$className] as $requiredClass) {
871  if (!is_array($classesArray['requiredBy'][$requiredClass])) {
872  $classesArray['requiredBy'][$requiredClass] = array();
873  }
874  if (!in_array($className, $classesArray['requiredBy'][$requiredClass])) {
875  $classesArray['requiredBy'][$requiredClass][] = $className;
876  }
877  }
878  }
879  }
880  // Scanning the list of sets of mutually exclusives classes if specified in the RTE config
881  if (is_array($RTEProperties['mutuallyExclusiveClasses.'])) {
882  foreach ($RTEProperties['mutuallyExclusiveClasses.'] as $listName => $conf) {
883  $classSet = GeneralUtility::trimExplode(',', $conf, true);
884  $classList = implode(',', $classSet);
885  foreach ($classSet as $className) {
886  $classesArray['XOR'][$className] = '/^(' . implode('|', GeneralUtility::trimExplode(',', GeneralUtility::rmFromList($className, $classList), true)) . ')$/';
887  }
888  }
889  }
890  foreach ($classesArray as $key => $subArray) {
891  $JSClassesArray .= 'HTMLArea.classes' . ucfirst($key) . ' = ' . $this->buildNestedJSArray($subArray) . ';' . LF;
892  }
893  return $JSClassesArray;
894  }
895 
905  protected function hasCircularDependency(&$classesArray, $requiringClass, $initialClass, $recursionLevel = 0)
906  {
907  if (is_array($classesArray['requires'][$requiringClass])) {
908  if (in_array($initialClass, $classesArray['requires'][$requiringClass])) {
909  return true;
910  } else {
911  if ($recursionLevel++ < 20) {
912  foreach ($classesArray['requires'][$requiringClass] as $requiringClass2) {
913  if ($this->hasCircularDependency($classesArray, $requiringClass2, $initialClass, $recursionLevel)) {
914  return true;
915  }
916  }
917  }
918  return false;
919  }
920  } else {
921  return false;
922  }
923  }
924 
934  protected function buildNestedJSArray($conf)
935  {
936  $convertedConf = GeneralUtility::removeDotsFromTS($conf);
937  return str_replace(
938  array(':"0"', ':"\\/^(', ')$\\/i"', ':"\\/^(', ')$\\/"', '[]'),
939  array(':false', ':/^(', ')$/i', ':/^(', ')$/', '{}'), json_encode($convertedConf)
940  );
941  }
942 
952  protected function writeTemporaryFile($label, $fileExtension = 'js', $contents = '')
953  {
954  $relativeFilename = 'typo3temp/RteHtmlArea/' . str_replace('-', '_', $label) . '_' . GeneralUtility::shortMD5($contents, 20) . '.' . $fileExtension;
955  $destination = PATH_site . $relativeFilename;
956  if (!file_exists($destination)) {
957  $minifiedJavaScript = '';
958  if ($fileExtension === 'js' && $contents !== '') {
959  $minifiedJavaScript = GeneralUtility::minifyJavaScript($contents);
960  }
961  $failure = GeneralUtility::writeFileToTypo3tempDir($destination, $minifiedJavaScript ? $minifiedJavaScript : $contents);
962  if ($failure) {
963  throw new \RuntimeException($failure, 1294585668);
964  }
965  }
966  if (isset($GLOBALS['TSFE'])) {
967  $fileName = $relativeFilename;
968  } else {
969  $fileName = '../' . $relativeFilename;
970  }
971  return GeneralUtility::resolveBackPath($fileName);
972  }
973 
981  protected function createJavaScriptLanguageLabelsFromFiles()
982  {
983  $labelArray = array();
984  // Load labels of 3 base files into JS
985  foreach (array('tooltips', 'msg', 'dialogs') as $identifier) {
986  $fileName = 'EXT:rtehtmlarea/Resources/Private/Language/locallang_' . $identifier . '.xlf';
987  $newLabels = $this->getMergedLabelsFromFile($fileName);
988  if (!empty($newLabels)) {
989  $labelArray[$identifier] = $newLabels;
990  }
991  }
992  // Load labels of plugins into JS
993  foreach ($this->pluginEnabledCumulativeArray as $pluginId) {
995  $plugin = $this->registeredPlugins[$pluginId];
996  $extensionKey = is_object($plugin) ? $plugin->getExtensionKey() : 'rtehtmlarea';
997  $fileName = 'EXT:' . $extensionKey . '/Resources/Private/Language/Plugins/' . $pluginId . '/locallang_js.xlf';
998  $newLabels = $this->getMergedLabelsFromFile($fileName);
999  if (!empty($newLabels)) {
1000  $labelArray[$pluginId] = $newLabels;
1001  }
1002  }
1003  $javaScriptString = 'TYPO3.jQuery(function() {';
1004  $javaScriptString .= 'HTMLArea.I18N = new Object();' . LF;
1005  $javaScriptString .= 'HTMLArea.I18N = ' . json_encode($labelArray);
1006  $javaScriptString .= '});';
1007  $this->resultArray['additionalJavaScriptPost'][] = $javaScriptString;
1008  }
1009 
1017  protected function getMergedLabelsFromFile($fileName)
1018  {
1020  $languageFactory = GeneralUtility::makeInstance(LocalizationFactory::class);
1021  $localizationArray = $languageFactory->getParsedData($fileName, $this->language, 'utf-8', 1);
1022  if (is_array($localizationArray) && !empty($localizationArray)) {
1023  if (!empty($localizationArray[$this->language])) {
1024  $finalLocalLang = $localizationArray['default'];
1025  ArrayUtility::mergeRecursiveWithOverrule($finalLocalLang, $localizationArray[$this->language], true, false);
1026  $localizationArray[$this->language] = $finalLocalLang;
1027  } else {
1028  $localizationArray[$this->language] = $localizationArray['default'];
1029  }
1030  } else {
1031  $localizationArray = array();
1032  }
1033  return $localizationArray[$this->language];
1034  }
1035 
1041  protected function getJSToolbarArray()
1042  {
1043  // The toolbar array
1044  $toolbar = array();
1045  // The current row; a "linebreak" ends the current row
1046  $row = array();
1047  // The current group; each group is between "bar"s; a "linebreak" ends the current group
1048  $group = array();
1049  // Process each toolbar item in the toolbar order list
1050  foreach ($this->toolbarOrderArray as $item) {
1051  switch ($item) {
1052  case 'linebreak':
1053  // Add row to toolbar if not empty
1054  if (!empty($group)) {
1055  $row[] = $group;
1056  $group = array();
1057  }
1058  if (!empty($row)) {
1059  $toolbar[] = $row;
1060  $row = array();
1061  }
1062  break;
1063  case 'bar':
1064  // Add group to row if not empty
1065  if (!empty($group)) {
1066  $row[] = $group;
1067  $group = array();
1068  }
1069  break;
1070  case 'space':
1071  if (end($group) != $this->convertToolbarForHtmlAreaArray[$item]) {
1072  $group[] = $this->convertToolbarForHtmlAreaArray[$item];
1073  }
1074  break;
1075  default:
1076  if (in_array($item, $this->toolbar)) {
1077  // Add the item to the group
1078  $convertedItem = $this->convertToolbarForHtmlAreaArray[$item];
1079  if ($convertedItem) {
1080  $group[] = $convertedItem;
1081  }
1082  }
1083  }
1084  }
1085  // Add the last group and last line, if not empty
1086  if (!empty($group)) {
1087  $row[] = $group;
1088  }
1089  if (!empty($row)) {
1090  $toolbar[] = $row;
1091  }
1092  return json_encode($toolbar);
1093  }
1094 
1101  protected function getFullFileName($filename)
1102  {
1103  if (substr($filename, 0, 4) === 'EXT:') {
1104  // extension
1105  list($extKey, $local) = explode('/', substr($filename, 4), 2);
1106  $newFilename = '';
1107  if ((string)$extKey !== '' && ExtensionManagementUtility::isLoaded($extKey) && (string)$local !== '') {
1108  $newFilename = ($this->isFrontendEditActive()
1109  ? ExtensionManagementUtility::siteRelPath($extKey)
1110  : ExtensionManagementUtility::extRelPath($extKey))
1111  . $local;
1112  }
1113  } else {
1114  $path = ($this->isFrontendEditActive() ? '' : '../');
1115  $newFilename = $path . ($filename[0] === '/' ? substr($filename, 1) : $filename);
1116  }
1117  return GeneralUtility::resolveBackPath($newFilename);
1118  }
1119 
1125  protected function addOnSubmitJavaScriptCode()
1126  {
1127  $onSubmitCode = array();
1128  $onSubmitCode[] = 'if (RTEarea["' . $this->domIdentifier . '"]) {';
1129  $onSubmitCode[] = 'document.editform["' . $this->data['parameterArray']['itemFormElName'] . '"].value = RTEarea["' . $this->domIdentifier . '"].editor.getHTML();';
1130  $onSubmitCode[] = '} else {';
1131  $onSubmitCode[] = 'OK = 0;';
1132  $onSubmitCode[] = '};';
1133  $this->resultArray['additionalJavaScriptSubmit'][] = implode(LF, $onSubmitCode);
1134  }
1135 
1141  protected function isFrontendEditActive()
1142  {
1143  return is_object($GLOBALS['TSFE']) && $GLOBALS['TSFE']->beUserLogin && $GLOBALS['BE_USER']->frontendEdit instanceof FrontendEditingController;
1144  }
1145 
1151  protected function clientInfo()
1152  {
1153  $userAgent = GeneralUtility::getIndpEnv('HTTP_USER_AGENT');
1154  $browserInfo = ClientUtility::getBrowserInfo($userAgent);
1155  // Known engines: order is not irrelevant!
1156  $knownEngines = array('opera', 'msie', 'gecko', 'webkit');
1157  if (is_array($browserInfo['all'])) {
1158  foreach ($knownEngines as $engine) {
1159  if ($browserInfo['all'][$engine]) {
1160  $browserInfo['browser'] = $engine;
1161  $browserInfo['version'] = ClientUtility::getVersion($browserInfo['all'][$engine]);
1162  break;
1163  }
1164  }
1165  }
1166  return $browserInfo;
1167  }
1168 
1174  public function initializeLanguageRelatedProperties()
1175  {
1176  $database = $this->getDatabaseConnection();
1177  $this->language = $GLOBALS['LANG']->lang;
1178  if ($this->language === 'default' || !$this->language) {
1179  $this->language = 'en';
1180  }
1181  $currentLanguageUid = $this->data['databaseRow']['sys_language_uid'];
1182  if (is_array($currentLanguageUid)) {
1183  $currentLanguageUid = $currentLanguageUid[0];
1184  }
1185  $this->contentLanguageUid = (int)max($currentLanguageUid, 0);
1186  if ($this->contentLanguageUid) {
1187  $this->contentISOLanguage = $this->language;
1188  if (ExtensionManagementUtility::isLoaded('static_info_tables')) {
1189  $tableA = 'sys_language';
1190  $tableB = 'static_languages';
1191  $selectFields = $tableA . '.uid,' . $tableB . '.lg_iso_2,' . $tableB . '.lg_country_iso_2';
1192  $tableAB = $tableA . ' LEFT JOIN ' . $tableB . ' ON ' . $tableA . '.static_lang_isocode=' . $tableB . '.uid';
1193  $whereClause = $tableA . '.uid = ' . intval($this->contentLanguageUid);
1194  $whereClause .= BackendUtility::BEenableFields($tableA);
1195  $whereClause .= BackendUtility::deleteClause($tableA);
1196  $res = $database->exec_SELECTquery($selectFields, $tableAB, $whereClause);
1197  while ($languageRow = $database->sql_fetch_assoc($res)) {
1198  $this->contentISOLanguage = strtolower(trim($languageRow['lg_iso_2']) . (trim($languageRow['lg_country_iso_2']) ? '_' . trim($languageRow['lg_country_iso_2']) : ''));
1199  }
1200  $database->sql_free_result($res);
1201  }
1202  } else {
1203  $this->contentISOLanguage = trim($this->processedRteConfiguration['defaultContentLanguage']) ?: 'en';
1204  $languageCodeParts = explode('_', $this->contentISOLanguage);
1205  $this->contentISOLanguage = strtolower($languageCodeParts[0]) . ($languageCodeParts[1] ? '_' . strtoupper($languageCodeParts[1]) : '');
1206  // Find the configured language in the list of localization locales
1208  $locales = GeneralUtility::makeInstance(Locales::class);
1209  // If not found, default to 'en'
1210  if (!in_array($this->contentISOLanguage, $locales->getLocales())) {
1211  $this->contentISOLanguage = 'en';
1212  }
1213  }
1214  $this->contentTypo3Language = $this->contentISOLanguage === 'en' ? 'default' : $this->contentISOLanguage;
1215  }
1216 
1225  protected function logDeprecatedProperty($deprecatedProperty, $useProperty, $version)
1226  {
1227  $backendUser = $this->getBackendUserAuthentication();
1228  if (!$this->processedRteConfiguration['logDeprecatedProperties.']['disabled']) {
1229  $message = sprintf(
1230  'RTE Page TSConfig property "%1$s" used on page id #%4$s is DEPRECATED and will be removed in TYPO3 %3$s. Use "%2$s" instead.',
1231  $deprecatedProperty,
1232  $useProperty,
1233  $version,
1234  $this->data['databaseRow']['pid']
1235  );
1236  GeneralUtility::deprecationLog($message);
1237  if ($this->processedRteConfiguration['logDeprecatedProperties.']['logAlsoToBELog']) {
1238  $message = sprintf(
1239  $this->getLanguageService()->sL('LLL:EXT:rtehtmlarea/Resources/Private/Language/locallang.xlf:deprecatedPropertyMessage'),
1240  $deprecatedProperty,
1241  $useProperty,
1242  $version,
1243  $this->data['databaseRow']['pid']
1244  );
1245  $backendUser->simplelog($message, 'rtehtmlarea');
1246  }
1247  }
1248  }
1249 
1255  protected function RTEtsConfigParams()
1256  {
1257  $parameters = BackendUtility::getSpecConfParametersFromArray($this->defaultExtras['rte_transform']['parameters']);
1258  $result = array(
1259  $this->data['tableName'],
1260  $this->data['databaseRow']['uid'],
1261  $this->data['fieldName'],
1262  $this->pidOfVersionedMotherRecord,
1263  $this->data['recordTypeValue'],
1264  $this->pidOfPageRecord,
1265  $parameters['imgpath'],
1266  );
1267  return implode(':', $result);
1268  }
1269 
1276  protected function cleanList($str)
1277  {
1278  if (strstr($str, '*')) {
1279  $str = '*';
1280  } else {
1281  $str = implode(',', array_unique(GeneralUtility::trimExplode(',', $str, true)));
1282  }
1283  return $str;
1284  }
1285 
1292  protected function transformDatabaseContentToEditor($value)
1293  {
1294  // change <strong> to <b>
1295  $value = preg_replace('/<(\\/?)strong/i', '<$1b', $value);
1296  // change <em> to <i>
1297  $value = preg_replace('/<(\\/?)em([^b>]*>)/i', '<$1i$2', $value);
1298 
1299  if ($this->defaultExtras['rte_transform']) {
1300  $parameters = BackendUtility::getSpecConfParametersFromArray($this->defaultExtras['rte_transform']['parameters']);
1301  // There must be a mode set for transformation
1302  if ($parameters['mode']) {
1304  $parseHTML = GeneralUtility::makeInstance(RteHtmlParser::class);
1305  $parseHTML->init($this->data['table'] . ':' . $this->data['fieldName'], $this->pidOfVersionedMotherRecord);
1306  $parseHTML->setRelPath('');
1307  $value = $parseHTML->RTE_transform($value, $this->defaultExtras, 'rte', $this->processedRteConfiguration);
1308  }
1309  }
1310  return $value;
1311  }
1312 
1318  protected function isInFullScreenMode()
1319  {
1320  return GeneralUtility::_GP('M') === 'wizard_rte';
1321  }
1322 
1326  protected function getLanguageService()
1327  {
1328  return $GLOBALS['LANG'];
1329  }
1330 
1334  protected function getBackendUserAuthentication()
1335  {
1336  return $GLOBALS['BE_USER'];
1337  }
1338 
1342  protected function getDatabaseConnection()
1343  {
1344  return $GLOBALS['TYPO3_DB'];
1345  }
1346 }