[FEATURE] Trigger execution of a specific task from CLI
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / class.tx_rtehtmlarea_base.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2004-2011 Kasper Skårhøj (kasper@typo3.com)
6 * (c) 2004-2011 Philipp Borgmann <philipp.borgmann@gmx.de>
7 * (c) 2004-2012 Stanislas Rolland <typo3(arobas)sjbr.ca>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * A RTE using the htmlArea editor
31 *
32 * @author Philipp Borgmann <philipp.borgmann@gmx.de>
33 * @author Stanislas Rolland <typo3(arobas)sjbr.ca>
34 */
35 class tx_rtehtmlarea_base extends t3lib_rteapi {
36 // Configuration of supported browsers
37 var $conf_supported_browser = array (
38 'msie' => array (
39 array (
40 'version' => 6.0,
41 'system' => array(
42 'allowed' => array(
43 'winNT',
44 'win98',
45 'win95',
46 ),
47 ),
48 ),
49 ),
50 'gecko' => array (
51 array (
52 'version' => 1.8,
53 ),
54 ),
55 'webkit' => array (
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 var $conf_toolbar_hide = array (
81 'showhelp', // Has no content yet
82 );
83
84 // The order of the toolbar: the name is the TYPO3-button name
85 var $defaultToolbarOrder;
86
87 // Conversion array: TYPO3 button names to htmlArea button names
88 var $convertToolbarForHtmlAreaArray = array (
89 'showhelp' => 'ShowHelp',
90 'space' => 'space',
91 'bar' => 'separator',
92 'linebreak' => 'linebreak',
93 );
94
95 var $pluginButton = array();
96 var $pluginLabel = array();
97 // Alternative style for RTE <div> tag.
98 public $RTEdivStyle;
99 // Relative path to this extension. It ends with "/"
100 public $extHttpPath;
101 public $backPath = '';
102 // TYPO3 site url
103 public $siteURL;
104 // TYPO3 host url
105 public $hostURL;
106 // Typo3 version
107 public $typoVersion;
108 // Identifies the RTE as being the one from the "rtehtmlarea" extension if any external code needs to know
109 var $ID = 'rtehtmlarea';
110 // If set, the content goes into a regular TEXT area field - for developing testing of transformations.
111 var $debugMode = FALSE;
112 // For the editor
113 var $client;
114
115 /**
116 * Reference to parent object, which is an instance of the TCEforms
117 *
118 * @var t3lib_TCEforms
119 */
120 var $TCEform;
121 var $elementId;
122 var $elementParts;
123 var $tscPID;
124 var $typeVal;
125 var $thePid;
126 var $RTEsetup;
127 var $thisConfig;
128 var $confValues;
129 public $language;
130 public $contentTypo3Language;
131 public $contentISOLanguage;
132 public $charset = 'utf-8';
133 public $contentCharset = 'utf-8';
134 public $OutputCharset = 'utf-8';
135 var $editorCSS;
136 var $specConf;
137 var $toolbar = array(); // Save the buttons for the toolbar
138 var $toolbarOrderArray = array();
139 protected $pluginEnabledArray = array(); // Array of plugin id's enabled in the current RTE editing area
140 protected $pluginEnabledCumulativeArray = array(); // Cumulative array of plugin id's enabled so far in any of the RTE editing areas of the form
141 public $registeredPlugins = array(); // Array of registered plugins indexed by their plugin Id's
142 protected $fullScreen = FALSE;
143 protected $pageRenderer;
144
145 /**
146 * Returns TRUE if the RTE is available. Here you check if the browser requirements are met.
147 * If there are reasons why the RTE cannot be displayed you simply enter them as text in ->errorLog
148 *
149 * @return boolean TRUE if this RTE object offers an RTE in the current browser environment
150 */
151 function isAvailable() {
152
153 $this->client = $this->clientInfo();
154 $this->errorLog = array();
155 if (!$this->debugMode) { // If debug-mode, let any browser through
156 $rteIsAvailable = FALSE;
157 $rteConfBrowser = $this->conf_supported_browser;
158 if (is_array($rteConfBrowser)) {
159 foreach ($rteConfBrowser as $browser => $browserConf) {
160 if ($browser == $this->client['browser']) {
161 // Config for Browser found, check it:
162 if (is_array($browserConf)) {
163 foreach ($browserConf as $browserConfSub) {
164 if ($browserConfSub['version'] <= $this->client['version'] || empty($browserConfSub['version'])) {
165 // Version is supported
166 if (is_array($browserConfSub['system'])) {
167 // Check against allowed systems
168 if (is_array($browserConfSub['system']['allowed'])) {
169 foreach ($browserConfSub['system']['allowed'] as $system) {
170 if (in_array($system, $this->client['all_systems'])) {
171 $rteIsAvailable = TRUE;
172 break;
173 }
174 }
175 } else {
176 // All allowed
177 $rteIsAvailable = TRUE;
178 }
179 // Check against disallowed systems
180 if (is_array($browserConfSub['system']['disallowed'])) {
181 foreach ($browserConfSub['system']['disallowed'] as $system) {
182 if (in_array($system, $this->client['all_systems'])) {
183 $rteIsAvailable = FALSE;
184 break;
185 }
186 }
187 }
188 } else {
189 // No system config: system is supported
190 $rteIsAvailable = TRUE;
191 break;
192 }// End of System
193 }// End of Version
194 }// End of foreach-BrowserSubpart
195 } else {
196 // no config for this browser found, so all versions or system with this browsers are allow
197 $rteIsAvailable = TRUE;
198 break;
199 }
200 } // End of Browser Check
201 } // foreach: Browser Check
202 } else {
203 // no Browser config for this RTE-Editor, so all Clients are allow
204 }
205 if (!$rteIsAvailable) {
206 $this->errorLog[] = 'RTE: Browser not supported.';
207 }
208 if (t3lib_utility_VersionNumber::convertVersionNumberToInteger(TYPO3_version) < 4000000) {
209 $rteIsAvailable = FALSE;
210 $this->errorLog[] = 'rte: This version of htmlArea RTE cannot run under this version of TYPO3.';
211 }
212 }
213 return $rteIsAvailable;
214 }
215
216 /**
217 * Draws the RTE as an iframe
218 *
219 * @param object Reference to parent object, which is an instance of the TCEforms.
220 * @param string The table name
221 * @param string The field name
222 * @param array The current row from which field is being rendered
223 * @param array 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.
224 * @param array "special" configuration - what is found at position 4 in the types configuration of a field from record, parsed into an array.
225 * @param array Configuration for RTEs; A mix between TSconfig and otherwise. Contains configuration for display, which buttons are enabled, additional transformation information etc.
226 * @param string Record "type" field value.
227 * @param string 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!
228 * @param integer PID value of record (true parent page id)
229 * @return string HTML code for RTE!
230 */
231
232 function drawRTE(&$parentObject, $table, $field, $row, $PA, $specConf, $thisConfig, $RTEtypeVal, $RTErelPath, $thePidValue) {
233 global $LANG, $TYPO3_DB, $TYPO3_CONF_VARS;
234
235 $this->TCEform = $parentObject;
236 $inline = $this->TCEform->inline;
237 $LANG->includeLLFile('EXT:' . $this->ID . '/locallang.xml');
238 $this->client = $this->clientInfo();
239 $this->typoVersion = t3lib_utility_VersionNumber::convertVersionNumberToInteger(TYPO3_version);
240 $this->userUid = 'BE_' . $GLOBALS['BE_USER']->user['uid'];
241
242 // Draw form element:
243 if ($this->debugMode) { // Draws regular text area (debug mode)
244 $item = parent::drawRTE($this->TCEform, $table, $field, $row, $PA, $specConf, $thisConfig, $RTEtypeVal, $RTErelPath, $thePidValue);
245 } else { // Draw real RTE
246
247 /* =======================================
248 * INIT THE EDITOR-SETTINGS
249 * =======================================
250 */
251 // Set backPath
252 $this->backPath = $this->TCEform->backPath;
253 // Get the path to this extension:
254 $this->extHttpPath = $this->backPath . t3lib_extMgm::extRelPath($this->ID);
255 // Get the site URL
256 $this->siteURL = t3lib_div::getIndpEnv('TYPO3_SITE_URL');
257 // Get the host URL
258 $this->hostURL = $this->siteURL . TYPO3_mainDir;
259 // Element ID + pid
260 $this->elementId = $PA['itemFormElName']; // Form element name
261 $this->elementParts = explode('][', preg_replace('/\]$/', '', preg_replace('/^(TSFE_EDIT\[data\]\[|data\[)/', '', $this->elementId)));
262 // Find the page PIDs:
263 list($this->tscPID, $this->thePid) = t3lib_BEfunc::getTSCpid(trim($this->elementParts[0]), trim($this->elementParts[1]), $thePidValue);
264
265 // Record "types" field value:
266 $this->typeVal = $RTEtypeVal; // TCA "types" value for record
267
268 // Find "thisConfig" for record/editor:
269 unset($this->RTEsetup);
270 $this->RTEsetup = $GLOBALS['BE_USER']->getTSConfig('RTE', t3lib_BEfunc::getPagesTSconfig($this->tscPID));
271 $this->thisConfig = $thisConfig;
272
273 // Special configuration and default extras:
274 $this->specConf = $specConf;
275
276 if ($this->thisConfig['forceHTTPS']) {
277 $this->extHttpPath = preg_replace('/^(http|https)/', 'https', $this->extHttpPath);
278 $this->siteURL = preg_replace('/^(http|https)/', 'https', $this->siteURL);
279 $this->hostURL = preg_replace('/^(http|https)/', 'https', $this->hostURL);
280 }
281 // Register RTE windows
282 $this->TCEform->RTEwindows[] = $PA['itemFormElName'];
283 $textAreaId = preg_replace('/[^a-zA-Z0-9_:.-]/', '_', $PA['itemFormElName']);
284 $textAreaId = htmlspecialchars(preg_replace('/^[^a-zA-Z]/', 'x', $textAreaId));
285
286 /* =======================================
287 * LANGUAGES & CHARACTER SETS
288 * =======================================
289 */
290
291 // Languages: interface and content
292 $this->language = $LANG->lang;
293 if ($this->language == 'default' || !$this->language) {
294 $this->language = 'en';
295 }
296 $this->contentTypo3Language = ($this->language == 'en') ? 'default' : $this->language;
297 $this->contentISOLanguage = 'en';
298 $this->contentLanguageUid = ($row['sys_language_uid'] > 0) ? $row['sys_language_uid'] : 0;
299 if (t3lib_extMgm::isLoaded('static_info_tables')) {
300 if ($this->contentLanguageUid) {
301 $tableA = 'sys_language';
302 $tableB = 'static_languages';
303 $languagesUidsList = $this->contentLanguageUid;
304 $selectFields = $tableA . '.uid,' . $tableB . '.lg_iso_2,' . $tableB . '.lg_country_iso_2,' . $tableB . '.lg_typo3';
305 $tableAB = $tableA . ' LEFT JOIN ' . $tableB . ' ON ' . $tableA . '.static_lang_isocode=' . $tableB . '.uid';
306 $whereClause = $tableA . '.uid IN (' . $languagesUidsList . ') ';
307 $whereClause .= t3lib_BEfunc::BEenableFields($tableA);
308 $whereClause .= t3lib_BEfunc::deleteClause($tableA);
309 $res = $TYPO3_DB->exec_SELECTquery($selectFields, $tableAB, $whereClause);
310 while($languageRow = $TYPO3_DB->sql_fetch_assoc($res)) {
311 $this->contentISOLanguage = strtolower(trim($languageRow['lg_iso_2']).(trim($languageRow['lg_country_iso_2'])?'_'.trim($languageRow['lg_country_iso_2']):''));
312 $this->contentTypo3Language = trim($languageRow['lg_typo3']) ? strtolower(trim($languageRow['lg_typo3'])) : 'default';
313 }
314 } else {
315 $this->contentISOLanguage = trim($this->thisConfig['defaultContentLanguage']) ? trim($this->thisConfig['defaultContentLanguage']) : 'en';
316 $selectFields = 'lg_iso_2, lg_typo3';
317 $tableAB = 'static_languages';
318 $whereClause = 'lg_iso_2 = ' . $TYPO3_DB->fullQuoteStr(strtoupper($this->contentISOLanguage), $tableAB);
319 $res = $TYPO3_DB->exec_SELECTquery($selectFields, $tableAB, $whereClause);
320 while($languageRow = $TYPO3_DB->sql_fetch_assoc($res)) {
321 $this->contentTypo3Language = trim($languageRow['lg_typo3']) ? strtolower(trim($languageRow['lg_typo3'])) : 'default';
322 }
323 }
324 }
325
326 /* =======================================
327 * TOOLBAR CONFIGURATION
328 * =======================================
329 */
330 $this->initializeToolbarConfiguration();
331
332 /* =======================================
333 * SET STYLES
334 * =======================================
335 */
336 // Check if wizard_rte called this for fullscreen edtition
337 if (basename(PATH_thisScript) == 'wizard_rte.php') {
338 $this->fullScreen = TRUE;
339 $RTEWidth = '100%';
340 $RTEHeight = '100%';
341 $RTEPaddingRight = '0';
342 $editorWrapWidth = '100%';
343 } else {
344 $RTEWidth = isset($GLOBALS['BE_USER']->userTS['options.']['RTESmallWidth']) ? $GLOBALS['BE_USER']->userTS['options.']['RTESmallWidth'] : '530';
345 $RTEHeight = isset($GLOBALS['BE_USER']->userTS['options.']['RTESmallHeight']) ? $GLOBALS['BE_USER']->userTS['options.']['RTESmallHeight'] : '380';
346 $RTEWidth = $RTEWidth + ($this->TCEform->docLarge ? (isset($GLOBALS['BE_USER']->userTS['options.']['RTELargeWidthIncrement']) ? $GLOBALS['BE_USER']->userTS['options.']['RTELargeWidthIncrement'] : '150') : 0);
347 $RTEWidth -= ($inline->getStructureDepth() > 0 ? ($inline->getStructureDepth()+1)*$inline->getLevelMargin() : 0);
348 $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']);
349 if ($RTEWidthOverride) {
350 if (strstr($RTEWidthOverride, '%')) {
351 if ($this->client['browser'] != 'msie') {
352 $RTEWidth = (intval($RTEWidthOverride) > 0) ? $RTEWidthOverride : '100%';
353 }
354 } else {
355 $RTEWidth = (intval($RTEWidthOverride) > 0) ? intval($RTEWidthOverride) : $RTEWidth;
356 }
357 }
358 $RTEWidth = strstr($RTEWidth, '%') ? $RTEWidth : $RTEWidth . 'px';
359 $RTEHeight = $RTEHeight + ($this->TCEform->docLarge ? (isset($GLOBALS['BE_USER']->userTS['options.']['RTELargeHeightIncrement']) ? $GLOBALS['BE_USER']->userTS['options.']['RTELargeHeightIncrement'] : 0) : 0);
360 $RTEHeightOverride = (is_object($GLOBALS['BE_USER']) && isset($GLOBALS['BE_USER']->uc['rteHeight']) && intval($GLOBALS['BE_USER']->uc['rteHeight'])) ? intval($GLOBALS['BE_USER']->uc['rteHeight']) : intval($this->thisConfig['RTEHeightOverride']);
361 $RTEHeight = ($RTEHeightOverride > 0) ? $RTEHeightOverride : $RTEHeight;
362 $RTEPaddingRight = '2px';
363 $editorWrapWidth = '99%';
364 }
365 $editorWrapHeight = '100%';
366 $this->RTEdivStyle = 'position:relative; left:0px; top:0px; height:' . $RTEHeight . 'px; width:' . $RTEWidth . '; border: 1px solid black; padding: 2px ' . $RTEPaddingRight . ' 2px 2px;';
367 /* =======================================
368 * LOAD CSS AND JAVASCRIPT
369 * =======================================
370 */
371 $this->pageRenderer = $GLOBALS['SOBE']->doc->getPageRenderer();
372 // Preloading the pageStyle and including RTE skin stylesheets
373 $this->addPageStyle();
374 $this->addSkin();
375 // Register RTE in JS
376 $this->TCEform->additionalJS_post[] = $this->registerRTEinJS($this->TCEform->RTEcounter, $table, $row['uid'], $field, $textAreaId);
377 // Set the save option for the RTE
378 $this->TCEform->additionalJS_submit[] = $this->setSaveRTE($this->TCEform->RTEcounter, $this->TCEform->formName, $textAreaId, $PA['itemFormElName']);
379 $this->TCEform->additionalJS_delete[] = $this->setDeleteRTE($this->TCEform->RTEcounter, $this->TCEform->formName, $textAreaId);
380 // Loading ExtJs inline code
381 $this->pageRenderer->enableExtJSQuickTips();
382 // Add TYPO3 notifications JavaScript
383 $this->pageRenderer->addJsFile('../t3lib/js/extjs/notifications.js');
384 // Add RTE JavaScript
385 $this->addRteJsFiles($this->TCEform->RTEcounter);
386 $this->pageRenderer->addJsFile($this->buildJSMainLangFile($this->TCEform->RTEcounter));
387 $this->pageRenderer->addJsInlineCode('HTMLArea-init', $this->getRteInitJsCode(), TRUE);
388 /* =======================================
389 * DRAW THE EDITOR
390 * =======================================
391 */
392
393 // Transform value:
394 $value = $this->transformContent('rte', $PA['itemFormElValue'], $table, $field, $row, $specConf, $thisConfig, $RTErelPath, $thePidValue);
395
396 // Further content transformation by registered plugins
397 foreach ($this->registeredPlugins as $pluginId => $plugin) {
398 if ($this->isPluginEnabled($pluginId) && method_exists($plugin, 'transformContent')) {
399 $value = $plugin->transformContent($value);
400 }
401 }
402 // Draw the textarea
403 $visibility = 'hidden';
404 $item = $this->triggerField($PA['itemFormElName']).'
405 <div id="pleasewait' . $textAreaId . '" class="pleasewait" style="display: block;" >' . $LANG->getLL('Please wait') . '</div>
406 <div id="editorWrap' . $textAreaId . '" class="editorWrap" style="visibility: hidden; width:' . $editorWrapWidth . '; height:' . $editorWrapHeight . ';">
407 <textarea id="RTEarea' . $textAreaId . '" name="'.htmlspecialchars($PA['itemFormElName']).'" rows="0" cols="0" style="'.t3lib_div::deHSCentities(htmlspecialchars($this->RTEdivStyle)).'">'.t3lib_div::formatForTextarea($value).'</textarea>
408 </div>' . LF;
409 }
410
411 // Return form item:
412 return $item;
413 }
414
415 /**
416 * Add link to content style sheet to document header
417 *
418 * @return void
419 */
420 protected function addPageStyle() {
421 $this->addStyleSheet(
422 'rtehtmlarea-page-style',
423 $this->getContentCssFileName(),
424 'htmlArea RTE Content CSS',
425 'alternate stylesheet'
426 );
427 }
428
429 /**
430 * Get the name of the contentCSS file to use
431 *
432 * @return the full file name of the content css file to use
433 */
434 protected function getContentCssFileName() {
435 // Get stylesheet file name from Page TSConfig if any
436 $fileName = trim($this->thisConfig['contentCSS']);
437 if ($fileName) {
438 $fileName = $this->getFullFileName($fileName);
439 }
440 $absolutePath = $fileName
441 ? t3lib_div::resolveBackPath(PATH_site . (($this->is_FE() || $this->isFrontendEditActive()) ? '' : TYPO3_mainDir) . $fileName)
442 : '';
443
444 // Fallback to default content css file if configured file does not exists or is of zero size
445 if (!$fileName || !file_exists($absolutePath) || !filesize($absolutePath)) {
446 $fileName = $this->getFullFileName('EXT:' . $this->ID . '/res/contentcss/default.css');
447 }
448 return $fileName;
449 }
450
451 /**
452 * Add links to skin style sheet(s) to document header
453 *
454 * @return void
455 */
456 protected function addSkin() {
457 // Get skin file name from Page TSConfig if any
458 $skinFilename = trim($this->thisConfig['skin']) ? trim($this->thisConfig['skin']) : 'EXT:' . $this->ID . '/htmlarea/skins/default/htmlarea.css';
459 $this->editorCSS = $this->getFullFileName($skinFilename);
460 $skinDir = dirname($this->editorCSS);
461 // Editing area style sheet
462 $this->editedContentCSS = $skinDir . '/htmlarea-edited-content.css';
463 $this->addStyleSheet(
464 'rtehtmlarea-editing-area-skin',
465 $this->editedContentCSS
466 );
467 // Main skin
468 $this->addStyleSheet(
469 'rtehtmlarea-skin',
470 $this->editorCSS
471 );
472 // Additional icons from registered plugins
473 foreach ($this->pluginEnabledCumulativeArray[$this->TCEform->RTEcounter] as $pluginId) {
474 if (is_object($this->registeredPlugins[$pluginId])) {
475 $pathToSkin = $this->registeredPlugins[$pluginId]->getPathToSkin();
476 if ($pathToSkin) {
477 $key = $this->registeredPlugins[$pluginId]->getExtensionKey();
478 $this->addStyleSheet(
479 'rtehtmlarea-plugin-' . $pluginId . '-skin',
480 ($this->is_FE() ? t3lib_extMgm::siteRelPath($key) : $this->backPath . t3lib_extMgm::extRelPath($key)) . $pathToSkin
481 );
482 }
483 }
484 }
485 }
486
487 /**
488 * Add style sheet file to document header
489 *
490 * @param string $key: some key identifying the style sheet
491 * @param string $href: uri to the style sheet file
492 * @param string $title: value for the title attribute of the link element
493 * @return string $relation: value for the rel attribute of the link element
494 * @return void
495 */
496 protected function addStyleSheet($key, $href, $title='', $relation='stylesheet') {
497 // If it was not known that an RTE-enabled would be created when the page was first created, the css would not be added to head
498 if (is_object($this->TCEform->inline) && $this->TCEform->inline->isAjaxCall) {
499 $this->TCEform->additionalCode_pre[$key] = '<link rel="' . $relation . '" type="text/css" href="' . $href . '" title="' . $title. '" />';
500 } else {
501 $this->pageRenderer->addCssFile($href, $relation, 'screen', $title);
502 }
503 }
504
505 /**
506 * Initialize toolbar configuration and enable registered plugins
507 *
508 * @return void
509 */
510 protected function initializeToolbarConfiguration() {
511
512 // Enable registred plugins
513 $this->enableRegisteredPlugins();
514
515 // Configure toolbar
516 $this->setToolbar();
517
518 // Check if some plugins need to be disabled
519 $this->setPlugins();
520
521 // Merge the list of enabled plugins with the lists from the previous RTE editing areas on the same form
522 $this->pluginEnabledCumulativeArray[$this->TCEform->RTEcounter] = $this->pluginEnabledArray;
523 if ($this->TCEform->RTEcounter > 1 && isset($this->pluginEnabledCumulativeArray[$this->TCEform->RTEcounter - 1]) && is_array($this->pluginEnabledCumulativeArray[$this->TCEform->RTEcounter - 1])) {
524 $this->pluginEnabledCumulativeArray[$this->TCEform->RTEcounter] = array_unique(
525 array_values(array_merge($this->pluginEnabledArray, $this->pluginEnabledCumulativeArray[$this->TCEform->RTEcounter - 1]))
526 );
527 }
528 }
529
530 /**
531 * Add registered plugins to the array of enabled plugins
532 *
533 */
534 function enableRegisteredPlugins() {
535 global $TYPO3_CONF_VARS;
536
537 // Traverse registered plugins
538 if (is_array($TYPO3_CONF_VARS['EXTCONF'][$this->ID]['plugins'])) {
539 foreach($TYPO3_CONF_VARS['EXTCONF'][$this->ID]['plugins'] as $pluginId => $pluginObjectConfiguration) {
540 $plugin = FALSE;
541 if (is_array($pluginObjectConfiguration) && count($pluginObjectConfiguration)) {
542 $plugin = t3lib_div::getUserObj($pluginObjectConfiguration['objectReference']);
543 }
544 if (is_object($plugin)) {
545 if ($plugin->main($this)) {
546 $this->registeredPlugins[$pluginId] = $plugin;
547 // Override buttons from previously registered plugins
548 $pluginButtons = t3lib_div::trimExplode(',', $plugin->getPluginButtons(), 1);
549 foreach ($this->pluginButton as $previousPluginId => $buttonList) {
550 $this->pluginButton[$previousPluginId] = implode(',', array_diff(t3lib_div::trimExplode(',', $this->pluginButton[$previousPluginId], 1), $pluginButtons));
551 }
552 $this->pluginButton[$pluginId] = $plugin->getPluginButtons();
553 $pluginLabels = t3lib_div::trimExplode(',', $plugin->getPluginLabels(), 1);
554 foreach ($this->pluginLabel as $previousPluginId => $labelList) {
555 $this->pluginLabel[$previousPluginId] = implode(',', array_diff(t3lib_div::trimExplode(',', $this->pluginLabel[$previousPluginId], 1), $pluginLabels));
556 }
557 $this->pluginLabel[$pluginId] = $plugin->getPluginLabels();
558 $this->pluginEnabledArray[] = $pluginId;
559 }
560 }
561 }
562 }
563 // Process overrides
564 $hidePlugins = array();
565 foreach ($this->registeredPlugins as $pluginId => $plugin) {
566 if ($plugin->addsButtons() && !$this->pluginButton[$pluginId]) {
567 $hidePlugins[] = $pluginId;
568 }
569 }
570 $this->pluginEnabledArray = array_unique(array_diff($this->pluginEnabledArray, $hidePlugins));
571 }
572
573 /**
574 * Set the toolbar config (only in this PHP-Object, not in JS):
575 *
576 */
577
578 function setToolbar() {
579 if ($this->client['browser'] == 'msie' || $this->client['browser'] == 'opera') {
580 $this->thisConfig['keepButtonGroupTogether'] = 0;
581 }
582
583 $this->defaultToolbarOrder = 'bar, blockstylelabel, blockstyle, space, textstylelabel, textstyle, linebreak,
584 bar, formattext, bold, strong, italic, emphasis, big, small, insertedtext, deletedtext, citation, code, definition, keyboard, monospaced, quotation, sample, variable, bidioverride, strikethrough, subscript, superscript, underline, span,
585 bar, fontstyle, space, fontsize, bar, formatblock, insertparagraphbefore, insertparagraphafter, blockquote, line,
586 bar, left, center, right, justifyfull,
587 bar, orderedlist, unorderedlist, definitionlist, definitionitem, outdent, indent, bar, lefttoright, righttoleft, language, showlanguagemarks,
588 bar, textcolor, bgcolor, textindicator,
589 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, acronym, bar, findreplace, spellcheck,
590 bar, chMode, inserttag, removeformat, bar, copy, cut, paste, pastetoggle, pastebehaviour, bar, undo, redo, bar, showhelp, about, linebreak,
591 ' . ($this->thisConfig['hideTableOperationsInToolbar'] ? '': 'bar, toggleborders,') . ' bar, tableproperties, tablerestyle, bar, rowproperties, rowinsertabove, rowinsertunder, rowdelete, rowsplit, bar,
592 columnproperties, columninsertbefore, columninsertafter, columndelete, columnsplit, bar,
593 cellproperties, cellinsertbefore, cellinsertafter, celldelete, cellsplit, cellmerge';
594
595 // Additional buttons from registered plugins
596 foreach($this->registeredPlugins as $pluginId => $plugin) {
597 if ($this->isPluginEnabled($pluginId)) {
598 $this->defaultToolbarOrder = $plugin->addButtonsToToolbar();
599 }
600 }
601 $toolbarOrder = $this->thisConfig['toolbarOrder'] ? $this->thisConfig['toolbarOrder'] : $this->defaultToolbarOrder;
602
603 // Getting rid of undefined buttons
604 $this->toolbarOrderArray = array_intersect(t3lib_div::trimExplode(',', $toolbarOrder, 1), t3lib_div::trimExplode(',', $this->defaultToolbarOrder, 1));
605 $toolbarOrder = array_unique(array_values($this->toolbarOrderArray));
606
607 // Fetching specConf for field from backend
608 $pList = is_array($this->specConf['richtext']['parameters']) ? implode(',', $this->specConf['richtext']['parameters']) : '';
609 if ($pList != '*') { // If not all
610 $show = is_array($this->specConf['richtext']['parameters']) ? $this->specConf['richtext']['parameters'] : array();
611 if ($this->thisConfig['showButtons']) {
612 if (!t3lib_div::inList($this->thisConfig['showButtons'], '*')) {
613 $show = array_unique(array_merge($show, t3lib_div::trimExplode(',', $this->thisConfig['showButtons'], 1)));
614 } else {
615 $show = array_unique(array_merge($show, $toolbarOrder));
616 }
617 }
618 if (is_array($this->thisConfig['showButtons.'])) {
619 foreach ($this->thisConfig['showButtons.'] as $buttonId => $value) {
620 if ($value) {
621 $show[] = $buttonId;
622 }
623 }
624 $show = array_unique($show);
625 }
626 } else {
627 $show = $toolbarOrder;
628 }
629
630 // Resticting to RTEkeyList for backend user
631 if(is_object($GLOBALS['BE_USER'])) {
632 $RTEkeyList = isset($GLOBALS['BE_USER']->userTS['options.']['RTEkeyList']) ? $GLOBALS['BE_USER']->userTS['options.']['RTEkeyList'] : '*';
633 if ($RTEkeyList != '*') { // If not all
634 $show = array_intersect($show, t3lib_div::trimExplode(',', $RTEkeyList, 1));
635 }
636 }
637
638 // Hiding buttons of disabled plugins
639 $hideButtons = array('space', 'bar', 'linebreak');
640 foreach ($this->pluginButton as $pluginId => $buttonList) {
641 if (!$this->isPluginEnabled($pluginId)) {
642 $buttonArray = t3lib_div::trimExplode(',', $buttonList, 1);
643 foreach ($buttonArray as $button) {
644 $hideButtons[] = $button;
645 }
646 }
647 }
648
649 // Hiding labels of disabled plugins
650 foreach ($this->pluginLabel as $pluginId => $label) {
651 if (!$this->isPluginEnabled($pluginId)) {
652 $hideButtons[] = $label;
653 }
654 }
655
656 // Hiding buttons
657 $show = array_diff($show, $this->conf_toolbar_hide, t3lib_div::trimExplode(',', $this->thisConfig['hideButtons'], 1));
658
659 // Apply toolbar constraints from registered plugins
660 foreach ($this->registeredPlugins as $pluginId => $plugin) {
661 if ($this->isPluginEnabled($pluginId) && method_exists($plugin, 'applyToolbarConstraints')) {
662 $show = $plugin->applyToolbarConstraints($show);
663 }
664 }
665 // Getting rid of the buttons for which we have no position
666 $show = array_intersect($show, $toolbarOrder);
667 $this->toolbar = $show;
668 }
669
670 /**
671 * Disable some plugins
672 *
673 */
674 function setPlugins() {
675
676 // Disabling a plugin that adds buttons if none of its buttons is in the toolbar
677 $hidePlugins = array();
678 foreach ($this->pluginButton as $pluginId => $buttonList) {
679 if ($this->registeredPlugins[$pluginId]->addsButtons()) {
680 $showPlugin = FALSE;
681 $buttonArray = t3lib_div::trimExplode(',', $buttonList, 1);
682 foreach ($buttonArray as $button) {
683 if (in_array($button, $this->toolbar)) {
684 $showPlugin = TRUE;
685 }
686 }
687 if (!$showPlugin) {
688 $hidePlugins[] = $pluginId;
689 }
690 }
691 }
692 $this->pluginEnabledArray = array_diff($this->pluginEnabledArray, $hidePlugins);
693
694 // Hiding labels of disabled plugins
695 $hideLabels = array();
696 foreach ($this->pluginLabel as $pluginId => $label) {
697 if (!$this->isPluginEnabled($pluginId)) {
698 $hideLabels[] = $label;
699 }
700 }
701 $this->toolbar = array_diff($this->toolbar, $hideLabels);
702
703 // Adding plugins declared as prerequisites by enabled plugins
704 $requiredPlugins = array();
705 foreach ($this->registeredPlugins as $pluginId => $plugin) {
706 if ($this->isPluginEnabled($pluginId)) {
707 $requiredPlugins = array_merge($requiredPlugins, t3lib_div::trimExplode(',', $plugin->getRequiredPlugins(), 1));
708 }
709 }
710 $requiredPlugins = array_unique($requiredPlugins);
711 foreach ($requiredPlugins as $pluginId) {
712 if (is_object($this->registeredPlugins[$pluginId]) && !$this->isPluginEnabled($pluginId)) {
713 $this->pluginEnabledArray[] = $pluginId;
714 }
715 }
716 $this->pluginEnabledArray = array_unique($this->pluginEnabledArray);
717
718 // Completing the toolbar conversion array for htmlArea
719 foreach ($this->registeredPlugins as $pluginId => $plugin) {
720 if ($this->isPluginEnabled($pluginId)) {
721 $this->convertToolbarForHtmlAreaArray = array_unique(array_merge($this->convertToolbarForHtmlAreaArray, $plugin->getConvertToolbarForHtmlAreaArray()));
722 }
723 }
724 }
725 /**
726 * Convert the TYPO3 names of buttons into the names for htmlArea RTE
727 *
728 * @param string buttonname (typo3-name)
729 *
730 * @return string buttonname (htmlarea-name)
731 */
732 function convertToolbarForHTMLArea($button) {
733 return $this->convertToolbarForHtmlAreaArray[$button];
734 }
735 /**
736 * Add RTE main scripts and plugin scripts
737 *
738 * @param string $RTEcounter: The index number of the current RTE editing area within the form.
739 *
740 * @return void
741 */
742 protected function addRteJsFiles($RTEcounter) {
743 $this->pageRenderer->addJsFile($this->getFullFileName('EXT:' . $this->ID . '/htmlarea/htmlarea.js'));
744 foreach ($this->pluginEnabledCumulativeArray[$RTEcounter] as $pluginId) {
745 $extensionKey = is_object($this->registeredPlugins[$pluginId]) ? $this->registeredPlugins[$pluginId]->getExtensionKey() : $this->ID;
746 $this->pageRenderer->addJsFile($this->getFullFileName('EXT:' . $extensionKey . '/htmlarea/plugins/' . $pluginId . '/' . strtolower(preg_replace('/([a-z])([A-Z])([a-z])/', '$1-$2$3', $pluginId)) . '.js'));
747 }
748 }
749 /**
750 * Return RTE initialization inline JavaScript code
751 *
752 * @return string RTE initialization inline JavaScript code
753 */
754 protected function getRteInitJsCode() {
755 return '
756 if (typeof(RTEarea) == "undefined") {
757 RTEarea = new Object();
758 RTEarea[0] = new Object();
759 RTEarea[0].version = "' . $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID]['version'] . '";
760 RTEarea[0].editorUrl = "' . $this->extHttpPath . 'htmlarea/";
761 RTEarea[0].editorCSS = "' . t3lib_div::createVersionNumberedFilename($this->editorCSS) . '";
762 RTEarea[0].editorSkin = "' . dirname($this->editorCSS) . '/";
763 RTEarea[0].editedContentCSS = "' . t3lib_div::createVersionNumberedFilename($this->editedContentCSS) . '";
764 RTEarea[0].hostUrl = "' . $this->hostURL . '";
765 RTEarea.init = function() {
766 if (typeof(HTMLArea) == "undefined" || !Ext.isReady) {
767 window.setTimeout("RTEarea.init();", 10);
768 } else {
769 Ext.QuickTips.init();
770 HTMLArea.init();
771 }
772 };
773 RTEarea.initEditor = function(editorNumber) {
774 if (typeof(HTMLArea) == "undefined" || !HTMLArea.isReady) {
775 RTEarea.initEditor.defer(40, null, [editorNumber]);
776 } else {
777 HTMLArea.initEditor(editorNumber);
778 }
779 };
780 }
781 RTEarea.init();';
782 }
783 /**
784 * Return the Javascript code for configuring the RTE
785 *
786 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
787 * @param string $table: The table that includes this RTE (optional, necessary for IRRE).
788 * @param string $uid: The uid of that table that includes this RTE (optional, necessary for IRRE).
789 * @param string $field: The field of that record that includes this RTE (optional).
790 *
791 * @return string the Javascript code for configuring the RTE
792 */
793 function registerRTEinJS($RTEcounter, $table = '', $uid = '', $field = '', $textAreaId = '') {
794 $configureRTEInJavascriptString = '
795 if (typeof(configureEditorInstance) == "undefined") {
796 configureEditorInstance = new Object();
797 }
798 configureEditorInstance["' . $textAreaId . '"] = function() {
799 if (typeof(RTEarea) == "undefined" || typeof(HTMLArea) == "undefined") {
800 window.setTimeout("configureEditorInstance[\'' . $textAreaId . '\']();", 40);
801 } else {
802 editornumber = "' . $textAreaId . '";
803 RTEarea[editornumber] = new Object();
804 RTEarea[editornumber].RTEtsConfigParams = "&RTEtsConfigParams=' . rawurlencode($this->RTEtsConfigParams()) . '";
805 RTEarea[editornumber].number = editornumber;
806 RTEarea[editornumber].deleted = false;
807 RTEarea[editornumber].textAreaId = "' . $textAreaId . '";
808 RTEarea[editornumber].id = "RTEarea" + editornumber;
809 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'])) . '";
810 RTEarea[editornumber].RTEHeightOverride = "' . ((is_object($GLOBALS['BE_USER']) && isset($GLOBALS['BE_USER']->uc['rteHeight']) && intval($GLOBALS['BE_USER']->uc['rteHeight'])) ? intval($GLOBALS['BE_USER']->uc['rteHeight']) : intval($this->thisConfig['RTEHeightOverride'])) . '";
811 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')) . ';
812 RTEarea[editornumber].maxHeight = "' . ((is_object($GLOBALS['BE_USER']) && isset($GLOBALS['BE_USER']->uc['rteMaxHeight']) && intval($GLOBALS['BE_USER']->uc['rteMaxHeight'])) ? trim($GLOBALS['BE_USER']->uc['rteMaxHeight']) : (intval($this->thisConfig['rteMaxHeight']) ? intval($this->thisConfig['rteMaxHeight']) : '2000')) . '";
813 RTEarea[editornumber].fullScreen = ' . ($this->fullScreen ? 'true' : 'false') . ';
814 RTEarea[editornumber].showStatusBar = ' . (trim($this->thisConfig['showStatusBar'])?'true':'false') . ';
815 RTEarea[editornumber].enableWordClean = ' . (trim($this->thisConfig['enableWordClean'])?'true':'false') . ';
816 RTEarea[editornumber].htmlRemoveComments = ' . (trim($this->thisConfig['removeComments'])?'true':'false') . ';
817 RTEarea[editornumber].disableEnterParagraphs = ' . (trim($this->thisConfig['disableEnterParagraphs'])?'true':'false') . ';
818 RTEarea[editornumber].disableObjectResizing = ' . (trim($this->thisConfig['disableObjectResizing'])?'true':'false') . ';
819 RTEarea[editornumber].removeTrailingBR = ' . (trim($this->thisConfig['removeTrailingBR'])?'true':'false') . ';
820 RTEarea[editornumber].useCSS = ' . (trim($this->thisConfig['useCSS'])?'true':'false') . ';
821 RTEarea[editornumber].keepButtonGroupTogether = ' . (trim($this->thisConfig['keepButtonGroupTogether'])?'true':'false') . ';
822 RTEarea[editornumber].disablePCexamples = ' . (trim($this->thisConfig['disablePCexamples'])?'true':'false') . ';
823 RTEarea[editornumber].showTagFreeClasses = ' . (trim($this->thisConfig['showTagFreeClasses'])?'true':'false') . ';
824 RTEarea[editornumber].useHTTPS = ' . ((trim(stristr($this->siteURL, 'https')) || $this->thisConfig['forceHTTPS'])?'true':'false') . ';
825 RTEarea[editornumber].tceformsNested = ' . (is_object($this->TCEform) && method_exists($this->TCEform, 'getDynNestedStack') ? $this->TCEform->getDynNestedStack(TRUE) : '[]') . ';
826 RTEarea[editornumber].dialogueWindows = new Object();';
827 if (isset($this->thisConfig['dialogueWindows.']['defaultPositionFromTop'])) {
828 $configureRTEInJavascriptString .= '
829 RTEarea[editornumber].dialogueWindows.positionFromTop = ' . intval($this->thisConfig['dialogueWindows.']['defaultPositionFromTop']) . ';';
830 }
831 if (isset($this->thisConfig['dialogueWindows.']['defaultPositionFromLeft'])) {
832 $configureRTEInJavascriptString .= '
833 RTEarea[editornumber].dialogueWindows.positionFromLeft = ' . intval($this->thisConfig['dialogueWindows.']['defaultPositionFromLeft']) . ';';
834 }
835 // The following properties apply only to the backend
836 if (!$this->is_FE()) {
837 $configureRTEInJavascriptString .= '
838 RTEarea[editornumber].sys_language_content = "' . $this->contentLanguageUid . '";
839 RTEarea[editornumber].typo3ContentLanguage = "' . $this->contentTypo3Language . '";
840 RTEarea[editornumber].typo3ContentCharset = "' . $this->contentCharset . '";
841 RTEarea[editornumber].userUid = "' . $this->userUid . '";';
842 }
843
844 // Setting the plugin flags
845 $configureRTEInJavascriptString .= '
846 RTEarea[editornumber].plugin = new Object();
847 RTEarea[editornumber].pathToPluginDirectory = new Object();';
848 foreach ($this->pluginEnabledArray as $pluginId) {
849 $configureRTEInJavascriptString .= '
850 RTEarea[editornumber].plugin.'.$pluginId.' = true;';
851 if (is_object($this->registeredPlugins[$pluginId])) {
852 $pathToPluginDirectory = $this->registeredPlugins[$pluginId]->getPathToPluginDirectory();
853 if ($pathToPluginDirectory) {
854 $configureRTEInJavascriptString .= '
855 RTEarea[editornumber].pathToPluginDirectory.'.$pluginId.' = "' . $pathToPluginDirectory . '";';
856 }
857 }
858 }
859
860 // Setting the buttons configuration
861 $configureRTEInJavascriptString .= '
862 RTEarea[editornumber].buttons = new Object();';
863 if (is_array($this->thisConfig['buttons.'])) {
864 foreach ($this->thisConfig['buttons.'] as $buttonIndex => $conf) {
865 $button = substr($buttonIndex, 0, -1);
866 if (is_array($conf)) {
867 $configureRTEInJavascriptString .= '
868 RTEarea[editornumber].buttons.'.$button.' = ' . $this->buildNestedJSArray($conf) . ';';
869 }
870 }
871 }
872
873 // Setting the list of tags to be removed if specified in the RTE config
874 if (trim($this->thisConfig['removeTags'])) {
875 $configureRTEInJavascriptString .= '
876 RTEarea[editornumber].htmlRemoveTags = /^(' . implode('|', t3lib_div::trimExplode(',', $this->thisConfig['removeTags'], 1)) . ')$/i;';
877 }
878
879 // Setting the list of tags to be removed with their contents if specified in the RTE config
880 if (trim($this->thisConfig['removeTagsAndContents'])) {
881 $configureRTEInJavascriptString .= '
882 RTEarea[editornumber].htmlRemoveTagsAndContents = /^(' . implode('|', t3lib_div::trimExplode(',', $this->thisConfig['removeTagsAndContents'], 1)) . ')$/i;';
883 }
884 // Setting array of custom tags if specified in the RTE config
885 if (!empty($this->thisConfig['customTags'])) {
886 $customTags = t3lib_div::trimExplode(',', $this->thisConfig['customTags'], 1);
887 if (!empty($customTags)) {
888 $configureRTEInJavascriptString .= '
889 RTEarea[editornumber].customTags= ' . json_encode($customTags) . ';';
890 }
891 }
892 // Setting the pageStyle
893 $configureRTEInJavascriptString .= '
894 RTEarea[editornumber].pageStyle = "' . t3lib_div::createVersionNumberedFilename($this->getContentCssFileName()) .'";';
895 // Process classes configuration
896 $classesConfigurationRequired = FALSE;
897 foreach ($this->registeredPlugins as $pluginId => $plugin) {
898 if ($this->isPluginEnabled($pluginId)) {
899 $classesConfigurationRequired = $classesConfigurationRequired || $plugin->requiresClassesConfiguration();
900 }
901 }
902 if ($classesConfigurationRequired) {
903 $configureRTEInJavascriptString .= $this->buildJSClassesConfig($RTEcounter);
904 }
905 // Add Javascript configuration for registered plugins
906 foreach ($this->registeredPlugins as $pluginId => $plugin) {
907 if ($this->isPluginEnabled($pluginId)) {
908 $configureRTEInJavascriptString .= $plugin->buildJavascriptConfiguration('editornumber');
909 }
910 }
911 // Avoid premature reference to HTMLArea when being initially loaded by IRRE Ajax call
912 $configureRTEInJavascriptString .= '
913 RTEarea[editornumber].toolbar = ' . $this->getJSToolbarArray() . ';
914 RTEarea[editornumber].convertButtonId = ' . json_encode(array_flip($this->convertToolbarForHtmlAreaArray)) . ';
915 RTEarea.initEditor(editornumber);
916 }
917 };
918 configureEditorInstance["' . $textAreaId . '"]();';
919 return $configureRTEInJavascriptString;
920 }
921
922 /**
923 * Return TRUE, if the plugin can be loaded
924 *
925 * @param string $pluginId: The identification string of the plugin
926 *
927 * @return boolean TRUE if the plugin can be loaded
928 */
929
930 function isPluginEnabled($pluginId) {
931 return in_array($pluginId, $this->pluginEnabledArray);
932 }
933
934 /**
935 * Build the default content style sheet
936 *
937 * @return string Style sheet
938 * @deprecated since TYPO3 6.0, will be removed in TYPO3 6.2
939 */
940 function buildStyleSheet() {
941 $stylesheet = '/* mainStyleOverride and inlineStyle properties ignored. */';
942 return $stylesheet;
943 }
944
945 /**
946 * Return Javascript configuration of classes
947 *
948 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
949 *
950 * @return string Javascript configuration of classes
951 */
952 function buildJSClassesConfig($RTEcounter) {
953 // Include JS arrays of configured classes
954 $configureRTEInJavascriptString .= '
955 RTEarea[editornumber].classesUrl = "' . (($this->is_FE() && $GLOBALS['TSFE']->absRefPrefix) ? $GLOBALS['TSFE']->absRefPrefix : '') . $this->writeTemporaryFile('', 'classes_' . $this->language, 'js', $this->buildJSClassesArray(), TRUE) . '";';
956 return $configureRTEInJavascriptString;
957 }
958
959 /**
960 * Return JS arrays of classes configuration
961 *
962 * @return string JS classes arrays
963 */
964 function buildJSClassesArray() {
965 if ($this->is_FE()) {
966 $RTEProperties = $this->RTEsetup;
967 } else {
968 $RTEProperties = $this->RTEsetup['properties'];
969 }
970 $classesArray = array('labels' => array(), 'values' => array(), 'noShow' => array(), 'alternating' => array(), 'counting' => array(), 'XOR' => array());
971 $JSClassesArray = '';
972 // Scanning the list of classes if specified in the RTE config
973 if (is_array($RTEProperties['classes.'])) {
974 foreach ($RTEProperties['classes.'] as $className => $conf) {
975 $className = rtrim($className, '.');
976 $classesArray['labels'][$className] = $this->getPageConfigLabel($conf['name'], FALSE);
977 $classesArray['values'][$className] = str_replace('\\\'', '\'', $conf['value']);
978 if (isset($conf['noShow'])) {
979 $classesArray['noShow'][$className] = $conf['noShow'];
980 }
981 if (is_array($conf['alternating.'])) {
982 $classesArray['alternating'][$className] = $conf['alternating.'];
983 }
984 if (is_array($conf['counting.'])) {
985 $classesArray['counting'][$className] = $conf['counting.'];
986 }
987 }
988 }
989 // Scanning the list of sets of mutually exclusives classes if specified in the RTE config
990 if (is_array($RTEProperties['mutuallyExclusiveClasses.'])) {
991 foreach ($RTEProperties['mutuallyExclusiveClasses.'] as $listName => $conf) {
992 $classSet = t3lib_div::trimExplode(',', $conf, 1);
993 $classList = implode(',', $classSet);
994 foreach ($classSet as $className) {
995 $classesArray['XOR'][$className] = '/^(' . implode('|', t3lib_div::trimExplode(',', t3lib_div::rmFromList($className, $classList), 1)) . ')$/';
996 }
997 }
998 }
999 foreach ($classesArray as $key => $subArray) {
1000 $JSClassesArray .= 'HTMLArea.classes' . ucfirst($key) . ' = ' . $this->buildNestedJSArray($subArray) . ';' . LF;
1001 }
1002 return $JSClassesArray;
1003 }
1004
1005 /**
1006 * Translate Page TS Config array in JS nested array definition
1007 * Replace 0 values with false
1008 * Unquote regular expression values
1009 * Replace empty arrays with empty objects
1010 *
1011 * @param array $conf: Page TSConfig configuration array
1012 *
1013 * @return string nested JS array definition
1014 */
1015 function buildNestedJSArray($conf) {
1016 $convertedConf = t3lib_div::removeDotsFromTS($conf);
1017 return str_replace(array(':"0"', ':"\/^(', ')$\/i"', ':"\/^(', ')$\/"', '[]'), array(':false', ':/^(', ')$/i', ':/^(', ')$/', '{}'), json_encode($convertedConf));
1018 }
1019
1020 /**
1021 * Return a Javascript localization array for htmlArea RTE
1022 *
1023 * @return string Javascript localization array
1024 */
1025 function buildJSMainLangArray() {
1026 $JSLanguageArray = 'HTMLArea.I18N = new Object();' . LF;
1027 $labelsArray = array('tooltips' => array(), 'msg' => array(), 'dialogs' => array());
1028 foreach ($labelsArray as $labels => $subArray) {
1029 $LOCAL_LANG = t3lib_div::readLLfile('EXT:' . $this->ID . '/htmlarea/locallang_' . $labels . '.xml', $this->language, 'utf-8');
1030 if (!empty($LOCAL_LANG[$this->language])) {
1031 $LOCAL_LANG[$this->language] = t3lib_div::array_merge_recursive_overrule($LOCAL_LANG['default'], $LOCAL_LANG[$this->language], FALSE, FALSE);
1032 } else {
1033 $LOCAL_LANG[$this->language] = $LOCAL_LANG['default'];
1034 }
1035 $labelsArray[$labels] = $LOCAL_LANG[$this->language];
1036 }
1037 $JSLanguageArray .= 'HTMLArea.I18N = ' . json_encode($labelsArray) . ';' . LF;
1038 return $JSLanguageArray;
1039 }
1040
1041 /**
1042 * Writes contents in a file in typo3temp/rtehtmlarea directory and returns the file name
1043 *
1044 * @param string $sourceFileName: The name of the file from which the contents should be extracted
1045 * @param string $label: A label to insert at the beginning of the name of the file
1046 * @param string $fileExtension: The file extension of the file, defaulting to 'js'
1047 * @param string $contents: The contents to write into the file if no $sourceFileName is provided
1048 *
1049 * @return string The name of the file writtten to typo3temp/rtehtmlarea
1050 */
1051 public function writeTemporaryFile($sourceFileName='', $label, $fileExtension='js', $contents='', $concatenate = FALSE) {
1052 if ($sourceFileName) {
1053 $output = '';
1054 $source = t3lib_div::getFileAbsFileName($sourceFileName);
1055 $output = file_get_contents($source);
1056 } else {
1057 $output = $contents;
1058 }
1059 $relativeFilename = 'typo3temp/' .
1060 $this->ID . '_' . str_replace('-', '_', $label) . '_' .
1061 t3lib_div::shortMD5((TYPO3_version . $TYPO3_CONF_VARS['EXTCONF'][$this->ID]['version'] . ($sourceFileName ? $sourceFileName : $output)), 20) .
1062 '.' . $fileExtension;
1063 $destination = PATH_site . $relativeFilename;
1064 if (!file_exists($destination)) {
1065 $minifiedJavaScript = '';
1066 if ($fileExtension == 'js' && $output != '') {
1067 $minifiedJavaScript = t3lib_div::minifyJavaScript($output);
1068 }
1069 $failure = t3lib_div::writeFileToTypo3tempDir($destination, $minifiedJavaScript ? $minifiedJavaScript : $output);
1070 if ($failure) {
1071 throw new RuntimeException($failure, 1294585668);
1072 }
1073 }
1074 if ($this->is_FE()) {
1075 $filename = $relativeFilename;
1076 } else {
1077 $filename = ($this->isFrontendEditActive() ? '' : ($this->backPath . '../')) . $relativeFilename;
1078 }
1079 return t3lib_div::resolveBackPath($filename);
1080 }
1081 /**
1082 * Return a file name containing the main JS language array for HTMLArea
1083 *
1084 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
1085 * @return string filename
1086 */
1087 function buildJSMainLangFile($RTEcounter) {
1088 $contents = $this->buildJSMainLangArray() . LF;
1089 foreach ($this->pluginEnabledCumulativeArray[$RTEcounter] as $pluginId) {
1090 $contents .= $this->buildJSLangArray($pluginId) . LF;
1091 }
1092 return $this->writeTemporaryFile('', $this->language.'_'.$this->OutputCharset, 'js', $contents, TRUE);
1093 }
1094
1095 /**
1096 * Return a Javascript localization array for the plugin
1097 *
1098 * @param string $plugin: identification string of the plugin
1099 *
1100 * @return string Javascript localization array
1101 */
1102 function buildJSLangArray($plugin) {
1103 $LOCAL_LANG = FALSE;
1104 $extensionKey = is_object($this->registeredPlugins[$plugin]) ? $this->registeredPlugins[$plugin]->getExtensionKey() : $this->ID;
1105 $LOCAL_LANG = t3lib_div::readLLfile('EXT:' . $extensionKey . '/htmlarea/plugins/' . $plugin . '/locallang.xml', $this->language, 'utf-8', 1);
1106 $JSLanguageArray = 'HTMLArea.I18N["' . $plugin . '"] = new Object();' . LF;
1107 if (is_array($LOCAL_LANG)) {
1108 if (!empty($LOCAL_LANG[$this->language])) {
1109 $LOCAL_LANG[$this->language] = t3lib_div::array_merge_recursive_overrule($LOCAL_LANG['default'], $LOCAL_LANG[$this->language], FALSE, FALSE);
1110 } else {
1111 $LOCAL_LANG[$this->language] = $LOCAL_LANG['default'];
1112 }
1113 $JSLanguageArray .= 'HTMLArea.I18N["' . $plugin . '"] = ' . json_encode($LOCAL_LANG[$this->language]) . ';'. LF;
1114 }
1115 return $JSLanguageArray;
1116 }
1117
1118 /**
1119 * Return the JS code of the toolbar configuration for the HTMLArea editor
1120 *
1121 * @return string the JS code as nested JS arrays
1122 */
1123 protected function getJSToolbarArray() {
1124 // The toolbar array
1125 $toolbar = array();
1126 // The current row; a "linebreak" ends the current row
1127 $row = array();
1128 // The current group; each group is between "bar"s; a "linebreak" ends the current group
1129 $group = array();
1130 // Process each toolbar item in the toolbar order list
1131 foreach ($this->toolbarOrderArray as $item) {
1132 switch ($item) {
1133 case 'linebreak':
1134 // Add row to toolbar if not empty
1135 if (!empty($group)) {
1136 $row[] = $group;
1137 $group = array();
1138 }
1139 if (!empty($row)) {
1140 $toolbar[] = $row;
1141 $row = array();
1142 }
1143 break;
1144 case 'bar':
1145 // Add group to row if not empty
1146 if (!empty($group)) {
1147 $row[] = $group;
1148 $group = array();
1149 }
1150 break;
1151 case 'space':
1152 if (end($group) != $this->convertToolbarForHTMLArea($item)) {
1153 $group[] = $this->convertToolbarForHTMLArea($item);
1154 }
1155 break;
1156 default:
1157 if (in_array($item, $this->toolbar)) {
1158 // Add the item to the group
1159 $convertedItem = $this->convertToolbarForHTMLArea($item);
1160 if ($convertedItem) {
1161 $group[] = $convertedItem;
1162 }
1163 }
1164 break;
1165 }
1166 }
1167 // Add the last group and last line, if not empty
1168 if (!empty($group)) {
1169 $row[] = $group;
1170 }
1171 if (!empty($row)) {
1172 $toolbar[] = $row;
1173 }
1174 return json_encode($toolbar);
1175 }
1176
1177 /**
1178 * Localize a string using the language of the content element rather than the language of the BE interface
1179 *
1180 * @param string string: the label to be localized
1181 * @return string Localized string.
1182 */
1183 public function getLLContent($string) {
1184 $BE_lang = $GLOBALS['LANG']->lang;
1185
1186 $GLOBALS['LANG']->lang = $this->contentTypo3Language;
1187 $LLString = $GLOBALS['LANG']->JScharCode($GLOBALS['LANG']->sL($string));
1188
1189 $GLOBALS['LANG']->lang = $BE_lang;
1190 return $LLString;
1191 }
1192
1193 public function getPageConfigLabel($string, $JScharCode=1) {
1194 global $LANG, $TSFE, $TYPO3_CONF_VARS;
1195
1196 if ($this->is_FE()) {
1197 if (strcmp(substr($string, 0, 4), 'LLL:')) {
1198 // A pure string coming from Page TSConfig must be in utf-8
1199 $label = $TSFE->csConvObj->conv($TSFE->sL(trim($string)), 'utf-8', $this->OutputCharset);
1200 } else {
1201 $label = $TSFE->csConvObj->conv($TSFE->sL(trim($string)), $this->charset, $this->OutputCharset);
1202 }
1203 $label = str_replace('"', '\"', str_replace('\\\'', '\'', $label));
1204 $label = $JScharCode ? $this->feJScharCode($label) : $label;
1205 } else {
1206 if (strcmp(substr($string, 0, 4), 'LLL:')) {
1207 $label = $string;
1208 } else {
1209 $label = $LANG->sL(trim($string));
1210 }
1211 $label = str_replace('"', '\"', str_replace('\\\'', '\'', $label));
1212 $label = $JScharCode ? $LANG->JScharCode($label) : $label;
1213 }
1214 return $label;
1215 }
1216
1217 function feJScharCode($str) {
1218 // Convert string to UTF-8:
1219 if ($this->OutputCharset != 'utf-8') {
1220 $str = $GLOBALS['TSFE']->csConvObj->utf8_encode($str, $this->OutputCharset);
1221 }
1222 // Convert the UTF-8 string into a array of char numbers:
1223 $nArr = $GLOBALS['TSFE']->csConvObj->utf8_to_numberarray($str);
1224 return 'String.fromCharCode(' . implode(',', $nArr) . ')';
1225 }
1226
1227 public function getFullFileName($filename) {
1228 if (substr($filename, 0, 4) == 'EXT:') { // extension
1229 list($extKey,$local) = explode('/', substr($filename, 4), 2);
1230 $newFilename = '';
1231 if (strcmp($extKey, '') && t3lib_extMgm::isLoaded($extKey) && strcmp($local, '')) {
1232 $newFilename = (($this->is_FE() || $this->isFrontendEditActive()) ? t3lib_extMgm::siteRelPath($extKey) : $this->backPath . t3lib_extMgm::extRelPath($extKey)) . $local;
1233 }
1234 } elseif (substr($filename, 0, 1) != '/') {
1235 $newFilename = (($this->is_FE() || $this->isFrontendEditActive()) ? '' : ($this->backPath . '../')) . $filename;
1236 } else {
1237 $newFilename = (($this->is_FE() || $this->isFrontendEditActive()) ? '' : ($this->backPath . '../')) . substr($filename, 1);
1238 }
1239 return t3lib_div::resolveBackPath($newFilename);
1240 }
1241
1242 /**
1243 * Return the Javascript code for copying the HTML code from the editor into the hidden input field.
1244 * This is for submit function of the form.
1245 *
1246 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
1247 * @param string $formName: the name of the form
1248 * @param string $textareaId: the id of the textarea
1249 * @param string $textareaName: the name of the textarea
1250 *
1251 * @return string Javascript code
1252 */
1253 function setSaveRTE($RTEcounter, $formName, $textareaId, $textareaName) {
1254 return 'if (RTEarea["' . $textareaId . '"]) { document.' . $formName . '["' . $textareaName . '"].value = RTEarea["' . $textareaId . '"].editor.getHTML(); } else { OK = 0; };';
1255 }
1256
1257 /**
1258 * Return the Javascript code for copying the HTML code from the editor into the hidden input field.
1259 * This is for submit function of the form.
1260 *
1261 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
1262 * @param string $formName: the name of the form
1263 * @param string $textareaId: the id of the textarea
1264 *
1265 * @return string Javascript code
1266 */
1267 function setDeleteRTE($RTEcounter, $formName, $textareaId) {
1268 return 'if (RTEarea["' . $textareaId . '"]) { RTEarea["' . $textareaId . '"].deleted = true;}';
1269 }
1270
1271 /**
1272 * Return TRUE if we are in the FE, but not in the FE editing feature of BE.
1273 *
1274 * @return boolean
1275 */
1276
1277 function is_FE() {
1278 return is_object($GLOBALS['TSFE']) && !$this->isFrontendEditActive() && TYPO3_MODE == 'FE';
1279 }
1280
1281 /**
1282 * Checks whether frontend editing is active.
1283 *
1284 * @return boolean
1285 */
1286 public function isFrontendEditActive() {
1287 return is_object($GLOBALS['TSFE']) && $GLOBALS['TSFE']->beUserLogin && ($GLOBALS['BE_USER']->frontendEdit instanceof t3lib_frontendedit);
1288 }
1289
1290 /**
1291 * Client Browser Information
1292 *
1293 * @param string $userAgent: The useragent string, t3lib_div::getIndpEnv('HTTP_USER_AGENT')
1294 * @return array Contains keys "useragent", "browser", "version", "system"
1295 * where "browser" is limited to the engines
1296 * and where "version" is a floating number
1297 */
1298 function clientInfo($userAgent = '') {
1299 if (!$userAgent) {
1300 $userAgent = t3lib_div::getIndpEnv('HTTP_USER_AGENT');
1301 }
1302 $browserInfo = t3lib_utility_Client::getBrowserInfo($userAgent);
1303 // Known engines: order is not irrelevant!
1304 $knownEngines = array('opera', 'msie', 'gecko', 'webkit');
1305 if (is_array($browserInfo['all'])) {
1306 foreach ($knownEngines as $engine) {
1307 if ($browserInfo['all'][$engine]) {
1308 $browserInfo['browser'] = $engine;
1309 $browserInfo['version'] = t3lib_utility_Client::getVersion($browserInfo['all'][$engine]);
1310 break;
1311 }
1312 }
1313 }
1314 return $browserInfo;
1315 }
1316
1317 /**
1318 * Log usage of deprecated Page TS Config Property
1319 *
1320 * @param string $deprecatedProperty: Name of deprecated property
1321 * @param string $useProperty: Name of property to use instead
1322 * @param string $version: Version of TYPO3 in which the property will be removed
1323 *
1324 * @return void
1325 */
1326 public function logDeprecatedProperty ($deprecatedProperty, $useProperty, $version) {
1327 if (!$this->thisConfig['logDeprecatedProperties.']['disabled']) {
1328 $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);
1329 t3lib_div::deprecationLog($message);
1330 if (is_object($GLOBALS['BE_USER']) && $this->thisConfig['logDeprecatedProperties.']['logAlsoToBELog']) {
1331 $message = sprintf($GLOBALS['LANG']->getLL('deprecatedPropertyMessage'), $deprecatedProperty, $useProperty, $version, $this->thePid);
1332 $GLOBALS['BE_USER']->simplelog($message, $this->ID);
1333 }
1334 }
1335 }
1336
1337 /***************************
1338 *
1339 * OTHER FUNCTIONS: (from Classic RTE)
1340 *
1341 ***************************/
1342 /**
1343 * @return [type] ...
1344 * @desc
1345 */
1346
1347 function RTEtsConfigParams() {
1348 if($this->is_FE()) {
1349 return '';
1350 } else {
1351 $p = t3lib_BEfunc::getSpecConfParametersFromArray($this->specConf['rte_transform']['parameters']);
1352 return $this->elementParts[0] . ':' . $this->elementParts[1] . ':' . $this->elementParts[2] . ':' . $this->thePid . ':' . $this->typeVal . ':' . $this->tscPID . ':' . $p['imgpath'];
1353 }
1354 }
1355
1356 public function cleanList($str) {
1357 if (strstr($str, '*')) {
1358 $str = '*';
1359 } else {
1360 $str = implode(',', array_unique(t3lib_div::trimExplode(',', $str, 1)));
1361 }
1362 return $str;
1363 }
1364
1365 function filterStyleEl($elValue, $matchList) {
1366 $matchParts = t3lib_div::trimExplode(',', $matchList, 1);
1367 $styleParts = explode(';', $elValue);
1368 $nStyle = array();
1369 foreach ($styleParts as $k => $p) {
1370 $pp = t3lib_div::trimExplode(':', $p);
1371 if ($pp[0] && $pp[1]) {
1372 foreach ($matchParts as $el) {
1373 $star=substr($el, -1) == '*';
1374 if (!strcmp($pp[0], $el) || ($star && t3lib_div::isFirstPartOfStr($pp[0], substr($el, 0, -1)) )) {
1375 $nStyle[] = $pp[0] . ':' . $pp[1];
1376 } else {
1377 unset($styleParts[$k]);
1378 }
1379 }
1380 } else {
1381 unset($styleParts[$k]);
1382 }
1383 }
1384 return implode('; ', $nStyle);
1385 }
1386
1387 // Hook on lorem_ipsum extension to insert text into the RTE in wysiwyg mode
1388 function loremIpsumInsert($params) {
1389 return '
1390 if (typeof(lorem_ipsum) == \'function\' && ' . $params['element'] . '.tagName.toLowerCase() == \'textarea\' ) lorem_ipsum(' . $params['element'] . ', lipsum_temp_strings[lipsum_temp_pointer]);
1391 ';
1392 }
1393 }
1394 ?>