Ticket #4067: 4067.patch
File 4067.patch, 20.7 KB (added by , 15 years ago) |
---|
-
_source/plugins/htmlwriter/plugin.js
67 67 68 68 var dtd = CKEDITOR.dtd; 69 69 70 for ( var e in CKEDITOR.tools.extend( {}, dtd.$ block, dtd.$listItem, dtd.$tableContent ) )70 for ( var e in CKEDITOR.tools.extend( {}, dtd.$noneBodyContent, dtd.$block, dtd.$listItem, dtd.$tableContent ) ) 71 71 { 72 72 this.setRules( e, 73 73 { -
_source/core/htmlparser/element.js
35 35 this.children = []; 36 36 37 37 var dtd = CKEDITOR.dtd, 38 isBlockLike = !!( dtd.$ block[ name ] || dtd.$listItem[ name ] || dtd.$tableContent[ name ] ),38 isBlockLike = !!( dtd.$noneBodyContent[ name ] || dtd.$block[ name ] || dtd.$listItem[ name ] || dtd.$tableContent[ name ] ), 39 39 isEmpty = !!dtd.$empty[ name ]; 40 40 41 41 this.isEmpty = isEmpty; -
_source/plugins/wysiwygarea/plugin.js
550 550 { 551 551 isLoadingData = true; 552 552 553 // Get the HTML version of the data.553 // Get the full page HTML version of the data. 554 554 if ( editor.dataProcessor ) 555 { 556 data = editor.dataProcessor.toHtml( data, fixForBody ); 557 } 555 data = editor.dataProcessor.toHtml( data, fixForBody, true ); 558 556 559 data = 560 editor.config.docType + 561 '<html dir="' + editor.config.contentsLangDirection + '">' + 562 '<head>' + 563 '<link type="text/css" rel="stylesheet" href="' + 564 [].concat( editor.config.contentsCss ).join( '"><link type="text/css" rel="stylesheet" href="' ) + 565 '">' + 566 '<style type="text/css" _fcktemp="true">' + 567 editor._.styles.join( '\n' ) + 568 '</style>'+ 569 '</head>' + 570 '<body>' + 571 data + 572 '</body>' + 573 '</html>' + 574 activationScript; 575 576 window[ '_cke_htmlToLoad_' + editor.name ] = data; 557 window[ '_cke_htmlToLoad_' + editor.name ] = data + activationScript; 577 558 CKEDITOR._[ 'contentDomReady' + editor.name ] = contentDomReady; 578 559 createIFrame(); 579 560 … … 589 570 590 571 getData : function() 591 572 { 592 var data = iframe.getFrameDocument().getBody().getHtml(); 573 var documentElement = iframe.getFrameDocument().getDocumentElement(), 574 docTypeAttr = documentElement.getAttribute( 'cke_docType' ), 575 data = ( docTypeAttr ? decodeURIComponent( docTypeAttr ) : '' ) + documentElement.getOuterHtml(); 593 576 594 577 if ( editor.dataProcessor ) 595 578 data = editor.dataProcessor.toDataFormat( data, fixForBody ); -
_source/core/dom/element.js
328 328 */ 329 329 getHtml : function() 330 330 { 331 return this.$.innerHTML; 331 var retval = this.$.innerHTML; 332 // Strip <?xml:namespace> tag in the output HTML of 333 // namespaced element in IE(#3341). 334 return CKEDITOR.env.ie ? retval.replace( /<\?[^>]*>/g, '' ) : retval; 332 335 }, 333 336 334 337 getOuterHtml : function() -
_source/core/htmlparser/filter.js
127 127 128 128 function addItemsToList( list, items, priority ) 129 129 { 130 if( typeof items == 'function' ) 131 items = [ items ]; 132 130 133 var i, j, 131 134 listLength = list.length, 132 135 itemsLength = items && items.length; -
_source/core/dtd.js
51 51 N = {'#':1}, 52 52 O = X({param:1},K), 53 53 P = X({form:1},A,D,E,I), 54 Q = {li:1}; 54 Q = {li:1}, 55 R = {style:1,script:1}, 56 S = {base:1,link:1,meta:1,title:1}, 57 T = X(S,R), 58 U = {head:1,body:1}, 59 V = {html:1}; 55 60 56 var block = {address:1,blockquote:1,center:1,dir:1,div:1,dl:1,fieldset:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,hr:1,isindex:1,menu:1,noframes:1,ol:1,p:1,pre:1,table:1,ul:1}; 61 var block = {address:1,blockquote:1,center:1,dir:1,div:1,dl:1,fieldset:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,hr:1,isindex:1,menu:1,noframes:1,ol:1,p:1,pre:1,table:1,ul:1}, 62 inline = {a:1,abbr:1,acronym:1,b:1,basefont:1,bdo:1,big:1,br:1,cite:1,code:1,dfn:1,em:1,font:1,i:1,img:1,input:1,kbd:1,label:1,q:1,s:1,samp:1,select:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,textarea:1,tt:1,u:1,'var':1,applet:1,button:1,del:1,iframe:1,ins:1,map:1,object:1,script:1}; 57 63 58 64 return /** @lends CKEDITOR.dtd */ { 59 65 60 66 // The "$" items have been added manually. 61 67 62 /** 68 /** 69 * The document element. 70 */ 71 $ : V, 72 73 // List of elements won't appear under body. 74 $noneBodyContent: X(V,U,S), 75 76 /** 63 77 * List of block elements, like "p" or "div". 64 78 * @type Object 65 79 * @example 66 80 */ 67 81 $block : block, 68 82 69 $body : X({script:1}, block),83 $inline : inline, 70 84 85 $body : X({script:1,style:1}, block), 86 71 87 $cdata : {script:1,style:1}, 72 88 73 89 /** … … 120 136 */ 121 137 $tableContent : {caption:1,col:1,colgroup:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1}, 122 138 123 col : {}, 139 html: U, 140 head: T, 141 style: N, 142 script: N, 143 body: X(inline, block), 144 col : {}, 124 145 tr : {td:1,th:1}, 125 146 img : {}, 126 147 colgroup : {col:1}, … … 200 221 pre : X(G,C), 201 222 p : L, 202 223 em : L, 203 dfn : L 224 dfn : L, 225 base: {}, 226 link: {}, 227 meta: {}, 228 title: N 204 229 }; 205 230 })(); 206 231 -
_source/core/htmlparser/basicwriter.js
15 15 16 16 proto : 17 17 { 18 docType : function( docType ) 19 { 20 this._.output.push( docType ); 21 }, 22 18 23 /** 19 24 * Writes the tag opening part for a opener tag. 20 25 * @param {String} tagName The element name for this tag. … … 117 122 reset : function() 118 123 { 119 124 this._.output = []; 125 this._.indent = false; 120 126 }, 121 127 122 128 /** -
_source/core/htmlparser/fragment.js
18 18 * alert( fragment.children.length ); "2" 19 19 */ 20 20 this.children = []; 21 this.attributes = {}; 21 22 22 23 /** 23 24 * Get the fragment parent. Should always be null. … … 30 31 /** @private */ 31 32 this._ = 32 33 { 34 docType : '', 33 35 isBlockLike : true, 34 36 hasInlineStarted : false 35 37 }; … … 114 116 elementName = realElementName; 115 117 else 116 118 elementName = element.name; 117 if ( !( elementName in CKEDITOR.dtd.$body ) ) 119 if ( elementName 120 && !( elementName in CKEDITOR.dtd.$body ) 121 && !( elementName in CKEDITOR.dtd.$noneBodyContent ) ) 118 122 { 119 123 var savedCurrent = currentNode; 120 124 … … 156 160 } 157 161 } 158 162 163 parser.onDocType = function ( docType ) 164 { 165 fragment._.docType = docType; 166 }; 167 159 168 parser.onTagOpen = function( tagName, attributes, selfClosing ) 160 169 { 161 170 var element = new CKEDITOR.htmlParser.element( tagName, attributes ); … … 180 189 } 181 190 182 191 var currentName = currentNode.name, 183 currentDtd = ( currentName && CKEDITOR.dtd[ currentName ] ) || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ); 192 currentDtd = currentName && 193 ( CKEDITOR.dtd[ currentName ] 194 || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ) ); 184 195 185 196 // If the element cannot be child of the current element. 186 if ( !element.isUnknown && !currentNode.isUnknown && !currentDtd[ tagName ] ) 197 if ( currentDtd // Fragment could receive any elements. 198 && !element.isUnknown && !currentNode.isUnknown && !currentDtd[ tagName ] ) 187 199 { 188 // If this is the fragment node, just ignore this tag and add189 // its children.190 if ( !currentName )191 return;192 200 193 201 var reApply = false, 194 202 addPoint; // New position to start adding nodes. … … 330 338 index--; 331 339 } 332 340 } 341 342 if( tagName == 'body' ) 343 fixForBody = false; 333 344 }; 334 345 335 346 parser.onText = function( text ) … … 345 356 346 357 checkPending(); 347 358 348 if ( fixForBody && !currentNode.type ) 359 if ( fixForBody 360 && CKEDITOR.tools.trim( text ) 361 && ( !currentNode.type || currentNode.name == 'body' ) ) 349 362 this.onTagOpen( fixForBody, {} ); 350 363 351 364 // Shrinking consequential spaces into one single for all elements … … 375 388 var parent = currentNode.parent, 376 389 node = currentNode; 377 390 378 if ( fixForBody && !parent.type && !CKEDITOR.dtd.$body[ node.name ] ) 391 if ( fixForBody 392 && ( !parent.type || parent.name == 'body' ) 393 && !CKEDITOR.dtd.$body[ node.name ] ) 379 394 { 380 395 currentNode = parent; 381 396 parser.onTagOpen( fixForBody, {} ); … … 444 459 */ 445 460 writeHtml : function( writer, filter ) 446 461 { 462 // Call element filter on fragment as well as write doc-type. 463 if( !this.name ) 464 { 465 filter && filter.onElement( this ); 466 this._.docType && writer.docType( this._.docType ); 467 } 468 447 469 for ( var i = 0, len = this.children.length ; i < len ; i++ ) 448 470 this.children[i].writeHtml( writer, filter ); 449 471 } -
_source/plugins/htmldataprocessor/plugin.js
11 11 12 12 var protectedSourceMarker = '{cke_protected}'; 13 13 14 function hasChild( element, tagName ) 15 { 16 var children = element.children, 17 child; 18 for ( var i = 0; i < children.length; i++ ) 19 { 20 child = children[ i ]; 21 if( child.name && child.name == tagName ) 22 return true; 23 } 24 } 14 25 15 26 // Return the last non-space child node of the block (#4344). 16 27 function lastNoneSpaceChild( block ) … … 78 89 // We just avoid filler in <pre> right now. 79 90 // TODO: Support filler for <pre>, line break is also occupy line height. 80 91 delete blockLikeTags.pre; 92 93 function addRoot( element, tagName ) 94 { 95 var childrens = element.children, 96 root = new CKEDITOR.htmlParser.element( tagName, {} ); 97 element.children = []; 98 element.add( root ); 99 for ( var i = 0; i < childrens.length; i++ ) 100 { 101 root.add( childrens[ i ] ); 102 } 103 return root; 104 } 105 81 106 var defaultDataFilterRules = 82 107 { 83 108 attributeNames : … … 199 224 }; 200 225 } 201 226 227 function dropElement( element ) 228 { 229 return false; 230 } 231 232 function removeElement( element ) 233 { 234 delete element.name; 235 }; 236 237 function cleanup( element ) 238 { 239 var children = element.children, 240 child; 241 for ( var i = 0; i < children.length; i++ ) 242 { 243 child = children[ i ]; 244 // 1. Remove any white-spaces preserve by some browsers around and inside <head>. 245 // 2. Remove any 'cke_temp' elements. 246 if( child.type == CKEDITOR.NODE_TEXT && !CKEDITOR.tools.trim( child.value ) 247 || child.attributes && child.attributes.cke_temp ) 248 children.splice( i--, 1 ); 249 } 250 } 251 252 var nonFullPageHtmlFilterRules = 253 { 254 elements : 255 { 256 'html' : removeElement, 257 'body' : removeElement, 258 'head' : dropElement 259 } 260 }; 261 262 var fullPageHtmlFilterRules = 263 { 264 attributeNames : 265 [ 266 [ 'spellcheck', '' ], 267 [ 'cke_doctype', '' ], 268 [ 'contenteditable', '' ], 269 [ 'hidefocus', '' ] 270 ], 271 272 attributes : 273 { 274 'spellcheck' : function( value, element ) 275 { 276 if ( element.name == 'body' ) 277 return false; 278 } 279 }, 280 281 elements : 282 { 283 head : cleanup, 284 html : cleanup, 285 title : cleanup 286 } 287 }; 288 202 289 var protectAttributeRegex = /<(?:a|area|img|input).*?\s((?:href|src|name)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+)))/gi; 203 290 204 291 function protectAttributes( html ) … … 206 293 return html.replace( protectAttributeRegex, '$& _cke_saved_$1' ); 207 294 } 208 295 209 var protectStyleTagsRegex = /<(style)(?=[ >])[^>]*>[^<]*<\/\1>/gi; 296 var protectStyleTagsRegex = /<(style)(?=[ >])[^>]*>[^<]*<\/\1>/gi, 297 protectFullPageElementsRegex = /<(:?link|meta|base).*?>/; 210 298 var encodedTagsRegex = /<cke:encoded>([^<]*)<\/cke:encoded>/gi; 211 299 var protectElementNamesRegex = /(<\/?)((?:object|embed|param).*?>)/gi; 300 var shelvefullPageElementsRegex = /(<\/?)((?:html|body|head|title).*?>)/gi, 301 shelvedElementsRegex = /(<\/?)cke_fullpage:([^>]*>)/gi; 212 302 var protectSelfClosingRegex = /<cke:param(.*?)\/>/gi; 213 303 214 function protectStyleTagsMatch( match )304 function encodeMatched( match ) 215 305 { 216 306 return '<cke:encoded>' + encodeURIComponent( match ) + '</cke:encoded>'; 217 307 } 218 308 309 function shelveTags( html, isUnShelve ) 310 { 311 if ( isUnShelve ) 312 return unprotectEncodedTags( html.replace( shelvedElementsRegex, '$1$2' ) ); 313 else 314 { 315 return html 316 .replace( shelvefullPageElementsRegex, '$1cke_fullpage:$2' ) 317 .replace( protectFullPageElementsRegex, encodeMatched ); 318 } 319 } 320 219 321 function protectStyleTags( html ) 220 322 { 221 return html.replace( protectStyleTagsRegex, protectStyleTagsMatch);323 return html.replace( protectStyleTagsRegex, encodeMatched ); 222 324 } 223 325 function protectElementsNames( html ) 224 326 { … … 291 393 292 394 dataProcessor.writer.forceSimpleAmpersand = editor.config.forceSimpleAmpersand; 293 395 294 dataProcessor.dataFilter.addRules( defaultDataFilterRules ); 396 397 dataProcessor.dataFilter.addRules( CKEDITOR.tools.extend( defaultDataFilterRules, 398 { 399 // Full page support. (#4067) 400 elements : 401 { 402 $ : function( element ) 403 { 404 // Fix full page at the root (fragment element). 405 if( ( element._.fullPage !== false ) && !element.name ) 406 { 407 var firstChild = element.children[ 0 ]; 408 // Full document. 409 if( firstChild && firstChild.name == 'html' ) 410 return; 411 // Missing <html>. 412 if ( !firstChild || firstChild.name in dtd.html ) 413 addRoot( element, 'html' ); 414 // Missing <html> and <body>/<head>. 415 else 416 { 417 addRoot( addRoot( element, 'html' ), 418 firstChild.name in dtd.head ? 'head' : 'body' ); 419 } 420 } 421 }, 422 423 html : function ( element ) 424 { 425 // Both <head> and <body> are mandatory. 426 if ( !hasChild( element, 'head' ) ) 427 element.children.splice( 0, 0, new CKEDITOR.htmlParser.element( 'head', {} ) ); 428 if ( !hasChild( element, 'body' ) ) 429 element.children.splice( element.children.length, 0, new CKEDITOR.htmlParser.element( 'body', {} ) ); 430 431 // 1. Save doc-type as a custom attribute; 432 // 2. Adding missing xml namespace attribute; 433 // 3. Adding missing language direction attribute. 434 var attrs = element.attributes, 435 docType = element.parent._.docType, 436 configDir = editor.config.contentsLangDirection; 437 if( docType ) 438 { 439 attrs.cke_docType = encodeURIComponent( docType ); 440 docType.match( /xhtml/i ) 441 && !attrs.xmlns 442 && ( attrs.xmlns = 'http://www.w3.org/1999/xhtml' ); 443 } 444 !attrs.dir && configDir && ( attrs.dir = configDir ); 445 }, 446 447 head : function ( element ) 448 { 449 // <title> is mandatory. 450 if ( !hasChild( element, 'title' ) ) 451 element.children.splice( 0, 0, new CKEDITOR.htmlParser.element( 'title', {} ) ); 452 453 // Adding default styles. 454 var styleLinks = [].concat( editor.config.contentsCss ), 455 styleText = editor._.styles.join( '\n' ); 456 457 if( styleLinks ) 458 { 459 for ( var i = 0; i < styleLinks.length; i++ ) 460 { 461 var link = new CKEDITOR.htmlParser.element( 'link', 462 { 463 type: 'text/css' , 464 rel : 'stylesheet', 465 href : styleLinks[ i ], 466 cke_temp : 1 467 } ); 468 element.add( link ); 469 } 470 } 471 if( styleText ) 472 { 473 var style = new CKEDITOR.htmlParser.element( 'style', 474 { 475 type: 'text/css', 476 cke_temp : 1 477 } ); 478 style.add( new CKEDITOR.htmlParser.text( styleText ) ); 479 element.add( style ); 480 } 481 } 482 } 483 } ) ); 295 484 dataProcessor.dataFilter.addRules( defaultDataBlockFilterRules ); 296 485 dataProcessor.htmlFilter.addRules( defaultHtmlFilterRules ); 297 486 dataProcessor.htmlFilter.addRules( defaultHtmlBlockFilterRules ); 487 dataProcessor.htmlFilter.addRules( editor.config.fullPage ? fullPageHtmlFilterRules : nonFullPageHtmlFilterRules ); 298 488 } 299 489 }); 300 490 … … 309 499 310 500 CKEDITOR.htmlDataProcessor.prototype = 311 501 { 312 toHtml : function( data, fixForBody )502 toHtml : function( data, fixForBody, fullPage ) 313 503 { 314 504 // The source data is already HTML, but we need to clean 315 505 // it up and apply the filter. … … 333 523 // protecting them into open-close.(#3591) 334 524 data = protectSelfClosingElements( data ); 335 525 526 data = shelveTags( data ); 336 527 // Call the browser to help us fixing a possibly invalid HTML 337 528 // structure. 338 var div = document.createElement( 'div' );529 var div = new CKEDITOR.dom.element( 'div' ); 339 530 // Add fake character to workaround IE comments bug. (#3801) 340 div. innerHTML = 'a' + data;341 data = div. innerHTML.substr( 1 );531 div.setHtml( 'a' + data ); 532 data = div.getHtml().substr( 1 ); 342 533 534 data = shelveTags( data, true ); 535 343 536 if ( CKEDITOR.env.ie ) 344 537 data = unprotectEncodedTags( data ); 345 538 … … 348 541 var fragment = CKEDITOR.htmlParser.fragment.fromHtml( data, fixForBody ), 349 542 writer = new CKEDITOR.htmlParser.basicWriter(); 350 543 544 var configDocType = this.editor.config.docType; 545 // Is docType missing and been explicitly defined in configuration? 546 configDocType && !fragment._.docType && ( fragment._.docType = configDocType ); 547 548 // Is Html snippet mode instead of full page? 549 ( fullPage !== true ) 550 && ( fragment._.fullPage = false, delete fragment._.docType ); 551 351 552 fragment.writeHtml( writer, this.dataFilter ); 352 553 353 554 return writer.getHtml( true ); … … 358 559 var writer = this.writer, 359 560 fragment = CKEDITOR.htmlParser.fragment.fromHtml( html, fixForBody ); 360 561 361 writer.reset(); 562 // Ignore doctype if not in full page output mode. 563 if ( !this.editor.config.fullPage && fragment._.docType ) 564 delete fragment._.docType; 362 565 566 writer.reset(); 363 567 fragment.writeHtml( writer, this.htmlFilter ); 364 568 365 569 return writer.getHtml( true ); -
_source/core/htmlparser.js
12 12 { 13 13 this._ = 14 14 { 15 htmlPartsRegex : new RegExp( '<(?:(?:\\/([^>]+)>)|(?:!--([\\S|\\s]*?)-->)|(?:([^\\s>]+)\\s*((?:(?:[^"\'>]+)|(?:"[^"]*")|(?:\'[^\']*\'))*)\\/?>))', 'g' ) 15 htmlPartsRegex : new RegExp( '<(?:(?:\\/([^>]+)>)|(?:!--([\\S|\\s]*?)-->)|(?:([^\\s>]+)\\s*((?:(?:[^"\'>]+)|(?:"[^"]*")|(?:\'[^\']*\'))*)\\/?>))', 'g' ), 16 docTypeRegex : /<!DOCTYPE[^>]*>/i 16 17 }; 17 18 }; 18 19 … … 24 25 CKEDITOR.htmlParser.prototype = 25 26 { 26 27 /** 28 * Function to be fired when a docType defintion is found. This function 29 * should be overriden when using this class. 30 * @param {String} docType The declaration text. 31 */ 32 onDocType : function() {}, 33 34 /** 27 35 * Function to be fired when a tag opener is found. This function 28 36 * should be overriden when using this class. 29 37 * @param {String} tagName The tag name. The name is guarantted to be … … 113 121 */ 114 122 parse : function( html ) 115 123 { 124 // Remove docType declaration at first. 125 var self = this; 126 html = html.replace( this._.docTypeRegex, function( match ) 127 { 128 self.onDocType( match ); 129 return ''; 130 } ); 131 116 132 var parts, 117 133 tagName, 118 134 nextIndex = 0,