Ticket #4067: 4067.patch

File 4067.patch, 20.7 KB (added by Garry Yao, 10 years ago)
  • _source/plugins/htmlwriter/plugin.js

     
    6767
    6868                var dtd = CKEDITOR.dtd;
    6969
    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 ) )
    7171                {
    7272                        this.setRules( e,
    7373                                {
  • _source/core/htmlparser/element.js

     
    3535        this.children = [];
    3636
    3737        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 ] ),
    3939                isEmpty         = !!dtd.$empty[ name ];
    4040
    4141        this.isEmpty    = isEmpty;
  • _source/plugins/wysiwygarea/plugin.js

     
    550550                                                        {
    551551                                                                isLoadingData = true;
    552552
    553                                                                 // Get the HTML version of the data.
     553                                                                // Get the full page HTML version of the data.
    554554                                                                if ( editor.dataProcessor )
    555                                                                 {
    556                                                                         data = editor.dataProcessor.toHtml( data, fixForBody );
    557                                                                 }
     555                                                                        data = editor.dataProcessor.toHtml( data, fixForBody, true );
    558556
    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;
    577558                                                                CKEDITOR._[ 'contentDomReady' + editor.name ] = contentDomReady;
    578559                                                                createIFrame();
    579560
     
    589570
    590571                                                        getData : function()
    591572                                                        {
    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();
    593576
    594577                                                                if ( editor.dataProcessor )
    595578                                                                        data = editor.dataProcessor.toDataFormat( data, fixForBody );
  • _source/core/dom/element.js

     
    328328                 */
    329329                getHtml : function()
    330330                {
    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;
    332335                },
    333336
    334337                getOuterHtml : function()
  • _source/core/htmlparser/filter.js

     
    127127
    128128        function addItemsToList( list, items, priority )
    129129        {
     130                if( typeof items == 'function' )
     131                        items = [ items ];
     132
    130133                var i, j,
    131134                        listLength = list.length,
    132135                        itemsLength = items && items.length;
  • _source/core/dtd.js

     
    5151                N = {'#':1},
    5252                O = X({param:1},K),
    5353                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};
    5560
    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};
    5763
    5864    return /** @lends CKEDITOR.dtd */ {
    5965
    6066                // The "$" items have been added manually.
    6167
    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            /**
    6377                 * List of block elements, like "p" or "div".
    6478                 * @type Object
    6579                 * @example
    6680                 */
    6781                $block : block,
    6882
    69                 $body : X({script:1}, block),
     83            $inline : inline,
    7084
     85                $body : X({script:1,style:1}, block),
     86
    7187                $cdata : {script:1,style:1},
    7288
    7389                /**
     
    120136                 */
    121137                $tableContent : {caption:1,col:1,colgroup:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1},
    122138
    123         col : {},
     139        html: U,
     140            head: T,
     141            style: N,
     142            script: N,
     143            body: X(inline, block),
     144            col : {},
    124145        tr : {td:1,th:1},
    125146        img : {},
    126147        colgroup : {col:1},
     
    200221        pre : X(G,C),
    201222        p : L,
    202223        em : L,
    203         dfn : L
     224        dfn : L,
     225            base: {},
     226                link: {},
     227            meta: {},
     228            title: N
    204229    };
    205230})();
    206231
  • _source/core/htmlparser/basicwriter.js

     
    1515
    1616        proto :
    1717        {
     18                docType : function( docType )
     19                {
     20                        this._.output.push( docType );
     21                },
     22
    1823                /**
    1924                 * Writes the tag opening part for a opener tag.
    2025                 * @param {String} tagName The element name for this tag.
     
    117122                reset : function()
    118123                {
    119124                        this._.output = [];
     125                        this._.indent = false;
    120126                },
    121127
    122128                /**
  • _source/core/htmlparser/fragment.js

     
    1818         * alert( fragment.children.length );  "2"
    1919         */
    2020        this.children = [];
     21        this.attributes = {};
    2122
    2223        /**
    2324         * Get the fragment parent. Should always be null.
     
    3031        /** @private */
    3132        this._ =
    3233        {
     34                docType : '',
    3335                isBlockLike : true,
    3436                hasInlineStarted : false
    3537        };
     
    114116                                        elementName = realElementName;
    115117                                else
    116118                                        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 )  )
    118122                                {
    119123                                        var savedCurrent = currentNode;
    120124
     
    156160                        }
    157161                }
    158162
     163                parser.onDocType = function ( docType )
     164                {
     165                        fragment._.docType = docType;
     166                };
     167
    159168                parser.onTagOpen = function( tagName, attributes, selfClosing )
    160169                {
    161170                        var element = new CKEDITOR.htmlParser.element( tagName, attributes );
     
    180189                        }
    181190
    182191                        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 ) );
    184195
    185196                        // 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 ] )
    187199                        {
    188                                 // If this is the fragment node, just ignore this tag and add
    189                                 // its children.
    190                                 if ( !currentName )
    191                                         return;
    192200
    193201                                var reApply = false,
    194202                                        addPoint;   // New position to start adding nodes.
     
    330338                                        index--;
    331339                                }
    332340                        }
     341
     342                        if( tagName == 'body' )
     343                                fixForBody = false;
    333344                };
    334345
    335346                parser.onText = function( text )
     
    345356
    346357                        checkPending();
    347358
    348                         if ( fixForBody && !currentNode.type )
     359                        if ( fixForBody
     360                                 && CKEDITOR.tools.trim( text )
     361                                 && ( !currentNode.type || currentNode.name == 'body' ) )
    349362                                this.onTagOpen( fixForBody, {} );
    350363
    351364                        // Shrinking consequential spaces into one single for all elements
     
    375388                        var parent = currentNode.parent,
    376389                                node = currentNode;
    377390
    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 ] )
    379394                        {
    380395                                currentNode = parent;
    381396                                parser.onTagOpen( fixForBody, {} );
     
    444459                 */
    445460                writeHtml : function( writer, filter )
    446461                {
     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
    447469                        for ( var i = 0, len = this.children.length ; i < len ; i++ )
    448470                                this.children[i].writeHtml( writer, filter );
    449471                }
  • _source/plugins/htmldataprocessor/plugin.js

     
    1111
    1212        var protectedSourceMarker = '{cke_protected}';
    1313
     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        }
    1425
    1526        // Return the last non-space child node of the block (#4344).
    1627        function lastNoneSpaceChild( block )
     
    7889        // We just avoid filler in <pre> right now.
    7990        // TODO: Support filler for <pre>, line break is also occupy line height.
    8091        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
    81106        var defaultDataFilterRules =
    82107        {
    83108                attributeNames :
     
    199224                };
    200225        }
    201226
     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
    202289        var protectAttributeRegex = /<(?:a|area|img|input).*?\s((?:href|src|name)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+)))/gi;
    203290
    204291        function protectAttributes( html )
     
    206293                return html.replace( protectAttributeRegex, '$& _cke_saved_$1' );
    207294        }
    208295
    209         var protectStyleTagsRegex = /<(style)(?=[ >])[^>]*>[^<]*<\/\1>/gi;
     296        var protectStyleTagsRegex = /<(style)(?=[ >])[^>]*>[^<]*<\/\1>/gi,
     297                protectFullPageElementsRegex = /<(:?link|meta|base).*?>/;
    210298        var encodedTagsRegex = /<cke:encoded>([^<]*)<\/cke:encoded>/gi;
    211299        var protectElementNamesRegex = /(<\/?)((?:object|embed|param).*?>)/gi;
     300        var shelvefullPageElementsRegex = /(<\/?)((?:html|body|head|title).*?>)/gi,
     301                shelvedElementsRegex = /(<\/?)cke_fullpage:([^>]*>)/gi;
    212302        var protectSelfClosingRegex = /<cke:param(.*?)\/>/gi;
    213303
    214         function protectStyleTagsMatch( match )
     304        function encodeMatched( match )
    215305        {
    216306                return '<cke:encoded>' + encodeURIComponent( match ) + '</cke:encoded>';
    217307        }
    218308
     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
    219321        function protectStyleTags( html )
    220322        {
    221                 return html.replace( protectStyleTagsRegex, protectStyleTagsMatch );
     323                return html.replace( protectStyleTagsRegex, encodeMatched );
    222324        }
    223325        function protectElementsNames( html )
    224326        {
     
    291393
    292394                        dataProcessor.writer.forceSimpleAmpersand = editor.config.forceSimpleAmpersand;
    293395
    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                        } ) );
    295484                        dataProcessor.dataFilter.addRules( defaultDataBlockFilterRules );
    296485                        dataProcessor.htmlFilter.addRules( defaultHtmlFilterRules );
    297486                        dataProcessor.htmlFilter.addRules( defaultHtmlBlockFilterRules );
     487                        dataProcessor.htmlFilter.addRules( editor.config.fullPage ? fullPageHtmlFilterRules : nonFullPageHtmlFilterRules );
    298488                }
    299489        });
    300490
     
    309499
    310500        CKEDITOR.htmlDataProcessor.prototype =
    311501        {
    312                 toHtml : function( data, fixForBody )
     502                toHtml : function( data, fixForBody, fullPage )
    313503                {
    314504                        // The source data is already HTML, but we need to clean
    315505                        // it up and apply the filter.
     
    333523                        // protecting them into open-close.(#3591)
    334524                        data = protectSelfClosingElements( data );
    335525
     526                        data = shelveTags( data );
    336527                        // Call the browser to help us fixing a possibly invalid HTML
    337528                        // structure.
    338                         var div = document.createElement( 'div' );
     529                        var div = new CKEDITOR.dom.element( 'div' );
    339530                        // 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 );
    342533
     534                        data = shelveTags( data, true );
     535
    343536                        if ( CKEDITOR.env.ie )
    344537                                data = unprotectEncodedTags( data );
    345538
     
    348541                        var fragment = CKEDITOR.htmlParser.fragment.fromHtml( data, fixForBody ),
    349542                                writer = new CKEDITOR.htmlParser.basicWriter();
    350543
     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
    351552                        fragment.writeHtml( writer, this.dataFilter );
    352553
    353554                        return writer.getHtml( true );
     
    358559                        var writer = this.writer,
    359560                                fragment = CKEDITOR.htmlParser.fragment.fromHtml( html, fixForBody );
    360561
    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;
    362565
     566                        writer.reset();
    363567                        fragment.writeHtml( writer, this.htmlFilter );
    364568
    365569                        return writer.getHtml( true );
  • _source/core/htmlparser.js

     
    1212{
    1313        this._ =
    1414        {
    15                 htmlPartsRegex : new RegExp( '<(?:(?:\\/([^>]+)>)|(?:!--([\\S|\\s]*?)-->)|(?:([^\\s>]+)\\s*((?:(?:[^"\'>]+)|(?:"[^"]*")|(?:\'[^\']*\'))*)\\/?>))', 'g' )
     15                htmlPartsRegex : new RegExp( '<(?:(?:\\/([^>]+)>)|(?:!--([\\S|\\s]*?)-->)|(?:([^\\s>]+)\\s*((?:(?:[^"\'>]+)|(?:"[^"]*")|(?:\'[^\']*\'))*)\\/?>))', 'g' ),
     16                docTypeRegex : /<!DOCTYPE[^>]*>/i
    1617        };
    1718};
    1819
     
    2425        CKEDITOR.htmlParser.prototype =
    2526        {
    2627                /**
     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                /**
    2735                 * Function to be fired when a tag opener is found. This function
    2836                 * should be overriden when using this class.
    2937                 * @param {String} tagName The tag name. The name is guarantted to be
     
    113121                 */
    114122                parse : function( html )
    115123                {
     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
    116132                        var parts,
    117133                                tagName,
    118134                                nextIndex = 0,
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy