Ticket #2909: 2909_2.patch

File 2909_2.patch, 13.1 KB (added by Frederico Caldeira Knabben, 10 years ago)
  • _source/core/dom/document.js

     
    8787                        return $ ? new CKEDITOR.dom.element( $ ) : null;
    8888                },
    8989
     90                getByAddress : function( address, normalized )
     91                {
     92                        var $ = this.$.documentElement;
     93
     94                        for ( var i = 0 ; $ && i < address.length ; i++ )
     95                        {
     96                                var target = address[ i ];
     97
     98                                if ( !normalized )
     99                                {
     100                                        $ = $.childNodes[ target ];
     101                                        continue;
     102                                }
     103
     104                                var currentIndex = -1;
     105
     106                                for (var j = 0 ; j < $.childNodes.length ; j++ )
     107                                {
     108                                        var candidate = $.childNodes[ j ];
     109
     110                                        if ( normalized === true &&
     111                                                        candidate.nodeType == 3 &&
     112                                                        candidate.previousSibling &&
     113                                                        candidate.previousSibling.nodeType == 3 )
     114                                        {
     115                                                continue;
     116                                        }
     117
     118                                        currentIndex++;
     119
     120                                        if ( currentIndex == target )
     121                                        {
     122                                                $ = candidate;
     123                                                break;
     124                                        }
     125                                }
     126                        }
     127
     128                        return $ ? new CKEDITOR.dom.node( $ ) : null;
     129                },
     130
    90131                /**
    91132                 * Gets the &lt;head&gt; element for this document.
    92133                 * @returns {CKEDITOR.dom.element} The &lt;head&gt; element.
  • _source/core/dom/node.js

     
    149149                },
    150150
    151151                /**
     152                 * Retrieves a uniquely identifiable tree address for this node.
     153                 * The tree address returns is an array of integers, with each integer
     154                 * indicating a child index of a DOM node, starting from
     155                 * document.documentElement.
     156                 *
     157                 * For example, assuming <body> is the second child from <html> (<head>
     158                 * being the first), and we'd like to address the third child under the
     159                 * fourth child of body, the tree address returned would be:
     160                 * [1, 3, 2]
     161                 *
     162                 * The tree address cannot be used for finding back the DOM tree node once
     163                 * the DOM tree structure has been modified.
     164                 */
     165                getAddress : function( normalized )
     166                {
     167                        var address = [];
     168                        var $documentElement = this.getDocument().$.documentElement;
     169                        var node = this.$;
     170
     171                        while ( node && node != $documentElement )
     172                        {
     173                                var parentNode = node.parentNode;
     174                                var currentIndex = -1;
     175
     176                                for ( var i = 0 ; i < parentNode.childNodes.length ; i++ )
     177                                {
     178                                        var candidate = parentNode.childNodes[i];
     179
     180                                        if ( normalized &&
     181                                                        candidate.nodeType == 3 &&
     182                                                        candidate.previousSibling &&
     183                                                        candidate.previousSibling.nodeType == 3 )
     184                                        {
     185                                                continue;
     186                                        }
     187
     188                                        currentIndex++;
     189
     190                                        if ( candidate == node )
     191                                                break;
     192                                }
     193
     194                                address.unshift( currentIndex );
     195
     196                                node = node.parentNode;
     197                        }
     198
     199                        return address;
     200                },
     201
     202                /**
    152203                 * Gets a DOM tree descendant under the current node.
    153204                 * @param {Array|Number} indices The child index or array of child indices under the node.
    154205                 * @returns {CKEDITOR.dom.node} The specified DOM child under the current node. Null if child does not exist.
  • _source/core/dom/range.js

     
    409409                        };
    410410                },
    411411
     412                /**
     413                 * Creates a "non intrusive" and "mutation sensible" bookmark. This
     414                 * kind of bookmark should be used only when the DOM is supposed to
     415                 * remain stable after its creation.
     416                 * @param {Boolean} [normalized] Indicates that the bookmark must
     417                 *              normalized. When normalized, the successive text nodes are
     418                 *              considered a single node. To sucessful load a normalized
     419                 *              bookmark, the DOM tree must be also normalized before calling
     420                 *              moveToBookmark.
     421                 * @returns {Object} An object representing the bookmark.
     422                 */
     423                createBookmark2 : function( normalized )
     424                {
     425                        var startContainer      = this.startContainer,
     426                                endContainer    = this.endContainer;
     427
     428                        var startOffset = this.startOffset,
     429                                endOffset       = this.endOffset;
     430
     431                        var child, previous;
     432
     433                        // If there is no range then get out of here.
     434                        // It happens on initial load in Safari #962 and if the editor it's
     435                        // hidden also in Firefox
     436                        if ( !startContainer || !endContainer )
     437                                return { start : 0, end : 0 };
     438
     439                        if ( normalized )
     440                        {
     441                                // Find out if the start is pointing to a text node that will
     442                                // be normalized.
     443                                if ( startContainer.type == CKEDITOR.NODE_ELEMENT )
     444                                {
     445                                        var child = startContainer.getChild( startOffset );
     446
     447                                        // In this case, move the start information to that text
     448                                        // node.
     449                                        if ( child && child.type == CKEDITOR.NODE_TEXT && child.getPrevious().type == CKEDITOR.NODE_TEXT )
     450                                        {
     451                                                startContainer = child;
     452                                                startOffset = 0;
     453                                        }
     454                                }
     455
     456                                // Normalize the start.
     457                                while ( startContainer.type == CKEDITOR.NODE_TEXT
     458                                                && ( previous = startContainer.getPrevious() )
     459                                                && previous.type == CKEDITOR.NODE_TEXT )
     460                                {
     461                                        startContainer = previous;
     462                                        startOffset += previous.getLength();
     463                                }
     464
     465                                // Process the end only if not normalized.
     466                                if ( !this.isCollapsed )
     467                                {
     468                                        // Find out if the start is pointing to a text node that
     469                                        // will be normalized.
     470                                        if ( endContainer.type == CKEDITOR.NODE_ELEMENT )
     471                                        {
     472                                                child = endContainer.getChild( endOffset );
     473
     474                                                // In this case, move the start information to that
     475                                                // text node.
     476                                                if ( child && child.type == CKEDITOR.NODE_TEXT && child.getPrevious().type == CKEDITOR.NODE_TEXT )
     477                                                {
     478                                                        endContainer = child;
     479                                                        endOffset = 0;
     480                                                }
     481                                        }
     482
     483                                        // Normalize the end.
     484                                        while ( endContainer.type == CKEDITOR.NODE_TEXT
     485                                                        && ( previous = endContainer.getPrevious() )
     486                                                        && previous.type == CKEDITOR.NODE_TEXT )
     487                                        {
     488                                                endContainer = previous;
     489                                                endOffset += previous.getLength();
     490                                        }
     491                                }
     492                        }
     493
     494                        return {
     495                                start           : startContainer.getAddress( normalized ),
     496                                end                     : this.isCollapsed ? null : endContainer.getAddress( normalized ),
     497                                startOffset     : startOffset,
     498                                endOffset       : endOffset,
     499                                is2                     : true          // It's a createBookmark2 bookmark.
     500                        };
     501                },
     502
    412503                moveToBookmark : function( bookmark )
    413504                {
    414                         // Set the range start at the bookmark start node position.
    415                         this.setStartBefore( bookmark.startNode );
     505                        if ( bookmark.is2 )             // Created with createBookmark2().
     506                        {
     507                                // Get the start information.
     508                                var startContainer      = this.document.getByAddress( bookmark.start, true ),
     509                                        startOffset     = bookmark.startOffset;
    416510
    417                         // Remove it, because it may interfere in the setEndBefore call.
    418                         bookmark.startNode.remove();
     511                                // Get the end information.
     512                                var endContainer        = bookmark.end && this.document.getByAddress( bookmark.end, true ),
     513                                        endOffset       = bookmark.endOffset;
    419514
    420                         // Set the range end at the bookmark end node position, or simply
    421                         // collapse it if it is not available.
    422                         var endNode = bookmark.endNode;
    423                         if ( endNode )
     515                                // Set the start boundary.
     516                                this.setStart( startContainer, startOffset );
     517
     518                                // Set the end boundary. If not available, collapse it.
     519                                if ( endContainer )
     520                                        this.setEnd( endContainer, endOffset );
     521                                else
     522                                        this.collapse( true );
     523                        }
     524                        else                                    // Created with createBookmark().
    424525                        {
    425                                 this.setEndBefore( endNode );
    426                                 endNode.remove();
     526                                // Set the range start at the bookmark start node position.
     527                                this.setStartBefore( bookmark.startNode );
     528
     529                                // Remove it, because it may interfere in the setEndBefore call.
     530                                bookmark.startNode.remove();
     531
     532                                // Set the range end at the bookmark end node position, or simply
     533                                // collapse it if it is not available.
     534                                var endNode = bookmark.endNode;
     535                                if ( endNode )
     536                                {
     537                                        this.setEndBefore( endNode );
     538                                        endNode.remove();
     539                                }
     540                                else
     541                                        this.collapse( true );
    427542                        }
    428                         else
    429                                 this.collapse( true );
    430543                },
    431544
    432545                getBoundaryNodes : function()
  • _source/tests/core/dom/range.html

     
    1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    22<html xmlns="http://www.w3.org/1999/xhtml">
    33<head>
    44        <title>CKEDITOR.dom.range</title>
     
    1111        //<![CDATA[
    1212
    1313var html1, html2;
     14var tests;
    1415
    1516CKEDITOR.test.addTestCase( (function()
    1617{
     
    2021
    2122        var doc = new CKEDITOR.dom.document( document );
    2223
    23         return {
     24        return tests = {
    2425                test__constructor : function()
    2526                {
    2627                        var range = new CKEDITOR.dom.range( doc );
     
    15101511                        assert.isFalse( range.collapsed, 'range.collapsed' );
    15111512                },
    15121513
     1514                test_createBookmark2_1 : function()
     1515                {
     1516                        doc.getById( 'playground' ).setHtml( '<p id="P">This is <b id="B">a test</b></p>' );
     1517
     1518                        var range = new CKEDITOR.dom.range( doc );
     1519
     1520                        range.setStart( doc.getById( 'P' ), 0 );
     1521                        range.setEnd( doc.getById( 'B' ).getFirst(), 3 );
     1522
     1523                        var bookmark = range.createBookmark2();
     1524
     1525                        range = new CKEDITOR.dom.range( doc );
     1526                        range.moveToBookmark( bookmark );
     1527
     1528                        assert.areSame( document.getElementById('P'), range.startContainer.$, 'range.startContainer' );
     1529                        assert.areSame( 0, range.startOffset, 'range.startOffset' );
     1530                        assert.areSame( document.getElementById('B').firstChild, range.endContainer.$, 'range.endContainer' );
     1531                        assert.areSame( 3, range.endOffset, 'range.endOffset' );
     1532                        assert.isFalse( range.collapsed, 'range.collapsed' );
     1533                },
     1534
     1535                // This test is just like test_createBookmark2_3, but uses a "non
     1536                // normalized" bookmark.
     1537                test_createBookmark2_2 : function()
     1538                {
     1539                        var html = '<p id="P">A B <b>C </b>D E</p>';
     1540
     1541                        doc.getById( 'playground' ).setHtml( html );
     1542
     1543                        var p = doc.getById( 'P' );
     1544
     1545                        // Split the text nodes.
     1546                        p.getFirst().split( 2 );        // Right before "B"
     1547                        p.getChild( 3 ).split( 2 );     // Right before "E"
     1548
     1549                        assert.areSame( 5, p.getChildCount(), 'The number of nodes after split doesn\'t match' );
     1550
     1551                        var range = new CKEDITOR.dom.range( doc );
     1552
     1553                        // Create a range that enbraces "E".
     1554                        range.setStartBefore( p.getChild( 4 ) );
     1555                        range.setEndAfter( p.getChild( 4 ) );
     1556
     1557                        var bookmark = range.createBookmark2();
     1558
     1559                        range = new CKEDITOR.dom.range( doc );
     1560                        range.moveToBookmark( bookmark );
     1561
     1562                        assert.areSame( document.getElementById('P'), range.startContainer.$, 'range.startContainer' );
     1563                        assert.areSame( 4, range.startOffset, 'range.startOffset' );
     1564                        assert.areSame( document.getElementById('P'), range.endContainer.$, 'range.endContainer' );
     1565                        assert.areSame( 5, range.endOffset, 'range.endOffset' );
     1566                        assert.isFalse( range.collapsed, 'range.collapsed' );
     1567                },
     1568
     1569                test_createBookmark2_3 : function()
     1570                {
     1571                        var html = '<p id="P">A B <b>C </b>D E</p>';
     1572
     1573                        doc.getById( 'playground' ).setHtml( html );
     1574
     1575                        var p = doc.getById( 'P' );
     1576
     1577                        // Split the text nodes.
     1578                        p.getFirst().split( 2 );        // Right before "B"
     1579                        p.getChild( 3 ).split( 2 );     // Right before "E"
     1580
     1581                        assert.areSame( 5, p.getChildCount(), 'The number of nodes after split doesn\'t match' );
     1582
     1583                        var range = new CKEDITOR.dom.range( doc );
     1584
     1585                        // Create a range that enbraces "E".
     1586                        range.setStartBefore( p.getChild( 4 ) );
     1587                        range.setEndAfter( p.getChild( 4 ) );
     1588
     1589                        var bookmark = range.createBookmark2( true );
     1590
     1591                        // Normalize the contents.
     1592                        doc.getById( 'playground' ).setHtml( html );
     1593
     1594                        range = new CKEDITOR.dom.range( doc );
     1595                        range.moveToBookmark( bookmark );
     1596
     1597                        assert.areSame( document.getElementById('P').childNodes[2], range.startContainer.$, 'range.startContainer' );
     1598                        assert.areSame( 2, range.startOffset, 'range.startOffset' );
     1599                        assert.areSame( document.getElementById('P'), range.endContainer.$, 'range.endContainer' );
     1600
     1601                        // Note that the endOffset doesn't get normalized as it's not
     1602                        // needed. Any offset pointing over the container size is meant to
     1603                        // be at the end of it.
     1604                        assert.areSame( 5, range.endOffset, 'range.endOffset' );
     1605                        assert.isFalse( range.collapsed, 'range.collapsed' );
     1606                },
     1607
    15131608                /////////////
    15141609
    15151610                setUp : function()
     
    15241619
    15251620//window.onload = function()
    15261621//{
    1527 //      // Local references.
    1528 //      var assert                      = CKEDITOR.test.assert;
    1529 //      var getInnerHtml        = CKEDITOR.test.getInnerHtml;
    1530 
    1531 //      var doc = new CKEDITOR.dom.document( document );
    1532 
    1533 //                      doc.getById( '_EnlargeP' ).setHtml( 'this <i>is some </i>sample text' );
    1534 
    1535 //                      var range = new CKEDITOR.dom.range( doc );
    1536 //                      range.setStart( doc.getById( '_EnlargeP' ), 0 );
    1537 //                      range.setEnd( doc.getById( '_EnlargeP' ).getChild( 1 ), 0 );
    1538 
    1539 //                      range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
     1622//      tests.test_createBookmark2_3();
    15401623//}
    15411624
    15421625        //]]>
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy