Ticket #3309: 3309.patch

File 3309.patch, 6.3 KB (added by Garry Yao, 11 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

     
    516516                 */
    517517                range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
    518518
    519                 var bookmark = range.createBookmark( true ),
    520                         startNode = range.document.getById( bookmark.startNode );
     519                var bookmark = range.createBookmark(),
     520                        startNode = bookmark.startNode;
    521521
    522522                if ( range.collapsed )
    523523                {
     
    531531                                if ( element == startPath.block || element == startPath.blockLimit )
    532532                                        break;
    533533
    534                                 if ( this.checkElementRemovable( element ) )
     534                                var newStyleRange,
     535                                        startOfElement = range.checkBoundaryOfElement( CKEDITOR.START_OF_ELEMENT ),
     536                                        endOfElement = range.checkBoundaryOfElement( CKEDITOR.END_OF_ELEMENT );
     537                                // Moving the selection outside the styles instead of remove the whole tag.(#3309)
     538                                if ( startOfElement || endOfElement )
     539                                {
     540                                        // Range is guaranteed to be collapsed inside the inner-most inline element,
     541                                        // so simply start from a cloned range.
     542                                        if( !newStyleRange )
     543                                                newStyleRange = range.clone();
     544                                        // Include the to-be-removed elements.
     545                                        if ( this.checkElementRemovable( element ) )
     546                                                newStyleRange[ startOfElement ?
     547                                                  'setStartBefore' : 'setEndAfter'].call( newStyleRange, element );
     548                                }
     549                                else if ( this.checkElementRemovable( element ) )
    535550                                {
    536551                                        /*
    537552                                         * Before removing the style node, there may be a sibling to the style node
     
    543558                                        removeFromElement( this, element );
    544559                                }
    545560                        }
    546                 }
     561                        // Indicate target style found when we're on the element boundaries,
     562                        // so move selection out of the style with inner style preserverd.
     563                        if ( newStyleRange && !newStyleRange.collapsed )
     564                        {
     565                                var styleElements = newStyleRange.cloneContents();
     566
     567                                // We need build a temp node here for 'removeFromInsideElement'.
     568                                var temp = range.document.createElement( 'div' );
     569                                temp.append( styleElements );
     570                                removeFromInsideElement( this, temp );
     571
     572                                // It's guaranteed that style elements is single rooted.
     573                                styleElements = temp.getFirst();
     574
     575                                // Start from the new position right before/after the topmost target style element.
     576                                newStyleRange.collapse( startOfElement ? true : false );
     577
     578                                // Continue with the inner styles.
     579                                if ( styleElements )
     580                                {
     581                                        newStyleRange.insertNode( styleElements );
     582                                        mergeSiblings( styleElements );
     583                                        // Destroy the bookmark node.
     584                                        startNode.remove();
     585                                        range.moveToElementEditStart( styleElements );
     586                                        return;
     587                                }
     588                                else    // No inner styles found.
     589                                        // Simply jump out of the target style element.
     590                                        newStyleRange.insertNode( bookmark.startNode );
     591                        }
     592                }
    547593                else
    548594                {
    549595                        /*
  • _source/core/dom/range.js

     
    133133
    134134                        while( currentNode )
    135135                        {
     136                                // Avoid cloning bookmark nodes.
     137                                if ( action == 2 &&
     138                                     currentNode.hasAttribute && currentNode.hasAttribute( '_fck_bookmark' ) )
     139                                {
     140                                        currentNode = currentSibling;
     141                                        continue;
     142                                }
    136143                                // Stop processing when the current node matches a node in the
    137144                                // endParents tree or if it is the endNode.
    138145                                if ( currentNode.equals( endParents[ j ] ) || currentNode.equals( endNode ) )
     
    180187
    181188                                while( currentNode )
    182189                                {
     190                                        // Avoid cloning bookmark nodes.
     191                                        if ( action == 2 &&
     192                                             currentNode.hasAttribute && currentNode.hasAttribute( '_fck_bookmark' ) )
     193                                        {
     194                                                currentNode = currentSibling;
     195                                                continue;
     196                                        }
    183197                                        // Stop processing when the current node matches a node in the
    184198                                        // startParents tree or if it is the startNode.
    185199                                        if ( currentNode.equals( startParents[ k ] ) || currentNode.equals( startNode ) )
     
    290304                };
    291305        }
    292306
     307        // Evaluator for CKEDITOR.dom.element::checkBoundaryOfElement.
     308        function elementBoundaryEval( node )
     309        {
     310                // Reject any text node unless it's being bookmark.
     311                return node.type != CKEDITOR.NODE_TEXT || node.getParent().hasAttribute( '_fck_bookmark' );
     312        };
     313        // Guard for CKEDITOR.dom.element::checkBoundaryOfElement.
     314        function elementBoundaryGuard( node )
     315        {
     316                return !node.type == CKEDITOR.NODE_ELEMENT ||
     317                           ( node.hasAttribute && node.hasAttribute( '_fck_bookmark') );
     318        };
     319
    293320        CKEDITOR.dom.range.prototype =
    294321        {
    295322                clone : function()
     
    13981425                        };
    13991426                },
    14001427
     1428                /**
     1429                 * Whether range is on the boundary of an element node.
     1430                 * @param {Number} checkType ( CKEDITOR.START_OF_ELEMENT|CKEDITOR.END_OF_ELEMENT)
     1431                 *  Specify check the range is at the start OR end of the element.
     1432                 */
     1433                checkBoundaryOfElement : function( checkType )
     1434                {
     1435                        var walkerRange = this.clone();
     1436                        // Expand the range clockwise.
     1437                        walkerRange[ checkType == CKEDITOR.START_OF_ELEMENT ?
     1438                                'setStartBefore' : 'setEndAfter'].call(
     1439                                        walkerRange, this.document.getBody() );
     1440                        var walker = new CKEDITOR.dom.walker( walkerRange ),
     1441                                retval = false;
     1442                        walker.evaluator = elementBoundaryEval;
     1443                        walker.guard = elementBoundaryGuard;
     1444                        return checkType == CKEDITOR.START_OF_ELEMENT ?
     1445                                walker.checkBackward() : walker.checkForward();
     1446                },
     1447
    14011448                // Calls to this function may produce changes to the DOM. The range may
    14021449                // be updated to reflect such changes.
    14031450                checkStartOfBlock : function()
     
    15241571CKEDITOR.ENLARGE_ELEMENT = 1;
    15251572CKEDITOR.ENLARGE_BLOCK_CONTENTS = 2;
    15261573CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS = 3;
     1574
     1575/**
     1576 * Check boundary types.
     1577 * @see CKEDITOR.dom.range::checkBoundaryOfElement
     1578 */
     1579CKEDITOR.START_OF_ELEMENT = 1;
     1580CKEDITOR.END_OF_ELEMENT = 2;
     1581CKEDITOR.STARTEND_OF_ELEMENT = 3;
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy