Index: /FCKeditor/trunk/editor/_source/classes/fckdomrange.js
===================================================================
--- /FCKeditor/trunk/editor/_source/classes/fckdomrange.js	(revision 823)
+++ /FCKeditor/trunk/editor/_source/classes/fckdomrange.js	(revision 824)
@@ -359,32 +359,6 @@
 		// Then, we record down the precise position of the container nodes
 		// by walking up the DOM tree and counting their childNode index
-		var curNode = this._Range.startContainer ;
-		while ( curNode && curNode != this.Window.document.documentElement )
-		{
-			var curParent = curNode.parentNode ;
-			for( var i = 0 ; i < curParent.childNodes.length ; i++ )
-			{
-				if ( curParent.childNodes.item( i ) == curNode )
-				{
-					bookmark.Start.unshift( i ) ;
-					break ;
-				}
-			}
-			curNode = curParent;
-		}
-		curNode = this._Range.endContainer;
-		while ( curNode && curNode != this.Window.document.documentElement )
-		{
-			var curParent = curNode.parentNode;
-			for ( var i = 0 ; i < curParent.childNodes.length ; i++ )
-			{
-				if ( curParent.childNodes.item( i ) == curNode )
-				{
-					bookmark.End.unshift( i );
-					break;
-				}
-			}
-			curNode = curParent;
-		}
+		bookmark.Start = FCKDomTools.GetNodeAddress( this._Range.startContainer ).concat( bookmark.Start ) ;
+		bookmark.End = FCKDomTools.GetNodeAddress( this._Range.endContainer ).concat( bookmark.End ) ;
 		return bookmark;
 	},
@@ -393,10 +367,6 @@
 	{
 		// Reverse the childNode counting algorithm in CreateBookmark2()
-		var curStart = this.Window.document.documentElement ;
-		var curEnd = this.Window.document.documentElement ;
-		for ( var i = 0 ; i < bookmark.Start.length - 1 ; i++ )
-			curStart = curStart.childNodes.item( bookmark.Start[ i ] ) ;
-		for ( var i = 0 ; i < bookmark.End.length - 1 ; i++ )
-			curEnd = curEnd.childNodes.item( bookmark.End[ i ] ) ;
+		var curStart = FCKDomTools.GetNodeFromAddress( this.Window.document, bookmark.Start.slice( 0, -1 ) ) ;
+		var curEnd = FCKDomTools.GetNodeFromAddress( this.Window.document, bookmark.End.slice( 0, -1 ) ) ;
 
 		// Generate the W3C Range object and update relevant data
Index: /FCKeditor/trunk/editor/_source/commandclasses/fckjustifycommands.js
===================================================================
--- /FCKeditor/trunk/editor/_source/commandclasses/fckjustifycommands.js	(revision 823)
+++ /FCKeditor/trunk/editor/_source/commandclasses/fckjustifycommands.js	(revision 824)
@@ -24,6 +24,8 @@
 var FCKJustifyCommand = function( alignValue )
 {
-	this.AlignVaue = alignValue ;
+	this.AlignValue = alignValue ;
 	this.CurrentState = FCK_TRISTATE_DISABLED ;
+	this.DefaultAlign = ( alignValue == 'left' && FCKConfig.ContentLangDirection.IEquals( 'ltr' ) ) ||
+			( alignValue == 'right' && FCKConfig.ContentLangDirection.IEquals( 'rtl' ) ) ;
 }
 
@@ -34,28 +36,34 @@
 		var range = new FCKDomRange( FCK.EditorWindow ) ;
 		range.MoveToSelection() ;
+
+		// Store a bookmark of the selection since the paragraph iterator might change the DOM tree and break selections.
 		var bookmark = range.CreateBookmark() ;
-		var paragraphs = range.GetParagraphs() ;
+		var iterator = new FCKDomRangeIterator( range ) ;
+		var block = null ;
+		var cssClassName = this._GetCSSClassName() ;
 
-		while ( paragraphs.length > 0 )
+		// Apply alignment setting for each paragraph.
+		while ( ( block = iterator.GetNextParagraph() ) )
 		{
-			range = paragraphs.shift() ;
-			if ( range.GetText().search( /^[\r\n\t ]*$/ ) == 0 )
-				continue ;
+			block.removeAttribute( 'align' ) ;
 
-			if ( range.StartContainer == range.Window.document.body )
-				range.FixBlock( true ) ;
-			range.StartContainer.removeAttribute( 'align' ) ;
-
-			if ( this.CurrentState == FCK_TRISTATE_OFF)
-				range.StartContainer.style.textAlign = this.AlignVaue ;
-			else if ( this.CurrentState == FCK_TRISTATE_ON )
-				range.StartContainer.style.textAlign = '' ;
-
-			var nextNode = range.EndNode ;
-			while ( nextNode.lastChild )
-				nextNode = nextNode.lastChild ;
-			currentNode = nextNode = FCKDomTools.GetNextSourceNode( nextNode ) ;
+			if ( cssClassName )
+			{
+				block.className = block.className.replace( FCKConfig.JustifyClassPattern, ' ' ) ;
+				if ( block.className.length && block.className.charAt( block.className.length - 1 ) != ' ' )
+					block.className += ' ' + cssClassName ;
+				else
+					block.className += cssClassName ;
+			}
+			else
+			{
+				if ( this.CurrentState == FCK_TRISTATE_OFF)
+					block.style.textAlign = this.AlignValue ;
+				else if ( this.CurrentState == FCK_TRISTATE_ON )
+					block.style.textAlign = '' ;
+			}
 		}
 
+		// Restore previous selection.
 		range.MoveToBookmark( bookmark ) ;
 		range.Select() ;
@@ -71,7 +79,25 @@
 		}
 
