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