Ticket #5367: 5367_3.patch

File 5367_3.patch, 17.7 KB (added by Garry Yao, 9 years ago)
  • _source/core/editor.js

     
    755755                        this.fire( 'insertHtml', data );
    756756                },
    757757
     758                /*
     759                 * Insert text content into the currently selected position in the
     760                 * editor, in WYSIWYG mode, styles of the selected element will be applied to the inserted text,
     761                 * spaces around the text will be leaving untouched.
     762                 * <strong>Note:</strong> two subsequent line-breaks will be translated into
     763                 * one enter-key in effect, result depends on {@link CKEDITOR.config.enterMode};
     764                 * A single line-break will be translated into per shift-enter-key correspondingly.
     765                 * @param {String} text Text to be inserted into the editor.
     766                 * @example
     767                 * CKEDITOR.instances.editor1.<b>insertText( ' line1 \n\n line2' )</b>;
     768                 */
     769                insertText : function( text )
     770                {
     771                        this.fire( 'insertText', text );
     772                },
     773
    758774                /**
    759775                 * Inserts an element into the currently selected position in the
    760776                 * editor.
  • _source/plugins/wysiwygarea/plugin.js

     
    2626                        return selection.getCommonAncestor().isReadOnly();
    2727        }
    2828
    29         function onInsertHtml( evt )
     29
     30        function onInsert( insertFunc )
    3031        {
    31                 if ( this.mode == 'wysiwyg' )
    32                 {
    33                         this.focus();
     32                return function( evt )
     33                {
     34                        if ( this.mode == 'wysiwyg' )
     35                        {
     36                                this.focus();
    3437
    35                         var selection = this.getSelection();
    36                         if ( checkReadOnly( selection ) )
    37                                 return;
     38                                var selection = this.getSelection();
     39                                if ( checkReadOnly( selection ) )
     40                                        return;
    3841
    39                         var data = evt.data;
    40                         this.fire( 'saveSnapshot' );
     42                                this.fire( 'saveSnapshot' );
    4143
    42                         if ( this.dataProcessor )
    43                                 data = this.dataProcessor.toHtml( data );
     44                                insertFunc.call( this, evt.data );
     45
     46                                // Save snaps after the whole execution completed.
     47                                // This's a workaround for make DOM modification's happened after
     48                                // 'insertElement' to be included either, e.g. Form-based dialogs' 'commitContents'
     49                                // call.
     50                                CKEDITOR.tools.setTimeout( function()
     51                                   {
     52                                           this.fire( 'saveSnapshot' );
     53                                   }, 0, this );
     54                        }
     55                }
     56        }
     57       
     58        function doInsertHtml( data )
     59        {
     60                if ( this.dataProcessor )
     61                        data = this.dataProcessor.toHtml( data );
    4462
    45                         if ( CKEDITOR.env.ie )
    46                         {
    47                                 var selIsLocked = selection.isLocked;
     63                var selection = this.getSelection();
     64                if ( CKEDITOR.env.ie )
     65                {
     66                        var selIsLocked = selection.isLocked;
    4867
    49                                 if ( selIsLocked )
    50                                         selection.unlock();
     68                        if ( selIsLocked )
     69                                selection.unlock();
    5170
    52                                 var $sel = selection.getNative();
     71                        var $sel = selection.getNative();
    5372
    54                                 // Delete control selections to avoid IE bugs on pasteHTML.
    55                                 if ( $sel.type == 'Control' )
    56                                         $sel.clear();
     73                        // Delete control selections to avoid IE bugs on pasteHTML.
     74                        if ( $sel.type == 'Control' )
     75                                $sel.clear();
    5776                                else if  ( selection.getType() == CKEDITOR.SELECTION_TEXT )
    58                                 {
    59                                         // Due to IE bugs on handling contenteditable=false blocks
    60                                         // (#6005), we need to make some checks and eventually
    61                                         // delete the selection first.
     77                        {
     78                                // Due to IE bugs on handling contenteditable=false blocks
     79                                // (#6005), we need to make some checks and eventually
     80                                // delete the selection first.
    6281
    63                                         var range = selection.getRanges()[0],
     82                                var range = selection.getRanges()[0],
    6483                                                endContainer = range && range.endContainer;
    6584
    66                                         if ( endContainer &&
    67                                                  endContainer.type == CKEDITOR.NODE_ELEMENT &&
    68                                                  endContainer.getAttribute( 'contenteditable' ) == 'false' &&
    69                                                  range.checkBoundaryOfElement( endContainer, CKEDITOR.END ) )
    70                                         {
    71                                                 range.setEndAfter( range.endContainer );
    72                                                 range.deleteContents();
    73                                         }
    74                                 }
     85                                if ( endContainer &&
     86                                                endContainer.type == CKEDITOR.NODE_ELEMENT &&
     87                                                endContainer.getAttribute( 'contenteditable' ) == 'false' &&
     88                                                range.checkBoundaryOfElement( endContainer, CKEDITOR.END ) )
     89                                {
     90                                        range.setEndAfter( range.endContainer );
     91                                        range.deleteContents();
     92                                }
     93                        }
    7594
    76                                 try
    77                                 {
    78                                         $sel.createRange().pasteHTML( data );
    79                                 }
     95                        try
     96                        {
     97                                $sel.createRange().pasteHTML( data );
     98                        }
    8099                                catch (e) {}
    81100
    82                                 if ( selIsLocked )
    83                                         this.getSelection().lock();
    84                         }
    85                         else
    86                                 this.document.$.execCommand( 'inserthtml', false, data );
     101                        if ( selIsLocked )
     102                                this.getSelection().lock();
     103                }
     104                else
     105                        this.document.$.execCommand( 'inserthtml', false, data );
    87106
    88                         // Webkit does not scroll to the cursor position after pasting (#5558)
    89                         if ( CKEDITOR.env.webkit )
    90                         {
    91                                 this.document.$.execCommand( 'inserthtml', false, '<span id="cke_paste_marker" data-cke-temp="1"></span>' );
    92                                 var marker = this.document.getById( 'cke_paste_marker' );
    93                                 marker.scrollIntoView();
    94                                 marker.remove();
    95                                 marker = null;
    96                         }
     107                // Webkit does not scroll to the cursor position after pasting (#5558)
     108                if ( CKEDITOR.env.webkit )
     109                {
     110                        this.document.$.execCommand( 'inserthtml', false, '<span id="cke_paste_marker" data-cke-temp="1"></span>' );
     111                        var marker = this.document.getById( 'cke_paste_marker' );
     112                        marker.scrollIntoView();
     113                        marker.remove();
     114                        marker = null;
     115                }
     116        }
    97117
    98                         CKEDITOR.tools.setTimeout( function()
    99                                 {
    100                                         this.fire( 'saveSnapshot' );
    101                                 }, 0, this );
     118        function doInsertText( text )
     119        {
     120                var selection = this.getSelection(),
     121                        mode = selection.getStartElement().hasAscendant( 'pre', true ) ?
     122                                   CKEDITOR.ENTER_BR : this.config.enterMode,
     123                        isEnterBrMode = mode == CKEDITOR.ENTER_BR;
     124
     125                var html = CKEDITOR.tools.htmlEncode( text.replace( /\r\n|\r/g, '\n' ) );
     126
     127                // Convert leading and trailing whitespaces into &nbsp;
     128                html = html.replace( /^[ \t]+|[ \t]+$/g, function( match, offset, s )
     129                        {
     130                                if ( match.length == 1 )        // one space, preserve it
     131                                        return '&nbsp;';
     132                                else if ( !offset )             // beginning of block
     133                                        return CKEDITOR.tools.repeat( '&nbsp;', match.length - 1 ) + ' ';
     134                                else                            // end of block
     135                                        return ' ' + CKEDITOR.tools.repeat( '&nbsp;', match.length - 1 );
     136                        } );
     137
     138                // Convert subsequent whitespaces into &nbsp;
     139                html = html.replace( /[ \t]{2,}/g, function ( match )
     140                   {
     141                           return CKEDITOR.tools.repeat( '&nbsp;', match.length - 1 ) + ' ';
     142                   } );
     143
     144                var paragraphTag = mode == CKEDITOR.ENTER_P ? 'p' : 'div';
     145
     146                // Two line-breaks create one paragraph.
     147                if ( !isEnterBrMode )
     148                {
     149                        html = html.replace( /(\n{2})([\s\S]*?)(?:$|\1)/g,
     150                                function( match, group1, text )
     151                                {
     152                                        return '<'+paragraphTag + '>' + text + '</' + paragraphTag + '>';
     153                                });
    102154                }
    103         }
     155
     156                // One <br> per line-break.
     157                html = html.replace( /\n/g, '<br>' );
     158
     159                // Compensate padding <br> for non-IE.
     160                if ( !( isEnterBrMode || CKEDITOR.env.ie ) )
     161                {
     162                        html = html.replace( new RegExp( '<br>(?=</' + paragraphTag + '>)' ), function( match )
     163                        {
     164                                return CKEDITOR.tools.repeat( match, 2 );
     165                        } );
     166                }
    104167
    105         function onInsertElement( evt )
    106         {
    107                 if ( this.mode == 'wysiwyg' )
    108                 {
    109                         this.focus();
     168                // Inline styles have to be inherited in Firefox.
     169                if ( CKEDITOR.env.gecko )
     170                {
     171                        var path = new CKEDITOR.dom.elementPath( selection.getStartElement() ),
     172                                context = [];
     173
     174                        for ( var i = 0; i < path.elements.length; i++ )
     175                        {
     176                                var tag = path.elements[ i ].getName();
     177                                if ( tag in CKEDITOR.dtd.$inline )
     178                                        context.unshift( path.elements[ i ].getOuterHtml().match( /^<.*?>/) );
     179                                else if ( tag in CKEDITOR.dtd.$block )
     180                                        break;
     181                        }
    110182
    111                         var selection = this.getSelection();
    112                         if ( checkReadOnly( selection ) )
    113                                 return;
     183                        // Reproduce the context  by preceding the pasted HTML with opening inline tags.
     184                        html = context.join( '' ) + html;
     185                }
    114186
    115                         this.fire( 'saveSnapshot' );
     187                doInsertHtml.call( this, html );
     188        }
    116189
    117                         var ranges = selection.getRanges(),
    118                                 element = evt.data,
     190        function doInsertElement( element )
     191        {
     192                var selection = this.getSelection(),
     193                                ranges = selection.getRanges(),
    119194                                elementName = element.getName(),
    120195                                isBlock = CKEDITOR.dtd.$block[ elementName ];
    121196
    122                         var selIsLocked = selection.isLocked;
     197                var selIsLocked = selection.isLocked;
    123198
    124                         if ( selIsLocked )
    125                                 selection.unlock();
     199                if ( selIsLocked )
     200                        selection.unlock();
    126201
    127                         var range, clone, lastElement, bookmark;
     202                var range, clone, lastElement, bookmark;
    128203
    129                         for ( var i = ranges.length - 1 ; i >= 0 ; i-- )
    130                         {
    131                                 range = ranges[ i ];
     204                for ( var i = ranges.length - 1 ; i >= 0 ; i-- )
     205                {
     206                        range = ranges[ i ];
    132207
    133                                 // Remove the original contents.
    134                                 range.deleteContents();
     208                        // Remove the original contents.
     209                        range.deleteContents();
    135210
    136                                 clone = !i && element || element.clone( 1 );
     211                        clone = !i && element || element.clone( 1 );
    137212
    138                                 // If we're inserting a block at dtd-violated position, split
    139                                 // the parent blocks until we reach blockLimit.
    140                                 var current, dtd;
    141                                 if ( isBlock )
    142                                 {
    143                                         while ( ( current = range.getCommonAncestor( 0, 1 ) )
    144                                                         && ( dtd = CKEDITOR.dtd[ current.getName() ] )
    145                                                         && !( dtd && dtd [ elementName ] ) )
    146                                         {
    147                                                 // Split up inline elements.
    148                                                 if ( current.getName() in CKEDITOR.dtd.span )
    149                                                         range.splitElement( current );
    150                                                 // If we're in an empty block which indicate a new paragraph,
    151                                                 // simply replace it with the inserting block.(#3664)
    152                                                 else if ( range.checkStartOfBlock()
    153                                                          && range.checkEndOfBlock() )
    154                                                 {
    155                                                         range.setStartBefore( current );
    156                                                         range.collapse( true );
    157                                                         current.remove();
    158                                                 }
    159                                                 else
    160                                                         range.splitBlock();
    161                                         }
    162                                 }
     213                        // If we're inserting a block at dtd-violated position, split
     214                        // the parent blocks until we reach blockLimit.
     215                        var current, dtd;
     216                        if ( isBlock )
     217                        {
     218                                while ( ( current = range.getCommonAncestor( 0, 1 ) )
     219                                                && ( dtd = CKEDITOR.dtd[ current.getName() ] )
     220                                                && !( dtd && dtd [ elementName ] ) )
     221                                {
     222                                        // Split up inline elements.
     223                                        if ( current.getName() in CKEDITOR.dtd.span )
     224                                                range.splitElement( current );
     225                                        // If we're in an empty block which indicate a new paragraph,
     226                                        // simply replace it with the inserting block.(#3664)
     227                                        else if ( range.checkStartOfBlock()
     228                                                        && range.checkEndOfBlock() )
     229                                        {
     230                                                range.setStartBefore( current );
     231                                                range.collapse( true );
     232                                                current.remove();
     233                                        }
     234                                        else
     235                                                range.splitBlock();
     236                                }
     237                        }
    163238
    164                                 // Insert the new node.
    165                                 range.insertNode( clone );
     239                        // Insert the new node.
     240                        range.insertNode( clone );
    166241
    167                                 // Save the last element reference so we can make the
    168                                 // selection later.
    169                                 if ( !lastElement )
    170                                         lastElement = clone;
    171                         }
     242                        // Save the last element reference so we can make the
     243                        // selection later.
     244                        if ( !lastElement )
     245                                lastElement = clone;
     246                }
    172247
    173                         range.moveToPosition( lastElement, CKEDITOR.POSITION_AFTER_END );
     248                range.moveToPosition( lastElement, CKEDITOR.POSITION_AFTER_END );
    174249
    175                         // If we're inserting a block element immediatelly followed by
    176                         // another block element, the selection must move there. (#3100,#5436)
    177                         if ( isBlock )
    178                         {
    179                                 var next = lastElement.getNext( notWhitespaceEval ),
     250                // If we're inserting a block element immediatelly followed by
     251                // another block element, the selection must move there. (#3100,#5436)
     252                if ( isBlock )
     253                {
     254                        var next = lastElement.getNext( notWhitespaceEval ),
    180255                                        nextName = next && next.type == CKEDITOR.NODE_ELEMENT && next.getName();
    181256
    182                                 // Check if it's a block element that accepts text.
    183                                 if ( nextName && CKEDITOR.dtd.$block[ nextName ] && CKEDITOR.dtd[ nextName ]['#'] )
    184                                         range.moveToElementEditStart( next );
    185                         }
     257                        // Check if it's a block element that accepts text.
     258                        if ( nextName && CKEDITOR.dtd.$block[ nextName ] && CKEDITOR.dtd[ nextName ]['#'] )
     259                                range.moveToElementEditStart( next );
     260                }
    186261
    187                         selection.selectRanges( [ range ] );
     262                selection.selectRanges( [ range ] );
    188263
    189                         if ( selIsLocked )
    190                                 this.getSelection().lock();
    191 
    192                         // Save snaps after the whole execution completed.
    193                         // This's a workaround for make DOM modification's happened after
    194                         // 'insertElement' to be included either, e.g. Form-based dialogs' 'commitContents'
    195                         // call.
    196                         CKEDITOR.tools.setTimeout( function(){
    197                                 this.fire( 'saveSnapshot' );
    198                         }, 0, this );
    199                 }
    200         }
     264                if ( selIsLocked )
     265                        this.getSelection().lock();
     266        }
    201267
    202268        // DOM modification here should not bother dirty flag.(#4385)
    203269        function restoreDirty( editor )
     
    9591025                                                        }
    9601026                                                });
    9611027
    962                                         editor.on( 'insertHtml', onInsertHtml, null, null, 20 );
    963                                         editor.on( 'insertElement', onInsertElement, null, null, 20 );
     1028                                        editor.on( 'insertHtml', onInsert( doInsertHtml ) , null, null, 20 );
     1029                                        editor.on( 'insertElement', onInsert( doInsertElement ), null, null, 20 );
     1030                                        editor.on( 'insertText', onInsert( doInsertText ), null, null, 20 );
    9641031                                        // Auto fixing on some document structure weakness to enhance usabilities. (#3190 and #3189)
    9651032                                        editor.on( 'selectionChange', onSelectionChangeFixBody, null, null, 1 );
    9661033                                });
  • _source/core/dom/element.js

     
    721721                        var thisLength = thisAttribs.length,
    722722                                otherLength = otherAttribs.length;
    723723
    724                         if ( !CKEDITOR.env.ie && thisLength != otherLength )
    725                                 return false;
    726 
    727724                        for ( var i = 0 ; i < thisLength ; i++ )
    728725                        {
    729726                                var attribute = thisAttribs[ i ];
    730727
     728                                if ( attribute.nodeName == '_moz_dirty' )
     729                                        continue;
     730
    731731                                if ( ( !CKEDITOR.env.ie || ( attribute.specified && attribute.nodeName != 'data-cke-expando' ) ) && attribute.nodeValue != otherElement.getAttribute( attribute.nodeName ) )
    732732                                        return false;
    733733                        }
  • _source/plugins/specialchar/dialogs/specialchar.js

     
    1212        var dialog,
    1313                lang = editor.lang.specialChar;
    1414
    15         var insertSpecialChar = function ( specialChar )
    16         {
    17                 var selection = editor.getSelection(),
    18                         ranges = selection.getRanges( true ),
    19                         range, textNode;
    20 
    21                 editor.fire( 'saveSnapshot' );
    22 
    23                 for ( var i = ranges.length - 1; i >= 0 ; i-- )
    24                 {
    25                         range = ranges[ i ];
    26                         range.deleteContents();
    27 
    28                         textNode = CKEDITOR.dom.element.createFromHtml( specialChar );
    29                         range.insertNode( textNode );
    30                 }
    31 
    32                 if ( range )
    33                 {
    34                         range.moveToPosition( textNode, CKEDITOR.POSITION_AFTER_END );
    35                         range.select();
    36                 }
    37 
    38                 editor.fire( 'saveSnapshot' );
    39         };
    40 
    4115        var onChoice = function( evt )
    4216        {
    4317                var target, value;
     
    5125                        target.removeClass( "cke_light_background" );
    5226                        dialog.hide();
    5327
    54                         // Firefox has bug on insert chars into a element use its own API. (#5170)
    55                         if ( CKEDITOR.env.gecko )
    56                                 insertSpecialChar( value );
    57                         else
    58                                 editor.insertHtml( value );
     28                        editor.insertText( value );
    5929                }
    6030        };
    6131
  • _source/plugins/pastetext/plugin.js

     
    3737                }
    3838        };
    3939
    40         function doInsertText( doc, text )
    41         {
    42                 // Native text insertion.
    43                 if ( CKEDITOR.env.ie )
    44                 {
    45                         var selection = doc.selection;
    46                         if ( selection.type == 'Control' )
    47                                 selection.clear();
    48                         selection.createRange().pasteHTML( text );
    49                 }
    50                 else
    51                         doc.execCommand( 'inserthtml', false, text );
    52         }
    53 
    5440        // Register the plugin.
    5541        CKEDITOR.plugins.add( 'pastetext',
    5642        {
     
    8470                requires : [ 'clipboard' ]
    8571        });
    8672
    87         function doEnter( editor, mode, times, forceMode )
    88         {
    89                 while ( times-- )
    90                 {
    91                         CKEDITOR.plugins.enterkey[ mode == CKEDITOR.ENTER_BR ? 'enterBr' : 'enterBlock' ]
    92                                         ( editor, mode, null, forceMode );
    93                 }
    94         }
    95 
    96         CKEDITOR.editor.prototype.insertText = function( text )
    97         {
    98                 this.focus();
    99                 this.fire( 'saveSnapshot' );
    100 
    101                 var mode = this.getSelection().getStartElement().hasAscendant( 'pre', true ) ? CKEDITOR.ENTER_BR : this.config.enterMode,
    102                         isEnterBrMode = mode == CKEDITOR.ENTER_BR,
    103                         doc = this.document.$,
    104                         self = this,
    105                         line;
    106 
    107                 text = CKEDITOR.tools.htmlEncode( text.replace( /\r\n|\r/g, '\n' ) );
    108 
    109                 var startIndex = 0;
    110                 text.replace( /\n+/g, function( match, lastIndex )
    111                  {
    112                         line = text.substring( startIndex, lastIndex );
    113                         startIndex = lastIndex + match.length;
    114                         line.length && doInsertText( doc, line );
    115 
    116                         var lineBreakNums = match.length,
    117                                 // Duo consequence line-break as a enter block.
    118                                 enterBlockTimes = isEnterBrMode ? 0 : Math.floor( lineBreakNums / 2 ),
    119                                 // Per link-break as a enter br.
    120                                 enterBrTimes = isEnterBrMode ? lineBreakNums : lineBreakNums % 2;
    121 
    122                         // Line-breaks are converted to editor enter key strokes.
    123                         doEnter( self, mode, enterBlockTimes );
    124                         doEnter( self, CKEDITOR.ENTER_BR, enterBrTimes, isEnterBrMode ? false : true );
    125                  });
    126 
    127                 // Insert the last text line of text.
    128                 line = text.substring( startIndex, text.length );
    129                 line.length && doInsertText( doc, line );
    130 
    131                 this.fire( 'saveSnapshot' );
    132         };
    13373})();
    13474
    13575
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy