Ticket #3188: 3188.patch

File 3188.patch, 16.5 KB (added by Garry Yao, 10 years ago)
  • _source/plugins/htmldataprocessor/plugin.js

     
    4343
    4444                        elements :
    4545                        {
     46                                br : function( element )
     47                                {
     48                                        // Gecko had been replacing all linebreaks into <br>s, which
     49                                        // are required to be restored here.
     50                                        if ( element.parent.name == 'pre' )
     51                                                element =  new CKEDITOR.htmlParser.text( '\n' );
     52                                        return element;
     53                                },
     54
    4655                                embed : function( element )
    4756                                {
    4857                                        var parent = element.parent;
     
    129138        CKEDITOR.htmlDataProcessor = function()
    130139        {
    131140                this.writer = new CKEDITOR.htmlWriter();
     141                // Disable indentation on <pre>.
     142                this.writer.setRules( 'pre',
     143                {
     144                  indent: false
     145                } );
    132146                this.dataFilter = new CKEDITOR.htmlParser.filter();
    133147                this.htmlFilter = new CKEDITOR.htmlParser.filter();
    134148        };
  • _source/plugins/styles/plugin.js

     
    102102                        :
    103103                                CKEDITOR.STYLE_INLINE;
    104104
     105                // Register custom style processer.
     106                if ( typeof styleDefinition.processor == 'function')
     107                        this[ this.type == CKEDITOR.STYLE_INLINE ? 'processRange' : 'processBlock' ]
     108                                        = styleDefinition.processor;
     109
    105110                this._ =
    106111                {
    107112                        definition : styleDefinition
     
    243248                                }
    244249                        }
    245250                        return false;
    246                 }
     251                },
     252                // Custom style processing callbacks.
     253                processBlock : null,
     254                processRange : null
    247255        };
    248256
    249257        // Build the cssText based on the styles definition.
     
    271279                if ( stylesText.length )
    272280                {
    273281                        stylesText = normalizeCssText( stylesText );
    274 
     282               
    275283                        if ( stylesText.length )
    276284                                stylesText = stylesText.replace( semicolonFixRegex, ';' );
    277285                }
     
    471479                                        parent = parent.getParent();
    472480                                }
    473481
    474                                 if ( styleNode )
     482                                // Delegate to customize inline style processing.
     483                                if ( this.processRange )
     484                                        this.processRange( styleRange, styleNode );
     485                                else
    475486                                {
    476487                                        // Move the contents of the range to the style element.
    477488                                        styleRange.extractContents().appendTo( styleNode );
     
    629640
    630641        function applyBlockStyle( range )
    631642        {
    632                 // Bookmark the range so we can re-select it after processing.
    633                 var bookmark = range.createBookmark();
     643                // Creating serialiable bookmarks to re-select ranges later.
     644                var bookmark = range.createBookmark( true );
    634645
    635646                var iterator = range.createIterator();
    636647                iterator.enforceRealBlocks = true;
     
    644655                        // Create the new node right before the current one.
    645656                        var newBlock = getElement( this, doc );
    646657
    647                         // Check if we are changing from/to <pre>.
    648 //                      var newBlockIsPre       = newBlock.nodeName.IEquals( 'pre' );
    649 //                      var blockIsPre          = block.nodeName.IEquals( 'pre' );
    650 
    651 //                      var toPre       = newBlockIsPre && !blockIsPre;
    652 //                      var fromPre     = !newBlockIsPre && blockIsPre;
    653 
    654                         // Move everything from the current node to the new one.
    655 //                      if ( toPre )
    656 //                              newBlock = this._ToPre( doc, block, newBlock );
    657 //                      else if ( fromPre )
    658 //                              newBlock = this._FromPre( doc, block, newBlock );
    659 //                      else    // Convering from a regular block to another regular block.
     658                        // Delegate to custom block style processing.
     659                        if( this.processBlock )
     660                                this.processBlock( block, newBlock );
     661                        else
     662                        {
    660663                                block.moveChildren( newBlock );
    661 
    662                         // Replace the current block.
    663                         newBlock.insertBefore( block );
    664                         block.remove();
    665 
    666                         // Complete other tasks after inserting the node in the DOM.
    667 //                      if ( newBlockIsPre )
    668 //                      {
    669 //                              if ( previousPreBlock )
    670 //                                      this._CheckAndMergePre( previousPreBlock, newBlock ) ;  // Merge successive <pre> blocks.
    671 //                              previousPreBlock = newBlock;
    672 //                      }
    673 //                      else if ( fromPre )
    674 //                              this._CheckAndSplitPre( newBlock ) ;    // Split <br><br> in successive <pre>s.
     664                                // Replace the current block.
     665                                newBlock.insertBefore( block );
     666                                block.remove();
     667                        }
    675668                }
    676669
    677670                range.moveToBookmark( bookmark );
  • _source/plugins/format/plugin.js

     
    22Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
    33For licensing, see LICENSE.html or http://ckeditor.com/license
    44*/
     5( function(){
     6        CKEDITOR.plugins.add( 'format',
     7        {
     8                requires : [ 'richcombo', 'styles' ],
     9
     10                init : function( editor )
     11                {
     12                        var config = editor.config,
     13                                lang = editor.lang.format;
    514
    6 CKEDITOR.plugins.add( 'format',
    7 {
    8         requires : [ 'richcombo', 'styles' ],
     15                        // Gets the list of tags from the settings.
     16                        var tags = config.format_tags.split( ';' ),
     17                                // Whether <pre> switching logic is needed.
     18                                hasPreFormat = !!config.format_pre;
    919
    10         init : function( editor )
    11         {
    12                 var config = editor.config,
    13                         lang = editor.lang.format;
     20                        // Special treatment for <pre> blocks is needed, which makes it possible
     21                        // to switch forth and back to <p>, with format well preserved, and
     22                        // merging/splitting adjacent when necessary.(#3188)
     23                        function processPre( block, newBlock )
     24                        {
     25                                var doc = editor.document;
     26                                // Create the new node right before the current one.
     27                                // Check if we are changing from/to <pre>.
     28                                var newBlockIsPre       = newBlock.is( 'pre' );
     29                                var blockIsPre          = block.is( 'pre' );
     30
     31                                var isToPre     = newBlockIsPre && !blockIsPre;
     32                                var isFromPre   = !newBlockIsPre && blockIsPre;
     33
     34                                // Move everything from the current node to the new one.
     35                                if ( isToPre )
     36                                        newBlock = toPre( block, newBlock, doc );
     37                                else if ( isFromPre )
     38                                        newBlock = fromPre( block, newBlock );
     39
     40                                newBlock.replace( block );
    1441
    15                 // Gets the list of tags from the settings.
    16                 var tags = config.format_tags.split( ';' );
     42                                if ( newBlockIsPre )
     43                                        // Merge successive <pre> blocks.
     44                                        mergePre( newBlock );
     45                                else if ( isFromPre )
     46                                        // Split <br><br> in successive <pre>s.
     47                                        splitIntoBlocks( newBlock, doc );
    1748
    18                 // Create style objects for all defined styles.
    19                 var styles = {};
    20                 for ( var i = 0 ; i < tags.length ; i++ )
    21                 {
    22                         var tag = tags[ i ];
    23                         styles[ tag ] = new CKEDITOR.style( config[ 'format_' + tag ] );
    24                 }
    2549
    26                 editor.ui.addRichCombo( 'Format',
     50                        };
     51                        // Create style objects for all defined styles.
     52                        var styles = {};
     53                        for ( var i = 0 ; i < tags.length ; i++ )
    2754                        {
    28                                 label : lang.label,
    29                                 title : lang.panelTitle,
    30                                 voiceLabel : lang.voiceLabel,
    31                                 className : 'cke_format',
    32                                 multiSelect : false,
     55                                var tag = tags[ i ],
     56                                        tagDef = config[ 'format_' + tag ];
     57
     58                                if ( hasPreFormat )
     59                                        // Now the <pre> pre-processor is attaching to each block style.
     60                                        tagDef.processor = processPre;
    3361
    34                                 panel :
    35                                 {
    36                                         css : [ config.contentsCss, CKEDITOR.getUrl( editor.skinPath + 'editor.css' ) ],
    37                                         voiceLabel : lang.panelVoiceLabel
    38                                 },
     62                                styles[ tag ] = new CKEDITOR.style( tagDef );
     63                        }
    3964
    40                                 init : function()
     65                        editor.ui.addRichCombo( 'Format',
    4166                                {
    42                                         this.startGroup( lang.panelTitle );
     67                                        label : lang.label,
     68                                        title : lang.panelTitle,
     69                                        voiceLabel : lang.voiceLabel,
     70                                        className : 'cke_format',
     71                                        multiSelect : false,
    4372
    44                                         for ( var tag in styles )
     73                                        panel :
    4574                                        {
    46                                                 var label = lang[ 'tag_' + tag ];
     75                                                css : [ config.contentsCss, CKEDITOR.getUrl( editor.skinPath + 'editor.css' ) ],
     76                                                voiceLabel : lang.panelVoiceLabel
     77                                        },
    4778
    48                                                 // Add the tag entry to the panel list.
    49                                                 this.add( tag, '<' + tag + '>' + label + '</' + tag + '>', label );
    50                                         }
    51                                 },
     79                                        init : function()
     80                                        {
     81                                                this.startGroup( lang.panelTitle );
    5282
    53                                 onClick : function( value )
    54                                 {
    55                                         editor.focus();
    56                                         editor.fire( 'saveSnapshot' );
     83                                                for ( var tag in styles )
     84                                                {
     85                                                        var label = lang[ 'tag_' + tag ];
    5786
    58                                         styles[ value ].apply( editor.document );
     87                                                        // Add the tag entry to the panel list.
     88                                                        this.add( tag, '<' + tag + '>' + label + '</' + tag + '>', label );
     89                                                }
     90                                        },
    5991
    60                                         editor.fire( 'saveSnapshot' );
    61                                 },
     92                                        onClick : function( value )
     93                                        {
     94                                                editor.focus();
     95                                                editor.fire( 'saveSnapshot' );
    6296
    63                                 onRender : function()
    64                                 {
    65                                         editor.on( 'selectionChange', function( ev )
    66                                                 {
    67                                                         var currentTag = this.getValue();
     97                                                styles[ value ].apply( editor.document );
    6898
    69                                                         var elementPath = ev.data.path;
     99                                                editor.fire( 'saveSnapshot' );
     100                                        },
    70101
    71                                                         for ( var tag in styles )
     102                                        onRender : function()
     103                                        {
     104                                                editor.on( 'selectionChange', function( ev )
    72105                                                        {
    73                                                                 if ( styles[ tag ].checkActive( elementPath ) )
     106                                                                var currentTag = this.getValue();
     107
     108                                                                var elementPath = ev.data.path;
     109
     110                                                                for ( var tag in styles )
    74111                                                                {
    75                                                                         if ( tag != currentTag )
    76                                                                                 this.setValue( tag, editor.lang.format[ 'tag_' + tag ] );
    77                                                                         return;
     112                                                                        if ( styles[ tag ].checkActive( elementPath ) )
     113                                                                        {
     114                                                                                if ( tag != currentTag )
     115                                                                                        this.setValue( tag, editor.lang.format[ 'tag_' + tag ] );
     116                                                                                return;
     117                                                                        }
    78118                                                                }
    79                                                         }
     119
     120                                                                // If no styles match, just empty it.
     121                                                                this.setValue( '' );
     122                                                        },
     123                                                        this);
     124                                        }
     125                                });
     126                }
     127        });
    80128
    81                                                         // If no styles match, just empty it.
    82                                                         this.setValue( '' );
    83                                                 },
    84                                                 this);
    85                                 }
    86                         });
     129        /**
     130         * Merge a <pre> block with a previous sibling if available.
     131         */
     132        function mergePre( preBlock )
     133        {
     134                var previousBlock;
     135                if ( !( ( previousBlock = preBlock.getPreviousSourceNode( true, CKEDITOR.NODE_ELEMENT ) )
     136                                 && previousBlock.is
     137                                 && previousBlock.is( 'pre') ) )
     138                        return;
     139
     140                // Merge the previous <pre> block contents into the current <pre>
     141                // block.
     142                //
     143                // Another thing to be careful here is that currentBlock might contain
     144                // a '\n' at the beginning, and previousBlock might contain a '\n'
     145                // towards the end. These new lines are not normally displayed but they
     146                // become visible after merging.
     147                var mergedHtml = previousBlock.getHtml().replace( /\n$/, '' ) + '\n\n' +
     148                                preBlock.getHtml().replace( /^\n/, '' ) ;
     149
     150                // Krugle: IE normalizes innerHTML from <pre>, breaking whitespaces.
     151                if ( CKEDITOR.env.ie )
     152                        preBlock.$.outerHTML = '<pre>' + mergedHtml + '</pre>';
     153                else
     154                        preBlock.setHtml( mergedHtml );
     155
     156                previousBlock.remove();
    87157        }
    88 });
    89158
     159        function splitIntoBlocks( newBlock, doc )
     160        {
     161                var duoBrRegex = /(:?<br\b[^>]*>)\s*(:?<br\b[^>]*>)/gi,
     162                        blockName = newBlock.getName(),
     163                        splitedHtml = newBlock.getOuterHtml().replace(
     164                                duoBrRegex, function()
     165                                        {
     166                                          return '<' + blockName + '/>' + '<' + blockName + '>';
     167                                        }
     168                                );
     169                var temp = doc.createElement( 'div' );
     170                temp.setHtml( splitedHtml );
     171                temp.replace( newBlock );
     172                temp.remove( true );
     173        }
     174
     175        /**
     176         * Converting from a PRE block to a non-PRE block in formatting operations.
     177         */
     178        function fromPre( block, newBlock )
     179        {
     180                var blockHtml = block.getHtml();
     181
     182                // Trim the first and last linebreaks immediately after and before <pre>, </pre>,
     183                // if they exist.
     184                // This is done because the linebreaks are not rendered.
     185                blockHtml = blockHtml.replace( /(\r\n|\r)/g, '\n' ) ;
     186                blockHtml = blockHtml.replace( /^[ \t]*\n/, '' ) ;
     187                blockHtml = blockHtml.replace( /\n$/, '' ) ;
     188
     189                // 1. Convert spaces or tabs at the beginning or at the end to &nbsp;
     190                blockHtml = blockHtml.replace( /^[ \t]+|[ \t]+$/g, function( match, offset, s )
     191                                {
     192                                        if ( match.length == 1 )        // one space, preserve it
     193                                                return '&nbsp;' ;
     194                                        else if ( offset == 0 )         // beginning of block
     195                                                return new Array( match.length ).join( '&nbsp;' ) + ' ' ;
     196                                        else                            // end of block
     197                                                return ' ' + new Array( match.length ).join( '&nbsp;' ) ;
     198                                } ) ;
     199
     200                // 2. Convert \n to <BR>.
     201                // 3. Convert contiguous (i.e. non-singular) spaces or tabs to &nbsp;
     202                blockHtml = blockHtml.replace( /\n/g, '<br>' ) ;
     203                blockHtml = blockHtml.replace( /[ \t]{2,}/g,
     204                                function ( match )
     205                                {
     206                                        return new Array( match.length ).join( '&nbsp;' ) + ' ' ;
     207                                } ) ;
     208                newBlock.setHtml( blockHtml );
     209                return newBlock ;
     210        }
     211
     212        /**
     213         * Converting from a non-PRE block to a PRE block in formatting operations.
     214         */
     215        function toPre( block, newBlock, doc )
     216        {
     217                // Handle converting from a regular block to a <pre> block.
     218                var preHtml = CKEDITOR.tools.trim( block.getHtml() );
     219
     220                // 1. Delete ANSI whitespaces immediately before and after <BR> because
     221                //    they are not visible.
     222                // 2. Mark down any <BR /> nodes here so they can be turned into \n in
     223                //    the next step and avoid being compressed.
     224                preHtml = preHtml.replace( /[ \t\r\n]*(<br[^>]*>)[ \t\r\n]*/gi, '$1' );
     225                // 3. Compress other ANSI whitespaces since they're only visible as one
     226                //    single space previously.
     227                // 4. Convert &nbsp; to spaces since &nbsp; is no longer needed in <PRE>.
     228                preHtml = preHtml.replace( /([ \t\n\r]+|&nbsp;)/g, ' ' );
     229                // 5. Convert any <BR /> to \n. This must not be done earlier because
     230                //    the \n would then get compressed.
     231                preHtml = preHtml.replace( /<br\b[^>]*>/gi, '\n' );
     232
     233                // Krugle: IE normalizes innerHTML to <pre>, breaking whitespaces.
     234                if ( CKEDITOR.env.ie )
     235                {
     236                        var temp = doc.createElement( 'div' );
     237                        temp.append( newBlock );
     238                        newBlock.$.outerHTML =  '<pre>\n' + preHtml + '</pre>';
     239                        newBlock = temp.getFirst().remove();
     240                }
     241                else
     242                        newBlock.setHtml( preHtml );
     243
     244                return newBlock;
     245        }
     246
     247
     248})();
    90249CKEDITOR.config.format_tags = 'p;h1;h2;h3;h4;h5;h6;pre;address;div';
    91250
    92251CKEDITOR.config.format_p                = { element : 'p' };
  • _source/core/htmlparser/element.js

     
    124124                                        if ( !( element = filter.onElement( element ) ) )
    125125                                                return;
    126126
    127                                         if ( element.name == writeName )
     127                                        // Element already get serialized.
     128                                        if ( typeof element == 'string')
     129                                        {
     130                                                writer.write( element );
     131                                                return;
     132                                        }
     133                                        else if ( element.name == writeName )
    128134                                                break;
    129135
    130136                                        writeName = element.name;
  • _source/core/htmlparser/text.js

     
    55
    66(function()
    77{
    8         var spacesRegex = /[\t\r\n ]{2,}|[\t\r\n]/g;
    98
    109        /**
    1110         * A lightweight representation of HTML text.
     
    1918                 * @type String
    2019                 * @example
    2120                 */
    22                 this.value = value.replace( spacesRegex, ' ' );
     21                this.value = value;
    2322
    2423                /** @private */
    2524                this._ =
  • _source/core/htmlparser/fragment.js

     
    4747                        {table:1,ul:1,ol:1,dl:1},
    4848                        CKEDITOR.dtd.table, CKEDITOR.dtd.ul, CKEDITOR.dtd.ol, CKEDITOR.dtd.dl );
    4949
     50        // Whitespaces within text node is required to be striped off.
     51        var spacesRegex = /[\t\r\n ]{2,}|[\t\r\n]/g;
    5052        /**
    5153         * Creates a {@link CKEDITOR.htmlParser.fragment} from an HTML string.
    5254         * @param {String} fragmentHtml The HTML to be parsed, filling the fragment.
     
    286288                        if ( fixForBody && !currentNode.type )
    287289                                this.onTagOpen( 'p', {} );
    288290
     291                        // Preserve whitespace, tabs, and carriage returns on <pre> element.
     292                        if ( currentNode.name != 'pre' )
     293                           text = text.replace( spacesRegex, '' );
     294
    289295                        currentNode.add( new CKEDITOR.htmlParser.text( text ) );
    290296                };
    291297
  • _source/core/htmlparser/filter.js

     
    8787                                                if ( ret === false )
    8888                                                        return null;
    8989
     90                                                // Element might been transformed into text node.
     91                                                if( ret && ret.type == CKEDITOR.NODE_TEXT )
     92                                                        return this.onText( ret.value );
     93                                               
    9094                                                if ( ret && ret != element )
    9195                                                        return this.onElement( ret );
    9296                                        }
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy