Ticket #3195: 3195.patch
File 3195.patch, 8.9 KB (added by , 15 years ago) |
---|
-
_source/core/htmlparser/fragment.js
41 41 // (expect empty elements). 42 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 43 44 var tableBlocks = {table:1,tbody:1,thead:1,tfoot:1,tr:1}; 45 44 46 /** 45 47 * Creates a {@link CKEDITOR.htmlParser.fragment} from an HTML string. 46 48 * @param {String} fragmentHtml The HTML to be parsed, filling the fragment. … … 56 58 html = [], 57 59 fragment = new CKEDITOR.htmlParser.fragment(), 58 60 pendingInline = [], 59 currentNode = fragment; 61 currentNode = fragment, 62 returnPoint; 60 63 61 var checkPending = function( newTagName )64 function checkPending( newTagName ) 62 65 { 63 66 if ( pendingInline.length > 0 ) 64 67 { … … 76 79 77 80 // Add it to the current node and make it the current, 78 81 // so the new element will be added inside of it. 79 currentNode.add( pendingElement );82 pendingElement.parent = currentNode; 80 83 currentNode = pendingElement; 81 84 82 85 // Remove the pending element (back the index by one … … 86 89 } 87 90 } 88 91 } 89 } ;92 } 90 93 94 function addElement( element, target, enforceCurrent ) 95 { 96 target = target || currentNode || fragment; 97 98 // If the target is the fragment and this element can't go inside 99 // body (if fixForBody). 100 if ( fixForBody && !target.type && !CKEDITOR.dtd.$body[ element.name ] ) 101 { 102 var savedCurrent = currentNode; 103 104 // Create a <p> in the fragment. 105 currentNode = target; 106 parser.onTagOpen( 'p', {} ); 107 108 // The new target now is the <p>. 109 target = currentNode; 110 111 if ( enforceCurrent ) 112 currentNode = savedCurrent; 113 } 114 115 target.add( element ); 116 117 if ( element.returnPoint ) 118 { 119 currentNode = element.returnPoint; 120 delete element.returnPoint; 121 } 122 } 123 91 124 parser.onTagOpen = function( tagName, attributes, selfClosing ) 92 125 { 93 if ( fixForBody && !currentNode.type && !CKEDITOR.dtd.$body[ tagName ] )94 this.onTagOpen( 'p', {} );95 96 126 var element = new CKEDITOR.htmlParser.element( tagName, attributes ); 97 127 98 128 // "isEmpty" will be always "false" for unknown elements, so we … … 123 153 // If the element name is the same as the current element name, 124 154 // then just close the current one and append the new one to the 125 155 // parent. This situation usually happens with <p>, <li>, <dt> and 126 // <dd>, specially in IE. 127 if ( tagName != currentName )156 // <dd>, specially in IE. Do not enter in this if block in this case. 157 if ( tagName == currentName ) 128 158 { 129 // If it is optional to close the current element, then 130 // close it at this point and simply add the new 131 // element after it. 132 if ( !optionalClose[ currentName ] ) 159 addElement( currentNode, currentNode.parent ); 160 } 161 else 162 { 163 if ( tableBlocks[ currentName ] ) 133 164 { 134 // The current element is an inline element, which 135 // cannot hold the new one. Put it in the pending list, 136 // and try adding the new one after it. 137 pendingInline.unshift( currentNode ); 165 if ( !returnPoint ) 166 returnPoint = currentNode; 138 167 } 168 else 169 { 170 addElement( currentNode, currentNode.parent, true ); 139 171 172 if ( !optionalClose[ currentName ] ) 173 { 174 // The current element is an inline element, which 175 // cannot hold the new one. Put it in the pending list, 176 // and try adding the new one after it. 177 pendingInline.unshift( currentNode ); 178 } 179 } 180 140 181 reApply = true; 141 182 } 142 183 143 184 // In any of the above cases, we'll be adding, or trying to 144 185 // add it to the parent. 145 currentNode = currentNode. parent;186 currentNode = currentNode.returnPoint || currentNode.parent; 146 187 147 188 if ( reApply ) 148 189 { … … 153 194 154 195 checkPending( tagName ); 155 196 156 currentNode.add( element ); 197 element.parent = currentNode; 198 element.returnPoint = returnPoint; 199 returnPoint = 0; 157 200 158 if ( !element.isEmpty ) 201 if ( element.isEmpty ) 202 addElement( element ); 203 else 159 204 currentNode = element; 160 205 }; 161 206 162 207 parser.onTagClose = function( tagName ) 163 208 { 164 var closingElement = currentNode, 165 index = 0; 209 var index = 0; 166 210 167 while ( c losingElement && closingElement.name != tagName )211 while ( currentNode.type && currentNode.name != tagName ) 168 212 { 169 213 // If this is an inline element, add it to the pending list, so 170 214 // it will continue after the closing tag. 171 if ( !c losingElement._.isBlockLike )215 if ( !currentNode._.isBlockLike ) 172 216 { 173 pendingInline.unshift( c losingElement);217 pendingInline.unshift( currentNode ); 174 218 175 219 // Increase the index, so it will not get checked again in 176 220 // the pending list check that follows. 177 221 index++; 178 222 } 179 223 180 closingElement = closingElement.parent; 224 addElement( currentNode, currentNode.parent ); 225 currentNode = currentNode.parent; 181 226 } 182 227 183 if ( closingElement ) 184 currentNode = closingElement.parent; 228 if ( currentNode.type ) 229 { 230 var node = currentNode; 231 addElement( currentNode, currentNode.parent ); 232 233 // The parent should start receiving new nodes now, except if 234 // addElement changed the currentNode. 235 if ( node == currentNode ) 236 currentNode = currentNode.parent; 237 } 185 238 else if ( pendingInline.length > index ) 186 239 { 187 240 // If we didn't find any parent to be closed, let's check the … … 223 276 currentNode.add( new CKEDITOR.htmlParser.comment( comment ) ); 224 277 }; 225 278 279 // Parse it. 226 280 parser.parse( fragmentHtml ); 227 281 282 // Close all pending nodes. 283 while ( currentNode.type ) 284 { 285 var parent = currentNode.parent, 286 node = currentNode; 287 288 if ( fixForBody && !parent.type && !CKEDITOR.dtd.$body[ node.name ] ) 289 { 290 currentNode = parent; 291 parser.onTagOpen( 'p', {} ); 292 parent = currentNode; 293 } 294 295 parent.add( node ); 296 currentNode = parent; 297 } 298 228 299 return fragment; 229 300 }; 230 301 -
_source/tests/core/htmlparser/fragment.html
10 10 <script type="text/javascript"> 11 11 //<![CDATA[ 12 12 13 CKEDITOR.test.addTestCase( (function() 13 var tc; 14 15 CKEDITOR.test.addTestCase( tc = (function() 14 16 { 15 17 // Local reference to the "assert" object. 16 18 var assert = CKEDITOR.test.assert; 17 19 20 function testParser( input, expected ) 21 { 22 var fragment = CKEDITOR.htmlParser.fragment.fromHtml( input, true ), 23 writer = new CKEDITOR.htmlParser.basicWriter(); 24 25 fragment.writeHtml( writer ); 26 27 assert.areSame( expected, writer.getHtml( true ) ); 28 } 29 18 30 return { 19 31 test_fromHtml_1 : function() 20 32 { … … 25 37 assert.areSame( 'p', fragment.children[0].name, 'Wrong child name' ); 26 38 }, 27 39 40 test_parser_1 : function() 41 { 42 testParser( '<table><tr><td>1</td><p><b>2</b> Test</p><td>3</td></tr></table>', 43 '<p><b>2</b> Test</p><table><tr><td>1</td><td>3</td></tr></table>' ); 44 }, 45 46 test_parser_2 : function() 47 { 48 testParser( '<b><table><tr><td>1</td><td>2</td></tr></table></b>', 49 '<table><tr><td><b>1</b></td><td><b>2</b></td></tr></table>' ); 50 }, 51 52 test_parser_3_1 : function() 53 { 54 testParser( '<b><i>Table:<table><tr><td>1</td><td>2</td></tr></table></i></b>', 55 '<p><b><i>Table:</i></b></p><table><tr><td><b><i>1</i></b></td><td><b><i>2</i></b></td></tr></table>' ); 56 }, 57 58 test_parser_3_2 : function() 59 { 60 testParser( '<b><i><table><tr><td>1</td><td>2</td></tr></table>Table</i></b>', 61 '<table><tr><td><b><i>1</i></b></td><td><b><i>2</i></b></td></tr></table><p><b><i>Table</i></b></p>' ); 62 }, 63 64 test_parser_4 : function() 65 { 66 testParser( '<b><i>Test', 67 '<p><b><i>Test</i></b></p>' ); 68 }, 69 70 test_parser_5 : function() 71 { 72 testParser( '<p>Para 1<p>Para 2<p>Para 3', 73 '<p>Para 1</p><p>Para 2</p><p>Para 3</p>' ); 74 }, 75 76 test_parser_6 : function() 77 { 78 testParser( '<b>A</b><i>B</i>', 79 '<p><b>A</b><i>B</i></p>' ); 80 }, 81 82 test_parser_7 : function() 83 { 84 testParser( '<p>Para 1<hr>Para 2<h1>Para 3', 85 '<p>Para 1</p><hr /><p>Para 2</p><h1>Para 3</h1>' ); 86 }, 87 88 test_ticket_3195 : function() 89 { 90 testParser( '<table><tr><td>1</td><p>2</p><td>3</td></tr></table>', 91 '<p>2</p><table><tr><td>1</td><td>3</td></tr></table>' ); 92 }, 93 28 94 name : document.title 29 95 }; 30 96 })() ); 31 97 98 // Uncomment the following to run a single test. 99 // window.onload = tc.test_parser_7; 100 32 101 //]]> 33 102 </script> 34 103 </head>