diff --git a/build/ctct-generic-content-handler-changelog.md b/build/ctct-generic-content-handler-changelog.md new file mode 100644 index 0000000000..26af7c4144 --- /dev/null +++ b/build/ctct-generic-content-handler-changelog.md @@ -0,0 +1,4 @@ +- **ENHANCEMENT**: Enhances the generic content handler removeComments function to remove comments that appear + as text nodes in Firefox. This change also refactors the code in the generic content handler to + be configuration driven. Each sub-handler run by this content handler can be enabled or disabled + via the Aloha.settings.contentHandler.handler.generic configuration. \ No newline at end of file diff --git a/doc/guides/source/plugin_contenthandler.textile b/doc/guides/source/plugin_contenthandler.textile index 385d7ae849..dd4cc01159 100644 --- a/doc/guides/source/plugin_contenthandler.textile +++ b/doc/guides/source/plugin_contenthandler.textile @@ -88,12 +88,12 @@ h4. Writing your own Content Handler ['aloha', 'jquery', 'aloha/contenthandlermanager'], function(Aloha, jQuery, ContentHandlerManager) { "use strict"; - + var MyContentHandler = ContentHandlerManager.createHandler({ handleContent: function( content ) { - + // do something with the content - + return content; // return as HTML text not jQuery/DOM object } }); @@ -157,6 +157,21 @@ The Generic Content Handler is a bit less generic than his name might suggest as ** ++ and ++ to ++ ** and by removing ++ tags (as underline text decoration should solely be used for links) +You may specify which of the above cleaning actions will e run bgy supplying your own configuration based on these default settings: + + +Aloha.settings.contentHandler.generic = { + prepareTableContents: true, + cleanLists: true, + removeComments: true, + unwrapTags: true, + removeStyles: true, + removeNamespacedElements: true, + transformFormattings: true, + transformLinks: false +} + + h4. Sanitize Content Handler WARNING: The Sanitize Content Handler does not work reliably on IE7, and will therefore just do nothing, if this browser is detected. diff --git a/src/plugins/common/contenthandler/lib/genericcontenthandler.js b/src/plugins/common/contenthandler/lib/genericcontenthandler.js index eae1486bb8..28a735192c 100755 --- a/src/plugins/common/contenthandler/lib/genericcontenthandler.js +++ b/src/plugins/common/contenthandler/lib/genericcontenthandler.js @@ -29,128 +29,156 @@ define([ 'aloha', 'aloha/contenthandlermanager', 'contenthandler/contenthandler-utils' -], function ( - $, - Aloha, - Manager, - Utils -) { +], function ($, Aloha, Manager, Utils ) { 'use strict'; - /** - * Tags used for semantic formatting - * @type {Array.} - * @see GenericContentHandler#transformFormattings - */ - var formattingTags = ['strong', 'em', 's', 'u', 'strike']; - - /** - * Checks whether the markup describes a paragraph that is propped by - * a
tag but is otherwise empty. - * - * Will return true for: - * - *


- * - * as well as: - * - *


- * - * @param {string} html Markup - * @return {boolean} True if html describes a propped paragraph. - */ - function isProppedParagraph(html) { - var trimmed = $.trim(html); - if (!trimmed) { - return false; - } - var node = $('
' + trimmed + '
')[0]; - var containsSingleP = node.firstChild === node.lastChild - && 'p' === node.firstChild.nodeName.toLowerCase(); - if (containsSingleP) { - var kids = node.firstChild.children; - return (kids && 1 === kids.length && - 'br' === kids[0].nodeName.toLowerCase()); - } - return false; - } - - - /** - * Transforms all tables in the given content to make them ready to for - * use with Aloha's table handling. - * - * Cleans tables of their unwanted attributes. - * Normalizes table cells. - * - * @param {jQuery.} $content - */ - function prepareTables($content) { - // Because Aloha does not provide a way for the editor to - // manipulate borders, cellspacing, cellpadding in tables. - // @todo what about width, height? - $content.find('table') - .removeAttr('cellpadding') - .removeAttr('cellspacing') - .removeAttr('border') - .removeAttr('border-top') - .removeAttr('border-bottom') - .removeAttr('border-left') - .removeAttr('border-right'); - - $content.find('td').each(function () { - var td = this; - - // Because cells with a single empty

are rendered to appear - // like empty cells, it simplifies the handeling of cells to - // normalize these table cells to contain actual white space - // instead. - if (isProppedParagraph(td.innerHTML)) { - td.innerHTML = ' '; - } - - // Because a single

wrapping the contents of a is - // initially superfluous and should be stripped out. - var $p = $('>p', td); - if (1 === $p.length) { - $p.contents().unwrap(); - } - }); - - // Because Aloha does not provide a means for editors to manipulate - // these properties. - $content.find('table,th,td,tr') - .removeAttr('width') - .removeAttr('height') - .removeAttr('valign'); - - // Because Aloha table handling simply does not regard colgroups. - // @TODO Use sanitize.js? - $content.find('colgroup').remove(); - } - - /** - * Return true if the nodeType is allowed in the settings, - * Aloha.settings.contentHandler.allows.elements - * - * @param {String} nodeType The tag name of the element to evaluate - * - * @return {Boolean} - */ - function isAllowedNodeName(nodeType){ - return !!( - Aloha.settings.contentHandler - && Aloha.settings.contentHandler.allows - && Aloha.settings.contentHandler.allows.elements - && ($.inArray( - nodeType.toLowerCase(), - Aloha.settings.contentHandler.allows.elements - ) !== -1 - ) - ); - } - - var GenericContentHandler = Manager.createHandler({ + var defaultConfig = { + handlers: { + prepareTableContents: true, + cleanLists: true, + removeComments: true, + unwrapTags: true, + removeStyles: true, + removeNamespacedElements: true, + transformFormattings: true, + transformLinks: false + } + }; + + var handlers = (function() { + var config = {}; + var init = function() { + if (Aloha.settings.contentHandler + && Aloha.settings.contentHandler.handler + && Aloha.settings.contentHandler.handler.generic) { + config = jQuery.extend({}, defaultConfig.handlers, Aloha.settings.contentHandler.handler.generic); + } else { + config = defaultConfig.handlers; + } + }; + + return { + config: function() { + init(); + return config; + } + }; + })(); + + /** + * Tags used for semantic formatting + * @type {Array.} + * @see GenericContentHandler#transformFormattings + */ + var formattingTags = ['strong', 'em', 's', 'u', 'strike']; + + /** + * Checks whether the markup describes a paragraph that is propped by + * a
tag but is otherwise empty. + * + * Will return true for: + * + *


+ * + * as well as: + * + *


+ * + * @param {string} html Markup + * @return {boolean} True if html describes a propped paragraph. + */ + function isProppedParagraph(html) { + var trimmed = $.trim(html); + if (!trimmed) { + return false; + } + var node = $('
' + trimmed + '
')[0]; + var containsSingleP = node.firstChild === node.lastChild + && 'p' === node.firstChild.nodeName.toLowerCase(); + if (containsSingleP) { + var kids = node.firstChild.children; + return (kids && 1 === kids.length && + 'br' === kids[0].nodeName.toLowerCase()); + } + return false; + } + + + /** + * Transforms all tables in the given content to make them ready to for + * use with Aloha's table handling. + * + * Cleans tables of their unwanted attributes. + * Normalizes table cells. + * + * @param {jQuery.} $content + */ + function prepareTables($content) { + // Because Aloha does not provide a way for the editor to + // manipulate borders, cellspacing, cellpadding in tables. + // @todo what about width, height? + $content.find('table') + .removeAttr('cellpadding') + .removeAttr('cellspacing') + .removeAttr('border') + .removeAttr('border-top') + .removeAttr('border-bottom') + .removeAttr('border-left') + .removeAttr('border-right'); + + $content.find('td').each(function () { + var td = this; + + // Because cells with a single empty

are rendered to appear + // like empty cells, it simplifies the handeling of cells to + // normalize these table cells to contain actual white space + // instead. + if (isProppedParagraph(td.innerHTML)) { + td.innerHTML = ' '; + } + + // Because a single

wrapping the contents of a is + // initially superfluous and should be stripped out. + var $p = $('>p', td); + if (1 === $p.length) { + $p.contents().unwrap(); + } + }); + + // Because Aloha does not provide a means for editors to manipulate + // these properties. + $content.find('table,th,td,tr') + .removeAttr('width') + .removeAttr('height') + .removeAttr('valign'); + + // Because Aloha table handling simply does not regard colgroups. + // @TODO Use sanitize.js? + $content.find('colgroup').remove(); + } + + /** + * Return true if the nodeType is allowed in the settings, + * Aloha.settings.contentHandler.allows.elements + * + * @param {String} nodeType The tag name of the element to evaluate + * + * @return {Boolean} + */ + function isAllowedNodeName(nodeType){ + return !!( + Aloha.settings.contentHandler + && Aloha.settings.contentHandler.allows + && Aloha.settings.contentHandler.allows.elements + && ($.inArray( + nodeType.toLowerCase(), + Aloha.settings.contentHandler.allows.elements + ) !== -1 + ) + ); + } + + var GenericContentHandler = Manager.createHandler({ /** * Transforms pasted content to make it safe and ready to be used in @@ -173,31 +201,25 @@ define([ return $content.html(); } - prepareTables($content); - this.cleanLists($content); - this.removeComments($content); - this.unwrapTags($content); - this.removeStyles($content); - this.removeNamespacedElements($content); - //this.transformLinks($content); - - var transformFormatting = true; - - if (Aloha.settings.contentHandler - && Aloha.settings.contentHandler.handler - && Aloha.settings.contentHandler.handler.generic - && typeof Aloha.settings.contentHandler.handler.generic.transformFormattings !== 'undefinded' - && !Aloha.settings.contentHandler.handler.generic.transformFormattings ) { - transformFormatting = false; - } - - if (transformFormatting) { - this.transformFormattings($content); - } + // Run each configured handler. + var handler, config = handlers.config(); + for (handler in config) { + if (config[handler]) { + this[handler]($content); + } + } return $content.html(); }, + /** + * Prepares table contents + * @param $content + */ + prepareTableContents: function($content) { + prepareTables($content); + }, + /** * Cleans lists. * The only allowed children of ol or ul elements are li's. Everything @@ -274,6 +296,9 @@ define([ content.contents().each(function () { if (this.nodeType === 8) { $(this).remove(); + } else if (this.nodeType == 3) { + // In FF, comments appear as text nodes + this.textContent = this.textContent.replace(//g, ''); } else { // do recursion that.removeComments($(this));