Index: /FCKeditor/branches/features/style/_test/automated/tests/fckdomtools.html
===================================================================
--- /FCKeditor/branches/features/style/_test/automated/tests/fckdomtools.html	(revision 758)
+++ /FCKeditor/branches/features/style/_test/automated/tests/fckdomtools.html	(revision 758)
@@ -0,0 +1,119 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!--
+ * 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 ==
+-->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>FCKDomTools - Tests for JsUnit</title>
+	<script src="../../../editor/_source/fckscriptloader.js" type="text/javascript"></script>
+	<script type="text/javascript" src="tests.js"></script>
+	<script type="text/javascript" src="../_jsunit/app/jsUnitCore.js"></script>
+	<script type="text/javascript">
+
+FCKScriptLoader.Load( 'FCKDomTools' ) ;
+
+	</script>
+	<script type="text/javascript">
+
+function test_GetNextSourceNode()
+{
+	var el = document.getElementById( 'xP' ) ;
+
+	el = FCKDomTools.GetNextSourceNode( el ) ;
+	assertEquals( 'Step 1', document.getElementById( 'xP' ).firstChild, el ) ;
+
+	el = FCKDomTools.GetNextSourceNode( el ) ;
+	assertEquals( 'Step 2', document.getElementById( 'xSpan' ), el ) ;
+
+	el = FCKDomTools.GetNextSourceNode( el ) ;
+	assertEquals( 'Step 3', document.getElementById( 'xSpan' ).firstChild, el ) ;
+
+	el = FCKDomTools.GetNextSourceNode( el ) ;
+	assertEquals( 'Step 4', document.getElementById( 'xSpan' ).nextSibling, el ) ;
+
+	el = FCKDomTools.GetNextSourceNode( el ) ;
+	assertEquals( 'Step 5', document.getElementById( 'xBR' ), el ) ;
+
+	el = FCKDomTools.GetNextSourceNode( el ) ;
+	assertEquals( 'Step 6', document.getElementById( 'xBR' ).nextSibling, el ) ;
+
+	el = FCKDomTools.GetNextSourceNode( el ) ;
+	assertEquals( 'Step 8', document.getElementById( 'xHR' ), el ) ;
+
+	el = FCKDomTools.GetNextSourceNode( el ) ;
+	assertEquals( 'Step 9', document.getElementById( 'xHR' ).nextSibling, el ) ;
+}
+
+function test_HasAttribute()
+{
+	assertTrue( 'Test 1',
+		FCKDomTools.HasAttribute( document.getElementById( 'xH1' ), 'class' ) ) ;
+
+	assertFalse( 'Test 2',
+		FCKDomTools.HasAttribute( document.getElementById( 'xH1' ), 'title' ) ) ;
+
+	assertFalse( 'Test 3',
+		FCKDomTools.HasAttribute( document.getElementById( 'xP' ), 'class' ) ) ;
+
+	assertTrue( 'Test 4',
+		FCKDomTools.HasAttribute( document.getElementById( 'xH2' ), 'style' ) ) ;
+
+	assertTrue( 'Test 5',
+		FCKDomTools.HasAttribute( document.getElementById( 'xIMG' ), 'src' ) ) ;
+
+	assertTrue( 'Test 6',
+		FCKDomTools.HasAttribute( document.getElementById( 'xIMG' ), 'alt' ) ) ;
+
+	assertFalse( 'Test 7',
+		FCKDomTools.HasAttribute( document.getElementById( 'xIMG' ), 'width' ) ) ;
+
+	assertFalse( 'Test 8',
+		FCKDomTools.HasAttribute( document.getElementById( 'xIMG' ), 'unknown' ) ) ;
+}
+
+	</script>
+</head>
+<body>
+	<h1 id="xH1" class="Test">
+		Test page for FCKeditor
+	</h1>
+	<p id="xP">
+		This document contains various markup features commonly used by content editors
+		or "<span id="xSpan" lang="fr">r&eacute;dacteurs de contenu</span>" as they are
+		called in France.<br id="xBR" />
+		It is important that a WYSIWYG tool has features that are easily available for the
+		editor. If not, there is a risk that content won't receive proper markup. Examples
+		of commonly found content are:</p><hr id="xHR" />
+	<h2 id="xH2" style="background-color: Silver">
+		Test procedure
+	</h2>
+	This text has no block tag. It should be corrected when working with the enter key
+	set to "p" or "div" tags. The "br" configuration should not make changes instead.
+	<p>
+		In the test we will try to recreate this document using the editor tools. To make
+		sure tables can be inserted <em>properly</em> we re-visit banana import statistics
+		from 1998.
+	</p>
+	<p>
+		This paragraph has and image at the very end of its contents.<img id="xIMG" src="http://www.fckeditor.net/images/logotop.gif"
+			alt="" />
+	</p>
+</body>
+</html>
Index: /FCKeditor/branches/features/style/_test/manual/fckdomrange/test1.html
===================================================================
--- /FCKeditor/branches/features/style/_test/manual/fckdomrange/test1.html	(revision 757)
+++ /FCKeditor/branches/features/style/_test/manual/fckdomrange/test1.html	(revision 758)
@@ -35,5 +35,5 @@
 	<script type="text/javascript">
 
-FCKConfig.Debug = true ;
+FCKConfig.Debug = false ;
 FCKConfig.BasePath = '../../../editor/' ;
 
Index: /FCKeditor/branches/features/style/_test/manual/fckstyle/test1.html
===================================================================
--- /FCKeditor/branches/features/style/_test/manual/fckstyle/test1.html	(revision 758)
+++ /FCKeditor/branches/features/style/_test/manual/fckstyle/test1.html	(revision 758)
@@ -0,0 +1,243 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<!--
+ * 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 ==
+-->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>FCKStyle &amp; FCKStyles</title>
+	<script src="../../../editor/_source/fckscriptloader.js" type="text/javascript"></script>
+	<script src="../_common/manual_test.js" type="text/javascript"></script>
+	<script type="text/javascript">
+
+var FCK = new Object() ;
+
+FCKScriptLoader.Load( 'FCKConfig' ) ;
+
+	</script>
+	<script type="text/javascript">
+
+FCKConfig.Debug = false ;
+FCKConfig.BasePath = '../../../editor/' ;
+FCKConfig.RemoveFormatTags = 'b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strong,sub,sup,tt,u,var' ;
+
+// Do not add, rename or remove styles here.
+FCKConfig.CoreStyles = 
+{
+	'Bold' : {
+		Element : 'b',
+		Overrides : 'strong'
+	},
+	'Italic' : {
+		Element : 'i',
+		Overrides : 'em'
+	},
+	'Underline' : {
+		Element : 'u'
+	},
+	'Strikethrough' : {
+		Element : 'strike'
+	},
+	'Subscript' : {
+		Element : 'sub'
+	},
+	'Superscript' : {
+		Element : 'sup'
+	}
+} ;
+
+FCKConfig.CustomStyles = {
+
+	'H1 Red Courier' : {
+		Element : 'h1',
+		Attributes : {
+			title : 'Title 1' },
+		Styles : {
+			'color' : '#ff0000',
+			'font-family' : 'Courier New' }
+	},
+	'Paragraph' : {
+		Element : 'p'
+	},
+	'Bold' : {
+		Element : 'b',
+		Overrides : 'strong'
+	},
+	'Italic' : {
+		Element : 'i',
+		Overrides : 'em'
+	},
+	'Strong' : {
+		Element : 'strong',
+		Overrides : 'b'
+	},
+	'Em' : {
+		Element : 'em',
+		Overrides : 'i'
+	},
+	'Span Class Test1' : {
+		Element : 'span',
+		Attributes : {
+			'class' : 'Test1' },
+		Overrides : { 
+			Attributes : {
+				'class' : /^Test\d$/ } 
+			}
+	},
+	'Span Class Test2' : {
+		Element : 'span',
+		Attributes : {
+			'class' : 'Test2' },
+		Overrides : { 
+			Attributes : {
+				'class' : /^Test\d$/ } 
+			}
+	},
+	'Span Style Orange' : {
+		Element : 'span',
+		Styles : {
+			'color' : '#ffcc00' }
+	},
+	'Span Style Green' : {
+		Element : 'span',
+		Styles : {
+			'color' : '#00cc00' }
+	},
+	'Font Red' : {
+		Element : 'font',
+		Attributes : {
+			'color' : 'red' }
+	},
+	'Font Blue' : {
+		Element : 'font',
+		Attributes : {
+			'color' : 'blue' }
+	}
+} ;
+
+	</script>
+	<script type="text/javascript">
+
+FCKScriptLoader.Load( 'FCKStyle' ) ;
+FCKScriptLoader.Load( 'FCKStyles' ) ;
+FCKScriptLoader.Load( 'FCKDebug' ) ;
+
+	</script>
+	<script type="text/javascript">
+
+var styles = FCKConfig.CustomStyles ;
+
+var targetWindow ;
+
+function InnerLoaded( innerWindow )
+{
+	var stylesCombo = document.getElementById( 'xStyles' ) ;
+	
+	for ( var styleName in styles )
+	{
+		AddComboOption( stylesCombo, styleName, styleName ) ;
+	}
+
+	// FCK.EditorWindow is required by FCKStyles.
+	FCK.EditorWindow = targetWindow = innerWindow ;
+	document.getElementById('xSource').value = targetWindow.document.body.innerHTML ;
+
+	document.getElementById('xBtnApply').disabled = false ;
+	document.getElementById('xBtnRemove').disabled = false ;
+	document.getElementById('xBtnRemoveAll').disabled = false ;
+}
+
+function ApplyStyle()
+{
+	var style = new FCKStyle( styles[ document.getElementById( 'xStyles' ).value ] ) ;
+	style.ApplyToSelection( targetWindow ) ;
+	
+	document.getElementById('xSource').value = targetWindow.document.body.innerHTML ;
+
+	targetWindow.focus() ;
+}
+
+function RemoveStyle()
+{
+	var style = new FCKStyle( styles[ document.getElementById( 'xStyles' ).value ] ) ;
+	style.RemoveFromSelection( targetWindow ) ;
+	
+	document.getElementById('xSource').value = targetWindow.document.body.innerHTML ;
+
+	targetWindow.focus() ;
+}
+
+function RemoveAll()
+{
+	FCKStyles.RemoveAll() ;
+	
+	document.getElementById('xSource').value = targetWindow.document.body.innerHTML ;
+
+	targetWindow.focus() ;
+}
+
+function AddComboOption(combo, optionText, optionValue)
+{
+	var oOption = document.createElement( 'option' ) ;
+
+	combo.options.add(oOption) ;
+
+	oOption.innerHTML = optionText ;
+	oOption.value     = optionValue ;
+
+	return oOption ;
+}
+
+	</script>
+</head>
+<body>
+	<table cellpadding="0" cellspacing="0" width="100%" height="100%" border="0">
+		<tr>
+			<td>
+				<h1>
+					 FCKStyle &amp; FCKStyles</h1>
+				<p>
+					<select id="xStyles">
+					</select>
+					<input id="xBtnApply" type="button" value="Apply" onclick="ApplyStyle(); return false;"
+						disabled="disabled" />
+					<input id="xBtnRemove" type="button" value="Remove" onclick="RemoveStyle(); return false;"
+						disabled="disabled" />
+					<input id="xBtnRemoveAll" type="button" value="Remove All" onclick="RemoveAll(); return false;"
+						disabled="disabled" />
+				</p>
+			</td>
+		</tr>
+		<tr>
+			<td height="100%">
+				<iframe src="test1_inner.html" width="100%" height="100%" frameborder="1"></iframe>
+			</td>
+		</tr>
+		<tr>
+			<td style="padding-top:5px;">
+				Source:</td>
+		</tr>
+		<tr>
+			<td>
+				<textarea id="xSource" style="width: 100%; height: 200px"></textarea>
+			</td>
+		</tr>
+	</table>
+</body>
+</html>
Index: /FCKeditor/branches/features/style/_test/manual/fckstyle/test1_inner.html
===================================================================
--- /FCKeditor/branches/features/style/_test/manual/fckstyle/test1_inner.html	(revision 758)
+++ /FCKeditor/branches/features/style/_test/manual/fckstyle/test1_inner.html	(revision 758)
@@ -0,0 +1,192 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!--
+ * 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 ==
+-->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>Test Page</title>
+	<style type="text/css">
+	
+		.Test1
+		{
+			background-color: #ffff66;
+		}
+
+		.Test2
+		{
+			background-color: #00ff00 ;
+		}
+
+		.MyBold
+		{
+			font-weight: bold;
+		}
+
+		.MyItalic
+		{
+			font-style: italic;
+		}
+	
+	</style>
+	<script type="text/javascript">
+
+window.onload = function()
+{
+	if ( (/msie/).test( navigator.userAgent.toLowerCase() ) )
+		document.body.contentEditable = true ;
+	else
+		document.designMode = 'on' ;
+
+	parent.InnerLoaded( window ) ;
+}
+
+	</script>
+</head>
+<body>
+	<h1>
+		Test page for FCKeditor
+	</h1>
+	<p>
+		This document contains various markup features commonly used by content editors
+		or "<span lang="fr">r&eacute;dacteurs de contenu</span>" as they are called in <a
+			href="http://en.wikipedia.org/wiki/France" title="Wikipedia article about France">
+			France</a>.<br />
+		It is important that a <acronym title="what you see is what you get">WYSIWYG</acronym>
+		tool has features that are easily available for the editor. If not, there is a risk
+		that content won't receive <strong>proper</strong> markup. Examples of commonly
+		found content are:</p>
+	<ol>
+		<li>Headings</li>
+		<li style="color: Red">Links (with optional title) </li>
+		<li>Lists (like this one)
+			<ul>
+				<li>including nested lists </li>
+			</ul>
+		</li>
+		<li>Tables
+			<ul>
+				<li>caption</li>
+				<li>headers</li>
+				<li>summary</li>
+			</ul>
+		</li>
+		<li>Language information</li>
+		<li>Acronyms and abbreviations</li>
+		<li>Emphasis and strong emphasis </li>
+		<li>Quotes, inline and block </li>
+		<li>Images</li>
+	</ol>
+	<hr />
+	<h2 style="background-color: Silver">
+		Test procedure
+	</h2>
+	This text has no block tag.<br />
+	This line has a BR before it, as well as the next one<br />
+	It should be corrected when working with the enter key set to "p" or "div" tags.
+	The "br" configuration should not make changes instead.
+	<p>
+		In the test we will try to recreate this document using the editor tools. To make
+		sure tables can be inserted <em>properly</em> we re-visit banana import statistics
+		from 1998.
+	</p>
+	<p>
+		This paragraph has and image at the very end of its contents.<img src="http://www.fckeditor.net/images/logotop.gif"
+			alt="" />
+	</p>
+	This text has no block tag. It should be corrected when working with the enter key
+	set to "p" or "div" tags. The <strong>"br" configuration</strong> should not make
+	changes instead.
+	<p>
+		In the test we will try to recreate this document using the editor tools. To make
+		sure tables can be inserted <em>properly</em> we re-visit banana import statistics
+		from 1998.
+	</p>
+	<table summary="Sweden was the top importing country by far in 1998.">
+		<caption>
+			Top banana importers 1998 (value of banana imports in millions of US dollars per
+			million people)<br />
+			<br />
+		</caption>
+		<tr>
+			<th scope="col">
+				Country</th>
+			<th scope="col">
+				Millions of US dollars per million people</th>
+		</tr>
+		<tr>
+			<td>
+				Sweden</td>
+			<td>
+				17.12</td>
+		</tr>
+		<tr>
+			<td>
+				United&nbsp;Kingdom</td>
+			<td>
+				8.88</td>
+		</tr>
+		<tr>
+			<td>
+				Germany</td>
+			<td>
+				8.36</td>
+		</tr>
+		<tr>
+			<td>
+				Italy</td>
+			<td>
+				5.96</td>
+		</tr>
+		<tr>
+			<td>
+				United States</td>
+			<td>
+				4.78</td>
+		</tr>
+	</table>
+	<p>
+		For block quotes we will have a look at <a href="http://fawny.org/rhcp.html">what Joe
+			Clark says about redheads</a>:
+	</p>
+	<blockquote cite="http://fawny.org/rhcp.html#me">
+		<p>
+			"Since boyhood I&rsquo;ve always believed, at the deepest level, that redheads are
+			standard-bearers of the grandest and most wondrous human beauty."
+		</p>
+	</blockquote>
+	<div>
+		This is some text inside a DIV.
+	</div>
+	<p>
+		<img src="http://www.fckeditor.net/images/logotop.gif" alt="" />
+	</p>
+	<p>
+		The above is the FCKeditor logo loaded from the FCKeditor.net web site.
+	</p>
+	<div>
+		<p>
+			First para inside DIV</p>
+		<p>
+			Second para inside DIV</p>
+	</div>
+	<p>
+		Para outside DIV</p>
+</body>
+</html>
Index: /FCKeditor/branches/features/style/editor/_source/classes/fckdocumentfragment_gecko.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/classes/fckdocumentfragment_gecko.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/classes/fckdocumentfragment_gecko.js	(revision 758)
@@ -44,4 +44,9 @@
 	{
 		FCKDomTools.InsertAfterNode( existingNode, this.RootNode ) ;
+	},
+
+	InsertBeforeNode : function( existingNode )
+	{
+		existingNode.parentNode.insertBefore( this.RootNode, existingNode ) ;
 	}
 }
Index: /FCKeditor/branches/features/style/editor/_source/classes/fckdocumentfragment_ie.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/classes/fckdocumentfragment_ie.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/classes/fckdocumentfragment_ie.js	(revision 758)
@@ -56,4 +56,13 @@
 		while( ( eLast = eRoot.lastChild ) )
 			FCKDomTools.InsertAfterNode( existingNode, eRoot.removeChild( eLast ) ) ;
+	},
+
+	InsertBeforeNode : function( existingNode )
+	{
+		var eRoot = this.RootNode ;
+		var eFirst ;
+
+		while( ( eFirst = eRoot.firstChild ) )
+			existingNode.parentNode.insertBefore( eRoot.removeChild( eFirst ), existingNode ) ;
 	}
 } ;
Index: /FCKeditor/branches/features/style/editor/_source/classes/fckdomrange.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/classes/fckdomrange.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/classes/fckdomrange.js	(revision 758)
@@ -34,13 +34,17 @@
 	_UpdateElementInfo : function()
 	{
-		if ( !this._Range )
+		var innerRange = this._Range ;
+
+		if ( !innerRange )
 			this.Release( true ) ;
 		else
 		{
-			var eStart	= this._Range.startContainer ;
-			var eEnd	= this._Range.endContainer ;
+			// For text nodes, the node itself is the StartNode.
+			var eStart	= innerRange.startContainer ;
+			var eEnd	= innerRange.endContainer ;
 
 			var oElementPath = new FCKElementPath( eStart ) ;
-			this.StartContainer		= oElementPath.LastElement ;
+			this.StartNode			= eStart.nodeType == 3 ? eStart : eStart.childNodes[ innerRange.startOffset ] ;
+			this.StartContainer		= eStart ;
 			this.StartBlock			= oElementPath.Block ;
 			this.StartBlockLimit	= oElementPath.BlockLimit ;
@@ -48,5 +52,6 @@
 			if ( eStart != eEnd )
 				oElementPath = new FCKElementPath( eEnd ) ;
-			this.EndContainer		= oElementPath.LastElement ;
+			this.EndNode			= eEnd.nodeType == 3 ? eEnd : eEnd.childNodes[ innerRange.endOffset ] ;
+			this.EndContainer		= eEnd ;
 			this.EndBlock			= oElementPath.Block ;
 			this.EndBlockLimit		= oElementPath.BlockLimit ;
@@ -215,11 +220,18 @@
 	},
 
-	CreateBookmark : function()
+	// This is an "intrusive" way to create a bookmark. It includes <span> tags
+	// in the range boundaries. The advantage of it is that it is possible to
+	// handle DOM mutations when moving back to the bookmark.
+	// Attention: the inclusion of nodes in the DOM is a design choice and
+	// should not be changes as there are other points in the code that may be
+	// using those nodes to perform operations. See GetBookmarkNode.
+	// For performance, includeNodes=true if intended to SelectBookmark.
+	CreateBookmark : function( includeNodes )
 	{
 		// Create the bookmark info (random IDs).
 		var oBookmark =
 		{
-			StartId	: 'fck_dom_range_start_' + (new Date()).valueOf() + '_' + Math.floor(Math.random()*1000),
-			EndId	: 'fck_dom_range_end_' + (new Date()).valueOf() + '_' + Math.floor(Math.random()*1000)
+			StartId	: (new Date()).valueOf() + Math.floor(Math.random()*1000) + 'S',
+			EndId	: (new Date()).valueOf() + Math.floor(Math.random()*1000) + 'E'
 		} ;
 
@@ -233,14 +245,27 @@
 			eSpan = oDoc.createElement( 'span' ) ;
 			eSpan.id = oBookmark.EndId ;
-			eSpan.innerHTML = '&nbsp;' ;	// For IE, it must have something inside, otherwise it may be removed during operations.
+			eSpan.setAttribute( '_fck_bookmark', true ) ;
+
+			// For IE, it must have something inside, otherwise it may be
+			// removed during DOM operations.
+//			if ( FCKBrowserInfo.IsIE )
+				eSpan.innerHTML = '&nbsp;' ;
 
 			oClone = this.Clone() ;
 			oClone.Collapse( false ) ;
 			oClone.InsertNode( eSpan ) ;
+
+			if ( includeNodes )
+				oBookmark.EndNode = eSpan ;
 		}
 
 		eSpan = oDoc.createElement( 'span' ) ;
 		eSpan.id = oBookmark.StartId ;
-		eSpan.innerHTML = '&nbsp;' ;	// For IE, it must have something inside, otherwise it may be removed during operations.
+		eSpan.setAttribute( '_fck_bookmark', true ) ;
+
+		// For IE, it must have something inside, otherwise it may be removed
+		// during DOM operations.
+//		if ( FCKBrowserInfo.IsIE )
+			eSpan.innerHTML = '&nbsp;' ;
 
 		oClone = this.Clone() ;
@@ -248,13 +273,25 @@
 		oClone.InsertNode( eSpan ) ;
 
+		if ( includeNodes )
+			oBookmark.StartNode = eSpan ;
+
 		return oBookmark ;
 	},
 