-		var nearestBlock = FCKSelection.GetParentBlock() ;
+		// Retrieve the first selected block.
+		var firstBlock = null ;
+		if ( FCKBrowserInfo.IsIE )
+		{
+			var range = FCK.EditorDocument.selection.createRange() ;
+			range.collapse( true ) ;
+			firstBlock = ( new FCKElementPath( range.parentElement() ) ).Block ;
+		}
+		else
+		{
+			var sel = FCK.EditorWindow.getSelection() ;
+			if ( ! sel || sel.rangeCount < 0 )
+			{
+				this.CurrentState = FCK_TRISTATE_DISABLED ;
+				return this.CurrentState ;
+			}
+			var range = sel.getRangeAt( 0 ) ;
+			firstBlock = ( new FCKElementPath( range.startContainer ) ).Block ;
+		}
 
-		if ( ! nearestBlock )
+		if ( ! firstBlock || firstBlock.nodeName.IEquals( 'body' ) )
 		{
 			this.CurrentState = FCK_TRISTATE_OFF ;
@@ -79,14 +105,43 @@
 		}
 
-		if ( nearestBlock.align == this.AlignVaue || nearestBlock.style.textAlign == this.AlignVaue  )
+		// See if the desired style is already applied to the first block.
+		var cssClassName = this._GetCSSClassName() ;
+		if ( ! cssClassName )
 		{
-			this.CurrentState = FCK_TRISTATE_ON ;
-			return this.CurrentState ;
+			if ( ! firstBlock.align && ! firstBlock.style.textAlign && this.DefaultAlign )
+				return FCK_TRISTATE_ON ;
+			this.CurrentState = ( firstBlock.align == this.AlignValue || firstBlock.style.textAlign == this.AlignValue ?
+					FCK_TRISTATE_ON : FCK_TRISTATE_OFF ) ;
 		}
 		else
 		{
-			this.CurrentState = FCK_TRISTATE_OFF ;
-			return this.CurrentState ;
+			if ( firstBlock.className.search( FCKConfig.JustifyClassPattern ) == -1 && this.DefaultAlign )
+				return FCK_TRISTATE_ON ;
+			this.CurrentState = ( firstBlock.className.search( new RegExp( '(^|\\s+)' + cssClassName + '($|\\s+)' ) ) == -1 ? 
+						FCK_TRISTATE_OFF : FCK_TRISTATE_ON ) ;
 		}
