2 /***************************************************************
5 * (c) 2004-2010 Kasper Skårhøj (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 (
89 // Always hide these toolbar buttons (TYPO3 button name)
90 var $conf_toolbar_hide = array (
91 'showhelp', // Has no content yet
94 // The order of the toolbar: the name is the TYPO3-button name
95 var $defaultToolbarOrder;
97 // Conversion array: TYPO3 button names to htmlArea button names
98 var $convertToolbarForHtmlAreaArray = array (
99 'showhelp' => 'ShowHelp',
101 'bar' => 'separator',
102 'linebreak' => 'linebreak',
105 var $pluginButton = array();
106 var $pluginLabel = array();
107 // Alternative style for RTE <div> tag.
109 // Relative path to this extension. It ends with "/"
111 public $backPath = '';
118 // Identifies the RTE as being the one from the "rtehtmlarea" extension if any external code needs to know
119 var $ID = 'rtehtmlarea';
120 // If set, the content goes into a regular TEXT area field - for developing testing of transformations.
121 var $debugMode = FALSE;
126 * Reference to parent object, which is an instance of the TCEforms
128 * @var t3lib_TCEforms
140 public $contentTypo3Language;
141 public $contentISOLanguage;
142 public $contentCharset;
143 public $OutputCharset;
146 var $toolbar = array(); // Save the buttons for the toolbar
147 var $toolbarOrderArray = array();
148 protected $pluginEnabledArray = array(); // Array of plugin id's enabled in the current RTE editing area
149 protected $pluginEnabledCumulativeArray = array(); // Cumulative array of plugin id's enabled so far in any of the RTE editing areas of the form
150 protected $cumulativeScripts = array();
151 public $registeredPlugins = array(); // Array of registered plugins indexed by their plugin Id's
152 protected $fullScreen = false;
155 * Returns true if the RTE is available. Here you check if the browser requirements are met.
156 * If there are reasons why the RTE cannot be displayed you simply enter them as text in ->errorLog
158 * @return boolean TRUE if this RTE object offers an RTE in the current browser environment
161 function isAvailable() {
162 global $TYPO3_CONF_VARS;
164 $this->client
= $this->clientInfo();
165 $this->errorLog
= array();
166 if (!$this->debugMode
) { // If debug-mode, let any browser through
168 $rteConfBrowser = $this->conf_supported_browser
;
169 if (is_array($rteConfBrowser)) {
170 foreach ($rteConfBrowser as $browser => $browserConf) {
171 if ($browser == $this->client
['browser']) {
172 // Config for Browser found, check it:
173 if (is_array($browserConf)) {
174 foreach ($browserConf as $browserConfNr => $browserConfSub) {
175 if ($browserConfSub['version'] <= $this->client
['version'] ||
empty($browserConfSub['version'])) {
176 // Version is correct
177 if ($browserConfSub['system'] == $this->client
['system'] ||
empty($browserConfSub['system'])) {
178 // System is correctly
182 }// End of foreach-BrowserSubpart
184 // no config for this browser found, so all versions or system with this browsers are allow
187 } // End of Browser Check
188 } // foreach: Browser Check
190 // no Browser config for this RTE-Editor, so all Clients are allow
192 if (!$rteIsAvailable) {
193 $this->errorLog
[] = 'rte: Browser not supported. Only msie Version 5 or higher and Mozilla based client 1. and higher.';
195 if (t3lib_div
::int_from_ver(TYPO3_version
) < 4000000) {
197 $this->errorLog
[] = 'rte: This version of htmlArea RTE cannot run under this version of TYPO3.';
200 if ($rteIsAvailable) return true;
204 * Draws the RTE as an iframe
206 * @param object Reference to parent object, which is an instance of the TCEforms.
207 * @param string The table name
208 * @param string The field name
209 * @param array The current row from which field is being rendered
210 * @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.
211 * @param array "special" configuration - what is found at position 4 in the types configuration of a field from record, parsed into an array.
212 * @param array Configuration for RTEs; A mix between TSconfig and otherwise. Contains configuration for display, which buttons are enabled, additional transformation information etc.
213 * @param string Record "type" field value.
214 * @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!
215 * @param integer PID value of record (true parent page id)
216 * @return string HTML code for RTE!
219 function drawRTE($parentObject, $table, $field, $row, $PA, $specConf, $thisConfig, $RTEtypeVal, $RTErelPath, $thePidValue) {
220 global $BE_USER, $LANG, $TYPO3_DB, $TYPO3_CONF_VARS;
222 $this->TCEform
= $parentObject;
223 $inline = $this->TCEform
->inline
;
224 $LANG->includeLLFile('EXT:' . $this->ID
. '/locallang.xml');
225 $this->client
= $this->clientInfo();
226 $this->typoVersion
= t3lib_div
::int_from_ver(TYPO3_version
);
227 $this->userUid
= 'BE_' . $BE_USER->user
['uid'];
229 // Draw form element:
230 if ($this->debugMode
) { // Draws regular text area (debug mode)
231 $item = parent
::drawRTE($this->TCEform
, $table, $field, $row, $PA, $specConf, $thisConfig, $RTEtypeVal, $RTErelPath, $thePidValue);
232 } else { // Draw real RTE
234 /* =======================================
235 * INIT THE EDITOR-SETTINGS
236 * =======================================
239 $this->backPath
= $this->TCEform
->backPath
;
240 // Get the path to this extension:
241 $this->extHttpPath
= $this->backPath
. t3lib_extMgm
::extRelPath($this->ID
);
243 $this->siteURL
= t3lib_div
::getIndpEnv('TYPO3_SITE_URL');
245 $this->hostURL
= $this->siteURL
. TYPO3_mainDir
;
247 $this->elementId
= $PA['itemFormElName']; // Form element name
248 $this->elementParts
= explode('][',preg_replace('/\]$/','',preg_replace('/^(TSFE_EDIT\[data\]\[|data\[)/','',$this->elementId
)));
249 // Find the page PIDs:
250 list($this->tscPID
,$this->thePid
) = t3lib_BEfunc
::getTSCpid(trim($this->elementParts
[0]),trim($this->elementParts
[1]),$thePidValue);
252 // Record "types" field value:
253 $this->typeVal
= $RTEtypeVal; // TCA "types" value for record
255 // Find "thisConfig" for record/editor:
256 unset($this->RTEsetup
);
257 $this->RTEsetup
= $BE_USER->getTSConfig('RTE',t3lib_BEfunc
::getPagesTSconfig($this->tscPID
));
258 $this->thisConfig
= $thisConfig;
260 // Special configuration and default extras:
261 $this->specConf
= $specConf;
263 if ($this->thisConfig
['forceHTTPS']) {
264 $this->extHttpPath
= preg_replace('/^(http|https)/', 'https', $this->extHttpPath
);
265 $this->siteURL
= preg_replace('/^(http|https)/', 'https', $this->siteURL
);
266 $this->hostURL
= preg_replace('/^(http|https)/', 'https', $this->hostURL
);
269 /* =======================================
270 * LANGUAGES & CHARACTER SETS
271 * =======================================
274 // Languages: interface and content
275 $this->language
= $LANG->lang
;
276 if ($this->language
=='default' ||
!$this->language
) {
277 $this->language
='en';
279 $this->contentTypo3Language
= $this->language
;
280 $this->contentISOLanguage
= 'en';
281 $this->contentLanguageUid
= ($row['sys_language_uid'] > 0) ?
$row['sys_language_uid'] : 0;
282 if (t3lib_extMgm
::isLoaded('static_info_tables')) {
283 if ($this->contentLanguageUid
) {
284 $tableA = 'sys_language';
285 $tableB = 'static_languages';
286 $languagesUidsList = $this->contentLanguageUid
;
287 $selectFields = $tableA . '.uid,' . $tableB . '.lg_iso_2,' . $tableB . '.lg_country_iso_2,' . $tableB . '.lg_typo3';
288 $tableAB = $tableA . ' LEFT JOIN ' . $tableB . ' ON ' . $tableA . '.static_lang_isocode=' . $tableB . '.uid';
289 $whereClause = $tableA . '.uid IN (' . $languagesUidsList . ') ';
290 $whereClause .= t3lib_BEfunc
::BEenableFields($tableA);
291 $whereClause .= t3lib_BEfunc
::deleteClause($tableA);
292 $res = $TYPO3_DB->exec_SELECTquery($selectFields, $tableAB, $whereClause);
293 while($languageRow = $TYPO3_DB->sql_fetch_assoc($res)) {
294 $this->contentISOLanguage
= strtolower(trim($languageRow['lg_iso_2']).(trim($languageRow['lg_country_iso_2'])?
'_'.trim($languageRow['lg_country_iso_2']):''));
295 $this->contentTypo3Language
= strtolower(trim($languageRow['lg_typo3']));
298 $this->contentISOLanguage
= trim($this->thisConfig
['defaultContentLanguage']) ?
trim($this->thisConfig
['defaultContentLanguage']) : 'en';
299 $selectFields = 'lg_iso_2, lg_typo3';
300 $tableAB = 'static_languages';
301 $whereClause = 'lg_iso_2 = ' . $TYPO3_DB->fullQuoteStr(strtoupper($this->contentISOLanguage
), $tableAB);
302 $res = $TYPO3_DB->exec_SELECTquery($selectFields, $tableAB, $whereClause);
303 while($languageRow = $TYPO3_DB->sql_fetch_assoc($res)) {
304 $this->contentTypo3Language
= strtolower(trim($languageRow['lg_typo3']));
309 // Character sets: interface and content
310 $this->charset
= $LANG->charSet
;
311 $this->OutputCharset
= $this->charset
;
313 $this->contentCharset
= $LANG->csConvObj
->charSetArray
[$this->contentTypo3Language
];
314 $this->contentCharset
= $this->contentCharset ?
$this->contentCharset
: 'iso-8859-1';
315 $this->origContentCharSet
= $this->contentCharset
;
316 $this->contentCharset
= (trim($TYPO3_CONF_VARS['BE']['forceCharset']) ?
trim($TYPO3_CONF_VARS['BE']['forceCharset']) : $this->contentCharset
);
318 /* =======================================
319 * TOOLBAR CONFIGURATION
320 * =======================================
322 $this->initializeToolbarConfiguration();
324 /* =======================================
326 * =======================================
329 $RTEWidth = isset($BE_USER->userTS
['options.']['RTESmallWidth']) ?
$BE_USER->userTS
['options.']['RTESmallWidth'] : '530';
330 $RTEHeight = isset($BE_USER->userTS
['options.']['RTESmallHeight']) ?
$BE_USER->userTS
['options.']['RTESmallHeight'] : '380';
331 $RTEWidth = $RTEWidth +
($this->TCEform
->docLarge ?
(isset($BE_USER->userTS
['options.']['RTELargeWidthIncrement']) ?
$BE_USER->userTS
['options.']['RTELargeWidthIncrement'] : '150') : 0);
332 $RTEWidth -= ($inline->getStructureDepth() > 0 ?
($inline->getStructureDepth()+
1)*$inline->getLevelMargin() : 0);
333 $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']);
334 if ($RTEWidthOverride) {
335 if (strstr($RTEWidthOverride, '%')) {
336 if ($this->client
['browser'] != 'msie') {
337 $RTEWidth = (intval($RTEWidthOverride) > 0) ?
$RTEWidthOverride : '100%';
340 $RTEWidth = (intval($RTEWidthOverride) > 0) ?
intval($RTEWidthOverride) : $RTEWidth;
343 $RTEWidth = strstr($RTEWidth, '%') ?
$RTEWidth : $RTEWidth . 'px';
344 $RTEHeight = $RTEHeight +
($this->TCEform
->docLarge ?
(isset($BE_USER->userTS
['options.']['RTELargeHeightIncrement']) ?
$BE_USER->userTS
['options.']['RTELargeHeightIncrement'] : 0) : 0);
345 $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']);
346 $RTEHeight = ($RTEHeightOverride > 0) ?
$RTEHeightOverride : $RTEHeight;
347 $editorWrapWidth = '99%';
348 $editorWrapHeight = '100%';
349 $this->RTEdivStyle
= 'position:relative; left:0px; top:0px; height:' . $RTEHeight . 'px; width:'.$RTEWidth.'; border: 1px solid black; padding: 2px 2px 2px 2px;';
351 /* =======================================
352 * LOAD CSS AND JAVASCRIPT
353 * =======================================
355 // Preloading the pageStyle and including RTE skin stylesheets
356 $this->addPageStyle();
358 // Loading JavaScript files and code
359 if ($this->TCEform
->RTEcounter
== 1) {
360 $this->TCEform
->additionalJS_pre
['rtehtmlarea-loadJScode'] = $this->loadJScode($this->TCEform
->RTEcounter
);
362 $this->TCEform
->additionalCode_pre
['rtehtmlarea-loadJSfiles'] = $this->loadJSfiles($this->TCEform
->RTEcounter
);
363 $pageRenderer = $GLOBALS['SOBE']->doc
->getPageRenderer();
364 $pageRenderer->enableExtJSQuickTips();
365 if (!$GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID
]['enableCompressedScripts']) {
366 $pageRenderer->enableExtJsDebug();
368 $pageRenderer->addJsFile('../t3lib/js/extjs/notifications.js');
369 /* =======================================
371 * =======================================
375 $value = $this->transformContent('rte',$PA['itemFormElValue'],$table,$field,$row,$specConf,$thisConfig,$RTErelPath,$thePidValue);
377 // Further content transformation by registered plugins
378 foreach ($this->registeredPlugins
as $pluginId => $plugin) {
379 if ($this->isPluginEnabled($pluginId) && method_exists($plugin, "transformContent")) {
380 $value = $plugin->transformContent($value);
383 // Register RTE windows
384 $this->TCEform
->RTEwindows
[] = $PA['itemFormElName'];
385 $textAreaId = preg_replace('/[^a-zA-Z0-9_:.-]/', '_', $PA['itemFormElName']);
386 $textAreaId = htmlspecialchars(preg_replace('/^[^a-zA-Z]/', 'x', $textAreaId));
388 // Check if wizard_rte called this for fullscreen edtition; if so, change the size of the RTE to fullscreen using JS
389 if (basename(PATH_thisScript
) == 'wizard_rte.php') {
390 $this->fullScreen
= true;
391 $editorWrapWidth = '100%';
392 $editorWrapHeight = '100%';
393 $this->RTEdivStyle
= 'position:relative; left:0px; top:0px; height:100%; width:100%; border: 1px solid black; padding: 2px 0px 2px 2px;';
396 // Register RTE in JS:
397 $this->TCEform
->additionalJS_post
[] = $this->registerRTEinJS($this->TCEform
->RTEcounter
, $table, $row['uid'], $field, $textAreaId);
399 // Set the save option for the RTE:
400 $this->TCEform
->additionalJS_submit
[] = $this->setSaveRTE($this->TCEform
->RTEcounter
, $this->TCEform
->formName
, $textAreaId, $PA['itemFormElName']);
401 $this->TCEform
->additionalJS_delete
[] = $this->setDeleteRTE($this->TCEform
->RTEcounter
, $this->TCEform
->formName
, $textAreaId);
404 $visibility = 'hidden';
405 $item = $this->triggerField($PA['itemFormElName']).'
406 <div id="pleasewait' . $textAreaId . '" class="pleasewait" style="display: block;" >' . $LANG->getLL('Please wait') . '</div>
407 <div id="editorWrap' . $textAreaId . '" class="editorWrap" style="visibility: hidden; width:' . $editorWrapWidth . '; height:' . $editorWrapHeight . ';">
408 <textarea id="RTEarea' . $textAreaId . '" name="'.htmlspecialchars($PA['itemFormElName']).'" rows="0" cols="0" style="'.t3lib_div
::deHSCentities(htmlspecialchars($this->RTEdivStyle
)).'">'.t3lib_div
::formatForTextarea($value).'</textarea>
409 </div>' . ($TYPO3_CONF_VARS['EXTCONF'][$this->ID
]['enableDebugMode'] ?
'<div id="HTMLAreaLog"></div>' : '') . '
418 * Add link to content style sheet to document header
422 protected function addPageStyle() {
423 // Get stylesheet file name from Page TSConfig if any
424 $filename = trim($this->thisConfig
['contentCSS']) ?
trim($this->thisConfig
['contentCSS']) : 'EXT:' . $this->ID
. '/res/contentcss/default.css';
425 $this->addStyleSheet(
426 'rtehtmlarea-page-style',
427 $this->getFullFileName($filename),
428 'htmlArea RTE Content CSS',
429 'alternate stylesheet'
434 * Add links to skin style sheet(s) to document header
438 protected function addSkin() {
439 // Get skin file name from Page TSConfig if any
440 $skinFilename = trim($this->thisConfig
['skin']) ?
trim($this->thisConfig
['skin']) : 'EXT:' . $this->ID
. '/htmlarea/skins/default/htmlarea.css';
441 $this->editorCSS
= $this->getFullFileName($skinFilename);
442 $skinDir = dirname($this->editorCSS
);
443 // Editing area style sheet
444 $this->editedContentCSS
= $skinDir . '/htmlarea-edited-content.css';
445 $this->addStyleSheet(
446 'rtehtmlarea-editing-area-skin',
447 $this->editedContentCSS
450 $this->addStyleSheet(
454 // Additional icons from registered plugins
455 foreach ($this->pluginEnabledCumulativeArray
[$this->TCEform
->RTEcounter
] as $pluginId) {
456 if (is_object($this->registeredPlugins
[$pluginId])) {
457 $pathToSkin = $this->registeredPlugins
[$pluginId]->getPathToSkin();
459 $key = $this->registeredPlugins
[$pluginId]->getExtensionKey();
460 $this->addStyleSheet(
461 'rtehtmlarea-plugin-' . $pluginId . '-skin',
462 ($this->is_FE() ? t3lib_extMgm
::siteRelPath($key) : $this->backPath
. t3lib_extMgm
::extRelPath($key)) . $pathToSkin
470 * Add style sheet file to document header
472 * @param string $key: some key identifying the style sheet
473 * @param string $href: uri to the style sheet file
474 * @param string $title: value for the title attribute of the link element
475 * @return string $relation: value for the rel attribute of the link element
478 protected function addStyleSheet($key, $href, $title='', $relation='stylesheet') {
479 // 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
480 if (is_object($this->TCEform
->inline
) && $this->TCEform
->inline
->isAjaxCall
) {
481 $this->TCEform
->additionalCode_pre
[$key] = '<link rel="' . $relation . '" type="text/css" href="' . $href . '" title="' . $title. '" />';
483 $pageRenderer = $GLOBALS['SOBE']->doc
->getPageRenderer();
484 $pageRenderer->addCssFile($href, $relation, 'screen', $title);
489 * Initialize toolbar configuration and enable registered plugins
493 protected function initializeToolbarConfiguration() {
495 // Enable registred plugins
496 $this->enableRegisteredPlugins();
501 // Check if some plugins need to be disabled
504 // Merge the list of enabled plugins with the lists from the previous RTE editing areas on the same form
505 $this->pluginEnabledCumulativeArray
[$this->TCEform
->RTEcounter
] = $this->pluginEnabledArray
;
506 if ($this->TCEform
->RTEcounter
> 1 && isset($this->pluginEnabledCumulativeArray
[$this->TCEform
->RTEcounter
-1]) && is_array($this->pluginEnabledCumulativeArray
[$this->TCEform
->RTEcounter
-1])) {
507 $this->pluginEnabledCumulativeArray
[$this->TCEform
->RTEcounter
] = array_unique(array_values(array_merge($this->pluginEnabledArray
,$this->pluginEnabledCumulativeArray
[$this->TCEform
->RTEcounter
-1])));
512 * Add registered plugins to the array of enabled plugins
515 function enableRegisteredPlugins() {
516 global $TYPO3_CONF_VARS;
517 // Traverse registered plugins
518 if (is_array($TYPO3_CONF_VARS['EXTCONF'][$this->ID
]['plugins'])) {
519 foreach($TYPO3_CONF_VARS['EXTCONF'][$this->ID
]['plugins'] as $pluginId => $pluginObjectConfiguration) {
521 if (is_array($pluginObjectConfiguration) && count($pluginObjectConfiguration)) {
522 $plugin = t3lib_div
::getUserObj($pluginObjectConfiguration['objectReference']);
524 if (is_object($plugin)) {
525 if ($plugin->main($this)) {
526 $this->registeredPlugins
[$pluginId] = $plugin;
527 // Override buttons from previously registered plugins
528 $pluginButtons = t3lib_div
::trimExplode(',', $plugin->getPluginButtons(), 1);
529 foreach ($this->pluginButton
as $previousPluginId => $buttonList) {
530 $this->pluginButton
[$previousPluginId] = implode(',',array_diff(t3lib_div
::trimExplode(',', $this->pluginButton
[$previousPluginId], 1), $pluginButtons));
532 $this->pluginButton
[$pluginId] = $plugin->getPluginButtons();
533 $pluginLabels = t3lib_div
::trimExplode(',', $plugin->getPluginLabels(), 1);
534 foreach ($this->pluginLabel
as $previousPluginId => $labelList) {
535 $this->pluginLabel
[$previousPluginId] = implode(',',array_diff(t3lib_div
::trimExplode(',', $this->pluginLabel
[$previousPluginId], 1), $pluginLabels));
537 $this->pluginLabel
[$pluginId] = $plugin->getPluginLabels();
538 $this->pluginEnabledArray
[] = $pluginId;
544 $hidePlugins = array();
545 foreach ($this->registeredPlugins
as $pluginId => $plugin) {
546 if ($plugin->addsButtons() && !$this->pluginButton
[$pluginId]) {
547 $hidePlugins[] = $pluginId;
550 $this->pluginEnabledArray
= array_unique(array_diff($this->pluginEnabledArray
, $hidePlugins));
554 * Set the toolbar config (only in this PHP-Object, not in JS):
558 function setToolbar() {
561 if ($this->client
['browser'] == 'msie' ||
$this->client
['browser'] == 'opera') {
562 $this->thisConfig
['keepButtonGroupTogether'] = 0;
565 $this->defaultToolbarOrder
= 'bar, blockstylelabel, blockstyle, space, textstylelabel, textstyle, linebreak,
566 bar, formattext, bold, strong, italic, emphasis, big, small, insertedtext, deletedtext, citation, code, definition, keyboard, monospaced, quotation, sample, variable, bidioverride, strikethrough, subscript, superscript, underline, span,
567 bar, fontstyle, space, fontsize, bar, formatblock, insertparagraphbefore, insertparagraphafter, blockquote, line,
568 bar, left, center, right, justifyfull,
569 bar, orderedlist, unorderedlist, definitionlist, definitionitem, outdent, indent, bar, lefttoright, righttoleft, language, showlanguagemarks,
570 bar, textcolor, bgcolor, textindicator,
571 bar, editelement, 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,
572 bar, chMode, inserttag, removeformat, bar, copy, cut, paste, pastetoggle, pastebehaviour, bar, undo, redo, bar, showhelp, about, linebreak,
573 ' . ($this->thisConfig
['hideTableOperationsInToolbar'] ?
'': 'bar, toggleborders,') . ' bar, tableproperties, tablerestyle, bar, rowproperties, rowinsertabove, rowinsertunder, rowdelete, rowsplit, bar,
574 columnproperties, columninsertbefore, columninsertafter, columndelete, columnsplit, bar,
575 cellproperties, cellinsertbefore, cellinsertafter, celldelete, cellsplit, cellmerge';
577 // Additional buttons from registered plugins
578 foreach($this->registeredPlugins
as $pluginId => $plugin) {
579 if ($this->isPluginEnabled($pluginId)) {
580 $this->defaultToolbarOrder
= $plugin->addButtonsToToolbar();
583 $toolbarOrder = $this->thisConfig
['toolbarOrder'] ?
$this->thisConfig
['toolbarOrder'] : $this->defaultToolbarOrder
;
585 // Getting rid of undefined buttons
586 $this->toolbarOrderArray
= array_intersect(t3lib_div
::trimExplode(',', $toolbarOrder, 1), t3lib_div
::trimExplode(',', $this->defaultToolbarOrder
, 1));
587 $toolbarOrder = array_unique(array_values($this->toolbarOrderArray
));
589 // Fetching specConf for field from backend
590 $pList = is_array($this->specConf
['richtext']['parameters']) ?
implode(',',$this->specConf
['richtext']['parameters']) : '';
591 if ($pList != '*') { // If not all
592 $show = is_array($this->specConf
['richtext']['parameters']) ?
$this->specConf
['richtext']['parameters'] : array();
593 if ($this->thisConfig
['showButtons']) {
594 if (!t3lib_div
::inList($this->thisConfig
['showButtons'],'*')) {
595 $show = array_unique(array_merge($show,t3lib_div
::trimExplode(',',$this->thisConfig
['showButtons'],1)));
597 $show = array_unique(array_merge($show, $toolbarOrder));
600 if (is_array($this->thisConfig
['showButtons.'])) {
601 foreach ($this->thisConfig
['showButtons.'] as $buttonId => $value) {
602 if ($value) $show[] = $buttonId;
604 $show = array_unique($show);
607 $show = $toolbarOrder;
610 // Resticting to RTEkeyList for backend user
611 if(is_object($BE_USER)) {
612 $RTEkeyList = isset($BE_USER->userTS
['options.']['RTEkeyList']) ?
$BE_USER->userTS
['options.']['RTEkeyList'] : '*';
613 if ($RTEkeyList != '*') { // If not all
614 $show = array_intersect($show, t3lib_div
::trimExplode(',',$RTEkeyList,1));
618 // Hiding buttons of disabled plugins
619 $hideButtons = array('space', 'bar', 'linebreak');
620 foreach ($this->pluginButton
as $pluginId => $buttonList) {
621 if (!$this->isPluginEnabled($pluginId)) {
622 $buttonArray = t3lib_div
::trimExplode(',',$buttonList,1);
623 foreach ($buttonArray as $button) {
624 $hideButtons[] = $button;
629 // Hiding labels of disabled plugins
630 foreach ($this->pluginLabel
as $pluginId => $label) {
631 if (!$this->isPluginEnabled($pluginId)) {
632 $hideButtons[] = $label;
637 $show = array_diff($show, $this->conf_toolbar_hide
, t3lib_div
::trimExplode(',',$this->thisConfig
['hideButtons'],1));
639 // Apply toolbar constraints from registered plugins
640 foreach ($this->registeredPlugins
as $pluginId => $plugin) {
641 if ($this->isPluginEnabled($pluginId) && method_exists($plugin, "applyToolbarConstraints")) {
642 $show = $plugin->applyToolbarConstraints($show);
645 // Getting rid of the buttons for which we have no position
646 $show = array_intersect($show, $toolbarOrder);
647 $this->toolbar
= $show;
651 * Disable some plugins
654 function setPlugins() {
656 // Disabling a plugin that adds buttons if none of its buttons is in the toolbar
657 $hidePlugins = array();
658 foreach ($this->pluginButton
as $pluginId => $buttonList) {
659 if ($this->registeredPlugins
[$pluginId]->addsButtons()) {
661 $buttonArray = t3lib_div
::trimExplode(',', $buttonList, 1);
662 foreach ($buttonArray as $button) {
663 if (in_array($button, $this->toolbar
)) {
668 $hidePlugins[] = $pluginId;
672 $this->pluginEnabledArray
= array_diff($this->pluginEnabledArray
, $hidePlugins);
674 // Hiding labels of disabled plugins
675 $hideLabels = array();
676 foreach ($this->pluginLabel
as $pluginId => $label) {
677 if (!$this->isPluginEnabled($pluginId)) {
678 $hideLabels[] = $label;
681 $this->toolbar
= array_diff($this->toolbar
, $hideLabels);
683 // Adding plugins declared as prerequisites by enabled plugins
684 $requiredPlugins = array();
685 foreach ($this->registeredPlugins
as $pluginId => $plugin) {
686 if ($this->isPluginEnabled($pluginId)) {
687 $requiredPlugins = array_merge($requiredPlugins, t3lib_div
::trimExplode(',', $plugin->getRequiredPlugins(), 1));
690 $requiredPlugins = array_unique($requiredPlugins);
691 foreach ($requiredPlugins as $pluginId) {
692 if (is_object($this->registeredPlugins
[$pluginId]) && !$this->isPluginEnabled($pluginId)) {
693 $this->pluginEnabledArray
[] = $pluginId;
696 $this->pluginEnabledArray
= array_unique($this->pluginEnabledArray
);
698 // Completing the toolbar conversion array for htmlArea
699 foreach ($this->registeredPlugins
as $pluginId => $plugin) {
700 if ($this->isPluginEnabled($pluginId)) {
701 $this->convertToolbarForHtmlAreaArray
= array_unique(array_merge($this->convertToolbarForHtmlAreaArray
, $plugin->getConvertToolbarForHtmlAreaArray()));
707 * Convert the TYPO3 names of buttons into the names for htmlArea RTE
709 * @param string buttonname (typo3-name)
710 * @return string buttonname (htmlarea-name)
713 function convertToolbarForHTMLArea($button) {
714 return $this->convertToolbarForHtmlAreaArray
[$button];
717 * Return the HTML code for loading the Javascript files
719 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
721 * @return string the html code for loading the Javascript Files
723 function loadJSfiles($RTEcounter) {
724 // Re-initialize the scripts array so that only the cumulative set of plugins of the last RTE on the page is used
725 $this->cumulativeScripts
[$RTEcounter] = array();
726 $this->writeTemporaryFile('EXT:' . $this->ID
. '/htmlarea/htmlarea.js', 'htmlarea', 'js', '', TRUE);
727 if ($this->client
['browser'] == 'msie') {
728 $this->writeTemporaryFile('EXT:' . $this->ID
. '/htmlarea/htmlarea-ie.js', 'htmlarea-ie', 'js', '', TRUE);
730 $this->writeTemporaryFile('EXT:' . $this->ID
. '/htmlarea/htmlarea-gecko.js', 'htmlarea-gecko', 'js', '', TRUE);
732 foreach ($this->pluginEnabledCumulativeArray
[$RTEcounter] as $pluginId) {
733 $extensionKey = is_object($this->registeredPlugins
[$pluginId]) ?
$this->registeredPlugins
[$pluginId]->getExtensionKey() : $this->ID
;
734 $this->writeTemporaryFile('EXT:' . $extensionKey . '/htmlarea/plugins/' . $pluginId . '/' . strtolower(preg_replace('/([a-z])([A-Z])([a-z])/', "$1".'-'."$2"."$3", $pluginId)) . '.js', $pluginId, 'js', '', TRUE);
736 $this->buildJSMainLangFile($RTEcounter);
737 // Avoid re-initialization on AJax call when RTEarea object was already initialized
738 $loadJavascriptCode = '<script type="text/javascript" src="' . $this->doConcatenate($RTEcounter) . '"></script>'. LF
;
739 $loadJavascriptCode .= t3lib_div
::wrapJS('
740 if (typeof(RTEarea) == "undefined") {
741 RTEarea = new Object();
742 RTEarea[0] = new Object();
743 RTEarea[0].version = "' . $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID
]['version'] . '";
744 RTEarea[0].editorUrl = "' . $this->extHttpPath
. 'htmlarea/";
745 RTEarea[0].editorCSS = "' . t3lib_div
::createVersionNumberedFilename($this->editorCSS
) . '";
746 RTEarea[0].editorSkin = "' . dirname($this->editorCSS
) . '/";
747 RTEarea[0].editedContentCSS = "' . t3lib_div
::createVersionNumberedFilename($this->editedContentCSS
) . '";
748 RTEarea[0].hostUrl = "' . $this->hostURL
. '";
749 RTEarea[0].enableDebugMode = ' . ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID
]['enableDebugMode'] ?
'true' : 'false') . ';
750 RTEarea.init = function() {
751 if (typeof(HTMLArea) == "undefined" || !Ext.isReady) {
752 window.setTimeout("RTEarea.init();", 40);
754 Ext.QuickTips.init();
758 RTEarea.initEditor = function(editorNumber) {
759 if (typeof(HTMLArea) == "undefined") {
760 RTEarea.initEditor.defer(40, null, [editorNumber]);
762 HTMLArea.initEditor(editorNumber);
767 return $loadJavascriptCode;
771 * Return the Javascript code for initializing the RTE
773 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
775 * @return string the Javascript code for initializing the RTE
777 function loadJScode($RTEcounter) {
778 return TAB
. 'RTEarea.init();';
782 * Return the Javascript code for configuring the RTE
784 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
785 * @param string $table: The table that includes this RTE (optional, necessary for IRRE).
786 * @param string $uid: The uid of that table that includes this RTE (optional, necessary for IRRE).
787 * @param string $field: The field of that record that includes this RTE (optional).
789 * @return string the Javascript code for configuring the RTE
791 function registerRTEinJS($RTEcounter, $table='', $uid='', $field='', $textAreaId = '') {
792 $configureRTEInJavascriptString = '
793 if (typeof(configureEditorInstance) == "undefined") {
794 configureEditorInstance = new Object();
796 configureEditorInstance["' . $textAreaId . '"] = function() {
797 if (typeof(RTEarea) == "undefined" || typeof(HTMLArea) == "undefined") {
798 window.setTimeout("configureEditorInstance[\'' . $textAreaId . '\']();", 40);
800 editornumber = "' . $textAreaId . '";
801 RTEarea[editornumber] = new Object();
802 RTEarea[editornumber].RTEtsConfigParams = "&RTEtsConfigParams=' . rawurlencode($this->RTEtsConfigParams()) . '";
803 RTEarea[editornumber].number = editornumber;
804 RTEarea[editornumber].deleted = false;
805 RTEarea[editornumber].textAreaId = "' . $textAreaId . '";
806 RTEarea[editornumber].id = "RTEarea" + editornumber;
807 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'])) . '";
808 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'])) . '";
809 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')) . ';
810 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')) . '";
811 RTEarea[editornumber].fullScreen = ' . ($this->fullScreen ?
'true' : 'false') . ';
812 RTEarea[editornumber].showStatusBar = ' . (trim($this->thisConfig
['showStatusBar'])?
'true':'false') . ';
813 RTEarea[editornumber].enableWordClean = ' . (trim($this->thisConfig
['enableWordClean'])?
'true':'false') . ';
814 RTEarea[editornumber].htmlRemoveComments = ' . (trim($this->thisConfig
['removeComments'])?
'true':'false') . ';
815 RTEarea[editornumber].disableEnterParagraphs = ' . (trim($this->thisConfig
['disableEnterParagraphs'])?
'true':'false') . ';
816 RTEarea[editornumber].disableObjectResizing = ' . (trim($this->thisConfig
['disableObjectResizing'])?
'true':'false') . ';
817 RTEarea[editornumber].removeTrailingBR = ' . (trim($this->thisConfig
['removeTrailingBR'])?
'true':'false') . ';
818 RTEarea[editornumber].useCSS = ' . (trim($this->thisConfig
['useCSS'])?
'true':'false') . ';
819 RTEarea[editornumber].keepButtonGroupTogether = ' . (trim($this->thisConfig
['keepButtonGroupTogether'])?
'true':'false') . ';
820 RTEarea[editornumber].disablePCexamples = ' . (trim($this->thisConfig
['disablePCexamples'])?
'true':'false') . ';
821 RTEarea[editornumber].showTagFreeClasses = ' . (trim($this->thisConfig
['showTagFreeClasses'])?
'true':'false') . ';
822 RTEarea[editornumber].useHTTPS = ' . ((trim(stristr($this->siteURL
, 'https')) ||
$this->thisConfig
['forceHTTPS'])?
'true':'false') . ';
823 RTEarea[editornumber].tceformsNested = ' . (is_object($this->TCEform
) && method_exists($this->TCEform
, 'getDynNestedStack') ?
$this->TCEform
->getDynNestedStack(true) : '[]') . ';
824 RTEarea[editornumber].dialogueWindows = new Object();
825 RTEarea[editornumber].dialogueWindows.defaultPositionFromTop = ' . (isset($this->thisConfig
['dialogueWindows.']['defaultPositionFromTop'])?
intval($this->thisConfig
['dialogueWindows.']['defaultPositionFromTop']) : '100') . ';
826 RTEarea[editornumber].dialogueWindows.defaultPositionFromLeft = ' . (isset($this->thisConfig
['dialogueWindows.']['defaultPositionFromLeft'])?
intval($this->thisConfig
['dialogueWindows.']['defaultPositionFromLeft']) : '100') . ';
827 RTEarea[editornumber].dialogueWindows.doNotResize = ' . (trim($this->thisConfig
['dialogueWindows.']['doNotResize'])?
'true':'false') . ';
828 RTEarea[editornumber].dialogueWindows.doNotCenter = ' . (trim($this->thisConfig
['dialogueWindows.']['doNotCenter'])?
'true':'false') . ';';
830 // The following properties apply only to the backend
831 if (!$this->is_FE()) {
832 $configureRTEInJavascriptString .= '
833 RTEarea[editornumber].sys_language_content = "' . $this->contentLanguageUid
. '";
834 RTEarea[editornumber].typo3ContentLanguage = "' . $this->contentTypo3Language
. '";
835 RTEarea[editornumber].typo3ContentCharset = "' . $this->contentCharset
. '";
836 RTEarea[editornumber].userUid = "' . $this->userUid
. '";';
839 // Setting the plugin flags
840 $configureRTEInJavascriptString .= '
841 RTEarea[editornumber].plugin = new Object();
842 RTEarea[editornumber].pathToPluginDirectory = new Object();';
843 foreach ($this->pluginEnabledArray
as $pluginId) {
844 $configureRTEInJavascriptString .= '
845 RTEarea[editornumber].plugin.'.$pluginId.' = true;';
846 if (is_object($this->registeredPlugins
[$pluginId])) {
847 $pathToPluginDirectory = $this->registeredPlugins
[$pluginId]->getPathToPluginDirectory();
848 if ($pathToPluginDirectory) {
849 $configureRTEInJavascriptString .= '
850 RTEarea[editornumber].pathToPluginDirectory.'.$pluginId.' = "' . $pathToPluginDirectory . '";';
855 // Setting the buttons configuration
856 $configureRTEInJavascriptString .= '
857 RTEarea[editornumber].buttons = new Object();';
858 if (is_array($this->thisConfig
['buttons.'])) {
859 foreach ($this->thisConfig
['buttons.'] as $buttonIndex => $conf) {
860 $button = substr($buttonIndex, 0, -1);
861 $configureRTEInJavascriptString .= '
862 RTEarea[editornumber].buttons.'.$button.' = ' . $this->buildNestedJSArray($conf) . ';';
866 // Setting the list of tags to be removed if specified in the RTE config
867 if (trim($this->thisConfig
['removeTags'])) {
868 $configureRTEInJavascriptString .= '
869 RTEarea[editornumber].htmlRemoveTags = /^(' . implode('|', t3lib_div
::trimExplode(',', $this->thisConfig
['removeTags'], 1)) . ')$/i;';
872 // Setting the list of tags to be removed with their contents if specified in the RTE config
873 if (trim($this->thisConfig
['removeTagsAndContents'])) {
874 $configureRTEInJavascriptString .= '
875 RTEarea[editornumber].htmlRemoveTagsAndContents = /^(' . implode('|', t3lib_div
::trimExplode(',', $this->thisConfig
['removeTagsAndContents'], 1)) . ')$/i;';
877 // Process default style configuration
878 $configureRTEInJavascriptString .= '
879 RTEarea[editornumber].defaultPageStyle = "' . $this->writeTemporaryFile('', 'defaultPageStyle', 'css', $this->buildStyleSheet()) . '";';
880 // Setting the pageStyle
881 $filename = trim($this->thisConfig
['contentCSS']) ?
trim($this->thisConfig
['contentCSS']) : 'EXT:' . $this->ID
. '/res/contentcss/default.css';
882 $configureRTEInJavascriptString .= '
883 RTEarea[editornumber].pageStyle = "' . t3lib_div
::createVersionNumberedFilename($this->getFullFileName($filename)) .'";';
884 // Process classes configuration
885 $classesConfigurationRequired = false;
886 foreach ($this->registeredPlugins
as $pluginId => $plugin) {
887 if ($this->isPluginEnabled($pluginId)) {
888 $classesConfigurationRequired = $classesConfigurationRequired ||
$plugin->requiresClassesConfiguration();
891 if ($classesConfigurationRequired) {
892 $configureRTEInJavascriptString .= $this->buildJSClassesConfig($RTEcounter);
894 // Add Javascript configuration for registered plugins
895 foreach ($this->registeredPlugins
as $pluginId => $plugin) {
896 if ($this->isPluginEnabled($pluginId)) {
897 $configureRTEInJavascriptString .= $plugin->buildJavascriptConfiguration('editornumber');
900 // Avoid premature reference to HTMLArea when being initially loaded by IRRE Ajax call
901 $configureRTEInJavascriptString .= '
902 RTEarea[editornumber].toolbar = ' . $this->getJSToolbarArray() . ';
903 RTEarea[editornumber].convertButtonId = ' . json_encode(array_flip($this->convertToolbarForHtmlAreaArray
)) . ';
904 RTEarea.initEditor(editornumber);
907 configureEditorInstance["' . $textAreaId . '"]();';
908 return $configureRTEInJavascriptString;
912 * Return true, if the plugin can be loaded
914 * @param string $pluginId: The identification string of the plugin
916 * @return boolean true if the plugin can be loaded
919 function isPluginEnabled($pluginId) {
920 return in_array($pluginId, $this->pluginEnabledArray
);
924 * Build the default content style sheet
926 * @return string Style sheet
928 function buildStyleSheet() {
930 if (!trim($this->thisConfig
['ignoreMainStyleOverride'])) {
931 $mainStyle_font = $this->thisConfig
['mainStyle_font'] ?
$this->thisConfig
['mainStyle_font']: 'Verdana,sans-serif';
933 $mainElements = array();
934 $mainElements['P'] = $this->thisConfig
['mainStyleOverride_add.']['P'];
935 $elList = explode(',','H1,H2,H3,H4,H5,H6,PRE');
936 foreach ($elList as $elListName) {
937 if ($this->thisConfig
['mainStyleOverride_add.'][$elListName]) {
938 $mainElements[$elListName] = $this->thisConfig
['mainStyleOverride_add.'][$elListName];
942 $addElementCode = '';
943 foreach ($mainElements as $elListName => $elValue) {
944 $addElementCode .= strToLower($elListName) . ' {' . $elValue . '}' . LF
;
947 $stylesheet = $this->thisConfig
['mainStyleOverride'] ?
$this->thisConfig
['mainStyleOverride'] : LF
.
948 'body.htmlarea-content-body { font-family: ' . $mainStyle_font .
949 '; font-size: '.($this->thisConfig
['mainStyle_size'] ?
$this->thisConfig
['mainStyle_size'] : '12px') .
950 '; color: '.($this->thisConfig
['mainStyle_color']?
$this->thisConfig
['mainStyle_color'] : 'black') .
951 '; background-color: '.($this->thisConfig
['mainStyle_bgcolor'] ?
$this->thisConfig
['mainStyle_bgcolor'] : 'white') .
952 ';'.$this->thisConfig
['mainStyleOverride_add.']['BODY'].'}' . LF
.
953 'td { ' . $this->thisConfig
['mainStyleOverride_add.']['TD'].'}' . LF
.
954 'div { ' . $this->thisConfig
['mainStyleOverride_add.']['DIV'].'}' . LF
.
955 'pre { ' . $this->thisConfig
['mainStyleOverride_add.']['PRE'].'}' . LF
.
956 'ol { ' . $this->thisConfig
['mainStyleOverride_add.']['OL'].'}' . LF
.
957 'ul { ' . $this->thisConfig
['mainStyleOverride_add.']['UL'].'}' . LF
.
958 'blockquote { ' . $this->thisConfig
['mainStyleOverride_add.']['BLOCKQUOTE'].'}' . LF
.
961 if (is_array($this->thisConfig
['inlineStyle.'])) {
962 $stylesheet .= LF
. implode(LF
, $this->thisConfig
['inlineStyle.']) . LF
;
965 $stylesheet = '/* mainStyleOverride and inlineStyle properties ignored. */';
971 * Return Javascript configuration of classes
973 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
975 * @return string Javascript configuration of classes
977 function buildJSClassesConfig($RTEcounter) {
978 // Build JS array of lists of classes
979 $classesTagList = 'classesCharacter, classesParagraph, classesImage, classesTable, classesLinks, classesTD';
980 $classesTagConvert = array( 'classesCharacter' => 'span', 'classesParagraph' => 'div', 'classesImage' => 'img', 'classesTable' => 'table', 'classesLinks' => 'a', 'classesTD' => 'td');
981 $classesTagArray = t3lib_div
::trimExplode(',' , $classesTagList);
982 $configureRTEInJavascriptString = '
983 RTEarea[editornumber].classesTag = new Object();';
984 foreach ($classesTagArray as $classesTagName) {
985 $HTMLAreaJSClasses = ($this->thisConfig
[$classesTagName])?
('"' . $this->cleanList($this->thisConfig
[$classesTagName]) . '";'):'null;';
986 $configureRTEInJavascriptString .= '
987 RTEarea[editornumber].classesTag.'. $classesTagConvert[$classesTagName] .' = '. $HTMLAreaJSClasses;
989 // Include JS arrays of configured classes
990 $configureRTEInJavascriptString .= '
991 RTEarea[editornumber].classesUrl = "' . $this->writeTemporaryFile('', 'classes_'.$LANG->lang
, 'js', $this->buildJSClassesArray()) . '";';
992 return $configureRTEInJavascriptString;
996 * Return JS arrays of classes configuration
998 * @return string JS classes arrays
1000 function buildJSClassesArray() {
1001 if ($this->is_FE()) {
1002 $RTEProperties = $this->RTEsetup
;
1004 $RTEProperties = $this->RTEsetup
['properties'];
1006 $classesArray = array('labels' => array(), 'values' => array(), 'noShow' => array(), 'alternating' => array(), 'counting' => array(), 'XOR' => array());
1007 $JSClassesArray = '';
1008 // Scanning the list of classes if specified in the RTE config
1009 if (is_array($RTEProperties['classes.'])) {
1010 foreach ($RTEProperties['classes.'] as $className => $conf) {
1011 $className = rtrim($className, '.');
1012 $classesArray['labels'][$className] = $this->getPageConfigLabel($conf['name'], FALSE);
1013 $classesArray['values'][$className] = str_replace('\\\'', '\'', $conf['value']);
1014 if (isset($conf['noShow'])) {
1015 $classesArray['noShow'][$className] = $conf['noShow'];
1017 if (is_array($conf['alternating.'])) {
1018 $classesArray['alternating'][$className] = $conf['alternating.'];
1020 if (is_array($conf['counting.'])) {
1021 $classesArray['counting'][$className] = $conf['counting.'];
1025 // Scanning the list of sets of mutually exclusives classes if specified in the RTE config
1026 if (is_array($RTEProperties['mutuallyExclusiveClasses.'])) {
1027 foreach ($RTEProperties['mutuallyExclusiveClasses.'] as $listName => $conf) {
1028 $classSet = t3lib_div
::trimExplode(',', $conf, 1);
1029 $classList = implode(',', $classSet);
1030 foreach ($classSet as $className) {
1031 $classesArray['XOR'][$className] = '/^(' . implode('|', t3lib_div
::trimExplode(',', t3lib_div
::rmFromList($className, $classList), 1)) . ')$/';
1035 foreach ($classesArray as $key => $subArray) {
1036 $JSClassesArray .= 'HTMLArea.classes' . ucfirst($key) . ' = ' . $this->buildNestedJSArray($subArray) . ';' . LF
;
1038 return $JSClassesArray;
1042 * Translate Page TS Config array in JS nested array definition
1043 * Replace 0 values with false
1044 * Unquote regular expression values
1045 * Replace empty arrays with empty objects
1047 * @param array $conf: Page TSConfig configuration array
1049 * @return string nested JS array definition
1051 function buildNestedJSArray($conf) {
1052 $convertedConf = t3lib_div
::removeDotsFromTS($conf);
1053 if ($this->is_FE()) {
1054 $GLOBALS['TSFE']->csConvObj
->convArray($convertedConf, ($GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] ?
$GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] : 'iso-8859-1'), 'utf-8');
1056 $GLOBALS['LANG']->csConvObj
->convArray($convertedConf, $GLOBALS['LANG']->charSet
, 'utf-8');
1058 return str_replace(array(':"0"', ':"\/^(', ')$\/i"', ':"\/^(', ')$\/"', '[]'), array(':false', ':/^(', ')$/i', ':/^(', ')$/', '{}'), json_encode($convertedConf));
1062 * Return a Javascript localization array for htmlArea RTE
1064 * @return string Javascript localization array
1066 function buildJSMainLangArray() {
1067 $JSLanguageArray = 'HTMLArea.I18N = new Object();' . LF
;
1068 $labelsArray = array('tooltips' => array(), 'msg' => array(), 'dialogs' => array());
1069 foreach ($labelsArray as $labels => $subArray) {
1070 $LOCAL_LANG = t3lib_div
::readLLfile('EXT:' . $this->ID
. '/htmlarea/locallang_' . $labels . '.xml', $this->language
, 'utf-8');
1071 if (!empty($LOCAL_LANG[$this->language
])) {
1072 $LOCAL_LANG[$this->language
] = t3lib_div
::array_merge_recursive_overrule($LOCAL_LANG['default'], $LOCAL_LANG[$this->language
]);
1074 $LOCAL_LANG[$this->language
] = $LOCAL_LANG['default'];
1076 $labelsArray[$labels] = $LOCAL_LANG[$this->language
];
1078 $JSLanguageArray .= 'HTMLArea.I18N = ' . json_encode($labelsArray) . ';' . LF
;
1079 return $JSLanguageArray;
1083 * Writes contents in a file in typo3temp/rtehtmlarea directory and returns the file name
1085 * @param string $sourceFileName: The name of the file from which the contents should be extracted
1086 * @param string $label: A label to insert at the beginning of the name of the file
1087 * @param string $fileExtension: The file extension of the file, defaulting to 'js'
1088 * @param string $contents: The contents to write into the file if no $sourceFileName is provided
1090 * @return string The name of the file writtten to typo3temp/rtehtmlarea
1092 public function writeTemporaryFile($sourceFileName='', $label, $fileExtension='js', $contents='', $concatenate = FALSE) {
1093 global $TYPO3_CONF_VARS;
1095 if ($sourceFileName) {
1097 $source = t3lib_div
::getFileAbsFileName($sourceFileName);
1098 $output = file_get_contents($source);
1100 $output = $contents;
1102 $compress = $TYPO3_CONF_VARS['EXTCONF'][$this->ID
]['enableCompressedScripts'] && ($fileExtension == 'js') && ($output != '');
1103 $relativeFilename = 'typo3temp/' . $this->ID
. '/' . str_replace('-','_',$label) . '_' . t3lib_div
::shortMD5(($TYPO3_CONF_VARS['EXTCONF'][$this->ID
]['version'] . ($sourceFileName ?
$sourceFileName : $output)), 20) . ($compress ?
'_compressed' : '') . '.' . $fileExtension;
1104 $destination = PATH_site
. $relativeFilename;
1105 if(!file_exists($destination)) {
1106 $compressedJavaScript = '';
1107 if ($compress && $fileExtension == 'js') {
1108 $compressedJavaScript = t3lib_div
::minifyJavaScript($output);
1110 $failure = t3lib_div
::writeFileToTypo3tempDir($destination, $compressedJavaScript ?
$compressedJavaScript : $output);
1115 if ($concatenate && $fileExtension == 'js') {
1116 $this->cumulativeScripts
[$this->TCEform
->RTEcounter
][] = $destination;
1118 if ($this->is_FE()) {
1119 $filename = ($GLOBALS['TSFE']->absRefPrefix ?
$GLOBALS['TSFE']->absRefPrefix
: '') . t3lib_div
::createVersionNumberedFilename($relativeFilename);
1121 $filename = t3lib_div
::createVersionNumberedFilename(($this->isFrontendEditActive() ?
'' : ($this->backPath
. '../')) . $relativeFilename);
1123 return t3lib_div
::resolveBackPath($filename);
1126 * Concatenates all accumulated scripts in a file in typo3temp/rtehtmlarea directory and returns the file name
1128 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
1130 * @return string The name of the file writtten to typo3temp/rtehtmlarea
1132 protected function doConcatenate($RTEcounter) {
1133 $fileExtension = 'js';
1134 $compress = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID
]['enableCompressedScripts'];
1135 $token = implode('|', $this->cumulativeScripts
[$RTEcounter]);
1136 $relativeFilename = 'typo3temp/' . $this->ID
. '/' . 'htmlarea_cumulative' . '_' . t3lib_div
::shortMD5(($TYPO3_CONF_VARS['EXTCONF'][$this->ID
]['version'] . $token ), 20) . ($compress ?
'_compressed' : '') . '.' . $fileExtension;
1137 $destination = PATH_site
. $relativeFilename;
1138 if (!file_exists($destination)) {
1139 foreach ($this->cumulativeScripts
[$RTEcounter] as $fileName) {
1140 $contents = file_get_contents($fileName);
1141 if (!file_exists($destination)) {
1142 $failure = t3lib_div
::writeFileToTypo3tempDir($destination, $contents);
1147 $success = file_put_contents($destination, $contents, FILE_APPEND
);
1149 die('Could not append script' +
$fileName);
1154 if ($this->is_FE()) {
1155 $filename = ($GLOBALS['TSFE']->absRefPrefix ?
$GLOBALS['TSFE']->absRefPrefix
: '') . t3lib_div
::createVersionNumberedFilename($relativeFilename);
1158 $compressor = t3lib_div
::makeInstance('t3lib_Compressor');
1159 $filename = $compressor->compressJsFile(($this->isFrontendEditActive() ?
'' : $this->backPath
) . '../' . $relativeFilename);
1160 if ($this->isFrontendEditActive()) {
1161 $filename = preg_replace('/^..\//', '', $filename);
1164 $filename = t3lib_div
::createVersionNumberedFilename(($this->isFrontendEditActive() ?
'' : ($this->backPath
. '../')) . $relativeFilename);
1167 return t3lib_div
::resolveBackPath($filename);
1171 * Return a file name containing the main JS language array for HTMLArea
1173 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
1175 * @return string filename
1177 function buildJSMainLangFile($RTEcounter) {
1178 $contents = $this->buildJSMainLangArray() . LF
;
1179 foreach ($this->pluginEnabledCumulativeArray
[$RTEcounter] as $pluginId) {
1180 $contents .= $this->buildJSLangArray($pluginId) . LF
;
1182 return $this->writeTemporaryFile('', $this->language
.'_'.$this->OutputCharset
, 'js', $contents, TRUE);
1186 * Return a Javascript localization array for the plugin
1188 * @param string $plugin: identification string of the plugin
1190 * @return string Javascript localization array
1193 function buildJSLangArray($plugin) {
1194 $LOCAL_LANG = FALSE;
1195 $extensionKey = is_object($this->registeredPlugins
[$plugin]) ?
$this->registeredPlugins
[$plugin]->getExtensionKey() : $this->ID
;
1196 $LOCAL_LANG = t3lib_div
::readLLfile('EXT:' . $extensionKey . '/htmlarea/plugins/' . $plugin . '/locallang.xml', $this->language
, 'utf-8', 1);
1197 $linebreak = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID
]['enableCompressedScripts'] ?
'' : LF
;
1198 $JSLanguageArray = 'HTMLArea.I18N["' . $plugin . '"] = new Object();' . $linebreak;
1199 if (is_array($LOCAL_LANG)) {
1200 if (!empty($LOCAL_LANG[$this->language
])) {
1201 $LOCAL_LANG[$this->language
] = t3lib_div
::array_merge_recursive_overrule($LOCAL_LANG['default'],$LOCAL_LANG[$this->language
]);
1203 $LOCAL_LANG[$this->language
] = $LOCAL_LANG['default'];
1205 $JSLanguageArray .= 'HTMLArea.I18N["' . $plugin . '"] = ' . json_encode($LOCAL_LANG[$this->language
]) . ';'. LF
;
1207 return $JSLanguageArray;
1211 * Return the JS code of the toolbar configuration for the HTMLArea editor
1213 * @return string the JS code as nested JS arrays
1215 protected function getJSToolbarArray() {
1216 // The toolbar array
1218 // The current row; a "linebreak" ends the current row
1220 // The current group; each group is between "bar"s; a "linebreak" ends the current group
1222 // Process each toolbar item in the toolbar order list
1223 foreach ($this->toolbarOrderArray
as $item) {
1226 // Add row to toolbar if not empty
1227 if (!empty($group)) {
1237 // Add group to row if not empty
1238 if (!empty($group)) {
1244 if (end($group) != $this->convertToolbarForHTMLArea($item)) {
1245 $group[] = $this->convertToolbarForHTMLArea($item);
1249 if (in_array($item, $this->toolbar
)) {
1250 // Add the item to the group
1251 $convertedItem = $this->convertToolbarForHTMLArea($item);
1252 if ($convertedItem) {
1253 $group[] = $convertedItem;
1259 // Add the last group and last line, if not empty
1260 if (!empty($group)) {
1266 return json_encode($toolbar);
1269 public function getLLContent($string) {
1272 $BE_lang = $LANG->lang
;
1273 $BE_charSet = $LANG->charSet
;
1274 $LANG->lang
= $this->contentTypo3Language
;
1275 $LANG->charSet
= $this->contentCharset
;
1276 $LLString = $LANG->JScharCode($LANG->sL($string));
1277 $LANG->lang
= $BE_lang;
1278 $LANG->charSet
= $BE_charSet;
1282 public function getPageConfigLabel($string,$JScharCode=1) {
1283 global $LANG, $TSFE, $TYPO3_CONF_VARS;
1285 if ($this->is_FE()) {
1286 if (strcmp(substr($string,0,4),'LLL:') && $TYPO3_CONF_VARS['BE']['forceCharset']) {
1287 // A pure string coming from Page TSConfig must be in forceCharset, otherwise we just don't know..
1288 $label = $TSFE->csConvObj
->conv($TSFE->sL(trim($string)), $TYPO3_CONF_VARS['BE']['forceCharset'], $this->OutputCharset
);
1290 $label = $TSFE->csConvObj
->conv($TSFE->sL(trim($string)), $this->charset
, $this->OutputCharset
);
1292 $label = str_replace('"', '\"', str_replace('\\\'', '\'', $label));
1293 $label = $JScharCode ?
$this->feJScharCode($label) : $label;
1295 if (strcmp(substr($string,0,4),'LLL:')) {
1298 $label = $LANG->sL(trim($string));
1300 $label = str_replace('"', '\"', str_replace('\\\'', '\'', $label));
1301 $label = $JScharCode ?
$LANG->JScharCode($label): $label;
1306 function feJScharCode($str) {
1308 // Convert string to UTF-8:
1309 if ($this->OutputCharset
!= 'utf-8') $str = $TSFE->csConvObj
->utf8_encode($str,$this->OutputCharset
);
1310 // Convert the UTF-8 string into a array of char numbers:
1311 $nArr = $TSFE->csConvObj
->utf8_to_numberarray($str);
1312 return 'String.fromCharCode('.implode(',',$nArr).')';
1315 public function getFullFileName($filename) {
1316 if (substr($filename,0,4)=='EXT:') { // extension
1317 list($extKey,$local) = explode('/',substr($filename,4),2);
1319 if (strcmp($extKey,'') && t3lib_extMgm
::isLoaded($extKey) && strcmp($local,'')) {
1320 $newFilename = (($this->is_FE() ||
$this->isFrontendEditActive()) ? t3lib_extMgm
::siteRelPath($extKey) : $this->backPath
. t3lib_extMgm
::extRelPath($extKey)) . $local;
1322 } elseif (substr($filename,0,1) != '/') {
1323 $newFilename = (($this->is_FE() ||
$this->isFrontendEditActive()) ?
'' : ($this->backPath
. '../')) . $filename;
1325 $newFilename = (($this->is_FE() ||
$this->isFrontendEditActive()) ?
'' : ($this->backPath
. '../')) . substr($filename, 1);
1327 return t3lib_div
::resolveBackPath($newFilename);
1331 * Return the Javascript code for copying the HTML code from the editor into the hidden input field.
1332 * This is for submit function of the form.
1334 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
1335 * @param string $formName: the name of the form
1336 * @param string $textareaId: the id of the textarea
1337 * @param string $textareaName: the name of the textarea
1339 * @return string Javascript code
1341 function setSaveRTE($RTEcounter, $formName, $textareaId, $textareaName) {
1342 return 'if (RTEarea["' . $textareaId . '"]) { document.' . $formName . '["' . $textareaName . '"].value = RTEarea["' . $textareaId . '"].editor.getHTML(); } else { OK = 0; };';
1346 * Return the Javascript code for copying the HTML code from the editor into the hidden input field.
1347 * This is for submit function of the form.
1349 * @param integer $RTEcounter: The index number of the current RTE editing area within the form.
1350 * @param string $formName: the name of the form
1351 * @param string $textareaId: the id of the textarea
1353 * @return string Javascript code
1355 function setDeleteRTE($RTEcounter, $formName, $textareaId) {
1356 return 'if (RTEarea["' . $textareaId . '"]) { RTEarea["' . $textareaId . '"].deleted = true;}';
1360 * Return true if we are in the FE, but not in the FE editing feature of BE.
1366 return is_object($GLOBALS['TSFE']) && !$this->isFrontendEditActive() && TYPO3_MODE
=='FE';
1370 * Checks whether frontend editing is active.
1374 public function isFrontendEditActive() {
1375 return is_object($GLOBALS['TSFE']) && $GLOBALS['TSFE']->beUserLogin
&& ($GLOBALS['BE_USER']->frontendEdit
instanceof t3lib_frontendedit
);
1378 * Client Browser Information
1380 * @param string $userAgent: The useragent string, t3lib_div::getIndpEnv('HTTP_USER_AGENT')
1381 * @return array Contains keys "useragent", "browser", "version", "system"
1382 * where "browser" is limited to the engines
1383 * and where "version" is a floating number
1385 function clientInfo ($userAgent='') {
1387 $userAgent = t3lib_div
::getIndpEnv('HTTP_USER_AGENT');
1389 $browserInfo = t3lib_utility_Client
::getBrowserInfo($userAgent);
1390 // Known engines: order is not irrelevant!
1391 $knownEngines = array('opera', 'msie', 'gecko', 'webkit');
1392 if (is_array($browserInfo['all'])) {
1393 foreach ($knownEngines as $engine) {
1394 if ($browserInfo['all'][$engine]) {
1395 $browserInfo['browser'] = $engine;
1396 $browserInfo['version'] = t3lib_utility_Client
::getVersion($browserInfo['all'][$engine]);
1401 if ($browserInfo['system'] == 'mac') {
1402 if (strstr($userAgent,'iPad')) {
1403 $browserInfo['system'] = 'iPad';
1404 } elseif (strstr($userAgent,'iPhone')) {
1405 $browserInfo['system'] = 'iPhone';
1406 } elseif (strstr($userAgent,'iPod')) {
1407 $browserInfo['system'] = 'iPod';
1410 return $browserInfo;
1412 /***************************
1414 * OTHER FUNCTIONS: (from Classic RTE)
1416 ***************************/
1418 * @return [type] ...
1422 function RTEtsConfigParams() {
1423 if($this->is_FE()) {
1426 $p = t3lib_BEfunc
::getSpecConfParametersFromArray($this->specConf
['rte_transform']['parameters']);
1427 return $this->elementParts
[0].':'.$this->elementParts
[1].':'.$this->elementParts
[2].':'.$this->thePid
.':'.$this->typeVal
.':'.$this->tscPID
.':'.$p['imgpath'];
1431 public function cleanList($str) {
1432 if (strstr($str,'*')) {
1435 $str = implode(',',array_unique(t3lib_div
::trimExplode(',',$str,1)));
1440 function filterStyleEl($elValue,$matchList) {
1441 $matchParts = t3lib_div
::trimExplode(',',$matchList,1);
1442 $styleParts = explode(';',$elValue);
1444 foreach ($styleParts as $k => $p) {
1445 $pp = t3lib_div
::trimExplode(':',$p);
1446 if ($pp[0]&&$pp[1]) {
1447 foreach ($matchParts as $el) {
1448 $star=substr($el,-1)=='*';
1449 if (!strcmp($pp[0],$el) ||
($star && t3lib_div
::isFirstPartOfStr($pp[0],substr($el,0,-1)) )) {
1450 $nStyle[]=$pp[0].':'.$pp[1];
1451 } else unset($styleParts[$k]);
1454 unset($styleParts[$k]);
1457 return implode('; ',$nStyle);
1460 // Hook on lorem_ipsum extension to insert text into the RTE in wysiwyg mode
1461 function loremIpsumInsert($params) {
1463 if (typeof(lorem_ipsum) == 'function' && " . $params['element'] . ".tagName.toLowerCase() == 'textarea' ) lorem_ipsum(" . $params['element'] . ", lipsum_temp_strings[lipsum_temp_pointer]);
1467 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['ext/rtehtmlarea/class.tx_rtehtmlarea_base.php']) {
1468 include_once($TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['ext/rtehtmlarea/class.tx_rtehtmlarea_base.php']);