From 66f1a19089b4e3621387ae8db1be8861dba6cacc Mon Sep 17 00:00:00 2001 From: Andrew Nacin Date: Fri, 7 Dec 2012 11:26:25 +0000 Subject: [PATCH] Add a sane, inclusive HTML element/attribute schema to TinyMCE. TinyMCE 3.4.x (shipped with WordPress 3.4.x) had an HTML4-based schema definition, with HTML5 elements added to it. TinyMCE 3.5.x (shipping, again coincidentally, with WordPress 3.5) allows for HTML5 schema support, which also provides for full HTML5 attribute support. The problem is its HTML5 schema excludes all HTML4 elements and attributes that were dropped in the HTML5 spec, which is unacceptable behavior. This "duck punch" of TinyMCE's Schema.js file creates a new, sane schema. It is TinyMCE's HTML4 and HTML5 schema definitions recursively merged. Objects are not whitelisted in either schema to allow for embed elements as child nodes, so object, param, and embed remain separately whitelisted in the WordPress TinyMCE plugin. Our attempts to add other attributes in said plugin is now superceded. props koopersmith, azaozz. fixes #22790. git-svn-id: https://develop.svn.wordpress.org/trunk@23120 602fd350-edb4-49c9-b593-d223f7449a82 --- wp-includes/class-wp-editor.php | 6 +- .../plugins/wordpress/editor_plugin_src.js | 15 +---- wp-includes/js/tinymce/wp-tinymce-schema.js | 63 ++++++++++++++++++- wp-includes/js/tinymce/wp-tinymce.php | 1 + 4 files changed, 67 insertions(+), 18 deletions(-) diff --git a/wp-includes/class-wp-editor.php b/wp-includes/class-wp-editor.php index e1e36abe8d..baefc7c696 100644 --- a/wp-includes/class-wp-editor.php +++ b/wp-includes/class-wp-editor.php @@ -569,10 +569,12 @@ final class _WP_Editors { $baseurl = self::$baseurl; if ( $tmce_on ) { - if ( $compressed ) + if ( $compressed ) { echo "\n"; - else + } else { echo "\n"; + echo "\n"; + } if ( 'en' != self::$mce_locale && isset($lang) ) echo "\n"; diff --git a/wp-includes/js/tinymce/plugins/wordpress/editor_plugin_src.js b/wp-includes/js/tinymce/plugins/wordpress/editor_plugin_src.js index 3c4dc9b20a..e5a512d631 100644 --- a/wp-includes/js/tinymce/plugins/wordpress/editor_plugin_src.js +++ b/wp-includes/js/tinymce/plugins/wordpress/editor_plugin_src.js @@ -135,21 +135,8 @@ } }); - // Add obsolete HTML attributes that are still in use. + // Extend and (#WP22790) ed.onPreInit.add(function(ed) { - // The commonAttr are from TinyMCE 3.5.7 getHTML5() - // Obsolete attributes are from TinyMCE 3.5.7 getHTML4() - var commonAttr = 'id|accesskey|class|dir|draggable|item|hidden|itemprop|role|spellcheck|style|subject|title|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup', - tdAttr = commonAttr + '|abbr|axis|headers|scope|rowspan|colspan|char|charoff|align|valign|halign|nowrap|bgcolor|width|height'; - // Obsolete table attributes - ed.schema.addValidElements('table['+commonAttr+'|summary|width|border|frame|rules|cellspacing|cellpadding|align|bgcolor]'); - // Obsolete tr attributes - ed.schema.addValidElements('tr['+commonAttr+'|align|char|charoff|valign|halign|bgcolor]'); - // Obsolete td and th attributes - ed.schema.addValidElements('td['+tdAttr+'],th['+tdAttr+']'); - // Adds "name" for - ed.schema.addValidElements('a['+commonAttr+'|href|target|ping|rel|media|type|name]'); - // Extend and ed.schema.addValidElements('object[*],param[id|name|value|valuetype|type],embed[*]'); ed.schema.addValidChildren('object[*]'); }); diff --git a/wp-includes/js/tinymce/wp-tinymce-schema.js b/wp-includes/js/tinymce/wp-tinymce-schema.js index afd03d225d..2115ffc80b 100644 --- a/wp-includes/js/tinymce/wp-tinymce-schema.js +++ b/wp-includes/js/tinymce/wp-tinymce-schema.js @@ -1,5 +1,7 @@ /** - * Schema.js + * TinyMCE Schema.js + * + * Duck-punched by WordPress core to support a sane schema superset. * * Copyright, Moxiecode Systems AB * Released under LGPL License. @@ -319,6 +321,59 @@ return html4; }; + /** + * WordPress Core + * + * Returns a schema that is the result of a deep merge between the HTML5 + * and HTML4 schemas. + */ + function getSaneSchema() { + var cachedMapCache = mapCache, + html5, html4; + + if ( mapCache.sane ) + return mapCache.sane; + + // Bust the mapCache so we're not dealing with the other schema objects. + mapCache = {}; + html5 = getHTML5(); + html4 = getHTML4(); + mapCache = cachedMapCache; + + each( html4, function( html4settings, tag ) { + var html5settings = html5[ tag ], + difference = []; + + // Merge tags missing in HTML5 mode. + if ( ! html5settings ) { + html5[ tag ] = html4settings; + return; + } + + // Merge attributes missing from this HTML5 tag. + each( html4settings.attributes, function( attribute, key ) { + if ( ! html5settings.attributes[ key ] ) + html5settings.attributes[ key ] = attribute; + }); + + // Merge any missing attributes into the attributes order. + each( html4settings.attributesOrder, function( key ) { + if ( -1 === tinymce.inArray( html5settings.attributesOrder, key ) ) + difference.push( key ); + }); + + html5settings.attributesOrder = html5settings.attributesOrder.concat( difference ); + + // Merge children missing from this HTML5 tag. + each( html4settings.children, function( child, key ) { + if ( ! html5settings.children[ key ] ) + html5settings.children[ key ] = child; + }); + }); + + return mapCache.sane = html5; + } + /** * Schema validator class. * @@ -368,7 +423,11 @@ }; settings = settings || {}; - schemaItems = settings.schema == "html5" ? getHTML5() : getHTML4(); + + /** + * WordPress core uses a sane schema in place of the default "HTML5" schema. + */ + schemaItems = settings.schema == "html5" ? getSaneSchema() : getHTML4(); // Allow all elements and attributes if verify_html is set to false if (settings.verify_html === false) diff --git a/wp-includes/js/tinymce/wp-tinymce.php b/wp-includes/js/tinymce/wp-tinymce.php index c2cf33ca34..83a003d720 100644 --- a/wp-includes/js/tinymce/wp-tinymce.php +++ b/wp-includes/js/tinymce/wp-tinymce.php @@ -33,5 +33,6 @@ if ( isset($_GET['c']) && 1 == $_GET['c'] && isset($_SERVER['HTTP_ACCEPT_ENCODIN echo $file; } else { echo get_file($basepath . '/tiny_mce.js'); + echo get_file($basepath . '/wp-tinymce-schema.js'); } exit;