Index: typo3/sysext/rtehtmlarea/htmlarea/htmlarea-gecko.js =================================================================== --- typo3/sysext/rtehtmlarea/htmlarea/htmlarea-gecko.js (révision 9247) +++ typo3/sysext/rtehtmlarea/htmlarea/htmlarea-gecko.js (copie de travail) @@ -481,13 +481,13 @@ } 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: typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js =================================================================== --- typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js (révision 9247) +++ typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js (copie de travail) @@ -36,10 +36,7 @@ // 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 @@ 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 : /((.|\n)*?)<\/head>/i, @@ -63,39 +62,48 @@ 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 ***************************************************/ HTMLArea.Config = function (editorId) { @@ -2085,6 +2093,10 @@ 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 @@ 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 @@ 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.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 @@ * @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 @@ * @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.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 @@ 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 @@ 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.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 (.) 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 @@ * @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 @@ * @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 @@ * * @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 @@ * @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: typo3/sysext/rtehtmlarea/htmlarea/plugins/BlockElements/block-elements.js =================================================================== --- typo3/sysext/rtehtmlarea/htmlarea/plugins/BlockElements/block-elements.js (révision 9247) +++ typo3/sysext/rtehtmlarea/htmlarea/plugins/BlockElements/block-elements.js (copie de travail) @@ -373,10 +373,10 @@ 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 @@ } 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 @@ } } 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ // 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: typo3/sysext/rtehtmlarea/htmlarea/plugins/BlockStyle/block-style.js =================================================================== --- typo3/sysext/rtehtmlarea/htmlarea/plugins/BlockStyle/block-style.js (révision 9247) +++ typo3/sysext/rtehtmlarea/htmlarea/plugins/BlockStyle/block-style.js (copie de travail) @@ -32,20 +32,14 @@ * 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 @@ 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 @@ 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 @@ } } }, - /* * 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 @@ 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 @@ 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 @@ } 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 @@ } } }, - /* - * 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 @@ })); 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]; - } - } + 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']; } - } - // 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]; + 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 + '-']; } } - } 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; + store.add(new store.recordType({ + text: value, + value: cssClass, + style: style + })); + }, this); } - 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 + '-']; - } - } - store.add(new store.recordType({ - text: cssArray[cssClass], - value: cssClass, - style: style - })); - } - } - } }, - /* * 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 @@ }); } 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 (.) 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: typo3/sysext/rtehtmlarea/htmlarea/plugins/InlineElements/inline-elements.js =================================================================== --- typo3/sysext/rtehtmlarea/htmlarea/plugins/InlineElements/inline-elements.js (révision 9247) +++ typo3/sysext/rtehtmlarea/htmlarea/plugins/InlineElements/inline-elements.js (copie de travail) @@ -357,7 +357,7 @@ 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: typo3/sysext/rtehtmlarea/htmlarea/plugins/Language/language.js =================================================================== --- typo3/sysext/rtehtmlarea/htmlarea/plugins/Language/language.js (révision 9247) +++ typo3/sysext/rtehtmlarea/htmlarea/plugins/Language/language.js (copie de travail) @@ -216,10 +216,10 @@ */ 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 @@ } 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: typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-checker.js =================================================================== --- typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-checker.js (révision 9247) +++ typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-checker.js (copie de travail) @@ -485,13 +485,13 @@ 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 @@ 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 @@ 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 @@ } // 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 @@ * 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 @@ 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: typo3/sysext/rtehtmlarea/htmlarea/plugins/TableOperations/table-operations.js =================================================================== --- typo3/sysext/rtehtmlarea/htmlarea/plugins/TableOperations/table-operations.js (révision 9247) +++ typo3/sysext/rtehtmlarea/htmlarea/plugins/TableOperations/table-operations.js (copie de travail) @@ -264,11 +264,8 @@ } 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 @@ 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 @@ */ 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 @@ */ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ } 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 @@ 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 @@ 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 @@ */ 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: typo3/sysext/rtehtmlarea/htmlarea/plugins/TextStyle/text-style.js =================================================================== --- typo3/sysext/rtehtmlarea/htmlarea/plugins/TextStyle/text-style.js (révision 9247) +++ typo3/sysext/rtehtmlarea/htmlarea/plugins/TextStyle/text-style.js (copie de travail) @@ -36,20 +36,14 @@ /* * 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 @@ 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 @@ 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 @@ * * @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 @@ 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 @@ 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 @@ } } }, - /* * 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); - } + onCssParsingComplete: function () { + if (this.textStyles.isReady) { + this.cssArray = this.textStyles.getClasses(); } - }, - - 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); + if (this.getEditorMode() === 'wysiwyg' && this.editor.isEditable()) { + this.updateToolbar('TextStyle'); } }, - - 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; - } - } + /* + * 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; }, - - 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; - }, - - 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; - }, - - 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 (.) 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]]; - } - } - } - 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 @@ } } }, - /* * 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 @@ })); 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 @@ 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"); - } } }); -