+	// This one should be a part of a hypothetic "bookmark" object.
+	GetBookmarkNode : function( bookmark, start )
+	{
+		var doc = this.Window.document ;
+
+		if ( start )
+			return bookmark.StartNode || doc.getElementById( bookmark.StartId ) ;
+		else
+			return bookmark.EndNode || doc.getElementById( bookmark.EndId ) ;
+	},
+
 	MoveToBookmark : function( bookmark, preserveBookmark )
 	{
-		var oDoc = this.Window.document ;
-
-		var eStartSpan	=  oDoc.getElementById( bookmark.StartId ) ;
-		var eEndSpan	=  oDoc.getElementById( bookmark.EndId ) ;
+		var eStartSpan	= this.GetBookmarkNode( bookmark, true ) ;
+		var eEndSpan	= this.GetBookmarkNode( bookmark, false ) ;
 
 		this.SetStart( eStartSpan, 3 ) ;
@@ -263,5 +300,5 @@
 			FCKDomTools.RemoveNode( eStartSpan ) ;
 
-		// If collapsed, the start span will not be available.
+		// If collapsed, the end span will not be available.
 		if ( eEndSpan )
 		{
@@ -284,7 +321,7 @@
 		if ( ! this._Range )
 			return { "Start" : 0, "End" : 0 } ;
-			
+
 		// First, we record down the offset values
-		var bookmark = 
+		var bookmark =
 		{
 			"Start" : [ this._Range.startOffset ],
@@ -424,4 +461,51 @@
 		switch ( unit )
 		{
+			// Expand the range to include all inline parent elements if we are
+			// are in their boundary limits.
+			// For example (where [ ] are the range limits):
+			//	Before =>		Some <b>[<i>Some sample text]</i></b>.
+			//	After =>		Some [<b><i>Some sample text</i></b>].
+			case 'inline_elements' :
+				// Expand the start boundary.
+				if ( this._Range.startOffset == 0 )
+				{
+					oNode = this._Range.startContainer ;
+
+					if ( oNode.nodeType != 1 )
+						oNode = oNode.parentNode ;
+
+					while ( FCKListsLib.InlineNonEmptyElements[ oNode.nodeName.toLowerCase() ] )
+					{
+						this._Range.setStartBefore( oNode ) ;
+
+						if ( oNode != oNode.parentNode.firstChild )
+							break ;
+
+						oNode = oNode.parentNode ;
+					}
+				}
+
+				// Expand the end boundary.
+				oNode = this._Range.endContainer ;
+				var offset = this._Range.endOffset ;
+
+				if ( ( oNode.nodeType == 3 && offset >= oNode.nodeValue.length ) || ( oNode.nodeType == 1 && offset >= oNode.childNodes.length ) || ( oNode.nodeType != 1 && oNode.nodeType != 3 ) )
+				{
+					if ( oNode.nodeType != 1 )
+						oNode = oNode.parentNode ;
+
+					while ( FCKListsLib.InlineNonEmptyElements[ oNode.nodeName.toLowerCase() ] )
+					{
+						this._Range.setEndAfter( oNode ) ;
+
+						if ( oNode != oNode.parentNode.lastChild )
+							break ;
+
+						oNode = oNode.parentNode ;
+					}
+				}
+
+				break ;
+
 			case 'block_contents' :
 				if ( this.StartBlock )
@@ -531,10 +615,10 @@
 				if ( !eStartBlock )
 				{
-					eStartBlock = this._FixBlock( true ) ;
-					eEndBlock	= this.EndBlock ;	// _FixBlock may have fixed the EndBlock too.
+					eStartBlock = this.FixBlock( true ) ;
+					eEndBlock	= this.EndBlock ;	// FixBlock may have fixed the EndBlock too.
 				}
 
 				if ( !eEndBlock )
-					eEndBlock = this._FixBlock( false ) ;
+					eEndBlock = this.FixBlock( false ) ;
 			}
 
@@ -546,5 +630,5 @@
 				this.DeleteContents() ;
 
-			if ( eStartBlock && eEndBlock &&  eStartBlock == eEndBlock )
+			if ( eStartBlock && eEndBlock && eStartBlock == eEndBlock )
 			{
 				if ( bIsStartOfBlock )
@@ -596,5 +680,5 @@
 
 	// Transform a block without a block tag in a valid block (orphan text in the body or td, usually).
-	_FixBlock : function( isStart )
+	FixBlock : function( isStart )
 	{
 		// Bookmark the range so we can restore it later.
@@ -628,11 +712,18 @@
 			this.Window = null ;
 
+		this.StartNode = null ;
 		this.StartContainer = null ;
 		this.StartBlock = null ;
 		this.StartBlockLimit = null ;
+		this.EndNode = null ;
 		this.EndContainer = null ;
 		this.EndBlock = null ;
 		this.EndBlockLimit = null ;
 		this._Range = null ;
+	},
+
+	CheckHasRange : function()
+	{
+		return ( this._Range && true ) ;
 	}
 } ;
Index: /FCKeditor/branches/features/style/editor/_source/classes/fckdomrange_gecko.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/classes/fckdomrange_gecko.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/classes/fckdomrange_gecko.js	(revision 758)
@@ -72,2 +72,25 @@
 	}
 }
+
+// Not compatible with bookmark created with CreateBookmark2.
+// The bookmark nodes will be deleted from the document.
+FCKDomRange.prototype.SelectBookmark = function( bookmark )
+{
+	var domRange = this.Window.document.createRange() ;
+
+	var startNode	= this.GetBookmarkNode( bookmark, true ) ;
+	var endNode		= this.GetBookmarkNode( bookmark, false ) ;
+
+	domRange.setStart( startNode.parentNode, FCKDomTools.GetIndexOf( startNode ) ) ;
+	FCKDomTools.RemoveNode( startNode ) ;
+
+	if ( endNode )
+	{
+		domRange.setEnd( endNode.parentNode, FCKDomTools.GetIndexOf( endNode ) ) ;
+		FCKDomTools.RemoveNode( endNode ) ;
+	}
+	
+	var selection = this.Window.getSelection() ;
+	selection.removeAllRanges() ;
+	selection.addRange( domRange ) ;
+}
Index: /FCKeditor/branches/features/style/editor/_source/classes/fckdomrange_ie.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/classes/fckdomrange_ie.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/classes/fckdomrange_ie.js	(revision 758)
@@ -70,73 +70,85 @@
 {
 	if ( this._Range )
-	{
-		var bIsCollapsed = this.CheckIsCollapsed() ;
+		this.SelectBookmark( this.CreateBookmark( true ) ) ;
+}
 
-		// Create marker tags for the start and end boundaries.
-		var eStartMarker	= this._GetRangeMarkerTag( true ) ;
+// Not compatible with bookmark created with CreateBookmark2.
+// The bookmark nodes will be deleted from the document.
+FCKDomRange.prototype.SelectBookmark = function( bookmark )
+{
+	var bIsCollapsed = this.CheckIsCollapsed() ;
 		var bIsStartMakerAlone ;
 
-		if ( !bIsCollapsed )
-			var eEndMarker	= this._GetRangeMarkerTag( false ) ;
+	// Create marker tags for the start and end boundaries.
+	var eStartMarker	= this.GetBookmarkNode( bookmark, true ) ;
+	
+	if ( !eStartMarker )
+		return ;
 
-		// Create the main range which will be used for the selection.
-		var oIERange = this.Window.document.body.createTextRange() ;
+	var eEndMarker ;
+	if ( !bIsCollapsed )
+		eEndMarker = this.GetBookmarkNode( bookmark, false ) ;
 
-		// Position the range at the start boundary.
-		oIERange.moveToElementText( eStartMarker ) ;
-		oIERange.moveStart( 'character', 1 ) ;
+	// Create the main range which will be used for the selection.
+	var oIERange = this.Window.document.body.createTextRange() ;
 
-		if ( !bIsCollapsed )
+	// Position the range at the start boundary.
+	oIERange.moveToElementText( eStartMarker ) ;
+	oIERange.moveStart( 'character', 1 ) ;
+
+	if ( eEndMarker )
+	{
+		// Create a tool range for the end.
+		var oIERangeEnd = this.Window.document.body.createTextRange() ;
+
+		// Position the tool range at the end.
+		oIERangeEnd.moveToElementText( eEndMarker ) ;
+
+		// Move the end boundary of the main range to match the tool range.
+		oIERange.setEndPoint( 'EndToEnd', oIERangeEnd ) ;
+		oIERange.moveEnd( 'character', -1 ) ;
+	}
+	else
+		bIsStartMakerAlone = ( !eStartMarker.previousSibling || eStartMarker.previousSibling.nodeName.toLowerCase() == 'br' ) && !eStartMarker.nextSibing ;
+
+	if ( !this._Range )
+		this._Range = this.CreateRange() ;
+
+	// Remove the markers (reset the position, because of the changes in the DOM tree).
+	this._Range.setStartBefore( eStartMarker ) ;
+	eStartMarker.parentNode.removeChild( eStartMarker ) ;
+
+	if ( bIsCollapsed )
+	{
+		if ( bIsStartMakerAlone )
 		{
-			// Create a tool range for the end.
-			var oIERangeEnd = this.Window.document.body.createTextRange() ;
+			// The following trick is needed so IE makes collapsed selections
+			// inside empty blocks visible (expands the block).
 
-			// Position the tool range at the end.
-			oIERangeEnd.moveToElementText( eEndMarker ) ;
+			try
+			{
+				oIERange.pasteHTML( '&nbsp;' ) ;
+				
+				// Move the selection start to include the &nbsp;.
+				oIERange.moveStart( 'character', -1 ) ;
+			}
+			catch (e){}
 
-			// Move the end boundary of the main range to match the tool range.
-			oIERange.setEndPoint( 'EndToEnd', oIERangeEnd ) ;
-			oIERange.moveEnd( 'character', -1 ) ;
+			// The following must be done into a separate try block. (#1034)
+			try
+			{	
+				oIERange.select() ;
+				this.Window.document.selection.clear() ;
+			}
+			catch (e){}
 		}
 		else
-			bIsStartMakerAlone = ( !eStartMarker.previousSibling || eStartMarker.previousSibling.nodeName.toLowerCase() == 'br' ) && !eStartMarker.nextSibing ;
-
-		// Remove the markers (reset the position, because of the changes in the DOM tree).
-		this._Range.setStartBefore( eStartMarker ) ;
-		eStartMarker.parentNode.removeChild( eStartMarker ) ;
-
-		if ( bIsCollapsed )
-		{
-			if ( bIsStartMakerAlone )
-			{
-				// The following trick is needed so IE makes collapsed selections
-				// inside empty blocks visible (expands the block).
-
-				try
-				{
-					oIERange.pasteHTML( '&nbsp;' ) ;
-					
-					// Move the selection start to include the &nbsp;.
-					oIERange.moveStart( 'character', -1 ) ;
-				}
-				catch (e){}
-
-				// The following must be done into a separate try block. (#1034)
-				try
-				{	
-					oIERange.select() ;
-					this.Window.document.selection.clear() ;
-				}
-				catch (e){}
-			}
-			else
-				oIERange.select() ;
-		}
-		else
-		{
-			this._Range.setEndBefore( eEndMarker ) ;
-			eEndMarker.parentNode.removeChild( eEndMarker ) ;
 			oIERange.select() ;
-		}
+	}
+	else
+	{
+		this._Range.setEndBefore( eEndMarker ) ;
+		eEndMarker.parentNode.removeChild( eEndMarker ) ;
+		oIERange.select() ;
 	}
 }
@@ -175,22 +187,2 @@
 	return doc.getElementById( sMarkerId ) ;
 }
-
-FCKDomRange.prototype._GetRangeMarkerTag = function( toStart )
-{
-	// Get a range for the start boundary.
-	var oRange = this._Range ;
-
-	// insertNode() will add the node at the beginning of the Range, updating
-	// the endOffset if necessary. So, we can work with the current range in this case.
-	if ( !toStart )
-	{
-		oRange = oRange.cloneRange() ;
-		oRange.collapse( toStart === true ) ;
-	}
-
-	var eSpan = this.Window.document.createElement( 'span' ) ;
-	eSpan.innerHTML = '&nbsp;' ;
-	oRange.insertNode( eSpan ) ;
-
-	return eSpan ;
-}
Index: /FCKeditor/branches/features/style/editor/_source/classes/fckspecialcombo.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/classes/fckspecialcombo.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/classes/fckspecialcombo.js	(revision 758)
@@ -117,13 +117,13 @@
 }
 
-FCKSpecialCombo.prototype.SelectItem = function( itemId )
-{
-	itemId = itemId ? itemId.toString().toLowerCase() : '' ;
-
-	var oDiv = this.Items[ itemId ] ;
-	if ( oDiv )
-	{
-		oDiv.className = oDiv.originalClass = 'SC_ItemSelected' ;
-		oDiv.Selected = true ;
+FCKSpecialCombo.prototype.SelectItem = function( item )
+{
+	if ( typeof item == 'string' )
+		item = this.Items[ item.toString().toLowerCase() ]
+
+	if ( item )
+	{
+		item.className = item.originalClass = 'SC_ItemSelected' ;
+		item.Selected = true ;
 	}
 }
Index: /FCKeditor/branches/features/style/editor/_source/classes/fckstyle.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/classes/fckstyle.js	(revision 758)
+++ /FCKeditor/branches/features/style/editor/_source/classes/fckstyle.js	(revision 758)
@@ -0,0 +1,1121 @@
+﻿/*
+ * 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 ==
+ *
+ * FCKStyle Class: contains a style definition, and all methods to work with
+ * the style in a document.
+ */
+
+/**
+ * @param {Object} styleDesc A "style descriptor" object, containing the raw
+ * style definition in the following format:
+ *		'<style name>' : {
+ *			Element : '<element name>',
+ *			Attributes : {
+ *				'<att name>' : '<att value>',
+ *				...
+ *			},
+ *			Styles : {
+ *				'<style name>' : '<style value>',
+ *				...
+ *			},
+ *			Overrides : '<element name>'|{
+ *				Element : '<element name>',
+ *				Attributes : {
+ *					'<att name>' : '<att value>'|/<att regex>/
+ *				},
+ *				Styles : {
+ *					'<style name>' : '<style value>'|/<style regex>/
+ *				},
+ *			}
+ *		}
+ */
+var FCKStyle = function( styleDesc )
+{
+	this.Element = ( styleDesc.Element || 'span' ).toLowerCase() ;
+	this._StyleDesc = styleDesc ;
+}
+
+FCKStyle.prototype =
+{
+	/**
+	 * Get the style type, based on its element name:
+	 *		- FCK_STYLE_BLOCK  (0): Block Style
+	 *		- FCK_STYLE_INLINE (1): Inline Style
+	 *		- FCK_STYLE_OBJECT (2): Object Style
+	 */
+	GetType : function()
+	{
+		var type = this.GetType_$ ;
+
+		if ( typeof type != 'undefined' )
+			return type ;
+
+		var elementName = this.Element ;
+
+		if ( elementName == '#' || FCKListsLib.StyleBlockElements[ elementName ] )
+			type = FCK_STYLE_BLOCK ;
+		else if ( FCKListsLib.StyleObjectElements[ elementName ] )
+			type = FCK_STYLE_OBJECT ;
+		else
+			type = FCK_STYLE_INLINE ;
+
+		return ( this.GetType_$ = type ) ;
+	},
+
+	/**
+	 * Apply the style to the current selection.
+	 */
+	ApplyToSelection : function( targetWindow )
+	{
+		// Create a range for the current selection.
+		var range = new FCKDomRange( targetWindow ) ;
+		range.MoveToSelection() ;
+
+		this.ApplyToRange( range, true ) ;
+	},
+
+	/**
+	 * Apply the style to a FCKDomRange.
+	 *
+	 * TODO:
+	 *  - Implement the Object type style.
+	 */
+	ApplyToRange : function( range, selectIt )
+	{
+		switch ( this.GetType() )
+		{
+			case FCK_STYLE_BLOCK :
+				this.ApplyToRange = this._ApplyBlockStyle ;
+				break ;
+			case FCK_STYLE_INLINE :
+				this.ApplyToRange = this._ApplyInlineStyle ;
+				break ;
+			case FCK_STYLE_OBJECT :
+			default :
+				return ;
+		}
+
+		this.ApplyToRange( range, selectIt ) ;
+	},
+
+	/**
+	 * Remove the style from the current selection.
+	 */
+	RemoveFromSelection : function( targetWindow )
+	{
+		// Create a range for the current selection.
+		var range = new FCKDomRange( targetWindow ) ;
+		range.MoveToSelection() ;
+
+		this.RemoveFromRange( range, true ) ;
+	},
+
+	/**
+	 * Remove the style from a FCKDomRange. Block type styles will have no
+	 * effect.
+	 */
+	RemoveFromRange : function( range, selectIt )
+	{
+		if ( range.CheckIsCollapsed() )
+			return ;
+
+		// Expand the range, if inside inline element boundaries.
+		range.Expand( 'inline_elements' ) ;
+
+		// Create the attribute list to be used later for element comparisons.
+		var styleAttribs = this._GetAttribsForComparison() ;
+		var styleOverrides = this._GetOverridesForComparison() ;
+
+		// Get the bookmark nodes.
+		// Bookmark the range so we can re-select it after processing.
+		var bookmark = range.CreateBookmark( true ) ;
+
+		// The style will be applied within the bookmark boundaries.
+		var startNode	= range.GetBookmarkNode( bookmark, true ) ;
+		var endNode		= range.GetBookmarkNode( bookmark, false ) ;
+
+		range.Release( true ) ;
+
+		// We need to check the selection boundaries (bookmark spans) to break
+		// the code in a way that we can properly remove partially selected nodes.
+		// For example, removing a <b> style from
+		//		<b>This is [some text</b> to show <b>the] problem</b>
+		// ... where [ and ] represent the selection, must result:
+		//		<b>This is </b>[some text to show the]<b> problem</b>
+		// The strategy is simple, we just break the partial nodes before the
+		// removal logic, having something that could be represented this way:
+		//		<b>This is </b>[<b>some text</b> to show <b>the</b>]<b> problem</b>
+
+		// Let's start checking the start boundary.
+		var path = new FCKElementPath( startNode ) ;
+		var pathElements = path.Elements ;
+		var pathElement ;
+
+		for ( var i = 1 ; i < pathElements.length ; i++ )
+		{
+			pathElement = pathElements[i] ;
+
+			if ( pathElement == path.Block || pathElement == path.BlockLimit )
+				break ;
+
+			// If this element can be removed (even partially).
+			if ( this.CheckElementRemovable( pathElement ) )
+				FCKDomTools.BreakParent( startNode, pathElement, range ) ;
+		}
+
+		// Now the end boundary.
+		path = new FCKElementPath( endNode ) ;
+		pathElements = path.Elements ;
+
+		for ( var i = 1 ; i < pathElements.length ; i++ )
+		{
+			pathElement = pathElements[i] ;
+
+			if ( pathElement == path.Block || pathElement == path.BlockLimit )
+				break ;
+
+			elementName = pathElement.nodeName.toLowerCase() ;
+
+			// If this element can be removed (even partially).
+			if ( this.CheckElementRemovable( pathElement ) )
+				FCKDomTools.BreakParent( endNode, pathElement, range ) ;
+		}
+
+		// Navigate through all nodes between the bookmarks.
+		var currentNode = FCKDomTools.GetNextSourceNode( startNode, true ) ;
+
+		while ( currentNode )
+		{
+			// Cache the next node to be processed. Do it now, because
+			// currentNode may be removed.
+			var nextNode = FCKDomTools.GetNextSourceNode( currentNode ) ;
+
+			// Remove elements nodes that match with this style rules.
+			if ( currentNode.nodeType == 1 )
+			{
+				var elementName = currentNode.nodeName.toLowerCase() ;
+
+				var mayRemove = ( elementName == this.Element ) ;
+				if ( mayRemove )
+				{
+					// Remove any attribute that conflict with this style, no matter
+					// their values.
+					for ( var att in styleAttribs )
+					{
+						if ( FCKDomTools.HasAttribute( currentNode, att ) )
+							FCKDomTools.RemoveAttribute( currentNode, att ) ;
+					}
+				}
+				else
+					mayRemove = !!styleOverrides[ elementName ] ;
+
+				if ( mayRemove )
+				{
+					// Remove overrides defined to the same element name.
+					this._RemoveOverrides( currentNode, styleOverrides[ elementName ] ) ;
+
+					// Remove the element if no more attributes are available.
+					this._RemoveNoAttribElement( currentNode ) ;
+				}
+			}
+
+			// If we have reached the end of the selection, stop looping.
+			if ( nextNode == endNode )
+				break ;
+
+			currentNode = nextNode ;
+		}
+
+		this._FixBookmarkStart( startNode ) ;
+
+		// Re-select the original range.
+		if ( selectIt )
+			range.SelectBookmark( bookmark ) ;
+	},
+
+	/**
+	 * Checks if an element, or any of its attributes, is removable by the
+	 * current style definition.
+	 */
+	CheckElementRemovable : function( element )
+	{
+		var elementName = element.nodeName.toLowerCase() ;
+
+		// If the element name is the same as the style name.
+		if ( elementName == this.Element )
+		{
+			// If no attributes are defined in the element.
+			if ( !FCKDomTools.HasAttributes( element ) )
+				return true ;
+
+			// If any attribute conflicts with the style attributes.
+			var attribs = this._GetAttribsForComparison() ;
+			for ( var att in attribs )
+			{
+				if ( FCKDomTools.HasAttribute( element, att ) )
+					return true ;
+			}
+		}
+
+		// Check if the element can be somehow overriden.
+		var override = this._GetOverridesForComparison()[ elementName ] ;
+		if ( override )
+		{
+			// If no attributes have been defined, remove the element.
+			if ( !( attribs = override.Attributes ) ) // Only one "="
+				return true ;
+
+			for ( var i = 0 ; i < attribs.length ; i++ )
+			{
+				var attName = attributes[i][0] ;
+				if ( FCKDomTools.HasAttribute( element, attName ) )
+				{
+					var attValue = attributes[i][1] ;
+
+					// Remove the attribute if:
+					//    - The override definition value is null ;
+					//    - The override definition valie is a string that
+					//      matches the attribute value exactly.
+					//    - The override definition value is a regex that
+					//      has matches in the attribute value.
+					if ( attValue == null ||
+							( typeof attValue == 'string' && element.getAttribute( attName, 2 ) == attValue ) ||
+							attValue.test( element.getAttribute( attName, 2 ) ) )
+						return true ;
+				}
+			}
+		}
+
+		return false ;
+	},
+
+	/**
+	 * Get the style state for an element path. Returns "true" if the element
+	 * is active in the path.
+	 */
+	CheckActive : function( elementPath )
+	{
+		switch ( this.GetType() )
+		{
+			case FCK_STYLE_BLOCK :
+				return this.CheckElementRemovable( elementPath.Block || elementPath.BlockLimit ) ;
+
+			case FCK_STYLE_INLINE :
+
+				var elements = elementPath.Elements ;
+
+				for ( var i = 0 ; i < elements.length ; i++ )
+				{
+					var element = elements[i] ;
+
+					if ( element == elementPath.Block || element == elementPath.BlockLimit )
+						continue ;
+
+					if ( this.CheckElementRemovable( element ) )
+						return true ;
+				}
+
+				return false ;
+
+			case FCK_STYLE_OBJECT :
+			default :
+				return ;
+		}
+	},
+
+	/**
+	 * Removes an inline style from inside an element tree. The element node
+	 * itself is not checked or removed, only the child tree inside of it.
+	 */
+	RemoveFromElement : function( element )
+	{
+		var attribs = this._GetAttribsForComparison() ;
+		var overrides = this._GetOverridesForComparison() ;
+
+		// Get all elements with the same name.
+		var innerElements = element.getElementsByTagName( this.Element ) ;
+
+		for ( var i = innerElements.length - 1 ; i >= 0 ; i-- )
+		{
+			var innerElement = innerElements[i] ;
+
+			// Remove any attribute that conflict with this style, no matter
+			// their values.
+			for ( var att in attribs )
+			{
+				if ( FCKDomTools.HasAttribute( innerElement, att ) )
+					FCKDomTools.RemoveAttribute( innerElement, att ) ;
+			}
+
+			// Remove overrides defined to the same element name.
+			this._RemoveOverrides( innerElement, overrides[ this.Element ] ) ;
+
+			// Remove the element if no more attributes are available.
+			this._RemoveNoAttribElement( innerElement ) ;
+		}
+
+		// Now remove any other element with different name that is
+		// defined to be overriden.
+		for ( var overrideElement in overrides )
+		{
+			if ( overrideElement != this.Element )
+			{
+				// Get all elements.
+				innerElements = element.getElementsByTagName( overrideElement ) ;
+
+				for ( var i = innerElements.length - 1 ; i >= 0 ; i-- )
+				{
+					var innerElement = innerElements[i] ;
+					this._RemoveOverrides( innerElement, overrides[ overrideElement ] ) ;
+					this._RemoveNoAttribElement( innerElement ) ;
+				}
+			}
+		}
+	},
+
+	/**
+	 * Remove all attributes that are defined to be overriden,
+	 */
+	_RemoveOverrides : function( element, override )
+	{
+		var attributes = override && override.Attributes ;
+
+		if ( attributes )
+		{
+			for ( var i = 0 ; i < attributes.length ; i++ )
+			{
+				var attName = attributes[i][0] ;
+
+				if ( FCKDomTools.HasAttribute( element, attName ) )
+				{
+					var attValue	= attributes[i][1] ;
+
+					// Remove the attribute if:
+					//    - The override definition value is null ;
+					//    - The override definition valie is a string that
+					//      matches the attribute value exactly.
+					//    - The override definition value is a regex that
+					//      has matches in the attribute value.
+					if ( attValue == null ||
+							( typeof attValue == 'string' && element.getAttribute( attName, 2 ) == attValue ) ||
+							attValue.test( element.getAttribute( attName, 2 ) ) )
+						FCKDomTools.RemoveAttribute( element, attName ) ;
+				}
+			}
+		}
+	},
+
+	/**
+	 * If the element has no more attributes, remove it.
+	 */
+	_RemoveNoAttribElement : function( element )
+	{
+		// If no more attributes remained in the element, remove it,
+		// leaving its children.
+		if ( !FCKDomTools.HasAttributes( element ) )
+		{
+			// Removing elements may open points where merging is possible,
+			// so let's cache the first and last nodes for later checking.
+			var firstChild	= element.firstChild ;
+			var lastChild	= element.lastChild ;
+
+			FCKDomTools.RemoveNode( element, true ) ;
+
+			// Check the cached nodes for merging.
+			this._MergeSiblings( firstChild ) ;
+
+			if ( firstChild != lastChild )
+				this._MergeSiblings( lastChild ) ;
+		}
+	},
+
+	/**
+	 * Creates a DOM element for this style object.
+	 */
+	BuildElement : function( targetDoc )
+	{
+		// Create the element.
+		var el = targetDoc.createElement( this.Element ) ;
+
+		// Assign all defined attributes.
+		var attribs	= this._StyleDesc.Attributes ;
+		var attValue ;
+		if ( attribs )
+		{
+			for ( var att in attribs )
+			{
+				attValue = this.GetFinalAttributeValue( att ) ;
+
+				if ( att.toLowerCase() == 'class' )
+					el.className = attValue ;
+				else
+					el.setAttribute( att, attValue ) ;
+			}
+		}
+
+		// Assign the style attribute.
+		if ( this._GetStyleText().length > 0 )
+			el.style.cssText = this.GetFinalStyleValue() ;
+
+		return el ;
+	},
+
+	GetFinalAttributeValue : function( attName )
+	{
+		var attValue = this._StyleDesc.Attributes[ attName ] ;
+
+		if ( this._Variables )
+			// Using custom Replace() to guarantee the correct scope.
+			attValue = attValue.Replace( FCKRegexLib.StyleVariableAttName, this._GetVariableReplace, this ) ;
+
+		return attValue ;
+	},
+
+	GetFinalStyleValue : function()
+	{
+		var attValue = this._GetStyleText() ;
+
+		if ( attValue.length > 0 && this._Variables )
+			// Using custom Replace() to guarantee the correct scope.
+			attValue = attValue.Replace( FCKRegexLib.StyleVariableAttName, this._GetVariableReplace, this ) ;
+
+		return attValue ;
+	},
+
+	_GetVariableReplace : function()
+	{
+		// The second group in the regex is the variable name.
+		return this._Variables[ arguments[2] ] || arguments[0] ;
+	},
+
+	/**
+	 * Set the value of a variable attribute or style, to be used when
+	 * appliying the style.
+	 */
+	SetVariable : function( name, value )
+	{
+		var variables = this._Variables ;
+
+		if ( !variables )
+			variables = this._Variables = {} ;
+
+		this._Variables[ name ] = value ;
+	},
+
+	/**
+	 * Apply an inline style to a FCKDomRange.
+	 *
+	 * TODO
+	 *	- Properly handle <li> to block changes.
+	 *	- Implement the "#" style handling.
+	 *	- Properly handle block containers like <div> and <blockquote>.
+	 */
+	_ApplyBlockStyle : function( range, selectIt )
+	{
+		// Bookmark the range so we can re-select it after processing.
+		var bookmark = range.CreateBookmark( true ) ;
+
+		var startNode	= range.StartNode ;
+		var endNode		= range.EndNode ;
+
+		if ( !range.CheckIsCollapsed() )
+		{
+			// Get the neighborhood nodes for the bookmark <span> tags.
+			startNode	= range.GetBookmarkNode( bookmark, true ).nextSibling ;
+			endNode		= range.GetBookmarkNode( bookmark, false ).previousSibling ;
+		}
+
+		var currentNodePath = new FCKElementPath( startNode ) ;
+
+		var currentNode = currentNodePath.Block || startNode ;
+		var isLast = false ;
+
+		while ( !isLast && currentNode )
+		{
+			// Check if this is the last node to be processed.
+			isLast = ( currentNode == endNode ) ;
+
+			switch ( currentNode.nodeType )
+			{
+				case 1 :	// Element Node
+
+					var elementName = currentNode.nodeName.toLowerCase() ;
+
+					// If the node is a block node, exchange it with the new block.
+					if ( FCKListsLib.StyleBlockElements[ elementName ] != null )
+					{
+						// Create the new node right before the current one.
+						var newNode = currentNode.parentNode.insertBefore( this.BuildElement( range.Window.document ), currentNode ) ;
+
+						// Move everything from the current node to the new one.
+						FCKDomTools.MoveChildren( currentNode, newNode ) ;
+
+						// Delete the current node.
+						FCKDomTools.RemoveNode( currentNode ) ;
+
+						currentNode = newNode ;
+
+						break ;
+					}
+
+					// If it is an inline element, fell in the Text Node case.
+					if ( FCKListsLib.InlineChildReqElements[ elementName ] == null )
+						break ;
+
+				case 3 :	// Text Node
+
+					// Ignore empty text nodes.
+					if ( currentNode.nodeType == 3 && ( !currentNode.nodeValue || currentNode.nodeValue.length == 0 ) )
+						break ;
+
+					currentNodePath = new FCKElementPath( currentNode ) ;
+
+					// If the node doesn't have a parent block element, fix it with the new block.
+					if ( !currentNodePath.Block )
+					{
+						// Create a range for the current node.
+						var fixRange = new FCKDomRange( range.Window ) ;
+						fixRange.MoveToNodeContents( currentNode ) ;
+
+						// Expands it to the block contents.
+						fixRange.Expand( 'block_contents' ) ;
+
+						// Ignore empty text blocks.
+						if ( fixRange.CheckIsEmpty() )
+							break ;
+
+						// Create the fixed block.
+						var fixBlock = this.BuildElement( range.Window.document ) ;
+
+						// Move the contents of the temporary range to the fixed block.
+						fixRange.ExtractContents().AppendTo( fixBlock ) ;
+
+						// Insert the fixed block into the DOM.
+						fixRange.InsertNode( fixBlock ) ;
+
+						currentNode = fixBlock.firstChild ;
+					}
+			}
+
+			if ( !isLast )
+				currentNode = FCKDomTools.GetNextSourceNode( currentNode ) ;
+		}
+
+		// As the style system break text nodes constantly, let's normalize
+		// things for performance.
+		// With IE, some paragraphs get broken when calling normalize()
+		// repeatedly. Also, for IE, we must normalize body, not documentElement.
+		// IE is also known for having a "crash effect" with normalize().
+		// We should try to normalize with IE too in some way, somewhere.
+		if ( !FCKBrowserInfo.IsIE )
+			range.Window.document.body.normalize() ;
+
+		// Re-select the original range.
+		if ( selectIt )
+			range.SelectBookmark( bookmark ) ;
+	},
+
+	/**
+	 * Apply an inline style to a FCKDomRange.
+	 *
+	 * TODO
+	 *	- Merge elements, when applying styles to similar elements that enclose
+	 *    the entire selection, outputing:
+	 *        <span style="color: #ff0000; background-color: #ffffff">XYZ</span>
+	 *    instead of:
+	 *        <span style="color: #ff0000;"><span style="background-color: #ffffff">XYZ</span></span>
+	 */
+	_ApplyInlineStyle : function( range, selectIt )
+	{
+		// The general idea here is navigating through all nodes inside the
+		// current selection, working on distinct range blocks, defined by the
+		// DTD compatibility between the style element and the nodes inside the
+		// ranges.
+		//
+		// For example, suppose we have the following selection (where [ and ]
+		// are the boundaries), and we apply a <b> style there:
+		//
+		//		<p>Here we [have <b>some</b> text.<p>
+		//		<p>And some here] here.</p>
+		//
+		// Two different ranges will be detected:
+		//
+		//		"have <i>some</i> text."
+		//		"And some here"
+		//
+		// Both ranges will be extracted, moved to a <b> element, and
+		// re-inserted, resulting in the following output:
+		//
+		//		<p>Here we [<b>have some text.</b><p>
+		//		<p><b>And some here</b>] here.</p>
+		//
+		// Note that the <b> element at <b>some</b> is also removed because it
+		// is not needed anymore.
+
+		if ( range.CheckIsCollapsed() )
+			return ;
+
+		var elementName = this.Element ;
+
+		// Get the DTD definition for the element. Defaults to "span".
+		var elementDTD = FCK.DTD[ elementName ] || FCK.DTD.span ;
+
+		// Create the attribute list to be used later for element comparisons.
+		var styleAttribs = this._GetAttribsForComparison() ;
+		var styleNode ;
+
+		// Expand the range, if inside inline element boundaries.
+		range.Expand( 'inline_elements' ) ;
+
+		// Bookmark the range so we can re-select it after processing.
+		var bookmark = range.CreateBookmark( true ) ;
+
+		// The style will be applied within the bookmark boundaries.
+		var startNode	= range.GetBookmarkNode( bookmark, true ) ;
+		var endNode		= range.GetBookmarkNode( bookmark, false ) ;
+
+		// We'll be reusing the range to apply the styles. So, release it here
+		// to indicate that it has not been initialized.
+		range.Release( true ) ;
+
+		// Let's start the nodes lookup from the node right after the bookmark
+		// span.
+		var currentNode = FCKDomTools.GetNextSourceNode( startNode, true ) ;
+
+		while ( currentNode )
+		{
+			var applyStyle = false ;
+
+			var nodeType = currentNode.nodeType ;
+			var nodeName = nodeType == 1 ? currentNode.nodeName.toLowerCase() : null ;
+
+			// Check if the current node can be a child of the style element.
+			if ( !nodeName || elementDTD[ nodeName ] )
+			{
+				// Check if the style element can be a child of the current
+				// node parent.
+				if ( ( FCK.DTD[ currentNode.parentNode.nodeName.toLowerCase() ] || FCK.DTD.span )[ elementName ] )
+				{
+					// This node will be part of our range, so if it has not
+					// been started, place its start right before the node.
+					if ( !range.CheckHasRange() )
+						range.SetStart( currentNode, 3 ) ;
+
+					// Non element nodes, or empty elements can be added
+					// completely to the range.
+					if ( nodeType != 1 || currentNode.childNodes.length == 0 )
+					{
+						var includedNode = currentNode ;
+						var parentNode = includedNode.parentNode ;
+
+						// This node is about to be included completelly, but,
+						// if this is the last node in its parent, we must also
+						// check if the parent itself can be added completelly
+						// to the range.
+						while ( includedNode == parentNode.lastChild
+							&& FCKListsLib.InlineNonEmptyElements[ parentNode.nodeName.toLowerCase() ] )
+						{
+							includedNode = parentNode ;
+						}
+
+						range.SetEnd( includedNode, 4 ) ;
+
+						// If the included node is the last node in its parent
+						// and its parent can't be inside the style node, apply
+						// the style immediately.
+						if ( includedNode == includedNode.parentNode.lastChild && !elementDTD[ includedNode.parentNode.nodeName.toLowerCase() ] )
+							applyStyle = true ;
+					}
+					else
+					{
+						// Element nodes will not be added directly. We need to
+						// check their children because the selection could end
+						// inside the node, so let's place the range end right
+						// before the element.
+						range.SetEnd( currentNode, 3 ) ;
+					}
+				}
+				else
+					applyStyle = true ;
+			}
+			else
+				applyStyle = true ;
+
+			// Get the next node to be processed.
+			currentNode = FCKDomTools.GetNextSourceNode( currentNode ) ;
+
+			// If we have reached the end of the selection, just apply the
+			// style ot the range, and stop looping.
+			if ( currentNode == endNode )
+			{
+				currentNode = null ;
+				applyStyle = true ;
+			}
+
+			// Apply the style if we have something to which apply it.
+			if ( applyStyle && range.CheckHasRange() && !range.CheckIsCollapsed() )
+			{
+				// Build the style element, based on the style object definition.
+				styleNode = this.BuildElement( range.Window.document ) ;
+
+				// Move the contents of the range to the style element.
+				range.ExtractContents().AppendTo( styleNode ) ;
+
+				// If it is not empty.
+				if ( styleNode.innerHTML.RTrim().length > 0 )
+				{
+					// Insert it in the range position (it is collapsed after
+					// ExtractContents.
+					range.InsertNode( styleNode ) ;
+
+					// Here we do some cleanup, removing all duplicated
+					// elements from the style element.
+					this.RemoveFromElement( styleNode ) ;
+
+					// Let's merge our new style with its neighbors, if possible.
+					this._MergeSiblings( styleNode, this._GetAttribsForComparison() ) ;
+
+					// As the style system breaks text nodes constantly, let's normalize
+					// things for performance.
+					// With IE, some paragraphs get broken when calling normalize()
+					// repeatedly. Also, for IE, we must normalize body, not documentElement.
+					// IE is also known for having a "crash effect" with normalize().
+					// We should try to normalize with IE too in some way, somewhere.
+					if ( !FCKBrowserInfo.IsIE )
+						styleNode.normalize() ;
+				}
+
+				// Style applied, let's release the range, so it gets marked to
+				// re-initialization in the next loop.
+				range.Release( true ) ;
+			}
+		}
+
+		this._FixBookmarkStart( startNode ) ;
+
+		// Re-select the original range.
+		if ( selectIt )
+			range.SelectBookmark( bookmark ) ;
+	},
+
+	_FixBookmarkStart : function( startNode )
+	{
+		// After appliying or remobing an inline style, the start boundary of
+		// the selection must be placed inside all inline elements it is
+		// bordering.
+		var startSibling ;
+		while ( ( startSibling = startNode.nextSibling ) )	// Only one "=".
+		{
+			if ( startSibling.nodeType == 1
+				&& FCKListsLib.InlineNonEmptyElements[ startSibling.nodeName.toLowerCase() ] )
+			{
+				// If it is an empty inline element, we can safely remove it.
+				if ( !startSibling.firstChild )
+					FCKDomTools.RemoveNode( startSibling ) ;
+				else
+					FCKDomTools.MoveNode( startNode, startSibling, true ) ;
+				continue ;
+			}
+
+			// Empty text nodes can be safely removed to not disturb.
+			if ( startSibling.nodeType == 3 && startSibling.length == 0 )
+			{
+				FCKDomTools.RemoveNode( startSibling ) ;
+				continue ;
+			}
+
+			break ;
+		}
+	},
+
+	/**
+	 * Merge an element with its similar siblings.
+	 * "attribs" is and object computed with _CreateAttribsForComparison.
+	 */
+	_MergeSiblings : function( element, attribs )
+	{
+		if ( !element || element.nodeType != 1 || !FCKListsLib.InlineNonEmptyElements[ element.nodeName.toLowerCase() ] )
+			return ;
+
+		this._MergeNextSibling( element, attribs ) ;
+		this._MergePreviousSibling( element, attribs ) ;
+	},
+
+	/**
+	 * Merge an element with its similar siblings after it.
+	 * "attribs" is and object computed with _CreateAttribsForComparison.
+	 */
+	_MergeNextSibling : function( element, attribs )
+	{
+		// Check the next sibling.
+		var sibling = element.nextSibling ;
+
+		// Check if the next sibling is a bookmark element. In this case, jump it.
+		var hasBookmark = ( sibling && sibling.nodeType == 1 && sibling.getAttribute( '_fck_bookmark' ) ) ;
+		if ( hasBookmark )
+			sibling = sibling.nextSibling ;
+
+		if ( sibling && sibling.nodeType == 1 && sibling.nodeName == element.nodeName )
+		{
+			if ( !attribs )
+				attribs = this._CreateElementAttribsForComparison( element ) ;
+
+			if ( this._CheckAttributesMatch( sibling, attribs ) )
+			{
+				// Save the last child to be checked too (to merge things like <b><i></i></b><b><i></i></b>).
+				var innerSibling = element.lastChild ;
+
+				if ( hasBookmark )
+					FCKDomTools.MoveNode( element.nextSibling, element ) ;
+
+				// Move contents from the sibling.
+				FCKDomTools.MoveChildren( sibling, element ) ;
+				FCKDomTools.RemoveNode( sibling ) ;
+
+				// Now check the last inner child (see two comments above).
+				if ( innerSibling )
+					this._MergeNextSibling( innerSibling ) ;
+			}
+		}
+	},
+
+	/**
+	 * Merge an element with its similar siblings before it.
+	 * "attribs" is and object computed with _CreateAttribsForComparison.
+	 */
+	_MergePreviousSibling : function( element, attribs )
+	{
+		// Check the previous sibling.
+		var sibling = element.previousSibling ;
+
+		// Check if the previous sibling is a bookmark element. In this case, jump it.
+		var hasBookmark = ( sibling && sibling.nodeType == 1 && sibling.getAttribute( '_fck_bookmark' ) ) ;
+		if ( hasBookmark )
+			sibling = sibling.previousSibling ;
+
+		if ( sibling && sibling.nodeType == 1 && sibling.nodeName == element.nodeName )
+		{
+			if ( !attribs )
+				attribs = this._CreateElementAttribsForComparison( element ) ;
+
+			if ( this._CheckAttributesMatch( sibling, attribs ) )
+			{
+				// Save the first child to be checked too (to merge things like <b><i></i></b><b><i></i></b>).
+				var innerSibling = element.firstChild ;
+
+				if ( hasBookmark )
+					FCKDomTools.MoveNode( element.previousSibling, element, true ) ;
+
+				// Move contents to the sibling.
+				FCKDomTools.MoveChildren( sibling, element, true ) ;
+				FCKDomTools.RemoveNode( sibling ) ;
+
+				// Now check the first inner child (see two comments above).
+				if ( innerSibling )
+					this._MergePreviousSibling( innerSibling ) ;
+			}
+		}
+	},
+
+	/**
+	 * Build the cssText based on the styles definition.
+	 */
+	_GetStyleText : function()
+	{
+		var stylesDef = this._StyleDesc.Styles ;
+
+		// Builds the StyleText.
+		var stylesText = '' ;
+
+		for ( var style in stylesDef )
+			stylesText += style + ':' + stylesDef[style] + ';' ;
+
+		// Browsers make some changes to the style when applying them. So, here
+		// we normalize it to the browser format. We'll not do that if there
+		// are variables inside the style.
+		if ( stylesText.length > 0 && !( /#\(/.test( stylesText ) ) )
+			stylesText = FCKTools.NormalizeCssText( stylesText ) ;
+
+		return (this._GetStyleText = function() { return stylesText ; })() ;
+	},
+
+	/**
+	 * Get the the collection used to compare the attributes defined in this
+	 * style with attributes in an element. All information in it is lowercased.
+	 */
+	_GetAttribsForComparison : function()
+	{
+		// If we have already computed it, just return it.
+		var attribs = this._GetAttribsForComparison_$ ;
+		if ( attribs )
+			return attribs ;
+
+		attribs = new Object() ;
+
+		// Loop through all defined attributes.
+		var styleAttribs = this._StyleDesc.Attributes ;
+		if ( styleAttribs )
+		{
+			for ( var styleAtt in styleAttribs )
+			{
+				attribs[ styleAtt.toLowerCase() ] = styleAttribs[ styleAtt ].toLowerCase() ;
+			}
+		}
+
+		// Includes the style definitions.
+		if ( this._GetStyleText().length > 0 )
+		{
+			attribs['style'] = this._GetStyleText().toLowerCase() ;
+		}
+
+		// Appends the "length" information to the object.
+		FCKTools.AppendLengthProperty( attribs, '_length' ) ;
+
+		// Return it, saving it to the next request.
+		return ( this._GetAttribsForComparison_$ = attribs ) ;
+	},
+
+	/**
+	 * Get the the collection used to compare the elements and attributes,
+	 * defined in this style overrides, with other element. All information in
+	 * it is lowercased.
+	 */
+	_GetOverridesForComparison : function()
+	{
+		// If we have already computed it, just return it.
+		var overrides = this._GetOverridesForComparison_$ ;
+		if ( overrides )
+			return overrides ;
+
+		overrides = new Object() ;
+
+		var overridesDesc = this._StyleDesc.Overrides ;
+
+		if ( overridesDesc )
+		{
+			// The override description can be a string, object or array.
+			// Internally, well handle arrays only, so transform it if needed.
+			if ( !FCKTools.IsArray( overridesDesc ) )
+				overridesDesc = [ overridesDesc ] ;
+
+			// Loop through all override definitions.
+			for ( var i = 0 ; i < overridesDesc.length ; i++ )
+			{
+				var override = overridesDesc[i] ;
+				var elementName ;
+				var overrideEl ;
+				var attrs ;
+
+				// If can be a string with the element name.
+				if ( typeof override == 'string' )
+					elementName = override.toLowerCase() ;
+				// Or an object.
+				else
+				{
+					elementName = override.Element ? override.Element.toLowerCase() : this.Element ;
+					attrs = override.Attributes ;
+				}
+
+				// We can have more than one override definition for the same
+				// element name, so we attempt to simply append information to
+				// it if it already exists.
+				overrideEl = overrides[ elementName ] || ( overrides[ elementName ] = {} ) ;
+
+				if ( attrs )
+				{
+					// The returning attributes list is an array, because we
+					// could have different override definitions for the same
+					// attribute name.
+					var overrideAttrs = ( overrideEl.Attributes = overrideEl.Attributes || new Array() ) ;
+					for ( var attName in attrs )
+					{
+						// Each item in the attributes array is also an array,
+						// where [0] is the attribute name and [1] is the
+						// override value.
+						overrideAttrs.push( [ attName.toLowerCase(), attrs[ attName ] ] ) ;
+					}
+				}
+			}
+		}
+
+		return ( this._GetOverridesForComparison_$ = overrides ) ;
+	},
+
+	/*
+	 * Create and object containing all attributes specified in an element,
+	 * added by a "_length" property. All values are lowercased.
+	 */
+	_CreateElementAttribsForComparison : function( element )
+	{
+		var attribs = new Object() ;
+		var attribsCount = 0 ;
+
+		for ( var i = 0 ; i < element.attributes.length ; i++ )
+		{
+			var att = element.attributes[i] ;
+
+			if ( att.specified )
+			{
+				attribs[ att.nodeName.toLowerCase() ] = att.nodeValue.toLowerCase() ;
+				attribsCount++ ;
+			}
+		}
+
+		attribs._length = attribsCount ;
+
+		return attribs ;
+	},
+
+	/**
+	 * Checks is the element attributes have a perfect match with the style
+	 * attributes.
+	 */
+	_CheckAttributesMatch : function( element, styleAttribs )
+	{
+		// Loop through all specified attributes. The same number of
+		// attributes must be found and their values must match to
+		// declare them as equal.
+
+		var elementAttrbs = element.attributes ;
+		var matchCount = 0 ;
+
+		for ( var i = 0 ; i < elementAttrbs.length ; i++ )
+		{
+			var att = elementAttrbs[i] ;
+			if ( att.specified )
+			{
+				var attName = att.nodeName.toLowerCase() ;
+				var styleAtt = styleAttribs[ attName ] ;
+
+				// The attribute is not defined in the style.
+				if ( !styleAtt )
+					break ;
+
+				// The values are different.
+				if ( styleAtt != FCKDomTools.GetAttributeValue( element, att ).toLowerCase() )
+					break ;
+
+				matchCount++ ;
+			}
+		}
+
+		return ( matchCount == styleAttribs._length ) ;
+	}
+} ;
Index: /FCKeditor/branches/features/style/editor/_source/classes/fcktoolbarfontformatcombo.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/classes/fcktoolbarfontformatcombo.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/classes/fcktoolbarfontformatcombo.js	(revision 758)
@@ -24,4 +24,7 @@
 var FCKToolbarFontFormatCombo = function( tooltip, style )
 {
+	if ( tooltip === false )
+		return ;
+
 	this.CommandName = 'FontFormat' ;
 	this.Label		= this.GetLabel() ;
@@ -37,5 +40,5 @@
 
 // Inherit from FCKToolbarSpecialCombo.
-FCKToolbarFontFormatCombo.prototype = new FCKToolbarSpecialCombo ;
+FCKToolbarFontFormatCombo.prototype = new FCKToolbarStyleCombo( false ) ;
 
 FCKToolbarFontFormatCombo.prototype.TypeOf = 'FCKToolbarFontFormatCombo' ;		// @Packager.RemoveLine
@@ -46,14 +49,7 @@
 }
 
-FCKToolbarFontFormatCombo.prototype.CreateItems = function( targetSpecialCombo )
+FCKToolbarFontFormatCombo.prototype.GetStyles = function()
 {
-	var oTargetDoc = targetSpecialCombo._Panel.Document ;
-
-	// Add the Editor Area CSS to the panel to create a realistic preview.
-	FCKTools.AppendStyleSheet( oTargetDoc, FCKConfig.ToolbarComboPreviewCSS ) ;
-	FCKTools.AppendStyleString( oTargetDoc, FCKConfig.EditorAreaStyles ) ;
-
-	// Add ID and Class to the body
-	FCKConfig.ApplyBodyAttributes( oTargetDoc.body ) ;
+	var styles = {} ;
 
 	// Get the format names from the language file.
@@ -69,55 +65,72 @@
 		h5		: aNames[7],
 		h6		: aNames[8],
-		div		: aNames[9]
+		div		: aNames[9] || ( aNames[0] + ' (DIV)')
 	} ;
+	
+	// Get the available formats from the configuration file.
+	var elements = FCKConfig.FontFormats.split(';') ;
 
-	// Get the available formats from the configuration file.
-	var aTags = FCKConfig.FontFormats.split(';') ;
+	for ( var i = 0 ; i < elements.length ; i++ )
+	{
+		var elementName = elements[ i ] ;
+		var style = FCKStyles.GetStyle( '_FCK_' + elementName )
+		style.Label = oNames[ elementName ] ;
+		styles[ '_FCK_' + elementName ] = style ;
+	}
 
-	for ( var i = 0 ; i < aTags.length ; i++ )
+	return styles ;
+}
+
+FCKToolbarFontFormatCombo.prototype.RefreshActiveItems = function( targetSpecialCombo )
+{
+	var startElement = FCKSelection.GetBoundaryParentElement( true ) ;
+
+	if ( startElement )
 	{
-		// Support for DIV in Firefox has been reintroduced on version 2.2.
-//		if ( aTags[i] == 'div' && FCKBrowserInfo.IsGecko )
-//			continue ;
+		var path = new FCKElementPath( startElement ) ;
+		var blockElement = path.Block ;
 
-		var sTag	= aTags[i] ;
-		var sLabel	= oNames[sTag] ;
+		if ( blockElement )
+		{
+			for ( var i in targetSpecialCombo.Items )
+			{
+				var item = targetSpecialCombo.Items[i] ;
+				var style = item.Style ;
 
-		if ( sTag == 'p' )
-			this.NormalLabel = sLabel ;
+				if ( style.CheckElementRemovable( blockElement ) )
+				{
+					targetSpecialCombo.SetLabel( style.Label ) ;
+					return ;
+				}
+			}
+		}
+	}
 
-		this._Combo.AddItem( sTag, '<div class="BaseFont"><' + sTag + '>' + sLabel + '</' + sTag + '></div>', sLabel ) ;
+	targetSpecialCombo.SetLabel( this.DefaultLabel ) ;
+}
+
+FCKToolbarFontFormatCombo.prototype.StyleCombo_OnBeforeClick = function( targetSpecialCombo )
+{
+	// Clear the current selection.
+	targetSpecialCombo.DeselectAll() ;
+
+	var startElement = FCKSelection.GetBoundaryParentElement( true ) ;
+
+	if ( startElement )
+	{
+		var path = new FCKElementPath( startElement ) ;
+		var blockElement = path.Block ;
+
+		for ( var i in targetSpecialCombo.Items )
+		{
+			var item = targetSpecialCombo.Items[i] ;
+			var style = item.Style ;
+
+			if ( style.CheckElementRemovable( blockElement ) )
+			{
+				targetSpecialCombo.SelectItem( item ) ;
+				return ;
+			}
+		}
 	}
 }
-
-if ( FCKBrowserInfo.IsIE )
-{
-	FCKToolbarFontFormatCombo.prototype.RefreshActiveItems = function( combo, value )
-	{
-//		FCKDebug.Output( 'FCKToolbarFontFormatCombo Value: ' + value ) ;
-
-		// IE returns normal for DIV and P, so to avoid confusion, we will not show it as normal.
-		if ( value == this.NormalLabel )
-		{
-			if ( combo.Label != '&nbsp;' )
-				combo.DeselectAll(true) ;
-				
-			combo.SetLabel( this.DefaultLabel ) ;
-		}
-		else
-		{
-			if ( this._LastValue == value )
-				return ;
-
-			if ( !value || value.length == 0 )
-			{
-				combo.DeselectAll() ;
-				combo.SetLabel( this.DefaultLabel ) ;
-			}
-			
-			combo.SelectItemByLabel( value, true ) ;
-		}
-
-		this._LastValue = value ;
-	}
-}
Index: /FCKeditor/branches/features/style/editor/_source/classes/fcktoolbarfontscombo.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/classes/fcktoolbarfontscombo.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/classes/fcktoolbarfontscombo.js	(revision 758)
@@ -28,10 +28,10 @@
 	this.Tooltip	= tooltip ? tooltip : this.Label ;
 	this.Style		= style ? style : FCK_TOOLBARITEM_ICONTEXT ;
-	
+
 	this.DefaultLabel = FCKConfig.DefaultFontLabel || '' ;
 }
 
 // Inherit from FCKToolbarSpecialCombo.
-FCKToolbarFontsCombo.prototype = new FCKToolbarSpecialCombo ;
+FCKToolbarFontsCombo.prototype = new FCKToolbarFontFormatCombo( false ) ;
 
 FCKToolbarFontsCombo.prototype.TypeOf = 'FCKToolbarFontsCombo' ;		// @Packager.RemoveLine
@@ -42,9 +42,45 @@
 }
 
-FCKToolbarFontsCombo.prototype.CreateItems = function( targetSpecialCombo )
+FCKToolbarFontFormatCombo.prototype.GetStyles = function()
 {
-	var aFonts = FCKConfig.FontNames.split(';') ;
+	var baseStyle = FCKStyles.GetStyle( '_FCK_FontFace' ) ;
 
-	for ( var i = 0 ; i < aFonts.length ; i++ )
-		this._Combo.AddItem( aFonts[i], '<font face="' + aFonts[i] + '" style="font-size: 12px">' + aFonts[i] + '</font>' ) ;
+	var styles = {} ;
+
+	var fonts = FCKConfig.FontNames.split(';') ;
+
+	for ( var i = 0 ; i < fonts.length ; i++ )
+	{
+		var fontParts = fonts[i].split('/') ;
+		var font = fontParts[0] ;
+		var caption = fontParts[1] || font ;
+
+		var style = FCKTools.CloneObject( baseStyle ) ;
+		style.SetVariable( 'Font', font ) ;
+		style.Label = caption ;
+
+		styles[ caption ] = style ;
+	}
+
+	return styles ;
 }
+
+//FCKToolbarFontsCombo.prototype.CreateItems = function( targetSpecialCombo )
+//{
+//	var style = FCKStyles.GetStyle( '_FCK_FontFace' ) ;
+
+//	var fonts = FCKConfig.FontNames.split(';') ;
+
+//	for ( var i = 0 ; i < fonts.length ; i++ )
+//	{
+//		var fontParts = fonts[i].split('/') ;
+//		var font = fontParts[0] ;
+//		var caption = fontParts[1] || font ;
+
+//		style.SetVariable( 'Font', font ) ;
+
+//		this._Combo.AddItem( font, '<span style="font-size: 12px">' + FCKToolbarStyleCombo_BuildPreview( style, caption ) + '</span>', caption ) ;
+//	}
+//}
+
+//FCKToolbarFontsCombo.prototype.RefreshActiveItems = FCKToolbarFontFormatCombo.prototype.RefreshActiveItems ;
Index: /FCKeditor/branches/features/style/editor/_source/classes/fcktoolbarfontsizecombo.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/classes/fcktoolbarfontsizecombo.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/classes/fcktoolbarfontsizecombo.js	(revision 758)
@@ -44,12 +44,19 @@
 FCKToolbarFontSizeCombo.prototype.CreateItems = function( targetSpecialCombo )
 {
+	var style = FCKStyles.GetStyle( '_FCK_Size' ) ;
+
 	targetSpecialCombo.FieldWidth = 70 ;
 
-	var aSizes = FCKConfig.FontSizes.split(';') ;
+	var sizes = FCKConfig.FontSizes.split(';') ;
 
-	for ( var i = 0 ; i < aSizes.length ; i++ )
+	for ( var i = 0 ; i < sizes.length ; i++ )
 	{
-		var aSizeParts = aSizes[i].split('/') ;
-		this._Combo.AddItem( aSizeParts[0], '<font size="' + aSizeParts[0] + '">' + aSizeParts[1] + '</font>', aSizeParts[1] ) ;
+		var sizeParts = sizes[i].split('/') ;
+		var size = sizeParts[0] ;
+		var caption = sizeParts[1] || size ;
+
+		style.SetVariable( 'Size', size ) ;
+		
+		this._Combo.AddItem( size, FCKToolbarStyleCombo_BuildPreview( style, caption ), caption ) ;
 	}
 }
Index: /FCKeditor/branches/features/style/editor/_source/classes/fcktoolbarstylecombo.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/classes/fcktoolbarstylecombo.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/classes/fcktoolbarstylecombo.js	(revision 758)
@@ -24,9 +24,12 @@
 var FCKToolbarStyleCombo = function( tooltip, style )
 {
+	if ( tooltip === false )
+		return ;
+
 	this.CommandName = 'Style' ;
 	this.Label		= this.GetLabel() ;
 	this.Tooltip	= tooltip ? tooltip : this.Label ;
 	this.Style		= style ? style : FCK_TOOLBARITEM_ICONTEXT ;
-	
+
 	this.DefaultLabel = FCKConfig.DefaultStyleLabel || '' ;
 }
@@ -42,70 +45,156 @@
 }
 
+FCKToolbarStyleCombo.prototype.GetStyles = function()
+{
+	var styles = {} ;
+	var allStyles = FCK.ToolbarSet.CurrentInstance.Styles.GetStyles() ;
+
+	for ( var styleName in allStyles )
+	{
+		var style = allStyles[ styleName ] ;
+		if ( !style.IsCore )
+			styles[ styleName ] = style ;
+	}
+	return styles ;
+}
+
 FCKToolbarStyleCombo.prototype.CreateItems = function( targetSpecialCombo )
 {
-	var oTargetDoc = targetSpecialCombo._Panel.Document ;
+	var targetDoc = targetSpecialCombo._Panel.Document ;
 
 	// Add the Editor Area CSS to the panel so the style classes are previewed correctly.
-	FCKTools.AppendStyleSheet( oTargetDoc, FCKConfig.ToolbarComboPreviewCSS ) ;
-	FCKTools.AppendStyleString( oTargetDoc, FCKConfig.EditorAreaStyles ) ;
-	oTargetDoc.body.className += ' ForceBaseFont' ;
-
-	// Add ID and Class to the body
-	FCKConfig.ApplyBodyAttributes( oTargetDoc.body ) ;
-
-	// For some reason Gecko is blocking inside the "RefreshVisibleItems" function.
-	// The problem is present only in old versions
-	if ( !( FCKBrowserInfo.IsGecko && FCKBrowserInfo.IsGecko10 ) )
-		targetSpecialCombo.OnBeforeClick = this.RefreshVisibleItems ;
-
-	// Add the styles to the special combo.
-	var aCommandStyles = FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( this.CommandName ).Styles ;
-	for ( var s in aCommandStyles )
-	{
-		var oStyle = aCommandStyles[s] ;
-		var oItem ;
-
-		if ( oStyle.IsObjectElement )
-			oItem = targetSpecialCombo.AddItem( s, s ) ;
+	FCKTools.AppendStyleSheet( targetDoc, FCKConfig.ToolbarComboPreviewCSS ) ;
+	FCKTools.AppendStyleString( targetDoc, FCKConfig.EditorAreaStyles ) ;
+	targetDoc.body.className += ' ForceBaseFont' ;
+
+	// Add ID and Class to the body.
+	FCKConfig.ApplyBodyAttributes( targetDoc.body ) ;
+
+	// Get the styles list.
+	var styles = this.GetStyles() ;
+
+	for ( var styleName in styles )
+	{
+		var style = styles[ styleName ] ;
+
+		// Object type styles have no preview.
+		var caption = style.GetType() == FCK_STYLE_OBJECT ? 
+			styleName : 
+			FCKToolbarStyleCombo_BuildPreview( style, style.Label || styleName ) ;
+	
+		var item = targetSpecialCombo.AddItem( styleName, caption ) ;
+
+		item.Style = style ;
+	}
+
+	// We must prepare the list before showing it.
+	targetSpecialCombo.OnBeforeClick = this.StyleCombo_OnBeforeClick ;
+}
+
+FCKToolbarStyleCombo.prototype.RefreshActiveItems = function( targetSpecialCombo )
+{
+	var startElement = FCKSelection.GetBoundaryParentElement( true ) ;
+
+	if ( startElement )
+	{
+		var path = new FCKElementPath( startElement ) ;
+		var elements = path.Elements ;
+
+		for ( var e = 0 ; e < elements.length ; e++ )
+		{
+			for ( var i in targetSpecialCombo.Items )
+			{
+				var item = targetSpecialCombo.Items[i] ;
+				var style = item.Style ;
+
+				if ( style.CheckElementRemovable( elements[ e ] ) )
+				{
+					targetSpecialCombo.SetLabel( style.Label || style.Name ) ;
+					return ;
+				}
+			}
+		}
+	}
+
+	targetSpecialCombo.SetLabel( this.DefaultLabel ) ;
+}
+
+FCKToolbarStyleCombo.prototype.StyleCombo_OnBeforeClick = function( targetSpecialCombo )
+{
+	// Two things are done here:
+	//	- In a control selection, get the element name, so we'll display styles
+	//	  for that element only.
+	//	- Select the styles that are active for the current selection.
+	
+	// Clear the current selection.
+	targetSpecialCombo.DeselectAll() ;
+
+	var startElement ;
+	var path ;
+	var tagName ;
+	
+	if ( FCKSelection.GetType() == 'Control' )
+	{
+		startElement = FCKSelection.GetSelectedElement() ;
+		tagName = startElement.nodeName.toLowerCase() ;
+	}
+	else
+	{
+		startElement = FCKSelection.GetBoundaryParentElement( true ) ;
+		path = new FCKElementPath( startElement ) ;
+	}
+
+	for ( var i in targetSpecialCombo.Items )
+	{
+		var item = targetSpecialCombo.Items[i] ;
+		var style = item.Style ;
+		
+		if ( ( tagName && style.Element == tagName ) || ( !tagName && style.GetType() != FCK_STYLE_OBJECT ) )
+		{
+			item.style.display = '' ;
+
+			if ( ( path && style.CheckActive( path ) ) || ( !path && style.CheckElementRemovable( startElement ) ) )
+				targetSpecialCombo.SelectItem( style.Name ) ;
+		}
 		else
-			oItem = targetSpecialCombo.AddItem( s, oStyle.GetOpenerTag() + s + oStyle.GetCloserTag() ) ;
-
-		oItem.Style = oStyle ;
-	}
-}
-
-FCKToolbarStyleCombo.prototype.RefreshActiveItems = function( targetSpecialCombo )
-{
-	// Clear the actual selection.
-	targetSpecialCombo.DeselectAll() ;
-
-	// Get the active styles.
-	var aStyles = FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( this.CommandName ).GetActiveStyles() ;
-
-	if ( aStyles.length > 0 )
-	{
-		// Select the active styles in the combo.
-		for ( var i = 0 ; i < aStyles.length ; i++ )
-			targetSpecialCombo.SelectItem( aStyles[i].Name ) ;
-
-		// Set the combo label to the first style in the collection.
-		targetSpecialCombo.SetLabelById( aStyles[0].Name ) ;
-	}
-	else
-		targetSpecialCombo.SetLabel(this.DefaultLabel) ;
-}
-
-FCKToolbarStyleCombo.prototype.RefreshVisibleItems = function( targetSpecialCombo )
-{
-	if ( FCKSelection.GetType() == 'Control' )
-		var sTagName = FCKSelection.GetSelectedElement().tagName ;
-
-	for ( var i in targetSpecialCombo.Items )
-	{
-		var oItem = targetSpecialCombo.Items[i] ;
-		if ( ( sTagName && oItem.Style.Element == sTagName ) || ( ! sTagName && ! oItem.Style.IsObjectElement ) )
-			oItem.style.display = '' ;
-		else
-			oItem.style.display = 'none' ;	// For some reason Gecko is blocking here.
-	}
-}
+			item.style.display = 'none' ;
+	}
+}
+
+function FCKToolbarStyleCombo_BuildPreview( style, caption ) 
+{
+	var styleType = style.GetType() ;
+	var html = [] ;
+	
+	if ( styleType == FCK_STYLE_BLOCK )
+		html.push( '<div class="BaseFont">' ) ;
+	
+	var elementName = style.Element ;
+	
+	// Avoid <bdo> in the preview.
+	if ( elementName == 'bdo' )
+		elementName = 'span' ;
+
+	html = [ '<', elementName ] ;
+
+	// Assign all defined attributes.
+	var attribs	= style._StyleDesc.Attributes ;
+	if ( attribs )
+	{
+		for ( var att in attribs )
+		{
+			html.push( ' ', att, '="', style.GetFinalAttributeValue( att ), '"' ) ;
+		}
+	}
+
+	// Assign the style attribute.
+	if ( style._GetStyleText().length > 0 )
+		html.push( ' style="', style.GetFinalStyleValue(), '"' ) ;
+
+	html.push( '>', caption, '</', elementName, '>' ) ;
+
+	if ( styleType == FCK_STYLE_BLOCK )
+		html.push( '</div>' ) ;
+
+	return html.join( '' ) ;
+}
Index: /FCKeditor/branches/features/style/editor/_source/classes/fckw3crange.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/classes/fckw3crange.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/classes/fckw3crange.js	(revision 758)
@@ -419,5 +419,14 @@
 			// topStart and topEnd. Otherwise, simply collapse it to the start. (W3C specs).
 			if ( topStart && topEnd && ( startNode.parentNode != topStart.parentNode || endNode.parentNode != topEnd.parentNode ) )
-				this.setStart( topEnd.parentNode, FCKDomTools.GetIndexOf( topEnd ) ) ;
+			{
+				var endIndex = FCKDomTools.GetIndexOf( topEnd ) ;
+				
+				// If the start node is to be removed, we must correct the
+				// index to reflect the removal.
+				if ( removeStartNode && topEnd.parentNode == startNode.parentNode )
+					endIndex-- ;
+
+				this.setStart( topEnd.parentNode, endIndex ) ;
+			}
 
 			// Collapse it to the start.
Index: /FCKeditor/branches/features/style/editor/_source/classes/fckxml_gecko.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/classes/fckxml_gecko.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/classes/fckxml_gecko.js	(revision 758)
@@ -86,2 +86,8 @@
 		return null ;
 }
+
+FCKXml.GetAttribute = function( node, attName, defaultValue )
+{
+	var attNode = node.attributes.getNamedItem( attName ) ;
+	return attNode ? attNode.value : defaultValue ;
+}
Index: /FCKeditor/branches/features/style/editor/_source/classes/fckxml_ie.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/classes/fckxml_ie.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/classes/fckxml_ie.js	(revision 758)
@@ -89,2 +89,8 @@
 		return this.DOMDocument.selectSingleNode( xpath ) ;
 }
+
+FCKXml.GetAttribute = function( node, attName, defaultValue )
+{
+	var attNode = node.attributes.getNamedItem( attName ) ;
+	return attNode ? attNode.value : defaultValue ;
+}
Index: /FCKeditor/branches/features/style/editor/_source/commandclasses/fck_othercommands.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/commandclasses/fck_othercommands.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/commandclasses/fck_othercommands.js	(revision 758)
@@ -68,85 +68,65 @@
 
 // ### FontName
+
 var FCKFontNameCommand = function()
-{
-	this.Name = 'FontName' ;
-}
-
-FCKFontNameCommand.prototype.Execute = function( fontName )
-{
-	if (fontName == null || fontName == "")
-	{
-		// TODO: Remove font name attribute.
-		/*jsl:pass*/ // @Packager.RemoveLine
-	}
-	else
-		FCK.ExecuteNamedCommand( 'FontName', fontName ) ;
-}
-
-FCKFontNameCommand.prototype.GetState = function()
-{
-	var value = FCK.GetNamedCommandValue( 'FontName' ) ;
-	if (value && value.charAt( 0 ) == "'" && value.charAt( value.length - 1 ) == "'")
-		value = value.slice( 1, -1 ) ;
-	return value ;
-}
+{}
+
+FCKFontNameCommand.prototype = 
+{
+	Name : 'FontName',
+	
+	Execute : function( fontName )
+	{
+		var style = FCKStyles.GetStyle( '_FCK_FontFace' ) ;
+
+		style.SetVariable( 'Font', fontName ) ;
+
+		FCKStyles.ApplyStyle( style ) ;
+	},
+	
+	GetState : function()
+	{
+		return FCK.EditorDocument ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
+	}
+};
 
 // ### FontSize
 var FCKFontSizeCommand = function()
-{
-	this.Name = 'FontSize' ;
-}
-
-FCKFontSizeCommand.prototype.Execute = function( fontSize )
-{
-	if ( typeof( fontSize ) == 'string' ) fontSize = parseInt(fontSize, 10) ;
-
-	// If user wants the font size cleared, we have to find
-	// where the font size tag is and go clear it (if there's one)
-	if ( !fontSize )
-	{
-		var oFont = FCK.Selection.MoveToAncestorNode('FONT');
-		if ( oFont && oFont.getAttribute("size") )
-		{
-			//if the only thing here is SIZE, collapse the whole tag
-			if (oFont.attributes.length == 1 ||
-				(oFont.outerHTML && oFont.outerHTML.search(/<FONT size=["]*\d["]*>/i)))
-			{
-				FCKTools.RemoveOuterTags(oFont);
-			}
-			else
-				oFont.removeAttribute("size");
-		}	
-
-	}
-	else
-		FCK.ExecuteNamedCommand( 'FontSize', fontSize ) ;
-}
-
-FCKFontSizeCommand.prototype.GetState = function()
-{
-	return FCK.GetNamedCommandValue( 'FontSize' ) ;
-}
+{}
+
+FCKFontSizeCommand.prototype = 
+{
+	Name : 'FontSize',
+	
+	Execute : function( fontSize )
+	{
+		var style = FCKStyles.GetStyle( '_FCK_Size' ) ;
+
+		style.SetVariable( 'Size', fontSize ) ;
+
+		FCKStyles.ApplyStyle( style ) ;
+	},
+	
+	GetState : function()
+	{
+		return FCK.EditorDocument ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
+	}
+};
 
 // ### FormatBlock
 var FCKFormatBlockCommand = function()
-{
-	this.Name = 'FormatBlock' ;
-}
-
-FCKFormatBlockCommand.prototype.Execute = function( formatName )
-{
-	if ( formatName == null || formatName == '' )
-		FCK.ExecuteNamedCommand( 'FormatBlock', '<P>' ) ;
-	else if ( formatName == 'div' && FCKBrowserInfo.IsGecko )
-		FCK.ExecuteNamedCommand( 'FormatBlock', 'div' ) ;
-	else
-		FCK.ExecuteNamedCommand( 'FormatBlock', '<' + formatName + '>' ) ;
-}
-
-FCKFormatBlockCommand.prototype.GetState = function()
-{
-	return FCK.GetNamedCommandValue( 'FormatBlock' ) ;
-}
+{}
+
+FCKFormatBlockCommand.prototype = 
+{
+	Name : 'FormatBlock',
+	
+	Execute : FCKStyleCommand.prototype.Execute,
+	
+	GetState : function()
+	{
+		return FCK.EditorDocument ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
+	}
+};
 
 // ### Preview
Index: /FCKeditor/branches/features/style/editor/_source/commandclasses/fckcorestylecommand.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/commandclasses/fckcorestylecommand.js	(revision 758)
+++ /FCKeditor/branches/features/style/editor/_source/commandclasses/fckcorestylecommand.js	(revision 758)
@@ -0,0 +1,54 @@
+﻿/*
+ * 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 ==
+ *
+ * FCKCoreStyleCommand Class: controls the execution of a core style. Core
+ * styles are usually represented as buttons in the toolbar., like Bold and
+ * Italic.
+ */
+ 
+ var FCKCoreStyleCommand = function( coreStyleName )
+ {
+ 	this.Name = 'CoreStyle' ;
+ 	this.StyleName = '_FCK_' + coreStyleName ;
+ 	this.IsActive = false ;
+ 	
+ 	FCKStyles.AttachStyleStateChange( this.StyleName, this._OnStyleStateChange, this ) ;
+ }
+ 
+ FCKCoreStyleCommand.prototype = 
+ {
+	Execute : function()
+	{
+		if ( this.IsActive )
+			FCKStyles.RemoveStyle( this.StyleName ) ;
+		else
+			FCKStyles.ApplyStyle( this.StyleName ) ;
+	},
+	
+	GetState : function()
+	{
+		return this.IsActive ? FCK_TRISTATE_ON : FCK_TRISTATE_OFF ;
+	},
+	
+	_OnStyleStateChange : function( styleName, isActive )
+	{
+		this.IsActive = isActive ;
+	}
+ };
Index: /FCKeditor/branches/features/style/editor/_source/commandclasses/fckremoveformatcommand.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/commandclasses/fckremoveformatcommand.js	(revision 758)
+++ /FCKeditor/branches/features/style/editor/_source/commandclasses/fckremoveformatcommand.js	(revision 758)
@@ -0,0 +1,42 @@
+﻿/*
+ * 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 ==
+ *
+ * FCKRemoveFormatCommand Class: controls the execution of a core style. Core
+ * styles are usually represented as buttons in the toolbar., like Bold and
+ * Italic.
+ */
+ 
+ var FCKRemoveFormatCommand = function()
+ {
+ 	this.Name = 'RemoveFormat' ;
+ }
+ 
+ FCKRemoveFormatCommand.prototype = 
+ {
+	Execute : function()
+	{
+		FCKStyles.RemoveAll() ;
+	},
+	
+	GetState : function()
+	{
+		return FCK.EditorWindow ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
+	}
+ };
Index: /FCKeditor/branches/features/style/editor/_source/commandclasses/fckstylecommand.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/commandclasses/fckstylecommand.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/commandclasses/fckstylecommand.js	(revision 758)
@@ -23,77 +23,39 @@
 
 var FCKStyleCommand = function()
+{}
+
+FCKStyleCommand.prototype =
 {
-	this.Name = 'Style' ;
+	Name : 'Style',
+	
+	Execute : function( styleName, styleComboItem )
+	{
+		FCKUndo.SaveUndoStep() ;
 
-	// Load the Styles defined in the XML file.
-	this.StylesLoader = new FCKStylesLoader() ;
-	this.StylesLoader.Load( FCKConfig.StylesXmlPath ) ;
-	this.Styles = this.StylesLoader.Styles ;
-}
+		if ( styleComboItem.Selected )
+			FCK.Styles.RemoveStyle( styleComboItem.Style ) ;
+		else
+			FCK.Styles.ApplyStyle( styleComboItem.Style ) ;
 
-FCKStyleCommand.prototype.Execute = function( styleName, styleComboItem )
-{
-	FCKUndo.SaveUndoStep() ;
+		FCKUndo.SaveUndoStep() ;
 
-	if ( styleComboItem.Selected )
-		styleComboItem.Style.RemoveFromSelection() ;
-	else
-		styleComboItem.Style.ApplyToSelection() ;
+		FCK.Focus() ;
 
-	FCKUndo.SaveUndoStep() ;
+		FCK.Events.FireEvent( 'OnSelectionChange' ) ;
+	},
 
-	FCK.Focus() ;
+	GetState : function()
+	{
+		if ( !FCK.EditorDocument )
+			return FCK_TRISTATE_DISABLED ;
 
-	FCK.Events.FireEvent( "OnSelectionChange" ) ;
-}
+		if ( FCKSelection.GetType() == 'Control' )
+		{
+			var el = FCKSelection.GetSelectedElement() ;
+			if ( !el || !FCKStyles.CheckHasObjectStyle( el.nodeName.toLowerCase() ) )
+				return FCK_TRISTATE_DISABLED ;
+		}
 
-FCKStyleCommand.prototype.GetState = function()
-{
-	if ( !FCK.EditorDocument )
-		return FCK_TRISTATE_DISABLED ;
-
-	var oSelection = FCK.EditorDocument.selection ;
-
-	if ( FCKSelection.GetType() == 'Control' )
-	{
-		var e = FCKSelection.GetSelectedElement() ;
-		if ( e )
-			return this.StylesLoader.StyleGroups[ e.tagName ] ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
+		return FCK_TRISTATE_OFF ;
 	}
-
-	return FCK_TRISTATE_OFF ;
-}
-
-FCKStyleCommand.prototype.GetActiveStyles = function()
-{
-	var aActiveStyles = new Array() ;
-
-	if ( FCKSelection.GetType() == 'Control' )
-		this._CheckStyle( FCKSelection.GetSelectedElement(), aActiveStyles, false ) ;
-	else
-		this._CheckStyle( FCKSelection.GetParentElement(), aActiveStyles, true ) ;
-
-	return aActiveStyles ;
-}
-
-FCKStyleCommand.prototype._CheckStyle = function( element, targetArray, checkParent )
-{
-	if ( ! element )
-		return ;
-
-	if ( element.nodeType == 1 )
-	{
-		var aStyleGroup = this.StylesLoader.StyleGroups[ element.tagName ] ;
-		if ( aStyleGroup )
-		{
-			for ( var i = 0 ; i < aStyleGroup.length ; i++ )
-			{
-				if ( aStyleGroup[i].IsEqual( element ) )
-					targetArray[ targetArray.length ] = aStyleGroup[i] ;
-			}
-		}
-	}
-
-	if ( checkParent )
-		this._CheckStyle( element.parentNode, targetArray, checkParent ) ;
-}
+};
Index: /FCKeditor/branches/features/style/editor/_source/commandclasses/fcktextcolorcommand.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/commandclasses/fcktextcolorcommand.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/commandclasses/fcktextcolorcommand.js	(revision 758)
@@ -58,18 +58,10 @@
 FCKTextColorCommand.prototype.SetColor = function( color )
 {
-	if ( FCK._ActiveColorPanelType == 'ForeColor' )
-		FCK.ExecuteNamedCommand( 'ForeColor', color ) ;
-	else if ( FCKBrowserInfo.IsGeckoLike )
-	{
-		if ( FCKBrowserInfo.IsGecko && !FCKConfig.GeckoUseSPAN )
-			FCK.EditorDocument.execCommand( 'useCSS', false, false ) ;
+	var style = FCKStyles.GetStyle( '_FCK_' + 
+		( FCK._ActiveColorPanelType == 'ForeColor' ? 'Color' : 'BackColor' ) ) ;
 
-		FCK.ExecuteNamedCommand( 'hilitecolor', color ) ;
+	style.SetVariable( 'Color', color ) ;
 
-		if ( FCKBrowserInfo.IsGecko && !FCKConfig.GeckoUseSPAN )
-			FCK.EditorDocument.execCommand( 'useCSS', false, true ) ;
-	}
-	else
-		FCK.ExecuteNamedCommand( 'BackColor', color ) ;
+	FCKStyles.ApplyStyle( style ) ;
 
 	// Delete the "cached" active panel type.
Index: /FCKeditor/branches/features/style/editor/_source/fckconstants.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/fckconstants.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/fckconstants.js	(revision 758)
@@ -51,2 +51,6 @@
 var SHIFT	= 2000 ;
 var ALT		= 4000 ;
+
+var FCK_STYLE_BLOCK		= 0 ;
+var FCK_STYLE_INLINE	= 1 ;
+var FCK_STYLE_OBJECT	= 2 ;
Index: /FCKeditor/branches/features/style/editor/_source/fckjscoreextensions.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/fckjscoreextensions.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/fckjscoreextensions.js	(revision 758)
@@ -135,4 +135,19 @@
 }
 
+String.prototype.Replace = function( regExp, replacement, thisObj )
+{
+	if ( typeof replacement == 'function' )
+	{
+		return this.replace( regExp, 
+			function() 
+			{ 
+				return replacement.apply( thisObj || this, arguments ) ; 
+			} 
+		) ;
+	}
+	else
+		return this.replace( regExp, replacement ) ;
+}
+
 Array.prototype.AddItem = function( item )
 {
Index: /FCKeditor/branches/features/style/editor/_source/fckscriptloader.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/fckscriptloader.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/fckscriptloader.js	(revision 758)
@@ -93,4 +93,6 @@
 FCKScriptLoader.AddScript( 'FCKJSCoreExtensions' ) ;
 
+FCKScriptLoader.AddScript( 'FCK_Xhtml10Transitional', '../dtd/' ) ;
+
 FCKScriptLoader.AddScript( 'FCKDataProcessor'	, 'classes/'	, ['FCKConfig','FCKBrowserInfo','FCKRegexLib','FCKXHtml'] ) ;
 FCKScriptLoader.AddScript( 'FCKDocumentFragment', 'classes/'	, ['FCKDomTools'], FCK_SPECIFIC ) ;
@@ -100,4 +102,5 @@
 FCKScriptLoader.AddScript( 'FCKImagePreloader'	, 'classes/' ) ;
 FCKScriptLoader.AddScript( 'FCKKeystrokeHandler', 'classes/'	, ['FCKConstants','FCKBrowserInfo','FCKTools'], FCK_GENERIC ) ;
+FCKScriptLoader.AddScript( 'FCKStyle'			, 'classes/'	, ['FCKConstants','FCKDomRange','FCKDomTools','FCKListsLib','FCK_Xhtml10Transitional'], FCK_GENERIC ) ;
 FCKScriptLoader.AddScript( 'FCKW3CRange'		, 'classes/'	, ['FCKDomTools','FCKTools','FCKDocumentFragment'], FCK_GENERIC ) ;
 
@@ -106,8 +109,9 @@
 FCKScriptLoader.AddScript( 'FCKConfig'			, 'internals/'	, ['FCKBrowserInfo','FCKConstants'] ) ;
 FCKScriptLoader.AddScript( 'FCKDebug'			, 'internals/'	, ['FCKConfig'] ) ;
-FCKScriptLoader.AddScript( 'FCKDomTools'		, 'internals/'	, ['FCKJSCoreExtensions'], FCK_GENERIC ) ;
+FCKScriptLoader.AddScript( 'FCKDomTools'		, 'internals/'	, ['FCKJSCoreExtensions','FCKBrowserInfo','FCKTools'], FCK_GENERIC ) ;
 FCKScriptLoader.AddScript( 'FCKListsLib'		, 'internals/' ) ;
-FCKScriptLoader.AddScript( 'FCKListHandler'		, 'internals/'	, ['FCKConfig', 'FCKDocumentFragment', 'FCKJSCoreExtensions','FCKDomTools','FCKTools'], FCK_GENERIC ) ;
+FCKScriptLoader.AddScript( 'FCKListHandler'		, 'internals/'	, ['FCKConfig', 'FCKDocumentFragment', 'FCKJSCoreExtensions','FCKDomTools'], FCK_GENERIC ) ;
 FCKScriptLoader.AddScript( 'FCKRegexLib'		, 'internals/' ) ;
+FCKScriptLoader.AddScript( 'FCKStyles'			, 'internals/'	, ['FCKConfig', 'FCKDocumentFragment', 'FCKDomRange','FCKDomTools','FCKElementPath','FCKTools'], FCK_GENERIC ) ;
 FCKScriptLoader.AddScript( 'FCKTools'			, 'internals/'	, ['FCKJSCoreExtensions','FCKBrowserInfo'], FCK_GENERIC_SPECIFIC ) ;
 FCKScriptLoader.AddScript( 'FCKXHtml'			, 'internals/'	, ['FCKBrowserInfo','FCKCodeFormatter','FCKConfig','FCKDomTools','FCKListsLib','FCKRegexLib','FCKTools','FCKXHtmlEntities'], FCK_GENERIC_SPECIFIC ) ;
Index: /FCKeditor/branches/features/style/editor/_source/internals/fck.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/internals/fck.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/internals/fck.js	(revision 758)
@@ -361,15 +361,4 @@
 			data = FCK.ProtectTags( data ) ;
 
-			// Firefox can't handle correctly the editing of the STRONG and EM tags.
-			// We must replace them with B and I.
-			// TODO : remove this check  if possible, as soon as the new style system is in use.
-			if ( FCKBrowserInfo.IsGecko )
-			{
-				data = data.replace( FCKRegexLib.StrongOpener, '<b$1' ) ;
-				data = data.replace( FCKRegexLib.StrongCloser, '<\/b>' ) ;
-				data = data.replace( FCKRegexLib.EmOpener, '<i$1' ) ;
-				data = data.replace( FCKRegexLib.EmCloser, '<\/i>' ) ;
-			}
-
 			// Insert the base tag (FCKConfig.BaseHref), if not exists in the source.
 			// The base must be the first tag in the HEAD, to get relative
@@ -737,5 +726,5 @@
 } ;
 
