Ticket #3188: 3188_4.patch
File 3188_4.patch, 13.9 KB (added by , 14 years ago) |
---|
-
_source/core/tools.js
519 519 { 520 520 return length + ( decimalRegex.test( length ) ? 'px' : '' ); 521 521 }; 522 })() 522 })(), 523 524 multiple : function( str, times ) 525 { 526 return new Array( times + 1 ).join( str ); 527 } 523 528 }; 524 529 })(); 525 530 -
_source/plugins/styles/plugin.js
662 662 } 663 663 664 664 range.moveToBookmark( bookmark ); 665 665 } 666 666 667 667 function applyBlockStyle( range ) 668 668 { 669 // Bookmark the range so we can re-select it after processing. 670 var bookmark = range.createBookmark(); 669 // Serializible bookmarks is needed here since 670 // elements may be merged. 671 var bookmark = range.createBookmark( true ); 671 672 672 673 var iterator = range.createIterator(); 673 674 iterator.enforceRealBlocks = true; … … 678 679 679 680 while( ( block = iterator.getNextParagraph() ) ) // Only one = 680 681 { 681 // Create the new node right before the current one.682 682 var newBlock = getElement( this, doc ); 683 replaceBlock( block, newBlock ); 684 } 683 685 684 // Check if we are changing from/to <pre>. 685 // var newBlockIsPre = newBlock.nodeName.IEquals( 'pre' ); 686 // var blockIsPre = block.nodeName.IEquals( 'pre' ); 686 range.moveToBookmark( bookmark ); 687 } 687 688 688 // var toPre = newBlockIsPre && !blockIsPre; 689 // var fromPre = !newBlockIsPre && blockIsPre; 689 // Replace the original block with new one, with special treatment 690 // for <pre> blocks to make sure content format is well preserved, and merging/splitting adjacent 691 // when necessary.(#3188) 692 function replaceBlock( block, newBlock ) 693 { 694 var newBlockIsPre = newBlock.is( 'pre' ); 695 var blockIsPre = block.is( 'pre' ); 690 696 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 ); 698 707 699 // Replace the current block. 700 newBlock.insertBefore( block ); 701 block.remove(); 708 newBlock.replace( block ); 702 709 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 } 713 744 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; 715 767 } 716 768 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 717 860 // Removes a style from an element itself, don't care about its subtree. 718 861 function removeFromElement( style, element ) 719 862 { -
_source/core/test.js
55 55 56 56 /** 57 57 * Gets the inner HTML of an element, for testing purposes. 58 * @param {Boolean} stripLineBreaks Assign 'false' to avoid trimming line-breaks. 58 59 */ 59 getInnerHtml : function( elementOrId )60 getInnerHtml : function( elementOrId , stripLineBreaks ) 60 61 { 61 62 var html; 62 63 … … 65 66 else if ( elementOrId.getHtml ) 66 67 html = elementOrId.getHtml(); 67 68 else 68 html = elementOrId.innerHTML || ''; 69 html = elementOrId.innerHTML // retrieve from innerHTML 70 || elementOrId.value; // retrieve from value 69 71 70 72 html = html.toLowerCase(); 71 html = html.replace( /[\n\r]/g, '' ); 73 if ( stripLineBreaks !== false ) 74 html = html.replace( /[\n\r]/g, '' ); 75 else 76 html = html.replace( /\r/g, '' ); // Normalize CRLF. 72 77 73 78 html = html.replace( /<\w[^>]*/g, function( match ) 74 79 { -
_source/plugins/domiterator/plugin.js
64 64 65 65 if ( this._.lastNode && 66 66 this._.lastNode.type == CKEDITOR.NODE_TEXT && 67 !CKEDITOR.tool .trim( this._.lastNode.getText( ) ) )67 !CKEDITOR.tools.trim( this._.lastNode.getText( ) ) ) 68 68 { 69 69 // Special case for #3887: 70 70 // We may have an empty text node at the end of block due to [3770]. -
_source/tests/plugins/styles/styles.html
7 7 <script type="text/javascript" src="../../test.js"></script> 8 8 <script type="text/javascript"> 9 9 10 CKEDITOR.plugins.load( 'styles');10 CKEDITOR.plugins.load( [ 'styles', 'domiterator', 'htmldataprocessor' ] ); 11 11 12 12 </script> 13 13 <script type="text/javascript"> … … 21 21 var assert = CKEDITOR.test.assert; 22 22 var getInnerHtml = CKEDITOR.test.getInnerHtml; 23 23 24 function getInnerHtmlParsed( element ) 25 { 26 var dataProcessor = new CKEDITOR.htmlDataProcessor(); 27 dataProcessor.writer = new CKEDITOR.htmlParser.basicWriter(); 28 return dataProcessor.toDataFormat( getInnerHtml( element, false ) ); 29 } 30 24 31 var doc = new CKEDITOR.dom.document( document ); 25 32 26 33 return { … … 537 544 // text <span><i>^</i></span><bold><span><b><i>styles</i></b></span></bold> 538 545 assert.areSame( 'text <span><i></i></span><strong><bold><span><b><i id="_i1">styles</i></b></span></bold></strong>', getInnerHtml( element ) ); 539 546 }, 547 548 // Test convert multiple paragraphs to one <pre>. 549 test_ticket_3188 : function() 550 { 551 var element = doc.getById( '_P1' ); 552 element.setHtml( '<p id="_P2">\nparagraph1<br /><br />para\t\ngraph2</p><p id="_P3">\nparagraph3\n</p>' ); 553 554 // <p id="_P2">[paragraph1</p><p id="_P3">paragraph2]</p> 555 var range = new CKEDITOR.dom.range( doc ); 556 range.setStartAt( doc.getById( '_P2' ), CKEDITOR.POSITION_AFTER_START ); 557 range.setEndAt( doc.getById( '_P3' ), CKEDITOR.POSITION_BEFORE_END ); 558 559 var style = new CKEDITOR.style( { element : 'pre' } ); 560 style.applyToRange( range ); 561 562 var result = getInnerHtmlParsed( element ); 563 assert.areSame( '<pre>paragraph1\n\npara graph2\n\nparagraph3</pre>', result ); 564 }, 565 566 // Test convert one <pre> to multiple paragraphs. 567 test_ticket_3188_2 : function() 568 { 569 var element = doc.getById( '_P1' ); 570 element.setHtml( '<pre>\n\tparagraph1\t\tparagraph1\nparagraph2\n\t\n\tpara graph3\n</pre>' ); 571 572 //<pre>[\n\tparagraph1\t\tparagraph1\nparagraph2\n\t\n\tpara graph3\n]</pre> 573 var range = new CKEDITOR.dom.range( doc ); 574 range.selectNodeContents( doc.getById( '_P1' ).getFirst() ); 575 var style = new CKEDITOR.style( { element : 'p' } ); 576 style.applyToRange( range ); 577 578 var result = getInnerHtmlParsed( element ); 579 assert.areSame( '<p> paragraph1 paragraph1<br />paragraph2</p><p> para graph3</p>', 580 result ); 581 }, 540 582 name : document.title 541 583 }; 542 584 })() ); 543 //window.onload = testCase.test_ticket_3 309_3;585 //window.onload = testCase.test_ticket_3188; 544 586 //]]> 545 587 </script> 546 588 </head> -
_source/tests/core/tools.html
154 154 assert.areSame( 'silver', clone.cars.Porsche.color ); 155 155 }, 156 156 157 test_multiple : function() 158 { 159 assert.areSame( ' ', CKEDITOR.tools.multiple( ' ', 3 ) ); 160 }, 161 157 162 name : document.title 158 163 }; 159 164 })() ); -
CHANGES.html
38 38 CKEditor 3.0 (SVN)</h3> 39 39 <p> 40 40 New features:</p> 41 <li><a href="http://dev.fckeditor.net/ticket/3188">#3188</a> : Introduce 42 <pre> formatting feature when converting from other blocks.</li> 41 43 <ul> 42 44 <li> </li> 43 45 </ul>