// Dtd of the fragment element, basically it accept anything except for intermediate structure, e.g. orphan <li>.\r
var rootDtd = CKEDITOR.tools.extend( {}, { html: 1 }, CKEDITOR.dtd.html, CKEDITOR.dtd.body, CKEDITOR.dtd.head, { style:1,script:1 } );\r
\r
+ function isRemoveEmpty( node )\r
+ {\r
+ // Empty link is to be removed when empty but not anchor. (#7894)\r
+ return node.name == 'a' && node.attributes.href\r
+ || CKEDITOR.dtd.$removeEmpty[ node.name ];\r
+ }\r
+\r
/**\r
* Creates a {@link CKEDITOR.htmlParser.fragment} from an HTML string.\r
* @param {String} fragmentHtml The HTML to be parsed, filling the fragment.\r
pendingInline = [],\r
pendingBRs = [],\r
currentNode = fragment,\r
+ // Indicate we're inside a <textarea> element, spaces should be touched differently.\r
+ inTextarea = false,\r
// Indicate we're inside a <pre> element, spaces should be touched differently.\r
inPre = false;\r
\r
pendingInline.splice( i, 1 );\r
i--;\r
}\r
+ else\r
+ {\r
+ // Some element of the same type cannot be nested, flat them,\r
+ // e.g. <a href="#">foo<a href="#">bar</a></a>. (#7894)\r
+ if ( pendingName == currentNode.name )\r
+ addElement( currentNode, currentNode.parent, 1 ), i--;\r
+ }\r
}\r
}\r
}\r
\r
// Rtrim empty spaces on block end boundary. (#3585)\r
if ( element._.isBlockLike\r
- && element.name != 'pre' )\r
+ && element.name != 'pre' && element.name != 'textarea' )\r
{\r
\r
var length = element.children.length,\r
element.isOptionalClose = tagName in optionalCloseTags || optionalClose;\r
\r
// This is a tag to be removed if empty, so do not add it immediately.\r
- if ( CKEDITOR.dtd.$removeEmpty[ tagName ] )\r
+ if ( isRemoveEmpty( element ) )\r
{\r
pendingInline.push( element );\r
return;\r
currentNode.add( new CKEDITOR.htmlParser.text( '\n' ) );\r
return;\r
}\r
+ else if ( tagName == 'textarea' )\r
+ inTextarea = true;\r
\r
if ( tagName == 'br' )\r
{\r
if ( currentNode.name == 'pre' )\r
inPre = false;\r
\r
+ if ( currentNode.name == 'textarea' )\r
+ inTextarea = false;\r
+\r
if ( candidate._.isBlockLike )\r
sendPendingBRs();\r
\r
\r
parser.onText = function( text )\r
{\r
- // Trim empty spaces at beginning of text contents except <pre>.\r
- if ( ( !currentNode._.hasInlineStarted || pendingBRs.length ) && !inPre )\r
+ // Trim empty spaces at beginning of text contents except <pre> and <textarea>.\r
+ if ( ( !currentNode._.hasInlineStarted || pendingBRs.length ) && !inPre && !inTextarea )\r
{\r
text = CKEDITOR.tools.ltrim( text );\r
\r
\r
// Shrinking consequential spaces into one single for all elements\r
// text contents.\r
- if ( !inPre )\r
+ if ( !inPre && !inTextarea )\r
text = text.replace( /[\t\r\n ]{2,}|[\t\r\n]/g, ' ' );\r
\r
currentNode.add( new CKEDITOR.htmlParser.text( text ) );\r