Changeset 6337


Ignore:
Timestamp:
01/19/11 09:01:12 (3 years ago)
Author:
garry.yao
Message:

#6438: Binary search algorithm boost the performance of range measurement of IE.

Location:
CKEditor/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • CKEditor/trunk/CHANGES.html

    r6334 r6337  
    9999                <li><a href="http://dev.ckeditor.com/ticket/6728">#6728</a> :  [BIDI] Change direction doesn't work with list nested inside blockquote.</li> 
    100100                <li><a href="http://dev.ckeditor.com/ticket/6432">#6432</a> :  Insert table over fully selected list result in JavaScript error.</li> 
     101                <li><a href="http://dev.ckeditor.com/ticket/6438">#6438</a> :  [IE] Performance enhancement when typing inside an element with many child nodes.</li> 
    101102                <li>Updated the following language files:<ul> 
    102103                        <li><a href="http://dev.ckeditor.com/ticket/6981">#6981</a> : English (GB);</li> 
  • CKEditor/trunk/_source/plugins/selection/plugin.js

    r6313 r6337  
    557557                                ( function() 
    558558                                { 
     559                                        function getNodeIndex( node ) { return new CKEDITOR.dom.node( node ).getIndex(); } 
     560 
    559561                                        // Finds the container and offset for a specific boundary 
    560562                                        // of an IE range. 
     
    567569                                                // Gets the element that encloses the range entirely. 
    568570                                                var parent = range.parentElement(); 
    569                                                 var siblings = parent.childNodes; 
    570  
    571                                                 var testRange; 
    572  
    573                                                 for ( var i = 0 ; i < siblings.length ; i++ ) 
    574                                                 { 
    575                                                         var child = siblings[ i ]; 
    576                                                         if ( child.nodeType == 1 ) 
    577                                                         { 
    578                                                                 testRange = range.duplicate(); 
    579  
    580                                                                 testRange.moveToElementText( child ); 
    581  
    582                                                                 var comparisonStart = testRange.compareEndPoints( 'StartToStart', range ), 
    583                                                                         comparisonEnd = testRange.compareEndPoints( 'EndToStart', range ); 
    584  
    585                                                                 testRange.collapse(); 
    586  
    587                                                                 if ( comparisonStart > 0 ) 
    588                                                                         break; 
    589                                                                 // When selection stay at the side of certain self-closing elements, e.g. BR, 
    590                                                                 // our comparison will never shows an equality. (#4824) 
    591                                                                 else if ( !comparisonStart 
    592                                                                         || comparisonEnd == 1 && comparisonStart == -1 ) 
    593                                                                         return { container : parent, offset : i }; 
    594                                                                 else if ( !comparisonEnd ) 
    595                                                                         return { container : parent, offset : i + 1 }; 
    596  
    597                                                                 testRange = null; 
     571 
     572                                                // Empty parent element, e.g. <i>^</i> 
     573                                                if ( !parent.hasChildNodes() ) 
     574                                                        return  { container : parent, offset : 0 }; 
     575 
     576                                                var siblings = parent.children, 
     577                                                        child, 
     578                                                        testRange = range.duplicate(), 
     579                                                        startIndex = 0, 
     580                                                        endIndex = siblings.length - 1, 
     581                                                        index = -1, 
     582                                                        position, 
     583                                                        distance; 
     584 
     585                                                // Binary search over all element childs to test the range to see whether 
     586                                                // range is right on the boundary of one element. 
     587                                                while ( startIndex <= endIndex ) 
     588                                                { 
     589                                                        index = Math.floor( ( startIndex + endIndex ) / 2 ); 
     590                                                        child = siblings[ index ]; 
     591                                                        testRange.moveToElementText( child ); 
     592                                                        position = testRange.compareEndPoints( 'StartToStart', range ); 
     593 
     594                                                        if ( position > 0 ) 
     595                                                                endIndex = index - 1; 
     596                                                        else if ( position < 0 ) 
     597                                                                startIndex = index + 1; 
     598                                                        else 
     599                                                                return { container : parent, offset : getNodeIndex( child ) }; 
     600                                                } 
     601 
     602                                                // All childs are text nodes. 
     603                                                if ( index == -1 ) 
     604                                                { 
     605                                                        // Adapt test range to embrace the entire parent contents. 
     606                                                        testRange.moveToElementText( parent ); 
     607                                                        testRange.setEndPoint( 'StartToStart', range ); 
     608 
     609                                                        // IE report line break as CRLF with range.text but 
     610                                                        // only LF with textnode.nodeValue, normalize them to avoid 
     611                                                        // breaking character counting logic below. (#3949) 
     612                                                        distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length; 
     613 
     614                                                        siblings = parent.childNodes; 
     615 
     616                                                        // Actual range anchor right beside test range at the inner boundary of text node. 
     617                                                        if ( !distance ) 
     618                                                        { 
     619                                                                child = siblings[ siblings.length - 1 ]; 
     620                                                                return  { container : child, offset : child.nodeValue.length }; 
    598621                                                        } 
    599                                                 } 
    600  
    601                                                 if ( !testRange ) 
    602                                                 { 
    603                                                         testRange = range.duplicate(); 
    604                                                         testRange.moveToElementText( parent ); 
    605                                                         testRange.collapse( false ); 
    606                                                 } 
    607  
    608                                                 testRange.setEndPoint( 'StartToStart', range ); 
    609                                                 // IE report line break as CRLF with range.text but 
    610                                                 // only LF with textnode.nodeValue, normalize them to avoid 
    611                                                 // breaking character counting logic below. (#3949) 
    612                                                 var distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length; 
    613  
    614                                                 try 
    615                                                 { 
     622 
     623                                                        // Start the measuring until distance overflows, meanwhile count the text nodes. 
     624                                                        var i = siblings.length; 
    616625                                                        while ( distance > 0 ) 
    617626                                                                distance -= siblings[ --i ].nodeValue.length; 
     627 
     628                                                        return  { container : siblings[ i ], offset : -distance }; 
    618629                                                } 
    619                                                 // Measurement in IE could be somtimes wrong because of <select> element. (#4611) 
    620                                                 catch( e ) 
    621                                                 { 
    622                                                         distance = 0; 
    623                                                 } 
    624  
    625  
    626                                                 if ( distance === 0 ) 
    627                                                 { 
    628                                                         return { 
    629                                                                 container : parent, 
    630                                                                 offset : i 
    631                                                         }; 
    632                                                 } 
     630                                                // Test range was one offset beyond OR behind the anchored text node. 
    633631                                                else 
    634632                                                { 
    635                                                         return { 
    636                                                                 container : siblings[ i ], 
    637                                                                 offset : -distance 
    638                                                         }; 
     633                                                        // Adapt one side of test range to the actual range 
     634                                                        // for measuring the offset between them. 
     635                                                        testRange.collapse( position > 0 ? true : false ); 
     636                                                        testRange.setEndPoint( position > 0 ? 'StartToStart' : 'EndToStart', range ); 
     637 
     638                                                        // IE report line break as CRLF with range.text but 
     639                                                        // only LF with textnode.nodeValue, normalize them to avoid 
     640                                                        // breaking character counting logic below. (#3949) 
     641                                                        distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length; 
     642 
     643                                                        // Actual range anchor right beside test range at the inner boundary of text node. 
     644                                                        if ( !distance ) 
     645                                                                return { container : parent, offset : getNodeIndex( child ) + ( position > 0 ? -1 : 1 ) }; 
     646 
     647                                                        // Start the measuring until distance overflows, meanwhile count the text nodes. 
     648                                                        while ( distance > 0 ) 
     649                                                        { 
     650                                                                child = child[ position > 0 ? 'previousSibling' : 'nextSibling' ]; 
     651                                                                try 
     652                                                                { 
     653                                                                        distance -= child.nodeValue.length; 
     654                                                                } 
     655                                                                // Measurement in IE could be somtimes wrong because of <select> element. (#4611) 
     656                                                                catch( e ) 
     657                                                                { 
     658                                                                        return { container : parent, offset : getNodeIndex( child ) }; 
     659                                                                } 
     660                                                        } 
     661 
     662                                                        return { container : child, offset : position > 0 ? -distance : child.nodeValue.length + distance }; 
    639663                                                } 
    640664                                        }; 
Note: See TracChangeset for help on using the changeset viewer.
© 2003 – 2012 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy