| 54 | | this.EndNode = eEnd.nodeType == 3 ? eEnd : eEnd.childNodes[ innerRange.endOffset ] ; |
| | 54 | |
| | 55 | // The innerRange.endContainer[ innerRange.endOffset ] is not |
| | 56 | // usually part of the range, but the marker for the range end. So, |
| | 57 | // let's get the previous available node as the real end. |
| | 58 | var eEndNode = eEnd ; |
| | 59 | if ( innerRange.endOffset == 0 ) |
| | 60 | { |
| | 61 | while ( eEndNode && !eEndNode.previousSibling ) |
| | 62 | eEndNode = eEndNode.parentNode ; |
| | 63 | |
| | 64 | eEndNode = eEndNode.previousSibling ; |
| | 65 | } |
| | 66 | else if ( eEndNode.nodeType == 1 ) |
| | 67 | eEndNode = eEndNode.childNodes[ innerRange.endOffset - 1 ] ; |
| | 68 | |
| | 69 | this.EndNode = eEndNode ; |
| 589 | | |
| | 580 | |
| | 581 | // In EnterMode='br', the end <br> boundary element must |
| | 582 | // be included in the expanded range. |
| | 583 | if ( oNode && oNode.nodeName.toLowerCase() == 'br' ) |
| | 584 | this._Range.setEndAfter( oNode ) ; |
| | 585 | } |
| | 586 | |
| | 587 | this._UpdateElementInfo() ; |
| | 588 | break ; // @Packager.Remove.Start |
| | 589 | |
| | 590 | case 'list_contents' : |
| | 591 | // Get the start node for the current range. |
| | 592 | oNode = this._Range.startContainer ; |
| | 593 | |
| | 594 | // If it is an element, get the current child node for the range (in the offset). |
| | 595 | // If the offset node is not available, the the first one. |
| | 596 | if ( oNode.nodeType == 1 ) |
| | 597 | oNode = oNode.childNodes[ this._Range.startOffset ] || oNode.firstChild ; |
| | 598 | |
| | 599 | // We must look for the left boundary, relative to the range |
| | 600 | // start, which is limited by a block element. |
| | 601 | while ( oNode |
| | 602 | && ( oNode.nodeType != 1 |
| | 603 | || ( oNode != this.StartBlockLimit |
| | 604 | && !FCKListsLib.ListBoundaries[ oNode.nodeName.toLowerCase() ] ) ) ) |
| | 605 | { |
| | 606 | this._Range.setStartBefore( oNode ) ; |
| | 607 | |
| | 608 | if ( oNode == oNode.parentNode.firstChild && FCKListsLib.ListBoundaries[ oNode.parentNode.nodeName.toLowerCase() ] ) |
| | 609 | break ; |
| | 610 | |
| | 611 | oNode = FCKDomTools.GetPreviousSourceNode( oNode, true ) ; |
| | 612 | } |
| | 613 | |
| | 614 | oNode = this._Range.endContainer ; |
| | 615 | if ( oNode.nodeType == 1 ) |
| | 616 | oNode = oNode.childNodes[ this._Range.endOffset ] || oNode.lastChild ; |
| | 617 | |
| | 618 | // We must look for the right boundary, relative to the range |
| | 619 | // end, which is limited by a block element. |
| | 620 | while ( oNode |
| | 621 | && ( oNode.nodeType != 1 |
| | 622 | || ( oNode != this.StartBlockLimit |
| | 623 | && !FCKListsLib.ListBoundaries[ oNode.nodeName.toLowerCase() ] ) ) ) |
| | 624 | { |
| 727 | | return ( this._Range && true ) ; |
| 728 | | }, |
| 729 | | |
| 730 | | _CheckIsParagraphBoundary : function( node ) |
| 731 | | { |
| 732 | | if ( node.nodeType == 1 ) |
| 733 | | { |
| 734 | | var tagName = node.tagName.toLowerCase() ; |
| 735 | | return ! ( FCKListsLib.InlineNonEmptyElements[tagName] || tagName == 'img' ) ; |
| 736 | | } |
| 737 | | return false ; |
| 738 | | }, |
| 739 | | |
| 740 | | _GenerateParagraphRange : function( paragraphList, targetWindow, startNode, endNode ) |
| 741 | | { |
| 742 | | if ( ! startNode || ! endNode ) |
| 743 | | return ; |
| 744 | | var range = new FCKDomRange( targetWindow ) ; |
| 745 | | range._Range = new FCKW3CRange( targetWindow.document ) ; |
| 746 | | if ( startNode.nodeName.toLowerCase() == 'br' ) |
| 747 | | range._Range.setStartBefore( startNode ) ; |
| | 772 | return !!this._Range ; |
| | 773 | }, |
| | 774 | |
| | 775 | GetParagraphs : function( forceBreakBr ) |
| | 776 | { |
| | 777 | var retval = [] ; |
| | 778 | |
| | 779 | // Get and "expanded" clone of this range. |
| | 780 | var range = this.Clone() ; |
| | 781 | if ( forceBreakBr ) |
| | 782 | range.Expand( 'list_contents' ) ; |
| 749 | | range._Range.setStart( startNode, 0 ) ; |
| 750 | | if ( endNode.nodeName.toLowerCase() == 'br' ) |
| 751 | | range._Range.setEndBefore( endNode ) ; |
| 752 | | else |
| 753 | | range._Range.setEnd( endNode, endNode.nodeType == 1 ? endNode.childNodes.length : endNode.nodeValue.length ) ; |
| 754 | | range._UpdateElementInfo() ; |
| 755 | | paragraphList.push( range ) ; |
| 756 | | }, |
| 757 | | |
| 758 | | GetSelectedParagraphs : function() |
| 759 | | { |
| 760 | | this.MoveToSelection() ; |
| 761 | | |
| 762 | | var startNode = this._Range.startContainer ; |
| 763 | | var endNode = this._Range.endContainer ; |
| 764 | | var startOffset = this._Range.startOffset ; |
| 765 | | var endOffset = this._Range.endOffset ; |
| 766 | | if ( startNode.childNodes && startNode.childNodes[startOffset] ) |
| 767 | | startNode = startNode.childNodes[startOffset] ; |
| 768 | | if ( endNode.childNodes && endNode.childNodes[endOffset] ) |
| 769 | | endNode = endNode.childNodes[endOffset] ; |
| 770 | | |
| 771 | | // Get the starting point of the selection's paragraph. |
| 772 | | var paragraphStartNode = startNode ; |
| 773 | | while ( paragraphStartNode && ! this._CheckIsParagraphBoundary( paragraphStartNode ) ) |
| 774 | | { |
| 775 | | var candidate = null ; |
| 776 | | if ( paragraphStartNode.previousSibling ) |
| 777 | | { |
| 778 | | if ( ! this._CheckIsParagraphBoundary( paragraphStartNode.previousSibling ) ) |
| 779 | | candidate = paragraphStartNode.previousSibling ; |
| 780 | | while ( candidate && candidate.lastChild && ! this._CheckIsParagraphBoundary( candidate.lastChild ) ) |
| 781 | | candidate = candidate.lastChild ; |
| 782 | | } |
| 783 | | else |
| 784 | | { |
| 785 | | if ( ! this._CheckIsParagraphBoundary( paragraphStartNode.parentNode ) ) |
| 786 | | candidate = paragraphStartNode.parentNode ; |
| 787 | | } |
| 788 | | |
| 789 | | if ( candidate ) |
| 790 | | paragraphStartNode = candidate ; |
| 791 | | else |
| 792 | | break ; |
| 793 | | } |
| 794 | | |
| 795 | | // Get the ending point of the selection's paragraph. |
| 796 | | var paragraphEndNode = endNode ; |
| 797 | | while ( paragraphEndNode && ! this._CheckIsParagraphBoundary( paragraphEndNode ) ) |
| 798 | | { |
| 799 | | var candidate = null ; |
| 800 | | if ( paragraphEndNode.firstChild ) |
| 801 | | { |
| 802 | | if ( ! this._CheckIsParagraphBoundary( paragraphEndNode.firstChild ) ) |
| 803 | | candidate = paragraphEndNode.firstChild ; |
| 804 | | } |
| 805 | | else if ( paragraphEndNode.nextSibling ) |
| 806 | | { |
| 807 | | if ( ! this._CheckIsParagraphBoundary( paragraphEndNode.nextSibling ) ) |
| 808 | | candidate = paragraphEndNode.nextSibling ; |
| 809 | | } |
| 810 | | else |
| 811 | | { |
| 812 | | var ancestor = paragraphEndNode.parentNode ; |
| 813 | | while ( ancestor ) |
| 814 | | { |
| 815 | | if ( this._CheckIsParagraphBoundary( ancestor ) ) |
| 816 | | break ; |
| 817 | | if ( ancestor.nextSibling ) |
| | 784 | range.Expand( 'block_contents' ) ; |
| | 785 | |
| | 786 | var currentNode = range.StartNode || range.StartContainer ; |
| | 787 | var lastNode = range.EndNode || range.EndContainer.lastChild || range.EndContainer ; |
| | 788 | |
| | 789 | var boundarySet = FCKListsLib.BlockBoundaries ; |
| | 790 | if ( forceBreakBr ) |
| | 791 | boundarySet = FCKListsLib.ListBoundaries ; |
| | 792 | |
| | 793 | // Let's reuse this range |
| | 794 | range = null ; |
| | 795 | |
| | 796 | while ( currentNode ) |
| | 797 | { |
| | 798 | // closeRange indicates that a paragraph boundary has been found, |
| | 799 | // so the range must be appended to the list. |
| | 800 | var closeRange = false ; |
| | 801 | |
| | 802 | var continueFromSibling = false ; |
| | 803 | |
| | 804 | // includeNode indicates that the current node is good to be part |
| | 805 | // of the range. |
| | 806 | var includeNode = ( currentNode.nodeType != 1 ) ; |
| | 807 | |
| | 808 | // If it is an element node, let's check if it can be part of the |
| | 809 | // range. |
| | 810 | if ( !includeNode ) |
| | 811 | { |
| | 812 | var nodeName = currentNode.nodeName.toLowerCase() ; |
| | 813 | |
| | 814 | if ( boundarySet[ nodeName ] ) |
| | 815 | { |
| | 816 | // <br> boundaries must be part of the range. It will |
| | 817 | // happen only if EnterMode='br'. |
| | 818 | if ( nodeName == 'br' ) |
| | 819 | includeNode = true ; |
| | 820 | |
| | 821 | closeRange = true ; |
| | 822 | } |
| | 823 | else |
| | 824 | { |
| | 825 | // If we have child nodes, let's check them. |
| | 826 | if ( currentNode.firstChild ) |
| 819 | | if ( this._CheckIsParagraphBoundary( ancestor.nextSibling ) ) |
| 820 | | break ; |
| 821 | | candidate = ancestor.nextSibling ; |
| | 828 | currentNode = currentNode.firstChild ; |
| | 829 | continue ; |
| | 830 | } |
| | 831 | includeNode = true ; |
| | 832 | } |
| | 833 | } |
| | 834 | else if ( currentNode.nodeType == 3 ) |
| | 835 | { |
| | 836 | // Ignore normal whitespaces (i.e. not including or |
| | 837 | // other unicode whitespaces) before/after a block node. |
| | 838 | if ( /^[\r\n\t ]+$/.test( currentNode.nodeValue ) ) |
| | 839 | includeNode = false ; |
| | 840 | } |
| | 841 | |
| | 842 | // The current node is good to be part of the range and we are |
| | 843 | // starting a new range, initialize it first. |
| | 844 | if ( includeNode && !range ) |
| | 845 | { |
| | 846 | range = new FCKDomRange( this.Window ) ; |
| | 847 | range.SetStart( currentNode, 3, true ) ; |
| | 848 | } |
| | 849 | |
| | 850 | // If we are in an element boundary, let's check if it is time |
| | 851 | // to close the range, otherwise we include the parent within it. |
| | 852 | if ( range && !closeRange ) |
| | 853 | { |
| | 854 | var parentNode = currentNode.parentNode ; |
| | 855 | while ( currentNode == parentNode.lastChild && currentNode != lastNode ) |
| | 856 | { |
| | 857 | if ( boundarySet[ parentNode.nodeName.toLowerCase() ] ) |
| | 858 | { |
| | 859 | closeRange = true ; |
| 824 | | else |
| 825 | | ancestor = ancestor.parentNode ; |
| 826 | | } |
| 827 | | } |
| 828 | | |
| 829 | | if ( candidate ) |
| 830 | | paragraphEndNode = candidate ; |
| 831 | | else |
| | 862 | |
| | 863 | currentNode = parentNode ; |
| | 864 | continueFromSibling = true ; |
| | 865 | } |
| | 866 | } |
| | 867 | |
| | 868 | // Now finally include the node. |
| | 869 | if ( includeNode ) |
| | 870 | range.SetEnd( currentNode, 4, true ) ; |
| | 871 | |
| | 872 | // We have found a block boundary. Let's add the range to the list, |
| | 873 | // and prepare it for the next one. |
| | 874 | if ( ( closeRange || currentNode == lastNode ) && range ) |
| | 875 | { |
| | 876 | range._UpdateElementInfo() ; |
| | 877 | retval.push( range ) ; |
| | 878 | range = null ; |
| | 879 | } |
| | 880 | |
| | 881 | // Stop processing if this is the last one. |
| | 882 | if ( currentNode == lastNode ) |
| 833 | | } |
| 834 | | |
| 835 | | // Break up the range between paragraphStartNode and paragraphEndNode into paragraphs represented by ranges. |
| 836 | | var retval = [] ; |
| 837 | | var currentStart = paragraphStartNode ; |
| 838 | | var currentEnd = currentStart ; |
| 839 | | |
| 840 | | // Each iteration advances the position by one node in a DFS tree walk. |
| 841 | | while ( currentEnd != paragraphEndNode ) |
| 842 | | { |
| 843 | | // 1. if we come across a <br> node, save a new paragraph |
| 844 | | // 2. if we come across a block element boundary, save a new paragraph |
| 845 | | // 3. set currentStart to null after saving a new paragraph |
| 846 | | // 4. set currentStart to currentEnd if currentStart is null and currentEnd is not boundary node |
| 847 | | if ( currentStart == null && currentEnd.nodeType == 3 ) |
| 848 | | { |
| 849 | | // Ignore normal whitespaces (i.e. not including or other unicode whitespaces) after a block node. |
| 850 | | if ( currentEnd.nodeValue.search( /^[\r\n\t ]+$/ ) == 0 ) |
| 851 | | { |
| 852 | | var prevNode = currentEnd.previousSibling ; |
| 853 | | if ( prevNode ) |
| 854 | | { |
| 855 | | var prevTag = String( prevNode.tagName ).toLowerCase() ; |
| 856 | | if ( ! ( FCKListsLib.BlockElements[prevTag] || FCKListsLib.NonEmptyBlockElements[prevTag] ) ) |
| 857 | | currentStart = currentEnd ; |
| 858 | | } |
| 859 | | } |
| 860 | | else if ( currentEnd.nodeValue.length > 0 ) |
| 861 | | currentStart = currentEnd ; |
| 862 | | } |
| 863 | | |
| 864 | | if ( currentEnd.firstChild ) |
| 865 | | { |
| 866 | | if ( this._CheckIsParagraphBoundary( currentEnd.firstChild ) ) |
| 867 | | { |
| 868 | | this._GenerateParagraphRange( retval, this.Window, currentStart, currentEnd ) ; |
| 869 | | currentStart = null ; |
| 870 | | } |
| 871 | | currentEnd = currentEnd.firstChild ; |
| 872 | | } |
| 873 | | else if ( currentEnd.nextSibling ) |
| 874 | | { |
| 875 | | if ( this._CheckIsParagraphBoundary( currentEnd.nextSibling ) ) |
| 876 | | { |
| 877 | | this._GenerateParagraphRange( retval, this.Window, currentStart, currentEnd ) ; |
| 878 | | currentStart = null ; |
| 879 | | } |
| 880 | | currentEnd = currentEnd.nextSibling ; |
| 881 | | } |
| 882 | | else |
| 883 | | { |
| 884 | | var ancestor = currentEnd.parentNode ; |
| 885 | | while ( ancestor ) |
| 886 | | { |
| 887 | | if ( this._CheckIsParagraphBoundary( ancestor ) ) |
| 888 | | { |
| 889 | | this._GenerateParagraphRange( retval, this.Window, currentStart, currentEnd ) ; |
| 890 | | currentStart = null ; |
| 891 | | } |
| 892 | | if ( ancestor.nextSibling ) |
| 893 | | { |
| 894 | | if ( this._CheckIsParagraphBoundary( ancestor.nextSibling ) ) |
| 895 | | { |
| 896 | | this._GenerateParagraphRange( retval, this.Window, currentStart, currentEnd ) ; |
| 897 | | currentStart = null ; |
| 898 | | } |
| 899 | | currentEnd = ancestor.nextSibling ; |
| 900 | | break ; |
| 901 | | } |
| 902 | | else |
| 903 | | ancestor = ancestor.parentNode ; |
| 904 | | } |
| 905 | | } |
| 906 | | } |
| 907 | | // Record the final range as well. |
| 908 | | if ( currentStart == null && currentEnd.nodeType == 3 ) |
| 909 | | currentStart = currentEnd ; |
| 910 | | this._GenerateParagraphRange( retval, this.Window, currentStart, currentEnd ) ; |
| | 884 | |
| | 885 | currentNode = FCKDomTools.GetNextSourceNode( currentNode, continueFromSibling ) ; |
| | 886 | } |