X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=_source%2Fplugins%2Fhtmldataprocessor%2Fplugin.js;h=2bf39af58fbcbcc8dba20c589eec20c6539f1734;hb=3fe9cac293e090ea459a3ee10d78cbe9e1dd0e03;hp=f9b5deab14620bc52a86c17fff26657b7dd56c9e;hpb=9afde8772159bd3436f1f5b7862960307710ae5a;p=ckeditor.git diff --git a/_source/plugins/htmldataprocessor/plugin.js b/_source/plugins/htmldataprocessor/plugin.js index f9b5dea..2bf39af 100644 --- a/_source/plugins/htmldataprocessor/plugin.js +++ b/_source/plugins/htmldataprocessor/plugin.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -21,6 +21,11 @@ For licensing, see LICENSE.html or http://ckeditor.com/license return last; } + function getNodeIndex( node ) { + var parent = node.parent; + return parent ? CKEDITOR.tools.indexOf( parent.children, node ) : -1; + } + function trimFillers( block, fromSource ) { // If the current node is a block, and if we're converting from source or @@ -44,14 +49,14 @@ For licensing, see LICENSE.html or http://ckeditor.com/license typeof extendEmptyBlock == 'function' && ( extendEmptyBlock( block ) === false ) ) ) return false; - // 1. For IE version >=8, empty blocks are displayed correctly themself in wysiwiyg; - // 2. For the rest, at least table cell and list item need no filler space. - // (#6248) - if ( fromSource && CKEDITOR.env.ie && - ( document.documentMode > 7 - || block.name in CKEDITOR.dtd.tr - || block.name in CKEDITOR.dtd.$listItem ) ) - return false; + // 1. For IE version >=8, empty blocks are displayed correctly themself in wysiwiyg; + // 2. For the rest, at least table cell and list item need no filler space. + // (#6248) + if ( fromSource && CKEDITOR.env.ie && + ( document.documentMode > 7 + || block.name in CKEDITOR.dtd.tr + || block.name in CKEDITOR.dtd.$listItem ) ) + return false; var lastChild = lastNoneSpaceChild( block ); @@ -80,6 +85,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license var dtd = CKEDITOR.dtd; + // Define orders of table elements. + var tableOrder = [ 'caption', 'colgroup', 'col', 'thead', 'tfoot', 'tbody' ]; + // Find out the list of block-like tags that can contain
. var blockLikeTags = CKEDITOR.tools.extend( {}, dtd.$block, dtd.$listItem, dtd.$tableContent ); for ( var i in blockLikeTags ) @@ -122,8 +130,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // Attributes saved for changes and protected attributes. [ ( /^data-cke-(saved|pa)-/ ), '' ], - // All "data-cke" attributes are to be ignored. - [ ( /^data-cke.*/ ), '' ], + // All "data-cke-" attributes are to be ignored. + [ ( /^data-cke-.*/ ), '' ], [ 'hidefocus', '' ] ], @@ -153,6 +161,34 @@ For licensing, see LICENSE.html or http://ckeditor.com/license return element; }, + // The contents of table should be in correct order (#4809). + table : function( element ) + { + // Clone the array as it would become empty during the sort call. + var children = element.children.slice( 0 ); + children.sort( function ( node1, node2 ) + { + var index1, index2; + + // Compare in the predefined order. + if ( node1.type == CKEDITOR.NODE_ELEMENT && + node2.type == node1.type ) + { + index1 = CKEDITOR.tools.indexOf( tableOrder, node1.name ); + index2 = CKEDITOR.tools.indexOf( tableOrder, node2.name ); + } + + // Make sure the sort is stable, if no order can be established above. + if ( !( index1 > -1 && index2 > -1 && index1 != index2 ) ) + { + index1 = getNodeIndex( node1 ); + index2 = getNodeIndex( node2 ); + } + + return index1 > index2 ? 1 : -1; + } ); + }, + embed : function( element ) { var parent = element.parent; @@ -193,6 +229,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license delete element.name; }, + // Empty
 in IE is reported with filler node ( ).
+				pre : function( element ) { CKEDITOR.env.ie && trimFillers( element ); },
+
 				html : function( element )
 				{
 					delete element.attributes.contenteditable;
@@ -228,43 +267,41 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 					// Remove all class names starting with "cke_".
 					return CKEDITOR.tools.ltrim( value.replace( /(?:^|\s+)cke_[^\s]*/g, '' ) ) || false;
 				}
-			},
-
-			comment : function( contents )
-			{
-				// If this is a comment for protected source.
-				if ( contents.substr( 0, protectedSourceMarker.length ) == protectedSourceMarker )
-				{
-					// Remove the extra marker for real comments from it.
-					if ( contents.substr( protectedSourceMarker.length, 3 ) == '{C}' )
-						contents = contents.substr( protectedSourceMarker.length + 3 );
-					else
-						contents = contents.substr( protectedSourceMarker.length );
-
-					return new CKEDITOR.htmlParser.cdata( decodeURIComponent( contents ) );
-				}
-
-				return contents;
 			}
 		};
 
 	if ( CKEDITOR.env.ie )
 	{
 		// IE outputs style attribute in capital letters. We should convert
-		// them back to lower case.
+		// them back to lower case, while not hurting the values (#5930)
 		defaultHtmlFilterRules.attributes.style = function( value, element )
 		{
-			return value.toLowerCase();
+			return value.replace( /(^|;)([^\:]+)/g, function( match )
+				{
+					return match.toLowerCase();
+				});
 		};
 	}
 
 	function protectReadOnly( element )
 	{
-		element.attributes.contenteditable = "false";
+		var attrs = element.attributes;
+
+		// We should flag that the element was locked by our code so
+		// it'll be editable by the editor functions (#6046).
+		if ( attrs.contenteditable != "false" )
+			attrs[ 'data-cke-editable' ] = attrs.contenteditable ? 'true' : 1;
+
+		attrs.contenteditable = "false";
 	}
 	function unprotectReadyOnly( element )
 	{
-		delete element.attributes.contenteditable;
+		var attrs = element.attributes;
+		switch( attrs[ 'data-cke-editable' ] )
+		{
+			case 'true':	attrs.contenteditable = 'true';	break;
+			case '1':		delete attrs.contenteditable;	break;
+		}
 	}
 	// Disable form elements editing mode provided by some browers. (#5746)
 	for ( i in { input : 1, textarea : 1 } )
