Ticket #3309: 3309_3.patch

File 3309_3.patch, 9.3 KB (added by Garry Yao, 10 years ago)
  • _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 make 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 endOfElement = range.checkBoundaryOfElement( element, CKEDITOR.END ),
     540                                                        startOfElement = !endOfElement && range.checkBoundaryOfElement( element, CKEDITOR.START );
     541                                        if ( startOfElement || endOfElement )
     542                                        {
     543                                                boundaryElement = element;
     544                                                boundaryElement.match = startOfElement ? 'start' : 'end';
     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                        // Re-create the style tree after/before the boundary element,
     562                        // the replication start from bookmark start node to define the
     563                        // new range.
     564                        if ( boundaryElement )
     565                        {
     566                                var clonedElement = startNode;
     567                                for ( var i = 0 ;; i++ )
     568                                {
     569                                        var newElement = startPath.elements[ i ];
     570                                        if ( newElement.equals( boundaryElement ) )
     571                                                break;
     572                                        // Avoid copying any removable style element.
     573                                        else if( newElement.match )
     574                                                continue;
     575                                        else
     576                                                newElement = newElement.clone();
     577                                        newElement.append( clonedElement );
     578                                        clonedElement = newElement;
     579                                }
     580                                clonedElement[ boundaryElement.match == 'start' ?
     581                                                        'insertBefore' : 'insertAfter' ]( boundaryElement );
     582                        }
     583                }
     584                else
    542585                {
    543586                        /*
    544587                         * Now our range isn't collapsed. Lets walk from the start node to the end
  • _source/core/dom/range.js

     
    296296                };
    297297        }
    298298
     299        // Evaluator for CKEDITOR.dom.element::checkBoundaryOfElement, reject any
     300        // text node and non-empty elements unless it's being bookmark text.
     301        function elementBoundaryEval( node )
     302        {
     303                // Reject any text node unless it's being bookmark.
     304                return node.type != CKEDITOR.NODE_TEXT
     305                       && node.getName() in CKEDITOR.dtd.$removeEmpty
     306                           || node.getParent().hasAttribute( '_fck_bookmark' );
     307        };
     308
    299309        CKEDITOR.dom.range.prototype =
    300310        {
    301311                clone : function()
     
    14671477                        };
    14681478                },
    14691479
     1480                /**
     1481                 * Check whether current range is on the inner edge of the specified element.
     1482                 * @param {Number} checkType ( CKEDITOR.START | CKEDITOR.END ) The checking side.
     1483                 * @param {CKEDITOR.dom.element} element The target element to check.
     1484                 */
     1485                checkBoundaryOfElement : function( element, checkType )
     1486                {
     1487                        var walkerRange = this.clone();
     1488                        // Expand the range to element boundary.
     1489                        walkerRange[ checkType == CKEDITOR.START ?
     1490                         'setStartAt' : 'setEndAt' ]
     1491                         ( element, checkType == CKEDITOR.START ?
     1492                           CKEDITOR.POSITION_AFTER_START
     1493                           : CKEDITOR.POSITION_BEFORE_END );
     1494
     1495                        var walker = new CKEDITOR.dom.walker( walkerRange ),
     1496                         retval = false;
     1497                        walker.evaluator = elementBoundaryEval;
     1498                        return walker[ checkType == CKEDITOR.START ?
     1499                                'checkBackward' : 'checkForward' ]();
     1500                },
    14701501                // Calls to this function may produce changes to the DOM. The range may
    14711502                // be updated to reflect such changes.
    14721503                checkStartOfBlock : function()
     
    15931624CKEDITOR.ENLARGE_ELEMENT = 1;
    15941625CKEDITOR.ENLARGE_BLOCK_CONTENTS = 2;
    15951626CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS = 3;
     1627
     1628/**
     1629 * Check boundary types.
     1630 * @see CKEDITOR.dom.range::checkBoundaryOfElement
     1631 */
     1632CKEDITOR.START = 1;
     1633CKEDITOR.END = 2;
     1634CKEDITOR.STARTEND = 3;
  • _source/tests/plugins/styles/styles.html

     
    336336
    337337                test_ticket_2040 : function()
    338338                {
    339                         doc.getById( '_P1' ).setHtml( 'This is some <strong>sample text<\/strong>. You are using <a href="http://www.fckeditor.net/">CKEditor<\/a>.' );
     339                        doc.getById( '_P1' ).setHtml( 'This is some <strong>sample text<\/strong>. You are using <a href="http://www.fckeditor.net/">ckeditor<\/a>.' );
    340340
    341341                        var range = new CKEDITOR.dom.range( doc );
    342342                        range.setStart( doc.getById( '_P1' ), 1 );
     
    345345                        var style = new CKEDITOR.style( { element : 'i' } );
    346346                        style.applyToRange( range );
    347347
    348                         assert.areSame( 'this is some <strong><i>sample</i> text<\/strong>. you are using <a href="http://www.fckeditor.net/">CKEditor<\/a>.', getInnerHtml( '_P1' ) );
     348                        assert.areSame( 'this is some <strong><i>sample</i> text<\/strong>. you are using <a href="http://www.fckeditor.net/">ckeditor<\/a>.', getInnerHtml( '_P1' ) );
    349349                },
    350350
    351351                test_checkElementRemovable1 : function()
     
    486486                        assert.areSame( '<p><i title="z">text</i></p><i title="z">outter</i>', getInnerHtml( element ) );
    487487                },
    488488
     489                // Remove inline style when range collapsed at element boundaries,
     490                // move out of the removing-style element, with inner style copied.
     491                test_ticket_3309 : function()
     492                {
     493                        var element = doc.getById( '_P1' );
     494                        element.setHtml( 'this is some <b><i id="_i1">styles</i></b> text' );
     495
     496                        // This is some <b><i>styles^</i></b> text
     497                        var range = new CKEDITOR.dom.range( doc );
     498                        range.setStartAt( doc.getById( '_i1' ), CKEDITOR.POSITION_BEFORE_END );
     499
     500                        var style = new CKEDITOR.style( { element : 'b' } );
     501                        style.removeFromRange( range );
     502
     503                        assert.areSame( 'this is some <b><i id="_i1">styles</i></b><i></i> text', getInnerHtml( element ) );
     504                },
     505
     506                // No inner style preserved, simply move out of the removing-style element.
     507                test_ticket_3309_2 : function()
     508                {
     509                        var element = doc.getById( '_P1' );
     510                        element.setHtml( 'this is some <b id="_b1">styles</b> text' );
     511
     512                        // This is some <b>styles^</b> text
     513                        var range = new CKEDITOR.dom.range( doc );
     514                        range.setStartAt( doc.getById( '_b1' ), CKEDITOR.POSITION_BEFORE_END );
     515
     516                        var style = new CKEDITOR.style( { element : 'b' } );
     517                        style.removeFromRange( range );
     518                        // This is some <b>styles</b>^ text
     519                        assert.areSame( doc.getById( '_b1' ).getParent().$, range.startContainer.$ );
     520                        assert.areSame( 2, range.startOffset );
     521                        assert.areSame( 'this is some <b id="_b1">styles</b> text', getInnerHtml( element ) );
     522                },
     523
     524                // With style overrides.
     525                test_ticket_3309_3 : function()
     526                {
     527                        var element = doc.getById( '_P1' );
     528                        element.setHtml( 'text <strong><bold><span><b><i id="_i1">styles</i></b></span></bold></strong>' );
     529
     530                        // text <strong><bold><span><b><i id="_i1">^styles</i></b></span></bold></strong>
     531                        var range = new CKEDITOR.dom.range( doc );
     532                        range.setStartAt( doc.getById( '_i1' ), CKEDITOR.POSITION_AFTER_START );
     533
     534                        var style = new CKEDITOR.style( { element : 'b' , overrides : [ 'strong', 'bold' ] } );
     535                        style.removeFromRange( range );
     536
     537                        // text <span><i>^</i></span><bold><span><b><i>styles</i></b></span></bold>
     538                        assert.areSame( 'text <span><i></i></span><strong><bold><span><b><i id="_i1">styles</i></b></span></bold></strong>', getInnerHtml( element ) );
     539                },
    489540                name : document.title
    490541        };
    491542})() );
    492 
     543//window.onload = testCase.test_ticket_3309_3;
    493544        //]]>
    494545        </script>
    495546</head>
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy