Ticket #3309: 3309_2.patch

File 3309_2.patch, 7.7 KB (added by Garry Yao, 10 years ago)
  • _source/core/dom/documentfragment.js

     
    4343                'getDocument' : 1,
    4444                'getChildCount' : 1,
    4545                'getChild' : 1,
    46                 'getChildren' : 1
     46                'getChildren' : 1,
     47                'type' : 1
    4748        } );
  • _source/plugins/styles/plugin.js

     
    510510                 */
    511511                range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
    512512
    513                 var bookmark = range.createBookmark( true ),
    514                         startNode = range.document.getById( bookmark.startNode );
     513                var bookmark = range.createBookmark(),
     514                        startNode = bookmark.startNode;
    515515
    516516                if ( range.collapsed )
    517517                {
    518                         /*
    519                          * If the range is collapsed, try to remove the style from all ancestor
    520                          * elements, until a block boundary is reached.
    521                          */
    522                         var startPath = new CKEDITOR.dom.elementPath( startNode.getParent() );
    523                         for ( var i = 0, element ; i < startPath.elements.length && ( element = startPath.elements[i] ) ; i++ )
    524                         {
     518                       
     519                        var startPath = new CKEDITOR.dom.elementPath( startNode.getParent() ),
     520                                // The topmost element in elementspatch which we should jump out of.
     521                                boundaryElement;
     522
     523
     524                        for ( var i = 0, element ; i < startPath.elements.length
     525                                        && ( element = startPath.elements[i] ) ; i++ )
     526                        {
     527                                /*
     528                                 * 1. If it's collaped inside text nodes, try to remove the style from the whole element.
     529                                 *
     530                                 * 2. Otherwise if it's collapsed on element boundaries, moving the selection
     531                                 *  outside the styles instead of removing the whole tag,
     532                                 *  also makre sure other inner styles were well preserverd.(#3309)
     533                                 */
    525534                                if ( element == startPath.block || element == startPath.blockLimit )
    526535                                        break;
    527536
    528537                                if ( this.checkElementRemovable( element ) )
    529538                                {
    530                                         /*
    531                                          * Before removing the style node, there may be a sibling to the style node
    532                                          * that's exactly the same to the one to be removed. To the user, it makes
    533                                          * no difference that they're separate entities in the DOM tree. So, merge
    534                                          * them before removal.
    535                                          */
    536                                         mergeSiblings( element );
    537                                         removeFromElement( this, element );
    538                                 }
    539                         }
    540                 }
    541                 else
     539                                        var startOfElement = range.checkBoundaryOfElement( element, CKEDITOR.START_OF_ELEMENT ),
     540                                                endOfElement = range.checkBoundaryOfElement( element, CKEDITOR.END_OF_ELEMENT );
     541                                        if ( startOfElement || endOfElement )
     542                                        {
     543                                                boundaryElement = element;
     544                                                boundaryElement.isStart = startOfElement;
     545                                        }
     546                                        else
     547                                        {
     548                                                /*
     549                                                 * Before removing the style node, there may be a sibling to the style node
     550                                                 * that's exactly the same to the one to be removed. To the user, it makes
     551                                                 * no difference that they're separate entities in the DOM tree. So, merge
     552                                                 * them before removal.
     553                                                 */
     554                                                mergeSiblings( element );
     555                                                removeFromElement( this, element );
     556
     557                                        }
     558                                }
     559                        }
     560
     561                        if ( boundaryElement )
     562                        {
     563                                // Range is guaranteed to be collapsed inside the inner-most inline element,
     564                                // so simply start from a cloned range.
     565                                var newStyleRange = range.clone();
     566
     567                                // Include it in the new range.
     568                                newStyleRange[ boundaryElement.isStart ?
     569                                  'setStartBefore' : 'setEndAfter'].call( newStyleRange, boundaryElement );
     570
     571                                var styleElements = newStyleRange.cloneContents();
     572
     573                                // We need build a temp node here for 'removeFromInsideElement'.
     574                                var temp = range.document.createElement( 'div' );
     575                                temp.append( styleElements );
     576                                removeFromInsideElement( this, temp );
     577
     578                                // It's guaranteed that style elements is single rooted.
     579                                styleElements = temp.getFirst();
     580
     581                                // Start from the new position right before/after the topmost target style element.
     582                                newStyleRange.collapse( boundaryElement.isStart ? true : false );
     583
     584                                // Continue with the inner styles.
     585                                if ( styleElements )
     586                                {
     587                                        newStyleRange.insertNode( styleElements );
     588                                        mergeSiblings( styleElements );
     589                                        // Destroy the bookmark node.
     590                                        startNode.remove();
     591                                        range.moveToElementEditStart( styleElements );
     592                                        return;
     593                                }
     594                                else
     595                                        // No inner styles found, simply jump out of boundary element.
     596                                        newStyleRange.insertNode( bookmark.startNode );
     597                        }
     598                }
     599                else
    542600                {
    543601                        /*
    544602                         * Now our range isn't collapsed. Lets walk from the start node to the end
  • _source/core/dom/range.js

     
    135135
    136136                        while( currentNode )
    137137                        {
     138                                // Avoid cloning bookmark nodes.
     139                                if ( action == 2 &&
     140                                     currentNode.hasAttribute && currentNode.hasAttribute( '_fck_bookmark' ) )
     141                                {
     142                                        currentNode = currentSibling;
     143                                        continue;
     144                                }
    138145                                // Stop processing when the current node matches a node in the
    139146                                // endParents tree or if it is the endNode.
    140147                                if ( currentNode.equals( endParents[ j ] ) || currentNode.equals( endNode ) )
     
    182189
    183190                                while( currentNode )
    184191                                {
     192                                        // Avoid cloning bookmark nodes.
     193                                        if ( action == 2 &&
     194                                             currentNode.hasAttribute && currentNode.hasAttribute( '_fck_bookmark' ) )
     195                                        {
     196                                                currentNode = currentSibling;
     197                                                continue;
     198                                        }
    185199                                        // Stop processing when the current node matches a node in the
    186200                                        // startParents tree or if it is the startNode.
    187201                                        if ( currentNode.equals( startParents[ k ] ) || currentNode.equals( startNode ) )
     
    292306                };
    293307        }
    294308
     309        // Evaluator for CKEDITOR.dom.element::checkBoundaryOfElement, reject all text type node,
     310        // while ignore bookmark node inner text.
     311        function elementBoundaryEval( node )
     312        {
     313                // Reject any text node unless it's being bookmark.
     314                return node.type != CKEDITOR.NODE_TEXT || node.getParent().hasAttribute( '_fck_bookmark' );
     315        };
     316
    295317        CKEDITOR.dom.range.prototype =
    296318        {
    297319                clone : function()
     
    14271449                        };
    14281450                },
    14291451
     1452                /**
     1453                 * Whether range is on the boundary of an element node.
     1454                 * @param {Number} checkType ( CKEDITOR.START_OF_ELEMENT|CKEDITOR.END_OF_ELEMENT)
     1455                 *  Specify check the range is at the start OR end of the element.
     1456                 */
     1457                checkBoundaryOfElement : function( element, checkType )
     1458                {
     1459                        var matched = false;
     1460                        var walkerRange = this.clone();
     1461                        // Expand the range clockwise.
     1462                        walkerRange[ checkType == CKEDITOR.START_OF_ELEMENT ?
     1463                                'setStartBefore' : 'setEndAfter'].call(
     1464                                        walkerRange, this.document.getBody() );
     1465                        var walker = new CKEDITOR.dom.walker( walkerRange ),
     1466                                retval = false;
     1467                        walker.evaluator = elementBoundaryEval;
     1468                        // Try to match among all the found boundary elements.
     1469                        walker.guard = function( node )
     1470                        {
     1471                                if ( node.type == CKEDITOR.NODE_ELEMENT && element.equals( node ) )
     1472                                        matched = true;
     1473                        };
     1474
     1475                        walker[ checkType == CKEDITOR.START_OF_ELEMENT ?
     1476                                'checkBackward' : 'checkForward' ].call( walker );
     1477                        return matched;
     1478                },
     1479
    14301480                // Calls to this function may produce changes to the DOM. The range may
    14311481                // be updated to reflect such changes.
    14321482                checkStartOfBlock : function()
     
    15531603CKEDITOR.ENLARGE_ELEMENT = 1;
    15541604CKEDITOR.ENLARGE_BLOCK_CONTENTS = 2;
    15551605CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS = 3;
     1606
     1607/**
     1608 * Check boundary types.
     1609 * @see CKEDITOR.dom.range::checkBoundaryOfElement
     1610 */
     1611CKEDITOR.START_OF_ELEMENT = 1;
     1612CKEDITOR.END_OF_ELEMENT = 2;
     1613CKEDITOR.STARTEND_OF_ELEMENT = 3;
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy