Index: editor/_source/classes/fckdomrange_gecko.js =================================================================== --- editor/_source/classes/fckdomrange_gecko.js (revision 1434) +++ editor/_source/classes/fckdomrange_gecko.js (working copy) @@ -101,4 +101,4 @@ var selection = this.Window.getSelection() ; selection.removeAllRanges() ; selection.addRange( domRange ) ; -} \ No newline at end of file +} Index: editor/_source/classes/fckstyle.js =================================================================== --- editor/_source/classes/fckstyle.js (revision 1434) +++ editor/_source/classes/fckstyle.js (working copy) @@ -759,21 +759,114 @@ var bookmark ; if ( selectIt ) - bookmark = range.CreateBookmark( true ) ; + bookmark = range.CreateBookmark() ; var iterator = new FCKDomRangeIterator( range ) ; iterator.EnforceRealBlocks = true ; var block ; + var doc = range.Window.document ; + var tagPattern = FCKRegexLib.HTMLTag; + 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 = 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 ) ; + if ( newBlock.nodeName.IEquals( 'pre' ) && !block.nodeName.IEquals( 'pre' ) ) + { + // Handle converting from a regular block to a
block. + var innerHTML = block.innerHTML.Trim() ; + var xhtmlIterator = new FCKXHTMLIterator( innerHTML ) ; + var results = [] ; + var lastNodeWasBr = false ; - // Delete the current node. + // 1. Delete ANSI whitespaces immediately before and after
because they are not visible. + // 2. Compress other ANSI whitespaces since they're only visible as one single space previously. + // 3. Convert to spaces since is no longer needed in. + var processor = function( type, value ) + { + if ( type == 'tag' ) + { + if ( /^
0 ) + results[results.length - 1] = results[results.length - 1].RTrim() ; + lastNodeWasBr = true ; + } + else + lastNodeWasBr = false ; + } + else + { + if ( lastNodeWasBr ) + value = value.LTrim() ; + value = value.replace( /([ \t\n\r]+| )/g, ' ' ) ; + lastNodeWasBr = false ; + } + results.push( value ) ; + } + xhtmlIterator.Each( processor ) ; + + // 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( '' ) ; + } + else if ( !newBlock.nodeName.IEquals( 'pre' ) && block.nodeName.IEquals( 'pre' ) ) + { + 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.match( /^(?:[ \t]*\n)?((?:[a]|[^a])*)$/ )[1] ; + var lastWhiteSpaceMatch = /\n$/.exec( innerHTML ) ; + if ( lastWhiteSpaceMatch ) + innerHTML = innerHTML.substr( 0, lastWhiteSpaceMatch.index ) ; + + // 1. Convert spaces or tabs at the beginning or at the end to + var beginSpaces = /^[ \t]+/.exec( innerHTML ) ; + var endSpaces = /[ \t]+$/.exec( innerHTML ) ; + if ( endSpaces ) + innerHTML = innerHTML.substr( 0, endSpaces.index ) + endSpaces[0].replace( /[ \t]/g, ' ' ) ; + if ( beginSpaces ) + innerHTML = beginSpaces[0].replace( /[ \t]/g, ' ' ) + innerHTML.substr( beginSpaces[0].length ) ; + + // 2. Convert \n to
. + // 3. Convert contiguous (i.e. non-singular) spaces or tabs to + var xhtmlIterator = new FCKXHTMLIterator( innerHTML ) ; + var results = [] ; + var processor = function( type, value ) + { + if ( type == 'text' ) + { + value = value.replace( /\n/g, '
' ) ; + value = value.replace( /[ \t]{2}/g, ' ' ) ; + } + results.push( value ) ; + } + xhtmlIterator.Each( processor ) ; + newBlock.innerHTML = results.join( '' ) ; + } + 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 ) ; } @@ -782,7 +875,7 @@ range.SelectBookmark( bookmark ) ; if ( updateRange ) - range.MoveToBookmark( range ) ; + range.MoveToBookmark( bookmark ) ; }, /** Index: editor/_source/classes/fckxhtmliterator.js =================================================================== --- editor/_source/classes/fckxhtmliterator.js (revision 0) +++ editor/_source/classes/fckxhtmliterator.js (revision 0) @@ -0,0 +1,68 @@ +/* + * 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 FCKXHTMLIterator = function( source ) +{ + this._sourceHTML = source ; +} +FCKXHTMLIterator.prototype = +{ + Next : function() + { + if ( this._sourceHTML == null ) + return null ; + + var match = FCKRegexLib.HTMLTag.exec( this._sourceHTML ) ; + var retval ; + if ( match ) + { + if ( match.index > 0 ) + { + retval = { 'type' : 'text', 'value' : this._sourceHTML.substr( 0, match.index ) } ; + this._sourceHTML = this._sourceHTML.substr( match.index ) ; + } + else + { + retval = { 'type' : 'tag', 'value' : match[0] } ; + this._sourceHTML = this._sourceHTML.substr( match[0].length ) ; + } + } + else + { + retval = { 'type' : 'text', 'value' : this._sourceHTML } ; + this._sourceHTML = null ; + } + return retval ; + }, + + Each : function( func ) + { + var chunk ; + while ( ( chunk = this.Next() ) ) + func( chunk.type, chunk.value ) ; + } +} ; Index: editor/_source/internals/fckregexlib.js =================================================================== --- editor/_source/internals/fckregexlib.js (revision 1434) +++ editor/_source/internals/fckregexlib.js (working copy) @@ -93,5 +93,7 @@ // name is returned with $2. StyleVariableAttName : /#\(\s*("|')(.+?)\1[^\)]*\s*\)/g, -RegExp : /^\/(.*)\/([gim]*)$/ +RegExp : /^\/(.*)\/([gim]*)$/, + +HTMLTag : /<[^\s<>](?:"[^"]*"|'[^']*'|[^<])*>/ } ; Index: editor/fckeditor.html =================================================================== --- editor/fckeditor.html (revision 1434) +++ editor/fckeditor.html (working copy) @@ -186,6 +186,7 @@ LoadScript( '_source/classes/fckmenublockpanel.js' ) ; LoadScript( '_source/classes/fckcontextmenu.js' ) ; LoadScript( '_source/internals/fck_contextmenu.js' ) ; +LoadScript( '_source/classes/fckxhtmliterator.js' ) ; LoadScript( '_source/classes/fckplugin.js' ) ; LoadScript( '_source/internals/fckplugins.js' ) ; Index: fckpackager.xml =================================================================== --- fckpackager.xml (revision 1434) +++ fckpackager.xml (working copy) @@ -157,6 +157,7 @@+ @@ -252,6 +253,7 @@ +