Ticket #4067: 4067_3.patch
File 4067_3.patch, 23.1 KB (added by , 11 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
15 15 */ 16 16 var nonExitableElementNames = { table:1,pre:1 }; 17 17 // Matching an empty paragraph at the end of document. 18 var emptyParagraphRegexp = /\s*<(p|div|address|h\d|center)[^>]*>\s*(?:<br[^>]*>| | )\s*(:?<\/\1>)?\s* $/gi;18 var emptyParagraphRegexp = /\s*<(p|div|address|h\d|center)[^>]*>\s*(?:<br[^>]*>| | )\s*(:?<\/\1>)?\s*(:?$|<\/body>)/gi; 19 19 20 20 function onInsertHtml( evt ) 21 21 { … … 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 555 { 556 data = editor.dataProcessor.toHtml( data, fixForBody ); 556 data = editor.dataProcessor.toHtml( data, fixForBody, 557 editor.config.fullPage, editor.config.docType ); 557 558 } 558 559 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; 560 // Provide basic fixings even without the full-page plugin. 561 if( !editor.config.fullPage ) 562 { 563 data = 564 editor.config.docType + 565 '<html dir="' + editor.config.contentsLangDirection + '">' + 566 '<head>' + 567 '<link type="text/css" rel="stylesheet" href="' + 568 [].concat( editor.config.contentsCss ).join( '"><link type="text/css" rel="stylesheet" href="' ) + 569 '">' + 570 '<style type="text/css" _cke_temp="true">' + 571 editor._.styles.join( '\n' ) + 572 '</style>'+ 573 '</head>' + 574 '<body>' + 575 data + 576 '</body>' + 577 '</html>'; 578 } 575 579 580 data += activationScript; 581 576 582 window[ '_cke_htmlToLoad_' + editor.name ] = data; 577 583 CKEDITOR._[ 'contentDomReady' + editor.name ] = contentDomReady; 578 584 createIFrame(); … … 589 595 590 596 getData : function() 591 597 { 592 var data = iframe.getFrameDocument().getBody().getHtml(); 598 var frameDoc = iframe.getFrameDocument(), 599 documentElement = frameDoc.getDocumentElement(), 600 docTypeAttr = documentElement.getAttribute( 'cke_docType' ), 601 data = editor.config.fullPage ? 602 ( docTypeAttr ? decodeURIComponent( docTypeAttr ) : '' ) + documentElement.getOuterHtml() 603 : frameDoc.getBody().getHtml(); 593 604 594 605 if ( editor.dataProcessor ) 595 data = editor.dataProcessor.toDataFormat( data, fixForBody );606 data = editor.dataProcessor.toDataFormat( data, fixForBody, editor.config.fullPage ); 596 607 597 608 // Strip the last blank paragraph within document. 598 609 if ( editor.config.ignoreEmptyParagraph ) -
_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/plugins/fullpage/plugin.js
1 /* 2 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 */ 5 6 /** 7 * @fileOverview The "wysiwygarea" plugin. It registers the "wysiwyg" editing 8 * mode, which handles the main editing area space. 9 */ 10 11 ( function() 12 { 13 var dtd = CKEDITOR.dtd; 14 CKEDITOR.plugins.add( 'fullpage', 15 { 16 requires : [ 'htmldataprocessor' ], 17 afterInit : function( editor ) 18 { 19 var fullPageDataFilterRules = 20 { 21 // Full page support. ( #4067 ) 22 elements : 23 { 24 $ : function( element ) 25 { 26 // Fix fullPage elements at the fragment element. 27 if ( ( element._.fullPage !== false ) && !element.name ) 28 { 29 var firstChild = element.children[ 0 ]; 30 // Full document. 31 if ( firstChild && firstChild.name == 'html' ) 32 return; 33 // Missing <html>. 34 if ( !firstChild || firstChild.name in dtd.html ) 35 wrapContent( element, 'html' ); 36 // Missing <html> and <body>/<head>. 37 else 38 { 39 wrapContent( wrapContent( element, 'html' ), 40 firstChild.name in dtd.head ? 'head' : 'body' ); 41 } 42 } 43 }, 44 45 html : function ( element ) 46 { 47 // Both <head> and <body> are mandatory. 48 if ( !childByTagName( element, 'head' ) ) 49 element.children.splice( 0, 0, new CKEDITOR.htmlParser.element( 'head', {} ) ); 50 if ( !childByTagName( element, 'body' ) ) 51 element.children.splice( element.children.length, 0, new CKEDITOR.htmlParser.element( 'body', {} ) ); 52 53 // 1. Save doc-type as a custom attribute; 54 // 2. Adding missing xml namespace attribute; 55 // 3. Adding missing language direction attribute. 56 var attrs = element.attributes, 57 docType = element.parent._.docType, 58 configDir = editor.config.contentsLangDirection; 59 if ( docType ) 60 { 61 attrs.cke_docType = encodeURIComponent( docType ); 62 docType.match( /xhtml/i ) 63 && !attrs.xmlns 64 && ( attrs.xmlns = 'http://www.w3.org/1999/xhtml' ); 65 } 66 !attrs.dir && configDir && ( attrs.dir = configDir ); 67 }, 68 69 head : function ( element ) 70 { 71 // <title> is mandatory. 72 if ( !childByTagName( element, 'title' ) ) 73 element.children.splice( 0, 0, new CKEDITOR.htmlParser.element( 'title', {} ) ); 74 75 // Adding default styles. 76 var styleLinks = [].concat( editor.config.contentsCss ), 77 styleText = editor._.styles.join( '\n' ); 78 79 if ( styleLinks ) 80 { 81 for ( var i = 0; i < styleLinks.length; i++ ) 82 { 83 var link = new CKEDITOR.htmlParser.element( 'link', 84 { 85 type: 'text/css' , 86 rel : 'stylesheet', 87 href : styleLinks[ i ], 88 cke_temp : 1 89 } ); 90 element.add( link ); 91 } 92 } 93 if ( styleText ) 94 { 95 var style = new CKEDITOR.htmlParser.element( 'style', 96 { 97 type: 'text/css', 98 cke_temp : 1 99 } ); 100 style.add( new CKEDITOR.htmlParser.text( styleText ) ); 101 element.add( style ); 102 } 103 } 104 } 105 }; 106 107 var fullPageHtmlFilterRules = 108 { 109 elements : 110 { 111 html : function ( element ) 112 { 113 delete element.attributes.cke_doctype; 114 // Preserve only body contents in non-fullPage mode. 115 if( element.parent._.fullPage === false ) 116 { 117 var children = element.children, 118 contents, 119 child; 120 for ( var i = 0; i < children.length; i++ ) 121 { 122 child = children[ i ]; 123 if ( 'body' == child.name ) 124 { 125 contents = child.children; 126 break; 127 } 128 } 129 130 element.children = contents; 131 delete element.name; 132 } 133 }, 134 135 body : function( element ) 136 { 137 delete element.attributes.spellcheck; 138 delete element.attributes.contenteditable; 139 }, 140 // Elements used interally in 'wysiwyg' mode shouldn't appear in output. 141 style : removeInternal, 142 link : removeInternal 143 }, 144 attributeNames : 145 [ 146 [ 'hidefocus', '' ] 147 ] 148 }; 149 150 var dataProcessor = editor.dataProcessor; 151 dataProcessor.dataFilter.addRules( fullPageDataFilterRules ); 152 dataProcessor.htmlFilter.addRules( fullPageHtmlFilterRules ); 153 } 154 } ); 155 156 function removeInternal( element ) 157 { 158 if( element.attributes.cke_temp ) 159 return false; 160 } 161 162 function childByTagName( element, tagName ) 163 { 164 var children = element.children, 165 child; 166 for ( var i = 0; i < children.length; i++ ) 167 { 168 child = children[ i ]; 169 if( child.name && child.name == tagName ) 170 return child; 171 } 172 } 173 function wrapContent( element, tagName ) 174 { 175 var childrens = element.children, 176 root = new CKEDITOR.htmlParser.element( tagName, {} ); 177 element.children = []; 178 element.add( root ); 179 for ( var i = 0; i < childrens.length; i++ ) 180 { 181 root.add( childrens[ i ] ); 182 } 183 return root; 184 } 185 186 } )(); -
_source/core/config.js
198 198 * @type String 199 199 * @example 200 200 */ 201 plugins : 'about,basicstyles,blockquote,button,clipboard,colorbutton,colordialog,contextmenu,elementspath,enterkey,entities,filebrowser,find,flash,font,format,forms, horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,maximize,newpage,pagebreak,pastefromword,pastetext,popup,preview,print,removeformat,resize,save,scayt,smiley,showblocks,sourcearea,stylescombo,table,tabletools,specialchar,tab,templates,toolbar,undo,wysiwygarea,wsc',201 plugins : 'about,basicstyles,blockquote,button,clipboard,colorbutton,colordialog,contextmenu,elementspath,enterkey,entities,filebrowser,find,flash,font,format,forms,fullpage,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,maximize,newpage,pagebreak,pastefromword,pastetext,popup,preview,print,removeformat,resize,save,scayt,smiley,showblocks,sourcearea,stylescombo,table,tabletools,specialchar,tab,templates,toolbar,undo,wysiwygarea,wsc', 202 202 203 203 /** 204 204 * List of additional plugins to be loaded. This is a tool setting which -
_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 $ : V, 69 70 // List of elements won't appear in body. 71 $noneBodyContent: X(V,U,S), 72 73 /** 63 74 * List of block elements, like "p" or "div". 64 75 * @type Object 65 76 * @example 66 77 */ 67 78 $block : block, 68 79 69 $body : X({script:1}, block),80 $inline : inline, 70 81 82 $body : X({script:1,style:1}, block), 83 71 84 $cdata : {script:1,style:1}, 72 85 73 86 /** … … 120 133 */ 121 134 $tableContent : {caption:1,col:1,colgroup:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1}, 122 135 123 col : {}, 136 html: U, 137 head: T, 138 style: N, 139 script: N, 140 body: X(inline, block), 141 col : {}, 124 142 tr : {td:1,th:1}, 125 143 img : {}, 126 144 colgroup : {col:1}, … … 200 218 pre : X(G,C), 201 219 p : L, 202 220 em : L, 203 dfn : L 221 dfn : L, 222 base: {}, 223 link: {}, 224 meta: {}, 225 title: N 204 226 }; 205 227 })(); 206 228 -
_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 fullPage : true, 35 docType : '', 33 36 isBlockLike : true, 34 37 hasInlineStarted : false 35 38 }; … … 114 117 elementName = realElementName; 115 118 else 116 119 elementName = element.name; 117 if ( !( elementName in CKEDITOR.dtd.$body ) ) 120 if ( elementName 121 && !( elementName in CKEDITOR.dtd.$body ) 122 && !( elementName in CKEDITOR.dtd.$noneBodyContent ) ) 118 123 { 119 124 var savedCurrent = currentNode; 120 125 … … 156 161 } 157 162 } 158 163 164 parser.onDocType = function ( docType ) 165 { 166 fragment._.docType = docType; 167 }; 168 159 169 parser.onTagOpen = function( tagName, attributes, selfClosing ) 160 170 { 161 171 var element = new CKEDITOR.htmlParser.element( tagName, attributes ); … … 180 190 } 181 191 182 192 var currentName = currentNode.name, 183 currentDtd = ( currentName && CKEDITOR.dtd[ currentName ] ) || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ); 193 currentDtd = currentName && 194 ( CKEDITOR.dtd[ currentName ] 195 || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ) ); 184 196 185 197 // If the element cannot be child of the current element. 186 if ( !element.isUnknown && !currentNode.isUnknown && !currentDtd[ tagName ] ) 198 if ( currentDtd // Fragment could receive any elements. 199 && !element.isUnknown && !currentNode.isUnknown && !currentDtd[ tagName ] ) 187 200 { 188 // If this is the fragment node, just ignore this tag and add189 // its children.190 if ( !currentName )191 return;192 201 193 202 var reApply = false, 194 203 addPoint; // New position to start adding nodes. … … 330 339 index--; 331 340 } 332 341 } 342 343 if( tagName == 'body' ) 344 fixForBody = false; 333 345 }; 334 346 335 347 parser.onText = function( text ) … … 345 357 346 358 checkPending(); 347 359 348 if ( fixForBody && !currentNode.type ) 360 if ( fixForBody 361 && CKEDITOR.tools.trim( text ) 362 && ( !currentNode.type || currentNode.name == 'body' ) ) 349 363 this.onTagOpen( fixForBody, {} ); 350 364 351 365 // Shrinking consequential spaces into one single for all elements … … 375 389 var parent = currentNode.parent, 376 390 node = currentNode; 377 391 378 if ( fixForBody && !parent.type && !CKEDITOR.dtd.$body[ node.name ] ) 392 if ( fixForBody 393 && ( !parent.type || parent.name == 'body' ) 394 && !CKEDITOR.dtd.$body[ node.name ] ) 379 395 { 380 396 currentNode = parent; 381 397 parser.onTagOpen( fixForBody, {} ); … … 444 460 */ 445 461 writeHtml : function( writer, filter ) 446 462 { 463 // Call element filter on fragment as well as write doc-type. 464 if( !this.name ) 465 { 466 filter && filter.onElement( this ); 467 this._.docType && writer.docType( this._.docType ); 468 } 469 447 470 for ( var i = 0, len = this.children.length ; i < len ; i++ ) 448 471 this.children[i].writeHtml( writer, filter ); 449 472 } -
_source/plugins/htmldataprocessor/plugin.js
206 206 return html.replace( protectAttributeRegex, '$& _cke_saved_$1' ); 207 207 } 208 208 209 var protectStyleTagsRegex = /<(style)(?=[ >])[^>]*>[^<]*<\/\1>/gi; 209 var protectStyleTagsRegex = /<(style)(?=[ >])[^>]*>[^<]*<\/\1>/gi, 210 protectFullPageElementsRegex = /<(:?link|meta|base).*?>/; 210 211 var encodedTagsRegex = /<cke:encoded>([^<]*)<\/cke:encoded>/gi; 211 212 var protectElementNamesRegex = /(<\/?)((?:object|embed|param).*?>)/gi; 213 var shelvefullPageElementsRegex = /(<\/?)((?:html|body|head|title).*?>)/gi, 214 shelvedElementsRegex = /(<\/?)cke_fullpage:([^>]*>)/gi; 212 215 var protectSelfClosingRegex = /<cke:param(.*?)\/>/gi; 213 216 214 function protectStyleTagsMatch( match )217 function encodeMatched( match ) 215 218 { 216 219 return '<cke:encoded>' + encodeURIComponent( match ) + '</cke:encoded>'; 217 220 } 218 221 222 function shelveTags( html, isUnShelve ) 223 { 224 if ( isUnShelve ) 225 return unprotectEncodedTags( html.replace( shelvedElementsRegex, '$1$2' ) ); 226 else 227 { 228 return html 229 .replace( shelvefullPageElementsRegex, '$1cke_fullpage:$2' ) 230 .replace( protectFullPageElementsRegex, encodeMatched ); 231 } 232 } 233 219 234 function protectStyleTags( html ) 220 235 { 221 return html.replace( protectStyleTagsRegex, protectStyleTagsMatch);236 return html.replace( protectStyleTagsRegex, encodeMatched ); 222 237 } 223 238 function protectElementsNames( html ) 224 239 { … … 309 324 310 325 CKEDITOR.htmlDataProcessor.prototype = 311 326 { 312 toHtml : function( data, fixForBody )327 toHtml : function( data, fixForBody, fullPage, docType ) 313 328 { 314 329 // The source data is already HTML, but we need to clean 315 330 // it up and apply the filter. … … 333 348 // protecting them into open-close.(#3591) 334 349 data = protectSelfClosingElements( data ); 335 350 351 data = shelveTags( data ); 336 352 // Call the browser to help us fixing a possibly invalid HTML 337 353 // structure. 338 var div = document.createElement( 'div' );354 var div = new CKEDITOR.dom.element( 'div' ); 339 355 // Add fake character to workaround IE comments bug. (#3801) 340 div. innerHTML = 'a' + data;341 data = div. innerHTML.substr( 1 );356 div.setHtml( 'a' + data ); 357 data = div.getHtml().substr( 1 ); 342 358 359 data = shelveTags( data, true ); 343 360 if ( CKEDITOR.env.ie ) 344 361 data = unprotectEncodedTags( data ); 345 362 … … 348 365 var fragment = CKEDITOR.htmlParser.fragment.fromHtml( data, fixForBody ), 349 366 writer = new CKEDITOR.htmlParser.basicWriter(); 350 367 368 // Is docType missing and been explicitly defined in configuration? 369 docType && !fragment._.docType && ( fragment._.docType = docType ); 370 371 // Is HTML snippet mode instead of full page ? 372 ( fullPage !== true ) 373 && ( fragment._.fullPage = false, delete fragment._.docType ); 374 351 375 fragment.writeHtml( writer, this.dataFilter ); 352 376 353 377 return writer.getHtml( true ); 354 378 }, 355 379 356 toDataFormat : function( html, fixForBody )380 toDataFormat : function( html, fixForBody, fullPage ) 357 381 { 358 382 var writer = this.writer, 359 383 fragment = CKEDITOR.htmlParser.fragment.fromHtml( html, fixForBody ); 360 384 361 writer.reset(); 385 // Is HTML snippet mode instead of full page ? 386 ( fullPage !== true ) 387 && ( fragment._.fullPage = false, delete fragment._.docType ); 362 388 389 writer.reset(); 363 390 fragment.writeHtml( writer, this.htmlFilter ); 364 391 365 392 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,