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(); |
| 575 | var siblings = parent.children, |
| 576 | child, |
| 577 | testRange = range.duplicate(), |
| 578 | startIndex = 0, endIndex = siblings.length - 1, index = -1, |
| 579 | position, |
| 580 | distance; |
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; |
598 | | } |
599 | | } |
| 589 | if ( position > 0 ) |
| 590 | endIndex = index - 1; |
| 591 | else if ( position < 0 ) |
| 592 | startIndex = index + 1; |
| 593 | else |
| 594 | return { container : parent, offset : getNodeIndex( child ) }; |
| 595 | } |
605 | | testRange.collapse( false ); |
606 | | } |
| 601 | testRange.setEndPoint( 'StartToStart', range ); |
| 602 | // IE report line break as CRLF with range.text but |
| 603 | // only LF with textnode.nodeValue, normalize them to avoid |
| 604 | // breaking character counting logic below. (#3949) |
| 605 | distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length; |
| 606 | siblings = parent.childNodes; |
| 607 | if ( !distance ) |
| 608 | { |
| 609 | child = siblings[ siblings.length - 1 ]; |
| 610 | return { container : child, offset : child.nodeValue.length }; |
| 611 | } |
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 | var i = siblings.length; |
| 614 | while ( distance > 0 ) |
| 615 | distance -= siblings[ --i ].nodeValue.length; |
| 616 | return { container : siblings[ i ], offset : -distance }; |
| 617 | } |
| 618 | // Test range far from the right OR left hand side of the actual range. |
| 619 | else |
| 620 | { |
| 621 | testRange.collapse( position > 0 ? true : false ); |
| 622 | testRange.setEndPoint( position > 0 ? 'StartToStart' : 'EndToStart', range ); |
| 623 | // IE report line break as CRLF with range.text but |
| 624 | // only LF with textnode.nodeValue, normalize them to avoid |
| 625 | // breaking character counting logic below. (#3949) |
| 626 | distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length; |
614 | | try |
615 | | { |
616 | | while ( distance > 0 ) |
617 | | distance -= siblings[ --i ].nodeValue.length; |
618 | | } |
619 | | // Measurement in IE could be somtimes wrong because of <select> element. (#4611) |
620 | | catch( e ) |
621 | | { |
622 | | distance = 0; |
623 | | } |
| 628 | if ( !distance ) |
| 629 | return { container : parent, offset : getNodeIndex( child ) + ( position > 0 ? -1 : 1 ) }; |
| 630 | |
| 631 | while ( distance > 0 ) |
| 632 | { |
| 633 | child = child[ position > 0 ? 'previousSibling' : 'nextSibling' ]; |
| 634 | try |
| 635 | { |
| 636 | distance -= child.nodeValue.length; |
| 637 | } |
| 638 | // Measurement in IE could be somtimes wrong because of <select> element. (#4611) |
| 639 | catch( e ) |
| 640 | { |
| 641 | return { container : parent, offset : getNodeIndex( child ) }; |
| 642 | } |
| 643 | } |