Ticket #3188: 3188_3.patch
File 3188_3.patch, 13.2 KB (added by , 14 years ago) |
---|
-
_source/core/tools.js
501 501 { 502 502 return length + ( decimalRegex.test( length ) ? 'px' : '' ); 503 503 }; 504 })() 504 })(), 505 506 multiple : function( str, times ) 507 { 508 return new Array( times + 1 ).join( str ); 509 } 505 510 }; 506 511 })(); 507 512 -
_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, doc ); 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, document ) 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; 698 699 699 // Replace the current block. 700 newBlock.insertBefore( block ); 701 block.remove(); 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 ); 702 705 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 } 706 newBlock.replace( block ); 707 708 if ( newBlockIsPre ) 709 // Merge previous <pre> blocks. 710 mergePre( newBlock ); 711 }; 712 713 /** 714 * Merge a <pre> block with a previous sibling if available. 715 */ 716 function mergePre( preBlock ) 717 { 718 var previousBlock; 719 if ( !( ( previousBlock = preBlock.getPreviousSourceNode( true, CKEDITOR.NODE_ELEMENT ) ) 720 && previousBlock.is 721 && previousBlock.is( 'pre') ) ) 722 return; 723 724 // Merge the previous <pre> block contents into the current <pre> 725 // block. 726 // 727 // Another thing to be careful here is that currentBlock might contain 728 // a '\n' at the beginning, and previousBlock might contain a '\n' 729 // towards the end. These new lines are not normally displayed but they 730 // become visible after merging. 731 var mergedHtml = replace( previousBlock.getHtml(), /\n$/, '' ) + '\n\n' + 732 replace( preBlock.getHtml(), /^\n/, '' ) ; 733 734 // Krugle: IE normalizes innerHTML from <pre>, breaking whitespaces. 735 if ( CKEDITOR.env.ie ) 736 preBlock.$.outerHTML = '<pre>' + mergedHtml + '</pre>'; 737 else 738 preBlock.setHtml( mergedHtml ); 739 740 previousBlock.remove(); 741 } 713 742 714 range.moveToBookmark( bookmark ); 743 /** 744 * Split into multiple <pre> blocks separated by double line-break. 745 * @param preBlock 746 */ 747 function splitIntoPres( preBlock ) 748 { 749 // Exclude the ones at header OR at tail, 750 // and ignore bookmark content between them. 751 var duoBrRegex = /(\S\s*)\n(?:\s|(<span[^>]+_fck_bookmark.*?\/span>))*\n(?!$)/gi, 752 blockName = preBlock.getName(), 753 splitedHtml = replace( preBlock.getOuterHtml(), 754 duoBrRegex, 755 function( match, charBefore, bookmark ) 756 { 757 return charBefore + '</pre>' + bookmark + '<pre>'; 758 } ); 759 760 var pres = []; 761 splitedHtml.replace( /<pre>([\s\S]*?)<\/pre>/gi, function( match, preContent ){ 762 pres.push( preContent ); 763 } ); 764 return pres; 715 765 } 716 766 767 // Wrapper function of String::replace without considering of head/tail bookmarks nodes. 768 function replace( str, regexp, replacement ) 769 { 770 var headBookmark = '', 771 tailBookmark = ''; 772 773 str = str.replace( /(^<span[^>]+_fck_bookmark.*?\/span>)|(<span[^>]+_fck_bookmark.*?\/span>$)/gi, 774 function( str, m1, m2 ){ 775 m1 && ( headBookmark = m1 ); 776 m2 && ( tailBookmark = m2 ); 777 return ''; 778 } ); 779 return headBookmark + str.replace( regexp, replacement ) + tailBookmark; 780 } 781 /** 782 * Converting a list of <pre> into blocks with format well preserved. 783 */ 784 function fromPres( preHtmls, newBlock ) 785 { 786 var docFrag = new CKEDITOR.dom.documentFragment(); 787 for ( var i = 0 ; i < preHtmls.length ; i++ ) 788 { 789 var blockHtml = preHtmls[ i ]; 790 791 // 1. Trim the first and last line-breaks immediately after and before <pre>, 792 // they're not visible. 793 blockHtml = blockHtml.replace( /(\r\n|\r)/g, '\n' ) ; 794 blockHtml = replace( blockHtml, /^[ \t]*\n/, '' ) ; 795 blockHtml = replace( blockHtml, /\n$/, '' ) ; 796 // 2. Convert spaces or tabs at the beginning or at the end to 797 blockHtml = replace( blockHtml, /^[ \t]+|[ \t]+$/g, function( match, offset, s ) 798 { 799 if ( match.length == 1 ) // one space, preserve it 800 return ' ' ; 801 else if ( offset == 0 ) // beginning of block 802 return CKEDITOR.tools.multiple( ' ', match.length - 1 ) + ' '; 803 else // end of block 804 return ' ' + CKEDITOR.tools.multiple( ' ', match.length - 1 ); 805 } ) ; 806 807 // 3. Convert \n to <BR>. 808 // 4. Convert contiguous (i.e. non-singular) spaces or tabs to 809 blockHtml = blockHtml.replace( /\n/g, '<br>' ) ; 810 blockHtml = blockHtml.replace( /[ \t]{2,}/g, 811 function ( match ) 812 { 813 return CKEDITOR.tools.multiple( ' ', match.length - 1 ) + ' ' ; 814 } ) ; 815 816 var newBlockClone = newBlock.clone(); 817 newBlockClone.setHtml( blockHtml ); 818 docFrag.append( newBlockClone ); 819 } 820 return docFrag; 821 } 822 823 /** 824 * Converting from a non-PRE block to a PRE block in formatting operations. 825 */ 826 function toPre( block, newBlock ) 827 { 828 // First trim the block content. 829 var preHtml = block.getHtml(); 830 831 // 1. Trim head/tail spaces, they're not visible. 832 preHtml = replace( preHtml, /(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, '' ); 833 // 2. Delete ANSI whitespaces immediately before and after <BR> because 834 // they are not visible. 835 preHtml = preHtml.replace( /[ \t\r\n]*(<br[^>]*>)[ \t\r\n]*/gi, '$1' ); 836 // 3. Compress other ANSI whitespaces since they're only visible as one 837 // single space previously. 838 // 4. Convert to spaces since is no longer needed in <PRE>. 839 preHtml = preHtml.replace( /([ \t\n\r]+| )/g, ' ' ); 840 // 5. Convert any <BR /> to \n. This must not be done earlier because 841 // the \n would then get compressed. 842 preHtml = preHtml.replace( /<br\b[^>]*>/gi, '\n' ); 843 844 // Krugle: IE normalizes innerHTML to <pre>, breaking whitespaces. 845 if ( CKEDITOR.env.ie ) 846 { 847 var temp = block.getDocument().createElement( 'div' ); 848 temp.append( newBlock ); 849 newBlock.$.outerHTML = '<pre>' + preHtml + '</pre>'; 850 newBlock = temp.getFirst().remove(); 851 } 852 else 853 newBlock.setHtml( preHtml ); 854 855 return newBlock; 856 } 857 717 858 // Removes a style from an element itself, don't care about its subtree. 718 859 function removeFromElement( style, element ) 719 860 { -
_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/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 { … … 494 501 element.setHtml( 'this is some <b><i id="_i1">styles</i></b> text' ); 495 502 496 503 // This is some <b><i>styles^</i></b> text 497 var range = new CKED ITOR.dom.range( doc );504 var range = new CKEDdITOR.dom.range( doc ); 498 505 range.setStartAt( doc.getById( '_i1' ), CKEDITOR.POSITION_BEFORE_END ); 499 506 500 507 var style = new CKEDITOR.style( { element : 'b' } ); … … 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 console.log( result ); 564 assert.areSame( '<pre>paragraph1\n\npara graph2\n\nparagraph3</pre>', result ); 565 }, 566 567 // Test convert one <pre> to multiple paragraphs. 568 test_ticket_3188_2 : function() 569 { 570 var element = doc.getById( '_P1' ); 571 element.setHtml( '<pre>\n\tparagraph1\t\tparagraph1\nparagraph2\n\t\n\tpara graph3\n</pre>' ); 572 573 //<pre>[\n\tparagraph1\t\tparagraph1\nparagraph2\n\t\n\tpara graph3\n]</pre> 574 var range = new CKEDITOR.dom.range( doc ); 575 range.selectNodeContents( doc.getById( '_P1' ).getFirst() ); 576 var style = new CKEDITOR.style( { element : 'p' } ); 577 style.applyToRange( range ); 578 579 var result = getInnerHtmlParsed( element ); 580 assert.areSame( '<p> paragraph1 paragraph1<br />paragraph2</p><p> para graph3</p>', 581 result ); 582 }, 540 583 name : document.title 541 584 }; 542 585 })() ); 543 //window.onload = testCase.test_ticket_3 309_3;586 //window.onload = testCase.test_ticket_3188; 544 587 //]]> 545 588 </script> 546 589 </head> -
_source/tests/core/tools.html
149 149 assert.areSame( 'silver', clone.cars.Porsche.color ); 150 150 }, 151 151 152 test_multiple : function() 153 { 154 assert.areSame( ' ', CKEDITOR.tools.multiple( ' ', 3 ) ); 155 }, 156 152 157 name : document.title 153 158 }; 154 159 })() );