Added feature #13580: htmlArea RTE: Extjize the RTE
authorStanislas Rolland <typo3@sjbr.ca>
Sun, 21 Feb 2010 15:56:10 +0000 (15:56 +0000)
committerStanislas Rolland <typo3@sjbr.ca>
Sun, 21 Feb 2010 15:56:10 +0000 (15:56 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@6940 709f56b5-9817-0410-a4d7-c38de5d9e867

65 files changed:
ChangeLog
typo3/sysext/rtehtmlarea/ChangeLog
typo3/sysext/rtehtmlarea/class.tx_rtehtmlarea_base.php
typo3/sysext/rtehtmlarea/ext_emconf.php
typo3/sysext/rtehtmlarea/ext_localconf.php
typo3/sysext/rtehtmlarea/extensions/Acronym/class.tx_rtehtmlarea_acronym.php
typo3/sysext/rtehtmlarea/extensions/BlockElements/class.tx_rtehtmlarea_blockelements.php
typo3/sysext/rtehtmlarea/extensions/BlockElements/skin/htmlarea.css
typo3/sysext/rtehtmlarea/extensions/BlockElements/skin/images/insertHorizontalRule.gif [new file with mode: 0644]
typo3/sysext/rtehtmlarea/extensions/ContextMenu/class.tx_rtehtmlarea_contextmenu.php
typo3/sysext/rtehtmlarea/extensions/InlineElements/class.tx_rtehtmlarea_inlineelements.php
typo3/sysext/rtehtmlarea/extensions/Language/class.tx_rtehtmlarea_language.php
typo3/sysext/rtehtmlarea/extensions/SelectFont/class.tx_rtehtmlarea_selectfont.php
typo3/sysext/rtehtmlarea/extensions/TYPO3Color/class.tx_rtehtmlarea_typo3color.php
typo3/sysext/rtehtmlarea/extensions/TYPO3Link/class.tx_rtehtmlarea_typo3link.php
typo3/sysext/rtehtmlarea/extensions/TableOperations/class.tx_rtehtmlarea_tableoperations.php
typo3/sysext/rtehtmlarea/extensions/TextIndicator/class.tx_rtehtmlarea_textindicator.php [new file with mode: 0644]
typo3/sysext/rtehtmlarea/extensions/TextIndicator/skin/htmlarea.css [new file with mode: 0644]
typo3/sysext/rtehtmlarea/htmlarea/htmlarea-gecko.js
typo3/sysext/rtehtmlarea/htmlarea/htmlarea-ie.js
typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js
typo3/sysext/rtehtmlarea/htmlarea/locallang_dialogs.xml
typo3/sysext/rtehtmlarea/htmlarea/plugins/Acronym/acronym.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/Acronym/locallang.xml
typo3/sysext/rtehtmlarea/htmlarea/plugins/BlockElements/block-elements.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/BlockElements/locallang.xml
typo3/sysext/rtehtmlarea/htmlarea/plugins/BlockStyle/block-style.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/CharacterMap/character-map.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/ContextMenu/context-menu.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/ContextMenu/locallang.xml
typo3/sysext/rtehtmlarea/htmlarea/plugins/CopyPaste/copy-paste.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/DefaultClean/default-clean.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/DefaultInline/default-inline.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/DefinitionList/definition-list.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/EditorMode/editor-mode.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/FindReplace/find-replace.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/InlineElements/inline-elements.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/InsertSmiley/insert-smiley.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/Language/language.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/QuickTag/locallang.xml
typo3/sysext/rtehtmlarea/htmlarea/plugins/QuickTag/quick-tag.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/RemoveFormat/remove-format.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/SelectFont/select-font.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-check-ui.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-checker.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/TYPO3Color/typo3color.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/TYPO3HtmlParser/typo3html-parser.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/TYPO3Link/typo3link.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/TableOperations/locallang.xml
typo3/sysext/rtehtmlarea/htmlarea/plugins/TableOperations/table-operations.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/TextIndicator/text-indicator.js [new file with mode: 0644]
typo3/sysext/rtehtmlarea/htmlarea/plugins/TextStyle/text-style.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/UndoRedo/undo-redo.js
typo3/sysext/rtehtmlarea/htmlarea/skins/default/htmlarea-edited-content.css
typo3/sysext/rtehtmlarea/htmlarea/skins/default/htmlarea.css
typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/BlockElements/insertHorizontalRule.gif [new file with mode: 0644]
typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/helpbubble.gif [new file with mode: 0644]
typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/loading.gif [new file with mode: 0644]
typo3/sysext/rtehtmlarea/pi2/class.tx_rtehtmlarea_pi2.php
typo3/sysext/rtehtmlarea/res/demo/pageTSConfig.txt
typo3/sysext/t3skin/rtehtmlarea/htmlarea-edited-content.css
typo3/sysext/t3skin/rtehtmlarea/htmlarea.css
typo3/sysext/t3skin/rtehtmlarea/images/BlockElements/insertHorizontalRule.gif [new file with mode: 0644]
typo3/sysext/t3skin/rtehtmlarea/images/helpbubble.gif [new file with mode: 0644]
typo3/sysext/t3skin/rtehtmlarea/images/loading.gif [new file with mode: 0644]

index d7fcb88..6a930ae 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2010-02-21  Stanislas Rolland  <typo3@sjbr.ca>
+
+       * Added feature #13580: htmlArea RTE: Extjize the RTE
+
 2010-02-21  Benjamin Mack  <benni@typo3.org>
 
        * Fixed #13574: html warning, because a plain & inside an url (Thanks to Stefan Galinski)
index aea2012..d8a4cfe 100644 (file)
@@ -1,3 +1,7 @@
+2010-02-21  Stanislas Rolland  <typo3@sjbr.ca>
+
+       * Added feature #13580: htmlArea RTE: Extjize the RTE
+
 2009-12-11  Stanislas Rolland  <typo3@sjbr.ca>
 
        * Fixed bug #12782: htmlArea RTE: Editing a link title or target with Firefox 3 sometimes simply unlinks the link
index 99f43af..fb8ed97 100644 (file)
@@ -4,7 +4,7 @@
 *
 *  (c) 2004-2009 Kasper Skaarhoj (kasper@typo3.com)
 *  (c) 2004-2009 Philipp Borgmann <philipp.borgmann@gmx.de>
-*  (c) 2004-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2004-2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
  */
 
 class tx_rtehtmlarea_base extends t3lib_rteapi {
-
                // Configuration of supported browsers
        var $conf_supported_browser = array (
                        'msie' => array (
                                1 => array (
-                                       'version' => 5.5,
+                                       'version' => 6.0,
                                        'system' => 'win'
                                )
                        ),
                        'gecko' => array (
                                1 => array (
-                                       'version' => 1.3
+                                       'version' => 1.8
                                )
                        ),
                        'safari' => array (
@@ -72,9 +71,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
 
                // Conversion array: TYPO3 button names to htmlArea button names
        var $convertToolbarForHtmlAreaArray = array (
-               'line'                  => 'InsertHorizontalRule',
                'showhelp'              => 'ShowHelp',
-               'textindicator'         => 'TextIndicator',
                'space'                 => 'space',
                'bar'                   => 'separator',
                'linebreak'             => 'linebreak',
@@ -120,11 +117,11 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
        var $editorCSS;
        var $specConf;
        var $toolbar = array();                                 // Save the buttons for the toolbar
-       var $toolbar_level_size;                                // The size for each level in the toolbar:
        var $toolbarOrderArray = array();
        protected $pluginEnabledArray = array();                // Array of plugin id's enabled in the current RTE editing area
        protected $pluginEnabledCumulativeArray = array();      // Cumulative array of plugin id's enabled so far in any of the RTE editing areas of the form
        public $registeredPlugins = array();                    // Array of registered plugins indexed by their plugin Id's
+       protected $fullScreen = false;
 
        /**
         * Returns true if the RTE is available. Here you check if the browser requirements are met.
@@ -338,13 +335,16 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                                // Preloading the pageStyle and including RTE skin stylesheets
                        $this->addPageStyle();
                        $this->addSkin();
-
                                // Loading JavaScript files and code
                        if ($this->TCEform->RTEcounter == 1) {
                                $this->TCEform->additionalJS_pre['rtehtmlarea-loadJScode'] = $this->loadJScode($this->TCEform->RTEcounter);
                        }
                        $this->TCEform->additionalCode_pre['rtehtmlarea-loadJSfiles'] = $this->loadJSfiles($this->TCEform->RTEcounter);
-
+                       $pageRenderer = $GLOBALS['SOBE']->doc->getPageRenderer();
+                       $pageRenderer->enableExtJSQuickTips();
+                       if (!$GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->ID]['enableCompressedScripts']) {
+                               $pageRenderer->enableExtJsDebug();
+                       }
                        /* =======================================
                         * DRAW THE EDITOR
                         * =======================================
@@ -365,20 +365,10 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
 
                                // Check if wizard_rte called this for fullscreen edtition; if so, change the size of the RTE to fullscreen using JS
                        if (basename(PATH_thisScript) == 'wizard_rte.php') {
-                               $height = 'window.innerHeight';
-                               $width = 'window.innerWidth';
-                               if ($this->client['BROWSER'] == 'msie') {
-                                       $height = 'document.body.offsetHeight';
-                                       $width = 'document.body.offsetWidth';
-                               }
-
-                                       // Subtract the docheader height from the calculated window height
-                               $height .= ' - document.getElementById("typo3-docheader").offsetHeight';
-
+                               $this->fullScreen = true;
                                $editorWrapWidth = '100%';
                                $editorWrapHeight = '100%';
                                $this->RTEdivStyle = 'position:relative; left:0px; top:0px; height:100%; width:100%; border: 1px solid black; padding: 2px 0px 2px 2px;';
-                               $this->TCEform->additionalJS_post[] = $this->setRTEsizeByJS('RTEarea' . $textAreaId, $height, $width);
                        }
 
                                // Register RTE in JS:
@@ -426,9 +416,6 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
        protected function addSkin() {
                        // Get skin file name from Page TSConfig if any
                $skinFilename = trim($this->thisConfig['skin']) ? trim($this->thisConfig['skin']) : 'EXT:' . $this->ID . '/htmlarea/skins/default/htmlarea.css';
-               if($this->client['BROWSER'] == 'gecko' && $this->client['VERSION'] == '1.3' && substr($skinFilename,0,4) == 'EXT:')  {
-                       $skinFilename = 'EXT:' . $this->ID . '/htmlarea/skins/default/htmlarea.css';
-               }
                        // Skin provided by some extension
                if (substr($skinFilename,0,4) == 'EXT:') {
                        list($extKey,$local) = explode('/',substr($skinFilename,4),2);
@@ -561,44 +548,22 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
        function setToolbar() {
                global $BE_USER;
 
-               if ($this->client['BROWSER'] == 'msie' || $this->client['BROWSER'] == 'opera' || ($this->client['BROWSER'] == 'gecko' && $this->client['VERSION'] == '1.3')) {
+               if ($this->client['BROWSER'] == 'msie' || $this->client['BROWSER'] == 'opera') {
                        $this->thisConfig['keepButtonGroupTogether'] = 0;
                }
 
                $this->defaultToolbarOrder = 'bar, blockstylelabel, blockstyle, space, textstylelabel, textstyle, linebreak,
                        bar, formattext, bold,  strong, italic, emphasis, big, small, insertedtext, deletedtext, citation, code, definition, keyboard, monospaced, quotation, sample, variable, bidioverride, strikethrough, subscript, superscript, underline, span,
-                       bar, fontstyle, space, fontsize, bar, formatblock, insertparagraphbefore, insertparagraphafter, blockquote,
+                       bar, fontstyle, space, fontsize, bar, formatblock, insertparagraphbefore, insertparagraphafter, blockquote, line,
                        bar, left, center, right, justifyfull,
                        bar, orderedlist, unorderedlist, definitionlist, definitionitem, outdent, indent,  bar, lefttoright, righttoleft, language, showlanguagemarks,
                        bar, textcolor, bgcolor, textindicator,
-                       bar, emoticon, insertcharacter, line, 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,
+                       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,
                        bar, chMode, inserttag, removeformat, bar, copy, cut, paste, bar, undo, redo, bar, showhelp, about, linebreak,
                        ' . ($this->thisConfig['hideTableOperationsInToolbar'] ? '': 'bar, toggleborders,') . ' bar, tableproperties, tablerestyle, bar, rowproperties, rowinsertabove, rowinsertunder, rowdelete, rowsplit, bar,
                        columnproperties, columninsertbefore, columninsertafter, columndelete, columnsplit, bar,
                        cellproperties, cellinsertbefore, cellinsertafter, celldelete, cellsplit, cellmerge';
 
-                       // Special toolbar for Mozilla Wamcom on Mac OS 9
-               if($this->client['BROWSER'] == 'gecko' && $this->client['VERSION'] == '1.3')  {
-                       $this->defaultToolbarOrder = $this->TCEform->docLarge ? 'bar, blockstylelabel, blockstyle, space, textstylelabel, textstyle, linebreak,
-                               bar, fontstyle, space, fontsize, space, formatblock, insertparagraphbefore, insertparagraphafter, blockquote, bar, bold, italic, underline, strikethrough,
-                               subscript, superscript, lefttoright, righttoleft, language, showlanguagemarks, bar, left, center, right, justifyfull, linebreak,
-                               bar, orderedlist, unorderedlist, definitionlist, definitionitem, outdent, indent, bar, textcolor, bgcolor, textindicator, bar, emoticon,
-                               insertcharacter, line, link, unlink, image, table, user, acronym, bar, findreplace, spellcheck, bar, chMode, inserttag,
-                               removeformat, bar, copy, cut, paste, bar, undo, redo, bar, showhelp, about, linebreak,
-                               bar, toggleborders, bar, tableproperties, tablerestyle, bar, rowproperties, rowinsertabove, rowinsertunder, rowdelete, rowsplit, bar,
-                               columnproperties, columninsertbefore, columninsertafter, columndelete, columnsplit, bar,
-                               cellproperties, cellinsertbefore, cellinsertafter, celldelete, cellsplit, cellmerge'
-                               : 'bar, blockstylelabel, blockstyle, space, textstylelabel, textstyle, linebreak,
-                               bar, fontstyle, space, fontsize, space, formatblock, insertparagraphbefore, insertparagraphafter, blockquote, bar, bold, italic, underline, strikethrough,
-                               subscript, superscript, linebreak, bar, lefttoright, righttoleft, language, showlanguagemarks, bar, left, center, right, justifyfull,
-                               orderedlist, unorderedlist, definitionlist, definitionitem, outdent, indent, bar, textcolor, bgcolor, textindicator, bar, emoticon,
-                               insertcharacter, line, link, unlink, image, table, user, acronym, linebreak, bar, findreplace, spellcheck, bar, chMode, inserttag,
-                               removeformat, bar, copy, cut, paste, bar, undo, redo, bar, showhelp, about, linebreak,
-                               bar, toggleborders, bar, tableproperties, tablerestyle, bar, rowproperties, rowinsertabove, rowinsertunder, rowdelete, rowsplit, bar,
-                               columnproperties, columninsertbefore, columninsertafter, columndelete, columnsplit, bar,
-                               cellproperties, cellinsertbefore, cellinsertafter, celldelete, cellsplit, cellmerge';
-               }
-
                        // Additional buttons from registered plugins
                foreach($this->registeredPlugins as $pluginId => $plugin) {
                        if ($this->isPluginEnabled($pluginId)) {
@@ -738,21 +703,6 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
         function convertToolbarForHTMLArea($button) {
                return $this->convertToolbarForHtmlAreaArray[$button];
         }
-
-       /**
-        * Return the JS-function for setting the RTE size.
-        *
-        * @param       string          DivID-Name
-        * @param       int                     the height for the RTE
-        * @param       int                     the width for the RTE
-        * @return string               Loader function in JS
-        */
-       function setRTEsizeByJS($divId, $height, $width) {
-               return '
-                       setRTEsizeByJS(\''.$divId.'\','.$height.', '.$width.');
-               ';
-       }
-
        /**
         * Return the HTML code for loading the Javascript files
         *
@@ -777,7 +727,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                        if (typeof(RTEarea) == "undefined") {
                                RTEarea = new Object();
                                RTEarea.init = function() {
-                                       if (typeof(HTMLArea) == "undefined") {
+                                       if (typeof(HTMLArea) == "undefined" || !Ext.isReady) {
                                                window.setTimeout("RTEarea.init();", 40);
                                        } else {'
                                                . $loadPluginCode . '
@@ -859,6 +809,10 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                        RTEarea[editornumber].deleted = false;
                        RTEarea[editornumber].textAreaId = "' . $textAreaId . '";
                        RTEarea[editornumber].id = "RTEarea" + editornumber;
+                       RTEarea[editornumber].RTEWidthOverride = "' . trim($this->thisConfig['RTEWidthOverride']) . '";
+                       RTEarea[editornumber].RTEHeightOverride = "' . trim($this->thisConfig['RTEHeightOverride']) . '";
+                       RTEarea[editornumber].fullScreen = ' . ($this->fullScreen ? 'true' : 'false') . ';
+                       RTEarea[editornumber].showStatusBar = ' . (trim($this->thisConfig['showStatusBar'])?'true':'false') . ';
                        RTEarea[editornumber].enableWordClean = ' . (trim($this->thisConfig['enableWordClean'])?'true':'false') . ';
                        RTEarea[editornumber]["htmlRemoveComments"] = ' . (trim($this->thisConfig['removeComments'])?'true':'false') . ';
                        RTEarea[editornumber].disableEnterParagraphs = ' . (trim($this->thisConfig['disableEnterParagraphs'])?'true':'false') . ';
@@ -1215,64 +1169,62 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
        }
 
        /**
-        * Return the JS-Code for the Toolbar-Config-Array for HTML-Area
+        * Return the JS code of the toolbar configuration for the HTMLArea editor
         *
-        * @return string               the JS-Code as an JS-Array
+        * @return string       the JS code as nested JS arrays
         */
-
-       function getJSToolbarArray() {
-               $toolbar = '';                  // The JS-Code for the toolbar
-               $group = '';                    // The TS-Code for the group in the moment, each group are between "bar"s
-               $group_has_button = false;      // True if the group has any enabled buttons
-               $group_needs_starting_bar = false;
-               $previous_is_space = false;
-
-                       // process each button in the order list
-               foreach ($this->toolbarOrderArray as $button) {
-                       // check if a new group starts
-                       if (($button == 'bar' || $button == 'linebreak') && $group_has_button) {
-                                       // New line
-                               if ($button == 'linebreak') {
-                                       $convertButton = '"' . $this->convertToolbarForHTMLArea('linebreak') . '"';
-                                       $group = ($group!='') ? ($group . ', ' . $convertButton) : $convertButton;
-                               }
-                                       // New group
-                               $toolbar .= $toolbar ? (', ' . $group) : ('[[' . $group);
-                               $group = '';
-                               $previous_is_space = false;
-                               $group_has_button = false;
-                               $group_needs_starting_bar = ($button == 'bar');
-                       } elseif ($toolbar && $button == 'linebreak' && !$group_has_button) {
-                                       // Insert linebreak if no group is opened
-                               $group = '';
-                               $previous_is_space = false;
-                               $group_needs_starting_bar = false;
-                               $toolbar .= ', "' . $this->convertToolbarForHTMLArea($button) . '"';
-                       } elseif ($button == 'bar' && !$group_has_button) {
-                               $group_needs_starting_bar = true;
-                       } elseif ($button == 'space' && $group_has_button && !$previous_is_space) {
-                               $convertButton = $this->convertToolbarForHTMLArea($button);
-                               $convertButton = '"' . $convertButton . '"';
-                               $group .= $group ? (', ' . $convertButton) : ($group_needs_starting_bar ? ('"' . $this->convertToolbarForHTMLArea('bar') . '", ' . $convertButton) : $convertButton);
-                               $group_needs_starting_bar = false;
-                               $previous_is_space = true;
-                       } elseif (in_array($button, $this->toolbar)) {
-                                       // Add the button to the group
-                               $convertButton = $this->convertToolbarForHTMLArea($button);
-                               if ($convertButton) {
-                                       $convertButton = '"' . $convertButton . '"';
-                                       $group .= $group ? (', ' . $convertButton) : ($group_needs_starting_bar ? ('"' . $this->convertToolbarForHTMLArea('bar') . '", ' . $convertButton) : $convertButton);
-                                       $group_has_button = true;
-                                       $group_needs_starting_bar = false;
-                                       $previous_is_space = false;
-                               }
+       protected function getJSToolbarArray() {
+                       // The toolbar array
+               $toolbar = array();
+                       // The current row;  a "linebreak" ends the current row
+               $row = array();
+                       // The current group; each group is between "bar"s; a "linebreak" ends the current group
+               $group = array();
+                       // Process each toolbar item in the toolbar order list
+               foreach ($this->toolbarOrderArray as $item) {
+                       switch ($item) {
+                               case 'linebreak':
+                                               // Add row to toolbar if not empty
+                                       if (!empty($group)) {
+                                               $row[] = $group;
+                                               $group = array();
+                                       }
+                                       if (!empty($row)) {
+                                               $toolbar[] = $row;
+                                               $row = array();
+                                       }
+                                       break;
+                               case 'bar':
+                                               // Add group to row if not empty
+                                       if (!empty($group)) {
+                                               $row[] = $group;
+                                               $group = array();
+                                       }
+                                       break;
+                               case 'space':
+                                       if (end($group) != $this->convertToolbarForHTMLArea($item)) {
+                                               $group[] = $this->convertToolbarForHTMLArea($item);
+                                       }
+                                       break;
+                               default:
+                                       if (in_array($item, $this->toolbar)) {
+                                                       // Add the item to the group
+                                               $convertedItem = $this->convertToolbarForHTMLArea($item);
+                                               if ($convertedItem) {
+                                                       $group[] = $convertedItem;
+                                               }
+                                       }
+                                       break;
                        }
-                       // else ignore
                }
-                       // add the last group
-               if($group_has_button) $toolbar .= $toolbar ? (', ' . $group) : ('[[' . $group);
-               $toolbar = $toolbar . ']]';
-               return $toolbar;
+                       // Add the last group and last line, if not empty
+               if (!empty($group)) {
+                       $row[] = $group;
+               }
+               if (!empty($row)) {
+                       $toolbar[] = $row;
+               }
+               return json_encode($toolbar);
        }
 
        public function getLLContent($string) {
@@ -1347,7 +1299,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
         * @return      string          Javascript code
         */
        function setSaveRTE($RTEcounter, $formName, $textareaId) {
-               return 'if (RTEarea["' . $textareaId . '"]) { document.' . $formName . '["' . $textareaId . '"].value = RTEarea["' . $textareaId . '"].editor.getPluginInstance("EditorMode").getHTML(); } else { OK = 0; };';
+               return 'if (RTEarea["' . $textareaId . '"]) { document.' . $formName . '["' . $textareaId . '"].value = RTEarea["' . $textareaId . '"].editor.getHTML(); } else { OK = 0; };';
        }
 
        /**
index c6b6f40..c3bb413 100644 (file)
@@ -19,7 +19,7 @@ $EM_CONF[$_EXTKEY] = array(
        'conflicts' => 'rte_conf',
        'priority' => '',
        'loadOrder' => '',
-       'module' => 'mod2,mod3,mod4,mod5,mod6',
+       'module' => 'mod3,mod4,mod5,mod6',
        'state' => 'stable',
        'internal' => 0,
        'uploadfolder' => 1,
@@ -32,7 +32,7 @@ $EM_CONF[$_EXTKEY] = array(
        'author_company' => 'SJBR',
        'CGLcompliance' => '',
        'CGLcompliance_note' => '',
-       'version' => '1.9.0',
+       'version' => '1.9.1',
        '_md5_values_when_last_written' => 'a:434:{s:9:"ChangeLog";s:4:"e5f3";s:29:"class.tx_rtehtmlarea_base.php";s:4:"8a14";s:27:"class.tx_rtehtmlareaapi.php";s:4:"69b4";s:21:"ext_conf_template.txt";s:4:"afd8";s:12:"ext_icon.gif";s:4:"2f41";s:17:"ext_localconf.php";s:4:"340c";s:14:"ext_tables.php";s:4:"ea2e";s:14:"ext_tables.sql";s:4:"bba8";s:13:"locallang.xml";s:4:"3cca";s:16:"locallang_db.xml";s:4:"c2ed";s:7:"tca.php";s:4:"6b5a";s:14:"doc/manual.sxw";s:4:"e68c";s:59:"extensions/AboutEditor/class.tx_rtehtmlarea_abouteditor.php";s:4:"d8ac";s:40:"extensions/AboutEditor/skin/htmlarea.css";s:4:"eb62";s:44:"extensions/AboutEditor/skin/images/about.gif";s:4:"1690";s:51:"extensions/Acronym/class.tx_rtehtmlarea_acronym.php";s:4:"ee28";s:36:"extensions/Acronym/skin/htmlarea.css";s:4:"c107";s:42:"extensions/Acronym/skin/images/acronym.gif";s:4:"1eaa";s:63:"extensions/BlockElements/class.tx_rtehtmlarea_blockelements.php";s:4:"aeef";s:38:"extensions/BlockElements/locallang.xml";s:4:"479e";s:42:"extensions/BlockElements/skin/htmlarea.css";s:4:"83ce";s:51:"extensions/BlockElements/skin/images/blockquote.gif";s:4:"34dc";s:47:"extensions/BlockElements/skin/images/indent.gif";s:4:"57df";s:58:"extensions/BlockElements/skin/images/insertOrderedList.gif";s:4:"eb1c";s:61:"extensions/BlockElements/skin/images/insertParagraphAfter.gif";s:4:"e335";s:62:"extensions/BlockElements/skin/images/insertParagraphBefore.gif";s:4:"9c42";s:60:"extensions/BlockElements/skin/images/insertUnorderedList.gif";s:4:"5620";s:54:"extensions/BlockElements/skin/images/justifyCenter.gif";s:4:"420d";s:52:"extensions/BlockElements/skin/images/justifyFull.gif";s:4:"b129";s:52:"extensions/BlockElements/skin/images/justifyLeft.gif";s:4:"3799";s:53:"extensions/BlockElements/skin/images/justifyRight.gif";s:4:"0662";s:48:"extensions/BlockElements/skin/images/outdent.gif";s:4:"4786";s:57:"extensions/BlockStyle/class.tx_rtehtmlarea_blockstyle.php";s:4:"3ba0";s:35:"extensions/BlockStyle/locallang.xml";s:4:"26b8";s:61:"extensions/CharacterMap/class.tx_rtehtmlarea_charactermap.php";s:4:"a537";s:41:"extensions/CharacterMap/skin/htmlarea.css";s:4:"06c8";s:55:"extensions/CharacterMap/skin/images/insertCharacter.gif";s:4:"af19";s:59:"extensions/ContextMenu/class.tx_rtehtmlarea_contextmenu.php";s:4:"e4b5";s:55:"extensions/CopyPaste/class.tx_rtehtmlarea_copypaste.php";s:4:"09ad";s:38:"extensions/CopyPaste/skin/htmlarea.css";s:4:"9391";s:41:"extensions/CopyPaste/skin/images/copy.gif";s:4:"98d2";s:40:"extensions/CopyPaste/skin/images/cut.gif";s:4:"1323";s:42:"extensions/CopyPaste/skin/images/paste.gif";s:4:"7df5";s:61:"extensions/DefaultClean/class.tx_rtehtmlarea_defaultclean.php";s:4:"142b";s:61:"extensions/DefaultColor/class.tx_rtehtmlarea_defaultcolor.php";s:4:"fa59";s:37:"extensions/DefaultColor/locallang.xml";s:4:"3fb4";s:41:"extensions/DefaultColor/skin/htmlarea.css";s:4:"6076";s:49:"extensions/DefaultColor/skin/images/forecolor.gif";s:4:"dbc8";s:51:"extensions/DefaultColor/skin/images/hilitecolor.gif";s:4:"d97c";s:59:"extensions/DefaultFont/class.tx_rtehtmlarea_defaultfont.php";s:4:"2172";s:36:"extensions/DefaultFont/locallang.xml";s:4:"8c90";s:61:"extensions/DefaultImage/class.tx_rtehtmlarea_defaultimage.php";s:4:"12cf";s:41:"extensions/DefaultImage/skin/htmlarea.css";s:4:"6cfe";s:45:"extensions/DefaultImage/skin/images/image.gif";s:4:"c0f0";s:63:"extensions/DefaultInline/class.tx_rtehtmlarea_defaultinline.php";s:4:"4e85";s:38:"extensions/DefaultInline/locallang.xml";s:4:"318f";s:42:"extensions/DefaultInline/skin/htmlarea.css";s:4:"6009";s:45:"extensions/DefaultInline/skin/images/bold.gif";s:4:"94f2";s:47:"extensions/DefaultInline/skin/images/italic.gif";s:4:"f60c";s:54:"extensions/DefaultInline/skin/images/strikethrough.gif";s:4:"3fd0";s:50:"extensions/DefaultInline/skin/images/subscript.gif";s:4:"cedd";s:52:"extensions/DefaultInline/skin/images/superscript.gif";s:4:"8aea";s:50:"extensions/DefaultInline/skin/images/underline.gif";s:4:"81e6";s:59:"extensions/DefaultLink/class.tx_rtehtmlarea_defaultlink.php";s:4:"2219";s:40:"extensions/DefaultLink/skin/htmlarea.css";s:4:"680b";s:43:"extensions/DefaultLink/skin/images/link.gif";s:4:"db9a";s:45:"extensions/DefaultLink/skin/images/unlink.gif";s:4:"86c4";s:65:"extensions/DefinitionList/class.tx_rtehtmlarea_definitionlist.php";s:4:"483d";s:43:"extensions/DefinitionList/skin/htmlarea.css";s:4:"a254";s:56:"extensions/DefinitionList/skin/images/definitionItem.gif";s:4:"33ae";s:56:"extensions/DefinitionList/skin/images/definitionList.gif";s:4:"d5d1";s:57:"extensions/EditorMode/class.tx_rtehtmlarea_editormode.php";s:4:"1453";s:39:"extensions/EditorMode/skin/htmlarea.css";s:4:"0793";s:45:"extensions/EditorMode/skin/images/ed_html.gif";s:4:"fa6e";s:59:"extensions/FindReplace/class.tx_rtehtmlarea_findreplace.php";s:4:"a968";s:40:"extensions/FindReplace/skin/htmlarea.css";s:4:"43cc";s:43:"extensions/FindReplace/skin/images/find.gif";s:4:"827f";s:65:"extensions/InlineElements/class.tx_rtehtmlarea_inlineelements.php";s:4:"452a";s:39:"extensions/InlineElements/locallang.xml";s:4:"07c6";s:46:"extensions/InlineElements/res/pageTSConfig.txt";s:4:"088c";s:43:"extensions/InlineElements/skin/htmlarea.css";s:4:"978b";s:54:"extensions/InlineElements/skin/images/bidioverride.gif";s:4:"f38b";s:45:"extensions/InlineElements/skin/images/big.gif";s:4:"779b";s:46:"extensions/InlineElements/skin/images/bold.gif";s:4:"06ac";s:50:"extensions/InlineElements/skin/images/citation.gif";s:4:"b6eb";s:46:"extensions/InlineElements/skin/images/code.gif";s:4:"6057";s:52:"extensions/InlineElements/skin/images/definition.gif";s:4:"692d";s:53:"extensions/InlineElements/skin/images/deletedtext.gif";s:4:"4eec";s:50:"extensions/InlineElements/skin/images/emphasis.gif";s:4:"04c9";s:54:"extensions/InlineElements/skin/images/insertedtext.gif";s:4:"a624";s:48:"extensions/InlineElements/skin/images/italic.gif";s:4:"be83";s:50:"extensions/InlineElements/skin/images/keyboard.gif";s:4:"53ac";s:52:"extensions/InlineElements/skin/images/monospaced.gif";s:4:"78c0";s:51:"extensions/InlineElements/skin/images/quotation.gif";s:4:"7c62";s:48:"extensions/InlineElements/skin/images/sample.gif";s:4:"667c";s:47:"extensions/InlineElements/skin/images/small.gif";s:4:"e013";s:46:"extensions/InlineElements/skin/images/span.gif";s:4:"0dfa";s:55:"extensions/InlineElements/skin/images/strikethrough.gif";s:4:"73b1";s:48:"extensions/InlineElements/skin/images/strong.gif";s:4:"7f50";s:51:"extensions/InlineElements/skin/images/subscript.gif";s:4:"36c0";s:53:"extensions/InlineElements/skin/images/superscript.gif";s:4:"40c4";s:51:"extensions/InlineElements/skin/images/underline.gif";s:4:"dfac";s:50:"extensions/InlineElements/skin/images/variable.gif";s:4:"da61";s:61:"extensions/InsertSmiley/class.tx_rtehtmlarea_insertsmiley.php";s:4:"4d97";s:41:"extensions/InsertSmiley/skin/htmlarea.css";s:4:"fb52";s:46:"extensions/InsertSmiley/skin/images/smiley.gif";s:4:"c331";s:53:"extensions/Language/class.tx_rtehtmlarea_language.php";s:4:"4f0b";s:33:"extensions/Language/locallang.xml";s:4:"ff62";s:37:"extensions/Language/skin/htmlarea.css";s:4:"7034";s:49:"extensions/Language/skin/images/left_to_right.gif";s:4:"1a1f";s:49:"extensions/Language/skin/images/right_to_left.gif";s:4:"2a38";s:55:"extensions/Language/skin/images/show-language-marks.gif";s:4:"0bbb";s:53:"extensions/QuickTag/class.tx_rtehtmlarea_quicktag.php";s:4:"c925";s:37:"extensions/QuickTag/skin/htmlarea.css";s:4:"b006";s:45:"extensions/QuickTag/skin/images/inserttag.gif";s:4:"a463";s:61:"extensions/RemoveFormat/class.tx_rtehtmlarea_removeformat.php";s:4:"f7a1";s:41:"extensions/RemoveFormat/skin/htmlarea.css";s:4:"be33";s:45:"extensions/RemoveFormat/skin/images/clean.gif";s:4:"2a0f";s:57:"extensions/SelectFont/class.tx_rtehtmlarea_selectfont.php";s:4:"281e";s:35:"extensions/SelectFont/locallang.xml";s:4:"cb6e";s:61:"extensions/SpellChecker/class.tx_rtehtmlarea_spellchecker.php";s:4:"9c27";s:41:"extensions/SpellChecker/skin/htmlarea.css";s:4:"cedf";s:51:"extensions/SpellChecker/skin/images/spell-check.gif";s:4:"6e0a";s:55:"extensions/StatusBar/class.tx_rtehtmlarea_statusbar.php";s:4:"7db4";s:57:"extensions/TYPO3Color/class.tx_rtehtmlarea_typo3color.php";s:4:"daad";s:35:"extensions/TYPO3Color/locallang.xml";s:4:"377f";s:39:"extensions/TYPO3Color/skin/htmlarea.css";s:4:"fad4";s:47:"extensions/TYPO3Color/skin/images/forecolor.gif";s:4:"dbc8";s:49:"extensions/TYPO3Color/skin/images/hilitecolor.gif";s:4:"d97c";s:67:"extensions/TYPO3HtmlParser/class.tx_rtehtmlarea_typo3htmlparser.php";s:4:"b885";s:57:"extensions/TYPO3Image/class.tx_rtehtmlarea_typo3image.php";s:4:"55d0";s:39:"extensions/TYPO3Image/skin/htmlarea.css";s:4:"f593";s:43:"extensions/TYPO3Image/skin/images/image.gif";s:4:"c0f0";s:55:"extensions/TYPO3Link/class.tx_rtehtmlarea_typo3link.php";s:4:"50b8";s:38:"extensions/TYPO3Link/skin/htmlarea.css";s:4:"73f9";s:41:"extensions/TYPO3Link/skin/images/link.gif";s:4:"db9a";s:43:"extensions/TYPO3Link/skin/images/unlink.gif";s:4:"86c4";s:67:"extensions/TableOperations/class.tx_rtehtmlarea_tableoperations.php";s:4:"56ba";s:44:"extensions/TableOperations/skin/htmlarea.css";s:4:"b57e";s:54:"extensions/TableOperations/skin/images/cell-delete.gif";s:4:"f371";s:60:"extensions/TableOperations/skin/images/cell-insert-after.gif";s:4:"2dd2";s:61:"extensions/TableOperations/skin/images/cell-insert-before.gif";s:4:"5d13";s:53:"extensions/TableOperations/skin/images/cell-merge.gif";s:4:"cb52";s:52:"extensions/TableOperations/skin/images/cell-prop.gif";s:4:"ca41";s:53:"extensions/TableOperations/skin/images/cell-split.gif";s:4:"0095";s:53:"extensions/TableOperations/skin/images/col-delete.gif";s:4:"da78";s:59:"extensions/TableOperations/skin/images/col-insert-after.gif";s:4:"80d8";s:60:"extensions/TableOperations/skin/images/col-insert-before.gif";s:4:"d47d";s:51:"extensions/TableOperations/skin/images/col-prop.gif";s:4:"b178";s:52:"extensions/TableOperations/skin/images/col-split.gif";s:4:"c168";s:55:"extensions/TableOperations/skin/images/insert_table.gif";s:4:"c01b";s:53:"extensions/TableOperations/skin/images/row-delete.gif";s:4:"a289";s:59:"extensions/TableOperations/skin/images/row-insert-above.gif";s:4:"1ef1";s:59:"extensions/TableOperations/skin/images/row-insert-under.gif";s:4:"9ad6";s:51:"extensions/TableOperations/skin/images/row-prop.gif";s:4:"5344";s:52:"extensions/TableOperations/skin/images/row-split.gif";s:4:"ebfd";s:53:"extensions/TableOperations/skin/images/table-prop.gif";s:4:"0a5c";s:56:"extensions/TableOperations/skin/images/table-restyle.gif";s:4:"9284";s:57:"extensions/TableOperations/skin/images/toggle-borders.gif";s:4:"50cb";s:55:"extensions/TextStyle/class.tx_rtehtmlarea_textstyle.php";s:4:"ed42";s:34:"extensions/TextStyle/locallang.xml";s:4:"23dd";s:53:"extensions/UndoRedo/class.tx_rtehtmlarea_undoredo.php";s:4:"d297";s:37:"extensions/UndoRedo/skin/htmlarea.css";s:4:"de26";s:40:"extensions/UndoRedo/skin/images/redo.gif";s:4:"5fdf";s:40:"extensions/UndoRedo/skin/images/undo.gif";s:4:"8d53";s:61:"extensions/UserElements/class.tx_rtehtmlarea_userelements.php";s:4:"984d";s:41:"extensions/UserElements/skin/htmlarea.css";s:4:"f66d";s:44:"extensions/UserElements/skin/images/user.gif";s:4:"bbb4";s:59:"hooks/clearrtecache/class.tx_rtehtmlarea_clearcachemenu.php";s:4:"b8fe";s:58:"hooks/clearrtecache/class.tx_rtehtmlarea_clearrtecache.php";s:4:"a33e";s:37:"hooks/clearrtecache/clearrtecache.png";s:4:"e03a";s:37:"hooks/clearrtecache/ext_localconf.php";s:4:"3cbb";s:33:"hooks/clearrtecache/locallang.xml";s:4:"3902";s:29:"htmlarea/HTMLAREA_LICENSE.txt";s:4:"a10f";s:26:"htmlarea/htmlarea-gecko.js";s:4:"786d";s:23:"htmlarea/htmlarea-ie.js";s:4:"601e";s:20:"htmlarea/htmlarea.js";s:4:"6dde";s:30:"htmlarea/locallang_dialogs.xml";s:4:"a7aa";s:26:"htmlarea/locallang_msg.xml";s:4:"7b6f";s:31:"htmlarea/locallang_tooltips.xml";s:4:"0152";s:44:"htmlarea/plugins/AboutEditor/about-editor.js";s:4:"8241";s:46:"htmlarea/plugins/AboutEditor/popups/about.html";s:4:"d677";s:35:"htmlarea/plugins/Acronym/acronym.js";s:4:"f9af";s:38:"htmlarea/plugins/Acronym/locallang.xml";s:4:"aea2";s:48:"htmlarea/plugins/BlockElements/block-elements.js";s:4:"4c56";s:44:"htmlarea/plugins/BlockElements/locallang.xml";s:4:"ee21";s:42:"htmlarea/plugins/BlockStyle/block-style.js";s:4:"d9e7";s:41:"htmlarea/plugins/BlockStyle/locallang.xml";s:4:"32ed";s:46:"htmlarea/plugins/CharacterMap/character-map.js";s:4:"3b2b";s:43:"htmlarea/plugins/CharacterMap/locallang.xml";s:4:"7211";s:58:"htmlarea/plugins/CharacterMap/popups/select_character.html";s:4:"c48a";s:44:"htmlarea/plugins/ContextMenu/context-menu.js";s:4:"d88e";s:42:"htmlarea/plugins/ContextMenu/locallang.xml";s:4:"3ead";s:40:"htmlarea/plugins/CopyPaste/copy-paste.js";s:4:"427b";s:40:"htmlarea/plugins/CopyPaste/locallang.xml";s:4:"6703";s:46:"htmlarea/plugins/DefaultClean/default-clean.js";s:4:"409f";s:43:"htmlarea/plugins/DefaultClean/locallang.xml";s:4:"9e62";s:46:"htmlarea/plugins/DefaultColor/default-color.js";s:4:"3c23";s:43:"htmlarea/plugins/DefaultColor/locallang.xml";s:4:"c8d1";s:54:"htmlarea/plugins/DefaultColor/popups/select_color.html";s:4:"8af8";s:44:"htmlarea/plugins/DefaultFont/default-font.js";s:4:"8d1c";s:42:"htmlarea/plugins/DefaultFont/locallang.xml";s:4:"a7f8";s:46:"htmlarea/plugins/DefaultImage/default-image.js";s:4:"9ca0";s:43:"htmlarea/plugins/DefaultImage/locallang.xml";s:4:"1fdd";s:54:"htmlarea/plugins/DefaultImage/popups/insert_image.html";s:4:"6773";s:48:"htmlarea/plugins/DefaultInline/default-inline.js";s:4:"c303";s:44:"htmlarea/plugins/DefaultInline/locallang.xml";s:4:"2b55";s:44:"htmlarea/plugins/DefaultLink/default-link.js";s:4:"3139";s:42:"htmlarea/plugins/DefaultLink/locallang.xml";s:4:"e233";s:45:"htmlarea/plugins/DefaultLink/popups/link.html";s:4:"6157";s:50:"htmlarea/plugins/DefinitionList/definition-list.js";s:4:"581b";s:45:"htmlarea/plugins/DefinitionList/locallang.xml";s:4:"5c85";s:42:"htmlarea/plugins/DynamicCSS/dynamiccss.css";s:4:"85b7";s:41:"htmlarea/plugins/DynamicCSS/locallang.xml";s:4:"b6bf";s:52:"htmlarea/plugins/DynamicCSS/img/red_arrow_bullet.gif";s:4:"82d6";s:42:"htmlarea/plugins/EditorMode/editor-mode.js";s:4:"eaab";s:41:"htmlarea/plugins/EditorMode/locallang.xml";s:4:"5b14";s:44:"htmlarea/plugins/FindReplace/find-replace.js";s:4:"5caf";s:41:"htmlarea/plugins/FindReplace/fr_engine.js";s:4:"4ce4";s:42:"htmlarea/plugins/FindReplace/locallang.xml";s:4:"f836";s:53:"htmlarea/plugins/FindReplace/popups/find_replace.html";s:4:"4ee2";s:40:"htmlarea/plugins/InlineCSS/locallang.xml";s:4:"7840";s:50:"htmlarea/plugins/InlineElements/inline-elements.js";s:4:"d31a";s:45:"htmlarea/plugins/InlineElements/locallang.xml";s:4:"6f8c";s:46:"htmlarea/plugins/InsertSmiley/insert-smiley.js";s:4:"23a1";s:43:"htmlarea/plugins/InsertSmiley/locallang.xml";s:4:"ed64";s:54:"htmlarea/plugins/InsertSmiley/popups/insertsmiley.html";s:4:"6ece";s:46:"htmlarea/plugins/InsertSmiley/smileys/0001.gif";s:4:"4aff";s:46:"htmlarea/plugins/InsertSmiley/smileys/0002.gif";s:4:"02c4";s:46:"htmlarea/plugins/InsertSmiley/smileys/0003.gif";s:4:"834f";s:46:"htmlarea/plugins/InsertSmiley/smileys/0004.gif";s:4:"fb6a";s:46:"htmlarea/plugins/InsertSmiley/smileys/0005.gif";s:4:"2a48";s:46:"htmlarea/plugins/InsertSmiley/smileys/0006.gif";s:4:"f970";s:46:"htmlarea/plugins/InsertSmiley/smileys/0007.gif";s:4:"97ee";s:46:"htmlarea/plugins/InsertSmiley/smileys/0008.gif";s:4:"10a6";s:46:"htmlarea/plugins/InsertSmiley/smileys/0009.gif";s:4:"1907";s:46:"htmlarea/plugins/InsertSmiley/smileys/0010.gif";s:4:"9ee6";s:46:"htmlarea/plugins/InsertSmiley/smileys/0011.gif";s:4:"ae73";s:46:"htmlarea/plugins/InsertSmiley/smileys/0012.gif";s:4:"f058";s:46:"htmlarea/plugins/InsertSmiley/smileys/0013.gif";s:4:"3ed8";s:46:"htmlarea/plugins/InsertSmiley/smileys/0014.gif";s:4:"a948";s:46:"htmlarea/plugins/InsertSmiley/smileys/0015.gif";s:4:"218d";s:46:"htmlarea/plugins/InsertSmiley/smileys/0016.gif";s:4:"3539";s:46:"htmlarea/plugins/InsertSmiley/smileys/0017.gif";s:4:"ee2e";s:46:"htmlarea/plugins/InsertSmiley/smileys/0018.gif";s:4:"8c66";s:46:"htmlarea/plugins/InsertSmiley/smileys/0019.gif";s:4:"ac36";s:46:"htmlarea/plugins/InsertSmiley/smileys/0020.gif";s:4:"71ef";s:37:"htmlarea/plugins/Language/language.js";s:4:"f923";s:39:"htmlarea/plugins/Language/locallang.xml";s:4:"d16c";s:39:"htmlarea/plugins/QuickTag/locallang.xml";s:4:"2f53";s:38:"htmlarea/plugins/QuickTag/quick-tag.js";s:4:"3efd";s:36:"htmlarea/plugins/QuickTag/tag-lib.js";s:4:"ba71";s:46:"htmlarea/plugins/QuickTag/popups/quicktag.html";s:4:"9f4b";s:43:"htmlarea/plugins/RemoveFormat/locallang.xml";s:4:"aa85";s:46:"htmlarea/plugins/RemoveFormat/remove-format.js";s:4:"cbbb";s:54:"htmlarea/plugins/RemoveFormat/popups/removeformat.html";s:4:"061e";s:42:"htmlarea/plugins/SelectColor/locallang.xml";s:4:"9f9e";s:42:"htmlarea/plugins/SelectFont/select-font.js";s:4:"af22";s:43:"htmlarea/plugins/SpellChecker/locallang.xml";s:4:"20d8";s:51:"htmlarea/plugins/SpellChecker/spell-check-style.css";s:4:"82bd";s:47:"htmlarea/plugins/SpellChecker/spell-check-ui.js";s:4:"7831";s:46:"htmlarea/plugins/SpellChecker/spell-checker.js";s:4:"c8a9";s:67:"htmlarea/plugins/SpellChecker/popups/spell-check-ui-iso-8859-1.html";s:4:"8a95";s:56:"htmlarea/plugins/SpellChecker/popups/spell-check-ui.html";s:4:"61dc";s:40:"htmlarea/plugins/StatusBar/status-bar.js";s:4:"c578";s:44:"htmlarea/plugins/TYPO3Browsers/locallang.xml";s:4:"89b8";s:47:"htmlarea/plugins/TYPO3Browsers/img/download.gif";s:4:"f6d9";s:52:"htmlarea/plugins/TYPO3Browsers/img/external_link.gif";s:4:"9e48";s:63:"htmlarea/plugins/TYPO3Browsers/img/external_link_new_window.gif";s:4:"6e8d";s:52:"htmlarea/plugins/TYPO3Browsers/img/internal_link.gif";s:4:"12b9";s:63:"htmlarea/plugins/TYPO3Browsers/img/internal_link_new_window.gif";s:4:"402a";s:43:"htmlarea/plugins/TYPO3Browsers/img/mail.gif";s:4:"d5a2";s:41:"htmlarea/plugins/TYPO3Color/locallang.xml";s:4:"3d3c";s:41:"htmlarea/plugins/TYPO3Color/typo3color.js";s:4:"5afa";s:46:"htmlarea/plugins/TYPO3HtmlParser/locallang.xml";s:4:"8010";s:52:"htmlarea/plugins/TYPO3HtmlParser/typo3html-parser.js";s:4:"99ea";s:41:"htmlarea/plugins/TYPO3Image/locallang.xml";s:4:"ab27";s:41:"htmlarea/plugins/TYPO3Image/typo3image.js";s:4:"ccc3";s:39:"htmlarea/plugins/TYPO3Link/typo3link.js";s:4:"677d";s:46:"htmlarea/plugins/TableOperations/locallang.xml";s:4:"e7ed";s:52:"htmlarea/plugins/TableOperations/table-operations.js";s:4:"1bbc";s:40:"htmlarea/plugins/TextStyle/locallang.xml";s:4:"ff67";s:40:"htmlarea/plugins/TextStyle/text-style.js";s:4:"7356";s:38:"htmlarea/plugins/UndoRedo/undo-redo.js";s:4:"762b";s:43:"htmlarea/plugins/UserElements/locallang.xml";s:4:"33f9";s:46:"htmlarea/plugins/UserElements/user-elements.js";s:4:"52c7";s:26:"htmlarea/popups/blank.html";s:4:"8d8d";s:32:"htmlarea/popups/editor_help.html";s:4:"398a";s:50:"htmlarea/skins/default/htmlarea-edited-content.css";s:4:"6626";s:35:"htmlarea/skins/default/htmlarea.css";s:4:"5112";s:48:"htmlarea/skins/default/images/definitionItem.gif";s:4:"33ae";s:48:"htmlarea/skins/default/images/definitionList.gif";s:4:"d5d1";s:42:"htmlarea/skins/default/images/ed_about.gif";s:4:"2763";s:42:"htmlarea/skins/default/images/ed_blank.gif";s:4:"0208";s:45:"htmlarea/skins/default/images/ed_color_bg.gif";s:4:"c6e2";s:45:"htmlarea/skins/default/images/ed_color_fg.gif";s:4:"5d7f";s:41:"htmlarea/skins/default/images/ed_copy.gif";s:4:"4f55";s:43:"htmlarea/skins/default/images/ed_custom.gif";s:4:"e7b2";s:40:"htmlarea/skins/default/images/ed_cut.gif";s:4:"1b00";s:43:"htmlarea/skins/default/images/ed_delete.gif";s:4:"926b";s:41:"htmlarea/skins/default/images/ed_help.gif";s:4:"e7fc";s:39:"htmlarea/skins/default/images/ed_hr.gif";s:4:"f384";s:41:"htmlarea/skins/default/images/ed_html.gif";s:4:"fa6e";s:42:"htmlarea/skins/default/images/ed_image.gif";s:4:"c0f0";s:50:"htmlarea/skins/default/images/ed_left_to_right.gif";s:4:"1a1f";s:41:"htmlarea/skins/default/images/ed_link.gif";s:4:"db9a";s:48:"htmlarea/skins/default/images/ed_list_bullet.gif";s:4:"5620";s:45:"htmlarea/skins/default/images/ed_list_num.gif";s:4:"eb1c";s:42:"htmlarea/skins/default/images/ed_paste.gif";s:4:"fbd2";s:41:"htmlarea/skins/default/images/ed_redo.gif";s:4:"e9e8";s:50:"htmlarea/skins/default/images/ed_right_to_left.gif";s:4:"2a38";s:41:"htmlarea/skins/default/images/ed_save.gif";s:4:"07ad";s:47:"htmlarea/skins/default/images/ed_splitblock.gif";s:4:"503e";s:45:"htmlarea/skins/default/images/ed_splitcel.gif";s:4:"2c04";s:41:"htmlarea/skins/default/images/ed_undo.gif";s:4:"b9ba";s:43:"htmlarea/skins/default/images/ed_unlink.gif";s:4:"86c4";s:53:"htmlarea/skins/default/images/fullscreen_maximize.gif";s:4:"2118";s:53:"htmlarea/skins/default/images/fullscreen_minimize.gif";s:4:"91d6";s:46:"htmlarea/skins/default/images/insert_table.gif";s:4:"c01b";s:49:"htmlarea/skins/default/images/language-marker.gif";s:4:"7b48";s:53:"htmlarea/skins/default/images/show-language-marks.gif";s:4:"0bbb";s:52:"htmlarea/skins/default/images/Acronym/ed_acronym.gif";s:4:"1eaa";s:58:"htmlarea/skins/default/images/BlockElements/blockquote.gif";s:4:"34dc";s:54:"htmlarea/skins/default/images/BlockElements/indent.gif";s:4:"57df";s:68:"htmlarea/skins/default/images/BlockElements/insertParagraphAfter.gif";s:4:"e335";s:69:"htmlarea/skins/default/images/BlockElements/insertParagraphBefore.gif";s:4:"9c42";s:61:"htmlarea/skins/default/images/BlockElements/justifyCenter.gif";s:4:"420d";s:59:"htmlarea/skins/default/images/BlockElements/justifyFull.gif";s:4:"b129";s:59:"htmlarea/skins/default/images/BlockElements/justifyLeft.gif";s:4:"3799";s:60:"htmlarea/skins/default/images/BlockElements/justifyRight.gif";s:4:"0662";s:55:"htmlarea/skins/default/images/BlockElements/outdent.gif";s:4:"4786";s:57:"htmlarea/skins/default/images/CharacterMap/ed_charmap.gif";s:4:"af19";s:53:"htmlarea/skins/default/images/FindReplace/ed_find.gif";s:4:"827f";s:61:"htmlarea/skins/default/images/InlineElements/bidioverride.gif";s:4:"f38b";s:52:"htmlarea/skins/default/images/InlineElements/big.gif";s:4:"779b";s:53:"htmlarea/skins/default/images/InlineElements/bold.gif";s:4:"06ac";s:57:"htmlarea/skins/default/images/InlineElements/citation.gif";s:4:"b6eb";s:53:"htmlarea/skins/default/images/InlineElements/code.gif";s:4:"6057";s:59:"htmlarea/skins/default/images/InlineElements/definition.gif";s:4:"692d";s:60:"htmlarea/skins/default/images/InlineElements/deletedtext.gif";s:4:"4eec";s:57:"htmlarea/skins/default/images/InlineElements/emphasis.gif";s:4:"04c9";s:61:"htmlarea/skins/default/images/InlineElements/insertedtext.gif";s:4:"a624";s:55:"htmlarea/skins/default/images/InlineElements/italic.gif";s:4:"be83";s:57:"htmlarea/skins/default/images/InlineElements/keyboard.gif";s:4:"53ac";s:59:"htmlarea/skins/default/images/InlineElements/monospaced.gif";s:4:"78c0";s:58:"htmlarea/skins/default/images/InlineElements/quotation.gif";s:4:"7c62";s:55:"htmlarea/skins/default/images/InlineElements/sample.gif";s:4:"667c";s:54:"htmlarea/skins/default/images/InlineElements/small.gif";s:4:"e013";s:53:"htmlarea/skins/default/images/InlineElements/span.gif";s:4:"0dfa";s:62:"htmlarea/skins/default/images/InlineElements/strikethrough.gif";s:4:"73b1";s:55:"htmlarea/skins/default/images/InlineElements/strong.gif";s:4:"7f50";s:58:"htmlarea/skins/default/images/InlineElements/subscript.gif";s:4:"36c0";s:60:"htmlarea/skins/default/images/InlineElements/superscript.gif";s:4:"40c4";s:58:"htmlarea/skins/default/images/InlineElements/underline.gif";s:4:"dfac";s:57:"htmlarea/skins/default/images/InlineElements/variable.gif";s:4:"da61";s:56:"htmlarea/skins/default/images/InsertSmiley/ed_smiley.gif";s:4:"c331";s:54:"htmlarea/skins/default/images/QuickTag/ed_quicktag.gif";s:4:"a463";s:55:"htmlarea/skins/default/images/RemoveFormat/ed_clean.gif";s:4:"2a0f";s:58:"htmlarea/skins/default/images/SpellChecker/spell-check.gif";s:4:"6e0a";s:59:"htmlarea/skins/default/images/TYPO3ViewHelp/module_help.gif";s:4:"a500";s:61:"htmlarea/skins/default/images/TableOperations/cell-delete.gif";s:4:"f371";s:67:"htmlarea/skins/default/images/TableOperations/cell-insert-after.gif";s:4:"2dd2";s:68:"htmlarea/skins/default/images/TableOperations/cell-insert-before.gif";s:4:"5d13";s:60:"htmlarea/skins/default/images/TableOperations/cell-merge.gif";s:4:"a2d2";s:59:"htmlarea/skins/default/images/TableOperations/cell-prop.gif";s:4:"ca41";s:60:"htmlarea/skins/default/images/TableOperations/cell-split.gif";s:4:"d87c";s:60:"htmlarea/skins/default/images/TableOperations/col-delete.gif";s:4:"da78";s:66:"htmlarea/skins/default/images/TableOperations/col-insert-after.gif";s:4:"80d8";s:67:"htmlarea/skins/default/images/TableOperations/col-insert-before.gif";s:4:"d47d";s:58:"htmlarea/skins/default/images/TableOperations/col-prop.gif";s:4:"b178";s:59:"htmlarea/skins/default/images/TableOperations/col-split.gif";s:4:"eacc";s:62:"htmlarea/skins/default/images/TableOperations/insert_table.gif";s:4:"c1db";s:60:"htmlarea/skins/default/images/TableOperations/row-delete.gif";s:4:"a289";s:66:"htmlarea/skins/default/images/TableOperations/row-insert-above.gif";s:4:"1ef1";s:66:"htmlarea/skins/default/images/TableOperations/row-insert-after.gif";s:4:"5e98";s:66:"htmlarea/skins/default/images/TableOperations/row-insert-under.gif";s:4:"9ad6";s:58:"htmlarea/skins/default/images/TableOperations/row-prop.gif";s:4:"5344";s:59:"htmlarea/skins/default/images/TableOperations/row-split.gif";s:4:"a712";s:60:"htmlarea/skins/default/images/TableOperations/table-prop.gif";s:4:"0a5c";s:63:"htmlarea/skins/default/images/TableOperations/table-restyle.gif";s:4:"9284";s:64:"htmlarea/skins/default/images/TableOperations/toggle-borders.gif";s:4:"50cb";s:54:"htmlarea/skins/default/images/UserElements/ed_user.gif";s:4:"bbb4";s:16:"mod2/acronym.php";s:4:"6dce";s:41:"mod2/class.tx_rtehtmlarea_acronym_mod.php";s:4:"9dce";s:14:"mod2/clear.gif";s:4:"cc11";s:13:"mod2/conf.php";s:4:"1ec2";s:18:"mod2/locallang.xml";s:4:"0cd8";s:21:"mod3/browse_links.php";s:4:"8d69";s:42:"mod3/class.tx_rtehtmlarea_browse_links.php";s:4:"f98e";s:46:"mod3/class.tx_rtehtmlarea_dam_browse_links.php";s:4:"e306";s:14:"mod3/clear.gif";s:4:"cc11";s:13:"mod3/conf.php";s:4:"b2fb";s:18:"mod3/locallang.xml";s:4:"2d51";s:46:"mod4/class.tx_rtehtmlarea_dam_browse_media.php";s:4:"a1e8";s:42:"mod4/class.tx_rtehtmlarea_select_image.php";s:4:"a55f";s:14:"mod4/clear.gif";s:4:"cc11";s:13:"mod4/conf.php";s:4:"8598";s:18:"mod4/locallang.xml";s:4:"8995";s:21:"mod4/select_image.php";s:4:"c6b9";s:34:"mod5/class.tx_rtehtmlarea_user.php";s:4:"f5fc";s:14:"mod5/clear.gif";s:4:"cc11";s:13:"mod5/conf.php";s:4:"7149";s:18:"mod5/locallang.xml";s:4:"7a78";s:13:"mod5/user.php";s:4:"f5b5";s:40:"mod6/class.tx_rtehtmlarea_parse_html.php";s:4:"33c4";s:13:"mod6/conf.php";s:4:"0cab";s:19:"mod6/parse_html.php";s:4:"e04e";s:32:"pi1/class.tx_rtehtmlarea_pi1.php";s:4:"54b2";s:17:"pi1/locallang.xml";s:4:"2e58";s:32:"pi2/class.tx_rtehtmlarea_pi2.php";s:4:"91ea";s:17:"pi2/locallang.xml";s:4:"a0a7";s:32:"pi3/class.tx_rtehtmlarea_pi3.php";s:4:"b2b7";s:36:"res/accessibilityicons/locallang.xml";s:4:"8211";s:39:"res/accessibilityicons/pageTSConfig.txt";s:4:"7e1a";s:39:"res/accessibilityicons/img/download.gif";s:4:"f6d9";s:44:"res/accessibilityicons/img/external_link.gif";s:4:"9e48";s:55:"res/accessibilityicons/img/external_link_new_window.gif";s:4:"6e8d";s:44:"res/accessibilityicons/img/internal_link.gif";s:4:"12b9";s:55:"res/accessibilityicons/img/internal_link_new_window.gif";s:4:"402a";s:35:"res/accessibilityicons/img/mail.gif";s:4:"d5a2";s:29:"res/advanced/pageTSConfig.txt";s:4:"414e";s:29:"res/advanced/userTSConfig.txt";s:4:"8e7a";s:26:"res/contentcss/default.css";s:4:"429f";s:28:"res/contentcss/locallang.xml";s:4:"ec0e";s:39:"res/contentcss/img/red_arrow_bullet.gif";s:4:"82d6";s:25:"res/demo/pageTSConfig.txt";s:4:"146c";s:25:"res/demo/userTSConfig.txt";s:4:"9b82";s:26:"res/image/pageTSConfig.txt";s:4:"9b6f";s:32:"res/indentalign/pageTSConfig.txt";s:4:"14d5";s:25:"res/proc/pageTSConfig.txt";s:4:"d4f8";s:26:"res/style/pageTSConfig.txt";s:4:"e8e7";s:28:"res/typical/pageTSConfig.txt";s:4:"d33d";s:28:"res/typical/userTSConfig.txt";s:4:"9fa6";s:29:"static/clickenlarge/setup.txt";s:4:"5681";}',
        'constraints' => array(
                'depends' => array(
index c139809..888fc5c 100644 (file)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2005-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2005-2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -68,6 +68,7 @@ require_once(t3lib_extMgm::extPath('rtehtmlarea').'hooks/clearrtecache/ext_local
        // Troubleshooting and experimentation
 $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['enableDebugMode'] = $_EXTCONF['enableDebugMode'] ? $_EXTCONF['enableDebugMode'] : 0;
 $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['enableCompressedScripts'] = $_EXTCONF['enableCompressedScripts'] ? $_EXTCONF['enableCompressedScripts'] : 0;
+$TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['enableCompressedScripts'] = $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['enableCompressedScripts'] && !$TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['enableDebugMode'];
 
        // Integrating with DAM
        // DAM browser may be enabled here only for DAM version lower than 1.1
@@ -95,9 +96,6 @@ if (t3lib_extMgm::isLoaded('lorem_ipsum') && (TYPO3_MODE == 'BE')) {
 
        // Initialize plugin registration array
 $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins'] = array();
-       // Status Bar configuration
-$TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['StatusBar'] = array();
-$TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['StatusBar']['objectReference'] = 'EXT:'.$_EXTKEY.'/extensions/StatusBar/class.tx_rtehtmlarea_statusbar.php:&tx_rtehtmlarea_statusbar';
        // Editor Mode configuration
 $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['EditorMode'] = array();
 $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['EditorMode']['objectReference'] = 'EXT:'.$_EXTKEY.'/extensions/EditorMode/class.tx_rtehtmlarea_editormode.php:&tx_rtehtmlarea_editormode';
@@ -186,10 +184,6 @@ if ($TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['enableAccessibilityIcons']) {
        // Register features that use the style attribute
 $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['allowStyleAttribute'] = $_EXTCONF['allowStyleAttribute'] ? $_EXTCONF['allowStyleAttribute'] : 0;
 if ($TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['allowStyleAttribute']) {
-       $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['DefaultColor'] = array();
-       $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['DefaultColor']['objectReference'] = 'EXT:'.$_EXTKEY.'/extensions/DefaultColor/class.tx_rtehtmlarea_defaultcolor.php:&tx_rtehtmlarea_defaultcolor';
-       $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['DefaultColor']['addIconsToSkin'] = 0;
-       $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['DefaultColor']['disableInFE'] = 0;
        $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['TYPO3Color'] = array();
        $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['TYPO3Color']['objectReference'] = 'EXT:'.$_EXTKEY.'/extensions/TYPO3Color/class.tx_rtehtmlarea_typo3color.php:&tx_rtehtmlarea_typo3color';
        $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['TYPO3Color']['addIconsToSkin'] = 0;
@@ -200,6 +194,10 @@ if ($TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['allowStyleAttribute']) {
        $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['SelectFont']['disableInFE'] = 0;
        t3lib_extMgm::addPageTSConfig('<INCLUDE_TYPOSCRIPT: source="FILE:EXT:' . $_EXTKEY . '/res/style/pageTSConfig.txt">');
 }
+$TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['TextIndicator'] = array();
+$TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['TextIndicator']['objectReference'] = 'EXT:'.$_EXTKEY.'/extensions/TextIndicator/class.tx_rtehtmlarea_textindicator.php:&tx_rtehtmlarea_textindicator';
+$TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['TextIndicator']['addIconsToSkin'] = 0;
+$TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['TextIndicator']['disableInFE'] = 0;
 $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['InsertSmiley'] = array();
 $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['InsertSmiley']['objectReference'] = 'EXT:'.$_EXTKEY.'/extensions/InsertSmiley/class.tx_rtehtmlarea_insertsmiley.php:&tx_rtehtmlarea_insertsmiley';
 $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plugins']['InsertSmiley']['addIconsToSkin'] = 0;
index d0740b4..8826814 100644 (file)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2008-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2008-2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the Typo3 project. The Typo3 project is
@@ -118,22 +118,18 @@ class tx_rtehtmlarea_acronym extends tx_rtehtmlareaapi {
 
                $charset = $GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] ? $GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] : 'iso-8859-1';
                $button = 'acronym';
-
-               $linebreak = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->htmlAreaRTE->ID]['enableCompressedScripts'] ? '' : chr(10);
-               $JSAcronymArray .= 'acronyms = { ' . $linebreak;
-               $JSAcronymLanguageArray .= 'acronymLanguage = { ' . $linebreak;
-               $JSAbbreviationArray .= 'abbreviations = { ' . $linebreak;
-               $JSAbbreviationLanguageArray .= 'abbreviationLanguage = { ' . $linebreak;
+               $acronymArray = array();
+               $abbrArray = array();
 
                $tableA = 'tx_rtehtmlarea_acronym';
                $tableB = 'static_languages';
-               $fields = $tableA.'.type,' . $tableA . '.term,' . $tableA . '.acronym,' . $tableB . '.lg_iso_2';
+               $fields = $tableA.'.type,' . $tableA . '.term,' . $tableA . '.acronym,' . $tableB . '.lg_iso_2,' . $tableB . '.lg_country_iso_2';
                $tableAB = $tableA . ' LEFT JOIN ' . $tableB . ' ON ' . $tableA . '.static_lang_isocode=' . $tableB . '.uid';
                $whereClause = '1=1';
                        // Get all acronyms on pages to which the user has access
                $lockBeUserToDBmounts = isset($this->thisConfig['buttons.'][$button.'.']['lockBeUserToDBmounts']) ? $this->thisConfig['buttons.'][$button.'.']['lockBeUserToDBmounts'] : $GLOBALS['TYPO3_CONF_VARS']['BE']['lockBeUserToDBmounts'];
                if (!$GLOBALS['BE_USER']->isAdmin() && $GLOBALS['TYPO3_CONF_VARS']['BE']['lockBeUserToDBmounts'] && $lockBeUserToDBmounts) {
-                // Temporarily setting alternative web browsing mounts
+                               // Temporarily setting alternative web browsing mounts
                        $altMountPoints = trim($GLOBALS['BE_USER']->getTSConfigVal('options.pageTree.altElementBrowserMountPoints'));
                        if ($altMountPoints) {
                                $savedGroupDataWebmounts = $GLOBALS['BE_USER']->groupData['webmounts'];
@@ -182,21 +178,16 @@ class tx_rtehtmlarea_acronym extends tx_rtehtmlareaapi {
                $whereClause .= t3lib_BEfunc::deleteClause($tableB);
                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fields, $tableAB, $whereClause);
                while ($acronymRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                       if( $acronymRow['type'] == 1) {
-                               $JSAcronymArray .= (($this->acronymIndex++)?',':'') . '"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['term'], $charset) . '":"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['acronym'], $charset) . '"' . $linebreak;
-                               $JSAcronymLanguageArray .= (($this->acronymIndex-1)?',':'') . '"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['term'], $charset) . '":"' . $GLOBALS['LANG']->csConvObj->utf8_encode(strtolower($acronymRow['lg_iso_2']), $charset) . '"' . $linebreak;
-                       }
-                       if ($acronymRow['type'] == 2) {
-                               $JSAbbreviationArray .= (($this->abbreviationIndex++)?',':'') . '"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['term'], $charset) . '":"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['acronym'], $charset) . '"' . $linebreak;
-                               $JSAbbreviationLanguageArray .= (($this->abbreviationIndex-1)?',':'') . '"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['term'], $charset) . '":"' . $GLOBALS['LANG']->csConvObj->utf8_encode(strtolower($acronymRow['lg_iso_2']), $charset) . '"' . $linebreak;
+                       $item = array($GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['term'], $charset), $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['acronym'], $charset), $GLOBALS['LANG']->csConvObj->utf8_encode(strtolower($acronymRow['lg_iso_2']), $charset) . ($acronymRow['lg_country_iso_2'] ? ('-' . $acronymRow['lg_country_iso_2']) : ''));
+                       if ($acronymRow['type'] == 1) {
+                               $acronymArray[] = $item;
+                       } else if ($acronymRow['type'] == 2) {
+                               $abbrArray[] = $item;
                        }
                }
-               $JSAcronymArray .= '};' . $linebreak;
-               $JSAcronymLanguageArray .= '};' . $linebreak;
-               $JSAbbreviationArray .= '};' . $linebreak;
-               $JSAbbreviationLanguageArray .= '};' . $linebreak;
-
-               return $JSAcronymArray . $JSAcronymLanguageArray . $JSAbbreviationArray . $JSAbbreviationLanguageArray;
+               $this->acronymIndex = count($acronymArray);
+               $this->abbreviationIndex = count($abbrArray);
+               return 'var acronyms = ' . json_encode($acronymArray) . ';' . 'var abbreviations = ' . json_encode($abbrArray) . ';';
        }
 }
 
index f680257..df748fc 100644 (file)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2007-2208 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2007-2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the Typo3 project. The Typo3 project is
@@ -43,7 +43,7 @@ class tx_rtehtmlarea_blockelements extends tx_rtehtmlareaapi {
        protected $toolbar;                                     // Reference to RTE toolbar array
        protected $LOCAL_LANG;                                  // Frontend language array
 
-       protected $pluginButtons = 'formatblock, indent, outdent, blockquote, insertparagraphbefore, insertparagraphafter, left, center, right, justifyfull, orderedlist, unorderedlist';
+       protected $pluginButtons = 'formatblock, indent, outdent, blockquote, insertparagraphbefore, insertparagraphafter, left, center, right, justifyfull, orderedlist, unorderedlist, line';
        protected $convertToolbarForHtmlAreaArray = array (
                'formatblock'           => 'FormatBlock',
                'indent'                => 'Indent',
@@ -57,6 +57,7 @@ class tx_rtehtmlarea_blockelements extends tx_rtehtmlareaapi {
                'justifyfull'           => 'JustifyFull',
                'orderedlist'           => 'InsertOrderedList',
                'unorderedlist'         => 'InsertUnorderedList',
+               'line'                  => 'InsertHorizontalRule',
                );
 
        protected $defaultBlockElements = array(
@@ -171,16 +172,13 @@ class tx_rtehtmlarea_blockelements extends tx_rtehtmlareaapi {
                                }
                        }
                                // Generating the javascript options
-                       $JSBlockElements = '{
-                       "'. $first.'" : "none"';
+                       $JSBlockElements = array();
+                       $JSBlockElements[] = array($first, 'none');
                        foreach ($blockElementsOptions as $item => $label) {
-                               $JSBlockElements .= ',
-                       "' . $label . '" : "' . $item . '"';
+                               $JSBlockElements[] = array($label, $item);
                        }
-                       $JSBlockElements .= '};';
-
                        $registerRTEinJavascriptString .= '
-                       RTEarea['.$RTEcounter.'].buttons.formatblock.dropDownOptions = '. $JSBlockElements;
+                       RTEarea['.$RTEcounter.'].buttons.formatblock.data = ' . json_encode($JSBlockElements) . ';';
                }
                return $registerRTEinJavascriptString;
        }
index 159f326..269b439 100644 (file)
@@ -11,3 +11,4 @@
 .htmlarea .toolbar .JustifyFull, .htmlarea-context-menu .JustifyFull {background-image:url("images/justifyFull.gif");}
 .htmlarea .toolbar .InsertOrderedList, .htmlarea-context-menu .InsertOrderedList {background-image:url("images/insertOrderedList.gif");}
 .htmlarea .toolbar .InsertUnorderedList, .htmlarea-context-menu .InsertUnorderedList {background-image:url("images/insertUnorderedList.gif");}
+.htmlarea .toolbar .InsertHorinzontalRule, .htmlarea-context-menu .InsertHorinzontalRule {background-image:url("images/insertHorizontalRule.gif");}
diff --git a/typo3/sysext/rtehtmlarea/extensions/BlockElements/skin/images/insertHorizontalRule.gif b/typo3/sysext/rtehtmlarea/extensions/BlockElements/skin/images/insertHorizontalRule.gif
new file mode 100644 (file)
index 0000000..ae680b2
Binary files /dev/null and b/typo3/sysext/rtehtmlarea/extensions/BlockElements/skin/images/insertHorizontalRule.gif differ
index ad8fd7f..6563943 100644 (file)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2008-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2008-2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the Typo3 project. The Typo3 project is
@@ -22,7 +22,7 @@
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/
 /**
- * About Editor plugin for htmlArea RTE
+ * Context Menu plugin for htmlArea RTE
  *
  * @author Stanislas Rolland <typo3(arobas)sjbr.ca>
  *
@@ -49,7 +49,6 @@ class tx_rtehtmlarea_contextmenu extends tx_rtehtmlareaapi {
        public function main($parentObject) {
                return parent::main($parentObject) && !($this->htmlAreaRTE->client['BROWSER'] == 'opera' || $this->thisConfig['disableContextMenu'] || $this->thisConfig['disableRightClick']);
        }
-
        /**
         * Return JS configuration of the htmlArea plugins registered by the extension
         *
@@ -59,17 +58,26 @@ class tx_rtehtmlarea_contextmenu extends tx_rtehtmlareaapi {
         *
         * The returned string will be a set of JS instructions defining the configuration that will be provided to the plugin(s)
         * Each of the instructions should be of the form:
-        *      RTEarea['.$RTEcounter.']["buttons"]["button-id"]["property"] = "value";
+        *      RTEarea['.$editorId.']["buttons"]["button-id"]["property"] = "value";
         */
-       public function buildJavascriptConfiguration($RTEcounter) {
+       public function buildJavascriptConfiguration($editorId) {
                $registerRTEinJavascriptString = '';
+               if (is_array( $this->thisConfig['contextMenu.'])) {
+                       $registerRTEinJavascriptString .= '
+       RTEarea['.$editorId.'].contextMenu = new Object();';
+                       if ($this->thisConfig['contextMenu.']['showButtons']) {
+                               $registerRTEinJavascriptString .= '
+       RTEarea['.$editorId.'].contextMenu.showButtons = ' . json_encode(t3lib_div::trimExplode(',', $this->htmlAreaRTE->cleanList(t3lib_div::strtolower($this->thisConfig['contextMenu.']['showButtons'])), 1)) . ';';
+                       }
+                       if ($this->thisConfig['contextMenu.']['hideButtons']) {
+                               $registerRTEinJavascriptString .= '
+       RTEarea['.$editorId.'].contextMenu.hideButtons = ' . json_encode(t3lib_div::trimExplode(',', $this->htmlAreaRTE->cleanList(t3lib_div::strtolower($this->thisConfig['contextMenu.']['hideButtons'])), 1)) . ';';
+                       }
+               }
                return $registerRTEinJavascriptString;
        }
-
-} // end of class
-
+}
 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/extensions/ContextMenu/class.tx_rtehtmlarea_contextmenu.php']) {
        include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/extensions/ContextMenu/class.tx_rtehtmlarea_contextmenu.php']);
 }
-
 ?>
\ No newline at end of file
index 8495a5c..f4f1ca9 100644 (file)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2007-2009 Stanislas Rolland <stanislas.rolland(arobas)fructifor.ca>
+*  (c) 2007-2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the Typo3 project. The Typo3 project is
@@ -24,7 +24,7 @@
 /**
  * InlineElements plugin for htmlArea RTE
  *
- * @author Stanislas Rolland <stanislas.rolland(arobas)fructifor.ca>
+ * @author Stanislas Rolland <typo3(arobas)sjbr.ca>
  *
  * TYPO3 SVN ID: $Id$
  *
@@ -161,8 +161,10 @@ class tx_rtehtmlarea_inlineelements extends tx_rtehtmlareaapi {
                                        $hideItems =  t3lib_div::trimExplode(',', $this->htmlAreaRTE->cleanList($this->thisConfig['buttons.']['formattext.']['removeItems']), 1);
                                }
                                        // Restriction clause
-                               if ($this->thisConfig['buttons.']['formattext.']['restrictToItems']) {
-                                       $restrictTo =  t3lib_div::trimExplode(',', $this->htmlAreaRTE->cleanList('none,'.$this->thisConfig['buttons.']['formattext.']['restrictTo']), 1);
+                               if ($this->thisConfig['buttons.']['formattext.']['restrictTo']) {
+                                       $restrictTo = t3lib_div::trimExplode(',', $this->htmlAreaRTE->cleanList('none,'.$this->thisConfig['buttons.']['formattext.']['restrictTo']), 1);
+                               } else if ($this->thisConfig['buttons.']['formattext.']['restrictToItems']) {
+                                       $restrictTo = t3lib_div::trimExplode(',', $this->htmlAreaRTE->cleanList('none,'.$this->thisConfig['buttons.']['formattext.']['restrictToItems']), 1);
                                }
                                        // Elements order
                                if ($this->thisConfig['buttons.']['formattext.']['orderItems']) {
@@ -200,16 +202,13 @@ class tx_rtehtmlarea_inlineelements extends tx_rtehtmlareaapi {
                                }
                        }
                                // Generating the javascript options
-                       $JSInlineElements = '{
-                       "'. $first.'" : "none"';
+                       $JSInlineElements = array();
+                       $JSInlineElements[] = array($first, 'none');
                        foreach ($inlineElementsOptions as $item => $label) {
-                               $JSInlineElements .= ',
-                       "' . $label . '" : "' . $item . '"';
+                               $JSInlineElements[] = array($label, $item);
                        }
-                       $JSInlineElements .= '};';
-
                        $registerRTEinJavascriptString .= '
-                       RTEarea['.$RTEcounter.'].buttons.formattext.dropDownOptions = '. $JSInlineElements;
+                       RTEarea['.$RTEcounter.'].buttons.formattext.data = ' . json_encode($JSInlineElements) . ';';
                }
                return $registerRTEinJavascriptString;
         }
index 1f9ba13..58e0280 100644 (file)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2008-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2008-2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the Typo3 project. The Typo3 project is
@@ -85,10 +85,14 @@ class tx_rtehtmlarea_language extends tx_rtehtmlareaapi {
                                $first = $GLOBALS['LANG']->getLL('No language mark');
                        }
                        $languages = array('none' => $first);
-                       $languages = array_merge($languages, $this->getLanguages());
-                       $languagesJSArray = 'HTMLArea.languageOptions = ' . json_encode(array_flip($languages));
+                       $languages = array_flip(array_merge($languages, $this->getLanguages()));
+                       $languagesJSArray = array();
+                       foreach ($languages as $key => $value) {
+                               $languagesJSArray[] = array($key, $value);
+                       }
+                       $languagesJSArray = 'var options = ' . json_encode($languagesJSArray) . ';';
                        $registerRTEinJavascriptString .= '
-                       RTEarea['.$RTEcounter.'].buttons.'. $button .'.languagesUrl = "' . $this->htmlAreaRTE->writeTemporaryFile('', 'languages_'.$this->htmlAreaRTE->contentLanguageUid, 'js', $languagesJSArray) . '";';
+                       RTEarea['.$RTEcounter.'].buttons.'. $button .'.dataUrl = "' . $this->htmlAreaRTE->writeTemporaryFile('', $button . '_' . $this->htmlAreaRTE->contentLanguageUid, 'js', $languagesJSArray) . '";';
                }
                return $registerRTEinJavascriptString;
        }
index d86fec7..08299ba 100644 (file)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2008-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2008-2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the Typo3 project. The Typo3 project is
@@ -133,13 +133,11 @@ class tx_rtehtmlarea_selectfont extends tx_rtehtmlareaapi {
                        // Initializing the items array
                $items = array();
                if ($this->htmlAreaRTE->is_FE()) {
-                       $items['none'] = '
-                       "' . $GLOBALS['TSFE']->getLLL((($buttonId == 'fontstyle') ? 'Default font' : 'Default size'), $this->LOCAL_LANG) . '" : ""';
+                       $items['none'] = array($GLOBALS['TSFE']->getLLL((($buttonId == 'fontstyle') ? 'Default font' : 'Default size'), $this->LOCAL_LANG), 'none');
                } else {
-                       $items['none'] = '
-                       "' . ($this->htmlAreaRTE->TCEform->inline->isAjaxCall
+                       $items['none'] = array(($this->htmlAreaRTE->TCEform->inline->isAjaxCall
                                        ? $GLOBALS['LANG']->csConvObj->utf8_encode($GLOBALS['LANG']->getLL(($buttonId == 'fontstyle') ? 'Default font' : 'Default size'), $GLOBALS['LANG']->charSet)
-                                       : $GLOBALS['LANG']->getLL(($buttonId == 'fontstyle') ? 'Default font' : 'Default size')) . '" : ""';
+                                       : $GLOBALS['LANG']->getLL(($buttonId == 'fontstyle') ? 'Default font' : 'Default size')), 'none');
                }
                        // Inserting and localizing default items
                if ($hideItems != '*') {
@@ -155,8 +153,7 @@ class tx_rtehtmlarea_selectfont extends tx_rtehtmlareaapi {
                                                }
                                                $label = $this->htmlAreaRTE->TCEform->inline->isAjaxCall ? $GLOBALS['LANG']->csConvObj->utf8_encode($label, $GLOBALS['LANG']->charSet) : $label;
                                        }
-                                       $items[$name] = '
-                               "' . $label . '" : "' . $this->htmlAreaRTE->cleanList($value) . '"';
+                                       $items[$name] = array($label, $this->htmlAreaRTE->cleanList($value));
                                }
                                $index++;
                        }
@@ -168,35 +165,29 @@ class tx_rtehtmlarea_selectfont extends tx_rtehtmlareaapi {
                                if (in_array($name, $addItems)) {
                                        $label = $this->htmlAreaRTE->getPageConfigLabel($conf['name'],0);
                                        $label = (!$this->htmlAreaRTE->is_FE() && $this->htmlAreaRTE->TCEform->inline->isAjaxCall) ? $GLOBALS['LANG']->csConvObj->utf8_encode($label, $GLOBALS['LANG']->charSet) : $label;
-                                       $items[$name] = '
-                               "' . $label . '" : "' . $this->htmlAreaRTE->cleanList($conf['value']) . '"';
+                                       $items[$name] = array($label, $this->htmlAreaRTE->cleanList($conf['value']));
                                }
                        }
                }
                        // Seting default item
                if ($this->thisConfig['buttons.'][$buttonId . '.']['defaultItem'] && $items[$this->thisConfig['buttons.'][$buttonId . '.']['defaultItem']]) {
-                       $items['none'] = $items[$this->thisConfig['buttons.'][$buttonId . '.']['defaultItem']];
+                       $items['none'] = array($items[$this->thisConfig['buttons.'][$buttonId . '.']['defaultItem']][0], 'none');
                        unset($items[$this->thisConfig['buttons.'][$buttonId . '.']['defaultItem']]);
                }
                        // Setting the JS list of options
-               $JSOptions = '';
-               $index = 0;
+               $itemsJSArray = array();
                foreach ($items as $option) {
-                       $JSOptions .= ($index ? ',' : '') . $option;
-                       $index++;
+                       $itemsJSArray[] = $option;
                }
-               $JSOptions = '{'
-                       . $JSOptions . '
-               };';
-
+               $itemsJSArray = 'var options = ' . json_encode($itemsJSArray) . ';';
+               
                        // Adding to button JS configuration
                if (!is_array( $this->thisConfig['buttons.']) || !is_array($this->thisConfig['buttons.'][$buttonId . '.'])) {
                        $configureRTEInJavascriptString .= '
                        RTEarea['.$RTEcounter.'].buttons.'. $buttonId .' = new Object();';
                }
                $configureRTEInJavascriptString .= '
-                       RTEarea['.$RTEcounter.'].buttons.'. $buttonId .'.options = '. $JSOptions;
-
+                       RTEarea['.$RTEcounter.'].buttons.'. $buttonId . '.dataUrl = \'' . $this->htmlAreaRTE->writeTemporaryFile('', $buttonId . '_'. $this->htmlAreaRTE->contentLanguageUid, 'js', $itemsJSArray) . '\';';
                return $configureRTEInJavascriptString;
        }
 } // end of class
index 2e15b13..5508266 100644 (file)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2008-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2008-2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the Typo3 project. The Typo3 project is
@@ -50,7 +50,7 @@ class tx_rtehtmlarea_typo3color extends tx_rtehtmlareaapi {
                );
 
        public function main($parentObject) {
-               return parent::main($parentObject) && $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['allowStyleAttribute'] && !$this->thisConfig['disableSelectColor'];
+               return parent::main($parentObject) && $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['allowStyleAttribute'];
        }
 
        /**
@@ -80,53 +80,40 @@ class tx_rtehtmlarea_typo3color extends tx_rtehtmlareaapi {
         * @return      string          Javascript configuration of colors
         */
        function buildJSColorsConfig($RTEcounter) {
-
                if ($this->htmlAreaRTE->is_FE()) {
                        $RTEProperties = $this->htmlAreaRTE->RTEsetup;
                } else {
                        $RTEProperties = $this->htmlAreaRTE->RTEsetup['properties'];
                }
-
                $configureRTEInJavascriptString = '';
-
                $configureRTEInJavascriptString .= '
                        RTEarea['.$RTEcounter.'].disableColorPicker = ' . (trim($this->thisConfig['disableColorPicker']) ? 'true' : 'false') . ';';
-
-                       // Building JS array of configured colors
+                       // Building the array of configured colors
                if (is_array($RTEProperties['colors.']) )  {
                        $HTMLAreaColorname = array();
                        foreach ($RTEProperties['colors.'] as $colorName => $conf) {
-                               $colorName=substr($colorName,0,-1);
-                               $colorLabel = $this->htmlAreaRTE->getPageConfigLabel($conf['name']);
-                               $HTMLAreaColorname[$colorName] = '
-                               [' . $colorLabel . ' , "' . $conf['value'] . '"]';
+                               $colorName = substr($colorName, 0, -1);
+                               $colorLabel = $this->htmlAreaRTE->getPageConfigLabel($conf['name'], 0);
+                               $colorLabel = (!$this->htmlAreaRTE->is_FE() && $this->htmlAreaRTE->TCEform->inline->isAjaxCall) ? $GLOBALS['LANG']->csConvObj->utf8_encode($colorLabel, $GLOBALS['LANG']->charSet) : $colorLabel;
+                               $HTMLAreaColorname[$colorName] = array($colorLabel, strtoupper(substr($conf['value'], 1, 6)));
                        }
                }
-
                        // Setting the list of colors if specified in the RTE config
-               if ($this->thisConfig['colors'] ) {
-                       $HTMLAreaJSColors = '[';
+               if ($this->thisConfig['colors']) {
                        $HTMLAreaColors = t3lib_div::trimExplode(',' , $this->htmlAreaRTE->cleanList($this->thisConfig['colors']));
-                       $HTMLAreaColorsIndex = 0;
+                       $HTMLAreaJSColors = array();
                        foreach ($HTMLAreaColors as $colorName) {
-                               if($HTMLAreaColorsIndex && $HTMLAreaColorname[$colorName]) {
-                                       $HTMLAreaJSColors .= ',';
+                               if ($HTMLAreaColorname[$colorName]) {
+                                       $HTMLAreaJSColors[] = $HTMLAreaColorname[$colorName];
                                }
-                               $HTMLAreaJSColors .= $HTMLAreaColorname[$colorName];
-                               $HTMLAreaColorsIndex++;
                        }
-                       $HTMLAreaJSColors .= '];';
                        $configureRTEInJavascriptString .= '
-                       RTEarea['.$RTEcounter.'].colors = '. $HTMLAreaJSColors;
+                       RTEarea['.$RTEcounter.'].colors = ' . json_encode($HTMLAreaJSColors) . ';';
                }
-
                return $configureRTEInJavascriptString;
        }
-
-} // end of class
-
+}
 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/extensions/TYPO3Color/class.tx_rtehtmlarea_typo3color.php']) {
        include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/extensions/TYPO3Color/class.tx_rtehtmlarea_typo3color.php']);
 }
-
 ?>
\ No newline at end of file
index d845a9e..5e4a886 100644 (file)
@@ -87,10 +87,8 @@ class tx_rtehtmlarea_typo3link extends tx_rtehtmlareaapi {
                                $registerRTEinJavascriptString .= '
                        RTEarea['.$RTEcounter.'].buttons.'. $button .'.classesAnchorUrl = "' . $this->htmlAreaRTE->writeTemporaryFile('', 'classesAnchor_'.$this->htmlAreaRTE->contentLanguageUid, 'js', $this->buildJSClassesAnchorArray()) . '";';
                        }
-                       if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->extensionKey]['plugins'][$this->pluginName]['additionalAttributes']) {
-                               $registerRTEinJavascriptString .= '
-                       RTEarea['.$RTEcounter.'].buttons.'. $button .'.additionalAttributes = "' . $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->extensionKey]['plugins'][$this->pluginName]['additionalAttributes'] .'";';
-                       }
+                       $registerRTEinJavascriptString .= '
+                       RTEarea['.$RTEcounter.'].buttons.'. $button .'.additionalAttributes = "external' . ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->extensionKey]['plugins'][$this->pluginName]['additionalAttributes'] ? (',' . $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->extensionKey]['plugins'][$this->pluginName]['additionalAttributes']) : '') . '";';
                }
                return $registerRTEinJavascriptString;
        }
index 5d6e352..b1e9fee 100644 (file)
@@ -111,18 +111,20 @@ class tx_rtehtmlarea_tableoperations extends tx_rtehtmlareaapi {
                        $disabledFieldsets = strtolower(implode(',', $disabledFieldsets));
 
                                // Dialogue fieldsets removal configuration
-                       $dialogues = array('table', 'tableproperties', 'rowproperties', 'columnproperties', 'cellproperties');
-                       foreach ($dialogues as $dialogue) {
-                               if (!is_array( $this->thisConfig['buttons.']) || !is_array( $this->thisConfig['buttons.'][$dialogue.'.'])) {
-                                       $registerRTEinJavascriptString .= '
-                       RTEarea['.$RTEcounter.'].buttons.'.$dialogue.' = new Object();
-                       RTEarea['.$RTEcounter.'].buttons.'.$dialogue.'.removeFieldsets = "' . $disabledFieldsets . '";';
-                               } else if ($this->thisConfig['buttons.'][$dialogue.'.']['removeFieldsets']) {
-                                       $registerRTEinJavascriptString .= '
-                       RTEarea['.$RTEcounter.'].buttons.'.$dialogue.'.removeFieldsets += ",' . $disabledFieldsets . '";';
-                               } else {
-                                       $registerRTEinJavascriptString .= '
-                       RTEarea['.$RTEcounter.'].buttons.'.$dialogue.'.removeFieldsets = ",' . $disabledFieldsets . '";';
+                       if ($disabledFieldsets) {
+                               $dialogues = array('table', 'tableproperties', 'rowproperties', 'columnproperties', 'cellproperties');
+                               foreach ($dialogues as $dialogue) {
+                                       if (!is_array( $this->thisConfig['buttons.']) || !is_array( $this->thisConfig['buttons.'][$dialogue.'.'])) {
+                                               $registerRTEinJavascriptString .= '
+                               RTEarea['.$RTEcounter.'].buttons.'.$dialogue.' = new Object();
+                               RTEarea['.$RTEcounter.'].buttons.'.$dialogue.'.removeFieldsets = "' . $disabledFieldsets . '";';
+                                       } else if ($this->thisConfig['buttons.'][$dialogue.'.']['removeFieldsets']) {
+                                               $registerRTEinJavascriptString .= '
+                               RTEarea['.$RTEcounter.'].buttons.'.$dialogue.'.removeFieldsets += ",' . $disabledFieldsets . '";';
+                                       } else {
+                                               $registerRTEinJavascriptString .= '
+                               RTEarea['.$RTEcounter.'].buttons.'.$dialogue.'.removeFieldsets = ",' . $disabledFieldsets . '";';
+                                       }
                                }
                        }
 
diff --git a/typo3/sysext/rtehtmlarea/extensions/TextIndicator/class.tx_rtehtmlarea_textindicator.php b/typo3/sysext/rtehtmlarea/extensions/TextIndicator/class.tx_rtehtmlarea_textindicator.php
new file mode 100644 (file)
index 0000000..5666c73
--- /dev/null
@@ -0,0 +1,66 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  All rights reserved
+*
+*  This script is part of the Typo3 project. The Typo3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+/**
+ * Text Indicator plugin for htmlArea RTE
+ *
+ * @author Stanislas Rolland <typo3(arobas)sjbr.ca>
+ *
+ * TYPO3 SVN ID: $Id: class.tx_rtehtmlarea_textindicator.php 5489 2009-05-23 15:26:20Z ohader $
+ *
+ */
+require_once(t3lib_extMgm::extPath('rtehtmlarea').'class.tx_rtehtmlareaapi.php');
+
+class tx_rtehtmlarea_textindicator extends tx_rtehtmlareaapi {
+       protected $extensionKey = 'rtehtmlarea';        // The key of the extension that is extending htmlArea RTE
+       protected $pluginName = 'TextIndicator';        // The name of the plugin registered by the extension
+       protected $relativePathToLocallangFile = '';    // Path to this main locallang file of the extension relative to the extension dir.
+       protected $relativePathToSkin = 'extensions/TextIndicator/skin/htmlarea.css';           // Path to the skin (css) file relative to the extension dir.
+       protected $htmlAreaRTE;                         // Reference to the invoking object
+       protected $thisConfig;                          // Reference to RTE PageTSConfig
+       protected $toolbar;                             // Reference to RTE toolbar array
+       protected $LOCAL_LANG;                          // Frontend language array
+       protected $pluginButtons = 'textindicator';
+       protected $convertToolbarForHtmlAreaArray = array (
+               'textindicator' => 'TextIndicator',
+               );
+       /**
+        * Return JS configuration of the htmlArea plugins registered by the extension
+        *
+        * @param       integer         Relative id of the RTE editing area in the form
+        *
+        * @return string               JS configuration for registered plugins
+        *
+        * The returned string will be a set of JS instructions defining the configuration that will be provided to the plugin(s)
+        * Each of the instructions should be of the form:
+        *      RTEarea['.$RTEcounter.']["buttons"]["button-id"]["property"] = "value";
+        */
+       public function buildJavascriptConfiguration($RTEcounter) {
+               $registerRTEinJavascriptString = '';
+               return $registerRTEinJavascriptString;
+       }
+}
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/extensions/TextIndicator/class.tx_rtehtmlarea_textindicator.php']) {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/extensions/TextIndicator/class.tx_rtehtmlarea_textindicator.php']);
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/rtehtmlarea/extensions/TextIndicator/skin/htmlarea.css b/typo3/sysext/rtehtmlarea/extensions/TextIndicator/skin/htmlarea.css
new file mode 100644 (file)
index 0000000..a22dbd3
--- /dev/null
@@ -0,0 +1,9 @@
+/* Selectors for the TextIndicator plugin of htmlArea RTE */
+/* TYPO3 SVN ID: $Id $ */
+.htmlarea .toolbar .indicator {
+       background-color:white;cursor:default;
+       width:20px;overflow:hidden;
+       text-align:center;
+       border:1px solid ButtonShadow;margin:4px 1px 0px 1px;padding:0px 3px;
+       float:left;
+}
index cd9f9cb..7054e8a 100644 (file)
@@ -3,7 +3,7 @@
 *
 *  (c) 2002-2004 interactivetools.com, inc.
 *  (c) 2003-2004 dynarch.com
-*  (c) 2004-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2004-2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
 /***************************************************
  *  GECKO-SPECIFIC FUNCTIONS
  ***************************************************/
-HTMLArea.prototype.isEditable = function() {
+HTMLArea.Editor.prototype.isEditable = function() {
        return (this._doc.designMode === "on");
 };
-
-/***************************************************
- *  MOZILLA/FIREFOX EDIT MODE INITILIZATION
- ***************************************************/
-
-HTMLArea.prototype._initEditMode = function () {
-               // We can't set designMode when we are in a hidden TYPO3 tab
-               // Then we will set it when the tab comes in the front.
-       var isNested = false;
-       var allDisplayed = true;
-
-       if (this.nested.sorted && this.nested.sorted.length) {
-               isNested = true;
-               allDisplayed = HTMLArea.allElementsAreDisplayed(this.nested.sorted);
-       }
-       if (!isNested || allDisplayed) {
-               try {
-                       this._iframe.style.display = "block";
-                       this._doc.designMode = "on";
-                       if (this._doc.queryCommandEnabled("insertbronreturn")) this._doc.execCommand("insertbronreturn", false, this.config.disableEnterParagraphs);
-                       if (this._doc.queryCommandEnabled("enableObjectResizing")) this._doc.execCommand("enableObjectResizing", false, !this.config.disableObjectResizing);
-                       if (this._doc.queryCommandEnabled("enableInlineTableEditing")) this._doc.execCommand("enableInlineTableEditing", false, (this.config.buttons.table && this.config.buttons.table.enableHandles) ? true : false);
-                       if (this._doc.queryCommandEnabled("styleWithCSS")) this._doc.execCommand("styleWithCSS", false, this.config.useCSS);
-                               else if (this._doc.queryCommandEnabled("useCSS")) this._doc.execCommand("useCSS", false, !this.config.useCSS);
-               } catch(e) {
-                       if (HTMLArea.is_wamcom) {
-                               this._doc.open();
-                               this._doc.close();
-                               this._initIframeTimer = window.setTimeout("HTMLArea.initIframe(\'" + this._editorNumber + "\');", 500);
-                               return false;
-                       }
-               }
-       }
-               // When the TYPO3 TCA feature div2tab is used, the editor iframe may become hidden with style.display = "none"
-               // This breaks the editor in Mozilla/Firefox browsers: the designMode attribute needs to be resetted after the style.display of the containing div is resetted to "block"
-               // Here we rely on TYPO3 naming conventions for the div id and class name
-       if (this.nested.sorted && this.nested.sorted.length) {
-               var nestedObj, listenerFunction;
-               for (var i=0, length=this.nested.sorted.length; i < length; i++) {
-                       nestedObj = document.getElementById(this.nested.sorted[i]);
-                       listenerFunction = HTMLArea.NestedListener(this, nestedObj, false);
-                       HTMLArea._addEvent(nestedObj, 'DOMAttrModified', listenerFunction);
-               }
-       }
-       return true;
-};
-
 /***************************************************
  *  SELECTIONS AND RANGES
  ***************************************************/
@@ -92,14 +45,14 @@ HTMLArea.prototype._initEditMode = function () {
 /*
  * Get the current selection object
  */
-HTMLArea.prototype._getSelection = function() {
+HTMLArea.Editor.prototype._getSelection = function() {
        return this._iframe.contentWindow.getSelection();
 };
 
 /*
  * Empty the selection object
  */
-HTMLArea.prototype.emptySelection = function(selection) {
+HTMLArea.Editor.prototype.emptySelection = function(selection) {
        if (HTMLArea.is_safari) {
                selection.empty();
        } else {
@@ -113,7 +66,7 @@ HTMLArea.prototype.emptySelection = function(selection) {
 /*
  * Add a range to the selection
  */
-HTMLArea.prototype.addRangeToSelection = function(selection, range) {
+HTMLArea.Editor.prototype.addRangeToSelection = function(selection, range) {
        if (HTMLArea.is_safari) {
                selection.setBaseAndExtent(range.startContainer, range.startOffset, range.endContainer, range.endOffset);
        } else {
@@ -124,7 +77,7 @@ HTMLArea.prototype.addRangeToSelection = function(selection, range) {
 /*
  * Create a range for the current selection
  */
-HTMLArea.prototype._createRange = function(sel) {
+HTMLArea.Editor.prototype._createRange = function(sel) {
        if (HTMLArea.is_safari) {
                var range = this._doc.createRange();
                if (typeof(sel) == "undefined") {
@@ -143,7 +96,9 @@ HTMLArea.prototype._createRange = function(sel) {
                        return range;
                }
        }
-       if (typeof(sel) == "undefined") return this._doc.createRange();
+       if (Ext.isEmpty(sel)) {
+               return this._doc.createRange();
+       }
        try {
                return sel.getRangeAt(0);
        } catch(e) {
@@ -154,7 +109,7 @@ HTMLArea.prototype._createRange = function(sel) {
 /*
  * Select a node AND the contents inside the node
  */
-HTMLArea.prototype.selectNode = function(node, endPoint) {
+HTMLArea.Editor.prototype.selectNode = function(node, endPoint) {
        this.focusEditor();
        var selection = this._getSelection();
        var range = this._doc.createRange();
@@ -173,7 +128,7 @@ HTMLArea.prototype.selectNode = function(node, endPoint) {
 /*
  * Select ONLY the contents inside the given node
  */
-HTMLArea.prototype.selectNodeContents = function(node, endPoint) {
+HTMLArea.Editor.prototype.selectNodeContents = function(node, endPoint) {
        this.focusEditor();
        var selection = this._getSelection();
        var range = this._doc.createRange();
@@ -185,7 +140,7 @@ HTMLArea.prototype.selectNodeContents = function(node, endPoint) {
        this.addRangeToSelection(selection, range);
 };
 
-HTMLArea.prototype.rangeIntersectsNode = function(range, node) {
+HTMLArea.Editor.prototype.rangeIntersectsNode = function(range, node) {
        var nodeRange = this._doc.createRange();
        try {
                nodeRange.selectNode(node);
@@ -200,7 +155,7 @@ HTMLArea.prototype.rangeIntersectsNode = function(range, node) {
 /*
  * Get the selection type
  */
-HTMLArea.prototype.getSelectionType = function(selection) {
+HTMLArea.Editor.prototype.getSelectionType = function(selection) {
                // By default set the type to "Text".
        var type = "Text";
        if (!selection) {
@@ -222,7 +177,7 @@ HTMLArea.prototype.getSelectionType = function(selection) {
 /*
  * Retrieves the selected element (if any), just in the case that a single element (object like and image or a table) is selected.
  */
-HTMLArea.prototype.getSelectedElement = function(selection) {
+HTMLArea.Editor.prototype.getSelectedElement = function(selection) {
        var selectedElement = null;
        if (!selection) {
                var selection = this._getSelection();
@@ -244,7 +199,7 @@ HTMLArea.prototype.getSelectedElement = function(selection) {
 /*
  * Retrieve the HTML contents of selected block
  */
-HTMLArea.prototype.getSelectedHTML = function() {
+HTMLArea.Editor.prototype.getSelectedHTML = function() {
        var range = this._createRange(this._getSelection());
        if (range.collapsed) return "";
        var cloneContents = range.cloneContents();
@@ -257,14 +212,14 @@ HTMLArea.prototype.getSelectedHTML = function() {
 /*
  * Retrieve simply HTML contents of the selected block, IE ignoring control ranges
  */
-HTMLArea.prototype.getSelectedHTMLContents = function() {
+HTMLArea.Editor.prototype.getSelectedHTMLContents = function() {
        return this.getSelectedHTML();
 };
 
 /*
  * Get the deepest node that contains both endpoints of the current selection.
  */
-HTMLArea.prototype.getParentElement = function(selection, range) {
+HTMLArea.Editor.prototype.getParentElement = function(selection, range) {
        if (!selection) {
                var selection = this._getSelection();
        }
@@ -290,7 +245,7 @@ HTMLArea.prototype.getParentElement = function(selection, range) {
  * @returns null | element
  * Borrowed from Xinha (is not htmlArea) - http://xinha.gogo.co.nz/
  */
-HTMLArea.prototype._activeElement = function(selection) {
+HTMLArea.Editor.prototype._activeElement = function(selection) {
        if (this._selectionEmpty(selection)) {
                return null;
        }
@@ -305,7 +260,7 @@ HTMLArea.prototype._activeElement = function(selection) {
 /*
  * Determine if the current selection is empty or not.
  */
-HTMLArea.prototype._selectionEmpty = function(sel) {
+HTMLArea.Editor.prototype._selectionEmpty = function(sel) {
        if (!sel) return true;
        return sel.isCollapsed;
 };
@@ -317,7 +272,7 @@ HTMLArea.prototype._selectionEmpty = function(sel) {
  * in the range boundaries. The advantage of it is that it is possible to
  * handle DOM mutations when moving back to the bookmark.
  */
-HTMLArea.prototype.getBookmark = function (range) {
+HTMLArea.Editor.prototype.getBookmark = function (range) {
                // Create the bookmark info (random IDs).
        var bookmark = {
                startId : (new Date()).valueOf() + Math.floor(Math.random()*1000) + 'S',
@@ -364,7 +319,7 @@ HTMLArea.prototype.getBookmark = function (range) {
  * Get the end point of the bookmark
  * Adapted from FCKeditor
  */
-HTMLArea.prototype.getBookmarkNode = function(bookmark, endPoint) {
+HTMLArea.Editor.prototype.getBookmarkNode = function(bookmark, endPoint) {
        if (endPoint) {
                return this._doc.getElementById(bookmark.startId);
        } else {
@@ -376,7 +331,7 @@ HTMLArea.prototype.getBookmarkNode = function(bookmark, endPoint) {
  * Move the range to the bookmark
  * Adapted from FCKeditor
  */
-HTMLArea.prototype.moveToBookmark = function (bookmark) {
+HTMLArea.Editor.prototype.moveToBookmark = function (bookmark) {
        var startSpan  = this.getBookmarkNode(bookmark, true);
        var endSpan    = this.getBookmarkNode(bookmark, false);
 
@@ -406,7 +361,7 @@ HTMLArea.prototype.moveToBookmark = function (bookmark) {
 /*
  * Select range
  */
-HTMLArea.prototype.selectRange = function (range) {
+HTMLArea.Editor.prototype.selectRange = function (range) {
        var selection = this._getSelection();
        this.emptySelection(selection);
        this.addRangeToSelection(selection, range);
@@ -421,7 +376,7 @@ HTMLArea.prototype.selectRange = function (range) {
  * Delete the current selection, if any.
  * Split the text node, if needed.
  */
-HTMLArea.prototype.insertNodeAtSelection = function(toBeInserted) {
+HTMLArea.Editor.prototype.insertNodeAtSelection = function(toBeInserted) {
        this.focusEditor();
        var range = this._createRange(this._getSelection());
        range.deleteContents();
@@ -434,7 +389,7 @@ HTMLArea.prototype.insertNodeAtSelection = function(toBeInserted) {
  * Insert HTML source code at the current position.
  * Delete the current selection, if any.
  */
-HTMLArea.prototype.insertHTML = function(html) {
+HTMLArea.Editor.prototype.insertHTML = function(html) {
        this.focusEditor();
        var fragment = this._doc.createDocumentFragment();
        var div = this._doc.createElement("div");
@@ -454,7 +409,7 @@ HTMLArea.prototype.insertHTML = function(html) {
  *
  * @return     void
  */
-HTMLArea.prototype.wrapWithInlineElement = function(element, selection, range) {
+HTMLArea.Editor.prototype.wrapWithInlineElement = function(element, selection, range) {
                // Sometimes Opera raises a bad boundary points error
        if (HTMLArea.is_opera) {
                try {
@@ -486,7 +441,7 @@ HTMLArea.prototype.wrapWithInlineElement = function(element, selection, range) {
  *
  * @return     void
  */
-HTMLArea.prototype.cleanAppleStyleSpans = function(node) {
+HTMLArea.Editor.prototype.cleanAppleStyleSpans = function(node) {
        if (HTMLArea.is_safari) {
                if (node.getElementsByClassName) {
                        var spans = node.getElementsByClassName("Apple-style-span");
@@ -513,103 +468,49 @@ HTMLArea.prototype.cleanAppleStyleSpans = function(node) {
 /***************************************************
  *  EVENTS HANDLERS
  ***************************************************/
-
-/*
- * TYPO3 hidden tab and inline event listener (gets event calls)
- */
-HTMLArea.NestedListener = function (editor,nestedObj,noOpenCloseAction) {
-       return (function(ev) {
-               if(!ev) var ev = window.event;
-               HTMLArea.NestedHandler(ev,editor,nestedObj,noOpenCloseAction);
-       });
-};
-
 /*
- * TYPO3 hidden tab and inline event handler (performs actions on event calls)
+ * Backspace event handler
  */
-HTMLArea.NestedHandler = function(ev,editor,nestedObj,noOpenCloseAction) {
+HTMLArea.Editor.prototype._checkBackspace = function() {
+       var self = this;
        window.setTimeout(function() {
-               var target = (ev.target) ? ev.target : ev.srcElement, styleEvent = true;
-                       // In older versions of Mozilla ev.attrName is not yet set and refering to it causes a non-catchable crash
-                       // We are assuming that this was fixed in Firefox 2.0.0.11
-               if (navigator.productSub > 20071127) {
-                       styleEvent = (ev.attrName == "style");
-               }
-               if (target == nestedObj && editor.getMode() == "wysiwyg" && styleEvent && (target.style.display == "" || target.style.display == "block")) {
-                               // Check if all affected nested elements are displayed (style.display!='none'):
-                       if (HTMLArea.allElementsAreDisplayed(editor.nested.sorted)) {
-                               window.setTimeout(function() {
-                                       try {
-                                               editor._doc.designMode = "on";
-                                               if (editor.config.sizeIncludesToolbar && editor._initialToolbarOffsetHeight != editor._toolbar.offsetHeight) {
-                                                       editor.sizeIframe(2);
-                                               }
-                                               if (editor._doc.queryCommandEnabled("insertbronreturn")) editor._doc.execCommand("insertbronreturn", false, editor.config.disableEnterParagraphs);
-                                               if (editor._doc.queryCommandEnabled("enableObjectResizing")) editor._doc.execCommand("enableObjectResizing", false, !editor.config.disableObjectResizing);
-                                               if (editor._doc.queryCommandEnabled("enableInlineTableEditing")) editor._doc.execCommand("enableInlineTableEditing", false, (editor.config.buttons.table && editor.config.buttons.table.enableHandles) ? true : false);
-                                               if (editor._doc.queryCommandEnabled("styleWithCSS")) editor._doc.execCommand("styleWithCSS", false, editor.config.useCSS);
-                                                       else if (editor._doc.queryCommandEnabled("useCSS")) editor._doc.execCommand("useCSS", false, !editor.config.useCSS);
-                                       } catch(e) {
-                                                       // If an event of a parent tab ("nested tabs") is triggered, the following lines should not be
-                                                       // processed, because this causes some trouble on all event handlers...
-                                               if (!noOpenCloseAction) {
-                                                       editor._doc.open();
-                                                       editor._doc.close();
-                                               }
-                                               editor.initIframe();
-                                       }
-                               }, 50);
+               var selection = self._getSelection();
+               var range = self._createRange(selection);
+               var startContainer = range.startContainer;
+               var startOffset = range.startOffset;
+               if (self._selectionEmpty()) {
+                       if (/^(body)$/i.test(startContainer.nodeName)) {
+                               var node = startContainer.childNodes[startOffset];
+                       } else if (/^(body)$/i.test(startContainer.parentNode.nodeName)) {
+                               var node = startContainer;
+                       } else {
+                               return false;
                        }
-                       HTMLArea._stopEvent(ev);
-               }
-       }, 50);
-};
-
-/*
- * Backspace event handler
- */
-HTMLArea.prototype._checkBackspace = function() {
-       if (!HTMLArea.is_safari && !HTMLArea.is_opera) {
-               var self = this;
-               window.setTimeout(function() {
-                       var selection = self._getSelection();
-                       var range = self._createRange(selection);
-                       var startContainer = range.startContainer;
-                       var startOffset = range.startOffset;
-                       if (self._selectionEmpty()) {
-                               if (/^(body)$/i.test(startContainer.nodeName)) {
-                                       var node = startContainer.childNodes[startOffset];
-                               } else if (/^(body)$/i.test(startContainer.parentNode.nodeName)) {
-                                       var node = startContainer;
-                               } else {
-                                       return false;
+                       if (/^(br|#text)$/i.test(node.nodeName) && !/\S/.test(node.textContent)) {
+                               var previousSibling = node.previousSibling;
+                               while (previousSibling && /^(br|#text)$/i.test(previousSibling.nodeName) && !/\S/.test(previousSibling.textContent)) {
+                                       previousSibling = previousSibling.previousSibling;
                                }
-                               if (/^(br|#text)$/i.test(node.nodeName) && !/\S/.test(node.textContent)) {
-                                       var previousSibling = node.previousSibling;
-                                       while (previousSibling && /^(br|#text)$/i.test(previousSibling.nodeName) && !/\S/.test(previousSibling.textContent)) {
-                                               previousSibling = previousSibling.previousSibling;
-                                       }
-                                       HTMLArea.removeFromParent(node);
-                                       if (/^(ol|ul|dl)$/i.test(previousSibling.nodeName)) {
-                                               self.selectNodeContents(previousSibling.lastChild, false);
-                                       } else if (/^(table)$/i.test(previousSibling.nodeName)) {
-                                               self.selectNodeContents(previousSibling.rows[previousSibling.rows.length-1].cells[previousSibling.rows[previousSibling.rows.length-1].cells.length-1], false);
-                                       } else if (!/\S/.test(previousSibling.textContent) && previousSibling.firstChild) {
-                                               self.selectNode(previousSibling.firstChild, true);
-                                       } else {
-                                               self.selectNodeContents(previousSibling, false);
-                                       }
+                               HTMLArea.removeFromParent(node);
+                               if (/^(ol|ul|dl)$/i.test(previousSibling.nodeName)) {
+                                       self.selectNodeContents(previousSibling.lastChild, false);
+                               } else if (/^(table)$/i.test(previousSibling.nodeName)) {
+                                       self.selectNodeContents(previousSibling.rows[previousSibling.rows.length-1].cells[previousSibling.rows[previousSibling.rows.length-1].cells.length-1], false);
+                               } else if (!/\S/.test(previousSibling.textContent) && previousSibling.firstChild) {
+                                       self.selectNode(previousSibling.firstChild, true);
+                               } else {
+                                       self.selectNodeContents(previousSibling, false);
                                }
                        }
-               }, 10);
-       }
+               }
+       }, 10);
        return false;
 };
 
 /*
  * Enter event handler
  */
-HTMLArea.prototype._checkInsertP = function() {
+HTMLArea.Editor.prototype._checkInsertP = function() {
        var editor = this;
        this.focusEditor();
        var i, left, right, rangeClone,
@@ -742,7 +643,8 @@ HTMLArea.prototype._checkInsertP = function() {
  * Detect emails and urls as they are typed in Mozilla
  * Borrowed from Xinha (is not htmlArea) - http://xinha.gogo.co.nz/
  */
-HTMLArea.prototype._detectURL = function(ev) {
+HTMLArea.Editor.prototype._detectURL = function(event) {
+       var ev = event.browserEvent;
        var editor = this;
        var s = this._getSelection();
        if (this.getParentElement(s).nodeName.toLowerCase() != 'a') {
@@ -754,7 +656,7 @@ HTMLArea.prototype._detectURL = function(ev) {
                        a.appendChild(textNode);
                        rightText.data += " ";
                        s.collapse(rightText, rightText.data.length);
-                       HTMLArea._stopEvent(ev);
+                       event.stopEvent();
        
                        editor._unLink = function() {
                                var t = a.firstChild;
@@ -800,7 +702,7 @@ HTMLArea.prototype._detectURL = function(ev) {
                                                var midText   = leftText.splitText(midStart);
                                                var midEnd = midText.data.search(/[^a-zA-Z0-9\._\-\/\&\?=:@]/);
                                                if (midEnd != -1) var endText = midText.splitText(midEnd);
-                                               autoWrap(midText, 'a').href = (m[1] ? m[1] : 'http://') + m[2];
+                                               autoWrap(midText, 'a').href = (m[1] ? m[1] : 'http://') + m[3];
                                                break;
                                        }
                                }
@@ -809,7 +711,7 @@ HTMLArea.prototype._detectURL = function(ev) {
                                if(ev.keyCode == 27 || (editor._unlinkOnUndo && ev.ctrlKey && ev.which == 122) ) {
                                        if(this._unLink) {
                                                this._unLink();
-                                               HTMLArea._stopEvent(ev);
+                                               event.stopEvent();
                                        }
                                        break;
                                } else if(ev.which || ev.keyCode == 8 || ev.keyCode == 46) {
@@ -833,7 +735,7 @@ HTMLArea.prototype._detectURL = function(ev) {
                                                                var textNode = s.anchorNode;
                                                                var fn = function() {
                                                                        var m = textNode.data.match(HTMLArea.RE_url);
-                                                                       a.href = (m[1] ? m[1] : 'http://') + m[2];
+                                                                       a.href = (m[1] ? m[1] : 'http://') + m[3];
                                                                        a._updateAnchTimeout = setTimeout(fn, 250);
                                                                }
                                                                a._updateAnchTimeout = setTimeout(fn, 250);
index b328f44..c307970 100644 (file)
@@ -3,7 +3,7 @@
 *
 *  (c) 2002-2004 interactivetools.com, inc.
 *  (c) 2003-2004 dynarch.com
-*  (c) 2004-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2004-2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -35,7 +35,7 @@
 /***************************************************
  *  IE-SPECIFIC FUNCTIONS
  ***************************************************/
-HTMLArea.prototype.isEditable = function() {
+HTMLArea.Editor.prototype.isEditable = function() {
        return this._doc.body.contentEditable;
 };
 
@@ -45,14 +45,14 @@ HTMLArea.prototype.isEditable = function() {
 /*
  * Get the current selection object
  */
-HTMLArea.prototype._getSelection = function() {
+HTMLArea.Editor.prototype._getSelection = function() {
        return this._doc.selection;
 };
 
 /*
  * Create a range for the current selection
  */
-HTMLArea.prototype._createRange = function(sel) {
+HTMLArea.Editor.prototype._createRange = function(sel) {
        if (typeof(sel) == "undefined") {
                var sel = this._getSelection();
        }
@@ -65,7 +65,7 @@ HTMLArea.prototype._createRange = function(sel) {
 /*
  * Select a node AND the contents inside the node
  */
-HTMLArea.prototype.selectNode = function(node) {
+HTMLArea.Editor.prototype.selectNode = function(node) {
        this.focusEditor();
        this.forceRedraw();
        var range = this._doc.body.createTextRange();
@@ -76,7 +76,7 @@ HTMLArea.prototype.selectNode = function(node) {
 /*
  * Select ONLY the contents inside the given node
  */
-HTMLArea.prototype.selectNodeContents = function(node, endPoint) {
+HTMLArea.Editor.prototype.selectNodeContents = function(node, endPoint) {
        this.focusEditor();
        this.forceRedraw();
        var range = this._doc.body.createTextRange();
@@ -90,7 +90,7 @@ HTMLArea.prototype.selectNodeContents = function(node, endPoint) {
 /*
  * Determine whether the node intersects the range
  */
-HTMLArea.prototype.rangeIntersectsNode = function(range, node) {
+HTMLArea.Editor.prototype.rangeIntersectsNode = function(range, node) {
        this.focusEditor();
        var nodeRange = this._doc.body.createTextRange();
        nodeRange.moveToElementText(node);
@@ -101,7 +101,7 @@ HTMLArea.prototype.rangeIntersectsNode = function(range, node) {
 /*
  * Retrieve the HTML contents of selected block
  */
-HTMLArea.prototype.getSelectedHTML = function() {
+HTMLArea.Editor.prototype.getSelectedHTML = function() {
        var sel = this._getSelection();
        var range = this._createRange(sel);
        if (sel.type.toLowerCase() == "control") {
@@ -116,7 +116,7 @@ HTMLArea.prototype.getSelectedHTML = function() {
 /*
  * Retrieve simply HTML contents of the selected block, IE ignoring control ranges
  */
-HTMLArea.prototype.getSelectedHTMLContents = function() {
+HTMLArea.Editor.prototype.getSelectedHTMLContents = function() {
        var sel = this._getSelection();
        var range = this._createRange(sel);
        return range.htmlText;
@@ -125,7 +125,7 @@ HTMLArea.prototype.getSelectedHTMLContents = function() {
 /*
  * Get the deepest node that contains both endpoints of the current selection.
  */
-HTMLArea.prototype.getParentElement = function(selection, range) {
+HTMLArea.Editor.prototype.getParentElement = function(selection, range) {
        if (!selection) {
                var selection = this._getSelection();
        }
@@ -136,7 +136,12 @@ HTMLArea.prototype.getParentElement = function(selection, range) {
                case "text":
                case "none":
                        var el = range.parentElement();
-                       if(el.nodeName.toLowerCase() == "li" && range.htmlText.replace(/\s/g,"") == el.parentNode.outerHTML.replace(/\s/g,"")) return el.parentNode;
+                       if (el.nodeName.toLowerCase() == 'form') {
+                               return this._doc.body;
+                       }
+                       if (el.nodeName.toLowerCase() == "li" && range.htmlText.replace(/\s/g,"") == el.parentNode.outerHTML.replace(/\s/g,"")) {
+                               return el.parentNode;
+                       }
                        return el;
                case "control": return range.item(0);
                default: return this._doc.body;
@@ -150,7 +155,7 @@ HTMLArea.prototype.getParentElement = function(selection, range) {
  * @returns null | element
  * Borrowed from Xinha (is not htmlArea) - http://xinha.gogo.co.nz/
  */
-HTMLArea.prototype._activeElement = function(sel) {
+HTMLArea.Editor.prototype._activeElement = function(sel) {
        if (sel == null) {
                return null;
        }
@@ -172,7 +177,7 @@ HTMLArea.prototype._activeElement = function(sel) {
 /*
  * Determine if the current selection is empty or not.
  */
-HTMLArea.prototype._selectionEmpty = function(selection) {
+HTMLArea.Editor.prototype._selectionEmpty = function(selection) {
        if (!selection || selection.type.toLowerCase() === "none") return true;
        if (selection.type.toLowerCase() === "text") {
                return !this._createRange(selection).text;
@@ -183,14 +188,14 @@ HTMLArea.prototype._selectionEmpty = function(selection) {
 /*
  * Get a bookmark
  */
-HTMLArea.prototype.getBookmark = function (range) {
+HTMLArea.Editor.prototype.getBookmark = function (range) {
        return range.getBookmark();
 };
 
 /*
  * Move the range to the bookmark
  */
-HTMLArea.prototype.moveToBookmark = function (bookmark) {
+HTMLArea.Editor.prototype.moveToBookmark = function (bookmark) {
        var range = this._createRange();
        range.moveToBookmark(bookmark);
        return range;
@@ -199,7 +204,7 @@ HTMLArea.prototype.moveToBookmark = function (bookmark) {
 /*
  * Select range
  */
-HTMLArea.prototype.selectRange = function (range) {
+HTMLArea.Editor.prototype.selectRange = function (range) {
        range.select();
 };
 /***************************************************
@@ -211,7 +216,7 @@ HTMLArea.prototype.selectRange = function (range) {
  * Delete the current selection, if any.
  * Split the text node, if needed.
  */
-HTMLArea.prototype.insertNodeAtSelection = function(toBeInserted) {
+HTMLArea.Editor.prototype.insertNodeAtSelection = function(toBeInserted) {
        this.insertHTML(toBeInserted.outerHTML);
 };
 
@@ -219,7 +224,7 @@ HTMLArea.prototype.insertNodeAtSelection = function(toBeInserted) {
  * Insert HTML source code at the current position.
  * Delete the current selection, if any.
  */
-HTMLArea.prototype.insertHTML = function(html) {
+HTMLArea.Editor.prototype.insertHTML = function(html) {
        var sel = this._getSelection();
        if (sel.type.toLowerCase() == "control") {
                sel.clear();
@@ -238,7 +243,7 @@ HTMLArea.prototype.insertHTML = function(html) {
  *
  * @return     void
  */
-HTMLArea.prototype.wrapWithInlineElement = function(element, selection, range) {
+HTMLArea.Editor.prototype.wrapWithInlineElement = function(element, selection, range) {
        var nodeName = element.nodeName;
        var parent = this.getParentElement(selection, range);
        var bookmark = this.getBookmark(range);
@@ -312,7 +317,7 @@ HTMLArea.prototype.wrapWithInlineElement = function(element, selection, range) {
 /*
  * Handle the backspace event in IE browsers
  */
-HTMLArea.prototype._checkBackspace = function() {
+HTMLArea.Editor.prototype._checkBackspace = function() {
        var selection = this._getSelection();
        var range = this._createRange(selection);
        if (selection.type == "Control"){ // Deleting or backspacing on a control selection : delete the element
index ea96bf8..3a90bfa 100644 (file)
@@ -3,7 +3,7 @@
 *
 *  (c) 2002-2004 interactivetools.com, inc.
 *  (c) 2003-2004 dynarch.com
-*  (c) 2004-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2004-2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
  *
  * TYPO3 SVN ID: $Id$
  */
-
+       // Avoid re-starting on Ajax request
+if (typeof(HTMLArea) == 'undefined') {
+       // Establish HTMLArea name space
+Ext.namespace('HTMLArea.util.TYPO3', 'HTMLArea.util.Tips', 'HTMLArea.util.Color', 'Ext.ux.form', 'Ext.ux.menu', 'Ext.ux.Toolbar');
 /***************************************************
- *  EDITOR INITIALIZATION AND CONFIGURATION
+ *  BROWSER IDENTIFICATION
  ***************************************************/
-       // Avoid re-starting on Ajax request
-if (typeof(HTMLArea) != "function") {
-
-/*
- * HTMLArea object constructor.
- */
-HTMLArea = function(textarea, config) {
-       if (HTMLArea.checkSupportedBrowser()) {
-               if (typeof(config) == "undefined") this.config = new HTMLArea.Config();
-                       else this.config = config;
-               this._htmlArea = null;
-               this._textArea = textarea;
-               if (typeof(this._textArea) == "string") {
-                       this._textArea = HTMLArea.getElementById("textarea", this._textArea);
-               }
-               this.plugins = {};
-               this._timerToolbar = null;
-               this.doctype = '';
-               this.eventHandlers = {};
-       }
-};
-
-/*
- * Browser identification
- */
 HTMLArea.agt = navigator.userAgent.toLowerCase();
-HTMLArea.is_opera  = (HTMLArea.agt.indexOf("opera") != -1);
+HTMLArea.is_opera  = Ext.isOpera;
 // Some operations require bug fixes provided by Opera 10 (Presto 2.2)
-HTMLArea.is_opera9 = HTMLArea.is_opera && HTMLArea.agt.indexOf("Presto/2.1") != -1;
-HTMLArea.is_ie = (HTMLArea.agt.indexOf("msie") != -1) && !HTMLArea.is_opera;
-HTMLArea.is_safari = (HTMLArea.agt.indexOf("webkit") != -1);
-HTMLArea.is_gecko  = (navigator.product == "Gecko") || HTMLArea.is_opera;
-HTMLArea.is_ff2 = (HTMLArea.agt.indexOf("firefox/2") != -1);
-HTMLArea.is_chrome = HTMLArea.is_safari && (HTMLArea.agt.indexOf("chrome") != -1);
-// Check on MacOS Wamcom version 1.3, if Mozilla will check earliest supported build in checkSupportedBrowser()
-HTMLArea.is_wamcom = (HTMLArea.agt.indexOf("wamcom") != -1) || (HTMLArea.is_gecko && HTMLArea.agt.indexOf("rv:1.3") != -1);
+HTMLArea.is_opera9 = Ext.isOpera && HTMLArea.agt.indexOf("Presto/2.1") != -1;
+HTMLArea.is_ie = Ext.isIE;
+HTMLArea.is_safari = Ext.isWebKit;
+HTMLArea.is_gecko  = Ext.isGecko || Ext.isOpera || Ext.isWebKit;
+HTMLArea.is_ff2 = Ext.isGecko2;
+HTMLArea.is_chrome = Ext.isChrome;
 
 /*
  * A log for troubleshooting
@@ -86,7 +62,9 @@ HTMLArea._appendToLog = function(str){
                }
        }
 };
-
+/***************************************************
+ *  SCRIPTS LOADING PROCESS
+ ***************************************************/
 /*
  * Build stack of scripts to be loaded
  */
@@ -97,7 +75,7 @@ HTMLArea.loadScript = function(url, pluginName, asynchronous) {
        if (typeof(asynchronous) == "undefined") {
                var asynchronous = true;
        }
-       if (HTMLArea.is_opera) url = _typo3_host_url + url;
+       if (Ext.isOpera) url = _typo3_host_url + url;
        if (HTMLArea._compressedScripts && url.indexOf("compressed") == -1) url = url.replace(/\.js$/gi, "_compressed.js");
        var scriptInfo = {
                pluginName      : pluginName,
@@ -202,8 +180,6 @@ HTMLArea.init = function() {
                if (typeof(_editor_edited_content_CSS) != "string") _editor_edited_content_CSS = _editor_skin + "htmlarea-edited-content.css";
                if (typeof(_editor_lang) == "string") _editor_lang = _editor_lang ? _editor_lang.toLowerCase() : "en";
                HTMLArea.editorCSS = _editor_CSS;
-                       // Initialize event cache
-               HTMLArea._eventCache = HTMLArea._eventCacheConstructor();
                        // Initialize pending request flag
                HTMLArea.pendingSynchronousXMLHttpRequest = false;
                        // Set troubleshooting mode
@@ -220,8 +196,8 @@ HTMLArea.init = function() {
                HTMLArea._scripts = [];
                HTMLArea._scriptLoaded = [];
                HTMLArea._request = [];
-               if (HTMLArea.is_gecko) HTMLArea.loadScript(RTEarea[0]["htmlarea-gecko"] ? RTEarea[0]["htmlarea-gecko"] : _editor_url + "htmlarea-gecko.js");
-               if (HTMLArea.is_ie) HTMLArea.loadScript(RTEarea[0]["htmlarea-ie"] ? RTEarea[0]["htmlarea-ie"] : _editor_url + "htmlarea-ie.js");
+               if (!Ext.isIE) HTMLArea.loadScript(RTEarea[0]["htmlarea-gecko"] ? RTEarea[0]["htmlarea-gecko"] : _editor_url + "htmlarea-gecko.js");
+               if (Ext.isIE) HTMLArea.loadScript(RTEarea[0]["htmlarea-ie"] ? RTEarea[0]["htmlarea-ie"] : _editor_url + "htmlarea-ie.js");
                for (var i = 0, n = HTMLArea_plugins.length; i < n; i++) {
                        HTMLArea.loadScript(HTMLArea_plugins[i].url, "", HTMLArea_plugins[i].asynchronous);
                }
@@ -247,10 +223,10 @@ HTMLArea.init = function() {
                        if (success) {
                                HTMLArea.checkInitialLoad();
                        } else {
-                               if (HTMLArea.is_ie) window.setTimeout('alert(HTMLArea.I18N.msg["ActiveX-required"]);', 200);
+                               if (Ext.isIE) window.setTimeout('alert(HTMLArea.I18N.msg["ActiveX-required"]);', 200);
                        }
                } else {
-                       if (HTMLArea.is_ie) alert(HTMLArea.I18N.msg["ActiveX-required"]);
+                       if (Ext.isIE) alert(HTMLArea.I18N.msg["ActiveX-required"]);
                }
        }
 };
@@ -259,25 +235,17 @@ HTMLArea.init = function() {
  * Compile some regular expressions
  */
 HTMLArea.RE_tagName = /(<\/|<)\s*([^ \t\n>]+)/ig;
-HTMLArea.RE_doctype = /(<!doctype((.|\n)*?)>)\n?/i;
 HTMLArea.RE_head    = /<head>((.|\n)*?)<\/head>/i;
 HTMLArea.RE_body    = /<body>((.|\n)*?)<\/body>/i;
 HTMLArea.Reg_body = new RegExp("<\/?(body)[^>]*>", "gi");
 HTMLArea.reservedClassNames = /htmlarea/;
 HTMLArea.RE_email    = /([0-9a-z]+([a-z0-9_-]*[0-9a-z])*){1}(\.[0-9a-z]+([a-z0-9_-]*[0-9a-z])*)*@([0-9a-z]+([a-z0-9_-]*[0-9a-z])*\.)+[a-z]{2,9}/i;
-HTMLArea.RE_url      = /(https?:\/\/)?(([a-z0-9_]+:[a-z0-9_]+@)?[a-z0-9_-]{2,}(\.[a-z0-9_-]{2,})+\.[a-z]{2,5}(:[0-9]+)?(\/\S+)*)/i;
-
-/*
- * Editor configuration object constructor
- */
-
-HTMLArea.Config = function () {
-       this.width = "auto";
-       this.height = "auto";
-               // whether the toolbar should be included in the size or not.
-       this.sizeIncludesToolbar = true;
-               // if true then HTMLArea will retrieve the full HTML, starting with the <HTML> tag.
-       this.fullPage = false;
+HTMLArea.RE_url      = /(([^:/?#]+):\/\/)?(([a-z0-9_]+:[a-z0-9_]+@)?[a-z0-9_-]{2,}(\.[a-z0-9_-]{2,})+\.[a-z]{2,5}(:[0-9]+)?(\/\S+)*)/i;
+/***************************************************
+ *  EDITOR CONFIGURATION
+ ***************************************************/
+HTMLArea.Config = function (editorId) {
+       this.editorId = editorId;
                // if the site is secure, create a secure iframe
        this.useHTTPS = false;
                // for Mozilla
@@ -300,7 +268,9 @@ HTMLArea.Config = function () {
        this.customTags = null;
                // BaseURL included in the iframe document
        this.baseURL = document.baseURI || document.URL;
-       if(this.baseURL && this.baseURL.match(/(.*)\/([^\/]+)/)) this.baseURL = RegExp.$1 + "/";
+       if (this.baseURL && this.baseURL.match(/(.*)\/([^\/]+)/)) {
+               this.baseURL = RegExp.$1 + "/";
+       }
                // URL-s
        this.imgURL = "images/";
        this.popupURL = "popups/";
@@ -308,1089 +278,2038 @@ HTMLArea.Config = function () {
        this.documentType = '<!DOCTYPE html\r'
                        + '    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\r'
                        + '    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r';
-
-       this.btnList = {
-               InsertHorizontalRule:   ["Horizontal Rule", "ed_hr.gif",false, function(editor) {editor.execCommand("InsertHorizontalRule");}],
-               SelectAll:              ["SelectAll", "", true, function(editor) {editor.execCommand("SelectAll");}, null, true, false]
-       };
-               // Default hotkeys
-       this.hotKeyList = {
-               a:      { cmd:  "SelectAll",    action: null}
-       };
-
-               // Initialize tooltips from the I18N module, generate correct image path
-       for (var buttonId in this.btnList) {
-               if (this.btnList.hasOwnProperty(buttonId)) {
-                       var btn = this.btnList[buttonId];
-                       if (typeof(HTMLArea.I18N.tooltips[buttonId.toLowerCase()]) !== "undefined") {
-                               btn[0] = HTMLArea.I18N.tooltips[buttonId.toLowerCase()];
-                       }
-                       if (typeof(btn[1]) === "string") {
-                               btn[1] = _editor_skin + this.imgURL + btn[1];
-                       } else {
-                               btn[1][0] = _editor_skin + this.imgURL + btn[1][0];
-                       }
+       this.resizable = TYPO3.settings.textareaResize;
+       this.maxHeight = TYPO3.settings.textareaMaxHeight;
+               // Hold the configuration of buttons and hot keys registered by plugins
+       this.buttonsConfig = {};
+       this.hotKeyList = {};
+               // Default configurations for toolbar items
+       this.configDefaults = {
+               all: {
+                       xtype: 'htmlareabutton',
+                       disabledClass: 'buttonDisabled',
+                       textMode: false,
+                       selection: false,
+                       dialog: false,
+                       hidden: false,
+                       hideMode: 'display'
+               },
+               htmlareabutton: {
+                       cls: 'button',
+                       overCls: 'buttonHover'
+               },
+               htmlareacombo: {
+                       cls: 'select',
+                       typeAhead: true,
+                       triggerAction: 'all',
+                       editable: !Ext.isIE,
+                       validationEvent: false,
+                       validateOnBlur: false,
+                       submitValue: false,
+                       forceSelection: true,
+                       mode: 'local',
+                       storeFields: [ { name: 'text'}, { name: 'value'}],
+                       valueField: 'value',
+                       displayField: 'text',
+                       labelSeparator: '',
+                       hideLabel: true,
+                       tpl: '<tpl for="."><div ext:qtip="{value}" style="text-align:left;font-size:11px;" class="x-combo-list-item">{text}</div></tpl>'
                }
-       }
-       this.customSelects = {};
-};
-
-/*
- * Register a new button with the configuration.
- * It can be called with all arguments, or with only one (first one).  When called with
- * only one argument it must be an object with the following properties:
- * id, tooltip, image, textMode, action, context.  Examples:
- *
- * 1. config.registerButton("my-hilite", "Hilite text", "my-hilite.gif", false, function(editor) {...}, context);
- * 2. config.registerButton({
- *     id              : "my-hilite",          // Unique id for the button
- *     tooltip         : "Hilite text",        // the tooltip
- *     image           : "my-hilite.gif",      // image to be displayed in the toolbar
- *     textMode        : false,                // disabled in text mode
- *     action          : function(editor) {    // called when the button is clicked
- *                             editor.surroundHTML('<span class="hilite">', '</span>');
- *                             },
- *     context         : "p"                   // will be disabled if not inside a <p> element
- *     hide            : false                 // hide in menu and show only in context menu
- *     selection       : false                 // will be disabled if there is no selection
- *     dialog          : true                  // the button opens a dialogue
- *     dimensions      : { width: nn, height: mm } // opening dimensions of the dialogue window
- *    });
- */
-HTMLArea.Config.prototype.registerButton = function(id,tooltip,image,textMode,action,context,hide,selection, dialog, dimensions) {
-       var buttonId;
-       switch (typeof(id)) {
-               case "string": buttonId = id; break;
-               case "object": buttonId = id.id; break;
-               default: HTMLArea._appendToLog("[HTMLArea.Config::registerButton]: invalid arguments");
-                        return false;
-       }
-       if (typeof(this.customSelects[buttonId]) !== "undefined") {
-               HTMLArea._appendToLog("[HTMLArea.Config::registerButton]: A dropdown with the same Id: " + buttonId + " already exists.");
-               return false;
-       }
-       if (typeof(this.btnList[buttonId]) !== "undefined") {
-               HTMLArea._appendToLog("[HTMLArea.Config::registerButton]: A button with the same Id: " + buttonId + " already exists and will be overidden.");
-       }
-       switch (typeof(id)) {
-               case "string":
-                       if (typeof(hide) === "undefined") var hide = false;
-                       if (typeof(selection) === "undefined") var selection = false;
-                       if (typeof(dialog) === "undefined") var dialog = true;
-                       this.btnList[id] = [tooltip, image, textMode, action, context, hide, selection, dialog, dimensions];
-                       break;
-               case "object":
-                       if (typeof(id.hide) === "undefined") id.hide = false;
-                       if (typeof(id.selection) === "undefined") id.selection = false;
-                       if (typeof(id.dialog) === "undefined") id.dialog = true;
-                       this.btnList[id.id] = [id.tooltip, id.image, id.textMode, id.action, id.context, id.hide, id.selection, id.dialog, id.dimensions];
-                       break;
-       }
-       return true;
-};
-
-/*
- * Register a dropdown box with the editor configuration.
- */
-HTMLArea.Config.prototype.registerDropdown = function(dropDownConfiguration) {
-       if (typeof(this.customSelects[dropDownConfiguration.id]) != "undefined") {
-               HTMLArea._appendToLog("[HTMLArea.Config::registerDropdown]: A dropdown with the same ID " + dropDownConfiguration.id + " already exists and will be overidden.");
-       }
-       if (typeof(this.btnList[dropDownConfiguration.id]) != "undefined") {
-               HTMLArea._appendToLog("ERROR [HTMLArea.Config::registerDropdown]: A button with the same ID " + dropDownConfiguration.id + " already exists.");
-               return false;
-       }
-       this.customSelects[dropDownConfiguration.id] = dropDownConfiguration;
-       return true;
+       };
 };
-
-/*
- * Register a hotkey with the editor configuration.
- */
-HTMLArea.Config.prototype.registerHotKey = function(hotKeyConfiguration) {
-       if (typeof(this.hotKeyList[hotKeyConfiguration.id]) != "undefined") {
-               HTMLArea._appendToLog("[HTMLArea.Config::registerHotKey]: A hotkey with the same key " + hotKeyConfiguration.id + " already exists and will be overidden.");
+HTMLArea.Config = Ext.extend(HTMLArea.Config, {
+       /**
+        * Registers a button for inclusion in the toolbar, adding some standard configuration properties for the ExtJS widgets
+        *
+        * @param       object          buttonConfiguration: the configuration object of the button:
+        *                                      id              : unique id for the button
+        *                                      tooltip         : tooltip for the button
+        *                                      textMode        : enable in text mode
+        *                                      context         : disable if not inside one of listed elements
+        *                                      hidden          : hide in menu and show only in context menu
+        *                                      selection       : disable if there is no selection
+        *                                      hotkey          : hotkey character
+        *                                      dialog          : if true, the button opens a dialogue
+        *                                      dimensions      : the opening dimensions object of the dialogue window: { width: nn, height: mm }
+        *                                      and potentially other ExtJS config properties (will be forwarded)
+        *
+        * @return      boolean         true if the button was successfully registered
+        */
+       registerButton: function (config) {
+               config.itemId = config.id;
+               if (Ext.type(this.buttonsConfig[config.id])) {
+                       HTMLArea._appendToLog('[HTMLArea.Config::registerButton]: A toolbar item with the same Id: ' + config.id + ' already exists and will be overidden.');
+               }
+                       // Apply defaults
+               config = Ext.applyIf(config, this.configDefaults['all']);
+               config = Ext.applyIf(config, this.configDefaults[config.xtype]);
+                       // Set some additional properties
+               switch (config.xtype) {
+                       case 'htmlareacombo':
+                                       // Create combo store
+                               config.store = new Ext.data.ArrayStore({
+                                       autoDestroy:  true,
+                                       fields: config.storeFields,
+                                       data: config.options
+                               });
+                               config.hideLabel = Ext.isEmpty(config.fieldLabel);
+                               config.helpTitle = config.tooltip;
+                               break;
+                       default:
+                               config.iconCls = config.id;
+                               break;
+               }
+               config.cmd = config.id;
+               config.tooltip = { title: config.tooltip };
+               this.buttonsConfig[config.id] = config;
+               return true;
+       },
+       /*
+        * Register a hotkey with the editor configuration.
+        */
+       registerHotKey: function (hotKeyConfiguration) {
+               if (Ext.isDefined(this.hotKeyList[hotKeyConfiguration.id])) {
+                       HTMLArea._appendToLog('[HTMLArea.Config::registerHotKey]: A hotkey with the same key ' + hotKeyConfiguration.id + ' already exists and will be overidden.');
+               }
+               if (Ext.isDefined(hotKeyConfiguration.cmd) && !Ext.isEmpty(hotKeyConfiguration.cmd) && Ext.isDefined(this.buttonsConfig[hotKeyConfiguration.cmd])) {
+                       this.hotKeyList[hotKeyConfiguration.id] = hotKeyConfiguration;
+                       HTMLArea._appendToLog('[HTMLArea.Config::registerHotKey]: A hotkey with key ' + hotKeyConfiguration.id + ' was registered for toolbar item ' + hotKeyConfiguration.cmd + '.');
+                       return true;
+               } else {
+                       HTMLArea._appendToLog('[HTMLArea.Config::registerHotKey]: A hotkey with key ' + hotKeyConfiguration.id + ' could not be registered because toolbar item with id ' + hotKeyConfiguration.cmd + ' was not registered.');
+                       return false;
+               }
+       },
+       /*
+        * Get the configured document type for dialogue windows
+        */
+       getDocumentType: function () {
+               return this.documentType;
        }
-       this.hotKeyList[hotKeyConfiguration.id] = hotKeyConfiguration;
-       return true;
-};
-
-HTMLArea.Config.prototype.getDocumentType = function () {
-       return this.documentType;
-};
-
+});
 /***************************************************
- *  EDITOR FRAMEWORK
+ *  TOOLBAR COMPONENTS
  ***************************************************/
 /*
- * Update the state of a toolbar element.
- * This function is member of a toolbar element object, unnamed object created by createButton or createSelect functions.
+ * Ext.ux.HTMLAreaButton extends Ext.Button
  */
-HTMLArea.setButtonStatus = function(id,newval) {
-       var oldval = this[id];
-       var el = document.getElementById(this.elementId);
-       if (oldval != newval) {
-               switch (id) {
-                       case "enabled":
-                               if (newval) {
-                                       if (!HTMLArea.is_wamcom) {
-                                               HTMLArea._removeClass(el, "buttonDisabled");
-                                               HTMLArea._removeClass(el.parentNode, "buttonDisabled");
-                                       }
-                                       el.disabled = false;
-                               } else {
-                                       if (!HTMLArea.is_wamcom) {
-                                               HTMLArea._addClass(el, "buttonDisabled");
-                                               HTMLArea._addClass(el.parentNode, "buttonDisabled");
-                                       }
-                                       el.disabled = true;
-                               }
-                               break;
-                           case "active":
-                               if (newval) {
-                                       HTMLArea._addClass(el, "buttonPressed");
-                                       HTMLArea._addClass(el.parentNode, "buttonPressed");
-                                       el.active = true;
-                               } else {
-                                       HTMLArea._removeClass(el, "buttonPressed");
-                                       HTMLArea._removeClass(el.parentNode, "buttonPressed");
-                                       el.active = false;
+Ext.ux.HTMLAreaButton = Ext.extend(Ext.Button, {
+       /*
+        * Component initialization
+        */
+       initComponent: function () {
+               Ext.ux.HTMLAreaButton.superclass.initComponent.call(this);
+               this.addEvents(
+                       /*
+                        * @event hotkey
+                        * Fires when the button hotkey is pressed
+                        */
+                       'hotkey'
+               );
+               this.addListener({
+                       afterrender: {
+                               fn: this.initEventListeners,
+                               single: true
+                       }
+               });
+       },
+       /*
+        * Initialize listeners
+        */
+       initEventListeners: function () {
+               this.addListener({
+                       click: {
+                               fn: this.onButtonClick
+                       },
+                       hotkey: {
+                               fn: this.onHotKey
+                       }
+               });
+                       // Monitor toolbar updates in order to refresh the state of the button
+               this.mon(this.getToolbar(), 'update', this.onUpdateToolbar, this);
+       },
+       /*
+        * Get a reference to the editor
+        */
+       getEditor: function() {
+               return RTEarea[this.ownerCt.editorId].editor;
+       },
+       /*
+        * Get a reference to the toolbar
+        */
+       getToolbar: function() {
+               return this.ownerCt;
+       },
+       /*
+        * Add properties and function to set button active or not depending on current selection
+        */
+       inactive: true,
+       activeClass: 'buttonActive',
+       setInactive: function (inactive) {
+               this.inactive = inactive;
+               return inactive ? this.removeClass(this.activeClass) : this.addClass(this.activeClass);
+       },
+       /*
+        * Determine if the button should be enabled based on the current selection and context configuration property
+        */
+       isInContext: function (mode, selectionEmpty, ancestors) {
+               var editor = this.getEditor();
+               var inContext = true;
+               if (mode === 'wysiwyg' && this.context) {
+                       var attributes = [],
+                               contexts = [];
+                       if (/(.*)\[(.*?)\]/.test(this.context)) {
+                               contexts = RegExp.$1.split(',');
+                               attributes = RegExp.$2.split(',');
+                       } else {
+                               contexts = this.context.split(',');
+                       }
+                       contexts = new RegExp( '^(' + contexts.join('|') + ')$', 'i');
+                       var matchAny = contexts.test('*');
+                       Ext.each(ancestors, function (ancestor) {
+                               inContext = matchAny || contexts.test(ancestor.nodeName);
+                               if (inContext) {
+                                       Ext.each(attributes, function (attribute) {
+                                               inContext = eval("ancestor." + attribute);
+                                               return inContext;
+                                       });
                                }
-                               break;
+                               return !inContext;
+                       });
                }
-               this[id] = newval;
-       }
-};
-
-/*
- * Create a new line in the toolbar
- */
-HTMLArea.newLine = function(toolbar) {
-       tb_line = document.createElement("ul");
-       tb_line.className = "tb-line";
-       toolbar.appendChild(tb_line);
-       return tb_line;
-};
-
-/*
- * Add a toolbar element to the current line or group
- */
-HTMLArea.addTbElement = function(element, tb_line, first_cell_on_line) {
-       var tb_cell = document.createElement("li");
-       if (first_cell_on_line) tb_cell.className = "tb-first-cell";
-               else tb_cell.className = "tb-cell";
-       HTMLArea._addClass(tb_cell, element.className);
-       tb_line.appendChild(tb_cell);
-       tb_cell.appendChild(element);
-       if(element.style.display == "none") {
-               tb_cell.style.display = "none";
-               if(HTMLArea._hasClass(tb_cell.previousSibling, "separator")) tb_cell.previousSibling.style.display = "none";
-       }
-       return false;
-};
-
-/*
- * Create a new group on the current line
- */
-HTMLArea.addTbGroup = function(tb_line, first_cell_on_line) {
-       var tb_group = document.createElement("ul");
-       tb_group.className = "tb-group";
-       HTMLArea.addTbElement(tb_group, tb_line, first_cell_on_line);
-       return tb_group;
-};
-
-/*
- * Create a combo box and add it to the toolbar
- */
-HTMLArea.prototype.createSelect = function(txt,tb_line,first_cell_on_line,labelObj) {
-       var options = null,
-               cmd = null,
-               context = null,
-               tooltip = "",
-               newObj = {
-                       created : false,
-                       el : null,
-                       first : first_cell_on_line,
-                       labelUsed : false
-               };
-
-       cmd = txt;
-       var dropdown = this.config.customSelects[cmd];
-       if (typeof(dropdown) != "undefined") {
-               options = dropdown.options;
-               context = dropdown.context;
-               if (typeof(dropdown.tooltip) != "undefined") tooltip = dropdown.tooltip;
-       }
-       if (options) {
-               newObj["el"] = document.createElement("select");
-               newObj["el"].className = "select";
-               newObj["el"].title = tooltip;
-               newObj["el"].id = this._editorNumber + "-" + txt;
-               newObj["first"] = HTMLArea.addTbElement(newObj["el"], tb_line, first_cell_on_line);
-               var obj = {
-                       name            : txt,                          // field name
-                       elementId       : newObj["el"].id,              // unique id for the UI element
-                       enabled         : true,                         // is it enabled?
-                       text            : false,                        // enabled in text mode?
-                       cmd             : cmd,                          // command ID
-                       state           : HTMLArea.setButtonStatus,     // for changing state
-                       context         : context,
-                       editorNumber    : this._editorNumber
-               };
-               this._toolbarObjects[txt] = obj;
-               newObj["el"]._obj = obj;
-               if (labelObj["labelRef"]) {
-                       labelObj["el"].htmlFor = newObj["el"].id;
-                       newObj["labelUsed"] = true;
+               return inContext && (!this.selection || !selectionEmpty);
+       },
+       /*
+        * Handler invoked when the button is clicked
+        */
+       onButtonClick: function (button, event, key) {
+               if (!this.disabled) {
+                       if (!this.plugins[this.action](this.getEditor(), key || this.itemId) && event) {
+                               event.stopEvent();
+                       }
+                       if (Ext.isOpera) {
+                               this.getEditor().focus();
+                       }
+                       if (this.dialog) {
+                               this.setDisabled(true);
+                       } else {
+                               this.getToolbar().update();
+                       }
                }
-               HTMLArea._addEvent(newObj["el"], "change", HTMLArea.toolBarButtonHandler);
-
-               for (var i in options) {
-                       if (options.hasOwnProperty(i)) {
-                               var op = document.createElement("option");
-                               op.innerHTML = i;
-                               op.value = options[i];
-                               newObj["el"].appendChild(op);
+               return false;
+       },
+       /*
+        * Handler invoked when the hotkey configured for this button is pressed
+        */
+       onHotKey: function (key, event) {
+               return this.onButtonClick(this, event, key);
+       },
+       /*
+        * Handler invoked when the toolbar is updated
+        */
+       onUpdateToolbar: function (mode, selectionEmpty, ancestors, endPointsInSameBlock) {
+               this.setDisabled(mode === 'textmode' && !this.textMode);
+               if (!this.disabled) {
+                       if (!this.noAutoUpdate) {
+                               this.setDisabled(!this.isInContext(mode, selectionEmpty, ancestors));
                        }
+                       this.plugins['onUpdateToolbar'](this, mode, selectionEmpty, ancestors, endPointsInSameBlock);
                }
-
-               newObj["created"] = true;
-       }
-
-       return newObj;
-};
-
-/*
- * Create a button and add it to the toolbar
- */
-HTMLArea.prototype.createButton = function (txt,tb_line,first_cell_on_line,labelObj) {
-       var btn = null,
-               newObj = {
-                       created : false,
-                       el : null,
-                       first : first_cell_on_line,
-                       labelUsed : false
-               };
-
-       switch (txt) {
-               case "separator":
-                       newObj["el"] = document.createElement("div");
-                       newObj["el"].className = "separator";
-                       newObj["first"] = HTMLArea.addTbElement(newObj["el"], tb_line, first_cell_on_line);
-                       newObj["created"] = true;
-                       break;
-               case "space":
-                       newObj["el"] = document.createElement("div");
-                       newObj["el"].className = "space";
-                       newObj["el"].innerHTML = "&nbsp;";
-                       newObj["first"] = HTMLArea.addTbElement(newObj["el"], tb_line, first_cell_on_line);
-                       newObj["created"] = true;
-                       break;
-               case "TextIndicator":
-                       newObj["el"] = document.createElement("div");
-                       newObj["el"].appendChild(document.createTextNode("A"));
-                       newObj["el"].className = "indicator";
-                       newObj["el"].title = HTMLArea.I18N.tooltips.textindicator;
-                       newObj["el"].id = this._editorNumber + "-" + txt;
-                       newObj["first"] = HTMLArea.addTbElement(newObj["el"], tb_line, first_cell_on_line);
-                       var obj = {
-                               name            : txt,
-                               elementId       : newObj["el"].id,
-                               enabled         : true,
-                               active          : false,
-                               text            : false,
-                               cmd             : "TextIndicator",
-                               state           : HTMLArea.setButtonStatus
-                       };
-                       this._toolbarObjects[txt] = obj;
-                       newObj["created"] = true;
-                       break;
-               default:
-                       btn = this.config.btnList[txt];
-       }
-       if(!newObj["created"] && btn) {
-               newObj["el"] = document.createElement("button");
-               newObj["el"].title = btn[0];
-               newObj["el"].className = "button";
-               newObj["el"].id = this._editorNumber + "-" + txt;
-               if (btn[5]) newObj["el"].style.display = "none";
-               newObj["first"] = HTMLArea.addTbElement(newObj["el"], tb_line, first_cell_on_line);
-               var obj = {
-                       name            : txt,                          // the button name
-                       elementId       : newObj["el"].id,              // unique id for the UI element
-                       enabled         : true,                         // is it enabled?
-                       active          : false,                        // is it pressed?
-                       text            : btn[2],                       // enabled in text mode?
-                       cmd             : btn[3],                       // the function to be invoked
-                       state           : HTMLArea.setButtonStatus,     // for changing state
-                       context         : btn[4] || null,               // enabled in a certain context?
-                       selection       : btn[6],                       // disabled when no selection?
-                       editorNumber    : this._editorNumber
-               };
-               this._toolbarObjects[txt] = obj;
-               newObj["el"]._obj = obj;
-               if (labelObj["labelRef"]) {
-                       labelObj["el"].htmlFor = newObj["el"].id;
-                       newObj["labelUsed"] = true;
-               }
-               HTMLArea._addEvents(newObj["el"],["mouseover", "mouseout", "mousedown", "click"], HTMLArea.toolBarButtonHandler);
-               newObj["el"].className += " " + txt;
-               newObj["created"] = true;
-       }
-       return newObj;
-};
-
-/*
- * Create a label and add it to the toolbar
- */
-HTMLArea.createLabel = function(txt,tb_line,first_cell_on_line) {
-       var newObj = {
-               created : false,
-               el : null,
-               labelRef : false,
-               first : first_cell_on_line
-       };
-       if (/^([IT])\[(.*?)\]/.test(txt)) {
-               var l7ed = RegExp.$1 == "I"; // localized?
-               var label = RegExp.$2;
-               if (l7ed) label = HTMLArea.I18N.dialogs[label];
-               newObj["el"] = document.createElement("label");
-               newObj["el"].className = "label";
-               newObj["el"].innerHTML = label;
-               newObj["labelRef"] = true;
-               newObj["created"] = true;
-               newObj["first"] = HTMLArea.addTbElement(newObj["el"], tb_line, first_cell_on_line);
        }
-       return newObj;
-};
-
+});
+Ext.reg('htmlareabutton', Ext.ux.HTMLAreaButton);
 /*
- * Create the toolbar and append it to the _htmlarea.
+ * Ext.ux.Toolbar.HTMLAreaToolbarText extends Ext.Toolbar.TextItem
  */
-HTMLArea.prototype._createToolbar = function () {
-       var j, k, code, n = this.config.toolbar.length, m,
-               tb_line = null, tb_group = null,
-               first_cell_on_line = true,
-               labelObj = new Object(),
-               tbObj = new Object();
-
-       var toolbar = document.createElement("div");
-       this._toolbar = toolbar;
-       toolbar.className = "toolbar";
-       toolbar.unselectable = "1";
-       this._toolbarObjects = new Object();
-
-       for (j = 0; j < n; ++j) {
-               tb_line = HTMLArea.newLine(toolbar);
-               if(!this.config.keepButtonGroupTogether) HTMLArea._addClass(tb_line, "free-float");
-               first_cell_on_line = true;
-               tb_group = null;
-               var group = this.config.toolbar[j];
-               m = group.length;
-               for (k = 0; k < m; ++k) {
-                       code = group[k];
-                       if (code == "linebreak") {
-                               tb_line = HTMLArea.newLine(toolbar);
-                               if(!this.config.keepButtonGroupTogether) HTMLArea._addClass(tb_line, "free-float");
-                               first_cell_on_line = true;
-                               tb_group = null;
-                       } else {
-                               if ((code == "separator" || first_cell_on_line) && this.config.keepButtonGroupTogether) {
-                                       tb_group = HTMLArea.addTbGroup(tb_line, first_cell_on_line);
-                                       first_cell_on_line = false;
-                               }
-                               created = false;
-                               if (/^([IT])\[(.*?)\]/.test(code)) {
-                                       labelObj = HTMLArea.createLabel(code, (tb_group?tb_group:tb_line), first_cell_on_line);
-                                       created = labelObj["created"] ;
-                                       first_cell_on_line = labelObj["first"];
-                               }
-                               if (!created) {
-                                       tbObj = this.createButton(code, (tb_group?tb_group:tb_line), first_cell_on_line, labelObj);
-                                       created = tbObj["created"];
-                                       first_cell_on_line = tbObj["first"];
-                                       if(tbObj["labelUsed"]) labelObj["labelRef"] = false;
-                               }
-                               if (!created) {
-                                       tbObj = this.createSelect(code, (tb_group?tb_group:tb_line), first_cell_on_line, labelObj);
-                                       created = tbObj["created"];
-                                       first_cell_on_line = tbObj["first"];
-                                       if(tbObj["labelUsed"]) labelObj["labelRef"] = false;
-                               }
-                               if (!created) HTMLArea._appendToLog("ERROR [HTMLArea::createToolbar]: Unknown toolbar item: " + code);
+Ext.ux.Toolbar.HTMLAreaToolbarText = Ext.extend(Ext.Toolbar.TextItem, {
+       /*
+        * Constructor
+        */
+       initComponent: function () {
+               Ext.ux.Toolbar.HTMLAreaToolbarText.superclass.initComponent.call(this);
+               this.addListener({
+                       afterrender: {
+                               fn: this.initEventListeners,
+                               single: true
                        }
+               });
+       },
+       /*
+        * Initialize listeners
+        */
+       initEventListeners: function () {
+                       // Monitor toolbar updates in order to refresh the state of the button
+               this.mon(this.getToolbar(), 'update', this.onUpdateToolbar, this);
+       },
+       /*
+        * Get a reference to the editor
+        */
+       getEditor: function() {
+               return RTEarea[this.ownerCt.editorId].editor;
+       },
+       /*
+        * Get a reference to the toolbar
+        */
+       getToolbar: function() {
+               return this.ownerCt;
+       },
+       /*
+        * Handler invoked when the toolbar is updated
+        */
+       onUpdateToolbar: function (mode, selectionEmpty, ancestors, endPointsInSameBlock) {
+               this.setDisabled(mode === 'textmode' && !this.textMode);
+               if (!this.disabled) {
+                       this.plugins['onUpdateToolbar'](this, mode, selectionEmpty, ancestors, endPointsInSameBlock);
                }
        }
-
-       tb_line = HTMLArea.newLine(toolbar);
-       this._htmlArea.appendChild(toolbar);
-};
-
+});
+Ext.reg('htmlareatoolbartext', Ext.ux.Toolbar.HTMLAreaToolbarText);
 /*
- * Handle toolbar element events handler
+ * Ext.ux.form.HTMLAreaCombo extends Ext.form.ComboBox
  */
-HTMLArea.toolBarButtonHandler = function(ev) {
-       if(!ev) var ev = window.event;
-       var target = (ev.target) ? ev.target : ev.srcElement;
-       while (target.tagName.toLowerCase() == "img" || target.tagName.toLowerCase() == "div") target = target.parentNode;
-       var obj = target._obj;
-       var editorNumber = obj["editorNumber"];
-       var editor = RTEarea[editorNumber]["editor"];
-       if (obj.enabled) {
-               switch (ev.type) {
-                       case "mouseover":
-                               HTMLArea._addClass(target, "buttonHover");
-                               HTMLArea._addClass(target.parentNode, "buttonHover");
-                               break;
-                       case "mouseout":
-                               HTMLArea._removeClass(target, "buttonHover");
-                               HTMLArea._removeClass(target.parentNode, "buttonHover");
-                               HTMLArea._removeClass(target, "buttonActive");
-                               HTMLArea._removeClass(target.parentNode, "buttonActive");
-                               if (obj.active) {
-                                       HTMLArea._addClass(target, "buttonPressed");
-                                       HTMLArea._addClass(target.parentNode, "buttonPressed");
-                               }
-                               break;
-                       case "mousedown":
-                               HTMLArea._addClass(target, "buttonActive");
-                               HTMLArea._addClass(target.parentNode, "buttonActive");
-                               HTMLArea._removeClass(target, "buttonPressed");
-                               HTMLArea._removeClass(target.parentNode, "buttonPressed");
-                               HTMLArea._stopEvent(ev);
-                               break;
-                       case "click":
-                               HTMLArea._removeClass(target, "buttonActive");
-                               HTMLArea._removeClass(target.parentNode, "buttonActive");
-                               HTMLArea._removeClass(target, "buttonHover");
-                               HTMLArea._removeClass(target.parentNode, "buttonHover");
-                               obj.cmd(editor, obj.name);
-                               HTMLArea._stopEvent(ev);
-                               if (HTMLArea.is_opera) {
-                                       editor._iframe.focus();
-                               }
-                               if (!editor.config.btnList[obj.name][7]) {
-                                       editor.updateToolbar();
-                               }
-                               break;
-                       case "change":
-                               editor.focusEditor();
-                               var dropdown = editor.config.customSelects[obj.name];
-                               if (typeof(dropdown) !== "undefined") {
-                                       dropdown.action(editor, obj.name);
-                                       HTMLArea._stopEvent(ev);
-                                       if (HTMLArea.is_opera) {
-                                               editor._iframe.focus();
-                                       }
-                                       editor.updateToolbar();
-                               } else {
-                                       HTMLArea._appendToLog("ERROR [HTMLArea::toolBarButtonHandler]: Combo box " + obj.name + " not registered.");
+Ext.ux.form.HTMLAreaCombo = Ext.extend(Ext.form.ComboBox, {
+       /*
+        * Constructor
+        */
+       initComponent: function () {
+               Ext.ux.form.HTMLAreaCombo.superclass.initComponent.call(this);
+               this.addEvents(
+                       /*
+                        * @event hotkey
+                        * Fires when a hotkey configured for the combo is pressed
+                        */
+                       'hotkey'
+               );
+               this.addListener({
+                       afterrender: {
+                               fn: this.initEventListeners,
+                               single: true
+                       }
+               });
+       },
+       /*
+        * Initialize listeners
+        */
+       initEventListeners: function () {
+               this.addListener({
+                       select: {
+                               fn: this.onComboSelect
+                       },
+                       specialkey: {
+                               fn: this.onSpecialKey
+                       },
+                       hotkey: {
+                               fn: this.onHotKey
+                       }
+               });
+                       // Monitor toolbar updates in order to refresh the state of the combo
+               this.mon(this.getToolbar(), 'update', this.onUpdateToolbar, this);
+                       // Monitor framework becoming ready
+               if (Ext.isIE) {
+                       this.mon(this.getToolbar().ownerCt, 'frameworkready', this.onFrameworkReady, this);
+               }
+       },
+       /*
+        * Get a reference to the editor
+        */
+       getEditor: function() {
+               return RTEarea[this.ownerCt.editorId].editor;
+       },
+       /*
+        * Get a reference to the toolbar
+        */
+       getToolbar: function() {
+               return this.ownerCt;
+       },
+       /*
+        * Handler invoked when an item is selected in the dropdown list
+        */
+       onComboSelect: function (combo, record, index) {
+               if (!combo.disabled) {
+                       var editor = this.getEditor();
+                               // In IE, reclaim lost focus on the editor iframe and restore the bookmarked selection
+                       if (Ext.isIE) {
+                               editor.focus();
+                               if (!Ext.isEmpty(this.bookmark)) {
+                                       editor.selectRange(editor.moveToBookmark(this.bookmark));
+                                       this.bookmark = null;
                                }
+                       }
+                               // Invoke the plugin onChange handler
+                       this.plugins[this.action](editor, combo, record, index);
+                               // In IE, bookmark the updated selection as the editor will be loosing focus
+                       if (Ext.isIE) { 
+                               editor.focus();
+                               this.bookmark = editor.getBookmark(editor._createRange(editor._getSelection()));
+                               this.triggered = true;
+                       }
+                       if (Ext.isOpera) {
+                               editor.focus();
+                       }
+                       this.getToolbar().update();
+               }
+               return false;
+       },
+       /*
+        * Handler invoked when the trigger element is clicked
+        * In IE, need to reclaim lost focus for the editor in order to restore the selection
+        */
+       onTriggerClick: function () {
+               Ext.ux.form.HTMLAreaCombo.superclass.onTriggerClick.call(this);
+                       // In IE, avoid focus being stolen and selection being lost
+               if (Ext.isIE) {
+                       this.triggered = true;
+                       this.getEditor().focus();
+               }
+       },
+       /*
+        * Handler invoked when the list of options is clicked in
+        */
+       onViewClick: function (doFocus) {
+                       // Avoid stealing focus from the editor
+               Ext.ux.form.HTMLAreaCombo.superclass.onViewClick.call(this, false);
+       },
+       /*
+        * Handler invoked in IE when the mouse moves out of the editor iframe
+        */
+       saveSelection: function (event) {
+               var editor = this.getEditor();
+               if (editor.document.hasFocus()) {
+                       this.bookmark = editor.getBookmark(editor._createRange(editor._getSelection()));
+               }
+       },
+       /*
+        * Handler invoked in IE when the editor gets the focus back
+        */
+       restoreSelection: function (event) {
+               if (!Ext.isEmpty(this.bookmark) && this.triggered) {
+                       var editor = this.getEditor();
+                       editor.selectRange(editor.moveToBookmark(this.bookmark));
+                       this.triggered = false;
+               }
+       },
+       /*
+        * Handler invoked when the enter key is pressed while the combo has focus
+        */
+       onSpecialKey: function (combo, event) {
+               if (event.getKey() == event.ENTER) {
+                       event.stopEvent();
+                }
+               return false;
+       },
+       /*
+        * Handler invoked when a hot key configured for this dropdown list is pressed
+        */
+       onHotKey: function (key) {
+               if (!this.disabled) {
+                       this.plugins.onHotKey(this.getEditor(), key);
+                       if (Ext.isOpera) {
+                               this.getEditor().focus();
+                       }
+                       this.getToolbar().update();
+               }
+               return false;
+       },
+       /*
+        * Handler invoked when the toolbar is updated
+        */
+       onUpdateToolbar: function (mode, selectionEmpty, ancestors, endPointsInSameBlock) {
+               this.setDisabled(mode === 'textmode' && !this.textMode);
+               if (!this.disabled) {
+                       this.plugins['onUpdateToolbar'](this, mode, selectionEmpty, ancestors, endPointsInSameBlock);
                }
+       },
+       /*
+        * Special handling for combo stealing focus in IE
+        * The iframe must have been rendered
+        */
+       onFrameworkReady: function () {
+                       // Take a bookmark in case the editor looses focus by activation of this combo
+               this.mon(this.getEditor().iframe.getEl(), 'mouseleave', this.saveSelection, this);
+                       // Restore the selection if combo was triggered
+               this.mon(this.getEditor().iframe.getEl(), 'focus', this.restoreSelection, this);
        }
-};
-
+});
+Ext.reg('htmlareacombo', Ext.ux.form.HTMLAreaCombo);
+/***************************************************
+ *  EDITOR FRAMEWORK
+ ***************************************************/
 /*
- * Create the htmlArea iframe and replace the textarea with it.
+ * HTMLArea.Toolbar extends Ext.Container
  */
-HTMLArea.prototype.generate = function () {
-       var self = this;
-               // Get the textarea, hide it and make it resizable
-       this.textArea = Ext.get(this._textArea).setVisibilityMode(2).setVisible(false);
-       if (TYPO3.settings.textareaResize) {
-               this.textArea.addClass('resizable');
-               this.textAreaResizer = new Ext.Resizable(this.textArea, {
-                       minWidth:  300,
-                       minHeight: 200,
-                       maxHeight: TYPO3.settings.textareaMaxHeight,
-                       dynamic:   true
-               });
-               this.textAreaResizer.on('resize', function(ev) { self.resizeOnTextAreaChange(2); });
-       }
-
-               // Create the editor framework and insert it before the textarea
-       this.htmlArea = Ext.DomHelper.insertBefore(this.textArea, {
-               tag: 'div',
-               cls: 'htmlarea'
-       }, true).setWidth(this.textArea.getStyle('width'));
-       this._htmlArea = this.htmlArea.dom;
-
-               // If we have a form, on reset, re-initialize the HTMLArea content and update the toolbar
-       if (this.textArea.dom.form) {
-               var f = this.textArea.dom.form;
-               if (typeof(f.onreset) == "function") {
-                       var funcref = f.onreset;
-                       if (typeof(f.__msh_prevOnReset) == "undefined") f.__msh_prevOnReset = [];
-                       f.__msh_prevOnReset.push(funcref);
-               }
-               f._editorNumber = this._editorNumber;
-               HTMLArea._addEvent(f, "reset", HTMLArea.resetHandler);
-       }
-
-               // Create & append the toolbar
-       this._createToolbar();
-       HTMLArea._appendToLog("[HTMLArea::generate]: Toolbar successfully created.");
-
-               // Create the editor iframe and append it to the toolbar
-       this.iframe = Ext.DomHelper.append(this.htmlArea, {
-                       tag: 'iframe',
-                       cls: 'editorIframe',
-                       src: (HTMLArea.is_gecko && !HTMLArea.is_safari && !HTMLArea.is_opera) ? 'javascript:void(0);' : (HTMLArea.is_opera?_typo3_host_url:'') + _editor_url + 'popups/blank.html'
-       }, true);
-       if (!this.getPluginInstance('StatusBar')) {
-               this.iframe.addClass('noStatusBar');
-       }
-       this._iframe = this.iframe.dom;
-       HTMLArea._appendToLog("[HTMLArea::generate]: Editor iframe successfully created.");
-               // Make the editor framework resizable
-       if (TYPO3.settings.textareaResize) {
-               this.htmlArea.addClass('resizable');
-               var dimensions = this.getDimensions();
-               this.htmlAreaResizer = new Ext.Resizable(this.htmlArea, {
-                       maxHeight: parseInt(TYPO3.settings.textareaMaxHeight) + dimensions.toolbar.height + dimensions.statusbar.height,
-                       dynamic:   false
+HTMLArea.Toolbar = Ext.extend(Ext.Container, {
+       /*
+        * Constructor
+        */
+       initComponent: function () {
+               HTMLArea.Toolbar.superclass.initComponent.call(this);
+               this.addEvents(
+                       /*
+                        * @event update
+                        * Fires when the toolbar is updated
+                        */
+                       'update'
+               );
+                       // Build the deferred toolbar update task
+               this.updateLater = new Ext.util.DelayedTask(this.update, this);
+                       // Add the toolbar items
+               this.addItems();
+               this.addListener({
+                       afterrender: {
+                               fn: this.initEventListeners,
+                               single: true
+                       }
                });
-               this.htmlAreaResizer.on('resize', function(ev) { self.resizeOnHtmlAreaChange(2); });
-       }
-       if (HTMLArea.is_opera) {
-               this.iframe.on('load', function() { self.initIframe(); } , this);
-       } else {
-               this.initIframe();
-       }
-       return this;
-};
-
-/*
- * Resize the editor framework and the iframe when the textarea was resized
- */
-HTMLArea.prototype.resizeOnTextAreaChange = function(diff) {
-               // Set width first as it may change the height of the toolbar and of the statusbar
-       var width = this.textArea.getStyle('width');
-       if (width.indexOf('%') == -1) {
-               width = (parseInt(width) + diff) + 'px';
-       }
-       this.iframe.setStyle('width', HTMLArea.is_opera ? width : '100%');
-       this.htmlArea.setStyle('width', width);
-               // Set height
-       var dimensions = this.getDimensions();
-       var height = this.textArea.getStyle('height');
-       if (height.indexOf('%') == -1) {
-               height = (parseInt(height) + diff) + 'px';
-       }
-       this.iframe.setStyle('height', height);
-       this.htmlArea.setStyle('height', (dimensions.toolbar.height + dimensions.statusbar.height) + 'px');
-};
-
-/*
- * Resize the textarea and iframe when the htmlArea was resized
- */
-HTMLArea.prototype.resizeOnHtmlAreaChange = function(diff) {
-               // Set width first as it may change the height of the toolbar and of the statusbar
-       var width = this.htmlArea.getStyle('width');
-               // Do not shrink narrower than configured textarea
-       if (parseInt(width) < this.textAreaResizer.minWidth + diff) {
-               width = (this.textAreaResizer.minWidth + diff) + 'px';
-               this.htmlArea.setStyle('width', width);
-       }
-       if (width.indexOf('%') == -1) {
-               width = (parseInt(width) - diff) + 'px';
-       }
-       this.textArea.setStyle('width', width);
-               // Set height
-       var height = this.iframe.getStyle('height');
-       if (height.indexOf('%') == -1) {
-               var dimensions = this.getDimensions();
-               height = parseInt(this.htmlArea.getStyle('height')) - dimensions.toolbar.height - dimensions.statusbar.height;
-                       // Do not shrink shorter than configured textarea
-               if (height < this.textAreaResizer.minHeight + diff) {
-                       height = this.textAreaResizer.minHeight + diff;
-                       this.htmlArea.setStyle('height', (height + dimensions.toolbar.height + dimensions.statusbar.height) + 'px');
-               }
-               this.iframe.setStyle('height', height + 'px');
-               height = (height - diff) + 'px';
-       }
-       this.textArea.setStyle('height', height);
-};
-
-/*
- * Size the iframe according to user's prefs or initial textarea
- */
-HTMLArea.prototype.sizeIframe = function(diff) {
-               // Clone the array of nested tabs and inline levels instead of using a reference (this.accessParentElements will change the array):
-       var parentElements = (this.nested.sorted && this.nested.sorted.length ? [].concat(this.nested.sorted) : []);
-               // Walk through all nested tabs and inline levels to make a correct positioning:
-       var dimensions = this.accessParentElements(parentElements, 'this.getDimensions()');
-               // Set height
-       this.config.height = (this.config.height == "auto") ? this._textArea.style.height : this.config.height;
-       var iframeHeight = this.config.height;
-       var textareaHeight = this.config.height;
-       var htmlAreaHeight = this.config.height;
-       if (this.config.height.indexOf("%") == -1) {
-               iframeHeight = parseInt(iframeHeight) - diff;
-               if (this.config.sizeIncludesToolbar) {
-                       this._initialToolbarOffsetHeight = this._initialToolbarOffsetHeight ? this._initialToolbarOffsetHeight : dimensions.toolbar.height;
-                       iframeHeight -= dimensions.toolbar.height;
-                       iframeHeight -= dimensions.statusbar.height;
-               }
-               if (iframeHeight < 0) {
-                       iframeHeight = 0;
-               }
-               htmlAreaHeight = (iframeHeight + dimensions.toolbar.height + dimensions.statusbar.height) + 'px';
-               textareaHeight = (iframeHeight - 4);
-               if (textareaHeight < 0) {
-                       textareaHeight = 0;
-               }
-               iframeHeight += "px";
-               textareaHeight += "px";
-       }
-       this._iframe.style.height = iframeHeight;
-       this._textArea.style.height = textareaHeight;
-       this.htmlArea.setStyle('height', htmlAreaHeight);
-               // Set width
-       this.config.width = (this.config.width == "auto") ? this._textArea.style.width : this.config.width;
-       var textareaWidth = this.config.width;
-       var iframeWidth = this.config.width;
-       if (textareaWidth.indexOf("%") == -1) {
-               iframeWidth = parseInt(textareaWidth) + "px";
-               textareaWidth = parseInt(textareaWidth) - diff;
-               if (textareaWidth < 0) {
-                       textareaWidth = 0;
-               }
-               textareaWidth += "px";
-       }
-       this._iframe.style.width = "100%";
-       if (HTMLArea.is_opera) {
-               this._iframe.style.width = iframeWidth;
-       }
-       this._textArea.style.width = textareaWidth;
-};
-
-/*
- * Resize the iframes
- */
-HTMLArea.resizeIframes = function(ev) {
-       if (!ev) var ev = window.event;
-       HTMLArea._stopEvent(ev);
-       for (var editorNumber in RTEarea) {
-               if (RTEarea.hasOwnProperty(editorNumber)) {
-                       var editor = RTEarea[editorNumber].editor;
-                       if (editor) {
-                               editor.sizeIframe(2);
+       },
+       /*
+        * Initialize listeners
+        */
+       initEventListeners: function () {
+                       // Monitor editor becoming ready
+               this.mon(this.getEditor(), 'editorready', this.update, this, {single: true});
+       },
+       /*
+        * editorId should be set in config
+        */
+       editorId: null,
+       /*
+        * Get a reference to the editor
+        */
+       getEditor: function() {
+               return RTEarea[this.editorId].editor;
+       },
+       /*
+        * Create the toolbar items based on editor toolbar configuration
+        */
+       addItems: function () {
+               var editor = this.getEditor();
+                       // Walk through the editor toolbar configuration nested arrays: [ toolbar [ row [ group ] ] ]
+               var firstOnRow = true;
+               var firstInGroup = true;
+               Ext.each(editor.config.toolbar, function (row) {
+                       if (!firstOnRow) {
+                                       // If a visible item was added to the previous line
+                               this.add({
+                                       xtype: 'tbspacer',
+                                       cls: 'x-form-clear-left'
+                               });
                        }
+                       firstOnRow = true;
+                               // Add the groups
+                       Ext.each(row, function (group) {
+                                       // To do: this.config.keepButtonGroupTogether ...
+                               if (!firstOnRow && !firstInGroup) {
+                                               // If a visible item was added to the line
+                                       this.add({
+                                               xtype: 'tbseparator',
+                                               cls: 'separator'
+                                       });
+                               }
+                               firstInGroup = true;
+                                       // Add each item
+                               Ext.each(group, function (item) {
+                                       if (item == 'space') {
+                                               this.add({
+                                                       xtype: 'tbspacer',
+                                                       cls: 'space'
+                                               });
+                                       } else {
+                                                       // Get the item's config as registered by some plugin
+                                               var itemConfig = editor.config.buttonsConfig[item];
+                                               if (!Ext.isEmpty(itemConfig)) {
+                                                       itemConfig.id = this.editorId + '-' + itemConfig.id;
+                                                       this.add(itemConfig);
+                                                       firstInGroup = firstInGroup && itemConfig.hidden;
+                                                       firstOnRow = firstOnRow && firstInGroup;
+                                               }
+                                       }
+                                       return true;
+                               }, this);
+                               return true;
+                       }, this);
+                       return true;
+               }, this);
+               this.add({
+                       xtype: 'tbspacer',
+                       cls: 'x-form-clear-left'
+               });
+       },
+       /*
+        * Retrieve a toolbar item by itemId
+        */
+       getButton: function (buttonId) {
+               return this.find('itemId', buttonId)[0];
+       },
+       /*
+        * Update the state of the toolbar
+        */
+       update: function() {
+               var editor = this.getEditor(),
+                       mode = editor.getMode(),
+                       selectionEmpty = true,
+                       ancestors = null,
+                       endPointsInSameBlock = true;
+               if (editor.getMode() === 'wysiwyg') {
+                       selectionEmpty = editor._selectionEmpty(editor._getSelection());
+                       ancestors = editor.getAllAncestors();
+                       endPointsInSameBlock = editor.endPointsInSameBlock();
                }
+               this.fireEvent('update', mode, selectionEmpty, ancestors, endPointsInSameBlock);
        }
-};
-
-/**
- * Get the dimensions of the toolbar and statusbar.
- *
- * @return     object          An object with width/height pairs for statusbar and toolbar.
- * @author     Oliver Hader <oh@inpublica.de>
- */
-HTMLArea.prototype.getDimensions = function() {
-       return {
-               toolbar: {width: this._toolbar.offsetWidth, height: this._toolbar.offsetHeight},
-               statusbar: {width: ((this.getPluginInstance("StatusBar") && this.getPluginInstance("StatusBar").statusBar) ? this.getPluginInstance("StatusBar").statusBar.offsetWidth : 0), height: ((this.getPluginInstance("StatusBar") && this.getPluginInstance("StatusBar").statusBar) ? this.getPluginInstance("StatusBar").statusBar.offsetHeight : 0)}
-       };
-};
-
-/**
- * Access an inline relational element or tab menu and make it "accessible".
- * If a parent object has the style "display: none", offsetWidth & offsetHeight are '0'.
- *
- * @params     object          callbackFunc: A function to be called, when the embedded objects are "accessible".
- * @return     object          An object returned by the callbackFunc.
- * @author     Oliver Hader <oh@inpublica.de>
+});
+Ext.reg('htmlareatoolbar', HTMLArea.Toolbar);
+/*
+ * HTMLArea.Iframe extends Ext.BoxComponent
  */
-HTMLArea.prototype.accessParentElements = function(parentElements, callbackFunc) {
-       var result = {};
-
-       if (parentElements.length) {
-               var currentElement = parentElements.pop();
-               var elementStyle = document.getElementById(currentElement).style;
-               var actionRequired = (elementStyle.display == 'none' ? true : false);
-
-               if (actionRequired) {
-                       var originalVisibility = elementStyle.visibility;
-                       var originalPosition = elementStyle.position;
-                       elementStyle.visibility = 'hidden';
-                       elementStyle.position = 'absolute';
-                       elementStyle.display = '';
+HTMLArea.Iframe = Ext.extend(Ext.BoxComponent, {
+       /*
+        * Constructor
+        */
+       initComponent: function () {
+               HTMLArea.Iframe.superclass.initComponent.call(this);
+               this.addEvents(
+                       /*
+                        * @event iframeready
+                        * Fires when the iframe style sheets become accessible
+                        */
+                       'iframeready'
+               );
+               this.addListener({
+                       afterrender: {
+                               fn: this.initEventListeners,
+                               single: true
+                       },
+                       beforeDestroy: {
+                               fn: this.onBeforeDestroy,
+                               single: true
+                       }
+               });
+               this.config = this.getEditor().config;
+               if (!this.config.showStatusBar) {
+                       this.addClass('noStatusBar');
                }
-
-               result = this.accessParentElements(parentElements, callbackFunc);
-
-               if (actionRequired) {
-                       elementStyle.display = 'none';
-                       elementStyle.position = originalPosition;
-                       elementStyle.visibility = originalVisibility;
+       },
+       /*
+        * Initialize event listeners and the document after the iframe has rendered
+        */
+       initEventListeners: function () {
+                       // The editor iframe may become hidden with style.display = "none"
+                       // This breaks the editor in Firefox: the designMode attribute needs to be reset after the style.display of the containing div is reset to "block"
+               if (Ext.isGecko && this.isNested) {
+                       Ext.each(this.nestedParentElements.sorted, function (nested) {
+                               this.mon(Ext.get(nested), 'DOMAttrModified', this.onNestedShow, this, {delay: 100});
+                       }, this);
                }
-
-       } else {
-               result = eval(callbackFunc);
-
-       }
-
-       return result;
-};
-
-/**
- * Simplify the array of nested levels. Create an indexed array with the correct names of the elements.
- *
- * @param      object          nested: The array with the nested levels
- * @return     object          The simplified array
- * @author     Oliver Hader <oh@inpublica.de>
- */
-HTMLArea.simplifyNested = function(nested) {
-       var i, type, level, max, simplifiedNested=[];
-       if (nested && nested.length) {
-               if (nested[0][0]=='inline') {
-                       nested = inline.findContinuedNestedLevel(nested, nested[0][1]);
+               if (Ext.isOpera) {
+                       this.mon(this.getEl(), 'load', this.initializeIframe , this, {single: true});
+               } else {
+                       this.initializeIframe();
                }
-               for (i=0, max=nested.length; i<max; i++) {
-                       type = nested[i][0];
-                       level = nested[i][1];
-                       if (type=='tab') {
-                               simplifiedNested.push(level+'-DIV');
-                       } else if (type=='inline') {
-                               simplifiedNested.push(level+'_fields');
+       },
+       /*
+        * editorId should be set in config
+        */
+       editorId: null,
+       /*
+        * Get a reference to the editor
+        */
+       getEditor: function() {
+               return RTEarea[this.editorId].editor;
+       },
+       /*
+        * Get a reference to the toolbar
+        */
+       getToolbar: function () {
+               return this.ownerCt.getTopToolbar();
+       },
+       /*
+        * Get a reference to a button
+        */
+       getButton: function (buttonId) {
+               return this.getToolbar().getButton(buttonId);
+       },
+       /*
+        * Flag set to true when the iframe becomes usable for editing
+        */
+       ready: false,
+       /*
+        * Create the iframe element at rendering time
+        */
+       onRender: function (ct, position){
+                       // from Ext.Component
+               if (!this.el && this.autoEl) {
+                       if (Ext.isString(this.autoEl)) {
+                               this.el = document.createElement(this.autoEl);
+                       } else {
+                                       // ExtJS Default method will not work with iframe element
+                               this.el = Ext.DomHelper.append(ct, this.autoEl, true);
+                       }
+                       if (!this.el.id) {
+                               this.el.id = this.getId();
                        }
                }
-       }
-       return simplifiedNested;
-};
-
-/*
- * Initialize the iframe
- */
-HTMLArea.initIframe = function(editorNumber) {
-       var editor = RTEarea[editorNumber]["editor"];
-       editor.initIframe();
-};
-
-HTMLArea.prototype.initIframe = function() {
-       if (this._initIframeTimer) window.clearTimeout(this._initIframeTimer);
-       if (!this._iframe || (!this._iframe.contentWindow && !this._iframe.contentDocument)) {
-               this._initIframeTimer = window.setTimeout("HTMLArea.initIframe(\'" + this._editorNumber + "\');", 50);
-               return false;
-       } else if (this._iframe.contentWindow && !HTMLArea.is_safari) {
-               if (!this._iframe.contentWindow.document || !this._iframe.contentWindow.document.documentElement) {
-                       this._initIframeTimer = window.setTimeout("HTMLArea.initIframe(\'" + this._editorNumber + "\');", 50);
-                       return false;
+                       // from Ext.BoxComponent
+               if (this.resizeEl){
+                       this.resizeEl = Ext.get(this.resizeEl);
                }
-       } else if (!this._iframe.contentDocument.documentElement || !this._iframe.contentDocument.body) {
-               this._initIframeTimer = window.setTimeout("HTMLArea.initIframe(\'" + this._editorNumber + "\');", 50);
-               return false;
-       }
-       var doc = this._iframe.contentWindow ? this._iframe.contentWindow.document : this._iframe.contentDocument;
-       this._doc = doc;
-               // Set Doc Type in Firefox (doctype is readonly in DOM 2)
-               // After adding doctype in Firefox, baseURL is set to the url of the parent document,
-               // base element is ignored, and all created links, including external, are prepended with incorrect base
-       /*if (HTMLArea.is_gecko && !HTMLArea.is_safari && !HTMLArea.is_opera) {
-               this._doc.open();
-               this._doc.write(this.config.getDocumentType());
-               this._doc.close();
-       }*/
-       if (!this.config.fullPage) {
-               var head = doc.getElementsByTagName("head")[0];
+               if (this.positionEl){
+                       this.positionEl = Ext.get(this.positionEl);
+               }
+       },
+       /*
+        * Proceed to build the iframe document head and ensure style sheets are available after the iframe document becomes available
+        */
+       initializeIframe: function () {
+               var iframe = this.getEl().dom;
+                       // All browsers
+               if (!iframe || (!iframe.contentWindow && !iframe.contentDocument)) {
+                       this.initializeIframe.defer(50, this);
+                       // All except Safari
+               } else if (iframe.contentWindow && !Ext.isWebKit && (!iframe.contentWindow.document || !iframe.contentWindow.document.documentElement)) {
+                       this.initializeIframe.defer(50, this);
+                       // Safari
+               } else if (!iframe.contentDocument.documentElement || !iframe.contentDocument.body) {
+                       this.initializeIframe.defer(50, this);
+               } else {
+                       this.document = iframe.contentWindow ? iframe.contentWindow.document : iframe.contentDocument;
+                       this.getEditor().document = this.document;
+                       this.getEditor()._doc = this.document;
+                       this.getEditor()._iframe = iframe;
+                       this.createHead();
+                       this.getStyleSheets();
+               }
+       },
+       /*
+        * Build the iframe document head
+        */
+       createHead: function () {
+               var head = this.document.getElementsByTagName('head')[0];
                if (!head) {
-                       head = doc.createElement("head");
-                       doc.documentElement.appendChild(head);
+                       head = this.document.createElement('head');
+                       this.document.documentElement.appendChild(head);
                }
-               if (this.config.baseURL && !HTMLArea.is_opera) {
-                       var base = doc.getElementsByTagName("base")[0];
+               if (this.config.baseURL && !Ext.isOpera) {
+                       var base = this.document.getElementsByTagName('base')[0];
                        if (!base) {
-                               base = doc.createElement("base");
+                               base = this.document.createElement('base');
                                base.href = this.config.baseURL;
                                head.appendChild(base);
                        }
-                       HTMLArea._appendToLog("[HTMLArea::initIframe]: Iframe baseURL set to: " + this.config.baseURL);
+                       HTMLArea._appendToLog('[HTMLArea.Iframe::createHead]: Iframe baseURL set to: ' + this.config.baseURL);
                }
-               var link0 = doc.getElementsByTagName("link")[0];
+               var link0 = this.document.getElementsByTagName('link')[0];
                if (!link0) {
-                       link0 = doc.createElement("link");
-                       link0.rel = "stylesheet";
+                       link0 = this.document.createElement('link');
+                       link0.rel = 'stylesheet';
                        link0.href = this.config.editedContentStyle;
                        head.appendChild(link0);
-                       HTMLArea._appendToLog("[HTMLArea::initIframe]: Skin CSS set to: " + this.config.editedContentStyle);
+                       HTMLArea._appendToLog('[HTMLArea.Iframe::createHead]: Skin CSS set to: ' + this.config.editedContentStyle);
                }
                if (this.config.defaultPageStyle) {
-                       var link = doc.getElementsByTagName("link")[1];
+                       var link = this.document.getElementsByTagName('link')[1];
                        if (!link) {
-                               link = doc.createElement("link");
-                               link.rel = "stylesheet";
+                               link = this.document.createElement('link');
+                               link.rel = 'stylesheet';
                                link.href = this.config.defaultPageStyle;
                                head.appendChild(link);
                        }
-                       HTMLArea._appendToLog("[HTMLArea::initIframe]: Override CSS set to: " + this.config.defaultPageStyle);
+                       HTMLArea._appendToLog('[HTMLArea.Iframe::createHead]: Override CSS set to: ' + this.config.defaultPageStyle);
                }
                if (this.config.pageStyle) {
-                       var link = doc.getElementsByTagName("link")[2];
+                       var link = this.document.getElementsByTagName('link')[2];
                        if (!link) {
-                               link = doc.createElement("link");
-                               link.rel = "stylesheet";
+                               link = this.document.createElement('link');
+                               link.rel = 'stylesheet';
                                link.href = this.config.pageStyle;
                                head.appendChild(link);
                        }
-                       HTMLArea._appendToLog("[HTMLArea::initIframe]: Content CSS set to: " + this.config.pageStyle);
+                       HTMLArea._appendToLog('[HTMLArea.Iframe::createHead]: Content CSS set to: ' + this.config.pageStyle);
                }
-       } else {
-               var html = this._textArea.value;
-               this.setFullHTML(html);
-       }
-       HTMLArea._appendToLog("[HTMLArea::initIframe]: Editor iframe head successfully initialized.");
-
-       this.stylesLoaded();
-};
-
-/*
- * Finalize editor Iframe initialization after loading the style sheets
- */
-HTMLArea.stylesLoaded = function(editorNumber) {
-       var editor = RTEarea[editorNumber]["editor"];
-       editor.stylesLoaded();
-};
-
-HTMLArea.prototype.stylesLoaded = function() {
-       var doc = this._doc;
-
-               // check if the stylesheets have been loaded
-       if (this._stylesLoadedTimer) window.clearTimeout(this._stylesLoadedTimer);
-       var stylesAreLoaded = true;
-       var errorText = '';
-       var rules;
-       if (HTMLArea.is_opera) {
-               if (doc.readyState != "complete") {
-                       stylesAreLoaded = false;
-                       errorText = "Stylesheets not yet loaded";
+               HTMLArea._appendToLog('[HTMLArea.Iframe::createHead]: Editor iframe document head successfully built.');
+       },
+       /*
+        * Fire event 'iframeready' when the iframe style sheets become accessible
+        */
+       getStyleSheets: function () {
+               var stylesAreLoaded = true;
+               var errorText = '';
+               var rules;
+               if (Ext.isOpera) {
+                       if (this.document.readyState != 'complete') {
+                               stylesAreLoaded = false;
+                               errorText = 'Stylesheets not yet loaded';
+                       }
+               } else {
+                       Ext.each(this.document.styleSheets, function (styleSheet) {
+                               if (!Ext.isIE) try { rules = styleSheet.cssRules; } catch(e) { stylesAreLoaded = false; errorText = e; }
+                               if (Ext.isIE) try { rules = styleSheet.rules; } catch(e) { stylesAreLoaded = false; errorText = e; }
+                               if (Ext.isIE) try { rules = styleSheet.imports; } catch(e) { stylesAreLoaded = false; errorText = e; }
+                       });
                }
-       } else {
-               for (var rule = 0; rule < doc.styleSheets.length; rule++) {
-                       if (HTMLArea.is_gecko) try { rules = doc.styleSheets[rule].cssRules; } catch(e) { stylesAreLoaded = false; errorText = e; }
-                       if (HTMLArea.is_ie) try { rules = doc.styleSheets[rule].rules; } catch(e) { stylesAreLoaded = false; errorText = e; }
-                       if (HTMLArea.is_ie) try { rules = doc.styleSheets[rule].imports; } catch(e) { stylesAreLoaded = false; errorText = e; }
+               if (!stylesAreLoaded) {
+                       this.getStyleSheets.defer(100, this);
+                       HTMLArea._appendToLog('[HTMLArea.Iframe::getStyleSheets]: Stylesheets not yet loaded (' + errorText + '). Retrying...');
+               } else {
+                       HTMLArea._appendToLog('[HTMLArea.Iframe::getStyleSheets]: Stylesheets successfully accessed.');
+                               // Style the document body
+                       Ext.get(this.document.body).addClass('htmlarea-content-body');
+                               // Start listening to things happening in the iframe
+                               // For some unknown reason, this is too early for Opera
+                       if (!Ext.isOpera) {
+                               this.startListening();
+                       }
+                               // Hide the iframe
+                       this.hide();
+                               // Set iframe ready
+                       this.ready = true;
+                       this.fireEvent('iframeready');
                }
-       }
-       if (!stylesAreLoaded && !HTMLArea.is_wamcom) {
-               HTMLArea._appendToLog("[HTMLArea::initIframe]: Failed attempt at loading stylesheets: " + errorText + " Retrying...");
-               this._stylesLoadedTimer = window.setTimeout("HTMLArea.stylesLoaded(\'" + this._editorNumber + "\');", 100);
-               return false;
-       }
-       HTMLArea._appendToLog("[HTMLArea::initIframe]: Stylesheets successfully loaded.");
-
-       doc.body.style.borderWidth = "0px";
-       doc.body.className = "htmlarea-content-body";
-
-               // Initialize editor mode
-       if (!this.getPluginInstance("EditorMode").init()) {
-               return false;
-       }
-
-               // set editor number in iframe and document for retrieval in event handlers
-       doc._editorNo = this._editorNumber;
-       if (HTMLArea.is_ie) doc.documentElement._editorNo = this._editorNumber;
-
-               // intercept events for updating the toolbar & for keyboard handlers
-       HTMLArea._addEvents((HTMLArea.is_ie ? doc.body : doc), ["keydown","keypress","mousedown","mouseup","drag"], HTMLArea._editorEvent, true);
-
-       HTMLArea._addEvent(window, "resize", HTMLArea.resizeIframes);
-
-               // add unload handler
-       if (!HTMLArea.hasUnloadHandler) {
-               HTMLArea.hasUnloadHandler = true;
-               HTMLArea._addEvent((this._iframe.contentWindow ? this._iframe.contentWindow : this._iframe.contentDocument), "unload", HTMLArea.removeEditorEvents);
-       }
-
-       window.setTimeout("HTMLArea.generatePlugins(\'" + this._editorNumber + "\');", 100);
-};
-
-HTMLArea.generatePlugins = function(editorNumber) {
-       var editor = RTEarea[editorNumber]["editor"];
-               // check if any plugins have registered generate handlers
-               // check also if any plugin has a onKeyPress handler
-       editor._hasPluginWithOnKeyPressHandler = false;
-       for (var pluginId in editor.plugins) {
-               if (editor.plugins.hasOwnProperty(pluginId)) {
-                       var pluginInstance = editor.plugins[pluginId].instance;
-                       if (typeof(pluginInstance.onGenerate) === "function") {
-                               pluginInstance.onGenerate();
+       },
+       /*
+        * Focus on the iframe
+        */
+       focus: function () {
+               try {
+                       if (Ext.isWebKit) {
+                               this.getEl().dom.focus();
+                       } else {
+                               this.getEl().dom.contentWindow.focus();
+                       }
+               } catch(e) { }
+       },
+       /*
+        * Flag indicating whether the framework is inside a tab or inline element that may be hidden
+        * Should be set in config
+        */
+       isNested: false,
+       /*
+        * All nested tabs and inline levels in the sorting order they were applied
+        * Should be set in config
+        */
+       nestedParentElements: {},
+       /*
+        * Set designMode
+        *
+        * @param       boolean         on: if true set designMode to on, otherwise set to off
+        *
+        * @rturn       void
+        */
+       setDesignMode: function (on) {
+               if (on) {
+                       if (!Ext.isIE) {
+                               if (Ext.isGecko) {
+                                               // In Firefox, we can't set designMode when we are in a hidden TYPO3 tab or inline element
+                                       if (!this.isNested || HTMLArea.util.TYPO3.allElementsAreDisplayed(this.nestedParentElements.sorted)) {
+                                               this.document.designMode = 'on';
+                                               this.setOptions();
+                                       }
+                               } else {
+                                       this.document.designMode = 'on';
+                                       this.setOptions();
+                               }
                        }
-                       if (typeof(pluginInstance.onGenerateOnce) === "function") {
-                               pluginInstance.onGenerateOnce();
-                               pluginInstance.onGenerateOnce = null;
+                       if (Ext.isIE || Ext.isWebKit) {
+                               this.document.body.contentEditable = true;
                        }
-                       if (typeof(pluginInstance.onKeyPress) === "function") {
-                               editor._hasPluginWithOnKeyPressHandler = true;
+               } else {
+                       if (!Ext.isIE) {
+                               this.document.designMode = 'off';
+                       }
+                       if (Ext.isIE || Ext.isWebKit) {
+                               this.document.body.contentEditable = false;
+                       }
+               }
+       },
+       /*
+        * Set editing mode options (if we can... raises exception in Firefox 3)
+        *
+        * @return      void
+        */
+       setOptions: function () {
+               if (!Ext.isIE) {
+                       try {
+                               if (this.document.queryCommandEnabled('insertbronreturn')) {
+                                       this.document.execCommand('insertbronreturn', false, this.config.disableEnterParagraphs);
+                               }
+                               if (this.document.queryCommandEnabled('styleWithCSS')) {
+                                       this.document.execCommand('styleWithCSS', false, this.config.useCSS);
+                               } else if (Ext.isGecko && this.document.queryCommandEnabled('useCSS')) {
+                                       this.document.execCommand('useCSS', false, !this.config.useCSS);
+                               }
+                               if (Ext.isGecko) {
+                                       if (this.document.queryCommandEnabled('enableObjectResizing')) {
+                                               this.document.execCommand('enableObjectResizing', false, !this.config.disableObjectResizing);
+                                       }
+                                       if (this.document.queryCommandEnabled('enableInlineTableEditing')) {
+                                               this.document.execCommand('enableInlineTableEditing', false, (this.config.buttons.table && this.config.buttons.table.enableHandles) ? true : false);
+                                       }
+                               }
+                       } catch(e) {}
+               }
+       },
+       /*
+        * Handler invoked when an hidden TYPO3 hidden nested tab or inline element is shown
+        */
+       onNestedShow: function (event, target) {
+               var styleEvent = true;
+                       // In older versions of Mozilla ev.attrName is not yet set and refering to it causes a non-catchable crash
+                       // We are assuming that this was fixed in Firefox 2.0.0.11
+               if (navigator.productSub > 20071127) {
+                       styleEvent = (event.browserEvent.attrName == 'style');
+               }
+               if (styleEvent && this.nestedParentElements.sorted.indexOf(target.id) != -1 && this.getEditor().getMode() === 'wysiwyg' && (target.style.display == '' || target.style.display == 'block')) {
+                               // Check if all affected nested elements are displayed (style.display!='none'):
+                       if (HTMLArea.util.TYPO3.allElementsAreDisplayed(this.nestedParentElements.sorted)) {
+                               this.setDesignMode(true);
+                               this.getEditor().updateToolbar();
                        }
                }
-       }
-       if (typeof(editor.onGenerate) === "function") {
-               editor.onGenerate();
-               editor.onGenerate = null;
-       }
-       HTMLArea._appendToLog("[HTMLArea::initIframe]: All plugins successfully generated.");
-               // Size the iframe
-       editor.sizeIframe(2);
-               // Focus on the first editor instance
-       for (var editorId in RTEarea) {
-               if (RTEarea.hasOwnProperty(editorId)) {
-                       if (RTEarea[editorId].editor) {
-                               if (editorNumber == editorId) {
-                                       editor.focusEditor();
+               event.stopEvent();
+       },
+       /*
+        * Get the HTML content of the iframe
+        */
+       getHTML: function () {
+               return HTMLArea.getHTML(this.document.body, false, this.getEditor());
+       },
+       /*
+        * Start listening to things happening in the iframe
+        */
+       startListening: function () {
+               var documentElement = Ext.get(Ext.isIE ? this.document.body : this.document.documentElement);
+                       // Create keyMap so that plugins may bind key handlers
+               this.keyMap = new Ext.KeyMap(documentElement, [], (Ext.isIE || Ext.isWebKit) ? 'keydown' : 'keypress');
+                       // Special keys map
+               this.keyMap.addBinding([
+                       {
+                               key: [Ext.EventObject.DOWN, Ext.EventObject.UP, Ext.EventObject.LEFT, Ext.EventObject.RIGHT],
+                               alt: false,
+                               handler: this.onArrow,
+                               scope: this
+                       },
+                       {
+                               key: Ext.EventObject.TAB,
+                               ctrl: false,
+                               alt: false,
+                               handler: this.onTab,
+                               scope: this
+                       },
+                       {
+                               key: Ext.EventObject.SPACE,
+                               ctrl: true,
+                               shift: false,
+                               alt: false,
+                               handler: this.onCtrlSpace,
+                               scope: this
+                       }
+               ]);
+               if (Ext.isGecko || Ext.isIE) {
+                       this.keyMap.addBinding(
+                       {
+                               key: [Ext.EventObject.BACKSPACE, Ext.EventObject.DELETE],
+                               alt: false,
+                               handler: this.onBackSpace,
+                               scope: this
+                       });
+               }
+               if (!Ext.isIE && !this.config.disableEnterParagraphs) {
+                       this.keyMap.addBinding(
+                       {
+                               key: Ext.EventObject.ENTER,
+                               shift: false,
+                               handler: this.onEnter,
+                               scope: this
+                       });
+               }
+               if (Ext.isWebKit) {
+                       this.keyMap.addBinding(
+                       {
+                               key: Ext.EventObject.ENTER,
+                               alt: false,
+                               handler: this.onWebKitEnter,
+                               scope: this
+                       });
+               }
+                       // Hot key map (on keydown for all brwosers)
+               var hotKeys = '';
+               Ext.iterate(this.config.hotKeyList, function (key) {
+                       if (key.length == 1) {
+                               hotKeys += key.toUpperCase();
+                       }
+               });
+               if (!Ext.isEmpty(hotKeys)) {
+                       this.hotKeyMap = new Ext.KeyMap(documentElement,
+                       {
+                               key: hotKeys,
+                               ctrl: true,
+                               shift: false,
+                               alt: false,
+                               handler: this.onHotKey,
+                               scope: this
+                       });
+               }
+               this.mon(documentElement, (Ext.isIE || Ext.isWebKit) ? 'keydown' : 'keypress', this.onAnyKey, this);
+               this.mon(documentElement, 'mouseup', this.onMouse, this);
+               this.mon(documentElement, 'click', this.onMouse, this);
+               this.mon(documentElement, 'drag', this.onMouse, this);
+       },
+       /*
+        * Handler for other key events
+        */
+       onAnyKey: function(event) {
+                       // In Opera, inhibit key events while synchronous XMLHttpRequest is being processed
+               if (Ext.isOpera && HTMLArea.pendingSynchronousXMLHttpRequest) {
+                       event.stopEvent();
+                       return false;
+               }
+                       // onKeyPress deprecated as of TYPO3 4.4
+               if (this.getEditor().hasPluginWithOnKeyPressHandler) {
+                       var letBubble = true;
+                       Ext.iterate(this.getEditor().plugins, function (pluginId) {
+                               var plugin = this.getEditor().getPlugin(pluginId);
+                               if (Ext.isFunction(plugin.onKeyPress)) {
+                                       if (!plugin.onKeyPress(event.browserEvent)) {
+                                               event.stopEvent();
+                                               letBubble = false;
+                                       }
                                }
-                               break;
+                               return letBubble;
+                       }, this);
+                       if (!letBubble) {
+                               return letBubble;
                        }
                }
+               if (!event.altKey && !event.ctrlKey) {
+                               // Detect URL in non-IE browsers
+                       if (!Ext.isIE) {
+                               this.getEditor()._detectURL(event);
+                       }
+                               // Handle option+SPACE for Mac users
+                       if (Ext.isMac && event.browserEvent.charCode == 160) {
+                               return this.onOptionSpace(event.browserEvent.charCode, event);
+                       }
+               }
+               return true;
+       },
+       /*
+        * Handler for mouse events
+        */
+       onMouse: function () {
+               this.getToolbar().updateLater.delay(100);
+               return true;
+       },
+       /*
+        * Handler for UP, DOWN, LEFT and RIGHT keys
+        */
+       onArrow: function () {
+               this.getToolbar().updateLater.delay(100);
+               return true;
+       },
+       /*
+        * Handler for TAB and SHIFT-TAB keys
+        *
+        * If available, BlockElements plugin will handle the TAB key
+        */
+       onTab: function (key, event) {
+               var keyName = (event.shiftKey ? 'SHIFT-' : '') + 'TAB';
+               if (this.config.hotKeyList[keyName] && this.config.hotKeyList[keyName].cmd) {
+                       var button = this.getButton(this.config.hotKeyList[keyName].cmd);
+                       if (button) {
+                               event.stopEvent();
+                               button.fireEvent('hotkey', keyName, event);
+                               return false;
+                       }
+               }
+               return true;
+       },
+       /*
+        * Handler for BACKSPACE and DELETE keys
+        */
+       onBackSpace: function (key, event) {
+               if ((!Ext.isIE && !event.shiftKey) || Ext.isIE) {
+                       if (this.getEditor()._checkBackspace()) {
+                               event.stopEvent();
+                       }
+               }
+                       // Update the toolbar state after some time
+               this.getToolbar().updateLater.delay(200);
+               return false;
+       },
+       /*
+        * Handler for ENTER key in non-IE browsers
+        */
+       onEnter: function (key, event) {
+               if (!event.shiftKey) {
+                       if (this.getEditor()._checkInsertP()) {
+                               event.stopEvent();
+                       }
+               }
+                       // Update the toolbar state after some time
+               this.getToolbar().updateLater.delay(200);
+               return false;
+       },
+       /*
+        * Handler for ENTER key in WebKit browsers
+        */
+       onWebKitEnter: function (key, event) {
+               if (event.shiftKey || this.config.disableEnterParagraphs) {
+                       var brNode = this.document.createElement('br');
+                       this.getEditor().insertNodeAtSelection(brNode);
+                       if (!brNode.nextSibling || !HTMLArea.getInnerText(brNode.nextSibling)) {
+                               var secondBrNode = this.document.createElement('br');
+                               secondBrNode = brNode.parentNode.appendChild(secondBrNode);
+                               this.getEditor().selectNode(secondBrNode, false);
+                       }
+                       event.stopEvent();
+               }
+                       // Update the toolbar state after some time
+               this.getToolbar().updateLater.delay(200);
+               return false;
+       },
+       /*
+        * Handler for CTRL-SPACE keys
+        */
+       onCtrlSpace: function (key, event) {
+               this.getEditor().insertHTML('&nbsp;');
+               event.stopEvent();
+               return false;
+       },
+       /*
+        * Handler for OPTION-SPACE keys on Mac
+        */
+       onOptionSpace: function (key, event) {
+               this.getEditor().insertHTML('&nbsp;');
+               event.stopEvent();
+               return false;
+       },
+       /*
+        * Handler for configured hotkeys
+        */
+       onHotKey: function (key, event) {
+               var hotKey = String.fromCharCode(key).toLowerCase();
+               this.getButton(this.config.hotKeyList[hotKey].cmd).fireEvent('hotkey', hotKey, event);
+               return false;
+       },
+       /*
+        * Cleanup
+        */
+       onBeforeDestroy: function () {
+               this.keyMap.disable();
+               this.hotKeyMap.disable();
        }
-       editor.updateToolbar();
-};
-
+});
+Ext.reg('htmlareaiframe', HTMLArea.Iframe);
 /*
- * When we have a form, on reset, re-initialize the HTMLArea content and update the toolbar
+ * HTMLArea.StatusBar extends Ext.Container
  */
-HTMLArea.resetHandler = function(ev) {
-       if(!ev) var ev = window.event;
-       var form = (ev.target) ? ev.target : ev.srcElement;
-       var editor = RTEarea[form._editorNumber]["editor"];
-       editor.getPluginInstance("EditorMode").setHTML(editor._textArea.value);
-       editor.updateToolbar();
-       var a = form.__msh_prevOnReset;
-               // call previous reset methods if they were there.
-       if (typeof(a) != "undefined") {
-               for (var i=a.length; --i >= 0; ) { a[i](); }
+HTMLArea.StatusBar = Ext.extend(Ext.Container, {
+       /*
+        * Constructor
+        */
+       initComponent: function () {
+               HTMLArea.StatusBar.superclass.initComponent.call(this);
+               this.addListener({
+                       render: {
+                               fn: this.addComponents,
+                               single: true
+                       },
+                       afterrender: {
+                               fn: this.initEventListeners,
+                               single: true
+                       }
+               });
+       },
+       /*
+        * Initialize listeners
+        */
+       initEventListeners: function () {
+               this.addListener({
+                       beforedestroy: {
+                               fn: this.clear,
+                               single: true
+                       }
+               });
+                       // Monitor toolbar updates in order to refresh the contents of the statusbar
+                       // The toolbar must have been rendered
+               this.mon(this.ownerCt.toolbar, 'update', this.onUpdateToolbar, this);
+                       // Monitor editor changing mode
+               this.mon(this.getEditor(), 'modeChange', this.onModeChange, this);
+       },
+       /*
+        * editorId should be set in config
+        */
+       editorId: null,
+       /*
+        * Get a reference to the editor
+        */
+       getEditor: function() {
+               return RTEarea[this.editorId].editor;
+       },
+       /*
+        * Create span elements to display when the status bar tree or a message when the editor is in text mode
+        */
+       addComponents: function () {
+               this.statusBarTree = Ext.DomHelper.append(this.getEl(), {
+                       id: this.editorId + '-statusBarTree',
+                       tag: 'span',
+                       cls: 'statusBarTree',
+                       html: HTMLArea.I18N.msg['Path'] + ': '
+               }, true).setVisibilityMode(Ext.Element.DISPLAY).setVisible(true);
+               this.statusBarTextMode = Ext.DomHelper.append(this.getEl(), {
+                       id: this.editorId + '-statusBarTextMode',
+                       tag: 'span',
+                       cls: 'statusBarTextMode',
+                       html: HTMLArea.I18N.msg['TEXT_MODE']
+               }, true).setVisibilityMode(Ext.Element.DISPLAY).setVisible(false);
+       },
+       /*
+        * Clear the status bar tree
+        */
+       clear: function () {
+               this.statusBarTree.removeAllListeners();
+               Ext.each(this.statusBarTree.query('a'), function (node) {
+                       Ext.QuickTips.unregister(node);
+               });
+               this.statusBarTree.update('');
+               this.setSelection(null);
+       },
+       /*
+        * Flag indicating that the status bar should not be updated on this toolbar update
+        */
+       noUpdate: false,
+       /*
+        * Update the status bar
+        */
+       onUpdateToolbar: function (mode, selectionEmpty, ancestors, endPointsInSameBlock) {
+               if (mode === 'wysiwyg' && !this.noUpdate) {
+                       var text,
+                               language,
+                               languageObject = this.getEditor().getPlugin('Language'),
+                               classes = new Array(),
+                               classText;
+                       this.clear();
+                       var path = Ext.DomHelper.append(this.statusBarTree, {
+                               tag: 'span',
+                               html: HTMLArea.I18N.msg['Path'] + ': '
+                       },true);
+                       Ext.each(ancestors, function (ancestor, index) {
+                               if (!ancestor) {
+                                       return true;
+                               }
+                               text = ancestor.nodeName.toLowerCase();
+                                       // Do not show any id generated by ExtJS
+                               if (ancestor.id && text !== 'body' && ancestor.id.substr(0, 7) !== 'ext-gen') {
+                                       text += '#' + ancestor.id;
+                               }
+                               if (languageObject && languageObject.getLanguageAttribute) {
+                                       language = languageObject.getLanguageAttribute(ancestor);
+                                       if (language != 'none') {
+                                               text += '[' + language + ']';
+                                       }
+                               }
+                               if (ancestor.className) {
+                                       classText = '';
+                                       classes = ancestor.className.trim().split(' ');
+                                       for (var j = 0, n = classes.length; j < n; ++j) {
+                                               if (!HTMLArea.reservedClassNames.test(classes[j])) {
+                                                       classText += '.' + classes[j];
+                                               }
+                                       }
+                                       text += classText;
+                               }
+                               var element = Ext.DomHelper.insertAfter(path, {
+                                       tag: 'a',
+                                       href: '#',
+                                       'ext:qtitle': HTMLArea.I18N.dialogs['statusBarStyle'],
+                                       'ext:qtip': ancestor.style.cssText.split(';').join('<br />'),
+                                       html: text
+                               }, true);
+                                       // Ext.DomHelper does not honour the custom attribute
+                               element.dom.ancestor = ancestor;
+                               if (Ext.isIE) {
+                                       element.on('click', this.onClick, this);
+                               } else {
+                                       element.on('mousedown', this.onMouseDown, this);
+                               }
+                               if (!Ext.isOpera) {
+                                       element.on('contextmenu', this.onContextMenu, this);
+                               }
+                               if (index) {
+                                       Ext.DomHelper.insertAfter(element, {
+                                               tag: 'span',
+                                               html: String.fromCharCode(0xbb)
+                                       });
+                               }
+                       }, this);
+               }
+               this.noUpdate = false;
+       },
+       /*
+        * Adapt status bar to current editor mode
+        *
+        * @param       string  mode: the mode to which the editor got switched to
+        */
+       onModeChange: function (mode) {
+               switch (mode) {
+                       case 'wysiwyg':
+                               this.statusBarTextMode.setVisible(false);
+                               this.statusBarTree.setVisible(true);
+                               break;
+                       case 'textmode':
+                       default:
+                               this.statusBarTree.setVisible(false);
+                               this.statusBarTextMode.setVisible(true);
+                               break;
+               }
+       },
+       /*
+        * Refrence to the element last selected on the status bar
+        */
+       selected: null,
+       /*
+        * Get the status bar selection
+        */
+       getSelection: function() {
+               return this.selected;
+       },
+       /*
+        * Set the status bar selection
+        *
+        * @param       object  element: set the status bar selection to the given element
+        */
+       setSelection: function(element) {
+               this.selected = element ? element : null;
+       },
+       /*
+        * Select the element that was clicked in the status bar and set the status bar selection
+        */
+       selectElement: function (element) {
+               var editor = this.getEditor();
+               element.blur();
+               if (!Ext.isIE) {
+                       editor.selectNodeContents(element.ancestor);
+               } else {
+                       var nodeName = element.ancestor.nodeName.toLowerCase();
+                       if (nodeName == 'table' || nodeName == 'img') {
+                               var range = editor.document.body.createControlRange();
+                               range.addElement(element.ancestor);
+                               range.select();
+                       } else {
+                               editor.selectNode(element.ancestor);
+                       }
+               }
+               this.setSelection(element.ancestor);
+               this.noUpdate = true;
+               editor.toolbar.update();
+       },
+       /*
+        * Click handler
+        */
+       onClick: function (event, element) {
+               this.selectElement(element);
+               event.stopEvent();
+               return false;
+       },
+       /*
+        * MouseDown handler
+        */
+       onMouseDown: function (event, element) {
+               this.selectElement(element);
+               if (Ext.isIE) {
+                       return true;
+               } else {
+                       event.stopEvent();
+                       return false;
+               }
+       },
+       /*
+        * ContextMenu handler
+        */
+       onContextMenu: function (event, target) {
+               this.selectElement(target);
+               return this.getEditor().getPlugin('ContextMenu') ? this.getEditor().getPlugin('ContextMenu').show(event, target.ancestor) : false;
        }
-};
-
+});
+Ext.reg('htmlareastatusbar', HTMLArea.StatusBar);
 /*
- * Clean up event handlers and object references, undo/redo snapshots, update the textarea for submission
+ * HTMLArea.Framework extends Ext.Panel
  */
-HTMLArea.removeEditorEvents = function(ev) {
-       if (!ev) var ev = window.event;
-       HTMLArea._stopEvent(ev);
-       if (HTMLArea._eventCache) {
-               HTMLArea._eventCache.flush();
+HTMLArea.Framework = Ext.extend(Ext.Panel, {
+       /*
+        * Constructor
+        */
+       initComponent: function () {
+               HTMLArea.Framework.superclass.initComponent.call(this);
+                       // Set some references
+               this.toolbar = this.getTopToolbar();
+               this.statusBar = this.getBottomToolbar();
+               this.iframe = this.getComponent('iframe');
+               this.textAreaContainer = this.getComponent('textAreaContainer');
+               this.addEvents(
+                       /*
+                        * @event frameworkready
+                        * Fires when the iframe is ready and all components are rendered
+                        */
+                       'frameworkready'
+               );
+               this.addListener({
+                       afterrender: {
+                               fn: this.initEventListeners,
+                               single: true
+                       }
+               });
+                       // Let the framefork render itself, but it will fail to do so if inside a hidden tab or inline element
+               if (!this.isNested || HTMLArea.util.TYPO3.allElementsAreDisplayed(this.nestedParentElements.sorted)) {
+                       this.render(this.textArea.parent(), this.textArea.id);
+               } else {
+                               // Clone the array of nested tabs and inline levels instead of using a reference as HTMLArea.util.TYPO3.accessParentElements will modify the array
+                       var parentElements = [].concat(this.nestedParentElements.sorted);
+                               // Walk through all nested tabs and inline levels to get correct sizes
+                       HTMLArea.util.TYPO3.accessParentElements(parentElements, 'args[0].render(args[0].textArea.parent(), args[0].textArea.id)', [this]);
+               }
+       },
+       /*
+        * Initiate events monitoring
+        */
+       initEventListeners: function () {
+                       // Monitor iframe becoming ready
+               this.mon(this.iframe, 'iframeready', this.onIframeReady, this, {single: true});
+                       // Make the framework resizable, if configured by the user
+               this.makeResizable();
+                       // Monitor textArea container becoming shown or hidden as it may change the height of the status bar
+               this.mon(this.textAreaContainer, 'show', this.onTextAreaShow, this);
+               if (this.resizable) {
+                               // Monitor iframe becoming shown or hidden as it may change the height of the status bar
+                       this.mon(this.iframe, 'show', this.onIframeShow, this);
+               }
+                       // Monitor window resizing
+               if (this.resizable || this.textAreaInitialSize.width.indexOf('%') !== -1) {
+                       Ext.EventManager.onWindowResize(this.onWindowResize, this);
+               }
+                       // If the textarea is inside a form, on reset, re-initialize the HTMLArea content and update the toolbar
+               var form = this.textArea.dom.form;
+               if (form) {
+                       if (Ext.isFunction(form.onsubmit)) {
+                               if (typeof(form.htmlAreaPreviousOnReset) == 'undefined') {
+                                       form.htmlAreaPreviousOnReset = [];
+                               }
+                               form.htmlAreaPreviousOnReset.push(form.onreset);
+                       }
+                       this.mon(Ext.get(form), 'reset', this.onReset, this);
+               }
+               this.addListener({
+                       beforedestroy: {
+                               fn: this.onBeforeDestroy
+                       }
+               });
+       },
+       /*
+        * editorId should be set in config
+        */
+       editorId: null,
+       /*
+        * Get a reference to the editor
+        */
+       getEditor: function() {
+               return RTEarea[this.editorId].editor;
+       },
+       /*
+        * Flag indicating whether the framework is inside a tab or inline element that may be hidden
+        * Should be set in config
+        */
+       isNested: false,
+       /*
+        * All nested tabs and inline levels in the sorting order they were applied
+        * Should be set in config
+        */
+       nestedParentElements: {},
+       /*
+        * Flag set to true when the framework is ready
+        */
+       ready: false,
+       /*
+        * All nested tabs and inline levels in the sorting order they were applied
+        * Should be set in config
+        */
+       nestedParentElements: {},
+       /*
+        * Whether the framework should be made resizable
+        * May be set in config
+        */
+       resizable: false,
+       /*
+        * Maximum height to which the framework may resized (in pixels)
+        * May be set in config
+        */
+       maxHeight: 2000,
+       /*
+        * Initial textArea dimensions
+        * Should be set in config
+        */
+       textAreaInitialSize: {
+               width: 0,
+               contextWidth: 0,
+               height: 0
+       },
+       /*
+        * Make the framework resizable, if configured
+        */
+       makeResizable: function () {
+               if (this.resizable) {
+                       this.addClass('resizable');
+                       this.resizer = new Ext.Resizable(this.getEl(), {
+                               minWidth: 300,
+                               maxHeight: this.maxHeight,
+                               dynamic: false
+                       });
+                       this.resizer.on('resize', this.onHtmlAreaResize, this);
+               }
+       },
+       /*
+        * Size the iframe according to initial textarea size as set by Page and User TSConfig
+        */
+       onWindowResize: function(width, height) {
+               if (!this.isNested || HTMLArea.util.TYPO3.allElementsAreDisplayed(this.nestedParentElements.sorted)) {
+                       this.resizeFramework(width, height);
+               } else {
+                               // Clone the array of nested tabs and inline levels instead of using a reference as HTMLArea.util.TYPO3.accessParentElements will modify the array
+                       var parentElements = [].concat(this.nestedParentElements.sorted);
+                               // Walk through all nested tabs and inline levels to get correct sizes
+                       HTMLArea.util.TYPO3.accessParentElements(parentElements, 'args[0].resizeFramework(args[1], args[2])', [this, width, height]);
+               }
+       },
+       /*
+        * Resize the framework to its initial size
+        */
+       resizeFramework: function (width, height) {
+               var frameworkHeight = this.fullScreen ? HTMLArea.util.TYPO3.getWindowSize().height - 20 : parseInt(this.textAreaInitialSize.height);
+               if (this.textAreaInitialSize.width.indexOf('%') === -1) {
+                               // Width is specified in pixels
+                       var frameworkWidth = parseInt(this.textAreaInitialSize.width) - this.getFrameWidth();
+               } else {
+                               // Width is specified in %
+                       if (Ext.isDefined(width)) {
+                                       // Framework sizing on actual window resize
+                               var frameworkWidth = parseInt(((width - this.textAreaInitialSize.nextSiblingWidth - (this.fullScreen ? 10 : Ext.getScrollBarWidth()) - this.getBox().x - 15) * parseInt(this.textAreaInitialSize.width))/100);
+                       } else {
+                                       // Initial framework sizing
+                               var frameworkWidth = parseInt(((HTMLArea.util.TYPO3.getWindowSize().width - this.textAreaInitialSize.nextSiblingWidth - (this.fullScreen ? 10 : Ext.getScrollBarWidth()) - this.getBox().x - 15) * parseInt(this.textAreaInitialSize.width))/100);
+                       }
+               }
+               if (this.resizable) {
+                       this.resizer.resizeTo(frameworkWidth, frameworkHeight);
+               } else {
+                       this.setSize(frameworkWidth, frameworkHeight);
+                               // Adjust height of iframe and textarea to height of toolbar and statusbar
+                       this.iframe.setSize(this.getInnerWidth(), this.getInnerHeight());
+                       this.textArea.setSize(this.getInnerWidth(), this.getInnerHeight());
+               }
+       },
+       /*
+        * Resize the components when the editor framework was resized
+        */
+       onHtmlAreaResize: function (resizer, width, height, event) {
+                       // Set width first as it may change the height of the toolbar and of the statusBar
+               this.setWidth(width);
+                       // Set height of iframe and textarea
+               this.iframe.setHeight(this.getInnerHeight());
+               this.textArea.setSize(this.getInnerWidth(), this.getInnerHeight());
+       },
+       /*
+        * Adjust the height to the changing size of the statusbar when the textarea is shown
+        */
+       onTextAreaShow: function () {
+               this.iframe.setHeight(this.getInnerHeight());
+               this.textArea.setHeight(this.getInnerHeight());
+       },
+       /*
+        * Adjust the height to the changing size of the statusbar when the iframe is shown
+        */
+       onIframeShow: function () {
+               this.iframe.setHeight(this.getInnerHeight());
+               this.textArea.setHeight(this.getInnerHeight());
+       },
+       /*
+        * Fire the editor when all components of the framework are rendered and ready
+        */
+       onIframeReady: function () {
+               this.ready = this.toolbar.rendered && this.statusBar.rendered && this.textAreaContainer.rendered;
+               if (this.ready) {
+                       this.textAreaContainer.show();
+                       if (!this.getEditor().config.showStatusBar) {
+                               this.statusBar.hide();
+                       }
+                               // Set the initial size of the framework
+                       this.onWindowResize();
+                       this.fireEvent('frameworkready');
+               } else {
+                       this.onIframeReady.defer(50, this);
+               }
+       },
+       /*
+        * Handler invoked if we are inside a form and the form is reset
+        * On reset, re-initialize the HTMLArea content and update the toolbar
+        */
+       onReset: function (event) {
+               this.getEditor().setHTML(this.textArea.getValue());
+               this.toolbar.update();
+                       // Invoke previous reset handlers, if any
+               var htmlAreaPreviousOnReset = event.getTarget().dom.htmlAreaPreviousOnReset;
+               if (typeof(htmlAreaPreviousOnReset) != 'undefined') {
+                       Ext.each(htmlAreaPreviousOnReset, function (onReset) {
+                               onReset();
+                               return true;
+                       });
+               }
+       },
+       /*
+        * Cleanup on framework destruction
+        */
+       onBeforeDestroy: function () {
+               if (this.resizable) {
+                       Ext.EventManager.removeResizeListener(this.onWindowResize, this);
+               }
+               var form = this.textArea.dom.form;
+               if (form) {
+                       form.htmlAreaPreviousOnReset = null;
+               }
        }
-       for (var editorNumber in RTEarea) {
-               if (RTEarea.hasOwnProperty(editorNumber)) {
-                       var editor = RTEarea[editorNumber].editor;
-                       if (editor) {
-                               RTEarea[editorNumber].editor = null;
-                                       // save the HTML content into the original textarea for submit, back/forward, etc.
-                               editor._textArea.value = editor.getPluginInstance("EditorMode").getHTML();
-                                       // do final cleanup
-                               HTMLArea.cleanup(editor);
+});
+Ext.reg('htmlareaframework', HTMLArea.Framework);
+/***************************************************
+ *  HTMLArea.Editor extends Ext.util.Observable
+ ***************************************************/
+HTMLArea.Editor = Ext.extend(Ext.util.Observable, {
+       /*
+        * HTMLArea.Editor constructor
+        */
+       constructor: function (config) {
+               HTMLArea.Editor.superclass.constructor.call(this, {});
+                       // Save the config
+               this.config = config;
+                       // Establish references to this editor
+               this.editorId = this.config.editorId;
+               RTEarea[this.editorId].editor = this;
+                       // Get textarea size and wizard context
+               this.textArea = Ext.get(this.config.id);
+               this.textAreaInitialSize = {
+                       width: this.config.RTEWidthOverride ? this.config.RTEWidthOverride : this.textArea.getStyle('width'),
+                       height: this.config.fullScreen ? HTMLArea.util.TYPO3.getWindowSize().height - 20 : this.textArea.getStyle('height'),
+                       nextSiblingWidth: 0
+               };
+                       // TYPO3 Inline elements and tabs
+               this.nestedParentElements = {
+                       all: this.config.tceformsNested,
+                       sorted: HTMLArea.util.TYPO3.simplifyNested(this.config.tceformsNested)
+               };
+               this.isNested = !Ext.isEmpty(this.nestedParentElements.sorted);
+                       // Get width of wizards
+               var nextSibling = this.textArea.parent().parent().next();
+               if (nextSibling) {
+                       if (!this.isNested || HTMLArea.util.TYPO3.allElementsAreDisplayed(this.nestedParentElements.sorted)) {
+                               this.textAreaInitialSize.nextSiblingWidth = nextSibling.getWidth();
+                       } else {
+                                       // Clone the array of nested tabs and inline levels instead of using a reference as HTMLArea.util.TYPO3.accessParentElements will modify the array
+                               var parentElements = [].concat(this.nestedParentElements.sorted);
+                                       // Walk through all nested tabs and inline levels to get correct size
+                                       this.textAreaInitialSize.nextSiblingWidth = HTMLArea.util.TYPO3.accessParentElements(parentElements, 'args[0].getWidth()', [nextSibling]);
+                       }
+               }
+                       // Plugins register
+               this.plugins = {};
+                       // Register the plugins included in the configuration
+               Ext.iterate(this.config.plugin, function (plugin) {
+                       if (this.config.plugin[plugin]) {
+                               this.registerPlugin(plugin);
+                       }
+               }, this);
+               this.addEvents(
+                       /*
+                        * @event editorready
+                        * Fires when initializatio of the editor is complete
+                        */
+                       'editorready',
+                       /*
+                        * @event modeChange
+                        * Fires when the editor changes mode
+                        */
+                       'modeChange'
+               );
+       },
+       /*
+        * Flag set to true when the editor initialization has completed
+        */
+       ready: false,
+       /*
+        * The current mode of the editor: 'wysiwyg' or 'textmode'
+        */
+       mode: 'textmode',
+       /*
+        * Create the htmlArea framework
+        */
+       generate: function () {
+                       // Create the editor framework
+               this.htmlArea = new HTMLArea.Framework({
+                       id: this.editorId + '-htmlArea',
+                       layout: 'anchor',
+                       baseCls: 'htmlarea',
+                       editorId: this.editorId,
+                       textArea: this.textArea,
+                       textAreaInitialSize: this.textAreaInitialSize,
+                       fullScreen: this.config.fullScreen,
+                       resizable: this.config.resizable,
+                       maxHeight: this.config.maxHeight,
+                       isNested: this.isNested,
+                       nestedParentElements: this.nestedParentElements,
+                               // The toolbar
+                       tbar: {
+                               xtype: 'htmlareatoolbar',
+                               id: this.editorId + '-toolbar',
+                               anchor: '100%',
+                               layout: 'form',
+                               cls: 'toolbar',
+                               editorId: this.editorId
+                       },
+                       items: [{
+                                               // The iframe
+                                       xtype: 'htmlareaiframe',
+                                       itemId: 'iframe',
+                                       anchor: '100%',
+                                       width: (this.textAreaInitialSize.width.indexOf('%') === -1) ? parseInt(this.textAreaInitialSize.width) : 300,
+                                       height: parseInt(this.textAreaInitialSize.height),
+                                       autoEl: {
+                                               id: this.editorId + '-iframe',
+                                               tag: 'iframe',
+                                               cls: 'editorIframe',
+                                               src: Ext.isGecko ? 'javascript:void(0);' : (Ext.isOpera ? _typo3_host_url : '') + _editor_url + 'popups/blank.html'
+                                       },
+                                       isNested: this.isNested,
+                                       nestedParentElements: this.nestedParentElements,
+                                       editorId: this.editorId
+                               },{
+                                               // Box container for the textarea
+                                       xtype: 'box',
+                                       itemId: 'textAreaContainer',
+                                       anchor: '100%',
+                                       width: (this.textAreaInitialSize.width.indexOf('%') === -1) ? parseInt(this.textAreaInitialSize.width) : 300,
+                                               // Let the framework swallow the textarea
+                                       listeners: {
+                                               afterRender: {
+                                                       fn: function (textAreaContainer) { textAreaContainer.getEl().appendChild(this.textArea); },
+                                                       single: true,
+                                                       scope: this
+                                               }
+                                       }
+                               }
+                       ],
+                               // The status bar
+                       bbar: {
+                               xtype: 'htmlareastatusbar',
+                               anchor: '100%',
+                               cls: 'statusBar',
+                               editorId: this.editorId
+                       }
+               });
+                       // Set some references
+               this.toolbar = this.htmlArea.getTopToolbar();
+               this.statusBar = this.htmlArea.getBottomToolbar();
+               this.iframe = this.htmlArea.getComponent('iframe');
+               this.textAreaContainer = this.htmlArea.getComponent('textAreaContainer');
+                       // Get triggered when the framework becomes ready
+               this.relayEvents(this.htmlArea, 'frameworkready');
+               this.on('frameworkready', this.onFrameworkReady, this, {single: true});
+       },
+       /*
+        * Initialize the editor
+        */
+       onFrameworkReady: function () {
+                       // Initialize editor mode
+               this.setMode('wysiwyg');
+                       // Initiate events listening
+               this.initEventsListening();
+                       // Generate plugins
+               this.generatePlugins();
+                       // Make the editor visible
+               this.show();
+                       // Focus on the first editor that is not hidden
+               Ext.iterate(RTEarea, function (editorId, RTE) {
+                       if (!Ext.isDefined(RTE.editor) || (RTE.editor.isNested && !HTMLArea.util.TYPO3.allElementsAreDisplayed(RTE.editor.nestedParentElements.sorted))) {
+                               return true;
+                       } else {
+                               RTE.editor.focus();
+                               return false;
                        }
+               }, this);
+               this.ready = true;
+               this.fireEvent('editorready');
+               HTMLArea._appendToLog('[HTMLArea.Editor::start]: Editor ready.');
+       },
+       /*
+        * Set editor mode
+        *
+        * @param       string          mode: 'textmode' or 'wysiwyg'
+        *
+        * @return      void
+        */
+       setMode: function (mode) {
+               switch (mode) {
+                       case 'textmode':
+                               this.textArea.set({ value: this.getHTML() }, false);
+                               this.iframe.setDesignMode(false);
+                               this.iframe.hide();
+                               this.textAreaContainer.show();
+                               this.mode = mode;
+                               break;
+                       case 'wysiwyg':
+                               try {
+                                       this.document.body.innerHTML = this.getHTML();
+                               } catch(e) {
+                                       HTMLArea._appendToLog('[HTMLArea.Editor::setMode]: The HTML document is not well-formed.');
+                                       alert(HTMLArea.I18N.msg['HTML-document-not-well-formed']);
+                                       break;
+                               }
+                               this.textAreaContainer.hide();
+                               this.iframe.show();
+                               this.iframe.setDesignMode(true);
+                               this.mode = mode;
+                               break;
                }
-       }
-};
-
-/*
- * Clean up a bunch of references in order to avoid memory leakages mainly in IE, but also in Firefox and Opera
- */
-HTMLArea.cleanup = function (editor) {
-               // nullify envent handlers
-       for (var handler in editor.eventHandlers) {
-               if (editor.eventHandlers.hasOwnProperty(handler)) {
-                       editor.eventHandlers[handler] = null;
+               this.fireEvent('modeChange', this.mode);
+               this.focus();
+               Ext.iterate(this.plugins, function(pluginId) {
+                       this.getPlugin(pluginId).onMode(this.mode);
+               }, this);
+       },
+       /*
+        * Get current editor mode
+        */
+       getMode: function () {
+               return this.mode;
+       },
+       /*
+        * Retrieve the HTML
+        * In the case of the wysiwyg mode, the html content is parsed
+        *
+        * @return      string          the textual html content from the current editing mode
+        */
+       getHTML: function () {
+               switch (this.mode) {
+                       case 'wysiwyg':
+                               return this.iframe.getHTML();
+                       case 'textmode':
+                               return this.textArea.getValue();
+                       default:
+                               return '';
                }
-       }
-       for (var button in editor.btnList) {
-               if (editor.btnList.hasOwnProperty(button)) {
-                       editor.btnList[button][3] = null;
+       },
+       /*
+        * Retrieve raw HTML
+        *
+        * @return      string  the textual html content from the current editing mode
+        */
+       getInnerHTML: function () {
+               switch (this.mode) {
+                       case 'wysiwyg':
+                               return this.document.body.innerHTML;
+                       case 'textmode':
+                               return this.textArea.getValue();
+                       default:
+                               return '';
                }
-       }
-       for (var dropdown in editor.config.customSelects) {
-               if (editor.config.customSelects.hasOwnProperty(dropdown)) {
-                       editor.config.customSelects[dropdown].action = null;
-                       editor.config.customSelects[dropdown].refresh = null;
+       },
+       /*
+        * Replace the html content
+        *
+        * @param       string          html: the textual html
+        *
+        * @return      void
+        */
+       setHTML: function (html) {
+               switch (this.mode) {
+                       case 'wysiwyg':
+                               this.document.body.innerHTML = html;
+                               break;
+                       case 'textmode':
+                               this.textArea.set({ value: html }, false);;
+                               break;
                }
-       }
-       for (var hotKey in editor.config.hotKeyList) {
-               if (editor.config.customSelects.hasOwnProperty(hotKey)) {
-                       editor.config.hotKeyList[hotKey].action = null;
+       },
+       /*
+        * Generate registered plugins
+        */
+       generatePlugins: function () {
+               this.hasPluginWithOnKeyPressHandler = false;
+               Ext.iterate(this.plugins, function (pluginId) {
+                       var plugin = this.getPlugin(pluginId);
+                       plugin.onGenerate();
+                               // onKeyPress deprecated as of TYPO3 4.4
+                       if (Ext.isFunction(plugin.onKeyPress)) {
+                               this.hasPluginWithOnKeyPressHandler = true;
+                               HTMLArea._appendToLog('[HTMLArea.Editor::generatePlugins]: Deprecated use of onKeyPress function by plugin ' + pluginId + '. Use keyMap instead.');
+                       }
+               }, this);
+               HTMLArea._appendToLog('[HTMLArea.Editor::generatePlugins]: All plugins successfully generated.');
+       },
+       /*
+        * Get the instance of the specified plugin, if it exists
+        *
+        * @param       string          pluginName: the name of the plugin
+        * @return      object          the plugin instance or null
+        */
+       getPlugin: function(pluginName) {
+               return (this.plugins[pluginName] ? this.plugins[pluginName].instance : null);
+       },
+       /*
+        * Focus on the editor
+        */
+       focus: function () {
+               switch (this.getMode()) {
+                       case 'wysiwyg':
+                               this.iframe.focus();
+                               break;
+                       case 'textmode':
+                               this.textArea.focus();
+                               break;
                }
-       }
-       editor.onGenerate = null;
-       if(editor._textArea.form) {
-               editor._textArea.form.__msh_prevOnReset = null;
-               editor._textArea.form._editorNumber = null;
-       }
-
-               // cleaning plugins
-       for (var plugin in editor.plugins) {
-               if (editor.plugins.hasOwnProperty(plugin)) {
-                       var pluginInstance = editor.plugins[plugin].instance;
-                       if (typeof(pluginInstance.onClose) === "function") {
-                               pluginInstance.onClose();
-                       }
-                       pluginInstance.onClose = null;
-                       pluginInstance.onChange = null;
-                       pluginInstance.onButtonPress = null;
-                       pluginInstance.onGenerate = null;
-                       pluginInstance.onGenerateOnce = null;
-                       pluginInstance.onMode = null;
-                       pluginInstance.onHotKey = null;
-                       pluginInstance.onKeyPress = null;
-                       pluginInstance.onSelect = null;
-                       pluginInstance.onUpdateTolbar = null;
+       },
+       /*
+        * Add listeners
+        */
+       initEventsListening: function () {
+               if (Ext.isOpera) {
+                       this.iframe.startListening();
+               }
+                       // Add unload handler
+               var iframe = this.iframe.getEl().dom;
+               Ext.EventManager.on(iframe.contentWindow ? iframe.contentWindow : iframe.contentDocument, 'unload', this.onUnload, this, {single: true});
+       },
+       /*
+        * Make the editor framework visible
+        */
+       show: function () {
+               document.getElementById('pleasewait' + this.editorId).style.display = 'none';
+               document.getElementById('editorWrap' + this.editorId).style.visibility = 'visible';
+       },
+       /*
+        * Iframe unload handler: Update the textarea for submission and cleanup
+        */
+       onUnload: function (event) {;
+                       // Save the HTML content into the original textarea for submit, back/forward, etc.
+               if (this.ready) {
+                       this.textArea.set({
+                               value: this.getHTML()
+                       }, false);
                }
+                       // Cleanup
+               Ext.TaskMgr.stopAll();
+               this.htmlArea.destroy();
+               RTEarea[this.editorId].editor = null;
        }
-               // cleaning the toolbar elements
-       for (var txt in editor._toolbarObjects) {
-               if (editor._toolbarObjects.hasOwnProperty(txt)) {
-                       var obj = editor._toolbarObjects[txt];
-                       obj.state = null;
-                       obj.cmd = null;
-                       var element = document.getElementById(obj.elementId);
-                       if (element) {
-                               element._obj = null;
-                       }
-                       editor._toolbarObjects[txt] = null;
+});
+/***************************************************
+ * HTMLArea.util.TYPO3: Utility functions for dealing with tabs and inline elements in TYPO3 forms
+ ***************************************************/
+HTMLArea.util.TYPO3 = function () {
+       return {
+               /*
+                * Simplify the array of nested levels. Create an indexed array with the correct names of the elements.
+                *
+                * @param       object          nested: The array with the nested levels
+                * @return      object          The simplified array
+                * @author      Oliver Hader <oh@inpublica.de>
+                */
+               simplifyNested: function(nested) {
+                       var i, type, level, max, simplifiedNested=[];
+                       if (nested && nested.length) {
+                               if (nested[0][0]=='inline') {
+                                       nested = inline.findContinuedNestedLevel(nested, nested[0][1]);
+                               }
+                               for (i=0, max=nested.length; i<max; i++) {
+                                       type = nested[i][0];
+                                       level = nested[i][1];
+                                       if (type=='tab') {
+                                               simplifiedNested.push(level+'-DIV');
+                                       } else if (type=='inline') {
+                                               simplifiedNested.push(level+'_fields');
+                                       }
+                               }
+                       }
+                       return simplifiedNested;
+               },
+               /*
+                * Access an inline relational element or tab menu and make it "accessible".
+                * If a parent or ancestor object has the style "display: none", offsetWidth & offsetHeight are '0'.
+                *
+                * @params      arry            parentElements: array of parent elements id's; note that this input array will be modified
+                * @params      object          callbackFunc: A function to be called, when the embedded objects are "accessible".
+                * @params      array           args: array of arguments
+                * @return      object          An object returned by the callbackFunc.
+                * @author      Oliver Hader <oh@inpublica.de>
+                */
+               accessParentElements: function (parentElements, callbackFunc, args) {
+                       var result = {};
+                       if (parentElements.length) {
+                               var currentElement = parentElements.pop();
+                               var elementStyle = document.getElementById(currentElement).style;
+                               var actionRequired = (elementStyle.display == 'none' ? true : false);
+                               if (actionRequired) {
+                                       var originalVisibility = elementStyle.visibility;
+                                       var originalPosition = elementStyle.position;
+                                       elementStyle.visibility = 'hidden';
+                                       elementStyle.position = 'absolute';
+                                       elementStyle.display = '';
+                               }
+                               result = this.accessParentElements(parentElements, callbackFunc, args);
+                               if (actionRequired) {
+                                       elementStyle.display = 'none';
+                                       elementStyle.position = originalPosition;
+                                       elementStyle.visibility = originalVisibility;
+                               }
+                       } else {
+                               result = eval(callbackFunc);
+                       }
+                       return result;
+               },
+               /*
+                * Check if all elements in input array are currently displayed
+                *
+                * @param       array           elements: array of element id's
+                * @return      boolean         true if all elements are displayed
+                */
+               allElementsAreDisplayed: function(elements) {
+                       var allDisplayed = true;
+                       Ext.each(elements, function (element) {
+                               allDisplayed = Ext.get(element).getStyle('display') != 'none';
+                               return allDisplayed;
+                       });
+                       return allDisplayed;
+               },
+               /*
+                * Get current size of window
+                *
+                * @return      object          width and height of window
+                */
+               getWindowSize: function () {
+                       if (Ext.isIE) {
+                               var size = Ext.getBody().getSize();
+                       } else {
+                               var size = {
+                                       width: window.innerWidth,
+                                       height: window.innerHeight
+                               };
+                       }
+                               // Subtract the docheader height from the calculated window height
+                       var docHeader = Ext.get('typo3-docheader');
+                       if (docHeader) {
+                               size.height -= docHeader.getHeight();
+                       }
+                       return size;
                }
        }
-               // final cleanup
-       editor._toolbar = null;
-       editor._htmlArea = null;
-       editor._iframe = null;
-};
-
-/*
- * Get editor mode
- */
-HTMLArea.prototype.getMode = function() {
-       return this.getPluginInstance("EditorMode").getEditorMode();
-};
-
-/*
- * Initialize iframe content when in full page mode
- */
-HTMLArea.prototype.setFullHTML = function(html) {
-       var save_multiline = RegExp.multiline;
-       RegExp.multiline = true;
-       if(html.match(HTMLArea.RE_doctype)) {
-               this.setDoctype(RegExp.$1);
-               html = html.replace(HTMLArea.RE_doctype, "");
-       };
-       RegExp.multiline = save_multiline;
-       if(!HTMLArea.is_ie) {
-               if(html.match(HTMLArea.RE_head)) this._doc.getElementsByTagName("head")[0].innerHTML = RegExp.$1;
-               if(html.match(HTMLArea.RE_body)) this._doc.getElementsByTagName("body")[0].innerHTML = RegExp.$1;
-       } else {
-               var html_re = /<html>((.|\n)*?)<\/html>/i;
-               html = html.replace(html_re, "$1");
-               this._doc.open();
-               this._doc.write(html);
-               this._doc.close();
-               this._doc.body.contentEditable = true;
-               return true;
-       };
-};
-
+}();
 /***************************************************
  *  PLUGINS, STYLESHEETS, AND IMAGE AND POPUP URL'S
  ***************************************************/
-
 /*
  * Instantiate the specified plugin and register it with the editor
  *
@@ -1398,7 +2317,7 @@ HTMLArea.prototype.setFullHTML = function(html) {
  *
  * @return     boolean         true if the plugin was successfully registered
  */
-HTMLArea.prototype.registerPlugin = function(plugin) {
+HTMLArea.Editor.prototype.registerPlugin = function(plugin) {
        var pluginName = plugin;
        if (typeof(plugin) === "string") {
                try {
@@ -1429,16 +2348,6 @@ HTMLArea.prototype.registerPlugin = function(plugin) {
 };
 
 /*
- * Get the instance of the specified plugin, if it exists
- *
- * @param      string          pluginName: the name of the plugin
- * @return     object          the plugin instance or null
- */
-HTMLArea.prototype.getPluginInstance = function(pluginName) {
-       return (this.plugins[pluginName] ? this.plugins[pluginName].instance : null);
-};
-
-/*
  * Load the required plugin script
  */
 HTMLArea.loadPlugin = function (pluginName, url, asynchronous) {
@@ -1468,7 +2377,7 @@ HTMLArea.loadStyle = function(style, plugin, url) {
 /*
  * Get the url of some image
  */
-HTMLArea.prototype.imgURL = function(file, plugin) {
+HTMLArea.Editor.prototype.imgURL = function(file, plugin) {
        if (typeof(plugin) == "undefined") return _editor_skin + this.config.imgURL + file;
                else return _editor_skin + this.config.imgURL + plugin + "/" + file;
 };
@@ -1476,7 +2385,7 @@ HTMLArea.prototype.imgURL = function(file, plugin) {
 /*
  * Get the url of some popup
  */
-HTMLArea.prototype.popupURL = function(file) {
+HTMLArea.Editor.prototype.popupURL = function(file) {
        var url = "";
        if(file.match(/^plugin:\/\/(.*?)\/(.*)/)) {
                var pluginId = RegExp.$1;
@@ -1509,36 +2418,22 @@ HTMLArea.getInnerText = function(el) {
        return txt;
 };
 
-HTMLArea.prototype.forceRedraw = function() {
-       this._doc.body.style.visibility = "hidden";
-       this._doc.body.style.visibility = "visible";
+HTMLArea.Editor.prototype.forceRedraw = function() {
+       this.htmlArea.doLayout();
 };
 
 /*
- * Focus the editor iframe document or the textarea.
+ * Focus the editor iframe window or the textarea.
  */
-HTMLArea.prototype.focusEditor = function() {
-       switch (this.getMode()) {
-               case "wysiwyg" :
-                       try {
-                               if (HTMLArea.is_safari) {
-                                       this._iframe.focus();
-                               } else {
-                                       this._iframe.contentWindow.focus();
-                               }
-                       } catch(e) { }
-                       break;
-               case "textmode":
-                       this._textArea.focus();
-                       break;
-       }
-       return this._doc;
+HTMLArea.Editor.prototype.focusEditor = function() {
+       this.focus();
+       return this.document;
 };
 
 /*
  * Check if any plugin has an opened window
  */
-HTMLArea.prototype.hasOpenedWindow = function () {
+HTMLArea.Editor.prototype.hasOpenedWindow = function () {
        for (var plugin in this.plugins) {
                if (this.plugins.hasOwnProperty(plugin)) {
                        if (HTMLArea.Dialog[plugin.name] && HTMLArea.Dialog[plugin.name].hasOpenedWindow && HTMLArea.Dialog[plugin.name].hasOpenedWindow()) {
@@ -1548,111 +2443,9 @@ HTMLArea.prototype.hasOpenedWindow = function () {
        }
        return false
 };
-
-/*
- * Update the enabled/disabled/active state of the toolbar elements
- */
-HTMLArea.updateToolbar = function(editorNumber) {
-       var editor = RTEarea[editorNumber]["editor"];
-       editor.updateToolbar();
-       editor._timerToolbar = null;
-};
-
-HTMLArea.prototype.updateToolbar = function(noStatus) {
-       var doc = this._doc,
-               initialToolbarHeight = this.getDimensions().toolbar.height,
-               text = (this.getMode() == "textmode"),
-               selection = false,
-               ancestors = null,
-               inContext, match, matchAny, k, j, n, commandState;
-       if (!text) {
-               selection = !this._selectionEmpty(this._getSelection());
-               ancestors = this.getAllAncestors();
-       }
-       for (var cmd in this._toolbarObjects) {
-               if (this._toolbarObjects.hasOwnProperty(cmd)) {
-                       var btn = this._toolbarObjects[cmd];
-                               // Determine if the button should be enabled
-                       inContext = true;
-                       if (btn.context && !text) {
-                               inContext = false;
-                               var attrs = [];
-                               var contexts = [];
-                               if (/(.*)\[(.*?)\]/.test(btn.context)) {
-                                       contexts = RegExp.$1.split(",");
-                                       attrs = RegExp.$2.split(",");
-                               } else {
-                                       contexts = btn.context.split(",");
-                               }
-                               for (j = contexts.length; --j >= 0;) contexts[j] = contexts[j].toLowerCase();
-                               matchAny = (contexts[0] == "*");
-                               for (k = 0; k < ancestors.length; ++k) {
-                                       if (!ancestors[k]) continue;
-                                       match = false;
-                                       for (j = contexts.length; --j >= 0;) match = match || (ancestors[k].tagName.toLowerCase() == contexts[j]);
-                                       if (matchAny || match) {
-                                               inContext = true;
-                                               for (j = attrs.length; --j >= 0;) {
-                                                       if (!eval("ancestors[k]." + attrs[j])) {
-                                                               inContext = false;
-                                                               break;
-                                                       }
-                                               }
-                                               if (inContext) break;
-                                       }
-                               }
-                       }
-
-                       if (cmd == "CreateLink") {
-                               btn.state("enabled", (!text || btn.text) && (inContext || selection));
-                       } else {
-                               btn.state("enabled", (!text || btn.text) && inContext && (selection || !btn.selection));
-                       }
-                       if (typeof(cmd) == "function") { continue; };
-                               // look-it-up in the custom dropdown boxes
-                       var dropdown = this.config.customSelects[cmd];
-                       if ((!text || btn.text) && (typeof(dropdown) !== "undefined") && (typeof(dropdown.refresh) === "function")) {
-                               dropdown.refresh(this, cmd);
-                               continue;
-                       }
-                       switch (cmd) {
-                               case "TextIndicator":
-                                       if(!text) {
-                                               try {with (document.getElementById(btn.elementId).style) {
-                                                       backgroundColor = HTMLArea._makeColor(doc.queryCommandValue((HTMLArea.is_ie || HTMLArea.is_safari) ? "BackColor" : "HiliteColor"));
-                                                               // Mozilla
-                                                       if(/transparent/i.test(backgroundColor)) { backgroundColor = HTMLArea._makeColor(doc.queryCommandValue("BackColor")); }
-                                                       color = HTMLArea._makeColor(doc.queryCommandValue("ForeColor"));
-                                                       fontFamily = doc.queryCommandValue("FontName");
-                                                               // Check if queryCommandState is available
-                                                       fontWeight = "normal";
-                                                       fontStyle = "normal";
-                                                       try { fontWeight = doc.queryCommandState("Bold") ? "bold" : "normal"; } catch(ex) { fontWeight = "normal"; };
-                                                       try { fontStyle = doc.queryCommandState("Italic") ? "italic" : "normal"; } catch(ex) { fontStyle = "normal"; };
-                                               }} catch (e) {
-                                                       // alert(e + "\n\n" + cmd);
-                                               }
-                                       }
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-       }
-       
-       for (var pluginId in this.plugins) {
-               if (this.plugins.hasOwnProperty(pluginId)) {
-                       var pluginInstance = this.plugins[pluginId].instance;
-                       if (typeof(pluginInstance.onUpdateToolbar) === "function") {
-                               pluginInstance.onUpdateToolbar();
-                       }
-               }
-       }
-       if (this.getDimensions().toolbar.height != initialToolbarHeight) {
-               this.sizeIframe(2);
-       }
+HTMLArea.Editor.prototype.updateToolbar = function(noStatus) {
+       this.toolbar.update(noStatus);
 };
-
 /***************************************************
  *  DOM TREE MANIPULATION
  ***************************************************/
@@ -1661,15 +2454,15 @@ HTMLArea.prototype.updateToolbar = function(noStatus) {
  * Surround the currently selected HTML source code with the given tags.
  * Delete the selection, if any.
  */
-HTMLArea.prototype.surroundHTML = function(startTag,endTag) {
+HTMLArea.Editor.prototype.surroundHTML = function(startTag,endTag) {
        this.insertHTML(startTag + this.getSelectedHTML().replace(HTMLArea.Reg_body, "") + endTag);
 };
 
 /*
  * Change the tag name of a node.
  */
-HTMLArea.prototype.convertNode = function(el,newTagName) {
-       var newel = this._doc.createElement(newTagName), p = el.parentNode;
+HTMLArea.Editor.prototype.convertNode = function(el,newTagName) {
+       var newel = this.document.createElement(newTagName), p = el.parentNode;
        while (el.firstChild) newel.appendChild(el.firstChild);
        p.insertBefore(newel, el);
        p.removeChild(el);
@@ -1692,7 +2485,7 @@ HTMLArea.getElementObject = function(el,tagName) {
  *
  * @return     void
  */
-HTMLArea.prototype.removeMarkup = function(element) {
+HTMLArea.Editor.prototype.removeMarkup = function(element) {
        var bookmark = this.getBookmark(this._createRange(this._getSelection()));
        var parent = element.parentNode;
        while (element.firstChild) {
@@ -1732,28 +2525,28 @@ HTMLArea.hasAllowedAttributes = function(element,allowedAttributes) {
 /*
  * Return true if we have some selected content
  */
-HTMLArea.prototype.hasSelectedText = function() {
+HTMLArea.Editor.prototype.hasSelectedText = function() {
        return this.getSelectedHTML() != "";
 };
 
 /*
  * Get an array with all the ancestor nodes of the selection.
  */
-HTMLArea.prototype.getAllAncestors = function() {
+HTMLArea.Editor.prototype.getAllAncestors = function() {
        var p = this.getParentElement();
        var a = [];
        while (p && (p.nodeType === 1) && (p.nodeName.toLowerCase() !== "body")) {
                a.push(p);
                p = p.parentNode;
        }
-       a.push(this._doc.body);
+       a.push(this.document.body);
        return a;
 };
 
 /*
  * Get the block ancestors of an element within a given block
  */
-HTMLArea.prototype.getBlockAncestors = function(element, withinBlock) {
+HTMLArea.Editor.prototype.getBlockAncestors = function(element, withinBlock) {
        var ancestors = new Array();
        var ancestor = element;
        while (ancestor && (ancestor.nodeType === 1) && !/^(body)$/i.test(ancestor.nodeName) && ancestor != withinBlock) {
@@ -1769,9 +2562,9 @@ HTMLArea.prototype.getBlockAncestors = function(element, withinBlock) {
 /*
  * Get the block elements containing the start and the end points of the selection
  */
-HTMLArea.prototype.getEndBlocks = function(selection) {
+HTMLArea.Editor.prototype.getEndBlocks = function(selection) {
        var range = this._createRange(selection);
-       if (HTMLArea.is_gecko) {
+       if (!Ext.isIE) {
                var parentStart = range.startContainer;
                var parentEnd = range.endContainer;
        } else {