X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=_source%2Fcore%2Fhtmlparser%2Ffragment.js;h=9db04dd8b0bd8eff3ed3ce966bdb7eb4a547bb0c;hb=039a051ccf3901311661022a30afd60fc38130c9;hp=66bb3be0e9f8d848f29e8744e630a5aca630a400;hpb=7cd80714081a8ffdf4a1a8d2c72f120ed5ef3d6d;p=ckeditor.git diff --git a/_source/core/htmlparser/fragment.js b/_source/core/htmlparser/fragment.js index 66bb3be..9db04dd 100644 --- a/_source/core/htmlparser/fragment.js +++ b/_source/core/htmlparser/fragment.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -64,6 +64,7 @@ CKEDITOR.htmlParser.fragment = function() html = [], fragment = new CKEDITOR.htmlParser.fragment(), pendingInline = [], + pendingBRs = [], currentNode = fragment, // Indicate we're inside a
 element, spaces should be touched differently.
 			inPre = false,
@@ -71,6 +72,8 @@ CKEDITOR.htmlParser.fragment = function()
 
 		function checkPending( newTagName )
 		{
+			var pendingBRsSent;
+
 			if ( pendingInline.length > 0 )
 			{
 				for ( var i = 0 ; i < pendingInline.length ; i++ )
@@ -82,6 +85,12 @@ CKEDITOR.htmlParser.fragment = function()
 
 					if ( ( !currentDtd || currentDtd[ pendingName ] ) && ( !newTagName || !pendingDtd || pendingDtd[ newTagName ] || !CKEDITOR.dtd[ newTagName ] ) )
 					{
+						if ( !pendingBRsSent )
+						{
+							sendPendingBRs();
+							pendingBRsSent = 1;
+						}
+
 						// Get a clone for the pending element.
 						pendingElement = pendingElement.clone();
 
@@ -99,6 +108,12 @@ CKEDITOR.htmlParser.fragment = function()
 			}
 		}
 
+		function sendPendingBRs( brsToIgnore )
+		{
+			while ( pendingBRs.length - ( brsToIgnore || 0 ) > 0 )
+				currentNode.add( pendingBRs.shift() );
+		}
+
 		function addElement( element, target, enforceCurrent )
 		{
 			target = target || currentNode || fragment;
@@ -114,7 +129,9 @@ CKEDITOR.htmlParser.fragment = function()
 					elementName = realElementName;
 				else
 					elementName =  element.name;
-				if ( !( elementName in CKEDITOR.dtd.$body ) )
+				if ( elementName
+						&& !( elementName in CKEDITOR.dtd.$body )
+						&& !( elementName in CKEDITOR.dtd.$nonBodyContent )  )
 				{
 					var savedCurrent = currentNode;
 
@@ -179,32 +196,38 @@ CKEDITOR.htmlParser.fragment = function()
 				return;
 			}
 
-			var currentName = currentNode.name,
-				currentDtd = ( currentName && CKEDITOR.dtd[ currentName ] ) || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span );
+			if ( tagName == 'br' )
+			{
+				pendingBRs.push( element );
+				return;
+			}
+
+			var currentName = currentNode.name;
+
+			var currentDtd = currentName
+				&& ( CKEDITOR.dtd[ currentName ]
+					|| ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ) );
 
 			// If the element cannot be child of the current element.
-			if ( !element.isUnknown && !currentNode.isUnknown && !currentDtd[ tagName ] )
+			if ( currentDtd   // Fragment could receive any elements.
+				 && !element.isUnknown && !currentNode.isUnknown && !currentDtd[ tagName ] )
 			{
-				// If this is the fragment node, just ignore this tag and add
-				// its children.
-				if ( !currentName )
-					return;
 
 				var reApply = false,
 					addPoint;   // New position to start adding nodes.
 
-				// Fixing malformed nested lists(#3828).
-				if( tagName in listBlocks
+				// Fixing malformed nested lists by moving it into a previous list item. (#3828)
+				if ( tagName in listBlocks
 					&& currentName in listBlocks )
 				{
 					var children = currentNode.children,
 						lastChild = children[ children.length - 1 ];
-					// Move inner list into to previous list item if any.
-					if( lastChild && lastChild.name in listItems )
-						returnPoint = currentNode, addPoint = lastChild;
-					// Move inner list outside in the worst case.
-					else
-						addElement( currentNode, currentNode.parent );
+
+					// Establish the list item if it's not existed.
+					if ( !( lastChild && lastChild.name in listItems ) )
+						addElement( ( lastChild = new CKEDITOR.htmlParser.element( 'li' ) ), currentNode );
+
+					returnPoint = currentNode, addPoint = lastChild;
 				}
 				// If the element name is the same as the current element name,
 				// then just close the current one and append the new one to the
@@ -214,6 +237,12 @@ CKEDITOR.htmlParser.fragment = function()
 				{
 					addElement( currentNode, currentNode.parent );
 				}
+				else if ( tagName in CKEDITOR.dtd.$listItem )
+				{
+					parser.onTagOpen( 'ul', {} );
+					addPoint = currentNode;
+					reApply = true;
+				}
 				else
 				{
 					if ( nonBreakingBlocks[ currentName ] )
@@ -237,7 +266,7 @@ CKEDITOR.htmlParser.fragment = function()
 					reApply = true;
 				}
 
-				if( addPoint )
+				if ( addPoint )
 					currentNode = addPoint;
 				// Try adding it to the return point, or the parent element.
 				else
@@ -251,6 +280,7 @@ CKEDITOR.htmlParser.fragment = function()
 			}
 
 			checkPending( tagName );
+			sendPendingBRs();
 
 			element.parent = currentNode;
 			element.returnPoint = returnPoint;
@@ -276,14 +306,16 @@ CKEDITOR.htmlParser.fragment = function()
 			}
 
 			var pendingAdd = [],
