Index: /FCKeditor/trunk/_whatsnew.html =================================================================== --- /FCKeditor/trunk/_whatsnew.html (revision 1558) +++ /FCKeditor/trunk/_whatsnew.html (revision 1559) @@ -103,4 +103,6 @@ which occurs in the Find/Replace dialog when the user presses "Find" or "Replace" after the "No match found" message has appeared. +
Index: /FCKeditor/trunk/editor/_source/classes/fckhtmliterator.js =================================================================== --- /FCKeditor/trunk/editor/_source/classes/fckhtmliterator.js (revision 1559) +++ /FCKeditor/trunk/editor/_source/classes/fckhtmliterator.js (revision 1559) @@ -0,0 +1,142 @@ +/* + * FCKeditor - The text editor for Internet - http://www.fckeditor.net + * Copyright (C) 2003-2007 Frederico Caldeira Knabben + * + * == BEGIN LICENSE == + * + * Licensed under the terms of any of the following licenses at your + * choice: + * + * - GNU General Public License Version 2 or later (the "GPL") + * http://www.gnu.org/licenses/gpl.html + * + * - GNU Lesser General Public License Version 2.1 or later (the "LGPL") + * http://www.gnu.org/licenses/lgpl.html + * + * - Mozilla Public License Version 1.1 or later (the "MPL") + * http://www.mozilla.org/MPL/MPL-1.1.html + * + * == END LICENSE == + * + * This class can be used to interate through nodes inside a range. + * + * During interation, the provided range can become invalid, due to document + * mutations, so CreateBookmark() used to restore it after processing, if + * needed. + */ + +var FCKHtmlIterator = function( source ) +{ + this._sourceHtml = source ; +} +FCKHtmlIterator.prototype = +{ + Next : function() + { + var sourceHtml = this._sourceHtml ; + if ( sourceHtml == null ) + return null ; + + var match = FCKRegexLib.HtmlTag.exec( sourceHtml ) ; + var isTag = false ; + var value = "" ; + if ( match ) + { + if ( match.index > 0 ) + { + value = sourceHtml.substr( 0, match.index ) ; + this._sourceHtml = sourceHtml.substr( match.index ) ; + } + else + { + isTag = true ; + value = match[0] ; + this._sourceHtml = sourceHtml.substr( match[0].length ) ; + } + } + else + { + value = sourceHtml ; + this._sourceHtml = null ; + } + return { 'isTag' : isTag, 'value' : value } ; + }, + + Each : function( func ) + { + var chunk ; + while ( ( chunk = this.Next() ) ) + func( chunk.isTag, chunk.value ) ; + } +} ; +/* + * FCKeditor - The text editor for Internet - http://www.fckeditor.net + * Copyright (C) 2003-2007 Frederico Caldeira Knabben + * + * == BEGIN LICENSE == + * + * Licensed under the terms of any of the following licenses at your + * choice: + * + * - GNU General Public License Version 2 or later (the "GPL") + * http://www.gnu.org/licenses/gpl.html + * + * - GNU Lesser General Public License Version 2.1 or later (the "LGPL") + * http://www.gnu.org/licenses/lgpl.html + * + * - Mozilla Public License Version 1.1 or later (the "MPL") + * http://www.mozilla.org/MPL/MPL-1.1.html + * + * == END LICENSE == + * + * This class can be used to interate through nodes inside a range. + * + * During interation, the provided range can become invalid, due to document + * mutations, so CreateBookmark() used to restore it after processing, if + * needed. + */ + +var FCKHtmlIterator = function( source ) +{ + this._sourceHtml = source ; +} +FCKHtmlIterator.prototype = +{ + Next : function() + { + var sourceHtml = this._sourceHtml ; + if ( sourceHtml == null ) + return null ; + + var match = FCKRegexLib.HtmlTag.exec( sourceHtml ) ; + var isTag = false ; + var value = "" ; + if ( match ) + { + if ( match.index > 0 ) + { + value = sourceHtml.substr( 0, match.index ) ; + this._sourceHtml = sourceHtml.substr( match.index ) ; + } + else + { + isTag = true ; + value = match[0] ; + this._sourceHtml = sourceHtml.substr( match[0].length ) ; + } + } + else + { + value = sourceHtml ; + this._sourceHtml = null ; + } + return { 'isTag' : isTag, 'value' : value } ; + }, + + Each : function( func ) + { + var chunk ; + while ( ( chunk = this.Next() ) ) + func( chunk.isTag, chunk.value ) ; + } +} ; Index: /FCKeditor/trunk/editor/_source/classes/fckstyle.js =================================================================== --- /FCKeditor/trunk/editor/_source/classes/fckstyle.js (revision 1558) +++ /FCKeditor/trunk/editor/_source/classes/fckstyle.js (revision 1559) @@ -748,4 +748,92 @@ /** + * Converting from a PRE block to a non-PRE block in formatting operations. + */ + _FromPre : function( doc, block, newBlock ) + { + var innerHTML = block.innerHTML ; + + // Trim the first and last linebreaks immediately after and before
,, + // if they exist. + // This is done because the linebreaks are not rendered. + innerHTML = innerHTML.replace( /(\r\n|\r)/g, '\n' ) ; + innerHTML = innerHTML.replace( /^[ \t]*\n/, '' ) ; + innerHTML = innerHTML.replace( /\n$/, '' ) ; + + // 1. Convert spaces or tabs at the beginning or at the end to + innerHTML = innerHTML.replace( /^[ \t]+|[ \t]+$/g, function( match, offset, s ) + { + if ( match.length == 1 ) // one space, preserve it + return ' ' ; + else if ( offset == 0 ) // beginning of block + return new Array( match.length ).join( ' ' ) + ' ' ; + else // end of block + return ' ' + new Array( match.length ).join( ' ' ) ; + } ) ; + + // 2. Convert \n to
block. + var innerHTML = block.innerHTML.Trim() ; + + // 1. Delete ANSI whitespaces immediately before and after
because they are not visible. + // 2. Mark down any
nodes here so they can be turned into \n in the next step and avoid being compressed. + innerHTML = innerHTML.replace( /[ \t\r\n]*(
]*>)[ \t\r\n]*/gi, '
' ) ; + + // 3. Compress other ANSI whitespaces since they're only visible as one single space previously. + // 4. Convert to spaces since is no longer needed in. + // 5. Convert any
to \n. This must not be done earlier because the \n would then get compressed. + var htmlIterator = new FCKHtmlIterator( innerHTML ) ; + var results = [] ; + htmlIterator.Each( function( isTag, value ) + { + if ( !isTag ) + value = value.replace( /([ \t\n\r]+| )/g, ' ' ) ; + else if ( isTag && value == '
' ) + value = '\n' ; + results.push( value ) ; + } ) ; + + // Assigning innerHTML toin IE causes all linebreaks to be reduced to spaces. + // Assigning outerHTML toin IE doesn't work if theisn't contained in another node + // since the node reference is changed after outerHTML assignment. + // So, we need some hacks to workaround IE bugs here. + if ( FCKBrowserInfo.IsIE ) + { + var temp = doc.createElement( 'div' ) ; + temp.appendChild( newBlock ) ; + newBlock.outerHTML = '\n' + results.join( '' ) + '' ; + newBlock = temp.removeChild( temp.firstChild ) ; + } + else + newBlock.innerHTML = results.join( '' ) ; + return newBlock ; + }, + + /** * Apply an inline style to a FCKDomRange. * @@ -760,5 +848,5 @@ if ( selectIt ) - bookmark = range.CreateBookmark( true ) ; + bookmark = range.CreateBookmark() ; var iterator = new FCKDomRangeIterator( range ) ; @@ -766,13 +854,23 @@ var block ; + var doc = range.Window.document ; + while( ( block = iterator.GetNextParagraph() ) ) // Only one = { // Create the new node right before the current one. - var newBlock = block.parentNode.insertBefore( this.BuildElement( range.Window.document ), block ) ; + var newBlock = this.BuildElement( doc ) ; // Move everything from the current node to the new one. - FCKDomTools.MoveChildren( block, newBlock ) ; - - // Delete the current node. + var newBlockIsPre = newBlock.nodeName.IEquals( 'pre' ) ; + var blockIsPre = block.nodeName.IEquals( 'pre' ) ; + if ( newBlockIsPre && !blockIsPre ) + newBlock = this._ToPre( doc, block, newBlock ) ; + else if ( !newBlockIsPre && blockIsPre ) + newBlock = this._FromPre( doc, block, newBlock ) ; + else // Convering from a regular block to another regular block. + FCKDomTools.MoveChildren( block, newBlock ) ; + + // Replace the current block. + block.parentNode.insertBefore( newBlock, block ) ; FCKDomTools.RemoveNode( block ) ; } @@ -783,5 +881,5 @@ if ( updateRange ) - range.MoveToBookmark( range ) ; + range.MoveToBookmark( bookmark ) ; }, Index: /FCKeditor/trunk/editor/_source/internals/fckregexlib.js =================================================================== --- /FCKeditor/trunk/editor/_source/internals/fckregexlib.js (revision 1558) +++ /FCKeditor/trunk/editor/_source/internals/fckregexlib.js (revision 1559) @@ -94,4 +94,6 @@ StyleVariableAttName : /#\(\s*("|')(.+?)\1[^\)]*\s*\)/g, -RegExp : /^\/(.*)\/([gim]*)$/ +RegExp : /^\/(.*)\/([gim]*)$/, + +HtmlTag : /<[^\s<>](?:"[^"]*"|'[^']*'|[^<])*>/ } ; Index: /FCKeditor/trunk/editor/fckeditor.html =================================================================== --- /FCKeditor/trunk/editor/fckeditor.html (revision 1558) +++ /FCKeditor/trunk/editor/fckeditor.html (revision 1559) @@ -187,4 +187,5 @@ LoadScript( '_source/classes/fckcontextmenu.js' ) ; LoadScript( '_source/internals/fck_contextmenu.js' ) ; +LoadScript( '_source/classes/fckhtmliterator.js' ) ; LoadScript( '_source/classes/fckplugin.js' ) ; LoadScript( '_source/internals/fckplugins.js' ) ; Index: /FCKeditor/trunk/fckpackager.xml =================================================================== --- /FCKeditor/trunk/fckpackager.xml (revision 1558) +++ /FCKeditor/trunk/fckpackager.xml (revision 1559) @@ -158,4 +158,5 @@+ @@ -253,4 +254,5 @@ +