@@ -273,8 +310,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 		defaultHtmlFilterRules.elements[ i ] = unprotectReadyOnly;
 	}
 
-	var protectAttributeRegex = /<((?:a|area|img|input)\b[\s\S]*?\s)((href|src|name)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+)))([^>]*)>/gi,
-		findSavedSrcRegex = /\sdata-cke-saved-src\s*=/;
+	var protectElementRegex = /<(a|area|img|input|source)\b([^>]*)>/gi,
+		protectAttributeRegex = /\b(on\w+|href|src|name)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+))/gi;
 
 	var protectElementsRegex = /(?:])[^>]*>[\s\S]*<\/style>)|(?:<(:?link|meta|base)[^>]*>)/gi,
 		encodedElementsRegex = /([^<]*)<\/cke:encoded>/gi;
@@ -286,14 +323,18 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 
 	function protectAttributes( html )
 	{
-		return html.replace( protectAttributeRegex, function( tag, beginning, fullAttr, attrName, end )
+		return html.replace( protectElementRegex, function( element, tag, attributes )
+		{
+			return '<' +  tag + attributes.replace( protectAttributeRegex, function( fullAttr, attrName )
 			{
-				// We should not rewrite the _cke_saved_src attribute (#5218)
-				if ( attrName == 'src' && findSavedSrcRegex.test( tag ) )
-					return tag;
-				else
-					return '<' + beginning + fullAttr + ' data-cke-saved-' + fullAttr + end + '>';
-			});
+				// Avoid corrupting the inline event attributes (#7243).
+				// We should not rewrite the existed protected attributes, e.g. clipboard content from editor. (#5218)
+				if ( !( /^on/ ).test( attrName ) && attributes.indexOf( 'data-cke-saved-' + attrName ) == -1 )
+					return ' data-cke-saved-' + fullAttr + ' data-cke-' + CKEDITOR.rnd + '-' + fullAttr;
+
+				return fullAttr;
+			}) + '>';
+		});
 	}
 
 	function protectElements( html )
@@ -351,9 +392,24 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 			});
 	}
 
-	function protectSource( data, protectRegexes )
+	function unprotectSource( html, editor )
+	{
+		var store = editor._.dataStore;
+
+		return html.replace( //g, function( match, data )
+			{
+				return decodeURIComponent( data );
+			}).replace( /\{cke_protected_(\d+)\}/g, function( match, id )
+			{
+				return store && store[ id ] || '';
+			});
+	}
+
+	function protectSource( data, editor )
 	{
 		var protectedHtml = [],
+			protectRegexes = editor.config.protectedSource,
+			store = editor._.dataStore || ( editor._.dataStore = { id : 1 } ),
 			tempRegex = /<\!--\{cke_temp(comment)?\}(\d*?)-->/g;
 
 		var regexes =
@@ -386,7 +442,10 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 							return protectedHtml[ id ];
 						}
 					);
-					return  '';
+
+					// Avoid protecting over protected, e.g. /\{.*?\}/
+					return ( /cke_temp(comment)?/ ).test( match ) ? match
+						: '';
 				});
 		}
 		data = data.replace( tempRegex,	function( $, isComment, id )
@@ -397,7 +456,17 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 						'-->';
 			}
 		);
-		return data;
+
+		// Different protection pattern is used for those that
+		// live in attributes to avoid from being HTML encoded.
+		return data.replace( /(['"]).*?\1/g, function ( match )
+		{
+			return match.replace( //g, function( match, data )
+			{
+				store[ store.id ] = decodeURIComponent( data );
+				return '{cke_protected_'+ ( store.id++ )  + '}';
+			});
+		});
 	}
 
 	CKEDITOR.plugins.add( 'htmldataprocessor',
@@ -443,7 +512,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 			// The source data is already HTML, but we need to clean
 			// it up and apply the filter.
 
-			data = protectSource( data, this.editor.config.protectedSource );
+			data = protectSource( data, this.editor );
 
 			// Before anything, we must protect the URL attributes as the
 			// browser may changing them when setting the innerHTML later in
@@ -469,10 +538,14 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 			// Call the browser to help us fixing a possibly invalid HTML
 			// structure.
 			var div = new CKEDITOR.dom.element( 'div' );
+
 			// Add fake character to workaround IE comments bug. (#3801)
 			div.setHtml( 'a' + data );
 			data = div.getHtml().substr( 1 );
 
+			// Restore shortly protected attribute names.
+			data = data.replace( new RegExp( ' data-cke-' + CKEDITOR.rnd + '-', 'ig' ), ' ' );
+
 			// Unprotect "some" of the protected elements at this point.
 			data = unprotectElementNames( data );
 
@@ -505,7 +578,13 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 
 			fragment.writeHtml( writer, this.htmlFilter );
 
-			return writer.getHtml( true );
+			var data = writer.getHtml( true );
+
+			// Restore those non-HTML protected source. (#4475,#4880)
+			data = unprotectRealComments( data );
+			data = unprotectSource( data, this.editor );
+
+			return data;
 		}
 	};
 })();