+				newPendingInline = [],
 				candidate = currentNode;
 
 			while ( candidate.type && candidate.name != tagName )
 			{
-				// If this is an inline element, add it to the pending list, so
-				// it will continue after the closing tag.
+				// If this is an inline element, add it to the pending list, if we're
+				// really closing one of the parents element later, they will continue
+				// after it.
 				if ( !candidate._.isBlockLike )
-					pendingInline.unshift( candidate );
+					newPendingInline.unshift( candidate );
 
 				// This node should be added to it's parent at this point. But,
 				// it should happen only if the closing tag is really closing
@@ -304,16 +336,24 @@ CKEDITOR.htmlParser.fragment = function()
 
 				currentNode = candidate;
 
-				if( currentNode.name == 'pre' )
+				if ( currentNode.name == 'pre' )
 					inPre = false;
 
+				if ( candidate._.isBlockLike )
+					sendPendingBRs();
+
 				addElement( candidate, candidate.parent );
 
 				// The parent should start receiving new nodes now, except if
 				// addElement changed the currentNode.
 				if ( candidate == currentNode )
 					currentNode = currentNode.parent;
+
+				pendingInline = pendingInline.concat( newPendingInline );
 			}
+
+			if ( tagName == 'body' )
+				fixForBody = false;
 		};
 
 		parser.onText = function( text )
@@ -327,10 +367,15 @@ CKEDITOR.htmlParser.fragment = function()
 					return;
 			}
 
+			sendPendingBRs();
 			checkPending();
 
-			if ( fixForBody && !currentNode.type )
+			if ( fixForBody
+				 && ( !currentNode.type || currentNode.name == 'body' )
+				 && CKEDITOR.tools.trim( text ) )
+			{
 				this.onTagOpen( fixForBody, {} );
+			}
 
 			// Shrinking consequential spaces into one single for all elements
 			// text contents.
@@ -347,19 +392,25 @@ CKEDITOR.htmlParser.fragment = function()
 
 		parser.onComment = function( comment )
 		{
+			checkPending();
 			currentNode.add( new CKEDITOR.htmlParser.comment( comment ) );
 		};
 
 		// Parse it.
 		parser.parse( fragmentHtml );
 
+		// Send all pending BRs except one, which we consider a unwanted bogus. (#5293)
+		sendPendingBRs( !CKEDITOR.env.ie && 1 );
+
 		// Close all pending nodes.
 		while ( currentNode.type )
 		{
 			var parent = currentNode.parent,
 				node = currentNode;
 
-			if ( fixForBody && !parent.type && !CKEDITOR.dtd.$body[ node.name ] )
+			if ( fixForBody
+				 && ( !parent.type || parent.name == 'body' )
+				 && !CKEDITOR.dtd.$body[ node.name ] )
 			{
 				currentNode = parent;
 				parser.onTagOpen( fixForBody, {} );
@@ -428,7 +479,25 @@ CKEDITOR.htmlParser.fragment = function()
 		 */
 		writeHtml : function( writer, filter )
 		{
-			for ( var i = 0, len = this.children.length ; i < len ; i++ )
+			var isChildrenFiltered;
+			this.filterChildren = function()
+			{
+				var writer = new CKEDITOR.htmlParser.basicWriter();
+				this.writeChildrenHtml.call( this, writer, filter, true );
+				var html = writer.getHtml();
+				this.children = new CKEDITOR.htmlParser.fragment.fromHtml( html ).children;
+				isChildrenFiltered = 1;
+			};
+
+			// Filtering the root fragment before anything else.
+			!this.name && filter && filter.onFragment( this );
+
+			this.writeChildrenHtml( writer, isChildrenFiltered ? null : filter );
+		},
+
+		writeChildrenHtml : function( writer, filter )
+		{
+			for ( var i = 0 ; i < this.children.length ; i++ )
 				this.children[i].writeHtml( writer, filter );
 		}
 	};