Added feature #16257: htmlArea RTE: Rewrite stylesheets parsing functions
authorStanislas Rolland <typo3@sjbr.ca>
Fri, 5 Nov 2010 03:48:07 +0000 (03:48 +0000)
committerStanislas Rolland <typo3@sjbr.ca>
Fri, 5 Nov 2010 03:48:07 +0000 (03:48 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@9281 709f56b5-9817-0410-a4d7-c38de5d9e867

ChangeLog
typo3/sysext/rtehtmlarea/ChangeLog
typo3/sysext/rtehtmlarea/htmlarea/htmlarea-gecko.js
typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/BlockElements/block-elements.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/BlockStyle/block-style.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/InlineElements/inline-elements.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/Language/language.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-checker.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/TableOperations/table-operations.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/TextStyle/text-style.js

index 4ccbe3d..efe0de7 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2010-11-04  Stanislas Rolland  <typo3@sjbr.ca>
+
+       * Added feature #16257: htmlArea RTE: Rewrite stylesheets parsing functions
+
 2010-11-04  Susanne Moog <typo3@susanne-moog.de>
 
        * Added feature #1333: stdWrap.age should differenciate between singular/plural
index 0fc8f7d..1f5a513 100644 (file)
@@ -1,3 +1,7 @@
+2010-11-04  Stanislas Rolland  <typo3@sjbr.ca>
+
+       * Added feature #16257: htmlArea RTE: Rewrite stylesheets parsing functions
+
 2010-11-03  Stanislas Rolland  <typo3@sjbr.ca>
 
        * Fixed bug #16175: htmlArea RTE: The path of classesAnchor images are modified when saving
index a0b7668..1b9a56e 100644 (file)
@@ -481,13 +481,13 @@ HTMLArea.Editor.prototype.cleanAppleStyleSpans = function(node) {
                } else {
                        var spans = node.getElementsByTagName("span");
                        for (var i = spans.length; --i >= 0;) {
-                               if (HTMLArea._hasClass(spans[i], "Apple-style-span")) {
+                               if (HTMLArea.DOM.hasClass(spans[i], "Apple-style-span")) {
                                        this.removeMarkup(spans[i]);
                                }
                        }
                        var fonts = node.getElementsByTagName("font");
                        for (i = fonts.length; --i >= 0;) {
-                               if (HTMLArea._hasClass(fonts[i], "Apple-style-span")) {
+                               if (HTMLArea.DOM.hasClass(fonts[i], "Apple-style-span")) {
                                        this.removeMarkup(fonts[i]);
                                }
                        }
index 46b6db3..8a28ab6 100644 (file)
        // Avoid re-initialization on AJax call when HTMLArea object was already initialized
 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');
-/***************************************************
- *  CONSTANTS
- ***************************************************/
+Ext.namespace('HTMLArea.CSS', 'HTMLArea.util.TYPO3', 'HTMLArea.util.Tips', 'HTMLArea.util.Color', 'Ext.ux.form', 'Ext.ux.menu', 'Ext.ux.Toolbar');
 Ext.apply(HTMLArea, {
        /*************************************************************************
         * THESE BROWSER IDENTIFICATION CONSTANTS ARE DEPRECATED AS OF TYPO3 4.4 *
@@ -51,7 +48,9 @@ Ext.apply(HTMLArea, {
        is_safari       : Ext.isWebKit,
        is_chrome       : Ext.isChrome,
        is_opera        : Ext.isOpera,
-               // Compile some regular expressions
+       /***************************************************
+        * COMPILED REGULAR EXPRESSIONS                    *
+        ***************************************************/
        RE_htmlTag              : /<.[^<>]*?>/g,
        RE_tagName              : /(<\/|<)\s*([^ \t\n>]+)/ig,
        RE_head                 : /<head>((.|\n)*?)<\/head>/i,
@@ -63,38 +62,47 @@ Ext.apply(HTMLArea, {
        RE_blockTags            : /^(body|p|h1|h2|h3|h4|h5|h6|ul|ol|pre|dl|dt|dd|div|noscript|blockquote|form|hr|table|caption|fieldset|address|td|tr|th|li|tbody|thead|tfoot|iframe)$/i,
        RE_closingTags          : /^(p|blockquote|a|li|ol|ul|dl|dt|td|th|tr|tbody|thead|tfoot|caption|colgroup|table|div|b|bdo|big|cite|code|del|dfn|em|i|ins|kbd|label|q|samp|small|span|strike|strong|sub|sup|tt|u|var|abbr|acronym|font|center|object|embed|style|script|title|head)$/i,
        RE_noClosingTag         : /^(img|br|hr|col|input|area|base|link|meta|param)$/i,
-       RE_numberOrPunctuation  : /[0-9.(),;:!¡?¿%#$'"_+=\\\/-]*/g
-});
-/***************************************************
- *  TROUBLESHOOTING
- ***************************************************/
-HTMLArea._appendToLog = function(str){
-       if (HTMLArea.enableDebugMode) {
-               var log = document.getElementById('HTMLAreaLog');
-               if(log) {
-                       log.appendChild(document.createTextNode(str));
-                       log.appendChild(document.createElement('br'));
+       RE_numberOrPunctuation  : /[0-9.(),;:!¡?¿%#$'"_+=\\\/-]*/g,
+       /***************************************************
+        * TROUBLESHOOTING                                 *
+        ***************************************************/
+       _appendToLog: function(str){
+               if (HTMLArea.enableDebugMode) {
+                       var log = document.getElementById('HTMLAreaLog');
+                       if(log) {
+                               log.appendChild(document.createTextNode(str));
+                               log.appendChild(document.createElement('br'));
+                       }
                }
+       },
+       appendToLog: function (editorId, objectName, functionName, text) {
+               HTMLArea._appendToLog(editorId + '[' + objectName + '::' + functionName + ']: ' + text);
+       },
+       /***************************************************
+        * LOCALIZATION                                    *
+        ***************************************************/
+       localize: function (label) {
+               return HTMLArea.I18N.dialogs[label] || HTMLArea.I18N.tooltips[label] || HTMLArea.I18N.msg[label] || label;
+       },
+       /***************************************************
+        * INITIALIZATION                                  *
+        ***************************************************/
+       init: function () {
+                       // Apply global configuration settings
+               Ext.apply(HTMLArea, RTEarea[0]);
+               Ext.applyIf(HTMLArea, {
+                       editorSkin      : HTMLArea.editorUrl + 'skins/default/',
+                       editorCSS       : HTMLArea.editorUrl + 'skins/default/htmlarea.css'
+               });
+               if (!Ext.isString(HTMLArea.editedContentCSS)) {
+                       HTMLArea.editedContentCSS = HTMLArea.editorSkin + 'htmlarea-edited-content.css';
+               }
+               HTMLArea.isReady = true;
+               HTMLArea._appendToLog("[HTMLArea::init]: Editor url set to: " + HTMLArea.editorUrl);
+               HTMLArea._appendToLog("[HTMLArea::init]: Editor skin CSS set to: " + HTMLArea.editorCSS);
+               HTMLArea._appendToLog("[HTMLArea::init]: Editor content skin CSS set to: " + HTMLArea.editedContentCSS);
        }
-};
-/***************************************************
- *  HTMLArea INITIALIZATION
- ***************************************************/
-HTMLArea.init = function() {
-               // Apply global configuration settings
-       Ext.apply(HTMLArea, RTEarea[0]);
-       Ext.applyIf(HTMLArea, {
-               editorSkin      : HTMLArea.editorUrl + 'skins/default/',
-               editorCSS       : HTMLArea.editorUrl + 'skins/default/htmlarea.css'
-       });
-       if (!Ext.isString(HTMLArea.editedContentCSS)) {
-               HTMLArea.editedContentCSS = HTMLArea.editorSkin + 'htmlarea-edited-content.css';
-       }
-       HTMLArea.isReady = true;
-       HTMLArea._appendToLog("[HTMLArea::init]: Editor url set to: " + HTMLArea.editorUrl);
-       HTMLArea._appendToLog("[HTMLArea::init]: Editor skin CSS set to: " + HTMLArea.editorCSS);
-       HTMLArea._appendToLog("[HTMLArea::init]: Editor content skin CSS set to: " + HTMLArea.editedContentCSS);
-};
+});
 /***************************************************
  *  EDITOR CONFIGURATION
  ***************************************************/
@@ -2085,6 +2093,10 @@ HTMLArea.Editor = Ext.extend(Ext.util.Observable, {
                                this.registerPlugin(plugin);
                        }
                }, this);
+                       // Create Ajax object
+               this.ajax = new HTMLArea.Ajax({
+                       editor: this
+               });
                        // Initialize keyboard input inhibit flag
                this.inhibitKeyboardInput = false;
                this.addEvents(
@@ -2423,6 +2435,17 @@ HTMLArea.Editor = Ext.extend(Ext.util.Observable, {
                document.getElementById('editorWrap' + this.editorId).style.visibility = 'visible';
        },
        /*
+        * Append an entry at the end of the troubleshooting log
+        *
+        * @param       string          functionName: the name of the editor function writing to the log
+        * @param       string          text: the text of the message
+        *
+        * @return      void
+        */
+       appendToLog: function (objectName, functionName, text) {
+               HTMLArea.appendToLog(this.editorId, objectName, functionName, text);
+       },
+       /*
         * Iframe unload handler: Update the textarea for submission and cleanup
         */
        onUnload: function (event) {
@@ -2450,6 +2473,83 @@ HTMLArea.Editor = Ext.extend(Ext.util.Observable, {
                RTEarea[this.editorId].editor = null;
        }
 });
+HTMLArea.Ajax = function (config) {
+       Ext.apply(this, config);
+};
+HTMLArea.Ajax = Ext.extend(HTMLArea.Ajax, {
+       /*
+        * Load a Javascript file asynchronously
+        *
+        * @param       string          url: url of the file to load
+        * @param       function        callBack: the callBack function
+        * @param       object          scope: scope of the callbacks
+        *
+        * @return      boolean         true on success of the request submission
+        */
+       getJavascriptFile: function (url, callback, scope) {
+               var success = false;
+               var self = this;
+               this.editor.appendToLog('HTMLArea.Ajax', 'getJavascriptFile', 'Requesting script ' + url);
+               Ext.Ajax.request({
+                       method: 'GET',
+                       url: url,
+                       callback: callback,
+                       success: function (response) {
+                               success = true;
+                       },
+                       failure: function (response) {
+                               self.editor.inhibitKeyboardInput = false;
+                               self.editor.appendToLog('HTMLArea.Ajax', 'getJavascriptFile', 'Unable to get ' + url + ' . Server reported ' + response.status);
+                       },
+                       scope: scope
+               });
+               return success;
+       },
+       /*
+        * Post data to the server
+        *
+        * @param       string          url: url to post data to
+        * @param       object          data: data to be posted
+        * @param       function        callback: function that will handle the response returned by the server
+        * @param       object          scope: scope of the callbacks
+        *
+        * @return      boolean         true on success
+        */
+       postData: function (url, data, callback, scope) {
+               var success = false;
+               var self = this;
+               data.charset = this.editor.config.typo3ContentCharset ? this.editor.config.typo3ContentCharset : 'utf-8';
+               var params = '';
+               Ext.iterate(data, function (parameter, value) {
+                       params += (params.length ? '&' : '') + parameter + '=' + encodeURIComponent(value);
+               });
+               params += this.editor.config.RTEtsConfigParams;
+               this.editor.appendToLog('HTMLArea.Ajax', 'postData', 'Posting to ' + url + '. Data: ' + params);
+               Ext.Ajax.request({
+                       method: 'POST',
+                       headers: {
+                               'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
+                       },
+                       url: url,
+                       params: params,
+                       callback: Ext.isFunction(callback) ? callback: function (options, success, response) {
+                               if (success) {
+                                       self.editor.appendToLog('HTMLArea.Ajax', 'postData', 'Post request to ' + url + ' successful. Server response: ' + response.responseText);
+                               } else {
+                                       self.editor.appendToLog('HTMLArea.Ajax', 'postData', 'Post request to ' + url + ' failed. Server reported ' + response.status);
+                               }
+                       },
+                       success: function (response) {
+                               success = true;
+                       },
+                       failure: function (response) {
+                               self.editor.appendToLog('HTMLArea.Ajax', 'postData', 'Unable to post ' + url + ' . Server reported ' + response.status);
+                       },
+                       scope: scope
+               });
+               return success;
+       }
+});
 /***************************************************
  * HTMLArea.util.TYPO3: Utility functions for dealing with tabs and inline elements in TYPO3 forms
  ***************************************************/
@@ -2929,7 +3029,6 @@ HTMLArea.Editor.prototype.scrollToCaret = function() {
 HTMLArea.checkSupportedBrowser = function() {
        return Ext.isGecko || Ext.isWebKit || Ext.isOpera || Ext.isIE;
 };
-
 /*
  * Remove a class name from the class attribute of an element
  *
@@ -2937,51 +3036,22 @@ HTMLArea.checkSupportedBrowser = function() {
  * @param      string          className: the class name to remove
  * @param      boolean         substring: if true, remove the first class name starting with the given string
  * @return     void
+ ***********************************************
+ * THIS FUNCTION IS DEPRECATED AS OF TYPO3 4.5 *
+ ***********************************************
  */
 HTMLArea._removeClass = function(el, className, substring) {
-       if (!el || !el.className) return;
-       var classes = el.className.trim().split(" ");
-       var newClasses = new Array();
-       for (var i = classes.length; --i >= 0;) {
-               if (!substring) {
-                       if (classes[i] != className) {
-                               newClasses[newClasses.length] = classes[i];
-                       }
-               } else if (classes[i].indexOf(className) != 0) {
-                       newClasses[newClasses.length] = classes[i];
-               }
-       }
-       if (newClasses.length == 0) {
-               if (!Ext.isOpera) {
-                       el.removeAttribute("class");
-                       if (Ext.isIE) {
-                               el.removeAttribute("className");
-                       }
-               } else {
-                       el.className = '';
-               }
-       } else {
-               el.className = newClasses.join(" ");
-       }
+       HTMLArea.DOM.removeClass(el, className, substring);
 };
-
 /*
  * Add a class name to the class attribute
+ ***********************************************
+ * THIS FUNCTION IS DEPRECATED AS OF TYPO3 4.5 *
+ ***********************************************
  */
-HTMLArea._addClass = function(el, addClassName) {
-       HTMLArea._removeClass(el, addClassName);
-       if (el.className && HTMLArea.classesXOR && HTMLArea.classesXOR.hasOwnProperty(addClassName) && typeof(HTMLArea.classesXOR[addClassName].test) == "function") {
-               var classNames = el.className.trim().split(" ");
-               for (var i = classNames.length; --i >= 0;) {
-                       if (HTMLArea.classesXOR[addClassName].test(classNames[i])) {
-                               HTMLArea._removeClass(el, classNames[i]);
-                       }
-               }
-       }
-       if (el.className) el.className += " " + addClassName;
-               else el.className = addClassName;
+HTMLArea._addClass = function(el, className) {
+       HTMLArea.DOM.addClass(el, className);
 };
-
 /*
  * Check if a class name is in the class attribute of an element
  *
@@ -2989,14 +3059,12 @@ HTMLArea._addClass = function(el, addClassName) {
  * @param      string          className: the class name to look for
  * @param      boolean         substring: if true, look for a class name starting with the given string
  * @return     boolean         true if the class name was found
+ ***********************************************
+ * THIS FUNCTION IS DEPRECATED AS OF TYPO3 4.5 *
+ ***********************************************
  */
 HTMLArea._hasClass = function(el, className, substring) {
-       if (!el || !el.className) return false;
-       var classes = el.className.trim().split(" ");
-       for (var i = classes.length; --i >= 0;) {
-               if (classes[i] == className || (substring && classes[i].indexOf(className) == 0)) return true;
-       }
-       return false;
+       return HTMLArea.DOM.hasClass(el, className, substring);
 };
 
 HTMLArea.isBlockElement = function(el) { return el && el.nodeType == 1 && HTMLArea.RE_blockTags.test(el.nodeName.toLowerCase()); };
@@ -3069,11 +3137,11 @@ HTMLArea.removeFromParent = function(el) {
 /*****************************************************************
  * HTMLArea.DOM: Utility functions for dealing with the DOM tree *
  *****************************************************************/
-/***************************************************
- *  DOM-RELATED CONSTANTS
- ***************************************************/
 HTMLArea.DOM = function () {
        return {
+               /***************************************************
+               *  DOM-RELATED CONSTANTS
+               ***************************************************/
                        // DOM node types
                ELEMENT_NODE: 1,
                ATTRIBUTE_NODE: 2,
@@ -3086,7 +3154,110 @@ HTMLArea.DOM = function () {
                DOCUMENT_NODE: 9,
                DOCUMENT_TYPE_NODE: 10,
                DOCUMENT_FRAGMENT_NODE: 11,
-               NOTATION_NODE: 12
+               NOTATION_NODE: 12,
+               /*
+                * Gets the class names assigned to a node, reserved classes removed
+                *
+                * @param       object          node: the node
+                * @return      array           array of class names on the node, reserved classes removed
+                */
+               getClassNames: function (node) {
+                       var classNames = [];
+                       if (node) {
+                               if (node.className && /\S/.test(node.className)) {
+                                       classNames = node.className.trim().split(' ');
+                               }
+                               if (HTMLArea.reservedClassNames.test(node.className)) {
+                                       var cleanClassNames = [];
+                                       var j = -1;
+                                       for (var i = 0; i < classNames.length; ++i) {
+                                               if (!HTMLArea.reservedClassNames.test(classNames[i])) {
+                                                       cleanClassNames[++j] = classNames[i];
+                                               }
+                                       }
+                                       classNames = cleanClassNames;
+                               }
+                       }
+                       return classNames;
+               },
+               /*
+                * Check if a class name is in the class attribute of a node
+                *
+                * @param       object          node: the node
+                * @param       string          className: the class name to look for
+                * @param       boolean         substring: if true, look for a class name starting with the given string
+                * @return      boolean         true if the class name was found, false otherwise
+                */
+               hasClass: function (node, className, substring) {
+                       var found = false;
+                       if (node && node.className) {
+                               var classes = node.className.trim().split(' ');
+                               for (var i = classes.length; --i >= 0;) {
+                                       found = ((classes[i] == className) || (substring && classes[i].indexOf(className) == 0));
+                                       if (found) {
+                                               break;
+                                       }
+                               }
+                       }
+                       return found;
+               },
+               /*
+                * Add a class name to the class attribute of a node
+                *
+                * @param       object          node: the node
+                * @param       string          className: the name of the class to be added
+                * @return      void
+                */
+               addClass: function (node, className) {
+                       if (node) {
+                               HTMLArea.DOM.removeClass(node, className);
+                                       // Remove classes configured to be incompatible with the class to be added
+                               if (node.className && HTMLArea.classesXOR && HTMLArea.classesXOR[className] && Ext.isFunction(HTMLArea.classesXOR[className].test)) {
+                                       var classNames = node.className.trim().split(' ');
+                                       for (var i = classNames.length; --i >= 0;) {
+                                               if (HTMLArea.classesXOR[className].test(classNames[i])) {
+                                                       HTMLArea.DOM.removeClass(node, classNames[i]);
+                                               }
+                                       }
+                               }
+                               if (node.className) {
+                                       node.className += ' ' + className;
+                               } else {
+                                       node.className = className;
+                               }
+                       }
+               },
+               /*
+                * Remove a class name from the class attribute of a node
+                *
+                * @param       object          node: the node
+                * @param       string          className: the class name to removed
+                * @param       boolean         substring: if true, remove the class names starting with the given string
+                * @return      void
+                */
+               removeClass: function (node, className, substring) {
+                       if (node && node.className) {
+                               var classes = node.className.trim().split(' ');
+                               var newClasses = [];
+                               for (var i = classes.length; --i >= 0;) {
+                                       if ((!substring && classes[i] != className) || (substring && classes[i].indexOf(className) != 0)) {
+                                               newClasses[newClasses.length] = classes[i];
+                                       }
+                               }
+                               if (newClasses.length) {
+                                       node.className = newClasses.join(' ');
+                               } else {
+                                       if (!Ext.isOpera) {
+                                               node.removeAttribute('class');
+                                               if (Ext.isIE) {
+                                                       node.removeAttribute('className');
+                                               }
+                                       } else {
+                                               node.className = '';
+                                       }
+                               }
+                       }
+               }
        };
 }();
 /***************************************************
@@ -3101,7 +3272,7 @@ HTMLArea.DOM.Walker = function (config) {
                keepTags: /.*/i,
                removeAttributes: /none/i,
                removeTrailingBR: true
-       }
+       };
        Ext.apply(this, config, configDefaults);
 };
 HTMLArea.DOM.Walker = Ext.extend(HTMLArea.DOM.Walker, {
@@ -3303,6 +3474,304 @@ HTMLArea.DOM.Walker = Ext.extend(HTMLArea.DOM.Walker, {
        }
 });
 /***************************************************
+ *  HTMLArea.CSS.Parser: CSS Parser
+ ***************************************************/
+HTMLArea.CSS.Parser = Ext.extend(Ext.util.Observable, {
+       /*
+        * HTMLArea.CSS.Parser constructor
+        */
+       constructor: function (config) {
+               HTMLArea.CSS.Parser.superclass.constructor.call(this, {});
+               var configDefaults = {
+                       parseAttemptsMaximumNumber: 17,
+                       prefixLabelWithClassName: false,
+                       postfixLabelWithClassName: false,
+                       showTagFreeClasses: false,
+                       tags: null,
+                       editor: null
+               };
+               Ext.apply(this, config, configDefaults);
+               this.addEvents(
+                       /*
+                        * @event HTMLAreaEventCssParsingComplete
+                        * Fires when parsing of the stylesheets of the iframe is complete
+                        */
+                       'HTMLAreaEventCssParsingComplete'
+               );
+       },
+       /*
+        * The parsed classes
+        */
+       parsedClasses: {},
+       /*
+        * Boolean indicating whether are not parsing is complete
+        */
+       isReady: false,
+       /*
+        * Boolean indicating whether or not the stylesheets were accessible
+        */
+       cssLoaded: false,
+       /*
+        * Counter of the number of attempts at parsing the stylesheets
+        */
+       parseAttemptsCounter: 0,
+       /*
+        * Parsing attempt timeout id
+        */
+       attemptTimeout: null,
+       /*
+        * The error that occurred on the last attempt at parsing the stylesheets
+        */
+       error: null,
+       /*
+        * This function gets the parsed css classes
+        *
+        * @return      object  this.parsedClasses
+        */
+       getClasses: function() {
+               return this.parsedClasses;
+       },
+       /*
+        * This function initiates parsing of the stylesheets
+        *
+        * @return      void
+        */
+       initiateParsing: function () {
+               if (this.editor.config.classesUrl && (typeof(HTMLArea.classesLabels) === 'undefined')) {
+                       this.editor.ajax.getJavascriptFile(this.editor.config.classesUrl, function (options, success, response) {
+                               if (success) {
+                                       try {
+                                               if (typeof(HTMLArea.classesLabels) === 'undefined') {
+                                                       eval(response.responseText);
+                                                       this.editor.appendToLog('HTMLArea.CSS.Parser', 'initiateParsing', 'Javascript file successfully evaluated: ' + this.editor.config.classesUrl);
+                                               }
+                                       } catch(e) {
+                                               this.editor.appendToLog('HTMLArea.CSS.Parser', 'initiateParsing', 'Error evaluating contents of Javascript file: ' + this.editor.config.classesUrl);
+                                       }
+                               }
+                               this.parse();
+                       }, this);
+               } else {
+                       this.parse();
+               }
+       },
+       /*
+        * This function parses the stylesheets of the iframe set in config
+        *
+        * @return      void    parsed css classes are accumulated in this.parsedClasses
+        */
+       parse: function() {
+               if (this.editor.document) {
+                       this.parseStyleSheets();
+                       if (!this.cssLoaded) {
+                               if (this.parseAttemptsCounter < this.parseAttemptsMaximumNumber) {
+                                       this.attemptTimeout = this.parse.defer(200, this);
+                                       this.parseAttemptsCounter++;
+                               } else {
+                                       this.editor.appendToLog('HTMLArea.CSS.Parser', 'parse', 'The stylesheets could not be parsed. Reported error: ' + this.error);
+                                       this.fireEvent('HTMLAreaEventCssParsingComplete');
+                               }
+                       } else {
+                               this.attemptTimeout = null;
+                               this.isReady = true;
+                               this.filterAllowedClasses();
+                               this.sort();
+                               this.fireEvent('HTMLAreaEventCssParsingComplete');
+                       }
+               }
+       },
+       /*
+        * This function parses the stylesheets of an iframe
+        *
+        * @return      void    parsed css classes are accumulated in this.parsedClasses
+        */
+       parseStyleSheets: function () {
+               this.cssLoaded = true;
+               this.error = null;
+               for (var i = 0; i < this.editor.document.styleSheets.length; i++) {
+                       if (!Ext.isIE) {
+                               try {
+                                       this.parseRules(this.editor.document.styleSheets[i].cssRules);
+                               } catch (e) {
+                                       this.error = e;
+                                       this.cssLoaded = false;
+                                       this.parsedClasses = {};
+                               }
+                       } else {
+                               try{
+                                       if (this.editor.document.styleSheets[i].imports) {
+                                               this.parseIeRules(this.editor.document.styleSheets[i].imports);
+                                       }
+                                       if (this.editor.document.styleSheets[i].rules) {
+                                               this.parseRules(this.editor.document.styleSheets[i].rules);
+                                       }
+                               } catch (e) {
+                                       this.error = e;
+                                       this.cssLoaded = false;
+                                       this.parsedClasses = {};
+                               }
+                       }
+               }
+       },
+       /*
+        * This function parses the set of rules from a standard stylesheet
+        *
+        * @param       array           cssRules: the array of rules of a stylesheet
+        * @return      void
+        */
+       parseRules: function (cssRules) {
+               for (var rule = 0; rule < cssRules.length; rule++) {
+                               // Style rule
+                       if (cssRules[rule].selectorText) {
+                               this.parseSelectorText(cssRules[rule].selectorText);
+                       } else {
+                                       // Import rule
+                               if (cssRules[rule].styleSheet) {
+                                       this.parseRules(cssRules[rule].styleSheet.cssRules);
+                               }
+                                       // Media rule
+                               if (cssRules[rule].cssRules) {
+                                       this.parseRules(cssRules[rule].cssRules);
+                               }
+                       }
+               }
+       },
+       /*
+        * This function parses the set of rules from an IE stylesheet
+        *
+        * @param       array           cssRules: the array of rules of a stylesheet
+        * @return      void
+        */
+       parseIeRules: function (cssRules) {
+               for (var rule = 0; rule < cssRules.length; rule++) {
+                               // Import rule
+                       if (cssRules[rule].imports) {
+                               this.parseIeRules(cssRules[rule].imports);
+                       }
+                               // Style rule
+                       if (cssRules[rule].rules) {
+                               this.parseRules(cssRules[rule].rules);
+                       }
+               }
+       },
+       /*
+        * This function parses a selector rule
+        *
+        * @param       string          selectorText: the text of the rule to parsed
+        * @return      void
+        */
+       parseSelectorText: function (selectorText) {
+               var cssElements = [],
+                       cssElement = [],
+                       nodeName, className,
+                       pattern = /(\S*)\.(\S+)/;
+               if (selectorText.search(/:+/) == -1) {
+                               // Split equal styles
+                       cssElements = selectorText.split(',');
+                       for (var k = 0; k < cssElements.length; k++) {
+                                       // Match all classes (<element name (optional)>.<class name>) in selector rule
+                               var s = cssElements[k], index;
+                               while ((index = s.search(pattern)) > -1) {
+                                       var match = pattern.exec(s.substring(index));
+                                       s = s.substring(index+match[0].length);
+                                       nodeName = (match[1] && (match[1] != '*')) ? match[1].toLowerCase().trim() : 'all';
+                                       className = match[2];
+                                       if (className && !HTMLArea.reservedClassNames.test(className)) {
+                                               if (((nodeName != 'all') && (!this.tags || !this.tags[nodeName]))
+                                                       || ((nodeName == 'all') && (!this.tags || !this.tags[nodeName]) && this.showTagFreeClasses)
+                                                       || (this.tags && this.tags[nodeName] && this.tags[nodeName].allowedClasses && this.tags[nodeName].allowedClasses.test(className))) {
+                                                       if (!this.parsedClasses[nodeName]) {
+                                                               this.parsedClasses[nodeName] = {};
+                                                       }
+                                                       cssName = className;
+                                                       if (HTMLArea.classesLabels && HTMLArea.classesLabels[className]) {
+                                                               cssName = this.prefixLabelWithClassName ? (className + ' - ' + HTMLArea.classesLabels[className]) : HTMLArea.classesLabels[className];
+                                                               cssName = this.postfixLabelWithClassName ? (cssName + ' - ' + className) : cssName;
+                                                       }
+                                                       this.parsedClasses[nodeName][className] = cssName;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       },
+       /*
+        * This function filters the class selectors allowed for each nodeName
+        *
+        * @return      void
+        */
+       filterAllowedClasses: function() {
+               Ext.iterate(this.tags, function (nodeName) {
+                       var allowedClasses = {};
+                               // Get classes allowed for all tags
+                       if (nodeName !== 'all' && Ext.isDefined(this.parsedClasses['all'])) {
+                               if (this.tags && this.tags[nodeName] && this.tags[nodeName].allowedClasses) {
+                                       var allowed = this.tags[nodeName].allowedClasses;
+                                       Ext.iterate(this.parsedClasses['all'], function (cssClass, value) {
+                                               if (allowed.test(cssClass)) {
+                                                       allowedClasses[cssClass] = value;
+                                               }
+                                       });
+                               } else {
+                                       allowedClasses = this.parsedClasses['all'];
+                               }
+                       }
+                               // Merge classes allowed for nodeName
+                       if (Ext.isDefined(this.parsedClasses[nodeName])) {
+                               if (this.tags && this.tags[nodeName] && this.tags[nodeName].allowedClasses) {
+                                       var allowed = this.tags[nodeName].allowedClasses;
+                                       Ext.iterate(this.parsedClasses[nodeName], function (cssClass, value) {
+                                               if (allowed.test(cssClass)) {
+                                                       allowedClasses[cssClass] = value;
+                                               }
+                                       });
+                               } else {
+                                       Ext.iterate(this.parsedClasses[nodeName], function (cssClass, value) {
+                                               allowedClasses[cssClass] = value;
+                                       });
+                               }
+                       }
+                       this.parsedClasses[nodeName] = allowedClasses;
+               }, this);
+                       // If showTagFreeClasses is set and there is no allowedClasses clause on a tag, merge classes allowed for all tags
+               if (this.showTagFreeClasses && Ext.isDefined(this.parsedClasses['all'])) {
+                       Ext.iterate(this.parsedClasses, function (nodeName) {
+                               if (nodeName !== 'all' && !this.tags[nodeName]) {
+                                       Ext.iterate(this.parsedClasses['all'], function (cssClass, value) {
+                                               this.parsedClasses[nodeName][cssClass] = value;
+                                       }, this);
+                               }
+                       }, this);
+               }
+       },
+       /*
+        * This function sorts the class selectors for each nodeName
+        *
+        * @return      void
+        */
+       sort: function() {
+               Ext.iterate(this.parsedClasses, function (nodeName, value) {
+                       var classes = [];
+                       var sortedClasses= {};
+                               // Collect keys
+                       Ext.iterate(value, function (cssClass) {
+                               classes.push(cssClass);
+                       });
+                       function compare(a, b) {
+                               x = value[a];
+                               y = value[b];
+                               return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+                       }
+                               // Sort keys by comparing texts
+                       classes = classes.sort(compare);
+                       for (var i = 0; i < classes.length; ++i) {
+                               sortedClasses[classes[i]] = value[classes[i]];
+                       }
+                       this.parsedClasses[nodeName] = sortedClasses;
+               }, this);
+       }
+});
+/***************************************************
  *  TIPS ON FORM FIELDS AND MENU ITEMS
  ***************************************************/
 /*
@@ -4156,7 +4625,7 @@ HTMLArea.Plugin = HTMLArea.Base.extend({
         * @return      string          the localization of the label
         */
        localize: function (label) {
-               return this.I18N[label] || HTMLArea.I18N.dialogs[label] || HTMLArea.I18N.tooltips[label] || HTMLArea.I18N.msg[label];
+               return this.I18N[label] || HTMLArea.localize(label);
        },
        /**
         * Load a Javascript file asynchronously
@@ -4167,22 +4636,8 @@ HTMLArea.Plugin = HTMLArea.Base.extend({
         * @return      boolean         true on success of the request submission
         */
        getJavascriptFile: function (url, callback) {
-               var success = false;
                this.appendToLog('getJavascriptFile', 'Requesting script ' + url);
-               Ext.Ajax.request({
-                       method: 'GET',
-                       url: url,
-                       callback: callback,
-                       success: function (response) {
-                               success = true;
-                       },
-                       failure: function (response) {
-                               this.editor.inhibitKeyboardInput = false;
-                               this.appendToLog('getJavascriptFile', 'Unable to get ' + url + ' . Server reported ' + response.status);
-                       },
-                       scope: this
-               });
-               return success;
+               return this.editor.ajax.getJavascriptFile(url, callback, this);
        },
        /**
         * Post data to the server
@@ -4193,39 +4648,10 @@ HTMLArea.Plugin = HTMLArea.Base.extend({
         *
         * @return      boolean         true on success
         */
-        postData: function (url, data, callback) {
-               var success = false;
-               data.charset = this.editorConfiguration.typo3ContentCharset ? this.editorConfiguration.typo3ContentCharset : 'utf-8';
-               var params = '';
-               Ext.iterate(data, function (parameter, value) {
-                       params += (params.length ? '&' : '') + parameter + '=' + encodeURIComponent(value);
-               });
-               params += this.editorConfiguration.RTEtsConfigParams;
-               this.appendToLog('postData', 'Posting to ' + url + '. Data: ' + params);
-               Ext.Ajax.request({
-                       method: 'POST',
-                       headers: {
-                               'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
-                       },
-                       url: url,
-                       params: params,
-                       callback: Ext.isFunction(callback) ? callback: function (options, success, response) {
-                               if (success) {
-                                       this.appendToLog('postData', 'Post request to ' + url + ' successful. Server response: ' + response.responseText);
-                               } else {
-                                       this.appendToLog('postData', 'Post request to ' + url + ' failed. Server reported ' + response.status);
-                               }
-                       },
-                       success: function (response) {
-                               success = true;
-                       },
-                       failure: function (response) {
-                               this.appendToLog('postData', 'Unable to post ' + url + ' . Server reported ' + response.status);
-                       },
-                       scope: this
-               });
-               return success;
-        },
+       postData: function (url, data, callback) {
+               this.appendToLog('postData', 'Posting to ' + url + '. Data: ' + params);
+               return this.editor.ajax.postData(url, data, callback, this);
+       },
        /**
         ***********************************************
         * THIS FUNCTION IS DEPRECATED AS OF TYPO3 4.4 *
@@ -4390,7 +4816,7 @@ HTMLArea.Plugin = HTMLArea.Base.extend({
         * @return      void
         */
        appendToLog: function (functionName, text) {
-               HTMLArea._appendToLog('[' + this.name + '::' + functionName + ']: ' + text);
+               this.editor.appendToLog(this.name, functionName, text);
        },
        /*
         * Add a config element to config array if not empty
index 0971af7..54bb70a 100644 (file)
@@ -373,10 +373,10 @@ HTMLArea.BlockElements = HTMLArea.Plugin.extend({
                                                this.appendToLog("onButtonPress", e + "\n\nby execCommand(" + buttonId + ");");
                                        }
                                } else if (this.isAllowedBlockElement("div")) {
-                                       if (/^div$/i.test(parentElement.nodeName) && !HTMLArea._hasClass(parentElement, this.useClass[buttonId])) {
-                                               HTMLArea._addClass(parentElement, this.useClass[buttonId]);
-                                       } else if (!/^div$/i.test(parentElement.nodeName) && /^div$/i.test(parentElement.parentNode.nodeName) && !HTMLArea._hasClass(parentElement.parentNode, this.useClass[buttonId])) {
-                                               HTMLArea._addClass(parentElement.parentNode, this.useClass[buttonId]);
+                                       if (/^div$/i.test(parentElement.nodeName) && !HTMLArea.DOM.hasClass(parentElement, this.useClass[buttonId])) {
+                                               HTMLArea.DOM.addClass(parentElement, this.useClass[buttonId]);
+                                       } else if (!/^div$/i.test(parentElement.nodeName) && /^div$/i.test(parentElement.parentNode.nodeName) && !HTMLArea.DOM.hasClass(parentElement.parentNode, this.useClass[buttonId])) {
+                                               HTMLArea.DOM.addClass(parentElement.parentNode, this.useClass[buttonId]);
                                        } else {
                                                var bookmark = this.editor.getBookmark(range);
                                                var newBlock = this.wrapSelectionInBlockElement("div", this.useClass[buttonId], null, true);
@@ -387,7 +387,7 @@ HTMLArea.BlockElements = HTMLArea.Plugin.extend({
                                }
                                break;
                        case "Outdent" :
-                               if (/^(ol|ul)$/i.test(parentElement.nodeName) && !HTMLArea._hasClass(parentElement, this.useClass.Indent)) {
+                               if (/^(ol|ul)$/i.test(parentElement.nodeName) && !HTMLArea.DOM.hasClass(parentElement, this.useClass.Indent)) {
                                        if (/^(li)$/i.test(parentElement.parentNode.nodeName)) {
                                                if (Ext.isOpera) {
                                                        try {
@@ -433,7 +433,7 @@ HTMLArea.BlockElements = HTMLArea.Plugin.extend({
                                        }
                                } else if (this.isAllowedBlockElement("div")) {
                                        for (var i = blockAncestors.length; --i >= 0;) {
-                                               if (HTMLArea._hasClass(blockAncestors[i], this.useClass.Indent)) {
+                                               if (HTMLArea.DOM.hasClass(blockAncestors[i], this.useClass.Indent)) {
                                                        var bookmark = this.editor.getBookmark(range);
                                                        var newBlock = this.wrapSelectionInBlockElement("div", false, blockAncestors[i]);
                                                                // If not directly under the div, we need to backtrack
@@ -447,7 +447,7 @@ HTMLArea.BlockElements = HTMLArea.Plugin.extend({
                                                                newBlock.appendChild(parent);
                                                        }
                                                        newBlock.className = blockAncestors[i].className;
-                                                       HTMLArea._removeClass(newBlock, this.useClass.Indent);
+                                                       HTMLArea.DOM.removeClass(newBlock, this.useClass.Indent);
                                                        if (!newBlock.previousSibling) {
                                                                while (newBlock.hasChildNodes()) {
                                                                        if (newBlock.firstChild.nodeType == 1) {
@@ -608,7 +608,7 @@ HTMLArea.BlockElements = HTMLArea.Plugin.extend({
                }
                var blockElement = this.editor._doc.createElement(blockName);
                if (useClass) {
-                       HTMLArea._addClass(blockElement, useClass);
+                       HTMLArea.DOM.addClass(blockElement, useClass);
                }
                var contextElement = endAncestors[0];
                if (i) {
@@ -664,13 +664,13 @@ HTMLArea.BlockElements = HTMLArea.Plugin.extend({
                                if (HTMLArea.isBlockElement(block)) {
                                        switch (buttonId) {
                                                case "Indent" :
-                                                       if (!HTMLArea._hasClass(block, this.useClass[buttonId])) {
-                                                               HTMLArea._addClass(block, this.useClass[buttonId]);
+                                                       if (!HTMLArea.DOM.hasClass(block, this.useClass[buttonId])) {
+                                                               HTMLArea.DOM.addClass(block, this.useClass[buttonId]);
                                                        }
                                                        break;
                                                case "Outdent" :
-                                                       if (HTMLArea._hasClass(block, this.useClass["Indent"])) {
-                                                               HTMLArea._removeClass(block, this.useClass["Indent"]);
+                                                       if (HTMLArea.DOM.hasClass(block, this.useClass["Indent"])) {
+                                                               HTMLArea.DOM.removeClass(block, this.useClass["Indent"]);
                                                        }
                                                        break;
                                                case "JustifyLeft"   :
@@ -683,7 +683,7 @@ HTMLArea.BlockElements = HTMLArea.Plugin.extend({
                                                        if (this.standardBlockElements.test(buttonId.toLowerCase()) && buttonId.toLowerCase() == block.nodeName.toLowerCase()) {
                                                                this.cleanClasses(block);
                                                                if (className) {
-                                                                       HTMLArea._addClass(block, className);
+                                                                       HTMLArea.DOM.addClass(block, className);
                                                                }
                                                        }
                                                        break;
@@ -702,10 +702,10 @@ HTMLArea.BlockElements = HTMLArea.Plugin.extend({
        toggleAlignmentClass : function(block, buttonId) {
                for (var alignmentButtonId in this.useClass) {
                        if (this.useClass.hasOwnProperty(alignmentButtonId) && alignmentButtonId !== "Indent") {
-                               if (HTMLArea._hasClass(block, this.useClass[alignmentButtonId])) {
-                                       HTMLArea._removeClass(block, this.useClass[alignmentButtonId]);
+                               if (HTMLArea.DOM.hasClass(block, this.useClass[alignmentButtonId])) {
+                                       HTMLArea.DOM.removeClass(block, this.useClass[alignmentButtonId]);
                                } else if (alignmentButtonId === buttonId) {
-                                       HTMLArea._addClass(block, this.useClass[alignmentButtonId]);
+                                       HTMLArea.DOM.addClass(block, this.useClass[alignmentButtonId]);
                                }
                        }
                }
@@ -997,15 +997,15 @@ HTMLArea.BlockElements = HTMLArea.Plugin.extend({
                        if (!HTMLArea.reservedClassNames.test(classNames[i])) {
                                if (this.tags && this.tags[nodeName] && this.tags[nodeName].allowedClasses) {
                                        if (!this.tags[nodeName].allowedClasses.test(classNames[i])) {
-                                               HTMLArea._removeClass(node, classNames[i]);
+                                               HTMLArea.DOM.removeClass(node, classNames[i]);
                                        }
                                } else if (this.tags && this.tags.all && this.tags.all.allowedClasses) {
                                        if (!this.tags.all.allowedClasses.test(classNames[i])) {
-                                               HTMLArea._removeClass(node, classNames[i]);
+                                               HTMLArea.DOM.removeClass(node, classNames[i]);
                                        }
                                }
                                if (this.formatBlockItems[nodeName] && this.formatBlockItems[nodeName].classList && this.formatBlockItems[nodeName].classList.test(classNames[i])) {
-                                       HTMLArea._removeClass(node, classNames[i]);
+                                       HTMLArea.DOM.removeClass(node, classNames[i]);
                                }
                        }
                }
@@ -1050,7 +1050,7 @@ HTMLArea.BlockElements = HTMLArea.Plugin.extend({
                                                        commandState = true;
                                                } else {
                                                        for (var j = blockAncestors.length; --j >= 0;) {
-                                                               if (HTMLArea._hasClass(blockAncestors[j], this.useClass.Indent) || /^(td|th)$/i.test(blockAncestors[j].nodeName)) {
+                                                               if (HTMLArea.DOM.hasClass(blockAncestors[j], this.useClass.Indent) || /^(td|th)$/i.test(blockAncestors[j].nodeName)) {
                                                                        commandState = true;
                                                                        break;
                                                                }
@@ -1090,7 +1090,7 @@ HTMLArea.BlockElements = HTMLArea.Plugin.extend({
                                                                button.setDisabled(false);
                                                                commandState = true;
                                                                for (var block = startAncestors[index]; block; block = block.nextSibling) {
-                                                                       commandState = commandState && HTMLArea._hasClass(block, this.useClass[button.itemId]);
+                                                                       commandState = commandState && HTMLArea.DOM.hasClass(block, this.useClass[button.itemId]);
                                                                        if (block == endAncestors[index]) {
                                                                                break;
                                                                        }
@@ -1159,7 +1159,7 @@ HTMLArea.BlockElements = HTMLArea.Plugin.extend({
                                // Could be a custom item ...
                        index = store.findBy(function(record, id) {
                                var item = this.formatBlockItems[record.get('value')];
-                               return item && item.tagName == nodeName && item.addClass && HTMLArea._hasClass(deepestBlockAncestor, item.addClass);
+                               return item && item.tagName == nodeName && item.addClass && HTMLArea.DOM.hasClass(deepestBlockAncestor, item.addClass);
                        }, this);
                        if (index == -1) {
                                        // ... or a standard one
index 9e5b953..0fb74d5 100644 (file)
  * TYPO3 SVN ID: $Id$
  */
 HTMLArea.BlockStyle = HTMLArea.Plugin.extend({
-               
        constructor : function(editor, pluginName) {
                this.base(editor, pluginName);
        },
-       
        /*
         * This function gets called by the class constructor
         */
-       configurePlugin : function(editor) {
-               this.cssLoaded = false;
-               this.cssTimeout = null;
-               this.cssParseCount = 0;
-               this.cssArray = new Object();
-               
+       configurePlugin: function (editor) {
+               this.cssArray = {};
                this.classesUrl = this.editorConfiguration.classesUrl;
                this.pageTSconfiguration = this.editorConfiguration.buttons.blockstyle;
                this.tags = this.pageTSconfiguration.tags;
@@ -95,21 +89,19 @@ HTMLArea.BlockStyle = HTMLArea.Plugin.extend({
                this.showTagFreeClasses = this.pageTSconfiguration.showTagFreeClasses || this.editorConfiguration.showTagFreeClasses;
                this.prefixLabelWithClassName = this.pageTSconfiguration.prefixLabelWithClassName;
                this.postfixLabelWithClassName = this.pageTSconfiguration.postfixLabelWithClassName;
-               
                /*
                 * Registering plugin "About" information
                 */
                var pluginInformation = {
-                       version         : "1.4",
-                       developer       : "Stanislas Rolland",
-                       developerUrl    : "http://www.sjbr.ca/",
-                       copyrightOwner  : "Stanislas Rolland",
-                       sponsor         : this.localize("Technische Universitat Ilmenau"),
-                       sponsorUrl      : "http://www.tu-ilmenau.de/",
-                       license         : "GPL"
+                       version         : '2.0',
+                       developer       : 'Stanislas Rolland',
+                       developerUrl    : 'http://www.sjbr.ca/',
+                       copyrightOwner  : 'Stanislas Rolland',
+                       sponsor         : this.localize('Technische Universitat Ilmenau'),
+                       sponsorUrl      : 'http://www.tu-ilmenau.de/',
+                       license         : 'GPL'
                };
                this.registerPluginInformation(pluginInformation);
-               
                /*
                 * Registering the drop-down list
                 */
@@ -139,11 +131,10 @@ HTMLArea.BlockStyle = HTMLArea.Plugin.extend({
                this.registerDropDown(dropDownConfiguration);
                return true;
        },
-       
        /*
-        * This function gets called when some block style was selected in the drop-down list
+        * This handler gets called when some block style was selected in the drop-down list
         */
-       onChange : function (editor, combo, record, index) {
+       onChange: function (editor, combo, record, index) {
                var className = combo.getValue();
                this.editor.focus();
                var blocks = this.getSelectedBlocks();
@@ -160,16 +151,15 @@ HTMLArea.BlockStyle = HTMLArea.Plugin.extend({
                        }
                }
        },
-       
        /*
         * This function applies the class change to the node
         */
-       applyClassChange : function (node, className) {
+       applyClassChange: function (node, className) {
                if (className == "none") {
                        var classNames = node.className.trim().split(" ");
                        for (var i = classNames.length; --i >= 0;) {
                                if (!HTMLArea.reservedClassNames.test(classNames[i])) {
-                                       HTMLArea._removeClass(node, classNames[i]);
+                                       HTMLArea.DOM.removeClass(node, classNames[i]);
                                        if (node.nodeName.toLowerCase() === "table" && this.getPluginInstance('TableOperations')) {
                                                this.getPluginInstance('TableOperations').removeAlternatingClasses(node, classNames[i]);
                                                this.getPluginInstance('TableOperations').removeCountingClasses(node, classNames[i]);
@@ -181,25 +171,24 @@ HTMLArea.BlockStyle = HTMLArea.Plugin.extend({
                        var nodeName = node.nodeName.toLowerCase();
                        if (this.tags && this.tags[nodeName] && this.tags[nodeName].allowedClasses) {
                                if (this.tags[nodeName].allowedClasses.test(className)) {
-                                       HTMLArea._addClass(node, className);
+                                       HTMLArea.DOM.addClass(node, className);
                                }
                        } else if (this.tags && this.tags.all && this.tags.all.allowedClasses) {
                                if (this.tags.all.allowedClasses.test(className)) {
-                                       HTMLArea._addClass(node, className);
+                                       HTMLArea.DOM.addClass(node, className);
                                }
                        } else {
-                               HTMLArea._addClass(node, className);
+                               HTMLArea.DOM.addClass(node, className);
                        }
                        if (nodeName === "table" && this.getPluginInstance('TableOperations')) {
                                this.getPluginInstance('TableOperations').reStyleTable(node);
                        }
                }
        },
-       
        /*
         * This function gets the list of selected blocks
         */
-       getSelectedBlocks : function() {
+       getSelectedBlocks: function () {
                var block, range, i = 0, blocks = [];
                var statusBarSelection = this.editor.statusBar ? this.editor.statusBar.getSelection() : null;
                if (Ext.isGecko) {
@@ -218,67 +207,54 @@ HTMLArea.BlockStyle = HTMLArea.Plugin.extend({
                return blocks;
        },
        /*
-        * This function gets called when the editor is generated
+        * This handler gets called when the editor is generated
         */
-       onGenerate: function() {
+       onGenerate: function () {
                        // Monitor editor changing mode
-               this.editor.iframe.mon(this.editor, 'modeChange', this.onModeChange, this);
-               if (!Ext.isIE) {
-                       this.generate(this.editor, 'BlockStyle');
-               }
+               this.editor.iframe.mon(this.editor, 'HTMLAreaEventModeChange', this.onModeChange, this);
+                       // Create CSS Parser object
+               this.blockStyles = new HTMLArea.CSS.Parser({
+                       prefixLabelWithClassName: this.prefixLabelWithClassName,
+                       postfixLabelWithClassName: this.postfixLabelWithClassName,
+                       showTagFreeClasses: this.showTagFreeClasses,
+                       tags: this.tags,
+                       editor: this.editor
+               });
+                       // Monitor css parsing being completed
+               this.editor.iframe.mon(this.blockStyles, 'HTMLAreaEventCssParsingComplete', this.onCssParsingComplete, this);
+               this.blockStyles.initiateParsing();
        },
        /*
-        * This function gets called when the toolbar is being updated
+        * This handler gets called when parsing of css classes is completed
         */
-       onUpdateToolbar: function (button, mode, selectionEmpty, ancestors) {
-               if (mode === 'wysiwyg') {
-                       this.generate(this.editor, button.itemId);
+       onCssParsingComplete: function () {
+               if (this.blockStyles.isReady) {
+                       this.cssArray = this.blockStyles.getClasses();
+               }
+               if (this.getEditorMode() === 'wysiwyg' && this.editor.isEditable()) {
+                       this.updateValue('BlockStyle');
                }
        },
        /*
-        * This function gets called when the editor has changed its mode to "wysiwyg"
+        * This handler gets called when the toolbar is being updated
         */
-       onModeChange: function(mode) {
-               if (this.getEditorMode() === "wysiwyg") {
-                       this.generate(this.editor, "BlockStyle");
+       onUpdateToolbar: function (button, mode, selectionEmpty, ancestors) {
+               if (mode === 'wysiwyg' && this.editor.isEditable()) {
+                       this.updateValue(button.itemId);
                }
        },
        /*
-        * This function gets called on plugin generation, on toolbar update and on change mode
-        * Re-initiate the parsing of the style sheets, if not yet completed, and refresh our toolbar components
+        * This handler gets called when the editor has changed its mode to "wysiwyg"
         */
-       generate: function(editor, dropDownId) {
-               if (this.cssLoaded && this.getEditorMode() === 'wysiwyg' && this.editor.isEditable()) {
-                       this.updateValue(dropDownId);
-               } else {
-                       if (this.cssTimeout) {
-                               window.clearTimeout(this.cssTimeout);
-                               this.cssTimeout = null;
-                       }
-                       if (this.classesUrl && (typeof(HTMLArea.classesLabels) === 'undefined')) {
-                               this.getJavascriptFile(this.classesUrl, function (options, success, response) {
-                                       if (success) {
-                                               try {
-                                                       if (typeof(HTMLArea.classesLabels) === 'undefined') {
-                                                               eval(response.responseText);
-                                                               this.appendToLog('generate', 'Javascript file successfully evaluated: ' + this.classesUrl);
-                                                       }
-                                               } catch(e) {
-                                                       this.appendToLog('generate', 'Error evaluating contents of Javascript file: ' + this.classesUrl);
-                                               }
-                                       }
-                                       this.buildCssArray(this.editor, dropDownId);
-                               });
-                       } else {
-                               this.buildCssArray(this.editor, dropDownId);
-                       }
+       onModeChange: function(mode) {
+               if (mode === 'wysiwyg' && this.editor.isEditable()) {
+                       this.updateValue('BlockStyle');
                }
        },
-       
        /*
         * This function updates the current value of the dropdown list
         */
-       updateValue : function(dropDownId) {
+       updateValue: function(dropDownId) {
                var dropDown = this.getButton(dropDownId);
                if (dropDown) {
                        var classNames = new Array();
@@ -290,7 +266,7 @@ HTMLArea.BlockStyle = HTMLArea.Plugin.extend({
                        }
                        if (parent) {
                                tagName = parent.nodeName.toLowerCase();
-                               classNames = this.getClassNames(parent);
+                               classNames = HTMLArea.DOM.getClassNames(parent);
                        }
                        if (tagName && tagName !== "body"){
                                this.buildDropDownOptions(dropDown, tagName);
@@ -301,34 +277,10 @@ HTMLArea.BlockStyle = HTMLArea.Plugin.extend({
                        }
                }
        },
-       
-       /*
-        * This function returns an array containing the class names assigned to the node
-        */
-       getClassNames : function (node) {
-               var classNames = new Array();
-               if (node) {
-                       if (node.className && /\S/.test(node.className)) {
-                               classNames = node.className.trim().split(" ");
-                       }
-                       if (HTMLArea.reservedClassNames.test(node.className)) {
-                               var cleanClassNames = new Array();
-                               var j = -1;
-                               for (var i = 0; i < classNames.length; ++i) {
-                                       if (!HTMLArea.reservedClassNames.test(classNames[i])) {
-                                               cleanClassNames[++j] = classNames[i];
-                                       }
-                               }
-                               return cleanClassNames;
-                       }
-               }
-               return classNames;
-       },
-       
        /*
         * This function reinitializes the options of the dropdown
         */
-       initializeDropDown : function (dropDown) {
+       initializeDropDown: function (dropDown) {
                var store = dropDown.getStore();
                store.removeAll(false);
                store.insert(0, new store.recordType({
@@ -337,94 +289,40 @@ HTMLArea.BlockStyle = HTMLArea.Plugin.extend({
                }));
                dropDown.setValue('none');
        },
-       
        /*
         * This function builds the options to be displayed in the dropDown box
         */
-       buildDropDownOptions : function (dropDown, tagName) {
+       buildDropDownOptions: function (dropDown, nodeName) {
                var store = dropDown.getStore();
-               var cssArray = new Array();
                this.initializeDropDown(dropDown);
-                       // Get classes allowed for all tags
-               if (typeof(this.cssArray.all) !== "undefined") {
-                       var cssArrayAll = this.cssArray.all;
-                       if (this.tags && this.tags[tagName] && this.tags[tagName].allowedClasses) {
-                               var allowedClasses = this.tags[tagName].allowedClasses;
-                               for (var cssClass in cssArrayAll) {
-                                       if (cssArrayAll.hasOwnProperty(cssClass) && allowedClasses.test(cssClass)) {
-                                               cssArray[cssClass] = cssArrayAll[cssClass];
-                                       }
-                               }
-                       } else {
-                               for (var cssClass in cssArrayAll) {
-                                       if (cssArrayAll.hasOwnProperty(cssClass)) {
-                                               cssArray[cssClass] = cssArrayAll[cssClass];
-                                       }
-                               }
-                       }
-               }
-                       // Merge classes allowed for tagName and sort the array
-               if (typeof(this.cssArray[tagName]) !== "undefined") {
-                       var cssArrayTagName = this.cssArray[tagName];
-                       if (this.tags && this.tags[tagName] && this.tags[tagName].allowedClasses) {
-                               var allowedClasses = this.tags[tagName].allowedClasses;
-                               for (var cssClass in cssArrayTagName) {
-                                       if (cssArrayTagName.hasOwnProperty(cssClass) && allowedClasses.test(cssClass)) {
-                                               cssArray[cssClass] = cssArrayTagName[cssClass];
-                                       }
-                               }
-                       } else {
-                               for (var cssClass in cssArrayTagName) {
-                                       if (cssArrayTagName.hasOwnProperty(cssClass)) {
-                                               cssArray[cssClass] = cssArrayTagName[cssClass];
-                                       }
-                               }
-                       }
-                       var sortedCssArray = new Object();
-                       var cssArrayKeys = new Array();
-                       for (var cssClass in cssArray) {
-                               if (cssArray.hasOwnProperty(cssClass)) {
-                                       cssArrayKeys.push(cssClass);
-                               }
-                       }
-                       function compare(a, b) {
-                               x = cssArray[a];
-                               y = cssArray[b];
-                               return ((x < y) ? -1 : ((x > y) ? 1 : 0));
-                       }
-                       cssArrayKeys = cssArrayKeys.sort(compare);
-                       for (var i = 0; i < cssArrayKeys.length; ++i) {
-                               sortedCssArray[cssArrayKeys[i]] = cssArray[cssArrayKeys[i]];
-                       }
-                       cssArray = sortedCssArray;
-               }
-               for (var cssClass in cssArray) {
-                       if (cssArray.hasOwnProperty(cssClass) && cssArray[cssClass]) {
-                               if (cssClass == 'none') {
-                                       store.getAt(0).set('text', cssArray[cssClass]);
-                               } else {
-                                       var style = null;
-                                       if (!this.editor.config.disablePCexamples) {
-                                               if (HTMLArea.classesValues[cssClass] && !HTMLArea.classesNoShow[cssClass]) {
-                                                       style = HTMLArea.classesValues[cssClass];
-                                               } else if (/-[0-9]+$/.test(cssClass) && HTMLArea.classesValues[RegExp.leftContext + '-'])  {
-                                                       style = HTMLArea.classesValues[RegExp.leftContext + '-'];
-                                               }
+               if (this.blockStyles.isReady) {
+                       var allowedClasses = {};
+                       if (Ext.isDefined(this.cssArray[nodeName])) {
+                               allowedClasses = this.cssArray[nodeName];
+                       } else if (this.showTagFreeClasses && Ext.isDefined(this.cssArray['all'])) {
+                               allowedClasses = this.cssArray['all'];
+                       }
+                       Ext.iterate(allowedClasses, function (cssClass, value) {
+                               var style = null;
+                               if (!this.editor.config.disablePCexamples) {
+                                       if (HTMLArea.classesValues[cssClass] && !HTMLArea.classesNoShow[cssClass]) {
+                                               style = HTMLArea.classesValues[cssClass];
+                                       } else if (/-[0-9]+$/.test(cssClass) && HTMLArea.classesValues[RegExp.leftContext + '-'])  {
+                                               style = HTMLArea.classesValues[RegExp.leftContext + '-'];
                                        }
-                                       store.add(new store.recordType({
-                                               text: cssArray[cssClass],
-                                               value: cssClass,
-                                               style: style
-                                       }));
                                }
-                       }
+                               store.add(new store.recordType({
+                                       text: value,
+                                       value: cssClass,
+                                       style: style
+                               }));
+                       }, this);
                }
        },
-       
        /*
         * This function sets the selected option of the dropDown box
         */
-       setSelectedOption : function (dropDown, classNames, noUnknown, defaultClass) {
+       setSelectedOption: function (dropDown, classNames, noUnknown, defaultClass) {
                var store = dropDown.getStore();
                dropDown.setValue('none');
                if (classNames.length) {
@@ -454,173 +352,5 @@ HTMLArea.BlockStyle = HTMLArea.Plugin.extend({
                        });
                }
                dropDown.setDisabled(!(store.getCount()>1));
-       },
-       
-       /*
-        * This function builds the main array of class selectors
-        */
-       buildCssArray : function(editor, dropDownId) {
-               this.cssArray = this.parseStyleSheet();
-               if (!this.cssLoaded && (this.cssParseCount < 17)) {
-                       this.cssTimeout = this.buildCssArray.defer(200, this, [editor, dropDownId]);
-                       this.cssParseCount++;
-               } else {
-                       this.cssTimeout = null;
-                       this.cssLoaded = true;
-                       this.cssArray = this.sortCssArray(this.cssArray);
-                       this.updateValue(dropDownId);
-               }
-       },
-       
-       /*
-        * This function parses the stylesheets
-        */
-       parseStyleSheet : function() {
-               var iframe = this.editor._iframe.contentWindow ? this.editor._iframe.contentWindow.document : this.editor._iframe.contentDocument;
-               var newCssArray = new Object();
-               this.cssLoaded = true;
-               for (var i = 0; i < iframe.styleSheets.length; i++) {
-                       if (!Ext.isIE) {
-                               try {
-                                       newCssArray = this.parseCssRule(iframe.styleSheets[i].cssRules, newCssArray);
-                               } catch(e) {
-                                       this.cssLoaded = false;
-                               }
-                       } else {
-                               try{
-                                               // @import StyleSheets (IE)
-                                       if (iframe.styleSheets[i].imports) {
-                                               newCssArray = this.parseCssIEImport(iframe.styleSheets[i].imports, newCssArray);
-                                       }
-                                       if (iframe.styleSheets[i].rules) {
-                                               newCssArray = this.parseCssRule(iframe.styleSheets[i].rules, newCssArray);
-                                       }
-                               } catch(e) {
-                                       this.cssLoaded = false;
-                               }
-                       }
-               }
-               return newCssArray;
-       },
-       
-       /*
-        * This function parses IE import rules
-        */
-       parseCssIEImport : function(cssIEImport, cssArray) {
-               var newCssArray = new Object();
-               newCssArray = cssArray;
-               for (var i=0; i < cssIEImport.length; i++) {
-                       if (cssIEImport[i].imports) {
-                               newCssArray = this.parseCssIEImport(cssIEImport[i].imports, newCssArray);
-                       }
-                       if (cssIEImport[i].rules) {
-                               newCssArray = this.parseCssRule(cssIEImport[i].rules, newCssArray);
-                       }
-               }
-               return newCssArray;
-       },
-       
-       /*
-        * This function parses gecko css rules
-        */
-       parseCssRule : function(cssRules, cssArray) {
-               var newCssArray = new Object();
-               newCssArray = cssArray;
-               for (var rule = 0; rule < cssRules.length; rule++) {
-                               // StyleRule
-                       if (cssRules[rule].selectorText) {
-                               newCssArray = this.parseSelectorText(cssRules[rule].selectorText, newCssArray);
-                       } else {
-                                       // ImportRule (Mozilla)
-                               if (cssRules[rule].styleSheet) {
-                                       newCssArray = this.parseCssRule(cssRules[rule].styleSheet.cssRules, newCssArray);
-                               }
-                                       // MediaRule (Mozilla)
-                               if (cssRules[rule].cssRules) {
-                                       newCssArray = this.parseCssRule(cssRules[rule].cssRules, newCssArray);
-                               }
-                       }
-               }
-               return newCssArray;
-       },
-       
-       /*
-        * This function parses each selector rule
-        */
-       parseSelectorText : function(selectorText, cssArray) {
-               var cssElements = new Array();
-               var cssElement = new Array();
-               var tagName, className;
-               var newCssArray = new Object();
-               newCssArray = cssArray;
-               if (selectorText.search(/:+/) == -1) {
-                               // split equal Styles (Mozilla-specific) e.q. head, body {border:0px}
-                               // for ie not relevant. returns allways one element
-                       cssElements = selectorText.split(",");
-                       for (var k = 0; k < cssElements.length; k++) {
-                                       // Match ALL classes (<element name (optional)>.<class name>) in selector rule
-                               var s = cssElements[k],
-                                       pattern = /(\S*)\.(\S+)/,
-                                       index;
-                               while ((index = s.search(pattern)) > -1) {
-                                       var match = pattern.exec(s.substring(index));
-                                       s = s.substring(index+match[0].length);
-
-                                       tagName = (match[1] && (match[1] != '*')) ? match[1].toLowerCase().trim() : "all";
-                                       className = match[2];
-
-                                       if (className && !HTMLArea.reservedClassNames.test(className)) {
-                                               if (((tagName != "all") && (!this.tags || !this.tags[tagName]))
-                                                       || ((tagName == "all") && (!this.tags || !this.tags[tagName]) && this.showTagFreeClasses)
-                                                       || (this.tags && this.tags[tagName] && this.tags[tagName].allowedClasses && this.tags[tagName].allowedClasses.test(className))) {
-                                                       if (!newCssArray[tagName]) {
-                                                               newCssArray[tagName] = new Object();
-                                                       }
-                                                       if (className) {
-                                                               cssName = className;
-                                                               if (HTMLArea.classesLabels && HTMLArea.classesLabels[className]) {
-                                                                       cssName = this.prefixLabelWithClassName ? (className + " - " + HTMLArea.classesLabels[className]) : HTMLArea.classesLabels[className];
-                                                                       cssName = this.postfixLabelWithClassName ? (cssName + " - " + className) : cssName;
-                                                               }
-                                                       } else {
-                                                               className = "none";
-                                                               cssName = this.localize("Element style");
-                                                       }
-                                                       newCssArray[tagName][className] = cssName;
-                                               }
-                                       }
-                               }
-                       }
-               }
-               return newCssArray;
-       },
-       
-       /*
-        * This function sorts the main array of class selectors
-        */
-       sortCssArray : function(cssArray) {
-               var newCssArray = new Object();
-               for (var tagName in cssArray) {
-                       if (cssArray.hasOwnProperty(tagName)) {
-                               newCssArray[tagName] = new Object();
-                               var tagArrayKeys = new Array();
-                               for (var cssClass in cssArray[tagName]) {
-                                       if (cssArray[tagName].hasOwnProperty(cssClass)) {
-                                               tagArrayKeys.push(cssClass);
-                                       }
-                               }
-                               function compare(a, b) {
-                                       x = cssArray[tagName][a];
-                                       y = cssArray[tagName][b];
-                                       return ((x < y) ? -1 : ((x > y) ? 1 : 0));
-                               }
-                               tagArrayKeys = tagArrayKeys.sort(compare);
-                               for (var i = 0; i < tagArrayKeys.length; ++i) {
-                                       newCssArray[tagName][tagArrayKeys[i]] = cssArray[tagName][tagArrayKeys[i]];
-                               }
-                       }
-               }
-               return newCssArray;
        }
 });
-
index d691745..9868389 100644 (file)
@@ -357,7 +357,7 @@ HTMLArea.InlineElements = HTMLArea.Plugin.extend({
                                classNames = newElement.className.trim().split(" ");
                                for (var i = 0; i < classNames.length; ++i) {
                                        if (!allowedClasses.test(classNames[i])) {
-                                               HTMLArea._removeClass(newElement, classNames[i]);
+                                               HTMLArea.DOM.removeClass(newElement, classNames[i]);
                                        }
                                }
                        }
index 7a59f86..b9dc442 100644 (file)
@@ -216,10 +216,10 @@ HTMLArea.Language = HTMLArea.Plugin.extend({
         */
        toggleLanguageMarks : function (forceLanguageMarks) {
                var body = this.editor._doc.body;
-               if (!HTMLArea._hasClass(body, 'htmlarea-show-language-marks')) {
-                       HTMLArea._addClass(body,'htmlarea-show-language-marks');
+               if (!HTMLArea.DOM.hasClass(body, 'htmlarea-show-language-marks')) {
+                       HTMLArea.DOM.addClass(body,'htmlarea-show-language-marks');
                } else if (!forceLanguageMarks) {
-                       HTMLArea._removeClass(body,'htmlarea-show-language-marks');
+                       HTMLArea.DOM.removeClass(body,'htmlarea-show-language-marks');
                }
        },
 
@@ -408,7 +408,7 @@ HTMLArea.Language = HTMLArea.Plugin.extend({
                                        }
                                        break;
                                case 'ShowLanguageMarks':
-                                       button.setInactive(!HTMLArea._hasClass(this.editor._doc.body, 'htmlarea-show-language-marks'));
+                                       button.setInactive(!HTMLArea.DOM.hasClass(this.editor._doc.body, 'htmlarea-show-language-marks'));
                                        break;
                                case 'Language':
                                                // Updating the language drop-down
index 299ecbf..5d14826 100644 (file)
@@ -485,13 +485,13 @@ HTMLArea.SpellChecker = HTMLArea.Plugin.extend({
                        element.onclick = null;
                        element.onmouseover = null;
                        element.onmouseout = null;
-                       if (!leaveFixed || !HTMLArea._hasClass(element, 'htmlarea-spellcheck-fixed')) {
+                       if (!leaveFixed || !HTMLArea.DOM.hasClass(element, 'htmlarea-spellcheck-fixed')) {
                                element.parentNode.insertBefore(element.firstChild, element);
                                element.parentNode.removeChild(element);
                        } else {
-                               HTMLArea._removeClass(element, 'htmlarea-spellcheck-error');
-                               HTMLArea._removeClass(element, 'htmlarea-spellcheck-same');
-                               HTMLArea._removeClass(element, 'htmlarea-spellcheck-current');
+                               HTMLArea.DOM.removeClass(element, 'htmlarea-spellcheck-error');
+                               HTMLArea.DOM.removeClass(element, 'htmlarea-spellcheck-same');
+                               HTMLArea.DOM.removeClass(element, 'htmlarea-spellcheck-current');
                        }
                }, this);
                        // Cleanup event handlers on links
@@ -521,11 +521,11 @@ HTMLArea.SpellChecker = HTMLArea.Plugin.extend({
                var id = 0;
                var self = this;
                Ext.each(contentWindow.document.getElementsByTagName('span'), function (span) {
-                       if (HTMLArea._hasClass(span, 'htmlarea-spellcheck-error')) {
+                       if (HTMLArea.DOM.hasClass(span, 'htmlarea-spellcheck-error')) {
                                this.misspelledWords.push(span);
                                span.onclick = function (event) { self.setCurrentWord(this, false); };
-                               span.onmouseover = function (event) { HTMLArea._addClass(this, 'htmlarea-spellcheck-hover'); };
-                               span.onmouseout = function (event) { HTMLArea._removeClass(this, 'htmlarea-spellcheck-hover'); };
+                               span.onmouseover = function (event) { HTMLArea.DOM.addClass(this, 'htmlarea-spellcheck-hover'); };
+                               span.onmouseout = function (event) { HTMLArea.DOM.removeClass(this, 'htmlarea-spellcheck-hover'); };
                                span.htmlareaId = id++;
                                span.htmlareaOriginalWord = span.firstChild.data;
                                span.htmlareaFixed = false;
@@ -533,7 +533,7 @@ HTMLArea.SpellChecker = HTMLArea.Plugin.extend({
                                        this.allWords[span.htmlareaOriginalWord] = [];
                                }
                                this.allWords[span.htmlareaOriginalWord].push(span);
-                       } else if (HTMLArea._hasClass(span, 'htmlarea-spellcheck-fixed')) {
+                       } else if (HTMLArea.DOM.hasClass(span, 'htmlarea-spellcheck-fixed')) {
                                this.correctedWords.push(span);
                        }
                }, this);
@@ -624,18 +624,18 @@ HTMLArea.SpellChecker = HTMLArea.Plugin.extend({
                }
                        // De-highlight all occurrences of current word
                if (this.currentElement) {
-                       HTMLArea._removeClass(this.currentElement, 'htmlarea-spellcheck-current');
+                       HTMLArea.DOM.removeClass(this.currentElement, 'htmlarea-spellcheck-current');
                        Ext.each(this.allWords[this.currentElement.htmlareaOriginalWord], function (word) {
-                               HTMLArea._removeClass(word, 'htmlarea-spellcheck-same');
+                               HTMLArea.DOM.removeClass(word, 'htmlarea-spellcheck-same');
                        });
                }
                        // Highlight all occurrences of new current word
                this.currentElement = element;
-               HTMLArea._addClass(this.currentElement, 'htmlarea-spellcheck-current');
+               HTMLArea.DOM.addClass(this.currentElement, 'htmlarea-spellcheck-current');
                var occurrences = this.allWords[this.currentElement.htmlareaOriginalWord];
                Ext.each(occurrences, function (word) {
                        if (word != this.currentElement) {
-                               HTMLArea._addClass(word, 'htmlarea-spellcheck-same');
+                               HTMLArea.DOM.addClass(word, 'htmlarea-spellcheck-same');
                        }
                }, this);
                this.dialog.find('itemId', 'replaceAll')[0].setDisabled(occurrences.length <= 1);
@@ -685,13 +685,13 @@ HTMLArea.SpellChecker = HTMLArea.Plugin.extend({
         * Handler invoked when the mouse moves over a misspelled word
         */
        onWordMouseOver: function (event, element) {
-               HTMLArea._addClass(element, 'htmlarea-spellcheck-hover');
+               HTMLArea.DOM.addClass(element, 'htmlarea-spellcheck-hover');
        },
        /*
         * Handler invoked when the mouse moves out of a misspelled word
         */
        onWordMouseOut: function (event, element) {
-               HTMLArea._removeClass(element, 'htmlarea-spellcheck-hover');
+               HTMLArea.DOM.removeClass(element, 'htmlarea-spellcheck-hover');
        },
        /*
         * Handler invoked when a suggestion is selected
@@ -711,17 +711,17 @@ HTMLArea.SpellChecker = HTMLArea.Plugin.extend({
        onRevertClick: function () {
                this.dialog.find('itemId', 'replacement')[0].setValue(this.currentElement.htmlareaOriginalWord);
                this.replaceWord(this.currentElement);
-               HTMLArea._removeClass(this.currentElement, 'htmlarea-spellcheck-fixed');
-               HTMLArea._addClass(this.currentElement, 'htmlarea-spellcheck-error');
-               HTMLArea._addClass(this.currentElement, 'htmlarea-spellcheck-current');
+               HTMLArea.DOM.removeClass(this.currentElement, 'htmlarea-spellcheck-fixed');
+               HTMLArea.DOM.addClass(this.currentElement, 'htmlarea-spellcheck-error');
+               HTMLArea.DOM.addClass(this.currentElement, 'htmlarea-spellcheck-current');
                return false;
        },
        /*
         * Replace the word contained in the element
         */
        replaceWord: function (element) {
-               HTMLArea._removeClass(element, 'htmlarea-spellcheck-hover');
-               HTMLArea._addClass(element, 'htmlarea-spellcheck-fixed');
+               HTMLArea.DOM.removeClass(element, 'htmlarea-spellcheck-hover');
+               HTMLArea.DOM.addClass(element, 'htmlarea-spellcheck-fixed');
                element.htmlareaFixed = true;
                var replacement = this.dialog.find('itemId', 'replacement')[0].getValue();
                if (element.innerHTML != replacement) {
index 1130a83..f46564d 100644 (file)
@@ -264,11 +264,8 @@ HTMLArea.TableOperations = HTMLArea.Plugin.extend({
                                }
                                break;
                }
-               if (this.removedFieldsets.indexOf('style') == -1 && this.getButton('BlockStyle')) {
-                       var blockStyle = this.getPluginInstance('BlockStyle');
-                       if (blockStyle && blockStyle.cssLoaded) {
-                               this.addConfigElement(this.buildStylingFieldsetConfig(element, buttonId), generalTabItems);
-                       }
+               if (this.removedFieldsets.indexOf('style') == -1 && this.getPluginInstance('BlockStyle')) {
+                       this.addConfigElement(this.buildStylingFieldsetConfig(element, buttonId), generalTabItems);
                }
                if (!Ext.isEmpty(generalTabItems)) {
                        tabItems.push({
@@ -525,16 +522,16 @@ HTMLArea.TableOperations = HTMLArea.Plugin.extend({
                            case "f_st_float":
                                switch (val) {
                                    case "not set":
-                                       HTMLArea._removeClass(table, this.floatRight);
-                                       HTMLArea._removeClass(table, this.floatLeft);
+                                       HTMLArea.DOM.removeClass(table, this.floatRight);
+                                       HTMLArea.DOM.removeClass(table, this.floatLeft);
                                        break;
                                    case "right":
-                                       HTMLArea._removeClass(table, this.floatLeft);
-                                       HTMLArea._addClass(table, this.floatRight);
+                                       HTMLArea.DOM.removeClass(table, this.floatLeft);
+                                       HTMLArea.DOM.addClass(table, this.floatRight);
                                        break;
                                    case "left":
-                                       HTMLArea._removeClass(table, this.floatRight);
-                                       HTMLArea._addClass(table, this.floatLeft);
+                                       HTMLArea.DOM.removeClass(table, this.floatRight);
+                                       HTMLArea.DOM.addClass(table, this.floatLeft);
                                        break;
                                }
                                break;
@@ -685,7 +682,7 @@ HTMLArea.TableOperations = HTMLArea.Plugin.extend({
         */
        onUpdateToolbar: function (button, mode, selectionEmpty, ancestors) {
                if (mode === 'wysiwyg' && this.editor.isEditable() && button.itemId === 'TO-toggle-borders') {
-                       button.setInactive(!HTMLArea._hasClass(this.editor._doc.body, 'htmlarea-showtableborders'));
+                       button.setInactive(!HTMLArea.DOM.hasClass(this.editor._doc.body, 'htmlarea-showtableborders'));
                }
        },
        /*
@@ -1182,10 +1179,10 @@ HTMLArea.TableOperations = HTMLArea.Plugin.extend({
         */
        toggleBorders : function (forceBorders) {
                var body = this.editor._doc.body;
-               if (!HTMLArea._hasClass(body, 'htmlarea-showtableborders')) {
-                       HTMLArea._addClass(body,'htmlarea-showtableborders');
+               if (!HTMLArea.DOM.hasClass(body, 'htmlarea-showtableborders')) {
+                       HTMLArea.DOM.addClass(body,'htmlarea-showtableborders');
                } else if (!forceBorders) {
-                       HTMLArea._removeClass(body,'htmlarea-showtableborders');
+                       HTMLArea.DOM.removeClass(body,'htmlarea-showtableborders');
                }
        },
        /*
@@ -1299,20 +1296,20 @@ HTMLArea.TableOperations = HTMLArea.Plugin.extend({
                        odd = oddClass[type];
                        even = evenClass[type];
                        if (remove) {
-                               HTMLArea._removeClass(row, odd);
-                               HTMLArea._removeClass(row, even);
+                               HTMLArea.DOM.removeClass(row, odd);
+                               HTMLArea.DOM.removeClass(row, even);
                                // Check if i is even, and apply classes for both possible results
                        } else if (odd && even) {
                                if ((i % 2) == 0) {
-                                       if (HTMLArea._hasClass(row, even)) {
-                                               HTMLArea._removeClass(row, even);
+                                       if (HTMLArea.DOM.hasClass(row, even)) {
+                                               HTMLArea.DOM.removeClass(row, even);
                                        }
-                                       HTMLArea._addClass(row, odd);
+                                       HTMLArea.DOM.addClass(row, odd);
                                } else {
-                                       if (HTMLArea._hasClass(row, odd)) {
-                                               HTMLArea._removeClass(row, odd);
+                                       if (HTMLArea.DOM.hasClass(row, odd)) {
+                                               HTMLArea.DOM.removeClass(row, odd);
                                        }
-                                       HTMLArea._addClass(row, even);
+                                       HTMLArea.DOM.addClass(row, even);
                                }
                        }
                }
@@ -1342,20 +1339,20 @@ HTMLArea.TableOperations = HTMLArea.Plugin.extend({
                                odd = oddClass[type];
                                even = evenClass[type];
                                if (remove) {
-                                       if (odd) HTMLArea._removeClass(cell, odd);
-                                       if (even) HTMLArea._removeClass(cell, even);
+                                       if (odd) HTMLArea.DOM.removeClass(cell, odd);
+                                       if (even) HTMLArea.DOM.removeClass(cell, even);
                                } else if (odd && even) {
                                                // Check if j+startAt is even, and apply classes for both possible results
                                        if ((j % 2) == 0) {
-                                               if (HTMLArea._hasClass(cell, even)) {
-                                                       HTMLArea._removeClass(cell, even);
+                                               if (HTMLArea.DOM.hasClass(cell, even)) {
+                                                       HTMLArea.DOM.removeClass(cell, even);
                                                }
-                                               HTMLArea._addClass(cell, odd);
+                                               HTMLArea.DOM.addClass(cell, odd);
                                        } else{
-                                               if (HTMLArea._hasClass(cell, odd)) {
-                                                       HTMLArea._removeClass(cell, odd);
+                                               if (HTMLArea.DOM.hasClass(cell, odd)) {
+                                                       HTMLArea.DOM.removeClass(cell, odd);
                                                }
-                                               HTMLArea._addClass(cell, even);
+                                               HTMLArea.DOM.addClass(cell, even);
                                        }
                                }
                        }
@@ -1422,23 +1419,23 @@ HTMLArea.TableOperations = HTMLArea.Plugin.extend({
                        lastRowClassName = rowLastClass[type];
                        if (remove) {
                                if (baseClassName) {
-                                       HTMLArea._removeClass(row, rowClassName);
+                                       HTMLArea.DOM.removeClass(row, rowClassName);
                                }
                                if (lastRowClassName && i == n-1) {
-                                       HTMLArea._removeClass(row, lastRowClassName);
+                                       HTMLArea.DOM.removeClass(row, lastRowClassName);
                                }
                        } else {
                                if (baseClassName) {
-                                       if (HTMLArea._hasClass(row, baseClassName, true)) {
-                                               HTMLArea._removeClass(row, baseClassName, true);
+                                       if (HTMLArea.DOM.hasClass(row, baseClassName, true)) {
+                                               HTMLArea.DOM.removeClass(row, baseClassName, true);
                                        }
-                                       HTMLArea._addClass(row, rowClassName);
+                                       HTMLArea.DOM.addClass(row, rowClassName);
                                }
                                if (lastRowClassName) {
                                        if (i == n-1) {
-                                               HTMLArea._addClass(row, lastRowClassName);
-                                       } else if (HTMLArea._hasClass(row, lastRowClassName)) {
-                                               HTMLArea._removeClass(row, lastRowClassName);
+                                               HTMLArea.DOM.addClass(row, lastRowClassName);
+                                       } else if (HTMLArea.DOM.hasClass(row, lastRowClassName)) {
+                                               HTMLArea.DOM.removeClass(row, lastRowClassName);
                                        }
                                }
                        }
@@ -1471,23 +1468,23 @@ HTMLArea.TableOperations = HTMLArea.Plugin.extend({
                                lastColumnClassName = columnLastClass[type];
                                if (remove) {
                                        if (baseClassName) {
-                                               HTMLArea._removeClass(cell, columnClassName);
+                                               HTMLArea.DOM.removeClass(cell, columnClassName);
                                        }
                                        if (lastColumnClassName && j == n-1) {
-                                                       HTMLArea._removeClass(cell, lastColumnClassName);
+                                                       HTMLArea.DOM.removeClass(cell, lastColumnClassName);
                                        }
                                } else {
                                        if (baseClassName) {
-                                               if (HTMLArea._hasClass(cell, baseClassName, true)) {
-                                                       HTMLArea._removeClass(cell, baseClassName, true);
+                                               if (HTMLArea.DOM.hasClass(cell, baseClassName, true)) {
+                                                       HTMLArea.DOM.removeClass(cell, baseClassName, true);
                                                }
-                                               HTMLArea._addClass(cell, columnClassName);
+                                               HTMLArea.DOM.addClass(cell, columnClassName);
                                        }
                                        if (lastColumnClassName) {
                                                if (j == n-1) {
-                                                       HTMLArea._addClass(cell, lastColumnClassName);
-                                               } else if (HTMLArea._hasClass(cell, lastColumnClassName)) {
-                                                       HTMLArea._removeClass(cell, lastColumnClassName);
+                                                       HTMLArea.DOM.addClass(cell, lastColumnClassName);
+                                               } else if (HTMLArea.DOM.hasClass(cell, lastColumnClassName)) {
+                                                       HTMLArea.DOM.removeClass(cell, lastColumnClassName);
                                                }
                                        }
                                }
@@ -1521,7 +1518,7 @@ HTMLArea.TableOperations = HTMLArea.Plugin.extend({
                        } else {
                                var firstRow = thead.rows[0];
                        }
-                       HTMLArea._removeClass(firstRow, this.useHeaderClass);
+                       HTMLArea.DOM.removeClass(firstRow, this.useHeaderClass);
                } else {
                        if (thead) {
                                var rows = thead.rows;
@@ -1540,10 +1537,10 @@ HTMLArea.TableOperations = HTMLArea.Plugin.extend({
                }
                if (headers == "both") {
                        var firstRow = tbody.rows[0];
-                       HTMLArea._addClass(firstRow, this.useHeaderClass);
+                       HTMLArea.DOM.addClass(firstRow, this.useHeaderClass);
                } else if (headers != "top") {
                        var firstRow = tbody.rows[0];
-                       HTMLArea._removeClass(firstRow, this.useHeaderClass);
+                       HTMLArea.DOM.removeClass(firstRow, this.useHeaderClass);
                        this.remapRowCells(firstRow, "td");
                }
                if (headers == "top" || headers == "both") {
@@ -1613,7 +1610,7 @@ HTMLArea.TableOperations = HTMLArea.Plugin.extend({
                                var classNames = newCell.className.trim().split(" ");
                                for (var i = classNames.length; --i >= 0;) {
                                        if (!allowedClasses.test(classNames[i])) {
-                                               HTMLArea._removeClass(newCell, classNames[i]);
+                                               HTMLArea.DOM.removeClass(newCell, classNames[i]);
                                        }
                                }
                        }
@@ -1818,7 +1815,7 @@ HTMLArea.TableOperations = HTMLArea.Plugin.extend({
                                if (thead.length && thead[0].rows.length) {
                                        selected = 'top';
                                } else if (tbody.length && tbody[0].rows.length) {
-                                       if (HTMLArea._hasClass(tbody[0].rows[0], this.useHeaderClass)) {
+                                       if (HTMLArea.DOM.hasClass(tbody[0].rows[0], this.useHeaderClass)) {
                                                selected = 'both';
                                        } else if (tbody[0].rows[0].cells.length && tbody[0].rows[0].cells[0].nodeName.toLowerCase() == 'th') {
                                                selected = 'left';
@@ -1928,12 +1925,12 @@ HTMLArea.TableOperations = HTMLArea.Plugin.extend({
         */
        setStyleOptions: function (dropDown, element, nodeName, defaultClass) {
                var blockStyle = this.getPluginInstance('BlockStyle');
-               if (dropDown && blockStyle && blockStyle.cssLoaded) {
+               if (dropDown && blockStyle) {
                        if (defaultClass) {
                                var classNames = new Array();
                                classNames.push(defaultClass);
                        } else {
-                               var classNames = blockStyle.getClassNames(element);
+                               var classNames = HTMLArea.DOM.getClassNames(element);
                        }
                        blockStyle.buildDropDownOptions(dropDown, nodeName);
                        blockStyle.setSelectedOption(dropDown, classNames, 'noUnknown', defaultClass);
index c3fa94d..99288c1 100644 (file)
@@ -36,20 +36,14 @@ HTMLArea.TextStyle = HTMLArea.Plugin.extend({
        /*
         * Let the base class do some initialization work
         */
-       constructor : function(editor, pluginName) {
+       constructor: function (editor, pluginName) {
                this.base(editor, pluginName);
        },
-       
        /*
         * This function gets called by the class constructor
         */
-       configurePlugin : function (editor) {
-               
-               this.cssLoaded = false;
-               this.cssTimeout = null;
-               this.cssParseCount = 0;
-               this.cssArray = new Object();
-               
+       configurePlugin: function (editor) {
+               this.cssArray = {};
                this.classesUrl = this.editorConfiguration.classesUrl;
                this.pageTSconfiguration = this.editorConfiguration.buttons.textstyle;
                this.tags = this.pageTSconfiguration.tags;
@@ -94,21 +88,19 @@ HTMLArea.TextStyle = HTMLArea.Plugin.extend({
                if (Ext.isIE) {
                        this.addAllowedAttribute("className");
                }
-               
                /*
                 * Registering plugin "About" information
                 */
                var pluginInformation = {
-                       version         : "1.1",
-                       developer       : "Stanislas Rolland",
-                       developerUrl    : "http://www.sjbr.ca/",
-                       copyrightOwner  : "Stanislas Rolland",
-                       sponsor         : this.localize("Technische Universitat Ilmenau"),
-                       sponsorUrl      : "http://www.tu-ilmenau.de/",
-                       license         : "GPL"
+                       version         : '2.0',
+                       developer       : 'Stanislas Rolland',
+                       developerUrl    : 'http://www.sjbr.ca/',
+                       copyrightOwner  : 'Stanislas Rolland',
+                       sponsor         : this.localize('Technische Universitat Ilmenau'),
+                       sponsorUrl      : 'http://www.tu-ilmenau.de/',
+                       license         : 'GPL'
                };
                this.registerPluginInformation(pluginInformation);
-               
                /* 
                 * Registering the dropdown list
                 */
@@ -139,10 +131,9 @@ HTMLArea.TextStyle = HTMLArea.Plugin.extend({
                return true;
        },
        
-       isInlineElement : function (el) {
+       isInlineElement: function (el) {
                return el && (el.nodeType === 1) && this.REInlineTags.test(el.nodeName.toLowerCase());
        },
-
        /*
         * This function adds an attribute to the array of allowed attributes on inline elements
         *
@@ -150,14 +141,13 @@ HTMLArea.TextStyle = HTMLArea.Plugin.extend({
         *
         * @return      void
         */
-       addAllowedAttribute : function (attribute) {
+       addAllowedAttribute: function (attribute) {
                this.allowedAttributes.push(attribute);
        },
-
        /*
         * This function gets called when some style in the drop-down list applies it to the highlighted textt
         */
-       onChange : function (editor, combo, record, index) {
+       onChange: function (editor, combo, record, index) {
                var className = combo.getValue();
                var classNames = null;
                var fullNodeSelected = false;
@@ -196,7 +186,7 @@ HTMLArea.TextStyle = HTMLArea.Plugin.extend({
                        if (className !== "none") {
                                        // Add span element with class attribute
                                var newElement = editor._doc.createElement("span");
-                               HTMLArea._addClass(newElement, className);
+                               HTMLArea.DOM.addClass(newElement, className);
                                editor.wrapWithInlineElement(newElement, selection, range);
                                if (!Ext.isIE) {
                                        range.detach();
@@ -207,10 +197,10 @@ HTMLArea.TextStyle = HTMLArea.Plugin.extend({
                        if (parent && !HTMLArea.isBlockElement(parent)) {
                                if (className === "none" && parent.className && /\S/.test(parent.className)) {
                                        classNames = parent.className.trim().split(" ");
-                                       HTMLArea._removeClass(parent, classNames[classNames.length-1]);
+                                       HTMLArea.DOM.removeClass(parent, classNames[classNames.length-1]);
                                }
                                if (className !== "none") {
-                                       HTMLArea._addClass(parent, className);
+                                       HTMLArea.DOM.addClass(parent, className);
                                }
                                        // Remove the span tag if it has no more attribute
                                if ((parent.nodeName.toLowerCase() === "span") && !HTMLArea.hasAllowedAttributes(parent, this.allowedAttributes)) {
@@ -219,211 +209,56 @@ HTMLArea.TextStyle = HTMLArea.Plugin.extend({
                        }
                }
        },
-
        /*
         * This function gets called when the plugin is generated
         * Get the classes configuration and initiate the parsing of the style sheets
         */
-       onGenerate: function() {
+       onGenerate: function () {
                        // Monitor editor changing mode
-               this.editor.iframe.mon(this.editor, 'modeChange', this.onModeChange, this);
-               this.generate(this.editor, "TextStyle");
+               this.editor.iframe.mon(this.editor, 'HTMLAreaEventModeChange', this.onModeChange, this);
+                       // Create CSS Parser object
+               this.textStyles = new HTMLArea.CSS.Parser({
+                       prefixLabelWithClassName: this.prefixLabelWithClassName,
+                       postfixLabelWithClassName: this.postfixLabelWithClassName,
+                       showTagFreeClasses: this.showTagFreeClasses,
+                       tags: this.tags,
+                       editor: this.editor
+               });
+                       // Monitor css parsing being completed
+               this.editor.iframe.mon(this.textStyles, 'HTMLAreaEventCssParsingComplete', this.onCssParsingComplete, this);
+               this.textStyles.initiateParsing();
        },
-       
        /*
-        * This function gets called on plugin generation, on toolbar update and  on change mode
-        * Re-initiate the parsing of the style sheets, if not yet completed, and refresh our toolbar components
+        * This handler gets called when parsing of css classes is completed
         */
-       generate: function (editor, dropDownId) {
-               if (this.cssLoaded) {
-                       this.updateToolbar(dropDownId);
-               } else {
-                       if (this.cssTimeout) {
-                               window.clearTimeout(this.cssTimeout);
-                               this.cssTimeout = null;
-                       }
-                       if (this.classesUrl && (typeof(HTMLArea.classesLabels) === 'undefined')) {
-                               this.getJavascriptFile(this.classesUrl, function (options, success, response) {
-                                       if (success) {
-                                               try {
-                                                       if (typeof(HTMLArea.classesLabels) === 'undefined') {
-                                                               eval(response.responseText);
-                                                               this.appendToLog('generate', 'Javascript file successfully evaluated: ' + this.classesUrl);
-                                                       }
-                                               } catch(e) {
-                                                       this.appendToLog('generate', 'Error evaluating contents of Javascript file: ' + this.classesUrl);
-                                               }
-                                       }
-                                       this.buildCssArray(this.editor, dropDownId);
-                               });
-                       } else {
-                               this.buildCssArray(this.editor, dropDownId);
-                       }
-               }
-       },
-       
-       buildCssArray : function(editor, dropDownId) {
-               this.cssArray = this.parseStyleSheet();
-               if (!this.cssLoaded && (this.cssParseCount < 17)) {
-                       this.cssTimeout = this.buildCssArray.defer(200, this, [editor, dropDownId]);
-                       this.cssParseCount++;
-               } else {
-                       this.cssTimeout = null;
-                       this.cssLoaded = true;
-                       this.cssArray = this.sortCssArray(this.cssArray);
-                       this.updateToolbar(dropDownId);
-               }
-       },
-       
-       parseStyleSheet : function() {
-               var iframe = this.editor._iframe.contentWindow ? this.editor._iframe.contentWindow.document : this.editor._iframe.contentDocument;
-               var newCssArray = new Object();
-               this.cssLoaded = true;
-               for (var i = 0; i < iframe.styleSheets.length; i++) {
-                       if (!Ext.isIE) {
-                               try {
-                                       newCssArray = this.parseCssRule(iframe.styleSheets[i].cssRules, newCssArray);
-                               } catch(e) {
-                                       this.cssLoaded = false;
-                               }
-                       } else {
-                               try{
-                                               // @import StyleSheets (IE)
-                                       if (iframe.styleSheets[i].imports) {
-                                               newCssArray = this.parseCssIEImport(iframe.styleSheets[i].imports, newCssArray);
-                                       }
-                                       if (iframe.styleSheets[i].rules) {
-                                               newCssArray = this.parseCssRule(iframe.styleSheets[i].rules, newCssArray);
-                                       }
-                               } catch(e) {
-                                       this.cssLoaded = false;
-                               }
-                       }
-               }
-               return newCssArray;
-       },
-       
-       parseCssIEImport : function(cssIEImport, cssArray) {
-               var newCssArray = new Object();
-               newCssArray = cssArray;
-               for (var i=0; i < cssIEImport.length; i++) {
-                       if (cssIEImport[i].imports) {
-                               newCssArray = this.parseCssIEImport(cssIEImport[i].imports, newCssArray);
-                       }
-                       if (cssIEImport[i].rules) {
-                               newCssArray = this.parseCssRule(cssIEImport[i].rules, newCssArray);
-                       }
+       onCssParsingComplete: function () {
+               if (this.textStyles.isReady) {
+                       this.cssArray = this.textStyles.getClasses();
                }
-               return newCssArray;
-       },
-       
-       parseCssRule : function(cssRules, cssArray) {
-               var newCssArray = new Object();
-               newCssArray = cssArray;
-               for (var rule = 0; rule < cssRules.length; rule++) {
-                               // StyleRule
-                       if (cssRules[rule].selectorText) {
-                               newCssArray = this.parseSelectorText(cssRules[rule].selectorText, newCssArray);
-                       } else {
-                                       // ImportRule (Mozilla)
-                               if (cssRules[rule].styleSheet) {
-                                       newCssArray = this.parseCssRule(cssRules[rule].styleSheet.cssRules, newCssArray);
-                               }
-                                       // MediaRule (Mozilla)
-                               if (cssRules[rule].cssRules) {
-                                       newCssArray = this.parseCssRule(cssRules[rule].cssRules, newCssArray);
-                               }
-                       }
+               if (this.getEditorMode() === 'wysiwyg' && this.editor.isEditable()) {
+                       this.updateToolbar('TextStyle');
                }
-               return newCssArray;
        },
-       
-       parseSelectorText : function(selectorText, cssArray) {
-               var cssElements = new Array();
-               var cssElement = new Array();
-               var tagName, className;
-               var newCssArray = new Object();
-               newCssArray = cssArray;
-               if (selectorText.search(/:+/) == -1) {
-                               // split equal Styles (Mozilla-specific) e.q. head, body {border:0px}
-                               // for ie not relevant. returns allways one element
-                       cssElements = selectorText.split(",");
-                       for (var k = 0; k < cssElements.length; k++) {
-                                       // Match ALL classes (<element name (optional)>.<class name>) in selector rule
-                               var s = cssElements[k],
-                                       pattern = /(\S*)\.(\S+)/,
-                                       index;
-                               while ((index = s.search(pattern)) > -1) {
-                                       var match = pattern.exec(s.substring(index));
-                                       s = s.substring(index+match[0].length);
-
-                                       tagName = (match[1] && (match[1] != '*')) ? match[1].toLowerCase().trim() : "all";
-                                       className = match[2];
-
-                                       if (className && !HTMLArea.reservedClassNames.test(className)) {
-                                               if (((tagName != "all") && (!this.tags || !this.tags[tagName]))
-                                                       || ((tagName == "all") && (!this.tags || !this.tags[tagName]) && this.showTagFreeClasses)
-                                                       || (this.tags && this.tags[tagName] && this.tags[tagName].allowedClasses && this.tags[tagName].allowedClasses.test(className))) {
-                                                       if (!newCssArray[tagName]) {
-                                                               newCssArray[tagName] = new Object();
-                                                       }
-                                                       if (className) {
-                                                               cssName = className;
-                                                               if (HTMLArea.classesLabels && HTMLArea.classesLabels[className]) {
-                                                                       cssName = this.prefixLabelWithClassName ? (className + " - " + HTMLArea.classesLabels[className]) : HTMLArea.classesLabels[className];
-                                                                       cssName = this.postfixLabelWithClassName ? (cssName + " - " + className) : cssName;
-                                                               }
-                                                       } else {
-                                                               className = 'none';
-                                                               cssName = this.localize("Element style");
-                                                       }
-                                                       newCssArray[tagName][className] = cssName;
-                                               }
-                                       }
-                               }
-                       }
-               }
-               return newCssArray;
-       },
-       
-       sortCssArray : function(cssArray) {
-               var newCssArray = new Object();
-               for (var tagName in cssArray) {
-                       if (cssArray.hasOwnProperty(tagName)) {
-                               newCssArray[tagName] = new Object();
-                               var tagArrayKeys = new Array();
-                               for (var cssClass in cssArray[tagName]) {
-                                       if (cssArray[tagName].hasOwnProperty(cssClass)) {
-                                               tagArrayKeys.push(cssClass);
-                                       }
-                               }
-                               function compare(a, b) {
-                                       x = cssArray[tagName][a];
-                                       y = cssArray[tagName][b];
-                                       return ((x < y) ? -1 : ((x > y) ? 1 : 0));
-                               }
-                               tagArrayKeys = tagArrayKeys.sort(compare);
-                               for (var i = 0; i < tagArrayKeys.length; ++i) {
-                                       newCssArray[tagName][tagArrayKeys[i]] = cssArray[tagName][tagArrayKeys[i]];
-                               }
-                       }
+       /*
+        * This handler gets called when the toolbar is being updated
+        */
+       onUpdateToolbar: function (button, mode, selectionEmpty, ancestors) {
+               if (mode === 'wysiwyg' && this.editor.isEditable()) {
+                       this.updateToolbar(button.itemId);
                }
-               return newCssArray;
        },
-       
        /*
-        * This function gets called when the toolbar is being updated
+        * This handler gets called when the editor has changed its mode to "wysiwyg"
         */
-       onUpdateToolbar: function(button, mode, selectionEmpty, ancestors) {
-               if (mode === "wysiwyg" && this.editor.isEditable()) {
-                       this.generate(this.editor, button.itemId);
+       onModeChange: function (mode) {
+               if (mode === 'wysiwyg' && this.editor.isEditable()) {
+                       this.updateToolbar('TextStyle');
                }
        },
-       
        /*
        * This function gets called when the drop-down list needs to be refreshed
        */
-       updateToolbar : function(dropDownId) {
+       updateToolbar: function(dropDownId) {
                var editor = this.editor;
                if (this.getEditorMode() === "wysiwyg" && this.editor.isEditable()) {
                        var tagName = false, classNames = Array(), fullNodeSelected = false;
@@ -475,11 +310,10 @@ HTMLArea.TextStyle = HTMLArea.Plugin.extend({
                        }
                }
        },
-
        /*
         * This function reinitializes the options of the dropdown
         */
-       initializeDropDown : function (dropDown) {
+       initializeDropDown: function (dropDown) {
                var store = dropDown.getStore();
                store.removeAll(false);
                store.insert(0, new store.recordType({
@@ -488,11 +322,10 @@ HTMLArea.TextStyle = HTMLArea.Plugin.extend({
                }));
                dropDown.setValue('none');
        },
-
        /*
         * This function sets the selected option of the dropDown box
         */
-       setSelectedOption : function (dropDown, classNames, noUnknown, defaultClass) {
+       setSelectedOption: function (dropDown, classNames, noUnknown, defaultClass) {
                var store = dropDown.getStore();
                var index = store.findExact('value', classNames[classNames.length-1]);
                if (index != -1) {
@@ -519,95 +352,36 @@ HTMLArea.TextStyle = HTMLArea.Plugin.extend({
                        return true;
                });
        },
-
-       updateValue : function(dropDownId, tagName, classNames, selectionEmpty, fullNodeSelected, disabled) {
+       /*
+        * This function updates the current value of the dropdown list
+        */
+       updateValue: function (dropDownId, nodeName, classNames, selectionEmpty, fullNodeSelected, disabled) {
                var editor = this.editor;
                var dropDown = this.getButton(dropDownId);
                if (dropDown) {
                        var store = dropDown.getStore();
-                       var cssArray = new Array();
                        this.initializeDropDown(dropDown);
-                       if (this.REInlineTags.test(tagName)) {
-                                       // Get classes allowed for all tags
-                               if (typeof(this.cssArray["all"]) !== "undefined") {
-                                       var cssArrayAll = this.cssArray.all;
-                                       if (this.tags && this.tags[tagName] && this.tags[tagName].allowedClasses) {
-                                               var allowedClasses = this.tags[tagName].allowedClasses;
-                                               for (var cssClass in cssArrayAll) {
-                                                       if (cssArrayAll.hasOwnProperty(cssClass) && allowedClasses.test(cssClass)) {
-                                                               cssArray[cssClass] = cssArrayAll[cssClass];
-                                                       }
-                                               }
-                                       } else {
-                                               for (var cssClass in cssArrayAll) {
-                                                       if (cssArrayAll.hasOwnProperty(cssClass)) {
-                                                               cssArray[cssClass] = cssArrayAll[cssClass];
-                                                       }
-                                               }
+                       if (this.textStyles.isReady) {
+                               var allowedClasses = {};
+                               if (this.REInlineTags.test(nodeName)) {
+                                       if (Ext.isDefined(this.cssArray[nodeName])) {
+                                               allowedClasses = this.cssArray[nodeName];
+                                       } else if (this.showTagFreeClasses && Ext.isDefined(this.cssArray['all'])) {
+                                               allowedClasses = this.cssArray['all'];
                                        }
                                }
-                                       // Merge classes allowed for tagName and sort the array
-                               if (typeof(this.cssArray[tagName]) !== "undefined") {
-                                       var cssArrayTagName = this.cssArray[tagName];
-                                       if (this.tags && this.tags[tagName] && this.tags[tagName].allowedClasses) {
-                                               var allowedClasses = this.tags[tagName].allowedClasses;
-                                               for (var cssClass in cssArrayTagName) {
-                                                       if (cssArrayTagName.hasOwnProperty(cssClass) && allowedClasses.test(cssClass)) {
-                                                               cssArray[cssClass] = cssArrayTagName[cssClass];
-                                                       }
-                                               }
-                                       } else {
-                                               for (var cssClass in cssArrayTagName) {
-                                                       if (cssArrayTagName.hasOwnProperty(cssClass)) {
-                                                               cssArray[cssClass] = cssArrayTagName[cssClass];
-                                                       }
-                                               }
-                                       }
-                                       var sortedCssArray = new Object();
-                                       var cssArrayKeys = new Array();
-                                       for (var cssClass in cssArray) {
-                                               if (cssArray.hasOwnProperty(cssClass)) {
-                                                       cssArrayKeys.push(cssClass);
-                                               }
-                                       }
-                                       function compare(a, b) {
-                                               x = cssArray[a];
-                                               y = cssArray[b];
-                                               return ((x < y) ? -1 : ((x > y) ? 1 : 0));
-                                       }
-                                       cssArrayKeys = cssArrayKeys.sort(compare);
-                                       for (var i = 0; i < cssArrayKeys.length; ++i) {
-                                               sortedCssArray[cssArrayKeys[i]] = cssArray[cssArrayKeys[i]];
-                                       }
-                                       cssArray = sortedCssArray;
-                               }
-                               for (var cssClass in cssArray) {
-                                       if (cssArray.hasOwnProperty(cssClass) && cssArray[cssClass]) {
-                                               if (cssClass == 'none') {
-                                                       store.getAt(0).set('text', cssArray[cssClass]);
-                                               } else {
-                                                       store.add(new store.recordType({
-                                                               text: cssArray[cssClass],
-                                                               value: cssClass,
-                                                               style: (!this.editor.config.disablePCexamples && HTMLArea.classesValues && HTMLArea.classesValues[cssClass] && !HTMLArea.classesNoShow[cssClass]) ? HTMLArea.classesValues[cssClass] : null
-                                                       }));
-                                               }
-                                       }
-                               }
-                               if (classNames.length && (selectionEmpty || fullNodeSelected)) {
-                                       this.setSelectedOption(dropDown, classNames);
-                               }
+                               Ext.iterate(allowedClasses, function (cssClass, value) {
+                                       store.add(new store.recordType({
+                                               text: value,
+                                               value: cssClass,
+                                               style: (!this.editor.config.disablePCexamples && HTMLArea.classesValues && HTMLArea.classesValues[cssClass] && !HTMLArea.classesNoShow[cssClass]) ? HTMLArea.classesValues[cssClass] : null
+                                       }));
+                               }, this);
+                       }
+                       if (classNames.length && (selectionEmpty || fullNodeSelected)) {
+                               this.setSelectedOption(dropDown, classNames);
                        }
                        dropDown.setDisabled(!(store.getCount()>1) || disabled);
                }
-       },
-       /*
-        * This function gets called when the editor has changed its mode to "wysiwyg"
-        */
-       onModeChange: function(mode) {
-               if (mode === "wysiwyg" && this.editor.isEditable()) {
-                       this.generate(this.editor, "TextStyle");
-               }
        }
 });
-