docs: function( listArray, database, baseIndex, paragraphMode, dir ) {
  			if ( !baseIndex )
  				baseIndex = 0;
  			if ( !listArray || listArray.length < baseIndex + 1 )
  				return null;
  			var i,
  				doc = listArray[ baseIndex ].parent.getDocument(),
  				retval = new CKEDITOR.dom.documentFragment( doc ),
  				rootNode = null,
  				currentIndex = baseIndex,
  				indentLevel = Math.max( listArray[ baseIndex ].indent, 0 ),
  				currentListItem = null,
  				orgDir, block,
  				paragraphName = ( paragraphMode == CKEDITOR.ENTER_P ? 'p' : 'div' );
  			while ( 1 ) {
  				var item = listArray[ currentIndex ],
  					itemGrandParent = item.grandparent;
  
  				orgDir = item.element.getDirection( 1 );
  
  				if ( item.indent == indentLevel ) {
  					if ( !rootNode || listArray[ currentIndex ].parent.getName() != rootNode.getName() ) {
  						rootNode = listArray[ currentIndex ].parent.clone( false, 1 );
  						dir && rootNode.setAttribute( 'dir', dir );
  						retval.append( rootNode );
  					}
  					currentListItem = rootNode.append( item.element.clone( 0, 1 ) );
  
  					if ( orgDir != rootNode.getDirection( 1 ) )
  						currentListItem.setAttribute( 'dir', orgDir );
  
  					for ( i = 0; i < item.contents.length; i++ )
  						currentListItem.append( item.contents[ i ].clone( 1, 1 ) );
  					currentIndex++;
  				} else if ( item.indent == Math.max( indentLevel, 0 ) + 1 ) {
  					// Maintain original direction (#6861).
  					var currDir = listArray[ currentIndex - 1 ].element.getDirection( 1 ),
  						listData = CKEDITOR.plugins.list.arrayToList( listArray, null, currentIndex, paragraphMode, currDir != orgDir ? orgDir : null );
  
  					// If the next block is an <li> with another list tree as the first
  					// child, we'll need to append a filler (<br>/NBSP) or the list item
  					// wouldn't be editable. (#6724)
  					if ( !currentListItem.getChildCount() && CKEDITOR.env.needsNbspFiller && !( doc.$.documentMode > 7 ) )
  						currentListItem.append( doc.createText( '\xa0' ) );
  					currentListItem.append( listData.listNode );
  					currentIndex = listData.nextIndex;
  				} else if ( item.indent == -1 && !baseIndex && itemGrandParent ) {
  					if ( listNodeNames[ itemGrandParent.getName() ] ) {
  						currentListItem = item.element.clone( false, true );
  						if ( orgDir != itemGrandParent.getDirection( 1 ) )
  							currentListItem.setAttribute( 'dir', orgDir );
  					} else
  						currentListItem = new CKEDITOR.dom.documentFragment( doc );
  
  					// Migrate all children to the new container,
  					// apply the proper text direction.
  					var dirLoose = itemGrandParent.getDirection( 1 ) != orgDir,
  						li = item.element,
  						className = li.getAttribute( 'class' ),
  						style = li.getAttribute( 'style' );
  
  					var needsBlock = currentListItem.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT && ( paragraphMode != CKEDITOR.ENTER_BR || dirLoose || style || className );
  
  					var child,
  						count = item.contents.length,
  						cachedBookmark;
  
  					for ( i = 0; i < count; i++ ) {
  						child = item.contents[ i ];
  
  						// Append bookmark if we can, or cache it and append it when we'll know
  						// what to do with it. Generally - we want to keep it next to its original neighbour.
  						// Exception: if bookmark is the only child it hasn't got any neighbour, so handle it normally
  						// (wrap with block if needed).
  						if ( bookmarks( child ) && count > 1 ) {
  							// If we don't need block, it's simple - append bookmark directly to the current list item.
  							if ( !needsBlock )
  								currentListItem.append( child.clone( 1, 1 ) );
  							else
  								cachedBookmark = child.clone( 1, 1 );
  						}
  						// Block content goes directly to the current list item, without wrapping.
  						else if ( child.type == CKEDITOR.NODE_ELEMENT && child.isBlockBoundary() ) {
  							// Apply direction on content blocks.
  							if ( dirLoose && !child.getDirection() )
  								child.setAttribute( 'dir', orgDir );
  
  							inheirtInlineStyles( li, child );
  
  							className && child.addClass( className );
  
  							// Close the block which we started for inline content.
  							block = null;
  							// Append bookmark directly before current child.
  							if ( cachedBookmark ) {
  								currentListItem.append( cachedBookmark );
  								cachedBookmark = null;
  							}
  							// Append this block element to the list item.
  							currentListItem.append( child.clone( 1, 1 ) );
  						}
  						// Some inline content was found - wrap it with block and append that
  						// block to the current list item or append it to the block previously created.
  						else if ( needsBlock ) {
  							// Establish new block to hold text direction and styles.
  							if ( !block ) {
  								block = doc.createElement( paragraphName );
  								currentListItem.append( block );
  								dirLoose && block.setAttribute( 'dir', orgDir );
  							}
  
  							// Copy over styles to new block;
  							style && block.setAttribute( 'style', style );
  							className && block.setAttribute( 'class', className );
  
  							// Append bookmark directly before current child.
  							if ( cachedBookmark ) {
  								block.append( cachedBookmark );
  								cachedBookmark = null;
  							}
  							block.append( child.clone( 1, 1 ) );
  						}
  						// E.g. BR mode - inline content appended directly to the list item.
  						else
  							currentListItem.append( child.clone( 1, 1 ) );
  					}
  
  					// No content after bookmark - append it to the block if we had one
  					// or directly to the current list item if we finished directly in the current list item.
  					if ( cachedBookmark ) {
  						( block || currentListItem ).append( cachedBookmark );
  						cachedBookmark = null;
  					}
  
  					if ( currentListItem.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT && currentIndex != listArray.length - 1 ) {
  						var last;
  
  						// Remove bogus <br> if this browser uses them.
  						if ( CKEDITOR.env.needsBrFiller ) {
  							last = currentListItem.getLast();
  							if ( last && last.type == CKEDITOR.NODE_ELEMENT && last.is( 'br' ) )
  								last.remove();
  						}
  
  						// If the last element is not a block, append <br> to separate merged list items.
  						last = currentListItem.getLast( nonEmpty );
  						if ( !( last && last.type == CKEDITOR.NODE_ELEMENT && last.is( CKEDITOR.dtd.$block ) ) )
  							currentListItem.append( doc.createElement( 'br' ) );
  					}
  
  					var currentListItemName = currentListItem.$.nodeName.toLowerCase();
  					if ( currentListItemName == 'div' || currentListItemName == 'p' )
  						currentListItem.appendBogus();
  					retval.append( currentListItem );
  					rootNode = null;
  					currentIndex++;
  				} else
  					return null;
  
  				block = null;
  
  				if ( listArray.length <= currentIndex || Math.max( listArray[ currentIndex ].indent, 0 ) < indentLevel )
  					break;
  			}
  
  			if ( database ) {
  				var currentNode = retval.getFirst(),
  					listRoot = listArray[ 0 ].parent;
  
  				while ( currentNode ) {
  					if ( currentNode.type == CKEDITOR.NODE_ELEMENT ) {
  						// Clear marker attributes for the new list tree made of cloned nodes, if any.
  						CKEDITOR.dom.element.clearMarkers( database, currentNode );
  
  						// Clear redundant direction attribute specified on list items.
  						if ( currentNode.getName() in CKEDITOR.dtd.$listItem )
  							cleanUpDirection( currentNode );
  					}
  
  					currentNode = currentNode.getNextSourceNode();
  				}
  			}
  
  			return { listNode: retval, nextIndex: currentIndex };
  		}