Index: FCKeditor/trunk/editor/_source/internals/fckdomtools.js
===================================================================
--- FCKeditor/trunk/editor/_source/internals/fckdomtools.js	(revision 824)
+++ 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 } ;
 	}
 } ;
+
