Ticket #6946: 6946_4.patch
File 6946_4.patch, 9.5 KB (added by , 13 years ago) |
---|
-
_source/core/htmlparser/fragment.js
37 37 38 38 (function() 39 39 { 40 // Elements which the end tag is marked as optional in the HTML 4.01 DTD41 // (expect empty elements).42 var optionalClose = {colgroup:1,dd:1,dt:1,li:1,option:1,p:1,td:1,tfoot:1,th:1,thead:1,tr:1};43 44 40 // Block-level elements whose internal structure should be respected during 45 41 // parser fixing. 46 var nonBreakingBlocks = CKEDITOR.tools.extend( 47 {table:1,ul:1,ol:1,dl:1}, 48 CKEDITOR.dtd.table, CKEDITOR.dtd.ul, CKEDITOR.dtd.ol, CKEDITOR.dtd.dl ), 49 listBlocks = CKEDITOR.dtd.$list, listItems = CKEDITOR.dtd.$listItem; 42 var nonBreakingBlocks = CKEDITOR.tools.extend( { table:1,ul:1,ol:1,dl:1 }, CKEDITOR.dtd.table, CKEDITOR.dtd.ul, CKEDITOR.dtd.ol, CKEDITOR.dtd.dl ); 50 43 44 var listBlocks = { ol:1, ul:1 }; 45 46 // Dtd of the fragment element, basically it accept anything except for intermediate structure, e.g. orphan <li>. 47 var rootDtd = CKEDITOR.tools.extend( {}, { html: 1 }, CKEDITOR.dtd.html, CKEDITOR.dtd.body, CKEDITOR.dtd.head, { style:1,script:1 } ); 48 51 49 /** 52 50 * Creates a {@link CKEDITOR.htmlParser.fragment} from an HTML string. 53 51 * @param {String} fragmentHtml The HTML to be parsed, filling the fragment. … … 61 59 CKEDITOR.htmlParser.fragment.fromHtml = function( fragmentHtml, fixForBody ) 62 60 { 63 61 var parser = new CKEDITOR.htmlParser(), 64 html = [],65 62 fragment = new CKEDITOR.htmlParser.fragment(), 66 63 pendingInline = [], 67 64 pendingBRs = [], 68 65 currentNode = fragment, 69 66 // Indicate we're inside a <pre> element, spaces should be touched differently. 70 inPre = false, 71 returnPoint; 67 inPre = false; 72 68 73 69 function checkPending( newTagName ) 74 70 { … … 114 110 currentNode.add( pendingBRs.shift() ); 115 111 } 116 112 117 function addElement( element, target, enforceCurrent ) 113 /* 114 * Beside of simply append specified element to target, it also takes 115 * care of other dirty lifts like forcing block in body, trimming spaces at 116 * the block boundaries etc. 117 * 118 * Note: This function should NOT change the "currentNode" global unless 119 * there's a return point node specified on the element. 120 */ 121 function addElement( element, target ) 118 122 { 123 // Ignore any element that has already been added. 124 if ( element.previous !== undefined ) 125 return; 126 119 127 target = target || currentNode || fragment; 120 128 129 // Current element might be mangled by fix body below, 130 // save it for restore later. 131 var savedCurrent = currentNode; 132 121 133 // If the target is the fragment and this inline element can't go inside 122 134 // body (if fixForBody). 123 if ( fixForBody && !target.type)135 if ( fixForBody && ( !target.type || target.name == 'body' ) ) 124 136 { 125 137 var elementName, realElementName; 126 138 if ( element.attributes … … 130 142 else 131 143 elementName = element.name; 132 144 133 if ( elementName && elementName in CKEDITOR.dtd.$inline)145 if ( elementName && !( elementName in CKEDITOR.dtd.$body || elementName == 'body' || element.isOrphan ) ) 134 146 { 135 var savedCurrent = currentNode;136 137 147 // Create a <p> in the fragment. 138 148 currentNode = target; 139 149 parser.onTagOpen( fixForBody, {} ); 140 150 141 151 // The new target now is the <p>. 142 152 target = currentNode; 143 144 if ( enforceCurrent )145 currentNode = savedCurrent;146 153 } 147 154 } 148 155 … … 170 177 currentNode = element.returnPoint; 171 178 delete element.returnPoint; 172 179 } 180 else 181 currentNode = savedCurrent; 173 182 } 174 183 175 184 parser.onTagOpen = function( tagName, attributes, selfClosing ) … … 201 210 return; 202 211 } 203 212 204 var currentName = currentNode.name; 213 while( 1 ) 214 { 215 var currentName = currentNode.name; 205 216 206 var currentDtd = currentName207 && ( CKEDITOR.dtd[ currentName ]208 || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ) );217 var currentDtd = currentName ? ( CKEDITOR.dtd[ currentName ] 218 || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ) ) 219 : rootDtd; 209 220 210 // If the element cannot be child of the current element. 211 if ( currentDtd // Fragment could receive any elements. 212 && !element.isUnknown && !currentNode.isUnknown && !currentDtd[ tagName ] ) 213 { 214 215 var reApply = false, 216 addPoint; // New position to start adding nodes. 217 218 // Fixing malformed nested lists by moving it into a previous list item. (#3828) 219 if ( tagName in listBlocks 220 && currentName in listBlocks ) 221 { 222 var children = currentNode.children, 223 lastChild = children[ children.length - 1 ]; 221 // If the element cannot be child of the current element. 222 if ( !element.isUnknown && !currentNode.isUnknown && !currentDtd[ tagName ] ) 223 { 224 // Fixing malformed nested lists by moving it into a previous list item. (#3828) 225 if ( tagName in listBlocks 226 && currentName in listBlocks ) 227 { 228 var children = currentNode.children, 229 lastChild = children[ children.length - 1 ]; 224 230 225 // Establish the list item if it's not existed.226 if ( !( lastChild && lastChild.name in listItems) )227 addElement( ( lastChild = new CKEDITOR.htmlParser.element( 'li' ) ), currentNode );231 // Establish the list item if it's not existed. 232 if ( !( lastChild && lastChild.name == 'li' ) ) 233 addElement( ( lastChild = new CKEDITOR.htmlParser.element( 'li' ) ), currentNode ); 228 234 229 returnPoint = currentNode, addPoint = lastChild; 230 } 231 // If the element name is the same as the current element name, 232 // then just close the current one and append the new one to the 233 // parent. This situation usually happens with <p>, <li>, <dt> and 234 // <dd>, specially in IE. Do not enter in this if block in this case. 235 else if ( tagName == currentName ) 236 { 237 addElement( currentNode, currentNode.parent ); 238 } 239 else if ( tagName in CKEDITOR.dtd.$listItem ) 240 { 241 parser.onTagOpen( 'ul', {} ); 242 addPoint = currentNode; 243 reApply = true; 244 } 245 else 246 { 247 if ( nonBreakingBlocks[ currentName ] ) 248 { 249 if ( !returnPoint ) 250 returnPoint = currentNode; 251 } 252 else 253 { 254 addElement( currentNode, currentNode.parent, true ); 255 256 if ( !optionalClose[ currentName ] ) 257 { 258 // The current element is an inline element, which 259 // cannot hold the new one. Put it in the pending list, 260 // and try adding the new one after it. 261 pendingInline.unshift( currentNode ); 235 currentNode = lastChild; 236 } 237 // Establish new list root for orphan list items. 238 else if ( tagName in CKEDITOR.dtd.$listItem && currentName != tagName ) 239 parser.onTagOpen( tagName == 'li' ? 'ul' : 'dl', {} ); 240 // We're inside a structural block like table and list, AND the incoming element 241 // is not of the same type (e.g. <td>td1<td>td2</td>), we simply add this new one before it, 242 // and most importantly, return back to here once this element is added, 243 // e.g. <table><tr><td>td1</td><p>p1</p><td>td2</td></tr></table> 244 else if ( currentName in nonBreakingBlocks && currentName != tagName ) 245 { 246 !element.returnPoint && ( element.returnPoint = currentNode ); 247 currentNode = currentNode.parent; 248 } 249 else 250 { 251 // The current element is an inline element, which 252 // need to be continued even after the close, so put 253 // it in the pending list. 254 if ( currentName in CKEDITOR.dtd.$inline ) 255 pendingInline.unshift( currentNode ); 256 257 // The most common case where we just need to close the 258 // current one and append the new one to the parent. 259 if ( currentNode.parent ) 260 { 261 addElement( currentNode, currentNode.parent ); 262 currentNode = currentNode.parent; 263 } 264 // We've tried our best to fix the embarrassment here, while 265 // this element still doesn't find it's parent, mark it as 266 // orphan and show our tolerance to it. 267 else 268 { 269 element.isOrphan = 1; 270 break; 262 271 } 263 272 } 264 265 reApply = true;266 273 } 267 268 if ( addPoint )269 currentNode = addPoint;270 // Try adding it to the return point, or the parent element.271 274 else 272 currentNode = currentNode.returnPoint || currentNode.parent; 273 274 if ( reApply ) 275 { 276 parser.onTagOpen.apply( this, arguments ); 277 return; 278 } 279 } 275 break; 276 } 280 277 281 278 checkPending( tagName ); 282 279 sendPendingBRs(); 283 280 284 281 element.parent = currentNode; 285 element.returnPoint = returnPoint;286 returnPoint = 0;287 282 288 283 if ( element.isEmpty ) 289 284 addElement( element ); … … 403 398 sendPendingBRs( !CKEDITOR.env.ie && 1 ); 404 399 405 400 // Close all pending nodes. 406 while ( currentNode .type )401 while ( currentNode && currentNode.type ) 407 402 { 408 var parent = currentNode.parent, 409 node = currentNode; 410 411 if ( fixForBody 412 && ( !parent.type || parent.name == 'body' ) 413 && !CKEDITOR.dtd.$body[ node.name ] ) 414 { 415 currentNode = parent; 416 parser.onTagOpen( fixForBody, {} ); 417 parent = currentNode; 418 } 403 addElement( currentNode, currentNode.parent ); 404 currentNode = currentNode.parent; 405 } 419 406 420 parent.add( node );421 currentNode = parent;422 }423 424 407 return fragment; 425 408 }; 426 409