Index: /FCKeditor/trunk/editor/_source/commandclasses/fckindentcommands.js
===================================================================
--- /FCKeditor/trunk/editor/_source/commandclasses/fckindentcommands.js	(revision 845)
+++ /FCKeditor/trunk/editor/_source/commandclasses/fckindentcommands.js	(revision 846)
@@ -85,5 +85,14 @@
 		var listNode = FCKDomTools.GetCommonParentNode( startContainer, endContainer, ['ul','ol'] ) ;
 
-		if ( ( ! FCKIndentCommand._UseIndentClasses && this.Name.IEquals( 'indent' ) ) || listNode )
+		if ( listNode )
+		{
+			if ( this.Name.IEquals( 'outdent' ) )
+				return FCK_TRISTATE_OFF ;
+			var firstItem = FCKTools.GetElementAscensor( startContainer, 'li' ) ;
+			if ( !firstItem || !firstItem.previousSibling )
+				return FCK_TRISTATE_DISABLED ;
+			return FCK_TRISTATE_OFF ;
+		}
+		if ( ! FCKIndentCommand._UseIndentClasses && this.Name.IEquals( 'indent' ) )
 			return FCK_TRISTATE_OFF;
 
@@ -166,5 +175,8 @@
 				currentOffset += this.Offset ;
 				currentOffset = Math.max( currentOffset, 0 ) ;
-				block.style[this.IndentCSSProperty] = currentOffset + 'px' ;
+				currentOffset = Math.ceil( currentOffset / this.Offset ) * this.Offset ;
+				block.style[this.IndentCSSProperty] = currentOffset ? currentOffset + 'px' : '' ;
+				if ( block.getAttribute( 'style' ) == '' )
+					block.removeAttribute( 'style' ) ;
 			}
 		}
@@ -177,7 +189,7 @@
 		var startContainer = range.StartContainer ;
 		var endContainer = range.EndContainer ;
-		while ( startContainer && ! startContainer.nodeName.IEquals( ['li', 'ul', 'ol'] ) ) 
+		while ( startContainer && startContainer.parentNode != listNode ) 
 			startContainer = startContainer.parentNode ;
-		while ( endContainer && ! endContainer.nodeName.IEquals( ['li', 'ul', 'ol'] ) )
+		while ( endContainer && endContainer.parentNode != listNode )
 			endContainer = endContainer.parentNode ;
 
@@ -185,78 +197,79 @@
 			return ;
 
-		range.SetStart( startContainer, 1 ) ;
-		range.SetEnd( endContainer, 2 ) ;
-
-		// Now we can iterate over the individual items.
-		var iterator = new FCKDomRangeIterator( range ) ;
-		var block ;
+		// Now we can iterate over the individual items on the same tree depth.
+		var block = startContainer ;
 		var itemsToMove = [] ;