-FCK.Events	= new FCKEvents( FCK ) ;
+FCK.Events = new FCKEvents( FCK ) ;
 
 // DEPRECATED in favor or "GetData".
Index: /FCKeditor/branches/features/style/editor/_source/internals/fck_gecko.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/internals/fck_gecko.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/internals/fck_gecko.js	(revision 758)
@@ -350,11 +350,4 @@
 	html = FCK.ProtectTags( html ) ;
 
-	// Firefox can't handle correctly the editing of the STRONG and EM tags.
-	// We must replace them with B and I.
-	html = html.replace( FCKRegexLib.StrongOpener, '<b$1' ) ;
-	html = html.replace( FCKRegexLib.StrongCloser, '<\/b>' ) ;
-	html = html.replace( FCKRegexLib.EmOpener, '<i$1' ) ;
-	html = html.replace( FCKRegexLib.EmCloser, '<\/i>' ) ;
-
 	// Save an undo snapshot first.
 	FCKUndo.SaveUndoStep() ;
Index: /FCKeditor/branches/features/style/editor/_source/internals/fckcommands.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/internals/fckcommands.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/internals/fckcommands.js	(revision 758)
@@ -39,4 +39,13 @@
 	switch ( commandName )
 	{
+		case 'Bold'			:
+		case 'Italic'		:
+		case 'Underline'	:
+		case 'StrikeThrough':
+		case 'Subscript'	:
+		case 'Superscript'	: oCommand = new FCKCoreStyleCommand( commandName ) ; break ;
+		
+		case 'RemoveFormat'	: oCommand = new FCKRemoveFormatCommand() ; break ;
+
 		case 'DocProps'		: oCommand = new FCKDialogCommand( 'DocProps'	, FCKLang.DocProps				, 'dialog/fck_docprops.html'	, 400, 390, FCKCommands.GetFullPageState ) ; break ;
 		case 'Templates'	: oCommand = new FCKDialogCommand( 'Templates'	, FCKLang.DlgTemplatesTitle		, 'dialog/fck_template.html'	, 380, 450 ) ; break ;
@@ -82,17 +91,17 @@
 		case 'TableInsertRowAfter'		: oCommand = new FCKTableCommand('TableInsertRowAfter') ; break ;
 		case 'TableInsertRowBefore'		: oCommand = new FCKTableCommand('TableInsertRowBefore') ; break ;
-		case 'TableDeleteRows'		: oCommand = new FCKTableCommand('TableDeleteRows') ; break ;
+		case 'TableDeleteRows'			: oCommand = new FCKTableCommand('TableDeleteRows') ; break ;
 		case 'TableInsertColumnAfter'	: oCommand = new FCKTableCommand('TableInsertColumnAfter') ; break ;
 		case 'TableInsertColumnBefore'	: oCommand = new FCKTableCommand('TableInsertColumnBefore') ; break ;
-		case 'TableDeleteColumns'	: oCommand = new FCKTableCommand('TableDeleteColumns') ; break ;
+		case 'TableDeleteColumns'		: oCommand = new FCKTableCommand('TableDeleteColumns') ; break ;
 		case 'TableInsertCellAfter'		: oCommand = new FCKTableCommand('TableInsertCellAfter') ; break ;
-		case 'TableInsertCellBefore'		: oCommand = new FCKTableCommand('TableInsertCellBefore') ; break ;
-		case 'TableDeleteCells'		: oCommand = new FCKTableCommand('TableDeleteCells') ; break ;
-		case 'TableMergeCells'		: oCommand = new FCKTableCommand('TableMergeCells') ; break ;
-		case 'TableMergeRight'		: oCommand = new FCKTableCommand('TableMergeRight') ; break ;
-		case 'TableMergeDown'		: oCommand = new FCKTableCommand('TableMergeDown') ; break ;
-		case 'TableHorizontalSplitCell'		: oCommand = new FCKTableCommand('TableHorizontalSplitCell') ; break ;
-		case 'TableVerticalSplitCell'		: oCommand = new FCKTableCommand('TableVerticalSplitCell') ; break ;
-		case 'TableDelete'			: oCommand = new FCKTableCommand('TableDelete') ; break ;
+		case 'TableInsertCellBefore'	: oCommand = new FCKTableCommand('TableInsertCellBefore') ; break ;
+		case 'TableDeleteCells'			: oCommand = new FCKTableCommand('TableDeleteCells') ; break ;
+		case 'TableMergeCells'			: oCommand = new FCKTableCommand('TableMergeCells') ; break ;
+		case 'TableMergeRight'			: oCommand = new FCKTableCommand('TableMergeRight') ; break ;
+		case 'TableMergeDown'			: oCommand = new FCKTableCommand('TableMergeDown') ; break ;
+		case 'TableHorizontalSplitCell'	: oCommand = new FCKTableCommand('TableHorizontalSplitCell') ; break ;
+		case 'TableVerticalSplitCell'	: oCommand = new FCKTableCommand('TableVerticalSplitCell') ; break ;
+		case 'TableDelete'				: oCommand = new FCKTableCommand('TableDelete') ; break ;
 
 		case 'Form'			: oCommand = new FCKDialogCommand( 'Form'		, FCKLang.Form			, 'dialog/fck_form.html'		, 380, 230 ) ; break ;
@@ -113,7 +122,7 @@
 		case 'Copy'	: oCommand = new FCKCopyCommand() ; break ;
 
-		case 'SelectAll' : oCommand = new FCKSelectAllCommand() ; break ;
-		case 'InsertOrderedList' : oCommand = new FCKListCommand( 'insertorderedlist' ) ; break ;
-		case 'InsertUnorderedList' : oCommand = new FCKListCommand( 'insertunorderedlist' ) ; break ;
+		case 'SelectAll'			: oCommand = new FCKSelectAllCommand() ; break ;
+		case 'InsertOrderedList'	: oCommand = new FCKListCommand( 'insertorderedlist' ) ; break ;
+		case 'InsertUnorderedList'	: oCommand = new FCKListCommand( 'insertunorderedlist' ) ; break ;
 		case 'ShowBlocks' : oCommand = new FCKShowBlockCommand( 'ShowBlocks', FCKConfig.StartupShowBlocks ? FCK_TRISTATE_ON : FCK_TRISTATE_OFF ) ; break ;
 
Index: /FCKeditor/branches/features/style/editor/_source/internals/fckdomtools.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/internals/fckdomtools.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/internals/fckdomtools.js	(revision 758)
@@ -24,5 +24,5 @@
 var FCKDomTools =
 {
-	MoveChildren : function( source, target )
+	MoveChildren : function( source, target, toTargetStart )
 	{
 		if ( source == target )
@@ -30,6 +30,23 @@
 
 		var eChild ;
-		while ( (eChild = source.firstChild) )
-			target.appendChild( source.removeChild( eChild ) ) ;
+
+		if ( toTargetStart )
+		{
+			while ( (eChild = source.lastChild) )
+				target.insertBefore( source.removeChild( eChild ), target.firstChild ) ;
+		}
+		else
+		{
+			while ( (eChild = source.firstChild) )
+				target.appendChild( source.removeChild( eChild ) ) ;
+		}
+	},
+
+	MoveNode : function( source, target, toTargetStart )
+	{
+		if ( toTargetStart )
+			target.insertBefore( FCKDomTools.RemoveNode( source ), target.firstChild ) ;
+		else
+			target.appendChild( FCKDomTools.RemoveNode( source ) ) ;
 	},
 
@@ -228,32 +245,40 @@
 	GetNextSourceElement : function( currentNode, ignoreSpaceTextOnly, stopSearchElements, ignoreElements )
 	{
+		while( currentNode = this.GetNextSourceNode( currentNode ) )
+		{
+			if ( currentNode.nodeType == 1 )
+			{
+				if ( stopSearchElements && currentNode.nodeName.IEquals( stopSearchElements ) )
+					break ;
+
+				if ( !ignoreElements || !currentNode.nodeName.IEquals( ignoreElements ) )
+					return currentNode ;
+			}
+			else if ( ignoreSpaceTextOnly && currentNode.nodeType == 3 && currentNode.nodeValue.RTrim().length > 0 )
+				break ;
+		}
+
+		return null ;
+	},
+
+	/*
+	 * Get the next DOM node available in source order.
+	 */
+	GetNextSourceNode : function( currentNode, startFromSibling, nodeType )
+	{
 		if ( !currentNode )
 			return null ;
 
-		if ( currentNode.nextSibling )
-			currentNode = currentNode.nextSibling ;
-		else
-			return this.GetNextSourceElement( currentNode.parentNode, ignoreSpaceTextOnly, stopSearchElements, ignoreElements ) ;
-
-		while ( currentNode )
-		{
-			if ( currentNode.nodeType == 1 )
-			{
-				if ( stopSearchElements && currentNode.nodeName.IEquals( stopSearchElements ) )
-					break ;
-
-				if ( !ignoreElements || !currentNode.nodeName.IEquals( ignoreElements ) )
-					return currentNode ;
-			}
-			else if ( ignoreSpaceTextOnly && currentNode.nodeType == 3 && currentNode.nodeValue.RTrim().length > 0 )
-				break ;
-
-			if ( currentNode.firstChild )
-				currentNode = currentNode.firstChild ;
-			else
-				return this.GetNextSourceElement( currentNode, ignoreSpaceTextOnly, stopSearchElements, ignoreElements ) ;
-		}
-
-		return null ;
+		var nextNode ;
+		
+		if ( !startFromSibling && currentNode.firstChild )
+			nextNode = currentNode.firstChild ;
+		else
+			nextNode = ( currentNode.nextSibling || this.GetNextSourceNode( currentNode.parentNode, true, nodeType ) ) ;
+		
+		if ( nodeType && nextNode && nextNode.nodeType != nodeType )
+			return this.GetNextSourceNode( nextNode, false, nodeType ) ;
+		
+		return nextNode ;
 	},
 
@@ -307,5 +332,5 @@
 			FCKTools.AppendBogusBr( node ) ;
 		this.PaddingNode = node ;
-		if ( doc.body.childNodes.length == 1 
+		if ( doc.body.childNodes.length == 1
 				&& doc.body.firstChild.nodeType == 1
 				&& doc.body.firstChild.tagName.toLowerCase() == 'br'
@@ -326,6 +351,6 @@
 		if ( paddingNode.parentNode != doc.body
 			|| paddingNode.tagName.toLowerCase() != tagName
-			|| ( paddingNode.childNodes.length > 1 ) 
-			|| ( paddingNode.firstChild && paddingNode.firstChild.nodeValue != '\xa0' 
+			|| ( paddingNode.childNodes.length > 1 )
+			|| ( paddingNode.firstChild && paddingNode.firstChild.nodeValue != '\xa0'
 				&& String(paddingNode.firstChild.tagName).toLowerCase() != 'br' ) )
 		{
@@ -341,4 +366,117 @@
 			this.PaddingNode = null ;
 		}
+	},
+
+	HasAttribute : function( element, attributeName )
+	{
+		if ( element.hasAttribute )
+			return element.hasAttribute( attributeName ) ;
+		else
+		{
+			var att = element.attributes[ attributeName ] ;
+			return ( att != undefined && att.specified ) ;
+		}
+	},
+
+	/**
+	 * Checks if an element has "specified" attributes.
+	 */
+	HasAttributes : function( element )
+	{
+		var attributes = element.attributes ;
+
+		for ( var i = 0 ; i < attributes.length ; i++ )
+		{
+			if ( attributes[i].specified )
+				return true ;
+		}
+
+		return false ;
+	},
+	
+	/**
+	 * Remove an attribute from an element.
+	 */
+	RemoveAttribute : function( element, attributeName )
+	{
+		if ( FCKBrowserInfo.IsIE && attributeName.toLowerCase() == 'class' )
+			attributeName = 'className' ;
+		
+		return element.removeAttribute( attributeName ) ;
+	},
+	
+	
+	GetAttributeValue : function( element, att )
+	{
+		var attName = att ;
+		
+		if ( typeof att == 'string' )
+			element.attributes[ att ] ;
+		else
+			attName = att.nodeName ;
+		
+		if ( att && att.specified )
+		{
+			// IE returns "null" for the nodeValue of a "style" attribute.
+			if ( attName == 'style' )
+				return element.style.cssText ;
+			// There are two cases when the nodeValue must be used:
+			//		- for the "class" attribute (all browsers).
+			//		- for events attributes (IE only).
+			else if ( attName == 'class' || attName.indexOf('on') == 0 )
+				return att.nodeValue ;
+			else
+			{
+				// Use getAttribute to get its value  exactly as it is
+				// defined.
+				return element.getAttribute( attName, 2 ) ;
+			}
+		}
+		return null ;
+	},
+	
+	/**
+	 * Checks whether one element contains the other. 
+	 */
+	Contains : function( mainElement, otherElement )
+	{
+		if ( mainElement.contains )
+			return mainElement.contains( otherElement ) ;
+		
+		while ( ( otherElement = otherElement.parentNode ) )	// Only one "="
+		{
+			if ( otherElement == mainElement )
+				return true ;
+		}
+		return false ;
+	},
+	
+	/**
+	 * Breaks a parent element in the position of one of its contained elements.
+	 * For example, in the following case:
+	 *		<b>This <i>is some<span /> sample</i> test text</b>
+	 * If element = <span />, we have these results:
+	 *		<b>This <i>is some</i><span /><i> sample</i> test text</b>			(If parent = <i>)
+	 *		<b>This <i>is some</i></b><span /><b<i> sample</i> test text</b>	(If parent = <b>)
+	 */
+	BreakParent : function( element, parent, reusableRange )
+	{
+		var range = reusableRange || new FCKDomRange( FCKTools.GetElementWindow( element ) ) ;
+		
+		// We'll be extracting part of this element, so let's use our
+		// range to get the correct piece.
+		range.SetStart( element, 4 ) ;
+		range.SetEnd( parent, 4 ) ;
+		
+		// Extract it.
+		var docFrag = range.ExtractContents() ;
+		
+		// Move the element outside the broken element.
+		range.InsertNode( element.parentNode.removeChild( element ) ) ;
+
+		// Re-insert the extracted piece after the element.
+		docFrag.InsertAfterNode( element ) ;
+		
+		range.Release( !!reusableRange ) ;
 	}
 } ;
Index: /FCKeditor/branches/features/style/editor/_source/internals/fcklistslib.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/internals/fcklistslib.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/internals/fcklistslib.js	(revision 758)
@@ -37,14 +37,23 @@
 	InlineChildReqElements : { abbr:1,acronym:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,'var':1 },
 
+	// Inline elements which are not marked as empty "Empty" in the XHTML DTD.
+	InlineNonEmptyElements : { a:1,abbr:1,acronym:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,'var':1 },
+
 	// Elements marked as empty "Empty" in the XHTML DTD.
 	EmptyElements : { base:1,meta:1,link:1,hr:1,br:1,param:1,img:1,area:1,input:1 },
-	
+
 	// Elements that may be considered the "Block boundary" in an element path.
 	PathBlockElements : { address:1,blockquote:1,dl:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1,ol:1,ul:1,li:1,dt:1,de:1 },
-	
+
 	// Elements that may be considered the "Block limit" in an element path.
 	PathBlockLimitElements : { body:1,td:1,th:1,caption:1,form:1 },
 
-	// Final setup of FCKListsLib once the editor is loaded (at FCK.StartEditor). 
+	// Block elements for the Styles System.
+	StyleBlockElements : { address:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1 },
+
+	// Object elements for the Styles System.
+	StyleObjectElements : { img:1,hr:1,li:1,table:1,tr:1,td:1,embed:1,object:1,ol:1,ul:1 },
+
+	// Final setup of FCKListsLib once the editor is loaded (at FCK.StartEditor).
 	// TODO: For v3, there should be a generic way to register to the editor
 	// startup event, so this function would not be needed to be defined here, not
@@ -54,5 +63,8 @@
 		// <div> is considered a block element only if EnterMode=div, otherwise it is a block limit.
 		if ( FCKConfig.EnterMode == 'div' )
+		{
 			this.PathBlockElements.div = 1 ;
+			this.StyleBlockElements.div = 1 ;
+		}
 		else
 			this.PathBlockLimitElements.div = 1 ;
Index: /FCKeditor/branches/features/style/editor/_source/internals/fckregexlib.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/internals/fckregexlib.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/internals/fckregexlib.js	(revision 758)
@@ -68,9 +68,4 @@
 TagBody			: /></ ,
 
-StrongOpener	: /<STRONG([ \>])/gi ,
-StrongCloser	: /<\/STRONG>/gi ,
-EmOpener		: /<EM([ \>])/gi ,
-EmCloser		: /<\/EM>/gi ,
-
 GeckoEntitiesMarker : /#\?-\:/g ,
 
@@ -92,4 +87,8 @@
 
 // [a-zA-Z0-9:]+ seams to be more efficient than [\w:]+
-InvalidSelfCloseTags : /(<(?!base|meta|link|hr|br|param|img|area|input)([a-zA-Z0-9:]+)[^>]*)\/>/gi
+InvalidSelfCloseTags : /(<(?!base|meta|link|hr|br|param|img|area|input)([a-zA-Z0-9:]+)[^>]*)\/>/gi,
+
+// All variables defined in a style attribute or style definition. The variable
+// name is returned with $2.
+StyleVariableAttName : /#\(\s*("|')(.+?)\1[^\)]*\s*\)/g
 } ;
Index: /FCKeditor/branches/features/style/editor/_source/internals/fckselection_gecko.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/internals/fckselection_gecko.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/internals/fckselection_gecko.js	(revision 758)
@@ -25,22 +25,25 @@
 FCKSelection.GetType = function()
 {
-//	if ( ! this._Type )
-//	{
-		// By default set the type to "Text".
-		this._Type = 'Text' ;
-
-		// Check if the actual selection is a Control (IMG, TABLE, HR, etc...).
-		var oSel ;
-		try { oSel = FCK.EditorWindow.getSelection() ; }
-		catch (e) {}
-
-		if ( oSel && oSel.rangeCount == 1 )
+	// By default set the type to "Text".
+	var type = 'Text' ;
+
+	// Check if the actual selection is a Control (IMG, TABLE, HR, etc...).
+
+	var sel ;
+	try { sel = FCK.EditorWindow.getSelection() ; } catch (e) {}
+
+	if ( sel && sel.rangeCount == 1 )
+	{
+		var range = sel.getRangeAt(0) ;
+		if ( range.startContainer == range.endContainer
+			&& ( range.endOffset - range.startOffset ) == 1
+			&& range.startContainer.nodeType == 1
+			&& FCKListsLib.StyleObjectElements[ range.startContainer.childNodes[ range.startOffset ].nodeName.toLowerCase() ] )
 		{
-			var oRange = oSel.getRangeAt(0) ;
-			if ( oRange.startContainer == oRange.endContainer && (oRange.endOffset - oRange.startOffset) == 1 && oRange.startContainer.nodeType != Node.TEXT_NODE )
-				this._Type = 'Control' ;
+			type = 'Control' ;
 		}
-//	}
-	return this._Type ;
+	}
+
+	return type ;
 }
 
@@ -52,5 +55,14 @@
 	{
 		var oSel = FCK.EditorWindow.getSelection() ;
-		return oSel.anchorNode.childNodes[ oSel.anchorOffset ] ;
+
+		// For Safari, the anchor node for a control selection is the control
+		// itself, which seams logic. FF and Opera use the parent as the anchor
+		// node, pointing to the control with the offset.
+		// As FF created the selection "standard", Safari would do better by
+		// following their steps.
+		if ( FCKBrowserInfo.IsSafari )
+			return oSel.anchorNode ;
+		else
+			return oSel.anchorNode.childNodes[ oSel.anchorOffset ] ;
 	}
 	return null ;
@@ -67,11 +79,12 @@
 		{
 			// make the common case fast - for collapsed/nearly collapsed selections just return anchor.parent.
-			if ( oSel.anchorNode == oSel.focusNode && oSel.anchorNode != null)
+			if ( oSel.anchorNode && oSel.anchorNode == oSel.focusNode )
 				return oSel.anchorNode.parentNode ;
 
 			// looks like we're having a large selection here. To make the behavior same as IE's TextRange.parentElement(),
 			// we need to find the nearest ancestor node which encapsulates both the beginning and the end of the selection.
+			// TODO: A simpler logic can be found.
 			var anchorPath = new FCKElementPath( oSel.anchorNode ) ;
-			var focusPath = new FCKElementPath( oSel.focusNode ) ; 
+			var focusPath = new FCKElementPath( oSel.focusNode ) ;
 			var deepPath = null ;
 			var shallowPath = null ;
@@ -86,5 +99,5 @@
 				shallowPath = anchorPath.Elements ;
 			}
-			
+
 			var deepPathBase = deepPath.length - shallowPath.length ;
 			for( var i = 0 ; i < shallowPath.length ; i++)
@@ -99,8 +112,45 @@
 }
 
+FCKSelection.GetBoundaryParentElement = function( startBoundary )
+{
+	if ( this.GetType() == 'Control' )
+		return FCKSelection.GetSelectedElement().parentNode ;
+	else
+	{
+		var oSel = FCK.EditorWindow.getSelection() ;
+		if ( oSel && oSel.rangeCount > 0 )
+		{
+			var range = oSel.getRangeAt( startBoundary ? 0 : ( oSel.rangeCount - 1 ) ) ;
+
+			var element = startBoundary ? range.startContainer : range.endContainer ;
+
+			// Firefox has a strange selection system which diverts from IE,
+			// Safari and Opera. If the start of the selection ends in the left
+			// boundary of an element, it is placed outside the element. All
+			// other browsers place it inside of it. So, the following code is
+			// needed to fix it.
+			if ( element.nodeType == 3
+				&& startBoundary
+				&& range.startOffset >= element.length )
+			{
+				var nextText = element ;
+				while ( nextText )
+				{
+					nextText = FCKDomTools.GetNextSourceNode( nextText, false, 3 ) ;
+
+					if ( nextText && nextText.length > 0 )
+						break ;
+				}
+				element = nextText || element ;
+			}
+
+			return ( element.nodeType == 1 ? element : element.parentNode ) ;
+		}
+	}
+	return null ;
+}
+
 FCKSelection.SelectNode = function( element )
 {
-//	FCK.Focus() ;
-
 	var oRange = FCK.EditorDocument.createRange() ;
 	oRange.selectNode( element ) ;
Index: /FCKeditor/branches/features/style/editor/_source/internals/fckselection_ie.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/internals/fckselection_ie.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/internals/fckselection_ie.js	(revision 758)
@@ -64,7 +64,5 @@
 		case 'Control' :
 			var el = FCKSelection.GetSelectedElement() ;
-			if ( !el )
-				return null ;
-			return el.parentElement ;
+			return el ? el.parentElement : null ;
 
 		case 'None' :
@@ -73,4 +71,22 @@
 		default :
 			return FCK.EditorDocument.selection.createRange().parentElement() ;
+	}
+} ;
+
+FCKSelection.GetBoundaryParentElement = function( startBoundary )
+{
+	switch ( this.GetType() )
+	{
+		case 'Control' :
+			var el = FCKSelection.GetSelectedElement() ;
+			return el ? el.parentElement : null ;
+
+		case 'None' :
+			return null ;
+
+		default :
+			var range = FCK.EditorDocument.selection.createRange() ;
+			range.collapse( startBoundary !== false ) ;
+			return range.parentElement() ;
 	}
 } ;
Index: /FCKeditor/branches/features/style/editor/_source/internals/fckstyles.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/internals/fckstyles.js	(revision 758)
+++ /FCKeditor/branches/features/style/editor/_source/internals/fckstyles.js	(revision 758)
@@ -0,0 +1,321 @@
+﻿/*
+ * 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 ==
+ *
+ * Handles styles in a give document.
+ */
+
+var FCKStyles = FCK.Styles =
+{
+	_Callbacks : {},
+	_ObjectStyles : {},
+
+	ApplyStyle : function( style )
+	{
+		if ( typeof style == 'string' )
+			style = this.GetStyles()[ style ] ;
+
+		if ( style )
+		{
+			style.ApplyToSelection( FCK.EditorWindow ) ;
+			FCK.Events.FireEvent( 'OnSelectionChange' ) ;
+		}
+	},
+
+	RemoveStyle : function( style )
+	{
+		if ( typeof style == 'string' )
+			style = this.GetStyles()[ style ] ;
+
+		if ( style )
+		{
+			style.RemoveFromSelection( FCK.EditorWindow ) ;
+			FCK.Events.FireEvent( 'OnSelectionChange' ) ;
+		}
+	},
+
+	/**
+	 * Defines a callback function to be called when the current state of a
+	 * specific style changes.
+	 */
+	AttachStyleStateChange : function( styleName, callback, callbackOwner )
+	{
+		var callbacks = this._Callbacks[ styleName ] ;
+
+		if ( !callbacks )
+			callbacks = this._Callbacks[ styleName ] = [] ;
+
+		callbacks.push( [ callback, callbackOwner ] ) ;
+	},
+
+	CheckSelectionChanges : function()
+	{
+		var startElement = FCKSelection.GetBoundaryParentElement( true ) ;
+
+		if ( !startElement )
+			return ;
+
+		// Walks the start node parents path, checking all styles that are being listened.
+		var path = new FCKElementPath( startElement ) ;
+		var styles = this.GetStyles() ;
+
+		for ( var styleName in styles )
+		{
+			var callbacks = this._Callbacks[ styleName ] ;
+
+			if ( callbacks )
+			{
+				var style = styles[ styleName ] ;
+				var state = style.CheckActive( path ) ;
+
+				if ( style._LastState != state )
+				{
+					style._LastState = state ;
+
+					for ( var i = 0 ; i < callbacks.length ; i++ )
+					{
+						var callback = callbacks[i][0] ;
+						var callbackOwner = callbacks[i][1] ;
+
+						callback.call( callbackOwner || window, styleName, state ) ;
+					}
+				}
+			}
+		}
+	},
+
+	CheckStyleInSelection : function( styleName )
+	{
+		return false ;
+	},
+
+	_GetRemoveFormatTagsRegex : function ()
+	{
+		var regex = new RegExp( '^(?:' + FCKConfig.RemoveFormatTags.replace( /,/g,'|' ) + ')$', 'i' ) ;
+
+		return (this._GetRemoveFormatTagsRegex = function()
+		{
+			return regex ;
+		})
+		&& regex  ;
+	},
+
+	/**
+	 * Remove all styles from the current selection.
+	 * TODO:
+	 *  - This is almost a duplication of FCKStyle.RemoveFromRange. We should
+	 *    try to merge things.
+	 */
+	RemoveAll : function()
+	{
+		var range = new FCKDomRange( FCK.EditorWindow ) ;
+		range.MoveToSelection() ;
+
+		if ( range.CheckIsCollapsed() )
+			return ;
+
+			// Expand the range, if inside inline element boundaries.
+		range.Expand( 'inline_elements' ) ;
+
+		// Get the bookmark nodes.
+		// Bookmark the range so we can re-select it after processing.
+		var bookmark = range.CreateBookmark( true ) ;
+
+		// The style will be applied within the bookmark boundaries.
+		var startNode	= range.GetBookmarkNode( bookmark, true ) ;
+		var endNode		= range.GetBookmarkNode( bookmark, false ) ;
+
+		range.Release( true ) ;
+
+		var tagsRegex = this._GetRemoveFormatTagsRegex() ;
+
+		// We need to check the selection boundaries (bookmark spans) to break
+		// the code in a way that we can properly remove partially selected nodes.
+		// For example, removing a <b> style from
+		//		<b>This is [some text</b> to show <b>the] problem</b>
+		// ... where [ and ] represent the selection, must result:
+		//		<b>This is </b>[some text to show the]<b> problem</b>
+		// The strategy is simple, we just break the partial nodes before the
+		// removal logic, having something that could be represented this way:
+		//		<b>This is </b>[<b>some text</b> to show <b>the</b>]<b> problem</b>
+
+		// Let's start checking the start boundary.
+		var path = new FCKElementPath( startNode ) ;
+		var pathElements = path.Elements ;
+		var pathElement ;
+
+		for ( var i = 1 ; i < pathElements.length ; i++ )
+		{
+			pathElement = pathElements[i] ;
+
+			if ( pathElement == path.Block || pathElement == path.BlockLimit )
+				break ;
+
+			// If this element can be removed (even partially).
+			if ( tagsRegex.test( pathElement.nodeName ) )
+				FCKDomTools.BreakParent( startNode, pathElement, range ) ;
+		}
+
+		// Now the end boundary.
+		path = new FCKElementPath( endNode ) ;
+		pathElements = path.Elements ;
+
+		for ( var i = 1 ; i < pathElements.length ; i++ )
+		{
+			pathElement = pathElements[i] ;
+
+			if ( pathElement == path.Block || pathElement == path.BlockLimit )
+				break ;
+
+			elementName = pathElement.nodeName.toLowerCase() ;
+
+			// If this element can be removed (even partially).
+			if ( tagsRegex.test( pathElement.nodeName ) )
+				FCKDomTools.BreakParent( endNode, pathElement, range ) ;
+		}
+
+		// Navigate through all nodes between the bookmarks.
+		var currentNode = FCKDomTools.GetNextSourceNode( startNode, true, 1 ) ;
+
+		while ( currentNode )
+		{
+			// If we have reached the end of the selection, stop looping.
+			if ( currentNode == endNode )
+				break ;
+
+			// Cache the next node to be processed. Do it now, because
+			// currentNode may be removed.
+			var nextNode = FCKDomTools.GetNextSourceNode( currentNode, false, 1 ) ;
+
+			// Remove elements nodes that match with this style rules.
+			if ( tagsRegex.test( currentNode.nodeName ) )
+				FCKDomTools.RemoveNode( currentNode, true ) ;
+
+			currentNode = nextNode ;
+		}
+
+		range.SelectBookmark( bookmark ) ;
+
+		FCK.Events.FireEvent( 'OnSelectionChange' ) ;
+	},
+	
+	GetStyle : function( styleName )
+	{
+		return this.GetStyles()[ styleName ] ;
+	},
+
+	GetStyles : function()
+	{
+		var styles = this._GetStyles ;
+		if ( !styles )
+		{
+			styles = this._LoadStylesCore() ;
+			styles = FCKTools.Merge( styles, this._LoadStylesXml() ) ;
+			this._GetStyles = styles ;
+		}
+		return styles ;
+	},
+	
+	CheckHasObjectStyle : function( elementName )
+	{
+		return !!this._ObjectStyles[ elementName ] ;
+	},
+
+	_LoadStylesCore : function()
+	{
+		var styles = {};
+		var styleDefs = FCKConfig.CoreStyles ;
+
+		for ( var styleName in styleDefs )
+		{
+			// Core styles are prefixed with _FCK_.
+			var style = styles[ '_FCK_' + styleName ] = new FCKStyle( styleDefs[ styleName ] ) ;
+			style.IsCore = true ;
+		}
+		return styles ;
+	},
+
+	_LoadStylesXml : function()
+	{
+		var styles = {};
+
+		var stylesXmlPath = FCKConfig.StylesXmlPath ;
+
+		if ( !stylesXmlPath || stylesXmlPath.length == 0 )
+			return ;
+
+		// Load the XML file into a FCKXml object.
+		var xml = new FCKXml() ;
+		xml.LoadUrl( stylesXmlPath ) ;
+
+		// Get the "Style" nodes defined in the XML file.
+		var styleNodes = xml.SelectNodes( 'Styles/Style' ) ;
+
+		// Add each style to our "Styles" collection.
+		for ( var i = 0 ; i < styleNodes.length ; i++ )
+		{
+			var styleNode = styleNodes[i] ;
+
+			var element = FCKXml.GetAttribute( styleNode, 'element', '' ).toLowerCase() ;
+
+			if ( element.length == 0 )
+				throw( 'The element name is required. Error loading "' + stylesXmlPath + '"' ) ;
+
+			var styleDef = {
+				Element : element,
+				Attributes : {},
+				Styles : {},
+				Overrides : []
+			} ;
+
+			// Get the attributes defined for the style (if any).
+			var attNodes = xml.SelectNodes( 'Attribute', styleNode ) ;
+
+			// Add the attributes to the style definition object.
+			for ( var j = 0 ; j < attNodes.length ; j++ )
+			{
+				styleDef.Attributes[ FCKXml.GetAttribute( attNodes[j], 'name' ) ] =
+					FCKXml.GetAttribute( attNodes[j], 'value' ) ;
+			}
+
+			// Get the styles defined for the style (if any).
+			var cssStyleNodes = xml.SelectNodes( 'Style', styleNode ) ;
+
+			// Add the attributes to the style definition object.
+			for ( var j = 0 ; j < cssStyleNodes.length ; j++ )
+			{
+				styleDef.Styles[ FCKXml.GetAttribute( cssStyleNodes[j], 'name' ) ] =
+					FCKXml.GetAttribute( cssStyleNodes[j], 'value' ) ;
+			}
+
+			// TODO: Implement overrides loading.
+
+			var style = new FCKStyle( styleDef ) ;
+			style.Name = FCKXml.GetAttribute( styleNode, 'name', element ) ;
+			
+			if ( style.GetType() == FCK_STYLE_OBJECT )
+				this._ObjectStyles[ element ] = true ;
+
+			// Add the style to the "Styles" collection using it's name as the key.
+			styles[ style.Name ] = style ;
+		}
+
+		return styles ;
+	}
+} ;
Index: /FCKeditor/branches/features/style/editor/_source/internals/fcktools.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/internals/fcktools.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/internals/fcktools.js	(revision 758)
@@ -519,2 +519,57 @@
 		domNode.style[i] = styleDict[ i ] ;
 }
+
+/**
+ * Merge all objects passed by argument into a single object.
+ */
+FCKTools.Merge = function()
+{
+	var args = arguments ;
+	var o = args[0] ;
+
+	for ( var i = 1 ; i < args.length ; i++ )
+	{
+		var arg = args[i] ;
+		for ( var p in arg )
+			o[p] = arg[p] ;
+	}
+
+	return o ;
+}
+
+/**
+ * Check if the passed argument is a real Array. It may not working when
+ * calling it cross windows.
+ */
+FCKTools.IsArray = function( it )
+{
+	return ( it instanceof Array ) ;
+}
+
+/**
+ * Appends a "length" property to an object, containing the number of
+ * properties available on it, excluded the append property itself.
+ */
+FCKTools.AppendLengthProperty = function( targetObject, propertyName )
+{
+	var counter = 0 ;
+
+	for ( var n in targetObject )
+		counter++ ;
+
+	return targetObject[ propertyName || 'length' ] = counter ;
+}
+
+/**
+ * Gets the browser parsed version of a css text (style attribute value). On
+ * some cases, the browser makes changes to the css text, returning a different
+ * value. For example, hexadecimal colors get transformed to rgb().
+ */
+FCKTools.NormalizeCssText = function( unparsedCssText )
+{
+	// Injects the style in a temporary span object, so the browser parses it,
+	// retrieving its final format.
+	var tempSpan = document.createElement( 'span' ) ;
+	tempSpan.style.cssText = unparsedCssText ;
+	return tempSpan.style.cssText ;
+}
Index: /FCKeditor/branches/features/style/editor/_source/internals/fckxhtml.js
===================================================================
--- /FCKeditor/branches/features/style/editor/_source/internals/fckxhtml.js	(revision 757)
+++ /FCKeditor/branches/features/style/editor/_source/internals/fckxhtml.js	(revision 758)
@@ -38,6 +38,4 @@
 	var bIsDirty = FCK.IsDirty() ;
 
-	this._CreateNode = FCKConfig.ForceStrongEm ? FCKXHtml_CreateNode_StrongEm : FCKXHtml_CreateNode_Normal ;
-
 	// Special blocks are blocks of content that remain untouched during the
 	// process. It is used for SCRIPTs and STYLEs.
@@ -51,4 +49,6 @@
 
 	FCKXHtml.CurrentJobNum++ ;
+
+//	var dTimer = new Date() ;
 
 	if ( includeNode )
@@ -59,4 +59,6 @@
 	// Get the resulting XHTML as a string.
 	var sXHTML = this._GetMainXmlString() ;
+
+//	alert( 'Time: ' + ( ( ( new Date() ) - dTimer ) ) + ' ms' ) ;
 
 	this.XML = null ;
@@ -232,6 +234,6 @@
 				return false ;
 
-			var oNode = this._CreateNode( sNodeName ) ;
-
+			var oNode = this.XML.createElement( sNodeName ) ;
+			
 			// Add all attributes.
 			FCKXHtml._AppendAttributes( xmlNode, htmlNode, oNode, sNodeName ) ;
@@ -279,23 +281,4 @@
 }
 
-function FCKXHtml_CreateNode_StrongEm( nodeName )
-{
-	switch ( nodeName )
-	{
-		case 'b' :
-			nodeName = 'strong' ;
-			break ;
-		case 'i' :
-			nodeName = 'em' ;
-			break ;
-	}
-	return this.XML.createElement( nodeName ) ;
-}
-
-function FCKXHtml_CreateNode_Normal( nodeName )
-{
-	return this.XML.createElement( nodeName ) ;
-}
-
 // Append an item to the SpecialBlocks array and returns the tag to be used.
 FCKXHtml._AppendSpecialItem = function( item )
Index: /FCKeditor/branches/features/style/editor/css/fck_editorarea.css
===================================================================
--- /FCKeditor/branches/features/style/editor/css/fck_editorarea.css	(revision 757)
+++ /FCKeditor/branches/features/style/editor/css/fck_editorarea.css	(revision 758)
@@ -41,5 +41,5 @@
 body, td
 {
-	font-family: Arial, Verdana, Sans-Serif;
+	font-family: Arial, Verdana, sans-serif;
 	font-size: 12px;
 }
