| 691 | | // Move everything from the current node to the new one. |
| 692 | | // if ( toPre ) |
| 693 | | // newBlock = this._ToPre( doc, block, newBlock ); |
| 694 | | // else if ( fromPre ) |
| 695 | | // newBlock = this._FromPre( doc, block, newBlock ); |
| 696 | | // else // Convering from a regular block to another regular block. |
| 697 | | block.moveChildren( newBlock ); |
| | 697 | var isToPre = newBlockIsPre && !blockIsPre; |
| | 698 | var isFromPre = !newBlockIsPre && blockIsPre; |
| | 699 | |
| | 700 | if ( isToPre ) |
| | 701 | newBlock = toPre( block, newBlock ); |
| | 702 | else if ( isFromPre ) |
| | 703 | // Split big <pre> into pieces before start to convert. |
| | 704 | newBlock = fromPres( splitIntoPres( block ), newBlock ); |
| | 705 | else |
| | 706 | block.moveChildren( newBlock ); |
| 703 | | // Complete other tasks after inserting the node in the DOM. |
| 704 | | // if ( newBlockIsPre ) |
| 705 | | // { |
| 706 | | // if ( previousPreBlock ) |
| 707 | | // this._CheckAndMergePre( previousPreBlock, newBlock ) ; // Merge successive <pre> blocks. |
| 708 | | // previousPreBlock = newBlock; |
| 709 | | // } |
| 710 | | // else if ( fromPre ) |
| 711 | | // this._CheckAndSplitPre( newBlock ) ; // Split <br><br> in successive <pre>s. |
| 712 | | } |
| | 710 | if ( newBlockIsPre ) |
| | 711 | // Merge previous <pre> blocks. |
| | 712 | mergePre( newBlock ); |
| | 713 | }; |
| | 714 | |
| | 715 | /** |
| | 716 | * Merge a <pre> block with a previous sibling if available. |
| | 717 | */ |
| | 718 | function mergePre( preBlock ) |
| | 719 | { |
| | 720 | var previousBlock; |
| | 721 | if ( !( ( previousBlock = preBlock.getPreviousSourceNode( true, CKEDITOR.NODE_ELEMENT ) ) |
| | 722 | && previousBlock.is |
| | 723 | && previousBlock.is( 'pre') ) ) |
| | 724 | return; |
| | 725 | |
| | 726 | // Merge the previous <pre> block contents into the current <pre> |
| | 727 | // block. |
| | 728 | // |
| | 729 | // Another thing to be careful here is that currentBlock might contain |
| | 730 | // a '\n' at the beginning, and previousBlock might contain a '\n' |
| | 731 | // towards the end. These new lines are not normally displayed but they |
| | 732 | // become visible after merging. |
| | 733 | var mergedHtml = replace( previousBlock.getHtml(), /\n$/, '' ) + '\n\n' + |
| | 734 | replace( preBlock.getHtml(), /^\n/, '' ) ; |
| | 735 | |
| | 736 | // Krugle: IE normalizes innerHTML from <pre>, breaking whitespaces. |
| | 737 | if ( CKEDITOR.env.ie ) |
| | 738 | preBlock.$.outerHTML = '<pre>' + mergedHtml + '</pre>'; |
| | 739 | else |
| | 740 | preBlock.setHtml( mergedHtml ); |
| | 741 | |
| | 742 | previousBlock.remove(); |
| | 743 | } |
| 714 | | range.moveToBookmark( bookmark ); |
| | 745 | /** |
| | 746 | * Split into multiple <pre> blocks separated by double line-break. |
| | 747 | * @param preBlock |
| | 748 | */ |
| | 749 | function splitIntoPres( preBlock ) |
| | 750 | { |
| | 751 | // Exclude the ones at header OR at tail, |
| | 752 | // and ignore bookmark content between them. |
| | 753 | var duoBrRegex = /(\S\s*)\n(?:\s|(<span[^>]+_fck_bookmark.*?\/span>))*\n(?!$)/gi, |
| | 754 | blockName = preBlock.getName(), |
| | 755 | splitedHtml = replace( preBlock.getOuterHtml(), |
| | 756 | duoBrRegex, |
| | 757 | function( match, charBefore, bookmark ) |
| | 758 | { |
| | 759 | return charBefore + '</pre>' + bookmark + '<pre>'; |
| | 760 | } ); |
| | 761 | |
| | 762 | var pres = []; |
| | 763 | splitedHtml.replace( /<pre>([\s\S]*?)<\/pre>/gi, function( match, preContent ){ |
| | 764 | pres.push( preContent ); |
| | 765 | } ); |
| | 766 | return pres; |
| | 769 | // Wrapper function of String::replace without considering of head/tail bookmarks nodes. |
| | 770 | function replace( str, regexp, replacement ) |
| | 771 | { |
| | 772 | var headBookmark = '', |
| | 773 | tailBookmark = ''; |
| | 774 | |
| | 775 | str = str.replace( /(^<span[^>]+_fck_bookmark.*?\/span>)|(<span[^>]+_fck_bookmark.*?\/span>$)/gi, |
| | 776 | function( str, m1, m2 ){ |
| | 777 | m1 && ( headBookmark = m1 ); |
| | 778 | m2 && ( tailBookmark = m2 ); |
| | 779 | return ''; |
| | 780 | } ); |
| | 781 | return headBookmark + str.replace( regexp, replacement ) + tailBookmark; |
| | 782 | } |
| | 783 | /** |
| | 784 | * Converting a list of <pre> into blocks with format well preserved. |
| | 785 | */ |
| | 786 | function fromPres( preHtmls, newBlock ) |
| | 787 | { |
| | 788 | var docFrag = new CKEDITOR.dom.documentFragment( newBlock.getDocument() ); |
| | 789 | for ( var i = 0 ; i < preHtmls.length ; i++ ) |
| | 790 | { |
| | 791 | var blockHtml = preHtmls[ i ]; |
| | 792 | |
| | 793 | // 1. Trim the first and last line-breaks immediately after and before <pre>, |
| | 794 | // they're not visible. |
| | 795 | blockHtml = blockHtml.replace( /(\r\n|\r)/g, '\n' ) ; |
| | 796 | blockHtml = replace( blockHtml, /^[ \t]*\n/, '' ) ; |
| | 797 | blockHtml = replace( blockHtml, /\n$/, '' ) ; |
| | 798 | // 2. Convert spaces or tabs at the beginning or at the end to |
| | 799 | blockHtml = replace( blockHtml, /^[ \t]+|[ \t]+$/g, function( match, offset, s ) |
| | 800 | { |
| | 801 | if ( match.length == 1 ) // one space, preserve it |
| | 802 | return ' ' ; |
| | 803 | else if ( offset == 0 ) // beginning of block |
| | 804 | return CKEDITOR.tools.multiple( ' ', match.length - 1 ) + ' '; |
| | 805 | else // end of block |
| | 806 | return ' ' + CKEDITOR.tools.multiple( ' ', match.length - 1 ); |
| | 807 | } ) ; |
| | 808 | |
| | 809 | // 3. Convert \n to <BR>. |
| | 810 | // 4. Convert contiguous (i.e. non-singular) spaces or tabs to |
| | 811 | blockHtml = blockHtml.replace( /\n/g, '<br>' ) ; |
| | 812 | blockHtml = blockHtml.replace( /[ \t]{2,}/g, |
| | 813 | function ( match ) |
| | 814 | { |
| | 815 | return CKEDITOR.tools.multiple( ' ', match.length - 1 ) + ' ' ; |
| | 816 | } ) ; |
| | 817 | |
| | 818 | var newBlockClone = newBlock.clone(); |
| | 819 | newBlockClone.setHtml( blockHtml ); |
| | 820 | docFrag.append( newBlockClone ); |
| | 821 | } |
| | 822 | return docFrag; |
| | 823 | } |
| | 824 | |
| | 825 | /** |
| | 826 | * Converting from a non-PRE block to a PRE block in formatting operations. |
| | 827 | */ |
| | 828 | function toPre( block, newBlock ) |
| | 829 | { |
| | 830 | // First trim the block content. |
| | 831 | var preHtml = block.getHtml(); |
| | 832 | |
| | 833 | // 1. Trim head/tail spaces, they're not visible. |
| | 834 | preHtml = replace( preHtml, /(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, '' ); |
| | 835 | // 2. Delete ANSI whitespaces immediately before and after <BR> because |
| | 836 | // they are not visible. |
| | 837 | preHtml = preHtml.replace( /[ \t\r\n]*(<br[^>]*>)[ \t\r\n]*/gi, '$1' ); |
| | 838 | // 3. Compress other ANSI whitespaces since they're only visible as one |
| | 839 | // single space previously. |
| | 840 | // 4. Convert to spaces since is no longer needed in <PRE>. |
| | 841 | preHtml = preHtml.replace( /([ \t\n\r]+| )/g, ' ' ); |
| | 842 | // 5. Convert any <BR /> to \n. This must not be done earlier because |
| | 843 | // the \n would then get compressed. |
| | 844 | preHtml = preHtml.replace( /<br\b[^>]*>/gi, '\n' ); |
| | 845 | |
| | 846 | // Krugle: IE normalizes innerHTML to <pre>, breaking whitespaces. |
| | 847 | if ( CKEDITOR.env.ie ) |
| | 848 | { |
| | 849 | var temp = block.getDocument().createElement( 'div' ); |
| | 850 | temp.append( newBlock ); |
| | 851 | newBlock.$.outerHTML = '<pre>' + preHtml + '</pre>'; |
| | 852 | newBlock = temp.getFirst().remove(); |
| | 853 | } |
| | 854 | else |
| | 855 | newBlock.setHtml( preHtml ); |
| | 856 | |
| | 857 | return newBlock; |
| | 858 | } |
| | 859 | |