Ticket #5309: 5309_3.patch

File 5309_3.patch, 16.5 KB (added by Sa'ar Zac Elias, 10 years ago)

Align the outdated patch

  • _source/core/dom/element.js

     
    254254                },
    255255
    256256                /**
     257                 * Retrieve block element's filler node if existed.
     258                 */
     259                getBogus : function()
     260                {
     261                        if ( !this.isBlockBoundary() )
     262                                return;
     263
     264                        var lastChild = this.getLast() ;
     265
     266                        // Ignore empty/spaces text.
     267                        while ( lastChild && lastChild.type == CKEDITOR.NODE_TEXT && !CKEDITOR.tools.rtrim( lastChild.getText() ) )
     268                                lastChild = lastChild.getPrevious();
     269
     270                        if ( lastChild &&
     271                                ( CKEDITOR.env.ie && lastChild.type == CKEDITOR.NODE_TEXT && CKEDITOR.tools.trim( lastChild.getText() ).match( /^(?: |\xa0)$/ )
     272                                ||      CKEDITOR.env.gecko && CKEDITOR.env.webkit && lastChild.is( 'br' ) ) )
     273                        {
     274                                return lastChild;
     275                        }
     276                },
     277
     278                /**
    257279                 * Breaks one of the ancestor element in the element position, moving
    258280                 * this element between the broken parts.
    259281                 * @param {CKEDITOR.dom.element} parent The anscestor element to get broken.
  • _source/core/dom/range.js

     
    317317                return !whitespaceEval( node ) && !bookmarkEval( node );
    318318        }
    319319
     320
     321        function collectValidChildren( element, parentName )
     322        {
     323                var next = element, isValid,
     324                                candidates = [];
     325
     326                while ( ( next = next.getNextSourceNode( isValid, CKEDITOR.NODE_ELEMENT ) ) )
     327                {
     328                        if ( isValid = next.getName() in CKEDITOR.dtd[ parentName ] )
     329                                candidates.push( next );
     330                }
     331
     332                var fragment = new CKEDITOR.dom.documentFragment();
     333                for ( var i = 0, count = candidates.length; i < count; i++ )
     334                        fragment.append( candidates[ i ] );
     335                return fragment;
     336        }
     337
     338        var emptyspaces = CKEDITOR.dom.walker.whitespaces(),
     339                        bookmarks = CKEDITOR.dom.walker.bookmark();
     340
    320341        CKEDITOR.dom.range.prototype =
    321342        {
    322343                clone : function()
     
    671692                },
    672693
    673694                /**
     695                 * Paste the give HTML at the start of the range, and replacing any previously selected nodes within the range.
     696                 * Note: This method might alter the specified HTML to make it fit the given range context. For example, when pasting a table
     697                 * when actually a table row is selected (a DTD violation), instead of inserting the table, it results in only the cells of the table
     698                 * getting pasted into the row.
     699                 * For predictable results, paste only well-formed HTML that fits at the given range context.
     700                 * @param {String} html Valid HTML string to paste into the range.
     701                 */
     702                pasteHtml : function ( html )
     703                {
     704                        // Create a fragment of nodes without context that represents the structure to paste. (W3C Spec)
     705                        var fragment = CKEDITOR.htmlParser.fragment.fromHtml( html, false ),
     706                                        nodeList = fragment.children;
     707
     708                        if ( !this.collapsed )
     709                        {
     710                                // Avoid resulting in dummy element after the deletion.
     711                                this.enlarge( CKEDITOR.NODE_ELEMENT );
     712                                this.extractContents();
     713                        }
     714
     715                        // Split up text node at position.
     716                        if ( this.startContainer.type == CKEDITOR.NODE_TEXT )
     717                                this.trim();
     718
     719                        // If we're at end of block, remove any bogus node, because:
     720                        // 1. It's not needed any more due to the incomming content.
     721                        // 2. It will get doubled (visible) if the to be inserted node is a bogus too.
     722                        var block;
     723                        if ( block = this.checkEndOfBlock() )
     724                        {
     725                                var bogus = block.getBogus();
     726                                bogus && bogus.remove();
     727                        }
     728
     729                        var targetNode, targetNodeOffset, targetName, path,
     730                                updateTarget = CKEDITOR.tools.bind( function ()
     731                                {
     732                                        targetNode = this.startContainer,
     733                                                        targetNodeOffset = this.startOffset,
     734                                                        targetName = targetNode.getName();
     735                                        path = new CKEDITOR.dom.elementPath( targetNode );
     736                                }, this );
     737
     738                        updateTarget();
     739                        for ( var i = 0, count = nodeList.length; i < count; i++ )
     740                        {
     741                                var node = nodeList[ i ],
     742                                                nodeName = node.type == CKEDITOR.NODE_ELEMENT ? node.name : '#';
     743
     744                                // If  we have a list to insert, and we're actually standing inside a list item,
     745                                // insert the appropriate children instead, in short, merge the lists
     746                                // instead of pasting in a sublist.
     747                                if ( nodeName in  CKEDITOR.dtd.$list
     748                                        && path.block && path.block.getName() in CKEDITOR.dtd.$listItem )
     749                                {
     750                                        this.splitElement( path.block );
     751                                        updateTarget();
     752                                }
     753
     754                                // The to be inserted node fails DTD examination.
     755                                while ( !CKEDITOR.dtd[ targetName ][ nodeName ] )
     756                                {
     757                                        // If the failure is caused by pasting table/list inside a table/list
     758                                        // structure, instead of splitting up the element, just insert the
     759                                        // appropriate children.
     760                                        if ( nodeName == 'table' && targetName in { table:1, tfoot:1,thead:1,tbody:1,tr:1 }
     761                                                || nodeName in { ul:1, ol:1, dl:1 } && targetName in { ul:1, ol:1, dl:1 } )
     762                                        {
     763                                                node = collectValidChildren( node.toDom(), targetName );
     764                                                break;
     765                                        }
     766
     767                                        //  Users are more likely want to paste content intead of the element, e.g. pre, headings.
     768                                        if ( ( targetName == nodeName )
     769                                                && ( nodeName == 'pre' || nodeName.match( /^h[1-6]$/ ) ) )
     770                                        {
     771                                                Array.prototype.splice.apply( nodeList, [ i, 1 ].concat( node.children ) );
     772                                                node = nodeList[ i ];
     773                                                break;
     774                                        }
     775
     776                                        // Ok, it's our last option, split up or move out of current element.
     777                                        this.splitElement( targetNode );
     778                                        updateTarget();
     779                                }
     780
     781                                var domNode = node.$ ? node : node.toDom();
     782                                // Where to put the cursor?
     783                                var anchorNode = domNode.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT ?
     784                                                domNode.getLast() : domNode;
     785
     786                                this.insertNode( domNode );
     787
     788                                // Try to place cursor at the end of the last pasted node,
     789                                // with the only exception that we should discontinue any pasted link,
     790                                // If that fails, simply collapse by the end of  last node.
     791                                if ( !( i == count - 1 && anchorNode.type == CKEDITOR.NODE_ELEMENT
     792                                                && !anchorNode.is( 'a' ) && this.moveToElementEditEnd( anchorNode ) ) )
     793                                        this.collapse();
     794                        }
     795                },
     796
     797                /**
    674798                 * Transforms the startContainer and endContainer properties from text
    675799                 * nodes to element nodes, whenever possible. This is actually possible
    676800                 * if either of the boundary containers point to a text node, and its
     
    871995                                                {
    872996                                                        // If we reached the common ancestor, mark the flag
    873997                                                        // for it.
    874                                                         if ( !commonReached && enlargeable.equals( commonAncestor ) )
     998                                                        if ( !commonReached && ( enlargeable.contains( commonAncestor ) || enlargeable.equals( commonAncestor ) ) )
    875999                                                                commonReached = true;
    8761000
    8771001                                                        if ( !body.contains( enlargeable ) )
     
    10411165                                        {
    10421166                                                if ( enlargeable && !sibling )
    10431167                                                {
    1044                                                         if ( !commonReached && enlargeable.equals( commonAncestor ) )
     1168                                                        if ( !commonReached && ( enlargeable.contains( commonAncestor ) || enlargeable.equals( commonAncestor ) ) )
    10451169                                                                commonReached = true;
    10461170
    10471171                                                        if ( !body.contains( enlargeable ) )
     
    13541478                        var startContainer = this.startContainer;
    13551479                        var startOffset = this.startOffset;
    13561480
     1481                        var count = node.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT ?
     1482                                node.getChildren().count() : 1;
     1483
     1484                        var anchorNode = node.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT ?
     1485                                node.getChildren().getItem( 0 ) : node;
     1486
    13571487                        var nextNode = startContainer.getChild( startOffset );
    13581488
    13591489                        if ( nextNode )
     
    13621492                                startContainer.append( node );
    13631493
    13641494                        // Check if we need to update the end boundary.
    1365                         if ( node.getParent().equals( this.endContainer ) )
    1366                                 this.endOffset++;
     1495                        if ( startContainer.equals( this.endContainer ) )
     1496                                this.endOffset += count;
    13671497
    13681498                        // Expand the range to embrace the new node.
    1369                         this.setStartBefore( node );
     1499                        this.setStartBefore( anchorNode );
    13701500                },
    13711501
    13721502                moveToPosition : function( node, position )
     
    16211751                        if ( !this.collapsed )
    16221752                                return null;
    16231753
     1754                        var testRange = this.clone(),
     1755                                        walker = new CKEDITOR.dom.walker( testRange );
     1756
     1757                        walker.evaluator = function( node )
     1758                        {
     1759                                return !!( emptyspaces( node ) || bookmarks( node ) );
     1760                        };
     1761
     1762                        testRange.setEndAfter( toSplit );
     1763                        if ( walker.checkForward() )
     1764                        {
     1765                                this.moveToPosition( toSplit, CKEDITOR.POSITION_AFTER_END );
     1766                                return null;
     1767                        }
     1768                        else
     1769                        {
     1770                                testRange = this.clone();
     1771                                testRange.setStartBefore( toSplit );
     1772                                walker.reset();
     1773                                walker.range = testRange;
     1774                                if ( walker.checkBackward() )
     1775                                {
     1776                                        this.moveToPosition( toSplit, CKEDITOR.POSITION_BEFORE_START );
     1777                                        return null;
     1778                                }
     1779                        }
     1780                               
    16241781                        // Extract the contents of the block from the selection point to the end
    16251782                        // of its contents.
    16261783                        this.setEndAt( toSplit, CKEDITOR.POSITION_BEFORE_END );
     
    17291886                        // Creates a range starting at the block start until the range start.
    17301887                        var walkerRange = this.clone();
    17311888                        walkerRange.collapse( false );
    1732                         walkerRange.setEndAt( path.block || path.blockLimit, CKEDITOR.POSITION_BEFORE_END );
     1889                        var pathBlock = path.block || path.blockLimit;
     1890                        walkerRange.setEndAt( pathBlock, CKEDITOR.POSITION_BEFORE_END );
    17331891
    17341892                        var walker = new CKEDITOR.dom.walker( walkerRange );
    17351893                        walker.evaluator = getCheckStartEndBlockEvalFunction( false );
    17361894
    1737                         return walker.checkForward();
     1895                        return walker.checkForward() && pathBlock;
    17381896                },
    17391897
    17401898                /**
  • _source/core/htmlparser/cdata.js

     
    3838                writeHtml : function( writer )
    3939                {
    4040                        writer.write( this.value );
     41                },
     42
     43                toDom : function( doc )
     44                {
     45                        return new CKEDITOR.dom.text( this.value, doc );
    4146                }
    4247        };
    4348})();
  • _source/core/htmlparser/comment.js

     
    5656                }
    5757
    5858                writer.comment( comment );
     59        },
     60
     61        toDom : function( doc )
     62        {
     63                return new CKEDITOR.dom.comment( this.value, doc );
    5964        }
     65
    6066};
  • _source/core/htmlparser/element.js

     
    235235                        // Send children.
    236236                        CKEDITOR.htmlParser.fragment.prototype.writeChildrenHtml.apply( this, arguments );
    237237
     238                },
     239
     240                toDom : function( doc )
     241                {
     242                        var element = new CKEDITOR.dom.element( this.name, doc );
     243                        element.setAttributes( this.attributes );
     244
     245                        for ( var i = 0, count = this.children.length; i < count; i++ )
     246                                element.append( this.children[ i ].toDom() );
     247
     248                        return element;
    238249                }
    239250        };
    240251})();
  • _source/core/htmlparser/fragment.js

     
    492492                {
    493493                        for ( var i = 0 ; i < this.children.length ; i++ )
    494494                                this.children[i].writeHtml( writer, filter );
     495                },
     496
     497                toDom : function( doc )
     498                {
     499                        var fragment = new CKEDITOR.dom.documentFragment( doc );
     500                        for ( var i = 0, count = this.children.length; i < count; i++ )
     501                                fragment.append( this.children[ i ].toDom( doc ) );
     502
     503                        return fragment;
    495504                }
    496505        };
    497506})();
  • _source/core/htmlparser/text.js

     
    5050                                return;
    5151
    5252                        writer.text( text );
     53                },
     54
     55                toDom : function( doc )
     56                {
     57                        // DON'T use CKEDITOR.dom.text, it's not handling entities..
     58                        return CKEDITOR.dom.element.createFromHtml( this.value );
    5359                }
    5460        };
    5561})();
  • _source/plugins/htmldataprocessor/plugin.js

     
    263263                defaultHtmlFilterRules.elements[ i ] = unprotectReadyOnly;
    264264        }
    265265
     266        // Disallow structural blocks without sub nodes.   
     267        var removeIfEmptyBlocks = { table:1, thead:1,tfoot:1,tbody:1, tr:1 },
     268                        removeIfEmptyFilterRules = { elements : {} },
     269                        removeIfEmtpyFilter = function( element ){ if ( !element.children.length ) return false; };
     270
     271        for ( i in removeIfEmptyBlocks )
     272                removeIfEmptyFilterRules.elements[ i ] = removeIfEmtpyFilter;
     273
    266274        var protectAttributeRegex = /<(?:a|area|img|input)[\s\S]*?\s((?:href|src|name)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+)))/gi;
    267275
    268276        var protectElementsRegex = /(?:<style(?=[ >])[^>]*>[\s\S]*<\/style>)|(?:<(:?link|meta|base)[^>]*>)/gi,
     
    389397
    390398                        dataProcessor.dataFilter.addRules( defaultDataFilterRules );
    391399                        dataProcessor.dataFilter.addRules( defaultDataBlockFilterRules );
     400                        dataProcessor.dataFilter.addRules( removeIfEmptyFilterRules );
    392401                        dataProcessor.htmlFilter.addRules( defaultHtmlFilterRules );
    393402                        dataProcessor.htmlFilter.addRules( defaultHtmlBlockFilterRules );
     403                        dataProcessor.htmlFilter.addRules( removeIfEmptyFilterRules );
    394404                }
    395405        });
    396406
  • _source/plugins/wysiwygarea/plugin.js

     
    3636                        if ( checkReadOnly( selection ) )
    3737                                return;
    3838
    39                         var data = evt.data;
     39                        var ranges = selection.getRanges( true ),
     40                                data = evt.data;
    4041                        this.fire( 'saveSnapshot' );
    4142
    4243                        if ( this.dataProcessor )
    4344                                data = this.dataProcessor.toHtml( data );
    4445
    45                         if ( CKEDITOR.env.ie )
     46                        // Process the ranges counter-clockwise to avoid any impacts among them.
     47                        for ( var i = ranges.length - 1 ; i >= 0 ; i-- )
    4648                        {
    47                                 var selIsLocked = selection.isLocked;
     49                                var range = ranges[ i ],
     50                                        previousRange = ranges[ i - 1 ];
    4851
    49                                 if ( selIsLocked )
    50                                         selection.unlock();
    51 
    52                                 var $sel = selection.getNative();
    53 
    54                                 // Delete control selections to avoid IE bugs on pasteHTML.
    55                                 if ( $sel.type == 'Control' )
    56                                         $sel.clear();
    57                                 else if  ( selection.getType() == CKEDITOR.SELECTION_TEXT )
     52                                // Merge next sibling range when possible, it's not a common case,
     53                                // but necessary for situation like multiple table cell selection in Firefox.
     54                                if ( previousRange )
    5855                                {
    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.
    62 
    63                                         var range = selection.getRanges()[0],
    64                                                 endContainer = range && range.endContainer;
    65 
    66                                         if ( endContainer &&
    67                                                  endContainer.type == CKEDITOR.NODE_ELEMENT &&
    68                                                  endContainer.getAttribute( 'contenteditable' ) == 'false' &&
    69                                                  range.checkBoundaryOfElement( endContainer, CKEDITOR.END ) )
     56                                        if ( previousRange.endContainer.equals( range.startContainer )
     57                                                && previousRange.endOffset == range.startOffset )
    7058                                        {
    71                                                 range.setEndAfter( range.endContainer );
    72                                                 range.deleteContents();
     59                                                previousRange.endContainer = range.endContainer;
     60                                                previousRange.endOffset = range.endOffset;
     61                                                ranges.splice( i, 1 );
     62                                                continue;
    7363                                        }
    7464                                }
    7565
    76                                 $sel.createRange().pasteHTML( data );
    77 
    78                                 if ( selIsLocked )
    79                                         this.getSelection().lock();
     66                                // Pasting should only go into the first range.
     67                                if ( i == 0 )
     68                                        range.pasteHtml( data );
     69                                else
     70                                {
     71                                        range.enlarge( CKEDITOR.NODE_ELEMENT );
     72                                        // Drop the range after selected content is deleted.
     73                                        range.extractContents();
     74                                        ranges.length--;
     75                                }
    8076                        }
    81                         else
    82                                 this.document.$.execCommand( 'inserthtml', false, data );
    8377
    84                         // Webkit does not scroll to the cursor position after pasting (#5558)
    85                         if ( CKEDITOR.env.webkit )
    86                         {
    87                                 this.document.$.execCommand( 'inserthtml', false, '<span id="cke_paste_marker" cke_temp="1"></span>' );
    88                                 var marker = this.document.getById( 'cke_paste_marker' );
    89                                 marker.scrollIntoView();
    90                                 marker.remove();
    91                         }
     78                        selection.selectRanges( ranges );
     79                        !CKEDITOR.env.ie && selection.scrollIntoView();
    9280
    9381                        CKEDITOR.tools.setTimeout( function()
    9482                                {
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy