f6652ab4363e085a789e8e06271d0d5081acd2fe
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / Classes / RteHtmlAreaBase.php
1 <?php
2 namespace TYPO3\CMS\Rtehtmlarea;
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
17 use TYPO3\CMS\Backend\Form\FormEngine;
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Backend\Form\InlineStackProcessor;
22 use TYPO3\CMS\Core\Database\DatabaseConnection;
23 use TYPO3\CMS\Lang\LanguageService;
24 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
25 use TYPO3\CMS\Core\Page\PageRenderer;
26
27 /**
28 * A RTE using the htmlArea editor
29 *
30 * @author Philipp Borgmann <philipp.borgmann@gmx.de>
31 * @author Stanislas Rolland <typo3(arobas)sjbr.ca>
32 */
33 class RteHtmlAreaBase extends \TYPO3\CMS\Backend\Rte\AbstractRte {
34
35 // Configuration of supported browsers
36 /**
37 * @var array
38 */
39 public $conf_supported_browser = array(
40 'msie' => array(
41 array(
42 'version' => 9.0,
43 'system' => array(
44 'allowed' => array(
45 'winNT',
46 'win98',
47 'win95'
48 )
49 )
50 )
51 ),
52 'gecko' => array(
53 array(
54 'version' => 1.8
55 )
56 ),
57 'webkit' => array(
58 array(
59 'version' => 534
60 ),
61 array(
62 'version' => 523,
63 'system' => array(
64 'disallowed' => array(
65 'iOS',
66 'android'
67 )
68 )
69 )
70 ),
71 'opera' => array(
72 array(
73 'version' => 9.62,
74 'system' => array(
75 'disallowed' => array(
76 'iOS',
77 'android'
78 )
79 )
80 )
81 )
82 );
83
84 // Always hide these toolbar buttons (TYPO3 button name)
85 /**
86 * @var array
87 */
88 public $conf_toolbar_hide = array(
89 'showhelp'
90 );
91
92 // The order of the toolbar: the name is the TYPO3-button name
93 /**
94 * @var string
95 */
96 public $defaultToolbarOrder;
97
98 // Conversion array: TYPO3 button names to htmlArea button names
99 /**
100 * @var array
101 */
102 public $convertToolbarForHtmlAreaArray = array(
103 'showhelp' => 'ShowHelp',
104 'space' => 'space',
105 'bar' => 'separator',
106 'linebreak' => 'linebreak'
107 );
108
109 /**
110 * @var array
111 */
112 public $pluginButton = array();
113
114 /**
115 * @var array
116 */
117 public $pluginLabel = array();
118
119 // Alternative style for RTE <div> tag.
120 public $RTEdivStyle;
121
122 // Relative path to this extension. It ends with "/"
123 public $extHttpPath;
124
125 public $backPath = '';
126
127 // TYPO3 site url
128 public $siteURL;
129
130 // TYPO3 host url
131 public $hostURL;
132
133 // Typo3 version
134 public $typoVersion;
135
136 // Identifies the RTE as being the one from the "rtehtmlarea" extension if any external code needs to know
137 /**
138 * @var string
139 */
140 public $ID = 'rtehtmlarea';
141
142 // For the editor
143 /**
144 * @var array
145 */
146 public $client;
147
148 /**
149 * @var string
150 */
151 public $elementId;
152
153 /**
154 * @var array
155 */
156 public $elementParts;
157
158 /**
159 * @var string
160 */
161 public $tscPID;
162
163 /**
164 * @var string
165 */
166 public $typeVal;
167
168 /**
169 * @var int
170 */
171 public $thePid;
172
173 /**
174 * @var array
175 */
176 public $RTEsetup;
177
178 /**
179 * @var array
180 */
181 public $thisConfig;
182
183 public $language;
184 /**
185 * TYPO3 language code of the content language
186 */
187 public $contentTypo3Language;
188 /**
189 * ISO language code of the content language
190 */
191 public $contentISOLanguage;
192 /**
193 * Language service object for localization to the content language
194 */
195 protected $contentLanguageService;
196 public $charset = 'utf-8';
197
198 public $contentCharset = 'utf-8';
199
200 public $OutputCharset = 'utf-8';
201
202 /**
203 * @var string
204 */
205 public $editorCSS;
206
207 /**
208 * @var array
209 */
210 public $specConf;
211
212 /**
213 * @var array
214 */
215 public $toolbar = array();
216
217 // Save the buttons for the toolbar
218 /**
219 * @var array
220 */
221 public $toolbarOrderArray = array();
222
223 protected $pluginEnabledArray = array();
224
225 // Array of plugin id's enabled in the current RTE editing area
226 protected $pluginEnabledCumulativeArray = array();
227
228 // Cumulative array of plugin id's enabled so far in any of the RTE editing areas of the form
229 public $registeredPlugins = array();
230
231 // Array of registered plugins indexed by their plugin Id's
232 protected $fullScreen = FALSE;
233
234 /**
235 * Page renderer object
236 *
237 * @var PageRenderer
238 */
239 protected $pageRenderer;
240
241 /**
242 * A list of global options given from parent to child elements
243 *
244 * @var array
245 */
246 protected $globalOptions = array();
247
248 /**
249 * Returns TRUE if the RTE is available. Here you check if the browser requirements are met.
250 * If there are reasons why the RTE cannot be displayed you simply enter them as text in ->errorLog
251 *
252 * @return bool TRUE if this RTE object offers an RTE in the current browser environment
253 */
254 public function isAvailable() {
255 $this->client = $this->clientInfo();
256 $this->errorLog = array();
257 $rteIsAvailable = FALSE;
258 $rteConfBrowser = $this->conf_supported_browser;
259 if (is_array($rteConfBrowser)) {
260 foreach ($rteConfBrowser as $browser => $browserConf) {
261 if ($browser == $this->client['browser']) {
262 // Config for Browser found, check it:
263 if (is_array($browserConf)) {
264 foreach ($browserConf as $browserConfSub) {
265 if ($browserConfSub['version'] <= $this->client['version'] || empty($browserConfSub['version'])) {
266 // Version is supported
267 if (is_array($browserConfSub['system'])) {
268 // Check against allowed systems
269 if (is_array($browserConfSub['system']['allowed'])) {
270 foreach ($browserConfSub['system']['allowed'] as $system) {
271 if (in_array($system, $this->client['all_systems'])) {
272 $rteIsAvailable = TRUE;
273 break;
274 }
275 }
276 } else {
277 // All allowed
278 $rteIsAvailable = TRUE;
279 }
280 // Check against disallowed systems
281 if (is_array($browserConfSub['system']['disallowed'])) {
282 foreach ($browserConfSub['system']['disallowed'] as $system) {
283 if (in_array($system, $this->client['all_systems'])) {
284 $rteIsAvailable = FALSE;
285 break;
286 }
287 }
288 }
289 } else {
290 // No system config: system is supported
291 $rteIsAvailable = TRUE;
292 break;
293 }
294 }
295 }
296 } else {
297 // no config for this browser found, so all versions or system with this browsers are allow
298 $rteIsAvailable = TRUE;
299 break;
300 }
301 }
302 }
303 } else {
304
305 }
306 if (!$rteIsAvailable) {
307 $this->errorLog[] = 'RTE: Browser not supported.';
308 }
309
310 return $rteIsAvailable;
311 }
312
313 /**
314 * Draws the RTE as an iframe
315 *
316 * @param FormEngine $_ Reference to parent object, which is an instance of the TCEforms. Obsolete DUMMY object only!
317 * @param string $table The table name
318 * @param string $field The field name
319 * @param array $row The current row from which field is being rendered
320 * @param array $PA Array of standard content for rendering form fields from TCEforms. See TCEforms for details on this. Includes for instance the value and the form field name, java script actions and more.
321 * @param array $specConf "special" configuration - what is found at position 4 in the types configuration of a field from record, parsed into an array.
322 * @param array $thisConfig Configuration for RTEs; A mix between TSconfig and otherwise. Contains configuration for display, which buttons are enabled, additional transformation information etc.
323 * @param string $RTEtypeVal Record "type" field value.
324 * @param string $RTErelPath Relative path for images/links in RTE; this is used when the RTE edits content from static files where the path of such media has to be transformed forth and back!
325 * @param int $thePidValue PID value of record (true parent page id)
326 * @param array $globalOptions Global options like 'readonly' for all elements. This is a hack until RTE is an own type
327 * @param array $resultArray Initialized final result array that is returned later filled with content. This is a hack until RTE is an own type
328 * @return string HTML code for RTE!
329 */
330 public function drawRTE($_, $table, $field, $row, $PA, $specConf, $thisConfig, $RTEtypeVal, $RTErelPath, $thePidValue, $globalOptions, $resultArray) {
331 $languageService = $this->getLanguageService();
332 $backendUser = $this->getBackendUserAuthentication();
333 $database = $this->getDatabaseConnection();
334
335 $this->globalOptions = $globalOptions;
336 $languageService->includeLLFile('EXT:' . $this->ID . '/locallang.xlf');
337 $this->client = $this->clientInfo();
338 $this->typoVersion = \TYPO3\CMS\Core\Utility\VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version);
339 $this->userUid = 'BE_' . $GLOBALS['BE_USER']->user['uid'];
340
341 // Draw real RTE
342 /* =======================================
343 * INIT THE EDITOR-SETTINGS
344 * =======================================
345 */
346 // Get the path to this extension:
347 $this->extHttpPath = $this->backPath . ExtensionManagementUtility::extRelPath($this->ID);
348 // Get the site URL
349 $this->siteURL = GeneralUtility::getIndpEnv('TYPO3_SITE_URL');
350 // Get the host URL
351 $this->hostURL = $this->siteURL . TYPO3_mainDir;
352 // Element ID + pid
353 $this->elementId = $PA['itemFormElName'];
354 // Form element name
355 $this->elementParts = explode('][', preg_replace('/\\]$/', '', preg_replace('/^(TSFE_EDIT\\[data\\]\\[|data\\[)/', '', $this->elementId)));
356 // Find the page PIDs:
357 list($this->tscPID, $this->thePid) = BackendUtility::getTSCpid(trim($this->elementParts[0]), trim($this->elementParts[1]), $thePidValue);
358 // Record "types" field value:
359 $this->typeVal = $RTEtypeVal;
360 // TCA "types" value for record
361 // Find "thisConfig" for record/editor:
362 unset($this->RTEsetup);
363 $this->RTEsetup = $backendUser->getTSConfig('RTE', BackendUtility::getPagesTSconfig($this->tscPID));
364 $this->thisConfig = $thisConfig;
365 // Special configuration and default extras:
366 $this->specConf = $specConf;
367 if ($this->thisConfig['forceHTTPS']) {
368 $this->extHttpPath = preg_replace('/^(http|https)/', 'https', $this->extHttpPath);
369 $this->siteURL = preg_replace('/^(http|https)/', 'https', $this->siteURL);
370 $this->hostURL = preg_replace('/^(http|https)/', 'https', $this->hostURL);
371 }
372 // Register RTE windows
373 $textAreaId = preg_replace('/[^a-zA-Z0-9_:.-]/', '_', $PA['itemFormElName']);
374 $textAreaId = htmlspecialchars(preg_replace('/^[^a-zA-Z]/', 'x', $textAreaId));
375 /* =======================================
376 * LANGUAGES & CHARACTER SETS
377 * =======================================
378 */
379 // Languages: interface and content
380 $this->language = $GLOBALS['LANG']->lang;
381 if ($this->language === 'default' || !$this->language) {
382 $this->language = 'en';
383 }
384 $this->contentLanguageUid = max($row['sys_language_uid'], 0);
385 if ($this->contentLanguageUid) {
386 $this->contentISOLanguage = $this->language;
387 if (ExtensionManagementUtility::isLoaded('static_info_tables')) {
388 $tableA = 'sys_language';
389 $tableB = 'static_languages';
390 $selectFields = $tableA . '.uid,' . $tableB . '.lg_iso_2,' . $tableB . '.lg_country_iso_2';
391 $tableAB = $tableA . ' LEFT JOIN ' . $tableB . ' ON ' . $tableA . '.static_lang_isocode=' . $tableB . '.uid';
392 $whereClause = $tableA . '.uid = ' . intval($this->contentLanguageUid);
393 $whereClause .= BackendUtility::BEenableFields($tableA);
394 $whereClause .= BackendUtility::deleteClause($tableA);
395 $res = $database->exec_SELECTquery($selectFields, $tableAB, $whereClause);
396 while ($languageRow = $database->sql_fetch_assoc($res)) {
397 $this->contentISOLanguage = strtolower(trim($languageRow['lg_iso_2']) . (trim($languageRow['lg_country_iso_2']) ? '_' . trim($languageRow['lg_country_iso_2']) : ''));
398 }
399 }
400 } else {
401 $this->contentISOLanguage = trim($this->thisConfig['defaultContentLanguage']) ?: 'en';
402 $languageCodeParts = explode('_', $this->contentISOLanguage);
403 $this->contentISOLanguage = strtolower($languageCodeParts[0]) . ($languageCodeParts[1] ? '_' . strtoupper($languageCodeParts[1]) : '');
404 // Find the configured language in the list of localization locales
405 /** @var $locales \TYPO3\CMS\Core\Localization\Locales */
406 $locales = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Localization\Locales::class);
407 // If not found, default to 'en'
408 if (!in_array($this->contentISOLanguage, $locales->getLocales())) {
409 $this->contentISOLanguage = 'en';
410 }
411 }
412 // Create content laguage service
413 $this->contentLanguageService = GeneralUtility::makeInstance(\TYPO3\CMS\Lang\LanguageService::class);
414 $this->contentTypo3Language = $this->contentISOLanguage === 'en' ? 'default' : $this->contentISOLanguage;
415 $this->contentLanguageService->init($this->contentTypo3Language);
416 /* =======================================
417 * TOOLBAR CONFIGURATION
418 * =======================================
419 */
420 $this->initializeToolbarConfiguration();
421 /* =======================================
422 * SET STYLES
423 * =======================================
424 */
425 // Check if wizard_rte called this for fullscreen edtition
426 if (GeneralUtility::_GP('M') === 'wizard_rte') {
427 $this->fullScreen = TRUE;
428 $RTEWidth = '100%';
429 $RTEHeight = '100%';
430 $RTEPaddingRight = '0';
431 $editorWrapWidth = '100%';
432 } else {
433 $options = $GLOBALS['BE_USER']->userTS['options.'];
434 $RTEWidth = 530 + (isset($options['RTELargeWidthIncrement']) ? (int)$options['RTELargeWidthIncrement'] : 150);
435 /** @var InlineStackProcessor $inlineStackProcessor */
436 $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
437 $inlineStackProcessor->initializeByGivenStructure($globalOptions['inlineStructure']);
438 $inlineStructureDepth = $inlineStackProcessor->getStructureDepth();
439 $RTEWidth -= $inlineStructureDepth > 0 ? ($inlineStructureDepth + 1) * 12 : 0;
440 $RTEWidthOverride = is_object($GLOBALS['BE_USER']) && isset($GLOBALS['BE_USER']->uc['rteWidth']) && trim($GLOBALS['BE_USER']->uc['rteWidth']) ? trim($GLOBALS['BE_USER']->uc['rteWidth']) : trim($this->thisConfig['RTEWidthOverride']);
441 if ($RTEWidthOverride) {
442 if (strstr($RTEWidthOverride, '%')) {
443 if ($this->client['browser'] != 'msie') {
444 $RTEWidth = (int)$RTEWidthOverride > 0 ? $RTEWidthOverride : '100%';
445 }
446 } else {
447 $RTEWidth = (int)$RTEWidthOverride > 0 ? (int)$RTEWidthOverride : $RTEWidth;
448 }
449 }
450 $RTEWidth = strstr($RTEWidth, '%') ? $RTEWidth : $RTEWidth . 'px';
451 $RTEHeight = 380 + (isset($options['RTELargeHeightIncrement']) ? (int)$options['RTELargeHeightIncrement'] : 0);
452 $RTEHeightOverride = is_object($GLOBALS['BE_USER']) && isset($GLOBALS['BE_USER']->uc['rteHeight']) && (int)$GLOBALS['BE_USER']->uc['rteHeight'] ? (int)$GLOBALS['BE_USER']->uc['rteHeight'] : (int)$this->thisConfig['RTEHeightOverride'];
453 $RTEHeight = $RTEHeightOverride > 0 ? $RTEHeightOverride : $RTEHeight;
454 $RTEPaddingRight = '2px';
455 $editorWrapWidth = '99%';
456 }
457 $editorWrapHeight = '100%';
458 $this->RTEdivStyle = 'position:relative; left:0px; top:0px; height:' . $RTEHeight . 'px; width:' . $RTEWidth . '; border: 1px solid black; padding: 2px ' . $RTEPaddingRight . ' 2px 2px;';
459 /* =======================================
460 * LOAD CSS AND JAVASCRIPT
461 * =======================================
462 */
463 $this->pageRenderer = $GLOBALS['SOBE']->doc->getPageRenderer();
464 // Preloading the pageStyle and including RTE skin stylesheets
465 $resultArray = $this->addPageStyle($resultArray);
466 $resultArray = $this->addSkin($resultArray);
467 // Register RTE in JS
468 $resultArray['additionalJavaScriptPost'][] = $this->registerRTEinJS(NULL, $table, $row['uid'], $field, $textAreaId);
469 // Set the save option for the RTE
470 $resultArray['additionalJavaScriptSubmit'][] = $this->setSaveRTE(NULL, 'editform', $textAreaId, $PA['itemFormElName']);
471 // Loading ExtJs inline code
472 $this->pageRenderer->enableExtJSQuickTips();
473 // Add TYPO3 notifications JavaScript
474 $this->pageRenderer->addJsFile('sysext/backend/Resources/Public/JavaScript/notifications.js');
475 // Add RTE JavaScript
476 $this->addRteJsFiles();
477 $this->pageRenderer->addJsFile($this->buildJSMainLangFile());
478 $this->pageRenderer->addJsInlineCode('HTMLArea-init', $this->getRteInitJsCode(), TRUE);
479 /* =======================================
480 * DRAW THE EDITOR
481 * =======================================
482 */
483 // Transform value:
484 $value = $this->transformContent('rte', $PA['itemFormElValue'], $table, $field, $row, $specConf, $thisConfig, $RTErelPath, $thePidValue);
485 // Further content transformation by registered plugins
486 foreach ($this->registeredPlugins as $pluginId => $plugin) {
487 if ($this->isPluginEnabled($pluginId) && method_exists($plugin, 'transformContent')) {
488 $value = $plugin->transformContent($value);
489 }
490 }
491 // Draw the textarea
492 $item = $this->triggerField($PA['itemFormElName']) . '
493 <div id="pleasewait' . $textAreaId . '" class="pleasewait" style="display: block;" >' . $languageService->getLL('Please wait') . '</div>
494 <div id="editorWrap' . $textAreaId . '" class="editorWrap" style="visibility: hidden; width:' . $editorWrapWidth . '; height:' . $editorWrapHeight . ';">
495 <textarea id="RTEarea' . $textAreaId . '" name="' . htmlspecialchars($PA['itemFormElName']) . '" rows="0" cols="0" style="' . htmlspecialchars($this->RTEdivStyle, ENT_COMPAT, 'UTF-8', FALSE) . '">' . GeneralUtility::formatForTextarea($value) . '</textarea>
496 </div>' . LF;
497
498 $resultArray['html'] = $item;
499 return $resultArray;
500 }
501
502 /**
503 * Add links to content style sheets to document header
504 *
505 * @param $resultArray array Incoming result array
506 * @return array Modified result array
507 */
508 protected function addPageStyle(array $resultArray) {
509 $contentCssFileNames = $this->getContentCssFileNames();
510 foreach ($contentCssFileNames as $contentCssKey => $contentCssFile) {
511 $resultArray = $this->addStyleSheet('rtehtmlarea-content-' . $contentCssKey, $contentCssFile, 'htmlArea RTE Content CSS', 'alternate stylesheet', $resultArray);
512 }
513 return $resultArray;
514 }
515
516 /**
517 * Get the name of the contentCSS files to use
518 *
519 * @return array An array of full file name of the content css files to use
520 */
521 protected function getContentCssFileNames() {
522 $contentCss = is_array($this->thisConfig['contentCSS.']) ? $this->thisConfig['contentCSS.'] : array();
523 if (isset($this->thisConfig['contentCSS'])) {
524 $contentCss[] = trim($this->thisConfig['contentCSS']);
525 }
526 $contentCssFiles = array();
527 if (count($contentCss)) {
528 foreach ($contentCss as $contentCssKey => $contentCssfile) {
529 $fileName = trim($contentCssfile);
530 $absolutePath = GeneralUtility::getFileAbsFileName($fileName);
531 if (file_exists($absolutePath) && filesize($absolutePath)) {
532 $contentCssFiles[$contentCssKey] = $this->getFullFileName($fileName);
533 }
534 }
535 }
536 // Fallback to default content css file if none of the configured files exists and is not empty
537 if (count($contentCssFiles) === 0) {
538 $contentCssFiles['default'] = $this->getFullFileName('EXT:' . $this->ID . '/Resources/Public/Css/ContentCss/Default.css');
539 }
540 return array_unique($contentCssFiles);
541 }
542
543 /**
544 * Add links to skin style sheet(s) to document header
545 *
546 * @param array $resultArray array Incoming result array
547 * @return array Modified result array
548 */
549 protected function addSkin(array $resultArray) {
550 // Get skin file name from Page TSConfig if any
551 $skinFilename = trim($this->thisConfig['skin']) ?: 'EXT:' . $this->ID . '/Resources/Public/Css/Skin/htmlarea.css';
552 $this->editorCSS = $this->getFullFileName($skinFilename);
553 $skinDir = dirname($this->editorCSS);
554 // Editing area style sheet
555 $this->editedContentCSS = $skinDir . '/htmlarea-edited-content.css';
556 $resultArray = $this->addStyleSheet('rtehtmlarea-editing-area-skin', $this->editedContentCSS, '', 'stylesheet', $resultArray);
557 // jQuery UI Resizable style sheet
558 $resultArray = $this->addStyleSheet('jquery-ui-resizable', $skinDir . '/jquery-ui-resizable.css', '', 'stylesheet', $resultArray);
559 // Main skin
560 $resultArray = $this->addStyleSheet('rtehtmlarea-skin', $this->editorCSS, '', 'stylesheet', $resultArray);
561 // Additional icons from registered plugins
562 foreach ($this->pluginEnabledCumulativeArray as $pluginId) {
563 if (is_object($this->registeredPlugins[$pluginId])) {
564 $pathToSkin = $this->registeredPlugins[$pluginId]->getPathToSkin();
565 if ($pathToSkin) {
566 $key = $this->registeredPlugins[$pluginId]->getExtensionKey();
567 $resultArray = $this->addStyleSheet(
568 'rtehtmlarea-plugin-' . $pluginId . '-skin',
569 ($this->is_FE() ? ExtensionManagementUtility::siteRelPath($key) : $this->backPath . ExtensionManagementUtility::extRelPath($key)) . $pathToSkin,
570 '',
571 'stylesheet',
572 $resultArray
573 );
574 }
575 }
576 }
577 return $resultArray;
578 }
579
580 /**
581 * Add style sheet file to document header
582 *
583 * @param string $key: some key identifying the style sheet
584 * @param string $href: uri to the style sheet file
585 * @param string $title: value for the title attribute of the link element
586 * @param string $relation: value for the rel attribute of the link element
587 * @param $resultArray array Incoming result array
588 * @return array Modified result array
589 */
590 protected function addStyleSheet($key, $href, $title = '', $relation = 'stylesheet', array $resultArray) {
591 // If it was not known that an RTE-enabled CE would be created when the page was first created, the css would not be added to head
592 if ($this->globalOptions['isAjaxContext']) {
593 $resultArray['additionalHeadTags'][] = '<link rel="' . $relation . '" type="text/css" href="' . $href . '" title="' . $title . '" />';
594 } else {
595 $this->pageRenderer->addCssFile($href, $relation, 'screen', $title);
596 }
597 return $resultArray;
598 }
599
600 /**
601 * Initialize toolbar configuration and enable registered plugins
602 *
603 * @return void
604 */
605 protected function initializeToolbarConfiguration() {
606 // Enable registred plugins
607 $this->enableRegisteredPlugins();
608 // Configure toolbar
609 $this->setToolbar();
610 // Check if some plugins need to be disabled
611 $this->setPlugins();
612 // Merge the list of enabled plugins with the lists from the previous RTE editing areas on the same form
613 $this->pluginEnabledCumulativeArray = $this->pluginEnabledArray;
614 }
615
616 /**
617 * Add registered plugins to the array of enabled plugins
618 */
619 public function enableRegisteredPlugins() {
620 // Traverse registered plugins
621 if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID]['plugins'])) {
622 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID]['plugins'] as $pluginId => $pluginObjectConfiguration) {
623 $plugin = FALSE;
624 if (is_array($pluginObjectConfiguration) && count($pluginObjectConfiguration)) {
625 $plugin = GeneralUtility::getUserObj($pluginObjectConfiguration['objectReference']);
626 }
627 if (is_object($plugin)) {
628 if ($plugin->main($this)) {
629 $this->registeredPlugins[$pluginId] = $plugin;
630 // Override buttons from previously registered plugins
631 $pluginButtons = GeneralUtility::trimExplode(',', $plugin->getPluginButtons(), TRUE);
632 foreach ($this->pluginButton as $previousPluginId => $buttonList) {
633 $this->pluginButton[$previousPluginId] = implode(',', array_diff(GeneralUtility::trimExplode(',', $this->pluginButton[$previousPluginId], TRUE), $pluginButtons));
634 }
635 $this->pluginButton[$pluginId] = $plugin->getPluginButtons();
636 $pluginLabels = GeneralUtility::trimExplode(',', $plugin->getPluginLabels(), TRUE);
637 foreach ($this->pluginLabel as $previousPluginId => $labelList) {
638 $this->pluginLabel[$previousPluginId] = implode(',', array_diff(GeneralUtility::trimExplode(',', $this->pluginLabel[$previousPluginId], TRUE), $pluginLabels));
639 }
640 $this->pluginLabel[$pluginId] = $plugin->getPluginLabels();
641 $this->pluginEnabledArray[] = $pluginId;
642 }
643 }
644 }
645 }
646 // Process overrides
647 $hidePlugins = array();
648 foreach ($this->registeredPlugins as $pluginId => $plugin) {
649 if ($plugin->addsButtons() && !$this->pluginButton[$pluginId]) {
650 $hidePlugins[] = $pluginId;
651 }
652 }
653 $this->pluginEnabledArray = array_unique(array_diff($this->pluginEnabledArray, $hidePlugins));
654 }
655
656 /**
657 * Set the toolbar config (only in this PHP-Object, not in JS):
658 */
659 public function setToolbar() {
660 if ($this->client['browser'] == 'msie' || $this->client['browser'] == 'opera') {
661 $this->thisConfig['keepButtonGroupTogether'] = 0;
662 }
663 $this->defaultToolbarOrder = 'bar, blockstylelabel, blockstyle, textstylelabel, textstyle, linebreak,
664 bar, formattext, bold, strong, italic, emphasis, big, small, insertedtext, deletedtext, citation, code, definition, keyboard, monospaced, quotation, sample, variable, bidioverride, strikethrough, subscript, superscript, underline, span,
665 bar, fontstyle, fontsize, bar, formatblock, insertparagraphbefore, insertparagraphafter, blockquote, line,
666 bar, left, center, right, justifyfull,
667 bar, orderedlist, unorderedlist, definitionlist, definitionitem, outdent, indent,
668 bar, language, showlanguagemarks,lefttoright, righttoleft,
669 bar, textcolor, bgcolor, textindicator,
670 bar, editelement, showmicrodata,
671 bar, image, emoticon, insertcharacter, insertsofthyphen, abbreviation, user,
672 bar, link, unlink,
673 bar, table,' . ($this->thisConfig['hideTableOperationsInToolbar'] && is_array($this->thisConfig['buttons.']) && is_array($this->thisConfig['buttons.']['toggleborders.']) && $this->thisConfig['buttons.']['toggleborders.']['keepInToolbar'] ? ' toggleborders,' : '') . '
674 bar, findreplace, spellcheck,
675 bar, chMode, inserttag, removeformat, bar, copy, cut, paste, pastetoggle, pastebehaviour, bar, undo, redo, bar, showhelp, about, linebreak,
676 ' . ($this->thisConfig['hideTableOperationsInToolbar'] ? '' : 'bar, toggleborders,') . ' bar, tableproperties, tablerestyle, bar, rowproperties, rowinsertabove, rowinsertunder, rowdelete, rowsplit, bar,
677 columnproperties, columninsertbefore, columninsertafter, columndelete, columnsplit, bar,
678 cellproperties, cellinsertbefore, cellinsertafter, celldelete, cellsplit, cellmerge';
679 // Additional buttons from registered plugins
680 foreach ($this->registeredPlugins as $pluginId => $plugin) {
681 if ($this->isPluginEnabled($pluginId)) {
682 $this->defaultToolbarOrder = $plugin->addButtonsToToolbar();
683 }
684 }
685 $toolbarOrder = $this->thisConfig['toolbarOrder'] ?: $this->defaultToolbarOrder;
686 // Getting rid of undefined buttons
687 $this->toolbarOrderArray = array_intersect(GeneralUtility::trimExplode(',', $toolbarOrder, TRUE), GeneralUtility::trimExplode(',', $this->defaultToolbarOrder, TRUE));
688 $toolbarOrder = array_unique(array_values($this->toolbarOrderArray));
689 // Fetching specConf for field from backend
690 $pList = is_array($this->specConf['richtext']['parameters']) ? implode(',', $this->specConf['richtext']['parameters']) : '';
691 if ($pList != '*') {
692 // If not all
693 $show = is_array($this->specConf['richtext']['parameters']) ? $this->specConf['richtext']['parameters'] : array();
694 if ($this->thisConfig['showButtons']) {
695 if (!GeneralUtility::inList($this->thisConfig['showButtons'], '*')) {
696 $show = array_unique(array_merge($show, GeneralUtility::trimExplode(',', $this->thisConfig['showButtons'], TRUE)));
697 } else {
698 $show = array_unique(array_merge($show, $toolbarOrder));
699 }
700 }
701 if (is_array($this->thisConfig['showButtons.'])) {
702 foreach ($this->thisConfig['showButtons.'] as $buttonId => $value) {
703 if ($value) {
704 $show[] = $buttonId;
705 }
706 }
707 $show = array_unique($show);
708 }
709 } else {
710 $show = $toolbarOrder;
711 }
712 // Resticting to RTEkeyList for backend user
713 if (is_object($GLOBALS['BE_USER'])) {
714 $RTEkeyList = isset($GLOBALS['BE_USER']->userTS['options.']['RTEkeyList']) ? $GLOBALS['BE_USER']->userTS['options.']['RTEkeyList'] : '*';
715 if ($RTEkeyList != '*') {
716 // If not all
717 $show = array_intersect($show, GeneralUtility::trimExplode(',', $RTEkeyList, TRUE));
718 }
719 }
720 // Hiding buttons of disabled plugins
721 $hideButtons = array('space', 'bar', 'linebreak');
722 foreach ($this->pluginButton as $pluginId => $buttonList) {
723 if (!$this->isPluginEnabled($pluginId)) {
724 $buttonArray = GeneralUtility::trimExplode(',', $buttonList, TRUE);
725 foreach ($buttonArray as $button) {
726 $hideButtons[] = $button;
727 }
728 }
729 }
730 // Hiding labels of disabled plugins
731 foreach ($this->pluginLabel as $pluginId => $label) {
732 if (!$this->isPluginEnabled($pluginId)) {
733 $hideButtons[] = $label;
734 }
735 }
736 // Hiding buttons
737 $show = array_diff($show, $this->conf_toolbar_hide, GeneralUtility::trimExplode(',', $this->thisConfig['hideButtons'], TRUE));
738 // Apply toolbar constraints from registered plugins
739 foreach ($this->registeredPlugins as $pluginId => $plugin) {
740 if ($this->isPluginEnabled($pluginId) && method_exists($plugin, 'applyToolbarConstraints')) {
741 $show = $plugin->applyToolbarConstraints($show);
742 }
743 }
744 // Getting rid of the buttons for which we have no position
745 $show = array_intersect($show, $toolbarOrder);
746 $this->toolbar = $show;
747 }
748
749 /**
750 * Disable some plugins
751 */
752 public function setPlugins() {
753 // Disabling a plugin that adds buttons if none of its buttons is in the toolbar
754 $hidePlugins = array();
755 foreach ($this->pluginButton as $pluginId => $buttonList) {
756 if ($this->registeredPlugins[$pluginId]->addsButtons()) {
757 $showPlugin = FALSE;
758 $buttonArray = GeneralUtility::trimExplode(',', $buttonList, TRUE);
759 foreach ($buttonArray as $button) {
760 if (in_array($button, $this->toolbar)) {
761 $showPlugin = TRUE;
762 }
763 }
764 if (!$showPlugin) {
765 $hidePlugins[] = $pluginId;
766 }
767 }
768 }
769 $this->pluginEnabledArray = array_diff($this->pluginEnabledArray, $hidePlugins);
770 // Hiding labels of disabled plugins
771 $hideLabels = array();
772 foreach ($this->pluginLabel as $pluginId => $label) {
773 if (!$this->isPluginEnabled($pluginId)) {
774 $hideLabels[] = $label;
775 }
776 }
777 $this->toolbar = array_diff($this->toolbar, $hideLabels);
778 // Adding plugins declared as prerequisites by enabled plugins
779 $requiredPlugins = array();
780 foreach ($this->registeredPlugins as $pluginId => $plugin) {
781 if ($this->isPluginEnabled($pluginId)) {
782 $requiredPlugins = array_merge($requiredPlugins, GeneralUtility::trimExplode(',', $plugin->getRequiredPlugins(), TRUE));
783 }
784 }
785 $requiredPlugins = array_unique($requiredPlugins);
786 foreach ($requiredPlugins as $pluginId) {
787 if (is_object($this->registeredPlugins[$pluginId]) && !$this->isPluginEnabled($pluginId)) {
788 $this->pluginEnabledArray[] = $pluginId;
789 }
790 }
791 $this->pluginEnabledArray = array_unique($this->pluginEnabledArray);
792 // Completing the toolbar conversion array for htmlArea
793 foreach ($this->registeredPlugins as $pluginId => $plugin) {
794 if ($this->isPluginEnabled($pluginId)) {
795 $this->convertToolbarForHtmlAreaArray = array_unique(array_merge($this->convertToolbarForHtmlAreaArray, $plugin->getConvertToolbarForHtmlAreaArray()));
796 }
797 }
798 }
799
800 /**
801 * Convert the TYPO3 names of buttons into the names for htmlArea RTE
802 *
803 * @param string buttonname (typo3-name)
804 * @return string buttonname (htmlarea-name)
805 */
806 public function convertToolbarForHTMLArea($button) {
807 return $this->convertToolbarForHtmlAreaArray[$button];
808 }
809
810 /**
811 * Add RTE main scripts and plugin scripts
812 *
813 * @param int $RTEcounter: The index number of the current RTE editing area within the form. @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8
814 * @return void
815 */
816 protected function addRteJsFiles($RTEcounter = NULL) {
817 if ($RTEcounter !== NULL) {
818 GeneralUtility::deprecationLog('$RTEcounter parameter is deprecated and ignored');
819 }
820
821 // Component files. Order is important.
822 $components = array(
823 'Util/Wrap.open',
824 'NameSpace/NameSpace',
825 'UserAgent/UserAgent',
826 'Util/Util',
827 'Util/Color',
828 'Util/Resizable',
829 'Util/String',
830 'Util/Tips',
831 'Util/TYPO3',
832 'Ajax/Ajax',
833 'DOM/DOM',
834 'Event/Event',
835 'Event/KeyMap',
836 'CSS/Parser',
837 'DOM/BookMark',
838 'DOM/Node',
839 'DOM/Selection',
840 'DOM/Walker',
841 'Configuration/Config',
842 'Toolbar/Button',
843 'Toolbar/ToolbarText',
844 'Toolbar/Select',
845 'Extjs/ColorPalette',
846 'Extjs/ux/ColorMenu',
847 'Extjs/ux/ColorPaletteField',
848 'LoremIpsum',
849 'Plugin/Plugin'
850 );
851 $components2 = array(
852 'Editor/Toolbar',
853 'Editor/Iframe',
854 'Editor/TextAreaContainer',
855 'Editor/StatusBar',
856 'Editor/Framework',
857 'Editor/Editor',
858 'HTMLArea'
859 );
860 foreach ($components as $component) {
861 $this->pageRenderer->addJsFile($this->getFullFileName('EXT:' . $this->ID . '/Resources/Public/JavaScript/HTMLArea/' . $component . '.js'));
862 }
863 foreach ($this->pluginEnabledCumulativeArray as $pluginId) {
864 $extensionKey = is_object($this->registeredPlugins[$pluginId]) ? $this->registeredPlugins[$pluginId]->getExtensionKey() : $this->ID;
865 $fileName = 'EXT:' . $extensionKey . '/Resources/Public/JavaScript/Plugins/' . $pluginId . '.js';
866 $absolutePath = GeneralUtility::getFileAbsFileName($fileName);
867 if (file_exists($absolutePath)) {
868 $this->pageRenderer->addJsFile($this->getFullFileName($fileName));
869 } else {
870 // Backward compatibility
871 $pluginName = strtolower(preg_replace('/([a-z])([A-Z])([a-z])/', '$1-$2$3', $pluginId));
872 $fileName = 'EXT:' . $extensionKey . '/htmlarea/plugins/' . $pluginId . '/' . $pluginName . '.js';
873 $absolutePath = GeneralUtility::getFileAbsFileName($fileName);
874 if (file_exists($absolutePath)) {
875 $this->pageRenderer->addJsFile($this->getFullFileName($fileName));
876 }
877 }
878 }
879 foreach ($components2 as $component) {
880 $this->pageRenderer->addJsFile($this->getFullFileName('EXT:' . $this->ID . '/Resources/Public/JavaScript/HTMLArea/' . $component . '.js'));
881 }
882 $this->pageRenderer->addJsFile($this->getFullFileName('EXT:' . $this->ID . '/Resources/Public/JavaScript/HTMLArea/Util/Wrap.close.js'));
883 }
884
885 /**
886 * Return RTE initialization inline JavaScript code
887 *
888 * @return string RTE initialization inline JavaScript code
889 */
890 protected function getRteInitJsCode() {
891 return 'require(["TYPO3/CMS/Rtehtmlarea/HTMLArea/HTMLArea"], function (HTMLArea) {
892 if (typeof RTEarea === "undefined") {
893 RTEarea = new Object();
894 RTEarea[0] = new Object();
895 RTEarea[0].version = "' . $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID]['version'] . '";
896 RTEarea[0].editorUrl = "' . $this->extHttpPath . '";
897 RTEarea[0].editorCSS = "' . GeneralUtility::createVersionNumberedFilename($this->editorCSS) . '";
898 RTEarea[0].editorSkin = "' . dirname($this->editorCSS) . '/";
899 RTEarea[0].editedContentCSS = "' . GeneralUtility::createVersionNumberedFilename($this->editedContentCSS) . '";
900 RTEarea[0].hostUrl = "' . $this->hostURL . '";
901 RTEarea.init = function() {
902 if (typeof HTMLArea === "undefined" || !Ext.isReady) {
903 window.setTimeout(function () {
904 RTEarea.init();
905 }, 10);
906 } else {
907 Ext.QuickTips.init();
908 HTMLArea.init();
909 }
910 };
911 RTEarea.initEditor = function(editorNumber) {
912 if (typeof HTMLArea === "undefined" || !HTMLArea.isReady) {
913 window.setTimeout(function () {
914 RTEarea.initEditor(editorNumber);
915 }, 40);
916 } else {
917 HTMLArea.initEditor(editorNumber);
918 }
919 };
920 }
921 RTEarea.init();
922 });';
923 }
924
925 /**
926 * Return the Javascript code for configuring the RTE
927 *
928 * @param int $RTEcounter: The index number of the current RTE editing area within the form. @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8
929 * @param string $table: The table that includes this RTE (optional, necessary for IRRE).
930 * @param string $uid: The uid of that table that includes this RTE (optional, necessary for IRRE).
931 * @param string $field: The field of that record that includes this RTE (optional).
932 * @param string $textAreaId ID of the textarea, to have a unigue number for the editor
933 * @return string the Javascript code for configuring the RTE
934 */
935 public function registerRTEinJS($RTEcounter = NULL, $table = '', $uid = '', $field = '', $textAreaId = '') {
936 if ($RTEcounter !== NULL) {
937 GeneralUtility::deprecationLog('$RTEcounter parameter is deprecated and ignored');
938 }
939 $configureRTEInJavascriptString = '
940 if (typeof configureEditorInstance === "undefined") {
941 configureEditorInstance = new Object();
942 }
943 configureEditorInstance["' . $textAreaId . '"] = function() {
944 if (typeof RTEarea === "undefined" || typeof HTMLArea === "undefined") {
945 window.setTimeout("configureEditorInstance[\'' . $textAreaId . '\']();", 40);
946 } else {
947 editornumber = "' . $textAreaId . '";
948 RTEarea[editornumber] = new Object();
949 RTEarea[editornumber].RTEtsConfigParams = "&RTEtsConfigParams=' . rawurlencode($this->RTEtsConfigParams()) . '";
950 RTEarea[editornumber].number = editornumber;
951 RTEarea[editornumber].deleted = false;
952 RTEarea[editornumber].textAreaId = "' . $textAreaId . '";
953 RTEarea[editornumber].id = "RTEarea" + editornumber;
954 RTEarea[editornumber].RTEWidthOverride = "' . (is_object($GLOBALS['BE_USER']) && isset($GLOBALS['BE_USER']->uc['rteWidth']) && trim($GLOBALS['BE_USER']->uc['rteWidth']) ? trim($GLOBALS['BE_USER']->uc['rteWidth']) : trim($this->thisConfig['RTEWidthOverride'])) . '";
955 RTEarea[editornumber].RTEHeightOverride = "' . (is_object($GLOBALS['BE_USER']) && isset($GLOBALS['BE_USER']->uc['rteHeight']) && (int)$GLOBALS['BE_USER']->uc['rteHeight'] ? (int)$GLOBALS['BE_USER']->uc['rteHeight'] : (int)$this->thisConfig['RTEHeightOverride']) . '";
956 RTEarea[editornumber].resizable = ' . (is_object($GLOBALS['BE_USER']) && isset($GLOBALS['BE_USER']->uc['rteResize']) && $GLOBALS['BE_USER']->uc['rteResize'] ? 'true' : (trim($this->thisConfig['rteResize']) ? 'true' : 'false')) . ';
957 RTEarea[editornumber].maxHeight = "' . (is_object($GLOBALS['BE_USER']) && isset($GLOBALS['BE_USER']->uc['rteMaxHeight']) && (int)$GLOBALS['BE_USER']->uc['rteMaxHeight'] ? trim($GLOBALS['BE_USER']->uc['rteMaxHeight']) : ((int)$this->thisConfig['rteMaxHeight'] ?: '2000')) . '";
958 RTEarea[editornumber].fullScreen = ' . ($this->fullScreen ? 'true' : 'false') . ';
959 RTEarea[editornumber].showStatusBar = ' . (trim($this->thisConfig['showStatusBar']) ? 'true' : 'false') . ';
960 RTEarea[editornumber].enableWordClean = ' . (trim($this->thisConfig['enableWordClean']) ? 'true' : 'false') . ';
961 RTEarea[editornumber].htmlRemoveComments = ' . (trim($this->thisConfig['removeComments']) ? 'true' : 'false') . ';
962 RTEarea[editornumber].disableEnterParagraphs = ' . (trim($this->thisConfig['disableEnterParagraphs']) ? 'true' : 'false') . ';
963 RTEarea[editornumber].disableObjectResizing = ' . (trim($this->thisConfig['disableObjectResizing']) ? 'true' : 'false') . ';
964 RTEarea[editornumber].removeTrailingBR = ' . (trim($this->thisConfig['removeTrailingBR']) ? 'true' : 'false') . ';
965 RTEarea[editornumber].useCSS = ' . (trim($this->thisConfig['useCSS']) ? 'true' : 'false') . ';
966 RTEarea[editornumber].keepButtonGroupTogether = ' . (trim($this->thisConfig['keepButtonGroupTogether']) ? 'true' : 'false') . ';
967 RTEarea[editornumber].disablePCexamples = ' . (trim($this->thisConfig['disablePCexamples']) ? 'true' : 'false') . ';
968 RTEarea[editornumber].showTagFreeClasses = ' . (trim($this->thisConfig['showTagFreeClasses']) ? 'true' : 'false') . ';
969 RTEarea[editornumber].useHTTPS = ' . (trim(stristr($this->siteURL, 'https')) || $this->thisConfig['forceHTTPS'] ? 'true' : 'false') . ';
970 RTEarea[editornumber].tceformsNested = ' . (count($this->globalOptions) ? json_encode($this->globalOptions['tabAndInlineStack']) : '[]') . ';
971 RTEarea[editornumber].dialogueWindows = new Object();';
972 if (isset($this->thisConfig['dialogueWindows.']['defaultPositionFromTop'])) {
973 $configureRTEInJavascriptString .= '
974 RTEarea[editornumber].dialogueWindows.positionFromTop = ' . (int)$this->thisConfig['dialogueWindows.']['defaultPositionFromTop'] . ';';
975 }
976 if (isset($this->thisConfig['dialogueWindows.']['defaultPositionFromLeft'])) {
977 $configureRTEInJavascriptString .= '
978 RTEarea[editornumber].dialogueWindows.positionFromLeft = ' . (int)$this->thisConfig['dialogueWindows.']['defaultPositionFromLeft'] . ';';
979 }
980 // The following properties apply only to the backend
981 if (!$this->is_FE()) {
982 $configureRTEInJavascriptString .= '
983 RTEarea[editornumber].sys_language_content = "' . $this->contentLanguageUid . '";
984 RTEarea[editornumber].typo3ContentLanguage = "' . $this->contentTypo3Language . '";
985 RTEarea[editornumber].typo3ContentCharset = "' . $this->contentCharset . '";
986 RTEarea[editornumber].userUid = "' . $this->userUid . '";';
987 }
988 // Setting the plugin flags
989 $configureRTEInJavascriptString .= '
990 RTEarea[editornumber].plugin = new Object();
991 RTEarea[editornumber].pathToPluginDirectory = new Object();';
992 foreach ($this->pluginEnabledArray as $pluginId) {
993 $configureRTEInJavascriptString .= '
994 RTEarea[editornumber].plugin.' . $pluginId . ' = true;';
995 if (is_object($this->registeredPlugins[$pluginId])) {
996 $pathToPluginDirectory = $this->registeredPlugins[$pluginId]->getPathToPluginDirectory();
997 if ($pathToPluginDirectory) {
998 $configureRTEInJavascriptString .= '
999 RTEarea[editornumber].pathToPluginDirectory.' . $pluginId . ' = "' . $pathToPluginDirectory . '";';
1000 }
1001 }
1002 }
1003 // Setting the buttons configuration
1004 $configureRTEInJavascriptString .= '
1005 RTEarea[editornumber].buttons = new Object();';
1006 if (is_array($this->thisConfig['buttons.'])) {
1007 foreach ($this->thisConfig['buttons.'] as $buttonIndex => $conf) {
1008 $button = substr($buttonIndex, 0, -1);
1009 if (is_array($conf)) {
1010 $configureRTEInJavascriptString .= '
1011 RTEarea[editornumber].buttons.' . $button . ' = ' . $this->buildNestedJSArray($conf) . ';';
1012 }
1013 }
1014 }
1015 // Setting the list of tags to be removed if specified in the RTE config
1016 if (trim($this->thisConfig['removeTags'])) {
1017 $configureRTEInJavascriptString .= '
1018 RTEarea[editornumber].htmlRemoveTags = /^(' . implode('|', GeneralUtility::trimExplode(',', $this->thisConfig['removeTags'], TRUE)) . ')$/i;';
1019 }
1020 // Setting the list of tags to be removed with their contents if specified in the RTE config
1021 if (trim($this->thisConfig['removeTagsAndContents'])) {
1022 $configureRTEInJavascriptString .= '
1023 RTEarea[editornumber].htmlRemoveTagsAndContents = /^(' . implode('|', GeneralUtility::trimExplode(',', $this->thisConfig['removeTagsAndContents'], TRUE)) . ')$/i;';
1024 }
1025 // Setting array of custom tags if specified in the RTE config
1026 if (!empty($this->thisConfig['customTags'])) {
1027 $customTags = GeneralUtility::trimExplode(',', $this->thisConfig['customTags'], TRUE);
1028 if (!empty($customTags)) {
1029 $configureRTEInJavascriptString .= '
1030 RTEarea[editornumber].customTags= ' . json_encode($customTags) . ';';
1031 }
1032 }
1033 // Setting array of content css files if specified in the RTE config
1034 $versionNumberedFileNames = array();
1035 $contentCssFileNames = $this->getContentCssFileNames();
1036 foreach ($contentCssFileNames as $contentCssFileName) {
1037 $versionNumberedFileNames[] = GeneralUtility::createVersionNumberedFilename($contentCssFileName);
1038 }
1039 $configureRTEInJavascriptString .= '
1040 RTEarea[editornumber].pageStyle = ["' . implode('","', $versionNumberedFileNames) . '"];';
1041 // Process classes configuration
1042 $classesConfigurationRequired = FALSE;
1043 foreach ($this->registeredPlugins as $pluginId => $plugin) {
1044 if ($this->isPluginEnabled($pluginId)) {
1045 $classesConfigurationRequired = $classesConfigurationRequired || $plugin->requiresClassesConfiguration();
1046 }
1047 }
1048 if ($classesConfigurationRequired) {
1049 $configureRTEInJavascriptString .= $this->buildJSClassesConfig();
1050 }
1051 // Add Javascript configuration for registered plugins
1052 foreach ($this->registeredPlugins as $pluginId => $plugin) {
1053 if ($this->isPluginEnabled($pluginId)) {
1054 $configureRTEInJavascriptString .= $plugin->buildJavascriptConfiguration('editornumber');
1055 }
1056 }
1057 // Avoid premature reference to HTMLArea when being initially loaded by IRRE Ajax call
1058 $configureRTEInJavascriptString .= '
1059 RTEarea[editornumber].toolbar = ' . $this->getJSToolbarArray() . ';
1060 RTEarea[editornumber].convertButtonId = ' . json_encode(array_flip($this->convertToolbarForHtmlAreaArray)) . ';
1061 RTEarea.initEditor(editornumber);
1062 }
1063 };
1064 configureEditorInstance["' . $textAreaId . '"]();';
1065 return $configureRTEInJavascriptString;
1066 }
1067
1068 /**
1069 * Return TRUE, if the plugin can be loaded
1070 *
1071 * @param string $pluginId: The identification string of the plugin
1072 * @return bool TRUE if the plugin can be loaded
1073 */
1074 public function isPluginEnabled($pluginId) {
1075 return in_array($pluginId, $this->pluginEnabledArray);
1076 }
1077
1078 /**
1079 * Return Javascript configuration of classes
1080 *
1081 * @param int $RTEcounter: The index number of the current RTE editing area within the form. @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8
1082 * @return string Javascript configuration of classes
1083 */
1084 public function buildJSClassesConfig($RTEcounter = NULL) {
1085 if ($RTEcounter !== NULL) {
1086 GeneralUtility::deprecationLog('$RTEcounter parameter is deprecated and ignored');
1087 }
1088 // Include JS arrays of configured classes
1089 $configureRTEInJavascriptString = '
1090 RTEarea[editornumber].classesUrl = "' . ($this->is_FE() && $GLOBALS['TSFE']->absRefPrefix ? $GLOBALS['TSFE']->absRefPrefix : '') . $this->writeTemporaryFile('', ('classes_' . $this->language), 'js', $this->buildJSClassesArray(), TRUE) . '";';
1091 return $configureRTEInJavascriptString;
1092 }
1093
1094 /**
1095 * Return JS arrays of classes configuration
1096 *
1097 * @return string JS classes arrays
1098 */
1099 public function buildJSClassesArray() {
1100 if ($this->is_FE()) {
1101 $RTEProperties = $this->RTEsetup;
1102 } else {
1103 $RTEProperties = $this->RTEsetup['properties'];
1104 }
1105 // Declare sub-arrays
1106 $classesArray = array(
1107 'labels' => array(),
1108 'values' => array(),
1109 'noShow' => array(),
1110 'alternating' => array(),
1111 'counting' => array(),
1112 'selectable' => array(),
1113 'requires' => array(),
1114 'requiredBy' => array(),
1115 'XOR' => array()
1116 );
1117 $JSClassesArray = '';
1118 // Scanning the list of classes if specified in the RTE config
1119 if (is_array($RTEProperties['classes.'])) {
1120 foreach ($RTEProperties['classes.'] as $className => $conf) {
1121 $className = rtrim($className, '.');
1122 $classesArray['labels'][$className] = trim($conf['name']) ? $this->getPageConfigLabel($conf['name'], FALSE) : '';
1123 $classesArray['values'][$className] = str_replace('\\\'', '\'', $conf['value']);
1124 if (isset($conf['noShow'])) {
1125 $classesArray['noShow'][$className] = $conf['noShow'];
1126 }
1127 if (is_array($conf['alternating.'])) {
1128 $classesArray['alternating'][$className] = $conf['alternating.'];
1129 }
1130 if (is_array($conf['counting.'])) {
1131 $classesArray['counting'][$className] = $conf['counting.'];
1132 }
1133 if (isset($conf['selectable'])) {
1134 $classesArray['selectable'][$className] = $conf['selectable'];
1135 }
1136 if (isset($conf['requires'])) {
1137 $classesArray['requires'][$className] = explode(',', GeneralUtility::rmFromList($className, $this->cleanList($conf['requires'])));
1138 }
1139 }
1140 // Remove circularities from classes dependencies
1141 $requiringClasses = array_keys($classesArray['requires']);
1142 foreach ($requiringClasses as $requiringClass) {
1143 if ($this->hasCircularDependency($classesArray, $requiringClass, $requiringClass)) {
1144 unset($classesArray['requires'][$requiringClass]);
1145 }
1146 }
1147 // Reverse relationship for the dependency checks when removing styles
1148 $requiringClasses = array_keys($classesArray['requires']);
1149 foreach ($requiringClasses as $className) {
1150 foreach ($classesArray['requires'][$className] as $requiredClass) {
1151 if (!is_array($classesArray['requiredBy'][$requiredClass])) {
1152 $classesArray['requiredBy'][$requiredClass] = array();
1153 }
1154 if (!in_array($className, $classesArray['requiredBy'][$requiredClass])) {
1155 $classesArray['requiredBy'][$requiredClass][] = $className;
1156 }
1157 }
1158 }
1159 }
1160 // Scanning the list of sets of mutually exclusives classes if specified in the RTE config
1161 if (is_array($RTEProperties['mutuallyExclusiveClasses.'])) {
1162 foreach ($RTEProperties['mutuallyExclusiveClasses.'] as $listName => $conf) {
1163 $classSet = GeneralUtility::trimExplode(',', $conf, TRUE);
1164 $classList = implode(',', $classSet);
1165 foreach ($classSet as $className) {
1166 $classesArray['XOR'][$className] = '/^(' . implode('|', GeneralUtility::trimExplode(',', GeneralUtility::rmFromList($className, $classList), TRUE)) . ')$/';
1167 }
1168 }
1169 }
1170 foreach ($classesArray as $key => $subArray) {
1171 $JSClassesArray .= 'HTMLArea.classes' . ucfirst($key) . ' = ' . $this->buildNestedJSArray($subArray) . ';' . LF;
1172 }
1173 return $JSClassesArray;
1174 }
1175
1176 /**
1177 * Check for possible circularity in classes dependencies
1178 *
1179 * @param array $classesArray: reference to the array of classes dependencies
1180 * @param string $requiringClass: class requiring at some iteration level from the initial requiring class
1181 * @param string $initialClass: initial class from which a circular relationship is being searched
1182 * @param int $recursionLevel: depth of recursive call
1183 * @return boolean TRUE, if a circular relationship is found
1184 */
1185 protected function hasCircularDependency(&$classesArray, $requiringClass, $initialClass, $recursionLevel = 0) {
1186 if (is_array($classesArray['requires'][$requiringClass])) {
1187 if (in_array($initialClass, $classesArray['requires'][$requiringClass])) {
1188 return TRUE;
1189 } else {
1190 if ($recursionLevel++ < 20) {
1191 foreach ($classesArray['requires'][$requiringClass] as $requiringClass2) {
1192 if ($this->hasCircularDependency($classesArray, $requiringClass2, $initialClass, $recursionLevel)) {
1193 return TRUE;
1194 }
1195 }
1196 }
1197 return FALSE;
1198 }
1199 } else {
1200 return FALSE;
1201 }
1202 }
1203
1204 /**
1205 * Translate Page TS Config array in JS nested array definition
1206 * Replace 0 values with false
1207 * Unquote regular expression values
1208 * Replace empty arrays with empty objects
1209 *
1210 * @param array $conf: Page TSConfig configuration array
1211 * @return string nested JS array definition
1212 */
1213 public function buildNestedJSArray($conf) {
1214 $convertedConf = GeneralUtility::removeDotsFromTS($conf);
1215 return str_replace(array(':"0"', ':"\\/^(', ')$\\/i"', ':"\\/^(', ')$\\/"', '[]'), array(':false', ':/^(', ')$/i', ':/^(', ')$/', '{}'), json_encode($convertedConf));
1216 }
1217
1218 /**
1219 * Return a Javascript localization array for htmlArea RTE
1220 *
1221 * @return string Javascript localization array
1222 */
1223 public function buildJSMainLangArray() {
1224 $JSLanguageArray = 'HTMLArea.I18N = new Object();' . LF;
1225 $labelsArray = array('tooltips' => array(), 'msg' => array(), 'dialogs' => array());
1226 foreach ($labelsArray as $labels => $subArray) {
1227 $LOCAL_LANG = GeneralUtility::readLLfile('EXT:' . $this->ID . '/htmlarea/locallang_' . $labels . '.xlf', $this->language, 'utf-8');
1228 if (!empty($LOCAL_LANG[$this->language])) {
1229 $mergedLocalLang = $LOCAL_LANG['default'];
1230 \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($mergedLocalLang, $LOCAL_LANG[$this->language], TRUE, FALSE);
1231 $LOCAL_LANG[$this->language] = $mergedLocalLang;
1232 } else {
1233 $LOCAL_LANG[$this->language] = $LOCAL_LANG['default'];
1234 }
1235 $labelsArray[$labels] = $LOCAL_LANG[$this->language];
1236 }
1237 $JSLanguageArray .= 'HTMLArea.I18N = ' . json_encode($labelsArray) . ';' . LF;
1238 return $JSLanguageArray;
1239 }
1240
1241 /**
1242 * Writes contents in a file in typo3temp/rtehtmlarea directory and returns the file name
1243 *
1244 * @param string $sourceFileName: The name of the file from which the contents should be extracted
1245 * @param string $label: A label to insert at the beginning of the name of the file
1246 * @param string $fileExtension: The file extension of the file, defaulting to 'js'
1247 * @param string $contents: The contents to write into the file if no $sourceFileName is provided
1248 * @param bool $concatenate Not used anymore
1249 * @return string The name of the file writtten to typo3temp/rtehtmlarea
1250 */
1251 public function writeTemporaryFile($sourceFileName = '', $label, $fileExtension = 'js', $contents = '', $concatenate = FALSE) {
1252 if ($sourceFileName) {
1253 $output = '';
1254 $source = GeneralUtility::getFileAbsFileName($sourceFileName);
1255 $output = file_get_contents($source);
1256 } else {
1257 $output = $contents;
1258 }
1259 $relativeFilename = 'typo3temp/' . $this->ID . '_' . str_replace('-', '_', $label) . '_' . GeneralUtility::shortMD5((TYPO3_version . $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID]['version'] . ($sourceFileName ? $sourceFileName : $output)), 20) . '.' . $fileExtension;
1260 $destination = PATH_site . $relativeFilename;
1261 if (!file_exists($destination)) {
1262 $minifiedJavaScript = '';
1263 if ($fileExtension == 'js' && $output != '') {
1264 $minifiedJavaScript = GeneralUtility::minifyJavaScript($output);
1265 }
1266 $failure = GeneralUtility::writeFileToTypo3tempDir($destination, $minifiedJavaScript ? $minifiedJavaScript : $output);
1267 if ($failure) {
1268 throw new \RuntimeException($failure, 1294585668);
1269 }
1270 }
1271 if ($this->is_FE()) {
1272 $filename = $relativeFilename;
1273 } else {
1274 $filename = ($this->isFrontendEditActive() ? '' : $this->backPath . '../') . $relativeFilename;
1275 }
1276 return GeneralUtility::resolveBackPath($filename);
1277 }
1278
1279 /**
1280 * Return a file name containing the main JS language array for HTMLArea
1281 *
1282 * @param int $RTEcounter: The index number of the current RTE editing area within the form. @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8
1283 * @return string filename
1284 */
1285 public function buildJSMainLangFile($RTEcounter = NULL) {
1286 if ($RTEcounter !== NULL) {
1287 GeneralUtility::deprecationLog('$RTEcounter parameter is deprecated and ignored');
1288 }
1289 $contents = $this->buildJSMainLangArray() . LF;
1290 foreach ($this->pluginEnabledCumulativeArray as $pluginId) {
1291 $contents .= $this->buildJSLangArray($pluginId) . LF;
1292 }
1293 return $this->writeTemporaryFile('', $this->language . '_' . $this->OutputCharset, 'js', $contents, TRUE);
1294 }
1295
1296 /**
1297 * Return a Javascript localization array for the plugin
1298 *
1299 * @param string $plugin: identification string of the plugin
1300 * @return string Javascript localization array
1301 */
1302 public function buildJSLangArray($plugin) {
1303 $extensionKey = is_object($this->registeredPlugins[$plugin]) ? $this->registeredPlugins[$plugin]->getExtensionKey() : $this->ID;
1304 $LOCAL_LANG = GeneralUtility::readLLfile('EXT:' . $extensionKey . '/htmlarea/plugins/' . $plugin . '/locallang.xlf', $this->language, 'utf-8', 1);
1305 $JSLanguageArray = 'HTMLArea.I18N["' . $plugin . '"] = new Object();' . LF;
1306 if (is_array($LOCAL_LANG)) {
1307 if (!empty($LOCAL_LANG[$this->language])) {
1308 $defaultLocalLang = $LOCAL_LANG['default'];
1309 \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($defaultLocalLang, $LOCAL_LANG[$this->language], TRUE, FALSE);
1310 $LOCAL_LANG[$this->language] = $defaultLocalLang;
1311 } else {
1312 $LOCAL_LANG[$this->language] = $LOCAL_LANG['default'];
1313 }
1314 $JSLanguageArray .= 'HTMLArea.I18N["' . $plugin . '"] = ' . json_encode($LOCAL_LANG[$this->language]) . ';' . LF;
1315 }
1316 return $JSLanguageArray;
1317 }
1318
1319 /**
1320 * Return the JS code of the toolbar configuration for the HTMLArea editor
1321 *
1322 * @return string the JS code as nested JS arrays
1323 */
1324 protected function getJSToolbarArray() {
1325 // The toolbar array
1326 $toolbar = array();
1327 // The current row; a "linebreak" ends the current row
1328 $row = array();
1329 // The current group; each group is between "bar"s; a "linebreak" ends the current group
1330 $group = array();
1331 // Process each toolbar item in the toolbar order list
1332 foreach ($this->toolbarOrderArray as $item) {
1333 switch ($item) {
1334 case 'linebreak':
1335 // Add row to toolbar if not empty
1336 if (!empty($group)) {
1337 $row[] = $group;
1338 $group = array();
1339 }
1340 if (!empty($row)) {
1341 $toolbar[] = $row;
1342 $row = array();
1343 }
1344 break;
1345 case 'bar':
1346 // Add group to row if not empty
1347 if (!empty($group)) {
1348 $row[] = $group;
1349 $group = array();
1350 }
1351 break;
1352 case 'space':
1353 if (end($group) != $this->convertToolbarForHTMLArea($item)) {
1354 $group[] = $this->convertToolbarForHTMLArea($item);
1355 }
1356 break;
1357 default:
1358 if (in_array($item, $this->toolbar)) {
1359 // Add the item to the group
1360 $convertedItem = $this->convertToolbarForHTMLArea($item);
1361 if ($convertedItem) {
1362 $group[] = $convertedItem;
1363 }
1364 }
1365 }
1366 }
1367 // Add the last group and last line, if not empty
1368 if (!empty($group)) {
1369 $row[] = $group;
1370 }
1371 if (!empty($row)) {
1372 $toolbar[] = $row;
1373 }
1374 return json_encode($toolbar);
1375 }
1376
1377 /**
1378 * Localize a string using the language of the content element rather than the language of the BE interface
1379 *
1380 * @param string string: the label to be localized
1381 * @return string Localized string.
1382 */
1383 public function getLLContent($string) {
1384 return GeneralUtility::quoteJSvalue($this->contentLanguageService->sL($string));
1385 }
1386
1387 public function getPageConfigLabel($string, $JScharCode = 1) {
1388 if ($this->is_FE()) {
1389 if (substr($string, 0, 4) !== 'LLL:') {
1390 // A pure string coming from Page TSConfig must be in utf-8
1391 $label = $GLOBALS['TSFE']->csConvObj->conv($GLOBALS['TSFE']->sL(trim($string)), 'utf-8', $this->OutputCharset);
1392 } else {
1393 $label = $GLOBALS['TSFE']->csConvObj->conv($GLOBALS['TSFE']->sL(trim($string)), $this->charset, $this->OutputCharset);
1394 }
1395 $label = str_replace('"', '\\"', str_replace('\\\'', '\'', $label));
1396 $label = $JScharCode ? $this->feJScharCode($label) : $label;
1397 } else {
1398 if (substr($string, 0, 4) !== 'LLL:') {
1399 $label = $string;
1400 } else {
1401 $label = $GLOBALS['LANG']->sL(trim($string));
1402 }
1403 $label = str_replace('"', '\\"', str_replace('\\\'', '\'', $label));
1404 $label = $JScharCode ? GeneralUtility::quoteJSvalue($label) : $label;
1405 }
1406 return $label;
1407 }
1408
1409 /**
1410 * JavaScript char code
1411 *
1412 * @param string $str
1413 * @return string
1414 */
1415 public function feJScharCode($str) {
1416 // Convert string to UTF-8:
1417 if ($this->OutputCharset != 'utf-8') {
1418 $str = $GLOBALS['TSFE']->csConvObj->utf8_encode($str, $this->OutputCharset);
1419 }
1420 // Convert the UTF-8 string into a 'JavaScript-safe' encoded string:
1421 return GeneralUtility::quoteJSvalue($str);
1422 }
1423
1424 /**
1425 * Make a file name relative to the PATH_site or to the PATH_typo3
1426 *
1427 * @param string $filename: a file name of the form EXT:.... or relative to the PATH_site
1428 * @return string the file name relative to the PATH_site if in frontend or relative to the PATH_typo3 if in backend
1429 */
1430 public function getFullFileName($filename) {
1431 if (substr($filename, 0, 4) == 'EXT:') {
1432 // extension
1433 list($extKey, $local) = explode('/', substr($filename, 4), 2);
1434 $newFilename = '';
1435 if ((string)$extKey !== '' && ExtensionManagementUtility::isLoaded($extKey) && (string)$local !== '') {
1436 $newFilename = ($this->is_FE() || $this->isFrontendEditActive() ? ExtensionManagementUtility::siteRelPath($extKey) : $this->backPath . ExtensionManagementUtility::extRelPath($extKey)) . $local;
1437 }
1438 } else {
1439 $path = ($this->is_FE() || $this->isFrontendEditActive() ? '' : $this->backPath . '../');
1440 $newFilename = $path . ($filename[0] === '/' ? substr($filename, 1) : $filename);
1441 }
1442 return GeneralUtility::resolveBackPath($newFilename);
1443 }
1444
1445 /**
1446 * Return the Javascript code for copying the HTML code from the editor into the hidden input field.
1447 * This is for submit function of the form.
1448 *
1449 * @param int $RTEcounter: The index number of the current RTE editing area within the form. @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8
1450 * @param string $formName: the name of the form
1451 * @param string $textareaId: the id of the textarea
1452 * @param string $textareaName: the name of the textarea
1453 * @return string Javascript code
1454 */
1455 public function setSaveRTE($RTEcounter, $formName, $textareaId, $textareaName) {
1456 if ($RTEcounter !== NULL) {
1457 GeneralUtility::deprecationLog('$RTEcounter parameter is deprecated and ignored');
1458 }
1459 return 'if (RTEarea["' . $textareaId . '"]) { document.' . $formName . '["' . $textareaName . '"].value = RTEarea["' . $textareaId . '"].editor.getHTML(); } else { OK = 0; };';
1460 }
1461
1462 /**
1463 * Return the Javascript code for copying the HTML code from the editor into the hidden input field.
1464 * This is for submit function of the form.
1465 *
1466 * @param int $RTEcounter: The index number of the current RTE editing area within the form.
1467 * @param string $formName: the name of the form
1468 * @param string $textareaId: the id of the textarea
1469 * @return string Javascript code
1470 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
1471 */
1472 public function setDeleteRTE($RTEcounter, $formName, $textareaId) {
1473 GeneralUtility::logDeprecatedFunction();
1474 return 'if (RTEarea["' . $textareaId . '"]) { RTEarea["' . $textareaId . '"].deleted = true;}';
1475 }
1476
1477 /**
1478 * Return TRUE if we are in the FE, but not in the FE editing feature of BE.
1479 *
1480 * @return bool
1481 */
1482 public function is_FE() {
1483 return is_object($GLOBALS['TSFE']) && !$this->isFrontendEditActive() && TYPO3_MODE == 'FE';
1484 }
1485
1486 /**
1487 * Checks whether frontend editing is active.
1488 *
1489 * @return boolean
1490 */
1491 public function isFrontendEditActive() {
1492 return is_object($GLOBALS['TSFE']) && $GLOBALS['TSFE']->beUserLogin && $GLOBALS['BE_USER']->frontendEdit instanceof \TYPO3\CMS\Core\FrontendEditing\FrontendEditingController;
1493 }
1494
1495 /**
1496 * Client Browser Information
1497 *
1498 * @param string $userAgent: The useragent string, \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('HTTP_USER_AGENT')
1499 * @return array Contains keys "useragent", "browser", "version", "system
1500 */
1501 public function clientInfo($userAgent = '') {
1502 if (!$userAgent) {
1503 $userAgent = GeneralUtility::getIndpEnv('HTTP_USER_AGENT');
1504 }
1505 $browserInfo = \TYPO3\CMS\Core\Utility\ClientUtility::getBrowserInfo($userAgent);
1506 // Known engines: order is not irrelevant!
1507 $knownEngines = array('opera', 'msie', 'gecko', 'webkit');
1508 if (is_array($browserInfo['all'])) {
1509 foreach ($knownEngines as $engine) {
1510 if ($browserInfo['all'][$engine]) {
1511 $browserInfo['browser'] = $engine;
1512 $browserInfo['version'] = \TYPO3\CMS\Core\Utility\ClientUtility::getVersion($browserInfo['all'][$engine]);
1513 break;
1514 }
1515 }
1516 }
1517 return $browserInfo;
1518 }
1519
1520 /**
1521 * Log usage of deprecated Page TS Config Property
1522 *
1523 * @param string $deprecatedProperty: Name of deprecated property
1524 * @param string $useProperty: Name of property to use instead
1525 * @param string $version: Version of TYPO3 in which the property will be removed
1526 * @return void
1527 */
1528 public function logDeprecatedProperty($deprecatedProperty, $useProperty, $version) {
1529 $backendUser = $this->getBackendUserAuthentication();
1530 $languageServire = $this->getLanguageService();
1531 if (!$this->thisConfig['logDeprecatedProperties.']['disabled']) {
1532 $message = sprintf('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.', $deprecatedProperty, $useProperty, $version, $this->thePid);
1533 GeneralUtility::deprecationLog($message);
1534 if (is_object($GLOBALS['BE_USER']) && $this->thisConfig['logDeprecatedProperties.']['logAlsoToBELog']) {
1535 $message = sprintf($languageServire->getLL('deprecatedPropertyMessage'), $deprecatedProperty, $useProperty, $version, $this->thePid);
1536 $backendUser->simplelog($message, $this->ID);
1537 }
1538 }
1539 }
1540
1541 /***************************
1542 *
1543 * OTHER FUNCTIONS: (from Classic RTE)
1544 *
1545 ***************************/
1546 /**
1547 * @return string
1548 */
1549 public function RTEtsConfigParams() {
1550 if ($this->is_FE()) {
1551 return '';
1552 } else {
1553 $p = BackendUtility::getSpecConfParametersFromArray($this->specConf['rte_transform']['parameters']);
1554 return $this->elementParts[0] . ':' . $this->elementParts[1] . ':' . $this->elementParts[2] . ':' . $this->thePid . ':' . $this->typeVal . ':' . $this->tscPID . ':' . $p['imgpath'];
1555 }
1556 }
1557
1558 /**
1559 * Clean list
1560 *
1561 * @param string $str
1562 * @return string
1563 */
1564 public function cleanList($str) {
1565 if (strstr($str, '*')) {
1566 $str = '*';
1567 } else {
1568 $str = implode(',', array_unique(GeneralUtility::trimExplode(',', $str, TRUE)));
1569 }
1570 return $str;
1571 }
1572
1573 /**
1574 * Filter style element
1575 *
1576 * @param string $elValue
1577 * @param string $matchList
1578 * @return string
1579 */
1580 public function filterStyleEl($elValue, $matchList) {
1581 $matchParts = GeneralUtility::trimExplode(',', $matchList, TRUE);
1582 $styleParts = explode(';', $elValue);
1583 $nStyle = array();
1584 foreach ($styleParts as $k => $p) {
1585 $pp = GeneralUtility::trimExplode(':', $p);
1586 if ($pp[0] && $pp[1]) {
1587 foreach ($matchParts as $el) {
1588 $star = substr($el, -1) == '*';
1589 if ($pp[0] === (string)$el || $star && GeneralUtility::isFirstPartOfStr($pp[0], substr($el, 0, -1))) {
1590 $nStyle[] = $pp[0] . ':' . $pp[1];
1591 } else {
1592 unset($styleParts[$k]);
1593 }
1594 }
1595 } else {
1596 unset($styleParts[$k]);
1597 }
1598 }
1599 return implode('; ', $nStyle);
1600 }
1601
1602 /**
1603 * @return LanguageService
1604 */
1605 protected function getLanguageService() {
1606 return $GLOBALS['LANG'];
1607 }
1608
1609 /**
1610 * @return BackendUserAuthentication
1611 */
1612 protected function getBackendUserAuthentication() {
1613 return $GLOBALS['BE_USER'];
1614 }
1615
1616 /**
1617 * @return DatabaseConnection
1618 */
1619 protected function getDatabaseConnection() {
1620 return $GLOBALS['TYPO3_DB'];
1621 }
1622 }