-		while ( ( block = iterator.GetNextParagraph() ) )
-		{
-			if ( block.parentNode == listNode )
-				itemsToMove.push( block ) ;
+		var stopFlag = false ;
+		while ( stopFlag == false ) 
+		{
+			if ( block == endContainer )
+				stopFlag = true ;
+			itemsToMove.push( block ) ;
+			block = block.nextSibling ;
 		}
 		if ( itemsToMove.length < 1 )
 			return ;
+
+		// Do indent or outdent operations on the array model of the list, not the list's DOM tree itself.
+		// The array model demands that it knows as much as possible about the surrounding lists, we need 
+		// to feed it the further ancestor node that is still a list.
+		var listParents = FCKDomTools.GetParents( listNode ) ;
+		for ( var i = 0 ; i < listParents.length ; i++ )
+		{
+			if ( listParents[i].nodeName.IEquals( ['ul', 'ol'] ) )
+			{
+				listNode = listParents[i] ;
+				break ;
+			}
+		}
+		var indentOffset = this.Name.IEquals( 'indent' ) ? 1 : -1 ;
+		var startItem = itemsToMove[0] ;
 		var lastItem = itemsToMove[ itemsToMove.length - 1 ] ;
-
-		if ( this.Name.IEquals( 'indent' ) )
-		{
-			// Indent is easy... just clone the list node, add under the original, and 
-			// move the contents inside the clone.
-			var indentList = listNode.cloneNode( false ) ;
-			FCKDomTools.InsertAfterNode( lastItem, indentList ) ;
-			while ( itemsToMove.length > 0 )
-				indentList.appendChild( itemsToMove.shift() ) ;
-		}
-		else if ( this.Name.IEquals( 'outdent' ) )
-		{
-			var startItem = itemsToMove[0] ;
-
-			// If we're in the middle of the list, we will have to split the list into two.
-			if ( startItem.previousSibling && lastItem.nextSibling )
-			{
-				range.SetStart( startItem, 3 ) ;
-				range.SetEnd( startItem, 3 ) ;
-				listNode = range.SplitBlock().NextBlock ;
-			}
-
-			// Remove the list items.
-			for ( var i = 0 ; i < itemsToMove.length ; i++ )
-				itemsToMove[i].parentNode.removeChild( itemsToMove[i] )  ;
-
-			// If the parent of listNode is not another list, then we need to convert the 
-			// listItems into paragraphs, depending on EnterMode.
-			if ( ! listNode.parentNode.nodeName.IEquals( ['ul', 'ol'] ) )
-			{
-				for ( var i = 0 ; i < itemsToMove.length ; i++ )
+		var markerObj = {} ;
+
+		// Convert the list DOM tree into a one dimensional array.
+		var listArray = FCKDomTools.ListToArray( listNode, null, null, markerObj ) ;
+
+		// Apply indenting or outdenting on the array.
+		var baseIndent = listArray[lastItem._FCK_ListArray_Index].indent ;
+		for ( var i = startItem._FCK_ListArray_Index ; i <= lastItem._FCK_ListArray_Index ; i++ ) 
+			listArray[i].indent += indentOffset ;
+		for ( var i = lastItem._FCK_ListArray_Index + 1 ; i < listArray.length && listArray[i].indent > baseIndent ; i++ )
+			listArray[i].indent += indentOffset ;
+
+		/* For debug use only
+		var PrintArray = function( listArray, doc )
+		{
+			var s = [] ;
+			for ( var i = 0 ; i < listArray.length ; i++ )
+			{
+				for ( var j in listArray[i] )
 				{
-					var container ;
-					if ( FCKConfig.EnterMode.IEquals( ['p', 'div'] ) )
-						container = listNode.ownerDocument.createElement( FCKConfig.EnterMode ) ;
+					if ( j != 'contents' )
+						s.push( j + ":" + listArray[i][j] + "; " ) ;
 					else
 					{
-						container = listNode.ownerDocument.createDocumentFragment() ;
-						container.appendChild( listNode.ownerDocument.createElement( 'br' ) ) ;
+						var docFrag = doc.createDocumentFragment() ;
+						var tmpNode = doc.createElement( 'span' ) ;
+						for ( var k = 0 ; k < listArray[i][j].length ; k++ )
+							docFrag.appendChild( listArray[i][j][k].cloneNode( true ) ) ;
+						tmpNode.appendChild( docFrag ) ;
+						s.push( j + ":" + tmpNode.innerHTML + "; ") ;
 					}
-
-					var listItem = itemsToMove[i] ;
-					while ( listItem.lastChild )
-					{
-						var node = listItem.removeChild( listItem.lastChild ) ;
-						container.insertBefore( node, container.firstChild ) ;
-					}
-					itemsToMove[i] = container ;
 				}
-			}
-
-			// Insert the content nodes to listNode's parent.
-			while ( itemsToMove.length > 0 )
-				listNode.parentNode.insertBefore( itemsToMove.shift(), listNode ) ;
-
-			// Cleanup: if the listNode becomes empty, remove it.
-			if ( ! listNode.lastChild )
-				listNode.parentNode.removeChild( listNode ) ;
-		}
+				s.push( '\n' ) ;
+			}
+			alert( s.join('') ) ;
+		}
+		PrintArray( listArray, FCK.EditorDocument ) ;
+		*/
+
+		// Convert the array back to a DOM forest (yes we might have a few subtrees now).
+		// And replace the old list with the new forest.
+		var newList = FCKDomTools.ArrayToList( listArray ) ;
+		listNode.parentNode.replaceChild( newList.listNode, listNode ) ;
+
+		// Clean up the markers.
+		FCKDomTools.ClearElementMarkers( markerObj ) ;
 	}
 } ;
Index: /FCKeditor/trunk/editor/_source/internals/fckdomtools.js
===================================================================
--- /FCKeditor/trunk/editor/_source/internals/fckdomtools.js	(revision 845)
+++ /FCKeditor/trunk/editor/_source/internals/fckdomtools.js	(revision 846)
@@ -575,4 +575,140 @@
 		
 		return element ;
+	},
+
+	ClearElementJSProperty : function( element, attrName )
+	{
+		if ( FCKBrowserInfo.IsIE )
+			element.removeAttribute( attrName ) ;
+		else
+			delete element[attrName] ;
+	},
+
+	SetElementMarker : function ( markObj, element, attrName, value)
+	{
+		var id = String( parseInt( Math.random() * 0xfffffff, 10 ) ) ;
+		element._FCKMarkerId = id ;
+		element[attrName] = value ;
+		if ( ! markObj[id] )
+			markObj[id] = { 'element' : element, 'markers' : {} } ;
+		markObj[id]['markers'][attrName] = value ;
+	},
+
+	ClearElementMarkers : function( markObj )
+	{
+		for ( var i in markObj )
+		{
+			var element = markObj[i]['element'] ;
+			this.ClearElementJSProperty( element, '_FCKMarkerId' ) ;
+			for ( var j in markObj[i]['markers'] )
+				this.ClearElementJSProperty( element, j ) ;
+			delete markObj[i] ;
+		}
+	},
+
+	// Convert a DOM list tree into a data structure that is easier to manipulate.
+	// This operation should be non-intrusive in the sense that it does not change the DOM tree,
+	// with the exception that it may add some markers to the list item nodes when markerObj is specified.
+	ListToArray : function( listNode, baseArray, baseIndentLevel, markerObj )
+	{
+		if ( ! listNode.nodeName.IEquals( ['ul', 'ol'] ) )
+			return [] ;
+
+		if ( ! baseIndentLevel )
+			baseIndentLevel = 0 ;
+		if ( ! baseArray )
+			baseArray = [] ;
+		// Iterate over all list items to get their contents and look for inner lists.
+		for ( var i = 0 ; i < listNode.childNodes.length ; i++ )
+		{
+			var listItem = listNode.childNodes[i] ;
+			if ( ! listItem.nodeName.IEquals( 'li' ) )
+				continue ;
+			var itemObj = { 'grandparent' : listNode.parentNode, 'parent' : listNode, 'indent' : baseIndentLevel, 'contents' : [] } ;
+			if ( itemObj.grandparent && itemObj.grandparent.nodeName.IEquals( 'li' ) )
+				itemObj.grandparent = itemObj.grandparent.parentNode ;
+			if ( markerObj )
+				this.SetElementMarker( markerObj, listItem, '_FCK_ListArray_Index', baseArray.length ) ;
+			baseArray.push( itemObj ) ;
+			for ( var j = 0 ; j < listItem.childNodes.length ; j++ )
+			{
+				var child = listItem.childNodes[j] ;
+				if ( child.nodeName.IEquals( ['ul', 'ol'] ) )
+					// Note the recursion here, it pushes inner list items with +1 indentation in the correct
+					// order.
+					this.ListToArray( child, baseArray, baseIndentLevel + 1, markerObj ) ;
+				else
+					itemObj.contents.push( child ) ;
+			}
+		}
+		return baseArray ;
+	},
+
+	// Convert our internal representation of a list back to a DOM tree.
+	ArrayToList : function( listArray, baseIndex )
+	{
+		if ( baseIndex == undefined )
+			baseIndex = 0 ;
+		if ( ! listArray || listArray.length < baseIndex + 1 )
+			return null ;
+		var retval = listArray[baseIndex].parent.ownerDocument.createDocumentFragment() ;
+		var rootNode = listArray[baseIndex].parent.cloneNode( false ) ;
+		retval.appendChild( rootNode ) ;
+		var currentIndex = baseIndex ;
+		var indentLevel = listArray[baseIndex].indent ;
+		var currentListItem = null ;
+		while ( true )
+		{
+			var item = listArray[currentIndex] ;
+			if ( item.indent == indentLevel )
+			{
+				if ( ! rootNode || listArray[currentIndex].parent.nodeName != rootNode.nodeName )
+				{
+					rootNode = listArray[currentIndex].parent.cloneNode( false ) ;
+					retval.appendChild( rootNode ) ;
+				}
+				currentListItem = rootNode.ownerDocument.createElement( 'li' ) ;
+				rootNode.appendChild( currentListItem ) ;
+				for ( var i = 0 ; i < item.contents.length ; i++ )
+					currentListItem.appendChild( item.contents[i].cloneNode( true ) ) ;
+				currentIndex++ ;
+			}
+			else if ( item.indent == Math.max( indentLevel, 0 ) + 1 )
+			{
+				var listData = this.ArrayToList( listArray, currentIndex ) ;
+				currentListItem.appendChild( listData.listNode ) ;
+				currentIndex = listData.nextIndex ;
+			}
+			else if ( item.indent == -1 && baseIndex == 0 && item.grandparent )
+			{
+				var currentListItem ;
+				if ( item.grandparent.nodeName.IEquals( ['ul', 'ol'] ) )
+					currentListItem = rootNode.ownerDocument.createElement( 'li' ) ;
+				else
+				{
+					if ( FCKConfig.EnterMode.IEquals( ['div', 'p'] ) )
+						currentListItem = rootNode.ownerDocument.createElement( FCKConfig.EnterMode ) ;
+					else
+						currentListItem = rootNode.ownerDocument.createDocumentFragment() ;
+				}
+				item.grandparent.appendChild( currentListItem )  ;
+				for ( var i = 0 ; i < item.contents.length ; i++ )
+					currentListItem.appendChild( item.contents[i].cloneNode( true ) ) ;
+				if ( currentListItem.nodeType == 11 )
+					currentListItem.appendChild( currentListItem.ownerDocument.createElement( 'br' ) ) ;
+				retval.appendChild( currentListItem ) ;
+				rootNode = null ;
+				currentIndex++ ;
+			}
+			else
+				break ;
+
+			if ( listArray.length <= currentIndex || Math.max( listArray[currentIndex].indent, 0 ) < indentLevel )
+			{
+				break ;
+			}
+		}
+		return { 'listNode' : retval, 'nextIndex' : currentIndex } ;
 	}
 } ;
+