Index: /FCKeditor/branches/features/style/editor/dtd/fck_dtd_test.html
===================================================================
--- /FCKeditor/branches/features/style/editor/dtd/fck_dtd_test.html	(revision 758)
+++ /FCKeditor/branches/features/style/editor/dtd/fck_dtd_test.html	(revision 758)
@@ -0,0 +1,38 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>DTD Test Page</title>
+	<script type="text/javascript" src="../_source/internals/fcktools.js"></script>
+	<script type="text/javascript" src="fck_xhtml10transitional.js"></script>
+</head>
+<body>
+	<h1>
+		DTD Contents
+	</h1>
+	<table border="1">
+		<script type="text/javascript">
+
+    alert(FCK.DTD);
+
+for ( var p in FCK.DTD )
+{
+	document.write( '<tr><td><b>' + p + '</b></td><td>' ) ;
+
+	var isFirst = true ;
+
+	for ( var c in FCK.DTD[p] )
+	{
+		if ( !isFirst )
+			document.write( ', ' ) ;
+		isFirst = false ;
+
+		document.write( c ) ;
+	}
+
+
+	document.write( '</td></tr>' ) ;
+}
+		</script>
+	</table>
+</body>
+</html>
Index: /FCKeditor/branches/features/style/editor/dtd/fck_xhtml10strict.js
===================================================================
--- /FCKeditor/branches/features/style/editor/dtd/fck_xhtml10strict.js	(revision 758)
+++ /FCKeditor/branches/features/style/editor/dtd/fck_xhtml10strict.js	(revision 758)
@@ -0,0 +1,116 @@
+/*
+ * 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 ==
+ *
+ * Contains the DTD mapping for XHTML 1.0 Strict.
+ * This file was automatically generated from the file: xhtml10-strict.dtd
+ */
+FCK.DTD = (function()
+{
+    X = FCKTools.Merge ;
+
+    var H,I,J,K,C,L,M,A,B,D,E,G,N,F ;
+    A = {ins:1, del:1, script:1} ;
+    B = {hr:1, ul:1, div:1, blockquote:1, noscript:1, table:1, address:1, pre:1, p:1, h5:1, dl:1, h4:1, ol:1, h6:1, h1:1, h3:1, h2:1} ;
+    C = X({fieldset:1}, B) ;
+    D = X({sub:1, bdo:1, 'var':1, sup:1, br:1, kbd:1, map:1, samp:1, b:1, acronym:1, '#':1, abbr:1, code:1, i:1, cite:1, tt:1, strong:1, q:1, em:1, big:1, small:1, span:1, dfn:1}, A) ;
+    E = X({img:1, object:1}, D) ;
+    F = {input:1, button:1, textarea:1, select:1, label:1} ;
+    G = X({a:1}, F) ;
+    H = {img:1, noscript:1, br:1, kbd:1, button:1, h5:1, h4:1, samp:1, h6:1, ol:1, h1:1, h3:1, h2:1, form:1, select:1, '#':1, ins:1, abbr:1, label:1, code:1, table:1, script:1, cite:1, input:1, strong:1, textarea:1, big:1, small:1, span:1, hr:1, sub:1, bdo:1, 'var':1, div:1, object:1, sup:1, map:1, dl:1, del:1, fieldset:1, ul:1, b:1, acronym:1, a:1, blockquote:1, i:1, address:1, tt:1, q:1, pre:1, p:1, em:1, dfn:1} ;
+
+    I = X({form:1, fieldset:1}, B, E, G) ;
+    J = {tr:1} ;
+    K = {'#':1} ;
+    L = X(E, G) ;
+    M = {li:1} ;
+    N = X({form:1}, A, C) ;
+
+    return {
+        col: {},
+        tr: {td:1, th:1},
+        img: {},
+        colgroup: {col:1},
+        noscript: N,
+        td: I,
+        br: {},
+        th: I,
+        kbd: L,
+        button: X(B, E),
+        h5: L,
+        h4: L,
+        samp: L,
+        h6: L,
+        ol: M,
+        h1: L,
+        h3: L,
+        option: K,
+        h2: L,
+        form: X(A, C),
+        select: {optgroup:1, option:1},
+        ins: I,
+        abbr: L,
+        label: L,
+        code: L,
+        table: {thead:1, col:1, tbody:1, tr:1, colgroup:1, caption:1, tfoot:1},
+        script: K,
+        tfoot: J,
+        cite: L,
+        li: I,
+        input: {},
+        strong: L,
+        textarea: K,
+        big: L,
+        small: L,
+        span: L,
+        dt: L,
+        hr: {},
+        sub: L,
+        optgroup: {option:1},
+        bdo: L,
+        param: {},
+        'var': L,
+        div: I,
+        object: X({param:1}, H),
+        sup: L,
+        dd: I,
+        area: {},
+        map: X({form:1, area:1}, A, C),
+        dl: {dt:1, dd:1},
+        del: I,
+        fieldset: X({legend:1}, H),
+        thead: J,
+        ul: M,
+        acronym: L,
+        b: L,
+        a: X({img:1, object:1}, D, F),
+        blockquote: N,
+        caption: L,
+        i: L,
+        tbody: J,
+        address: L,
+        tt: L,
+        legend: L,
+        q: L,
+        pre: X({a:1}, D, F),
+        p: L,
+        em: L,
+        dfn: L
+    } ;
+})() ;
Index: /FCKeditor/branches/features/style/editor/dtd/fck_xhtml10transitional.js
===================================================================
--- /FCKeditor/branches/features/style/editor/dtd/fck_xhtml10transitional.js	(revision 758)
+++ /FCKeditor/branches/features/style/editor/dtd/fck_xhtml10transitional.js	(revision 758)
@@ -0,0 +1,140 @@
+/*
+ * 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 ==
+ *
+ * Contains the DTD mapping for XHTML 1.0 Transitional.
+ * This file was automatically generated from the file: xhtml10-transitional.dtd
+ */
+FCK.DTD = (function()
+{
+    X = FCKTools.Merge ;
+
+    var A,L,J,M,N,O,D,H,P,K,Q,F,G,C,B,E,I ;
+    A = {isindex:1, fieldset:1} ;
+    B = {input:1, button:1, select:1, textarea:1, label:1} ;
+    C = X({a:1}, B) ;
+    D = X({iframe:1}, C) ;
+    E = {hr:1, ul:1, menu:1, div:1, blockquote:1, noscript:1, table:1, center:1, address:1, dir:1, pre:1, h5:1, dl:1, h4:1, noframes:1, h6:1, ol:1, h1:1, h3:1, h2:1} ;
+    F = {ins:1, del:1, script:1} ;
+    G = X({b:1, acronym:1, bdo:1, 'var':1, '#':1, abbr:1, code:1, br:1, i:1, cite:1, kbd:1, u:1, strike:1, s:1, tt:1, strong:1, q:1, samp:1, em:1, dfn:1, span:1}, F) ;
+    H = X({sub:1, img:1, object:1, sup:1, basefont:1, map:1, applet:1, font:1, big:1, small:1}, G) ;
+    I = X({p:1}, H) ;
+    J = X({iframe:1}, H, B) ;
+    K = {img:1, noscript:1, br:1, kbd:1, center:1, button:1, basefont:1, h5:1, h4:1, samp:1, h6:1, ol:1, h1:1, h3:1, h2:1, form:1, font:1, '#':1, select:1, menu:1, ins:1, abbr:1, label:1, code:1, table:1, script:1, cite:1, input:1, iframe:1, strong:1, textarea:1, noframes:1, big:1, small:1, span:1, hr:1, sub:1, bdo:1, 'var':1, div:1, object:1, sup:1, strike:1, dir:1, map:1, dl:1, applet:1, del:1, isindex:1, fieldset:1, ul:1, b:1, acronym:1, a:1, blockquote:1, i:1, u:1, s:1, tt:1, address:1, q:1, pre:1, p:1, em:1, dfn:1} ;
+
+    L = X({a:1}, J) ;
+    M = {tr:1} ;
+    N = {'#':1} ;
+    O = X({param:1}, K) ;
+    P = X({form:1}, A, D, E, I) ;
+    Q = {li:1} ;
+
+    return {
+        col: {},
+        tr: {td:1, th:1},
+        img: {},
+        colgroup: {col:1},
+        noscript: P,
+        td: P,
+        br: {},
+        th: P,
+        center: P,
+        kbd: L,
+        button: X(I, E),
+        basefont: {},
+        h5: L,
+        h4: L,
+        samp: L,
+        h6: L,
+        ol: Q,
+        h1: L,
+        h3: L,
+        option: N,
+        h2: L,
+        form: X(A, D, E, I),
+        select: {optgroup:1, option:1},
+        font: J,		// Changed from L to J (see (1))
+        ins: P,
+        menu: Q,
+        abbr: L,
+        label: L,
+        table: {thead:1, col:1, tbody:1, tr:1, colgroup:1, caption:1, tfoot:1},
+        code: L,
+        script: N,
+        tfoot: M,
+        cite: L,
+        li: P,
+        input: {},
+        iframe: P,
+        strong: J,		// Changed from L to J (see (1))
+        textarea: N,
+        noframes: P,
+        big: J,			// Changed from L to J (see (1))
+        small: J,		// Changed from L to J (see (1))
+        span: J,		// Changed from L to J (see (1))
+        hr: {},
+        dt: L,
+        sub: J,			// Changed from L to J (see (1))
+        optgroup: {option:1},
+        param: {},
+        bdo: L,
+        'var': J,		// Changed from L to J (see (1))
+        div: P,
+        object: O,
+        sup: J,			// Changed from L to J (see (1))
+        dd: P,
+        strike: J,		// Changed from L to J (see (1))
+        area: {},
+        dir: Q,
+        map: X({area:1, form:1, p:1}, A, F, E),
+        applet: O,
+        dl: {dt:1, dd:1},
+        del: P,
+        isindex: {},
+        fieldset: X({legend:1}, K),
+        thead: M,
+        ul: Q,
+        acronym: L,
+        b: J,			// Changed from L to J (see (1))
+        a: J,
+        blockquote: P,
+        caption: L,
+        i: J,			// Changed from L to J (see (1))
+        u: J,			// Changed from L to J (see (1))
+        tbody: M,
+        s: L,
+        address: X(D, I),
+        tt: J,			// Changed from L to J (see (1))
+        legend: L,
+        q: L,
+        pre: X(G, C),
+        p: L,
+        em: J,			// Changed from L to J (see (1))
+        dfn: L
+    } ;
+})() ;
+
+/*
+	Notes:
+	(1) According to the DTD, many elements, like <b> accept <a> elements
+	    inside of them. But, to produce better output results, we have manually
+	    changed the map to avoid breaking the links on pieces, having
+	    "<b>this is a </b><a><b>link</b> test</a>", instead of
+	    "<b>this is a <a>link</a></b><a> test</a>".
+*/
Index: /FCKeditor/branches/features/style/editor/fckeditor.html
===================================================================
--- /FCKeditor/branches/features/style/editor/fckeditor.html	(revision 757)
+++ /FCKeditor/branches/features/style/editor/fckeditor.html	(revision 758)
@@ -1,3 +1,3 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+﻿<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
 <!--
  * FCKeditor - The text editor for Internet - http://www.fckeditor.net
@@ -86,4 +86,8 @@
 LoadScript( '_source/classes/fckkeystrokehandler.js' ) ;
 
+LoadScript( 'dtd/fck_xhtml10transitional.js' ) ;
+LoadScript( '_source/classes/fckstyle.js' ) ;
+LoadScript( '_source/internals/fckstyles.js' ) ;
+
 LoadScript( '_source/internals/fcklisthandler.js' ) ;
 LoadScript( '_source/classes/fckelementpath.js' ) ;
@@ -106,4 +110,5 @@
 
 LoadScript( '_source/commandclasses/fcknamedcommand.js' ) ;
+LoadScript( '_source/commandclasses/fckstylecommand.js' ) ;
 LoadScript( '_source/commandclasses/fck_othercommands.js' ) ;
 LoadScript( '_source/commandclasses/fckshowblocks.js' ) ;
@@ -113,7 +118,8 @@
 LoadScript( '_source/commandclasses/fckpastewordcommand.js' ) ;
 LoadScript( '_source/commandclasses/fcktablecommand.js' ) ;
-LoadScript( '_source/commandclasses/fckstylecommand.js' ) ;
 LoadScript( '_source/commandclasses/fckfitwindow.js' ) ;
 LoadScript( '_source/commandclasses/fcklistcommands.js' ) ;
+LoadScript( '_source/commandclasses/fckcorestylecommand.js' ) ;
+LoadScript( '_source/commandclasses/fckremoveformatcommand.js' ) ;
 LoadScript( '_source/internals/fckcommands.js' ) ;
 
@@ -124,8 +130,8 @@
 LoadScript( '_source/classes/fckspecialcombo.js' ) ;
 LoadScript( '_source/classes/fcktoolbarspecialcombo.js' ) ;
+LoadScript( '_source/classes/fcktoolbarstylecombo.js' ) ;
+LoadScript( '_source/classes/fcktoolbarfontformatcombo.js' ) ;
 LoadScript( '_source/classes/fcktoolbarfontscombo.js' ) ;
 LoadScript( '_source/classes/fcktoolbarfontsizecombo.js' ) ;
-LoadScript( '_source/classes/fcktoolbarfontformatcombo.js' ) ;
-LoadScript( '_source/classes/fcktoolbarstylecombo.js' ) ;
 LoadScript( '_source/classes/fcktoolbarpanelbutton.js' ) ;
 LoadScript( '_source/internals/fcktoolbaritems.js' ) ;
@@ -169,4 +175,9 @@
 	FCK.IECleanup.AddItem( FCK, FCK_Cleanup ) ;
 }
+
+// The first function to be called on selection change must the the styles
+// change checker, because the result of its processing may be used by another
+// functions listening to the same event.
+FCK.Events.AttachEvent( 'OnSelectionChange', function() { FCKStyles.CheckSelectionChanges() ; } ) ;
 
 // The config hidden field is processed immediately, because
Index: /FCKeditor/branches/features/style/fckconfig.js
===================================================================
--- /FCKeditor/branches/features/style/fckconfig.js	(revision 757)
+++ /FCKeditor/branches/features/style/fckconfig.js	(revision 758)
@@ -74,5 +74,4 @@
 FCKConfig.FormatIndentator	= '    ' ;
 
-FCKConfig.ForceStrongEm = true ;
 FCKConfig.GeckoUseSPAN	= false ;
 FCKConfig.StartupFocus	= false ;
@@ -109,5 +108,5 @@
 	['Style','FontFormat','FontName','FontSize'],
 	['TextColor','BGColor'],
-	['FitWindow','ShowBlocks','-','About']
+	['FitWindow','ShowBlocks','-','About']		// No comma for the last row.
 ] ;
 
@@ -146,7 +145,7 @@
 FCKConfig.FontColors = '000000,993300,333300,003300,003366,000080,333399,333333,800000,FF6600,808000,808080,008080,0000FF,666699,808080,FF0000,FF9900,99CC00,339966,33CCCC,3366FF,800080,999999,FF00FF,FFCC00,FFFF00,00FF00,00FFFF,00CCFF,993366,C0C0C0,FF99CC,FFCC99,FFFF99,CCFFCC,CCFFFF,99CCFF,CC99FF,FFFFFF' ;
 
+FCKConfig.FontFormats	= 'p;div;pre;address;h1;h2;h3;h4;h5;h6' ;
 FCKConfig.FontNames		= 'Arial;Comic Sans MS;Courier New;Tahoma;Times New Roman;Verdana' ;
-FCKConfig.FontSizes		= '1/xx-small;2/x-small;3/small;4/medium;5/large;6/x-large;7/xx-large' ;
-FCKConfig.FontFormats	= 'p;div;pre;address;h1;h2;h3;h4;h5;h6' ;
+FCKConfig.FontSizes		= 'smaller;larger;xx-small;x-small;small;medium;large;x-large;xx-large' ;
 
 FCKConfig.StylesXmlPath		= FCKConfig.EditorPath + 'fckstyles.xml' ;
@@ -186,4 +185,37 @@
 // The option switches between trying to keep the html structure or do the changes so the content looks like it was in Word
 FCKConfig.CleanWordKeepsStructure = false ;
+
+// Only inline elements are valid.
+FCKConfig.RemoveFormatTags = 'b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var' ;
+
+// Do not add, rename or remove styles here. Only apply definition changes.
+FCKConfig.CoreStyles = 
+{
+	// Basic Inline Styles.
+	'Bold'			: { Element : 'b', Overrides : 'strong' },
+	'Italic'		: { Element : 'i', Overrides : 'em' },
+	'Underline'		: { Element : 'u' },
+	'StrikeThrough'	: { Element : 'strike' },
+	'Subscript'		: { Element : 'sub' },
+	'Superscript'	: { Element : 'sup' },
+	
+	// Basic Block Styles (Font Format Combo).
+	'p'				: { Element : 'p' },
+	'div'			: { Element : 'div' },
+	'pre'			: { Element : 'pre' },
+	'address'		: { Element : 'address' },
+	'h1'			: { Element : 'h1' },
+	'h2'			: { Element : 'h2' },
+	'h3'			: { Element : 'h3' },
+	'h4'			: { Element : 'h4' },
+	'h5'			: { Element : 'h5' },
+	'h6'			: { Element : 'h6' },
+	
+	// Other formatting features.
+	'FontFace'		: { Element : 'span', Styles : { 'font-family' : '#("Font")' } },
+	'Size'			: { Element : 'span', Styles : { 'font-size' : '#("Size","fontSize")' } },
+	'Color'			: { Element : 'span', Styles : { 'color' : '#("Color","color")' } },
+	'BackColor'		: { Element : 'span', Styles : { 'background-color' : '#("Color","color")' } }
+};
 
 // The following value defines which File Browser connector and Quick Upload
Index: /FCKeditor/branches/features/style/fckeditor.cfc
===================================================================
--- /FCKeditor/branches/features/style/fckeditor.cfc	(revision 757)
+++ /FCKeditor/branches/features/style/fckeditor.cfc	(revision 758)
@@ -211,5 +211,5 @@
 	lConfigKeys = lConfigKeys & ",PreloadImages,PluginsPath,AutoDetectLanguage,DefaultLanguage,ContentLangDirection";
 	lConfigKeys = lConfigKeys & ",ProcessHTMLEntities,IncludeLatinEntities,IncludeGreekEntities,ProcessNumericEntities,AdditionalNumericEntities";
-	lConfigKeys = lConfigKeys & ",FillEmptyBlocks,FormatSource,FormatOutput,FormatIndentator,ForceStrongEm";
+	lConfigKeys = lConfigKeys & ",FillEmptyBlocks,FormatSource,FormatOutput,FormatIndentator";
 	lConfigKeys = lConfigKeys & ",GeckoUseSPAN,StartupFocus,ForcePasteAsPlainText,AutoDetectPasteFromWord,ForceSimpleAmpersand";
 	lConfigKeys = lConfigKeys & ",TabSpaces,ShowBorders,SourcePopup,ToolbarStartExpanded,ToolbarCanCollapse";
Index: /FCKeditor/branches/features/style/fckeditor.cfm
===================================================================
--- /FCKeditor/branches/features/style/fckeditor.cfm	(revision 757)
+++ /FCKeditor/branches/features/style/fckeditor.cfm	(revision 758)
@@ -122,5 +122,5 @@
 		lConfigKeys = lConfigKeys & ",PreloadImages,PluginsPath,AutoDetectLanguage,DefaultLanguage,ContentLangDirection";
 		lConfigKeys = lConfigKeys & ",ProcessHTMLEntities,IncludeLatinEntities,IncludeGreekEntities,ProcessNumericEntities,AdditionalNumericEntities";
-		lConfigKeys = lConfigKeys & ",FillEmptyBlocks,FormatSource,FormatOutput,FormatIndentator,ForceStrongEm";
+		lConfigKeys = lConfigKeys & ",FillEmptyBlocks,FormatSource,FormatOutput,FormatIndentator";
 		lConfigKeys = lConfigKeys & ",GeckoUseSPAN,StartupFocus,ForcePasteAsPlainText,AutoDetectPasteFromWord,ForceSimpleAmpersand";
 		lConfigKeys = lConfigKeys & ",TabSpaces,ShowBorders,SourcePopup,ToolbarStartExpanded,ToolbarCanCollapse";
Index: /FCKeditor/branches/features/style/fckpackager.xml
===================================================================
--- /FCKeditor/branches/features/style/fckpackager.xml	(revision 757)
+++ /FCKeditor/branches/features/style/fckpackager.xml	(revision 758)
@@ -63,4 +63,7 @@
 		<Constant name="FCK_EDITMODE_WYSIWYG" value="0" />
 		<Constant name="FCK_EDITMODE_SOURCE" value="1" />
+		<Constant name="FCK_STYLE_BLOCK" value="0" />
+		<Constant name="FCK_STYLE_INLINE" value="1" />
+		<Constant name="FCK_STYLE_OBJECT" value="2" />
 	</Constants>
 	<PackageFile path="editor/js/fckeditorcode_ie.js">
Index: /FCKeditor/branches/features/style/fckstyles.xml
===================================================================
--- /FCKeditor/branches/features/style/fckstyles.xml	(revision 757)
+++ /FCKeditor/branches/features/style/fckstyles.xml	(revision 758)
@@ -26,4 +26,68 @@
 -->
 <Styles>
+	<!-- Block Styles -->
+
+	<!--
+	# These styles are already available in the "Format" combo, so they are not
+	# needed here.
+
+	<Style name="Heading 1" element="h1" />
+	<Style name="Heading 2" element="h2" />
+	<Style name="Heading 3" element="h3" />
+	<Style name="Heading 4" element="h4" />
+	<Style name="Heading 5" element="h5" />
+	<Style name="Heading 6" element="h6" />
+	<Style name="Paragraph" element="p" />
+	<Style name="Document Block" element="div" />
+	<Style name="Preformatted Text" element="pre" />
+	<Style name="Address" element="address" />
+	-->
+
+	<!-- Inline Styles -->
+
+	<!--
+	# These are core styles available as toolbar buttons.
+
+	<Style name="Bold" element="b" />
+	<Style name="Italic" element="i" />
+	<Style name="Underline" element="u" />
+	<Style name="Strikethrough" element="strike" />
+	<Style name="Subscript" element="sub" />
+	<Style name="Superscript" element="sup" />
+	-->
+
+	<Style name="Strong Emphasis" element="strong" />
+	<Style name="Emphasis" element="em" />
+
+	<Style name="Big" element="big" />
+	<Style name="Small" element="small" />
+	<Style name="Typewriter" element="tt" />
+
+	<Style name="Computer Code" element="code" />
+	<Style name="Keyboard Phrase" element="kbd" />
+	<Style name="Sample Text" element="samp" />
+	<Style name="Variable" element="var" />
+
+	<Style name="Deleted Text" element="del" />
+	<Style name="Inserted Text" element="ins" />
+
+	<Style name="Cited Work" element="cite" />
+	<Style name="Inline Quotation" element="q" />
+
+	<Style name="Language: RTL" element="span">
+		<Attribute name="dir" value="rtl" />
+	</Style>
+	<Style name="Language: LTR" element="span">
+		<Attribute name="dir" value="ltr" />
+	</Style>
+	<Style name="Language: RTL Strong" element="bdo">
+		<Attribute name="dir" value="rtl" />
+	</Style>
+	<Style name="Language: LTR Strong" element="bdo">
+		<Attribute name="dir" value="ltr" />
+	</Style>
+
+	<!-- Object Styles -->
+
 	<Style name="Image on Left" element="img">
 		<Attribute name="style" value="padding: 5px; margin-right: 5px" />
@@ -36,18 +100,3 @@
 		<Attribute name="align" value="right" />
 	</Style>
-	<Style name="Custom Bold" element="span">
-		<Attribute name="style" value="font-weight: bold;" />
-	</Style>
-	<Style name="Custom Italic" element="em" />
-	<Style name="Title" element="span">
-		<Attribute name="class" value="Title" />
-	</Style>
-	<Style name="Code" element="span">
-		<Attribute name="class" value="Code" />
-	</Style>
-	<Style name="Title H3" element="h3" />
-	<Style name="Custom Ruler" element="hr">
-		<Attribute name="size" value="1" />
-		<Attribute name="color" value="#ff0000" />
-	</Style>
 </Styles>
