2 /***************************************************************
5 * (c) 2004-2010 Kasper Skaarhoj (kasper@typo3.com)
6 * (c) 2004-2010 Philipp Borgmann <philipp.borgmann@gmx.de>
7 * (c) 2004-2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
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.
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.
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.
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
30 * A RTE using the htmlArea editor
32 * @author Philipp Borgmann <philipp.borgmann@gmx.de>
33 * @author Stanislas Rolland <typo3(arobas)sjbr.ca>
38 class tx_rtehtmlarea_base
extends t3lib_rteapi
{
39 // Configuration of supported browsers
40 var $conf_supported_browser = array (
72 // Always hide these toolbar buttons (TYPO3 button name)
73 var $conf_toolbar_hide = array (
74 'showhelp', // Has no content yet
77 // The order of the toolbar: the name is the TYPO3-button name
78 var $defaultToolbarOrder;
80 // Conversion array: TYPO3 button names to htmlArea button names
81 var $convertToolbarForHtmlAreaArray = array (
82 'showhelp' => 'ShowHelp',
85 'linebreak' => 'linebreak',
88 var $pluginButton = array();
89 var $pluginLabel = array();
90 // Alternative style for RTE <div> tag.
92 // Relative path to this extension. It ends with "/"
94 public $backPath = '';
101 // Identifies the RTE as being the one from the "rtehtmlarea" extension if any external code needs to know
102 var $ID = 'rtehtmlarea';
103 // If set, the content goes into a regular TEXT area field - for developing testing of transformations.
104 var $debugMode = FALSE;
109 * Reference to parent object, which is an instance of the TCEforms
111 * @var t3lib_TCEforms
123 public $contentTypo3Language;
124 public $contentISOLanguage;
125 public $contentCharset;
126 public $OutputCharset;
129 var $toolbar = array(); // Save the buttons for the toolbar
130 var $toolbarOrderArray = array();
131 protected $pluginEnabledArray = array(); // Array of plugin id's enabled in the current RTE editing area
132 protected $pluginEnabledCumulativeArray = array(); // Cumulative array of plugin id's enabled so far in any of the RTE editing areas of the form
133 protected $cumulativeScripts = array();
134 public $registeredPlugins = array(); // Array of registered plugins indexed by their plugin Id's
135 protected $fullScreen = false;
138 * Returns true if the RTE is available. Here you check if the browser requirements are met.
139 * If there are reasons why the RTE cannot be displayed you simply enter them as text in ->errorLog
141 * @return boolean TRUE if this RTE object offers an RTE in the current browser environment
144 function isAvailable() {
145 global $TYPO3_CONF_VARS;
147 $this->client
= $this->clientInfo();
148 $this->errorLog
= array();
149 if (!$this->debugMode
) { // If debug-mode, let any browser through
151 $rteConfBrowser = $this->conf_supported_browser
;
152 if (is_array($rteConfBrowser)) {
153 foreach ($rteConfBrowser as $browser => $browserConf) {
154 if ($browser == $this->client
['browser']) {
155 // Config for Browser found, check it:
156 if (is_array($browserConf)) {
157 foreach ($browserConf as $browserConfNr => $browserConfSub) {
158 if ($browserConfSub['version'] <= $this->client
['version'] ||
empty($browserConfSub['version'])) {
159 // Version is correct
160 if ($browserConfSub['system'] == $this->client
['system'] ||
empty($browserConfSub['system'])) {
161 // System is correctly
165 }// End of foreach-BrowserSubpart
167 // no config for this browser found, so all versions or system with this browsers are allow
170 } // End of Browser Check
171 } // foreach: Browser Check
173 // no Browser config for this RTE-Editor, so all Clients are allow
175 if (!$rteIsAvailable) {
176 $this->errorLog
[] = 'rte: Browser not supported. Only msie Version 5 or higher and Mozilla based client 1. and higher.';
178 if (t3lib_div
::int_from_ver(TYPO3_version
) < 4000000) {
180 $this->errorLog
[] = 'rte: This version of htmlArea RTE cannot run under this version of TYPO3.';
183 if ($rteIsAvailable) return true;
187 * Draws the RTE as an iframe
189 * @param object Reference to parent object, which is an instance of the TCEforms.
190 * @param string The table name
191 * @param string The field name
192 * @param array The current row from which field is being rendered
193 * @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.
194 * @param array "special" configuration - what is found at position 4 in the types configuration of a field from record, parsed into an array.
195 * @param array Configuration for RTEs; A mix between TSconfig and otherwise. Contains configuration for display, which buttons are enabled, additional transformation information etc.
196 * @param string Record "type" field value.
197 * @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!
198 * @param integer PID value of record (true parent page id)
199 * @return string HTML code for RTE!
202 function drawRTE($parentObject, $table, $field, $row, $PA, $specConf, $thisConfig, $RTEtypeVal, $RTErelPath, $thePidValue) {
203 global $BE_USER, $LANG, $TYPO3_DB, $TYPO3_CONF_VARS;
205 $this->TCEform
= $parentObject;
206 $inline = $this->TCEform
->inline
;
207 $LANG->includeLLFile('EXT:' . $this->ID
. '/locallang.xml');
208 $this->client
= $this->clientInfo();
209 $this->typoVersion
= t3lib_div
::int_from_ver(TYPO3_version
);
210 $this->userUid
= 'BE_' . $BE_USER->user
['uid'];
212 // Draw form element:
213 if ($this->debugMode
) { // Draws regular text area (debug mode)
214 $item = parent
::drawRTE($this->TCEform
, $table, $field, $row, $PA, $specConf, $thisConfig, $RTEtypeVal, $RTErelPath, $thePidValue);
215 } else { // Draw real RTE
217 /* =======================================
218 * INIT THE EDITOR-SETTINGS
219 * =======================================
222 $this->backPath
= $this->TCEform
->backPath
;
223 // Get the path to this extension:
224 $this->extHttpPath
= $this->backPath
. t3lib_extMgm
::extRelPath($this->ID
);
226 $this->siteURL
= t3lib_div
::getIndpEnv('TYPO3_SITE_URL');
228 $this->hostURL
= $this->siteURL
. TYPO3_mainDir
;
230 $this->elementId
= $PA['itemFormElName']; // Form element name
231 $this->elementParts
= explode('][',preg_replace('/\]$/','',preg_replace('/^(TSFE_EDIT\[data\]\[|data\[)/','',$this->elementId
)));
232 // Find the page PIDs:
233 list($this->tscPID
,$this->thePid
) = t3lib_BEfunc
::getTSCpid(trim($this->elementParts
[0]),trim($this->elementParts
[1]),$thePidValue);
235 // Record "types" field value:
236 $this->typeVal
= $RTEtypeVal; // TCA "types" value for record
238 // Find "thisConfig" for record/editor:
239 unset($this->RTEsetup
);
240 $this->RTEsetup
= $BE_USER->getTSConfig('RTE',t3lib_BEfunc
::getPagesTSconfig($this->tscPID
));
241 $this->thisConfig
= $thisConfig;
243 // Special configuration and default extras:
244 $this->specConf
= $specConf;
246 if ($this->thisConfig
['forceHTTPS']) {
247 $this->extHttpPath
= preg_replace('/^(http|https)/', 'https', $this->extHttpPath
);
248 $this->siteURL
= preg_replace('/^(http|https)/', 'https', $this->siteURL
);
249 $this->hostURL
= preg_replace('/^(http|https)/', 'https', $this->hostURL
);
252 /* =======================================
253 * LANGUAGES & CHARACTER SETS
254 * =======================================
257 // Languages: interface and content
258 $this->language
= $LANG->lang
;
259 if ($this->language
=='default' ||
!$this->language
) {
260 $this->language
='en';
262 $this->contentTypo3Language
= $this->language
;
263 $this->contentISOLanguage
= 'en';
264 $this->contentLanguageUid
= ($row['sys_language_uid'] > 0) ?
$row['sys_language_uid'] : 0;
265 if (t3lib_extMgm
::isLoaded('static_info_tables')) {
266 if ($this->contentLanguageUid
) {
267 $tableA = 'sys_language';
268 $tableB = 'static_languages';
269 $languagesUidsList = $this->contentLanguageUid
;
270 $selectFields = $tableA . '.uid,' . $tableB . '.lg_iso_2,' . $tableB . '.lg_country_iso_2,' . $tableB . '.lg_typo3';
271 $tableAB = $tableA . ' LEFT JOIN ' . $tableB . ' ON ' . $tableA . '.static_lang_isocode=' . $tableB . '.uid';
272 $whereClause = $tableA . '.uid IN (' . $languagesUidsList . ') ';
273 $whereClause .= t3lib_BEfunc
::BEenableFields($tableA);
274 $whereClause .= t3lib_BEfunc
::deleteClause($tableA);
275 $res = $TYPO3_DB->exec_SELECTquery($selectFields, $tableAB, $whereClause);
276 while($languageRow = $TYPO3_DB->sql_fetch_assoc($res)) {
277 $this->contentISOLanguage
= strtolower(trim($languageRow['lg_iso_2']).(trim($languageRow['lg_country_iso_2'])?
'_'.trim($languageRow['lg_country_iso_2']):''));
278 $this->contentTypo3Language
= strtolower(trim($languageRow['lg_typo3']));
281 $this->contentISOLanguage
= trim($this->thisConfig
['defaultContentLanguage']) ?
trim($this->thisConfig
['defaultContentLanguage']) : 'en';
282 $selectFields = 'lg_iso_2, lg_typo3';
283 $tableAB = 'static_languages';
284 $whereClause = 'lg_iso_2 = ' . $TYPO3_DB->fullQuoteStr(strtoupper($this->contentISOLanguage
), $tableAB);
285 $res = $TYPO3_DB->exec_SELECTquery($selectFields, $tableAB, $whereClause);
286 while($languageRow = $TYPO3_DB->sql_fetch_assoc($res)) {
287 $this->contentTypo3Language
= strtolower(trim($languageRow['lg_typo3']));
292 // Character sets: interface and content
293 $this->charset
= $LANG->charSet
;
294 $this->OutputCharset
= $this->charset
;
296 $this->contentCharset
= $LANG->csConvObj
->charSetArray
[$this->contentTypo3Language
];
297 $this->contentCharset
= $this->contentCharset ?
$this->contentCharset
: 'iso-8859-1';
298 $this->origContentCharSet
= $this->contentCharset
;
299 $this->contentCharset
= (trim($TYPO3_CONF_VARS['BE']['forceCharset']) ?
trim($TYPO3_CONF_VARS['BE']['forceCharset']) : $this->contentCharset
);
301 /* =======================================
302 * TOOLBAR CONFIGURATION
303 * =======================================
305 $this->initializeToolbarConfiguration();
307 /* =======================================
309 * =======================================
312 $RTEWidth = isset($BE_USER->userTS
['options.']['RTESmallWidth']) ?
$BE_USER->userTS
['options.']['RTESmallWidth'] : '530';
313 $RTEHeight = isset($BE_USER->userTS
['options.']['RTESmallHeight']) ?
$BE_USER->userTS
['options.']['RTESmallHeight'] : '380';
314 $RTEWidth = $RTEWidth +
($this->TCEform
->docLarge ?
(isset($BE_USER->userTS
['options.']['RTELargeWidthIncrement']) ?
$BE_USER->userTS
['options.']['RTELargeWidthIncrement'] : '150') : 0);
315 $RTEWidth -= ($inline->getStructureDepth() > 0 ?
($inline->getStructureDepth()+
1)*$inline->getLevelMargin() : 0);
316 if (isset($this->thisConfig
['RTEWidthOverride'])) {
317 if (strstr($this->thisConfig
['RTEWidthOverride'], '%')) {
318 if ($this->client
['browser'] != 'msie') {
319 $RTEWidth = (intval($this->thisConfig
['RTEWidthOverride']) > 0) ?
$this->thisConfig
['RTEWidthOverride'] : '100%';
322 $RTEWidth = (intval($this->thisConfig
['RTEWidthOverride']) > 0) ?
intval($this->thisConfig
['RTEWidthOverride']) : $RTEWidth;
325 $RTEWidth = strstr($RTEWidth, '%') ?
$RTEWidth : $RTEWidth . 'px';
326 $RTEHeight = $RTEHeight +
($this->TCEform
->docLarge ?
(isset($BE_USER->userTS
['options.']['RTELargeHeightIncrement']) ?
$BE_USER->userTS
['options.']['RTELargeHeightIncrement'] : 0) : 0);
327 $RTEHeightOverride = intval($this->thisConfig
['RTEHeightOverride']);
328 $RTEHeight = ($RTEHeightOverride > 0) ?
$RTEHeightOverride : $RTEHeight;
329 $editorWrapWidth = '99%';
330 $editorWrapHeight = '100%';
331 $this->RTEdivStyle
= 'position:relative; left:0px; top:0px; height:' . $RTEHeight . 'px; width:'.$RTEWidth.'; border: 1px solid black; padding: 2px 2px 2px 2px;';
333 /* =======================================
334 * LOAD CSS AND JAVASCRIPT
335 * =======================================
337 // Preloading the pageStyle and including RTE skin stylesheets
338 $this->addPageStyle();
340 // Loading JavaScript files and code
341 if ($this->TCEform
->RTEcounter
== 1) {
342 $this->TCEform
->additionalJS_pre
['rtehtmlarea-loadJScode'] = $this->loadJScode($this->TCEform
->RTEcounter
);
344 $this->TCEform
->additionalCode_pre
['rtehtmlarea-loadJSfiles'] = $this->loadJSfiles($this->TCEform
->RTEcounter
);
345 $pageRenderer = $GLOBALS['SOBE']->doc
->getPageRenderer();
346 $pageRenderer->enableExtJSQuickTips();
347 if (!$GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID
]['enableCompressedScripts']) {
348 $pageRenderer->enableExtJsDebug();
350 /* =======================================
352 * =======================================
356 $value = $this->transformContent('rte',$PA['itemFormElValue'],$table,$field,$row,$specConf,$thisConfig,$RTErelPath,$thePidValue);
358 // Further content transformation by registered plugins
359 foreach ($this->registeredPlugins
as $pluginId => $plugin) {
360 if ($this->isPluginEnabled($pluginId) && method_exists($plugin, "transformContent")) {
361 $value = $plugin->transformContent($value);
364 // Register RTE windows
365 $this->TCEform
->RTEwindows
[] = $PA['itemFormElName'];
366 $textAreaId = htmlspecialchars($PA['itemFormElName']);
368 // Check if wizard_rte called this for fullscreen edtition; if so, change the size of the RTE to fullscreen using JS
369 if (basename(PATH_thisScript
) == 'wizard_rte.php') {
370 $this->fullScreen
= true;
371 $editorWrapWidth = '100%';
372 $editorWrapHeight = '100%';
373 $this->RTEdivStyle
= 'position:relative; left:0px; top:0px; height:100%; width:100%; border: 1px solid black; padding: 2px 0px 2px 2px;';
376 // Register RTE in JS:
377 $this->TCEform
->additionalJS_post
[] = $this->registerRTEinJS($this->TCEform
->RTEcounter
, $table, $row['uid'], $field, $textAreaId);
379 // Set the save option for the RTE:
380 $this->TCEform
->additionalJS_submit
[] = $this->setSaveRTE($this->TCEform
->RTEcounter
, $this->TCEform
->formName
, $textAreaId);
381 $this->TCEform
->additionalJS_delete
[] = $this->setDeleteRTE($this->TCEform
->RTEcounter
, $this->TCEform
->formName
, $textAreaId);
384 $visibility = 'hidden';
385 $item = $this->triggerField($PA['itemFormElName']).'
386 <div id="pleasewait' . $textAreaId . '" class="pleasewait" style="display: block;" >' . $LANG->getLL('Please wait') . '</div>
387 <div id="editorWrap' . $textAreaId . '" class="editorWrap" style="visibility: hidden; width:' . $editorWrapWidth . '; height:' . $editorWrapHeight . ';">
388 <textarea id="RTEarea' . $textAreaId . '" name="'.htmlspecialchars($PA['itemFormElName']).'" style="'.t3lib_div
::deHSCentities(htmlspecialchars($this->RTEdivStyle
)).'">'.t3lib_div
::formatForTextarea($value).'</textarea>
389 </div>' . ($TYPO3_CONF_VARS['EXTCONF'][$this->ID
]['enableDebugMode'] ?
'<div id="HTMLAreaLog"></div>' : '') . '
398 * Add link to content style sheet to document header
402 protected function addPageStyle() {
403 // Get stylesheet file name from Page TSConfig if any
404 $filename = trim($this->thisConfig
['contentCSS']) ?
trim($this->thisConfig
['contentCSS']) : 'EXT:' . $this->ID
. '/res/contentcss/default.css';
405 $this->addStyleSheet(
406 'rtehtmlarea-page-style',
407 $this->getFullFileName($filename),
408 'htmlArea RTE Content CSS',
409 'alternate stylesheet'
414 * Add links to skin style sheet(s) to document header
418 protected function addSkin() {
419 // Get skin file name from Page TSConfig if any
420 $skinFilename = trim($this->thisConfig
['skin']) ?
trim($this->thisConfig
['skin']) : 'EXT:' . $this->ID
. '/htmlarea/skins/default/htmlarea.css';
421 $this->editorCSS
= $this->getFullFileName($skinFilename);
422 $skinDir = dirname($this->editorCSS
);
423 // Editing area style sheet
424 $this->editedContentCSS
= $skinDir . '/htmlarea-edited-content.css';
425 $this->addStyleSheet(
426 'rtehtmlarea-editing-area-skin',
427 $this->editedContentCSS
430 $this->addStyleSheet(
434 // Additional icons from registered plugins
435 foreach ($this->pluginEnabledCumulativeArray
[$this->TCEform
->RTEcounter
] as $pluginId) {
436 if (is_object($this->registeredPlugins
[$pluginId])) {
437 $pathToSkin = $this->registeredPlugins
[$pluginId]->getPathToSkin();
439 $key = $this->registeredPlugins
[$pluginId]->getExtensionKey();
440 $this->addStyleSheet(
441 'rtehtmlarea-plugin-' . $pluginId . '-skin',
442 ($this->is_FE() ? t3lib_extMgm
::siteRelPath($key) : $this->backPath
. t3lib_extMgm
::extRelPath($key)) . $pathToSkin
450 * Add style sheet file to document header
452 * @param string $key: some key identifying the style sheet
453 * @param string $href: uri to the style sheet file
454 * @param string $title: value for the title attribute of the link element
455 * @return string $relation: value for the rel attribute of the link element
458 protected function addStyleSheet($key, $href, $title='', $relation='stylesheet') {
459 // 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
460 if (is_object($this->TCEform
->inline
) && $this->TCEform
->inline
->isAjaxCall
) {
461 $this->TCEform
->additionalCode_pre
[$key] = '<link rel="' . $relation . '" type="text/css" href="' . $href . '" title="' . $title. '" />';
463 $pageRenderer = $GLOBALS['SOBE']->doc
->getPageRenderer();
464 $pageRenderer->addCssFile($href, $relation, 'screen', $title);
469 * Initialize toolbar configuration and enable registered plugins
473 protected function initializeToolbarConfiguration() {
475 // Enable registred plugins
476 $this->enableRegisteredPlugins();
481 // Check if some plugins need to be disabled
484 // Merge the list of enabled plugins with the lists from the previous RTE editing areas on the same form
485 $this->pluginEnabledCumulativeArray
[$this->TCEform
->RTEcounter
] = $this->pluginEnabledArray
;
486 if ($this->TCEform
->RTEcounter
> 1 && isset($this->pluginEnabledCumulativeArray
[$this->TCEform
->RTEcounter
-1]) && is_array($this->pluginEnabledCumulativeArray
[$this->TCEform
->RTEcounter
-1])) {
487 $this->pluginEnabledCumulativeArray
[$this->TCEform
->RTEcounter
] = array_unique(array_values(array_merge($this->pluginEnabledArray
,$this->pluginEnabledCumulativeArray
[$this->TCEform
->RTEcounter
-1])));
492 * Add registered plugins to the array of enabled plugins
495 function enableRegisteredPlugins() {
496 global $TYPO3_CONF_VARS;
497 // Traverse registered plugins
498 if (is_array($TYPO3_CONF_VARS['EXTCONF'][$this->ID
]['plugins'])) {
499 foreach($TYPO3_CONF_VARS['EXTCONF'][$this->ID
]['plugins'] as $pluginId => $pluginObjectConfiguration) {
501 if (is_array($pluginObjectConfiguration) && count($pluginObjectConfiguration)) {
502 $plugin = t3lib_div
::getUserObj($pluginObjectConfiguration['objectReference']);
504 if (is_object($plugin)) {
505 if ($plugin->main($this)) {
506 $this->registeredPlugins
[$pluginId] = $plugin;
507 // Override buttons from previously registered plugins
508 $pluginButtons = t3lib_div
::trimExplode(',', $plugin->getPluginButtons(), 1);
509 foreach ($this->pluginButton
as $previousPluginId => $buttonList) {
510 $this->pluginButton
[$previousPluginId] = implode(',',array_diff(t3lib_div
::trimExplode(',', $this->pluginButton
[$previousPluginId], 1), $pluginButtons));
512 $this->pluginButton
[$pluginId] = $plugin->getPluginButtons();
513 $pluginLabels = t3lib_div
::trimExplode(',', $plugin->getPluginLabels(), 1);
514 foreach ($this->pluginLabel
as $previousPluginId => $labelList) {
515 $this->pluginLabel
[$previousPluginId] = implode(',',array_diff(t3lib_div
::trimExplode(',', $this->pluginLabel
[$previousPluginId], 1), $pluginLabels));
517 $this->pluginLabel
[$pluginId] = $plugin->getPluginLabels();
518 $this->pluginEnabledArray
[] = $pluginId;
524 $hidePlugins = array();
525 foreach ($this->registeredPlugins
as $pluginId => $plugin) {
526 if ($plugin->addsButtons() && !$this->pluginButton
[$pluginId]) {
527 $hidePlugins[] = $pluginId;
530 $this->pluginEnabledArray
= array_unique(array_diff($this->pluginEnabledArray
, $hidePlugins));
534 * Set the toolbar config (only in this PHP-Object, not in JS):
538 function setToolbar() {
541 if ($this->client
['browser'] == 'msie' ||
$this->client
['browser'] == 'opera') {
542 $this->thisConfig
['keepButtonGroupTogether'] = 0;
545 $this->defaultToolbarOrder
= 'bar, blockstylelabel, blockstyle, space, textstylelabel, textstyle, linebreak,
546 bar, formattext, bold, strong, italic, emphasis, big, small, insertedtext, deletedtext, citation, code, definition, keyboard, monospaced, quotation, sample, variable, bidioverride, strikethrough, subscript, superscript, underline, span,
547 bar, fontstyle, space, fontsize, bar, formatblock, insertparagraphbefore, insertparagraphafter, blockquote, line,
548 bar, left, center, right, justifyfull,
549 bar, orderedlist, unorderedlist, definitionlist, definitionitem, outdent, indent, bar, lefttoright, righttoleft, language, showlanguagemarks,
550 bar, textcolor, bgcolor, textindicator,
551 bar, emoticon, insertcharacter, 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,
552 bar, chMode, inserttag, removeformat, bar, copy, cut, paste, bar, undo, redo, bar, showhelp, about, linebreak,
553 ' . ($this->thisConfig
['hideTableOperationsInToolbar'] ?
'': 'bar, toggleborders,') . ' bar, tableproperties, tablerestyle, bar, rowproperties, rowinsertabove, rowinsertunder, rowdelete, rowsplit, bar,
554 columnproperties, columninsertbefore, columninsertafter, columndelete, columnsplit, bar,
555 cellproperties, cellinsertbefore, cellinsertafter, celldelete, cellsplit, cellmerge';
557 // Additional buttons from registered plugins
558 foreach($this->registeredPlugins
as $pluginId => $plugin) {
559 if ($this->isPluginEnabled($pluginId)) {
560 $this->defaultToolbarOrder
= $plugin->addButtonsToToolbar();
563 $toolbarOrder = $this->thisConfig
['toolbarOrder'] ?
$this->thisConfig
['toolbarOrder'] : $this->defaultToolbarOrder
;
565 // Getting rid of undefined buttons
566 $this->toolbarOrderArray
= array_intersect(t3lib_div
::trimExplode(',', $toolbarOrder, 1), t3lib_div
::trimExplode(',', $this->defaultToolbarOrder
, 1));
567 $toolbarOrder = array_unique(array_values($this->toolbarOrderArray
));
569 // Fetching specConf for field from backend
570 $pList = is_array($this->specConf
['richtext']['parameters']) ?
implode(',',$this->specConf
['richtext']['parameters']) : '';
571 if ($pList != '*') { // If not all
572 $show = is_array($this->specConf
['richtext']['parameters']) ?
$this->specConf
['richtext']['parameters'] : array();
573 if ($this->thisConfig
['showButtons']) {
574 if (!t3lib_div
::inList($this->thisConfig
['showButtons'],'*')) {
575 $show = array_unique(array_merge($show,t3lib_div
::trimExplode(',',$this->thisConfig
['showButtons'],1)));
577 $show = array_unique(array_merge($show, $toolbarOrder));
580 if (is_array($this->thisConfig
['showButtons.'])) {
581 foreach ($this->thisConfig
['showButtons.'] as $buttonId => $value) {
582 if ($value) $show[] = $buttonId;
584 $show = array_unique($show);
587 $show = $toolbarOrder;
590 // Resticting to RTEkeyList for backend user
591 if(is_object($BE_USER)) {
592 $RTEkeyList = isset($BE_USER->userTS
['options.']['RTEkeyList']) ?
$BE_USER->userTS
['options.']['RTEkeyList'] : '*';
593 if ($RTEkeyList != '*') { // If not all
594 $show = array_intersect($show, t3lib_div
::trimExplode(',',$RTEkeyList,1));
598 // Hiding buttons of disabled plugins
599 $hideButtons = array('space', 'bar', 'linebreak');
600 foreach ($this->pluginButton
as $pluginId => $buttonList) {
601 if (!$this->isPluginEnabled($pluginId)) {
602 $buttonArray = t3lib_div
::trimExplode(',',$buttonList,1);
603 foreach ($buttonArray as $button) {
604 $hideButtons[] = $button;
609 // Hiding labels of disabled plugins
610 foreach ($this->pluginLabel
as $pluginId => $label) {
611 if (!$this->isPluginEnabled($pluginId)) {
612 $hideButtons[] = $label;
617 $show = array_diff($show, $this->conf_toolbar_hide
, t3lib_div
::trimExplode(',',$this->thisConfig
['hideButtons'],1));
619 // Apply toolbar constraints from registered plugins
620 foreach ($this->registeredPlugins
as $pluginId => $plugin) {
621 if ($this->isPluginEnabled($pluginId) && method_exists($plugin, "applyToolbarConstraints")) {
622 $show = $plugin->applyToolbarConstraints($show);
625 // Getting rid of the buttons for which we have no position
626 $show = array_intersect($show, $toolbarOrder);
627 $this->toolbar
= $show;
631 * Disable some plugins
634 function setPlugins() {
636 // Disabling a plugin that adds buttons if none of its buttons is in the toolbar
637 $hidePlugins = array();
638 foreach ($this->pluginButton
as $pluginId => $buttonList) {
639 if ($this->registeredPlugins
[$pluginId]->addsButtons()) {
641 $buttonArray = t3lib_div
::trimExplode(',', $buttonList, 1);
642 foreach ($buttonArray as $button) {
643 if (in_array($button, $this->toolbar
)) {
648 $hidePlugins[] = $pluginId;
652 $this->pluginEnabledArray
= array_diff($this->pluginEnabledArray
, $hidePlugins);
654 // Hiding labels of disabled plugins
655 $hideLabels = array();
656 foreach ($this->pluginLabel
as $pluginId => $label) {
657 if (!$this->isPluginEnabled($pluginId)) {
658 $hideLabels[] = $label;
661 $this->toolbar
= array_diff($this->toolbar
, $hideLabels);
663 // Adding plugins declared as prerequisites by enabled plugins
664 $requiredPlugins = array();
665 foreach ($this->registeredPlugins
as $pluginId => $plugin) {
666 if ($this->isPluginEnabled($pluginId)) {
667 $requiredPlugins = array_merge($requiredPlugins, t3lib_div
::trimExplode(',', $plugin->getRequiredPlugins(), 1));
670 $requiredPlugins = array_unique($requiredPlugins);
671 foreach ($requiredPlugins as $pluginId) {
672 if (is_object($this->registeredPlugins
[$pluginId]) && !$this->isPluginEnabled($pluginId)) {
673 $this->pluginEnabledArray
[] = $pluginId;
676 $this->pluginEnabledArray
= array_unique($this->pluginEnabledArray
);
678 // Completing the toolbar conversion array for htmlArea
679 foreach ($this->registeredPlugins
as $pluginId => $plugin) {
680 if ($this->isPluginEnabled($pluginId)) {
681 $this->convertToolbarForHtmlAreaArray
= array_unique(array_merge($this->convertToolbarForHtmlAreaArray
, $plugin->getConvertToolbarForHtmlAreaArray()));
687 * Convert the TYPO3 names of buttons into the names for htmlArea RTE
689 * @param string buttonname (typo3-name)
690 * @return string buttonname (htmlarea-name)
693 function convertToolbarForHTMLArea($button) {
694 return $this->convertToolbarForHtmlAreaArray
[$button];
697 * Return the HTML code for loading the Javascript files
699 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
701 * @return string the html code for loading the Javascript Files
703 function loadJSfiles($RTEcounter) {
704 // Re-initialize the scripts array so that only the cumulative set of plugins of the last RTE on the page is used
705 $this->cumulativeScripts
[$RTEcounter] = array();
706 $this->writeTemporaryFile('EXT:' . $this->ID
. '/htmlarea/htmlarea.js', 'htmlarea', 'js', '', TRUE);
707 if ($this->client
['browser'] == 'msie') {
708 $this->writeTemporaryFile('EXT:' . $this->ID
. '/htmlarea/htmlarea-ie.js', 'htmlarea-ie', 'js', '', TRUE);
710 $this->writeTemporaryFile('EXT:' . $this->ID
. '/htmlarea/htmlarea-gecko.js', 'htmlarea-gecko', 'js', '', TRUE);
712 foreach ($this->pluginEnabledCumulativeArray
[$RTEcounter] as $pluginId) {
713 $extensionKey = is_object($this->registeredPlugins
[$pluginId]) ?
$this->registeredPlugins
[$pluginId]->getExtensionKey() : $this->ID
;
714 $this->writeTemporaryFile('EXT:' . $extensionKey . '/htmlarea/plugins/' . $pluginId . '/' . strtolower(preg_replace('/([a-z])([A-Z])([a-z])/', "$1".'-'."$2"."$3", $pluginId)) . '.js', $pluginId, 'js', '', TRUE);
716 $this->buildJSMainLangFile($RTEcounter);
717 // Avoid re-initialization on AJax call when RTEarea object was already initialized
718 $loadJavascriptCode = '
719 <script type="text/javascript" src="' . $this->doConcatenate($RTEcounter) . '"></script>
720 <script type="text/javascript">
722 if (typeof(RTEarea) == "undefined") {
723 RTEarea = new Object();
724 RTEarea[0] = new Object();
725 RTEarea[0].version = "' . $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID
]['version'] . '";
726 RTEarea[0].editorUrl = "' . $this->extHttpPath
. 'htmlarea/";
727 RTEarea[0].editorCSS = "' . t3lib_div
::createVersionNumberedFilename($this->editorCSS
) . '";
728 RTEarea[0].editorSkin = "' . dirname($this->editorCSS
) . '/";
729 RTEarea[0].editedContentCSS = "' . t3lib_div
::createVersionNumberedFilename($this->editedContentCSS
) . '";
730 RTEarea[0].hostUrl = "' . $this->hostURL
. '";
731 RTEarea[0].enableDebugMode = ' . ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID
]['enableDebugMode'] ?
'true' : 'false') . ';
732 RTEarea.init = function() {
733 if (typeof(HTMLArea) == "undefined" || !Ext.isReady) {
734 window.setTimeout("RTEarea.init();", 40);
736 Ext.QuickTips.init();
740 RTEarea.initEditor = function(editorNumber) {
741 if (typeof(HTMLArea) == "undefined") {
742 RTEarea.initEditor.defer(40, null, [editorNumber]);
744 HTMLArea.initEditor(editorNumber);
750 return $loadJavascriptCode;
754 * Return the Javascript code for initializing the RTE
756 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
758 * @return string the Javascript code for initializing the RTE
760 function loadJScode($RTEcounter) {
761 return (!$this->is_FE() ?
'' : '
762 ' . '/*<![CDATA[*/') . '
763 RTEarea.init();' . (!$this->is_FE() ?
'' : '
769 * Return the Javascript code for configuring the RTE
771 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
772 * @param string $table: The table that includes this RTE (optional, necessary for IRRE).
773 * @param string $uid: The uid of that table that includes this RTE (optional, necessary for IRRE).
774 * @param string $field: The field of that record that includes this RTE (optional).
776 * @return string the Javascript code for configuring the RTE
778 function registerRTEinJS($RTEcounter, $table='', $uid='', $field='', $textAreaId = '') {
780 $configureRTEInJavascriptString = (!$this->is_FE() ?
'' : '
781 ' . '/*<![CDATA[*/') . '
782 if (typeof(configureEditorInstance) == "undefined") {
783 configureEditorInstance = new Object();
785 configureEditorInstance["' . $textAreaId . '"] = function() {
786 if (typeof(RTEarea) == "undefined" || typeof(HTMLArea) == "undefined") {
787 window.setTimeout("configureEditorInstance[\'' . $textAreaId . '\']();", 40);
789 editornumber = "' . $textAreaId . '";
790 RTEarea[editornumber] = new Object();
791 RTEarea[editornumber].RTEtsConfigParams = "&RTEtsConfigParams=' . rawurlencode($this->RTEtsConfigParams()) . '";
792 RTEarea[editornumber].number = editornumber;
793 RTEarea[editornumber].deleted = false;
794 RTEarea[editornumber].textAreaId = "' . $textAreaId . '";
795 RTEarea[editornumber].id = "RTEarea" + editornumber;
796 RTEarea[editornumber].RTEWidthOverride = "' . trim($this->thisConfig
['RTEWidthOverride']) . '";
797 RTEarea[editornumber].RTEHeightOverride = "' . trim($this->thisConfig
['RTEHeightOverride']) . '";
798 RTEarea[editornumber].fullScreen = ' . ($this->fullScreen ?
'true' : 'false') . ';
799 RTEarea[editornumber].showStatusBar = ' . (trim($this->thisConfig
['showStatusBar'])?
'true':'false') . ';
800 RTEarea[editornumber].enableWordClean = ' . (trim($this->thisConfig
['enableWordClean'])?
'true':'false') . ';
801 RTEarea[editornumber].htmlRemoveComments = ' . (trim($this->thisConfig
['removeComments'])?
'true':'false') . ';
802 RTEarea[editornumber].disableEnterParagraphs = ' . (trim($this->thisConfig
['disableEnterParagraphs'])?
'true':'false') . ';
803 RTEarea[editornumber].disableObjectResizing = ' . (trim($this->thisConfig
['disableObjectResizing'])?
'true':'false') . ';
804 RTEarea[editornumber].removeTrailingBR = ' . (trim($this->thisConfig
['removeTrailingBR'])?
'true':'false') . ';
805 RTEarea[editornumber].useCSS = ' . (trim($this->thisConfig
['useCSS'])?
'true':'false') . ';
806 RTEarea[editornumber].keepButtonGroupTogether = ' . (trim($this->thisConfig
['keepButtonGroupTogether'])?
'true':'false') . ';
807 RTEarea[editornumber].disablePCexamples = ' . (trim($this->thisConfig
['disablePCexamples'])?
'true':'false') . ';
808 RTEarea[editornumber].showTagFreeClasses = ' . (trim($this->thisConfig
['showTagFreeClasses'])?
'true':'false') . ';
809 RTEarea[editornumber].useHTTPS = ' . ((trim(stristr($this->siteURL
, 'https')) ||
$this->thisConfig
['forceHTTPS'])?
'true':'false') . ';
810 RTEarea[editornumber].tceformsNested = ' . (is_object($this->TCEform
) && method_exists($this->TCEform
, 'getDynNestedStack') ?
$this->TCEform
->getDynNestedStack(true) : '[]') . ';
811 RTEarea[editornumber].dialogueWindows = new Object();
812 RTEarea[editornumber].dialogueWindows.defaultPositionFromTop = ' . (isset($this->thisConfig
['dialogueWindows.']['defaultPositionFromTop'])?
intval($this->thisConfig
['dialogueWindows.']['defaultPositionFromTop']) : '100') . ';
813 RTEarea[editornumber].dialogueWindows.defaultPositionFromLeft = ' . (isset($this->thisConfig
['dialogueWindows.']['defaultPositionFromLeft'])?
intval($this->thisConfig
['dialogueWindows.']['defaultPositionFromLeft']) : '100') . ';
814 RTEarea[editornumber].dialogueWindows.doNotResize = ' . (trim($this->thisConfig
['dialogueWindows.']['doNotResize'])?
'true':'false') . ';
815 RTEarea[editornumber].dialogueWindows.doNotCenter = ' . (trim($this->thisConfig
['dialogueWindows.']['doNotCenter'])?
'true':'false') . ';';
817 // The following properties apply only to the backend
818 if (!$this->is_FE()) {
819 $configureRTEInJavascriptString .= '
820 RTEarea[editornumber].sys_language_content = "' . $this->contentLanguageUid
. '";
821 RTEarea[editornumber].typo3ContentLanguage = "' . $this->contentTypo3Language
. '";
822 RTEarea[editornumber].typo3ContentCharset = "' . $this->contentCharset
. '";
823 RTEarea[editornumber].userUid = "' . $this->userUid
. '";';
826 // Setting the plugin flags
827 $configureRTEInJavascriptString .= '
828 RTEarea[editornumber].plugin = new Object();
829 RTEarea[editornumber].pathToPluginDirectory = new Object();';
830 foreach ($this->pluginEnabledArray
as $pluginId) {
831 $configureRTEInJavascriptString .= '
832 RTEarea[editornumber].plugin.'.$pluginId.' = true;';
833 if (is_object($this->registeredPlugins
[$pluginId])) {
834 $pathToPluginDirectory = $this->registeredPlugins
[$pluginId]->getPathToPluginDirectory();
835 if ($pathToPluginDirectory) {
836 $configureRTEInJavascriptString .= '
837 RTEarea[editornumber].pathToPluginDirectory.'.$pluginId.' = "' . $pathToPluginDirectory . '";';
842 // Setting the buttons configuration
843 $configureRTEInJavascriptString .= '
844 RTEarea[editornumber].buttons = new Object();';
845 if (is_array($this->thisConfig
['buttons.'])) {
846 foreach ($this->thisConfig
['buttons.'] as $buttonIndex => $conf) {
847 $button = substr($buttonIndex, 0, -1);
848 if (in_array($button,$this->toolbar
)) {
849 $configureRTEInJavascriptString .= '
850 RTEarea[editornumber].buttons.'.$button.' = ' . $this->buildNestedJSArray($conf) . ';';
855 // Setting the list of tags to be removed if specified in the RTE config
856 if (trim($this->thisConfig
['removeTags'])) {
857 $configureRTEInJavascriptString .= '
858 RTEarea[editornumber].htmlRemoveTags = /^(' . implode('|', t3lib_div
::trimExplode(',', $this->thisConfig
['removeTags'], 1)) . ')$/i;';
861 // Setting the list of tags to be removed with their contents if specified in the RTE config
862 if (trim($this->thisConfig
['removeTagsAndContents'])) {
863 $configureRTEInJavascriptString .= '
864 RTEarea[editornumber].htmlRemoveTagsAndContents = /^(' . implode('|', t3lib_div
::trimExplode(',', $this->thisConfig
['removeTagsAndContents'], 1)) . ')$/i;';
866 // Process default style configuration
867 $configureRTEInJavascriptString .= '
868 RTEarea[editornumber].defaultPageStyle = "' . $this->writeTemporaryFile('', 'defaultPageStyle', 'css', $this->buildStyleSheet()) . '";';
869 // Setting the pageStyle
870 $filename = trim($this->thisConfig
['contentCSS']) ?
trim($this->thisConfig
['contentCSS']) : 'EXT:' . $this->ID
. '/res/contentcss/default.css';
871 $configureRTEInJavascriptString .= '
872 RTEarea[editornumber].pageStyle = "' . t3lib_div
::createVersionNumberedFilename($this->getFullFileName($filename)) .'";';
873 // Process classes configuration
874 $classesConfigurationRequired = false;
875 foreach ($this->registeredPlugins
as $pluginId => $plugin) {
876 if ($this->isPluginEnabled($pluginId)) {
877 $classesConfigurationRequired = $classesConfigurationRequired ||
$plugin->requiresClassesConfiguration();
880 if ($classesConfigurationRequired) {
881 $configureRTEInJavascriptString .= $this->buildJSClassesConfig($RTEcounter);
883 // Add Javascript configuration for registered plugins
884 foreach ($this->registeredPlugins
as $pluginId => $plugin) {
885 if ($this->isPluginEnabled($pluginId)) {
886 $configureRTEInJavascriptString .= $plugin->buildJavascriptConfiguration('editornumber');
889 // Avoid premature reference to HTMLArea when being initially loaded by IRRE Ajax call
890 $configureRTEInJavascriptString .= '
891 RTEarea[editornumber].toolbar = ' . $this->getJSToolbarArray() . ';
892 RTEarea[editornumber].convertButtonId = ' . json_encode(array_flip($this->convertToolbarForHtmlAreaArray
)) . ';
893 RTEarea.initEditor(editornumber);
896 configureEditorInstance["' . $textAreaId . '"]();'. (!$this->is_FE() ?
'' : '
898 return $configureRTEInJavascriptString;
902 * Return true, if the plugin can be loaded
904 * @param string $pluginId: The identification string of the plugin
906 * @return boolean true if the plugin can be loaded
909 function isPluginEnabled($pluginId) {
910 return in_array($pluginId, $this->pluginEnabledArray
);
914 * Build the default content style sheet
916 * @return string Style sheet
918 function buildStyleSheet() {
920 if (!trim($this->thisConfig
['ignoreMainStyleOverride'])) {
921 $mainStyle_font = $this->thisConfig
['mainStyle_font'] ?
$this->thisConfig
['mainStyle_font']: 'Verdana,sans-serif';
923 $mainElements = array();
924 $mainElements['P'] = $this->thisConfig
['mainStyleOverride_add.']['P'];
925 $elList = explode(',','H1,H2,H3,H4,H5,H6,PRE');
926 foreach ($elList as $elListName) {
927 if ($this->thisConfig
['mainStyleOverride_add.'][$elListName]) {
928 $mainElements[$elListName] = $this->thisConfig
['mainStyleOverride_add.'][$elListName];
932 $addElementCode = '';
933 foreach ($mainElements as $elListName => $elValue) {
934 $addElementCode .= strToLower($elListName) . ' {' . $elValue . '}' . LF
;
937 $stylesheet = $this->thisConfig
['mainStyleOverride'] ?
$this->thisConfig
['mainStyleOverride'] : LF
.
938 'body.htmlarea-content-body { font-family: ' . $mainStyle_font .
939 '; font-size: '.($this->thisConfig
['mainStyle_size'] ?
$this->thisConfig
['mainStyle_size'] : '12px') .
940 '; color: '.($this->thisConfig
['mainStyle_color']?
$this->thisConfig
['mainStyle_color'] : 'black') .
941 '; background-color: '.($this->thisConfig
['mainStyle_bgcolor'] ?
$this->thisConfig
['mainStyle_bgcolor'] : 'white') .
942 ';'.$this->thisConfig
['mainStyleOverride_add.']['BODY'].'}' . LF
.
943 'td { ' . $this->thisConfig
['mainStyleOverride_add.']['TD'].'}' . LF
.
944 'div { ' . $this->thisConfig
['mainStyleOverride_add.']['DIV'].'}' . LF
.
945 'pre { ' . $this->thisConfig
['mainStyleOverride_add.']['PRE'].'}' . LF
.
946 'ol { ' . $this->thisConfig
['mainStyleOverride_add.']['OL'].'}' . LF
.
947 'ul { ' . $this->thisConfig
['mainStyleOverride_add.']['UL'].'}' . LF
.
948 'blockquote { ' . $this->thisConfig
['mainStyleOverride_add.']['BLOCKQUOTE'].'}' . LF
.
951 if (is_array($this->thisConfig
['inlineStyle.'])) {
952 $stylesheet .= LF
. implode(LF
, $this->thisConfig
['inlineStyle.']) . LF
;
955 $stylesheet = '/* mainStyleOverride and inlineStyle properties ignored. */';
961 * Return Javascript configuration of classes
963 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
965 * @return string Javascript configuration of classes
967 function buildJSClassesConfig($RTEcounter) {
968 // Build JS array of lists of classes
969 $classesTagList = 'classesCharacter, classesParagraph, classesImage, classesTable, classesLinks, classesTD';
970 $classesTagConvert = array( 'classesCharacter' => 'span', 'classesParagraph' => 'div', 'classesImage' => 'img', 'classesTable' => 'table', 'classesLinks' => 'a', 'classesTD' => 'td');
971 $classesTagArray = t3lib_div
::trimExplode(',' , $classesTagList);
972 $configureRTEInJavascriptString = '
973 RTEarea[editornumber].classesTag = new Object();';
974 foreach ($classesTagArray as $classesTagName) {
975 $HTMLAreaJSClasses = ($this->thisConfig
[$classesTagName])?
('"' . $this->cleanList($this->thisConfig
[$classesTagName]) . '";'):'null;';
976 $configureRTEInJavascriptString .= '
977 RTEarea[editornumber].classesTag.'. $classesTagConvert[$classesTagName] .' = '. $HTMLAreaJSClasses;
979 // Include JS arrays of configured classes
980 $configureRTEInJavascriptString .= '
981 RTEarea[editornumber].classesUrl = "' . $this->writeTemporaryFile('', 'classes_'.$LANG->lang
, 'js', $this->buildJSClassesArray()) . '";';
982 return $configureRTEInJavascriptString;
986 * Return JS arrays of classes configuration
988 * @return string JS classes arrays
990 function buildJSClassesArray() {
991 if ($this->is_FE()) {
992 $RTEProperties = $this->RTEsetup
;
994 $RTEProperties = $this->RTEsetup
['properties'];
996 $classesArray = array('labels' => array(), 'values' => array(), 'noShow' => array(), 'alternating' => array(), 'counting' => array(), 'XOR' => array());
997 $JSClassesArray = '';
998 // Scanning the list of classes if specified in the RTE config
999 if (is_array($RTEProperties['classes.'])) {
1000 foreach ($RTEProperties['classes.'] as $className => $conf) {
1001 $className = rtrim($className, '.');
1002 $classesArray['labels'][$className] = $this->getPageConfigLabel($conf['name'], FALSE);
1003 $classesArray['values'][$className] = str_replace('\\\'', '\'', $conf['value']);
1004 if (isset($conf['noShow'])) {
1005 $classesArray['noShow'][$className] = $conf['noShow'];
1007 if (is_array($conf['alternating.'])) {
1008 $classesArray['alternating'][$className] = $conf['alternating.'];
1010 if (is_array($conf['counting.'])) {
1011 $classesArray['counting'][$className] = $conf['counting.'];
1015 // Scanning the list of sets of mutually exclusives classes if specified in the RTE config
1016 if (is_array($RTEProperties['mutuallyExclusiveClasses.'])) {
1017 foreach ($RTEProperties['mutuallyExclusiveClasses.'] as $listName => $conf) {
1018 $classSet = t3lib_div
::trimExplode(',', $conf, 1);
1019 $classList = implode(',', $classSet);
1020 foreach ($classSet as $className) {
1021 $classesArray['XOR'][$className] = '/^(' . implode('|', t3lib_div
::trimExplode(',', t3lib_div
::rmFromList($className, $classList), 1)) . ')$/';
1025 foreach ($classesArray as $key => $subArray) {
1026 $JSClassesArray .= 'HTMLArea.classes' . ucfirst($key) . ' = ' . $this->buildNestedJSArray($subArray) . ';' . LF
;
1028 return $JSClassesArray;
1032 * Translate Page TS Config array in JS nested array definition
1033 * Replace 0 values with false
1034 * Unquote regular expression values
1035 * Replace empty arrays with empty objects
1037 * @param array $conf: Page TSConfig configuration array
1039 * @return string nested JS array definition
1041 function buildNestedJSArray($conf) {
1042 $convertedConf = t3lib_div
::removeDotsFromTS($conf);
1043 if ($this->is_FE()) {
1044 $GLOBALS['TSFE']->csConvObj
->convArray($convertedConf, ($GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] ?
$GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] : 'iso-8859-1'), 'utf-8');
1046 $GLOBALS['LANG']->csConvObj
->convArray($convertedConf, $GLOBALS['LANG']->charSet
, 'utf-8');
1048 return str_replace(array(':"0"', ':"\/^(', ')$\/i"', ':"\/^(', ')$\/"', '[]'), array(':false', ':/^(', ')$/i', ':/^(', ')$/', '{}'), json_encode($convertedConf));
1052 * Return a Javascript localization array for htmlArea RTE
1054 * @return string Javascript localization array
1056 function buildJSMainLangArray() {
1057 $JSLanguageArray = 'HTMLArea.I18N = new Object();' . LF
;
1058 $labelsArray = array('tooltips' => array(), 'msg' => array(), 'dialogs' => array());
1059 foreach ($labelsArray as $labels => $subArray) {
1060 $LOCAL_LANG = t3lib_div
::readLLfile('EXT:' . $this->ID
. '/htmlarea/locallang_' . $labels . '.xml', $this->language
, 'utf-8');
1061 if (!empty($LOCAL_LANG[$this->language
])) {
1062 $LOCAL_LANG[$this->language
] = t3lib_div
::array_merge_recursive_overrule($LOCAL_LANG['default'], $LOCAL_LANG[$this->language
]);
1064 $LOCAL_LANG[$this->language
] = $LOCAL_LANG['default'];
1066 $labelsArray[$labels] = $LOCAL_LANG[$this->language
];
1068 $JSLanguageArray .= 'HTMLArea.I18N = ' . json_encode($labelsArray) . ';' . LF
;
1069 return $JSLanguageArray;
1073 * Writes contents in a file in typo3temp/rtehtmlarea directory and returns the file name
1075 * @param string $sourceFileName: The name of the file from which the contents should be extracted
1076 * @param string $label: A label to insert at the beginning of the name of the file
1077 * @param string $fileExtension: The file extension of the file, defaulting to 'js'
1078 * @param string $contents: The contents to write into the file if no $sourceFileName is provided
1080 * @return string The name of the file writtten to typo3temp/rtehtmlarea
1082 public function writeTemporaryFile($sourceFileName='', $label, $fileExtension='js', $contents='', $concatenate = FALSE) {
1083 global $TYPO3_CONF_VARS;
1085 if ($sourceFileName) {
1087 $source = t3lib_div
::getFileAbsFileName($sourceFileName);
1088 $output = file_get_contents($source);
1090 $output = $contents;
1092 $compress = $TYPO3_CONF_VARS['EXTCONF'][$this->ID
]['enableCompressedScripts'] && ($fileExtension == 'js') && ($output != '');
1093 $relativeFilename = 'typo3temp/' . $this->ID
. '/' . str_replace('-','_',$label) . '_' . t3lib_div
::shortMD5(($TYPO3_CONF_VARS['EXTCONF'][$this->ID
]['version'] . ($sourceFileName ?
$sourceFileName : $output)), 20) . ($compress ?
'_compressed' : '') . '.' . $fileExtension;
1094 $destination = PATH_site
. $relativeFilename;
1095 if(!file_exists($destination)) {
1096 $compressedJavaScript = '';
1097 if ($compress && $fileExtension == 'js') {
1098 $compressedJavaScript = t3lib_div
::minifyJavaScript($output);
1100 $failure = t3lib_div
::writeFileToTypo3tempDir($destination, $compressedJavaScript ?
$compressedJavaScript : $output);
1105 if ($concatenate && $fileExtension == 'js') {
1106 $this->cumulativeScripts
[$this->TCEform
->RTEcounter
][] = $destination;
1108 if ($this->is_FE()) {
1109 $filename = ($GLOBALS['TSFE']->absRefPrefix ?
$GLOBALS['TSFE']->absRefPrefix
: '') . t3lib_div
::createVersionNumberedFilename($relativeFilename);
1111 $filename = t3lib_div
::createVersionNumberedFilename(($this->isFrontendEditActive() ?
'' : ($this->backPath
. '../')) . $relativeFilename);
1113 return t3lib_div
::resolveBackPath($filename);
1116 * Concatenates all accumulated scripts in a file in typo3temp/rtehtmlarea directory and returns the file name
1118 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
1120 * @return string The name of the file writtten to typo3temp/rtehtmlarea
1122 protected function doConcatenate($RTEcounter) {
1123 $fileExtension = 'js';
1124 $compress = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID
]['enableCompressedScripts'];
1125 $token = implode('|', $this->cumulativeScripts
[$RTEcounter]);
1126 $relativeFilename = 'typo3temp/' . $this->ID
. '/' . 'htmlarea_cumulative' . '_' . t3lib_div
::shortMD5(($TYPO3_CONF_VARS['EXTCONF'][$this->ID
]['version'] . $token ), 20) . ($compress ?
'_compressed' : '') . '.' . $fileExtension;
1127 $destination = PATH_site
. $relativeFilename;
1128 if (!file_exists($destination)) {
1129 foreach ($this->cumulativeScripts
[$RTEcounter] as $fileName) {
1130 $contents = file_get_contents($fileName);
1131 if (!file_exists($destination)) {
1132 $failure = t3lib_div
::writeFileToTypo3tempDir($destination, $contents);
1137 $success = file_put_contents($destination, $contents, FILE_APPEND
);
1139 die('Could not append script' +
$fileName);
1144 if ($this->is_FE()) {
1145 $filename = ($GLOBALS['TSFE']->absRefPrefix ?
$GLOBALS['TSFE']->absRefPrefix
: '') . t3lib_div
::createVersionNumberedFilename($relativeFilename);
1148 $compressor = t3lib_div
::makeInstance('t3lib_Compressor');
1149 $filename = $compressor->compressJsFile(($this->isFrontendEditActive() ?
'' : $this->backPath
) . '../' . $relativeFilename);
1150 if ($this->isFrontendEditActive()) {
1151 $filename = preg_replace('/^..\//', '', $filename);
1154 $filename = t3lib_div
::createVersionNumberedFilename(($this->isFrontendEditActive() ?
'' : ($this->backPath
. '../')) . $relativeFilename);
1157 return t3lib_div
::resolveBackPath($filename);
1161 * Return a file name containing the main JS language array for HTMLArea
1163 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
1165 * @return string filename
1167 function buildJSMainLangFile($RTEcounter) {
1168 $contents = $this->buildJSMainLangArray() . LF
;
1169 foreach ($this->pluginEnabledCumulativeArray
[$RTEcounter] as $pluginId) {
1170 $contents .= $this->buildJSLangArray($pluginId) . LF
;
1172 return $this->writeTemporaryFile('', $this->language
.'_'.$this->OutputCharset
, 'js', $contents, TRUE);
1176 * Return a Javascript localization array for the plugin
1178 * @param string $plugin: identification string of the plugin
1180 * @return string Javascript localization array
1183 function buildJSLangArray($plugin) {
1184 $LOCAL_LANG = FALSE;
1185 $extensionKey = is_object($this->registeredPlugins
[$plugin]) ?
$this->registeredPlugins
[$plugin]->getExtensionKey() : $this->ID
;
1186 $LOCAL_LANG = t3lib_div
::readLLfile('EXT:' . $extensionKey . '/htmlarea/plugins/' . $plugin . '/locallang.xml', $this->language
, 'utf-8', 1);
1187 $linebreak = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID
]['enableCompressedScripts'] ?
'' : LF
;
1188 $JSLanguageArray = 'HTMLArea.I18N["' . $plugin . '"] = new Object();' . $linebreak;
1189 if (is_array($LOCAL_LANG)) {
1190 if (!empty($LOCAL_LANG[$this->language
])) {
1191 $LOCAL_LANG[$this->language
] = t3lib_div
::array_merge_recursive_overrule($LOCAL_LANG['default'],$LOCAL_LANG[$this->language
]);
1193 $LOCAL_LANG[$this->language
] = $LOCAL_LANG['default'];
1195 $JSLanguageArray .= 'HTMLArea.I18N["' . $plugin . '"] = ' . json_encode($LOCAL_LANG[$this->language
]) . ';'. LF
;
1197 return $JSLanguageArray;
1201 * Return the JS code of the toolbar configuration for the HTMLArea editor
1203 * @return string the JS code as nested JS arrays
1205 protected function getJSToolbarArray() {
1206 // The toolbar array
1208 // The current row; a "linebreak" ends the current row
1210 // The current group; each group is between "bar"s; a "linebreak" ends the current group
1212 // Process each toolbar item in the toolbar order list
1213 foreach ($this->toolbarOrderArray
as $item) {
1216 // Add row to toolbar if not empty
1217 if (!empty($group)) {
1227 // Add group to row if not empty
1228 if (!empty($group)) {
1234 if (end($group) != $this->convertToolbarForHTMLArea($item)) {
1235 $group[] = $this->convertToolbarForHTMLArea($item);
1239 if (in_array($item, $this->toolbar
)) {
1240 // Add the item to the group
1241 $convertedItem = $this->convertToolbarForHTMLArea($item);
1242 if ($convertedItem) {
1243 $group[] = $convertedItem;
1249 // Add the last group and last line, if not empty
1250 if (!empty($group)) {
1256 return json_encode($toolbar);
1259 public function getLLContent($string) {
1262 $BE_lang = $LANG->lang
;
1263 $BE_charSet = $LANG->charSet
;
1264 $LANG->lang
= $this->contentTypo3Language
;
1265 $LANG->charSet
= $this->contentCharset
;
1266 $LLString = $LANG->JScharCode($LANG->sL($string));
1267 $LANG->lang
= $BE_lang;
1268 $LANG->charSet
= $BE_charSet;
1272 public function getPageConfigLabel($string,$JScharCode=1) {
1273 global $LANG, $TSFE, $TYPO3_CONF_VARS;
1275 if ($this->is_FE()) {
1276 if (strcmp(substr($string,0,4),'LLL:') && $TYPO3_CONF_VARS['BE']['forceCharset']) {
1277 // A pure string coming from Page TSConfig must be in forceCharset, otherwise we just don't know..
1278 $label = $TSFE->csConvObj
->conv($TSFE->sL(trim($string)), $TYPO3_CONF_VARS['BE']['forceCharset'], $this->OutputCharset
);
1280 $label = $TSFE->csConvObj
->conv($TSFE->sL(trim($string)), $this->charset
, $this->OutputCharset
);
1282 $label = str_replace('"', '\"', str_replace('\\\'', '\'', $label));
1283 $label = $JScharCode ?
$this->feJScharCode($label) : $label;
1285 if (strcmp(substr($string,0,4),'LLL:')) {
1288 $label = $LANG->sL(trim($string));
1290 $label = str_replace('"', '\"', str_replace('\\\'', '\'', $label));
1291 $label = $JScharCode ?
$LANG->JScharCode($label): $label;
1296 function feJScharCode($str) {
1298 // Convert string to UTF-8:
1299 if ($this->OutputCharset
!= 'utf-8') $str = $TSFE->csConvObj
->utf8_encode($str,$this->OutputCharset
);
1300 // Convert the UTF-8 string into a array of char numbers:
1301 $nArr = $TSFE->csConvObj
->utf8_to_numberarray($str);
1302 return 'String.fromCharCode('.implode(',',$nArr).')';
1305 public function getFullFileName($filename) {
1306 if (substr($filename,0,4)=='EXT:') { // extension
1307 list($extKey,$local) = explode('/',substr($filename,4),2);
1309 if (strcmp($extKey,'') && t3lib_extMgm
::isLoaded($extKey) && strcmp($local,'')) {
1310 $newFilename = (($this->is_FE() ||
$this->isFrontendEditActive()) ? t3lib_extMgm
::siteRelPath($extKey) : $this->backPath
. t3lib_extMgm
::extRelPath($extKey)) . $local;
1312 } elseif (substr($filename,0,1) != '/') {
1313 $newFilename = (($this->is_FE() ||
$this->isFrontendEditActive()) ?
'' : ($this->backPath
. '../')) . $filename;
1315 $newFilename = (($this->is_FE() ||
$this->isFrontendEditActive()) ?
'' : ($this->backPath
. '../')) . substr($filename, 1);
1317 return t3lib_div
::resolveBackPath($newFilename);
1321 * Return the Javascript code for copying the HTML code from the editor into the hidden input field.
1322 * This is for submit function of the form.
1324 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
1325 * @param string $formName: the name of the form
1326 * @param string $textareaId: the id of the textarea
1328 * @return string Javascript code
1330 function setSaveRTE($RTEcounter, $formName, $textareaId) {
1331 return 'if (RTEarea["' . $textareaId . '"]) { document.' . $formName . '["' . $textareaId . '"].value = RTEarea["' . $textareaId . '"].editor.getHTML(); } else { OK = 0; };';
1335 * Return the Javascript code for copying the HTML code from the editor into the hidden input field.
1336 * This is for submit function of the form.
1338 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
1339 * @param string $formName: the name of the form
1340 * @param string $textareaId: the id of the textarea
1342 * @return string Javascript code
1344 function setDeleteRTE($RTEcounter, $formName, $textareaId) {
1345 return 'if (RTEarea["' . $textareaId . '"]) { RTEarea["' . $textareaId . '"].deleted = true;}';
1349 * Return true if we are in the FE, but not in the FE editing feature of BE.
1355 return is_object($GLOBALS['TSFE']) && !$this->isFrontendEditActive();
1359 * Checks whether frontend editing is active.
1363 public function isFrontendEditActive() {
1364 return is_object($GLOBALS['TSFE']) && $GLOBALS['TSFE']->beUserLogin
&& ($GLOBALS['BE_USER']->frontendEdit
instanceof t3lib_frontendedit
);
1367 * Client Browser Information
1369 * @param string $userAgent: The useragent string, t3lib_div::getIndpEnv('HTTP_USER_AGENT')
1370 * @return array Contains keys "useragent", "browser", "version", "system"
1371 * where "browser" is limited to the engines
1372 * and where "version" is a floating number
1374 function clientInfo ($userAgent='') {
1376 $userAgent = t3lib_div
::getIndpEnv('HTTP_USER_AGENT');
1378 $browserInfo = t3lib_utility_Client
::getBrowserInfo($userAgent);
1379 // Known engines: order is not irrelevant!
1380 $knownEngines = array('opera', 'msie', 'gecko', 'webkit');
1381 if (is_array($browserInfo['all'])) {
1382 foreach ($knownEngines as $engine) {
1383 if ($browserInfo['all'][$engine]) {
1384 $browserInfo['browser'] = $engine;
1385 $browserInfo['version'] = t3lib_utility_Client
::getVersion($browserInfo['all'][$engine]);
1390 return $browserInfo;
1392 /***************************
1394 * OTHER FUNCTIONS: (from Classic RTE)
1396 ***************************/
1398 * @return [type] ...
1402 function RTEtsConfigParams() {
1403 if($this->is_FE()) {
1406 $p = t3lib_BEfunc
::getSpecConfParametersFromArray($this->specConf
['rte_transform']['parameters']);
1407 return $this->elementParts
[0].':'.$this->elementParts
[1].':'.$this->elementParts
[2].':'.$this->thePid
.':'.$this->typeVal
.':'.$this->tscPID
.':'.$p['imgpath'];
1411 public function cleanList($str) {
1412 if (strstr($str,'*')) {
1415 $str = implode(',',array_unique(t3lib_div
::trimExplode(',',$str,1)));
1420 function filterStyleEl($elValue,$matchList) {
1421 $matchParts = t3lib_div
::trimExplode(',',$matchList,1);
1422 $styleParts = explode(';',$elValue);
1424 foreach ($styleParts as $k => $p) {
1425 $pp = t3lib_div
::trimExplode(':',$p);
1426 if ($pp[0]&&$pp[1]) {
1427 foreach ($matchParts as $el) {
1428 $star=substr($el,-1)=='*';
1429 if (!strcmp($pp[0],$el) ||
($star && t3lib_div
::isFirstPartOfStr($pp[0],substr($el,0,-1)) )) {
1430 $nStyle[]=$pp[0].':'.$pp[1];
1431 } else unset($styleParts[$k]);
1434 unset($styleParts[$k]);
1437 return implode('; ',$nStyle);
1440 // Hook on lorem_ipsum extension to insert text into the RTE in wysiwyg mode
1441 function loremIpsumInsert($params) {
1443 if (typeof(lorem_ipsum) == 'function' && " . $params['element'] . ".tagName.toLowerCase() == 'textarea' ) lorem_ipsum(" . $params['element'] . ", lipsum_temp_strings[lipsum_temp_pointer]);
1447 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['ext/rtehtmlarea/class.tx_rtehtmlarea_base.php']) {
1448 include_once($TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['ext/rtehtmlarea/class.tx_rtehtmlarea_base.php']);