, specially in IE. Do not enter in this if block in this case.
- if ( tagName == currentName )
- {
- addElement( currentNode, currentNode.parent );
- }
- else
+ // If the element cannot be child of the current element.
+ if ( !element.isUnknown && !currentNode.isUnknown && !currentDtd[ tagName ] )
{
- if ( nonBreakingBlocks[ currentName ] )
+ // Current node doesn't have a close tag, time for a close
+ // as this element isn't fit in. (#7497)
+ if ( currentNode.isOptionalClose )
+ parser.onTagClose( currentName );
+ // Fixing malformed nested lists by moving it into a previous list item. (#3828)
+ else if ( tagName in listBlocks
+ && currentName in listBlocks )
+ {
+ var children = currentNode.children,
+ lastChild = children[ children.length - 1 ];
+
+ // Establish the list item if it's not existed.
+ if ( !( lastChild && lastChild.name == 'li' ) )
+ addElement( ( lastChild = new CKEDITOR.htmlParser.element( 'li' ) ), currentNode );
+
+ !element.returnPoint && ( element.returnPoint = currentNode );
+ currentNode = lastChild;
+ }
+ // Establish new list root for orphan list items.
+ else if ( tagName in CKEDITOR.dtd.$listItem && currentName != tagName )
+ parser.onTagOpen( tagName == 'li' ? 'ul' : 'dl', {}, 0, 1 );
+ // We're inside a structural block like table and list, AND the incoming element
+ // is not of the same type (e.g. td1 | td2 | ), we simply add this new one before it,
+ // and most importantly, return back to here once this element is added,
+ // e.g.
+ else if ( currentName in nonBreakingBlocks && currentName != tagName )
{
- if ( !returnPoint )
- returnPoint = currentNode;
+ !element.returnPoint && ( element.returnPoint = currentNode );
+ currentNode = currentNode.parent;
}
else
{
- addElement( currentNode, currentNode.parent, true );
+ // The current element is an inline element, which
+ // need to be continued even after the close, so put
+ // it in the pending list.
+ if ( currentName in CKEDITOR.dtd.$inline )
+ pendingInline.unshift( currentNode );
- if ( !optionalClose[ currentName ] )
+ // The most common case where we just need to close the
+ // current one and append the new one to the parent.
+ if ( currentNode.parent )
+ addElement( currentNode, currentNode.parent, 1 );
+ // We've tried our best to fix the embarrassment here, while
+ // this element still doesn't find it's parent, mark it as
+ // orphan and show our tolerance to it.
+ else
{
- // The current element is an inline element, which
- // cannot hold the new one. Put it in the pending list,
- // and try adding the new one after it.
- pendingInline.unshift( currentNode );
+ element.isOrphan = 1;
+ break;
}
}
-
- reApply = true;
- }
-
- // In any of the above cases, we'll be adding, or trying to
- // add it to the parent.
- currentNode = currentNode.returnPoint || currentNode.parent;
-
- if ( reApply )
- {
- parser.onTagOpen.apply( this, arguments );
- return;
}
+ else
+ break;
}
checkPending( tagName );
+ sendPendingBRs();
element.parent = currentNode;
- element.returnPoint = returnPoint;
- returnPoint = 0;
if ( element.isEmpty )
addElement( element );
@@ -247,35 +324,42 @@ CKEDITOR.htmlParser.fragment = function()
parser.onTagClose = function( tagName )
{
- var index = 0,
- pendingAdd = [],
+ // Check if there is any pending tag to be closed.
+ for ( var i = pendingInline.length - 1 ; i >= 0 ; i-- )
+ {
+ // If found, just remove it from the list.
+ if ( tagName == pendingInline[ i ].name )
+ {
+ pendingInline.splice( i, 1 );
+ return;
+ }
+ }
+
+ var pendingAdd = [],
+ newPendingInline = [],
candidate = currentNode;
- while ( candidate.type && candidate.name != tagName )
+ while ( candidate != fragment && 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 );
-
- // Increase the index, so it will not get checked again in
- // the pending list check that follows.
- index++;
- }
+ 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
// one of the nodes. So, for now, we just cache it.
pendingAdd.push( candidate );
- candidate = candidate.parent;
+ // Make sure return point is properly restored.
+ candidate = candidate.returnPoint || candidate.parent;
}
- if ( candidate.type )
+ if ( candidate != fragment )
{
// Add all elements that have been found in the above loop.
- for ( var i = 0 ; i < pendingAdd.length ; i++ )
+ for ( i = 0 ; i < pendingAdd.length ; i++ )
{
var node = pendingAdd[ i ];
addElement( node, node.parent );
@@ -283,8 +367,8 @@ CKEDITOR.htmlParser.fragment = function()
currentNode = candidate;
- if( currentNode.name == 'pre' )
- inPre = false;
+ if ( candidate._.isBlockLike )
+ sendPendingBRs();
addElement( candidate, candidate.parent );
@@ -292,33 +376,18 @@ CKEDITOR.htmlParser.fragment = function()
// addElement changed the currentNode.
if ( candidate == currentNode )
currentNode = currentNode.parent;
- }
- // The tag is not actually closing anything, thus we need invalidate
- // the pending elements.(#3862)
- else
- {
- pendingInline.splice( 0, index );
- index = 0;
- }
- // Check if there is any pending tag to be closed.
- for ( ; index < pendingInline.length ; index++ )
- {
- // If found, just remove it from the list.
- if ( tagName == pendingInline[ index ].name )
- {
- pendingInline.splice( index, 1 );
-
- // Decrease the index so we continue from the next one.
- index--;
- }
+ pendingInline = pendingInline.concat( newPendingInline );
}
+
+ if ( tagName == 'body' )
+ fixForBody = false;
};
parser.onText = function( text )
{
- // Trim empty spaces at beginning of element contents except .
- if ( !currentNode._.hasInlineStarted && !inPre )
+ // Trim empty spaces at beginning of text contents except and