+
+		return this.CurrentState ;
+	},
+
+	_GetCSSClassName : function()
+	{
+		var cssClassName = null ;
+		switch ( this.AlignValue )
+		{
+			case 'left' :
+				cssClassName = FCKConfig.LeftJustifyClass ;
+				break ;
+			case 'right' :
+				cssClassName = FCKConfig.RightJustifyClass ;
+				break ;
+			case 'center' :
+				cssClassName = FCKConfig.CenterJustifyClass ;
+				break ;
+			case 'justify' :
+				cssClassName = FCKConfig.FullJustifyClass ;
+				break ;
+		}
+		return cssClassName ;
 	}
 } ;
Index: /FCKeditor/trunk/editor/_source/internals/fckdomtools.js
===================================================================
--- /FCKeditor/trunk/editor/_source/internals/fckdomtools.js	(revision 823)
+++ /FCKeditor/trunk/editor/_source/internals/fckdomtools.js	(revision 824)
@@ -532,4 +532,38 @@
 		range.Release( !!reusableRange ) ;
 	},
+
+	/**
+	 * Retrieves a uniquely identifiable tree address of a DOM tree node.
+	 * The tree address returns is an array of integers, with each integer indicating a child index from a DOM tree node,
+	 * starting from document.documentElement.
+	 *
+	 * For example, assuming <body> is the second child from <html> (<head> being the first), and we'd like to address
+	 * the third child under the fourth child of body, the tree address returned would be:
+	 * [1, 3, 2]
+	 *
+	 * The tree address cannot be used for finding back the DOM tree node once the DOM tree structure has been modified.
+	 */
+	GetNodeAddress : function( node )
+	{
+		var retval = [] ;
+		while ( node && node != node.ownerDocument.documentElement )
+		{
+			retval.unshift( this.GetIndexOf( node ) ) ;
+			node = node.parentNode ;
+		}
+		return retval ;
+	},
+
+	/**
+	 * The reverse transformation of FCKDomTools.GetNodeAddress(). This function returns the DOM node pointed to by its
+	 * index address.
+	 */
+	GetNodeFromAddress : function( doc, addr )
+	{
+		var cursor = doc.documentElement ;
+		for ( var i = 0 ; i < addr.length ; i++ )
+			cursor = cursor.childNodes[ addr[i] ] ;
+		return cursor ;
+	},
 	
 	CloneElement : function( element )
Index: /FCKeditor/trunk/fckconfig.js
===================================================================
--- /FCKeditor/trunk/fckconfig.js	(revision 823)
+++ /FCKeditor/trunk/fckconfig.js	(revision 824)
@@ -59,4 +59,7 @@
 FCKConfig.DefaultLanguage		= 'en' ;
 FCKConfig.ContentLangDirection	= 'ltr' ;
+
+// The distance of an indentation step, in pixels.
+FCKConfig.IndentLength = 25 ;
 
 FCKConfig.ProcessHTMLEntities	= true ;
@@ -291,2 +294,11 @@
 FCKConfig.SmileyWindowWidth		= 320 ;
 FCKConfig.SmileyWindowHeight	= 240 ;
+
+// XHTML 1.1 compliant options example
+/*
+FCKConfig.JustifyClassPattern = /(^|\s+)Justify(Left|Right|Center|Full)($|\s+)/ ;
+FCKConfig.LeftJustifyClass = 'JustifyLeft' ;
+FCKConfig.RightJustifyClass = 'JustifyRight' ;
+FCKConfig.CenterJustifyClass = 'JustifyCenter' ;
+FCKConfig.FullJustifyClass = 'JustifyFull' ;
+*/
