Index: _source/plugins/div/dialogs/div.js
===================================================================
--- _source/plugins/div/dialogs/div.js	(revision 0)
+++ _source/plugins/div/dialogs/div.js	(revision 0)
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.html or http://ckeditor.com/license
+ */
+
+(function()
+{
+	
+	/**
+	 * Add to collection with DUP examination.
+	 * @param {Object} collection
+	 * @param {Object} element
+	 * @param {Object} database
+	 */
+	function addSafely( collection, element, database )
+	{
+		// avoid duplicate
+		if ( !element.getCustomData( 'block_processed' ) )
+		{
+			CKEDITOR.dom.element.setMarker( database, element,
+				'block_processed', true );
+			collection.push( element );
+		}
+	}
+	
+	/**
+	 * Dialog reused by both 'creatediv' and 'editdiv' commands.
+	 * @param {Object} editor
+	 * @param {String} command	The command name which indicate what the current command is.
+	 */
+	function divDialog( editor, command ) {
+		
+		// Definition of elements at which div operation should stopped.
+		var divLimitDefiniton = (function(){
+			
+			// Customzie from specialize blockLimit elements
+			var definition = CKEDITOR.tools.extend( {}, 
+			CKEDITOR.dom.elementPath.pathBlockLimitElements );
+			// Exclude 'div' itself.
+			delete definition.div;
+			// Exclude 'td' and 'th' when 'wrapping table' 
+			if( editor.config.div_wrapTable)
+			{
+				delete definition.td;
+				delete definition.th;
+			}
+			return definition;
+		})();
+		
+		// DTD of 'div' element
+		var dtd = CKEDITOR.dtd.div;
+		
+		/**
+		 * Get the first div limit element on the element's path.
+		 * @param {Object} element
+		 */
+		function getDivLimitElement( element )
+		{
+			var pathElements = new CKEDITOR.dom.elementPath( element ).elements;
+			var i, l = pathElements.length, divLimit;
+			for ( i = 0; i < l; i++ ) 
+			{
+				if ( pathElements[ i ].getName() in divLimitDefiniton ) 
+				{
+					divLimit = pathElements[ i ];
+					break;
+				}
+			}
+			return divLimit;
+		}
+		
+		/**
+		 * Init all fields' setup/commit function.
+		 * @memberof divDialog
+		 */
+		function setupFields()
+		{
+			this.foreach( function( field )
+			{
+				//Exclude layout container elements
+				if( /^(?!vbox|hbox)/.test( field.type ))	
+				{
+					if ( !field.setup )
+					{
+						// Read the dialog fields values from the specified
+						// element attributes.
+						field.setup = function( element )
+						{
+							field.setValue( element.getAttribute( field.id ) || '' );
+						};
+					}
+					if ( !field.commit )
+					{
+						// Set element attributes assigned by the dialog
+						// fields.
+						field.commit = function( element )
+						{
+							var fieldValue = this.getValue();
+							// ignore default element attribute values
+							if ( 'dir' == field.id
+								&& element.getComputedStyle( 'direction' ) == fieldValue )
+								return true;
+							if ( fieldValue )
+								element.setAttribute( field.id, fieldValue );
+						};
+					}
+				}
+			} );
+		}
+		
+		/**
+		 * Either create or detect the desired block containers among the selected ranges.
+		 * @param {Object} editor
+		 * @param {Object} containerTagName The tagName of the container.
+		 * @param {Object} isCreate Whether it's a creation process OR a detection process.
+		 */	
+		function applyDiv( editor, isCreate )
+		{
+			// new adding containers OR detected pre-existed containers.
+			var containers = [],
+			// node markers store. 
+			database = {},
+			// All block level elements which contained by the ranges.
+			containedBlocks = [], block;
+	
+			// Get all ranges from the selection.
+			var selection = editor.document.getSelection();
+			var ranges = selection.getRanges();
+			var i, l = ranges.length, iterator;
+	
+			// collect all included elements from dom-iterator
+			for( i = 0 ; i < l ; i++ )
+			{
+				iterator = ranges[ i ].createIterator();
+				while( ( block = iterator.getNextParagraph() ) )
+				{
+					// include contents of blockLimit elements.
+					if( block.getName() in divLimitDefiniton )
+					{
+						var j, childNodes = block.getChildren(), s = childNodes.count();
+						for ( j = 0; j < s; j++) {
+							addSafely( containedBlocks, childNodes.getItem( j ) , database );
+						}
+					}
+					else
+					{
+						// Bypass dtd disallowed elements.	
+						while( !dtd[ block.getName() ] && block.getName() != 'body' )
+						{
+							block = block.getParent();
+						}
+						addSafely( containedBlocks, block, database );
+					}
+				}
+			}
+			
+			CKEDITOR.dom.element.clearAllMarkers(database);
+			
+			var blockGroups = groupByDivLimit( containedBlocks ), 
+				l = blockGroups.length, ancestor, blockEl, divElement;
+			for( i = 0 ; i < l ; i++ )
+			{
+				var currentBlock = blockGroups[ i ][0];
+				
+				// Calculate the common parent node of all contained elements.
+				ancestor = currentBlock .getParent();
+				var j  = 1, s = blockGroups[ i ].length;
+				for ( ; j < s; j++ )
+					ancestor = ancestor.getCommonAncestor( blockGroups[ i ][ j ] );
+				
+				if(isCreate)
+				{
+					divElement = new CKEDITOR.dom.element( 'div' ,
+						editor.document );
+				}
+				
+				var j, s = blockGroups[ i ].length,
+				//Wrapped blocks counting
+				childCount = 0;
+				for( j = 0; j < s; j++ )
+				{
+					currentBlock = blockGroups[ i ][ j ];
+	
+					// Reconstruct the block list to only contain direct
+					// children of common ancestor.
+					while( !currentBlock.getParent().equals( ancestor ) )
+						currentBlock = currentBlock.getParent();
+	
+					// Avoid DUP
+					if ( !currentBlock.getCustomData( 'block_processed' ) )
+					{
+						CKEDITOR.dom.element.setMarker( database, currentBlock, 'block_processed', true );
+						if( isCreate )
+						{
+							// Establish new container, wrapping all
+							// elements in this group.
+							if( j == 0 )
+								divElement.insertBefore( currentBlock );
+							divElement.append( currentBlock );
+						}
+						else
+							childCount++;
+					}
+				}
+				CKEDITOR.dom.element.clearAllMarkers( database );
+	
+				if( isCreate )
+				{
+					// drop pre-existed container, since new container already
+					// established.
+					if ( command == 'editdiv' &&
+							ancestor.getName() == 'div'
+							&& 1 == ancestor.getNonEmptyChildren().length )
+							ancestor.remove( true );
+					containers.push( divElement );
+				}
+				else
+				{
+					// discover existed container
+					if ( ancestor.getName() == 'div'
+						&& childCount == ancestor.getNonEmptyChildren().length )
+						containers.push( ancestor );
+				}
+			}
+	
+			return containers;
+		}
+		
+		/**
+		 * Divide a set of nodes to different groups by their path's blocklimit element.
+		 * Note: the specified nodes should be in source order naturally, which mean they are supposed to producea by following class:
+		 *  * CKEDITOR.dom.range.Iterator
+		 *  * CKEDITOR.dom.domWalker
+		 *  @return {Array []} the grouped nodes
+		 */
+		function groupByDivLimit( nodes )
+		{
+			var groups = [],
+				lastDivLimit = null,
+				path, block;
+			for ( var i = 0 ; i < nodes.length ; i++ )
+			{
+				block = nodes[i];
+				var limit = getDivLimitElement( block );
+				if ( !limit.equals( lastDivLimit ) )
+				{
+					lastDivLimit = limit ;
+					groups.push( [] ) ;
+				}
+				groups[ groups.length - 1 ].push( block ) ;
+			}
+			return groups;
+		}
+		
+		function compareNodes()
+		{
+			return arguments[ 0 ].equals( arguments[ 1 ] );
+		}
+		
+		/**
+		 * Hold a collection of created block container elements.  
+		 */
+		var containers = [];
+		/**
+		 * @type divDialog
+		 */ 
+		return {
+			title : editor.lang.div.title,
+			minWidth : 400,
+			minHeight : 320,
+			contents : 
+			[
+			{
+				id :'info',
+				label :editor.lang.common.generalTab,
+				title :editor.lang.common.generalTab,
+				elements : 
+				[
+					{
+						type :'hbox',
+						widths : [ '50%', '50%' ],
+						children : 
+						[
+							{
+								id :'elementStyle',
+								type :'select',
+								style :'width: 100%;',
+								label :editor.lang.div.styleSelectLabel,
+								'default' :editor.config.div_defaultStyle,
+								items : [],
+								setup : function(){
+									//TODO: Read 'elementStyle' field
+								},
+								commit: function()
+								{
+									//TODO: Commit 'elementStyle' field value
+								}
+							// TODO: Fill 'elementStyle' selection options.
+							},
+							{
+								id :'class',
+								type :'text',
+								label :editor.lang.common.cssClass,
+								'default' :editor.config.div_defaultCssClass
+							} 
+						]
+					} 
+				]
+			},
+			{
+					id :'advanced',
+					label :editor.lang.common.advancedTab,
+					title :editor.lang.common.advancedTab,
+					elements : 
+					[
+					{
+						type :'vbox',
+						padding :1,
+						children : 
+						[
+							{
+								type :'hbox',
+								widths : [ '50%', '50%' ],
+								children : 
+								[
+									{
+										type :'text',
+										id :'id',
+										label :editor.lang.common.id,
+										'default' :editor.config.div_defaultId
+									},
+									{
+										type :'text',
+										id :'lang',
+										label :editor.lang.link.langCode,
+										'default' :editor.config.div_defaultLanguageCode
+									} 
+								]
+							},
+							{
+								type :'hbox',
+								children : 
+								[
+										{
+											type :'text',
+											id :'style',
+											style :'width: 100%;',
+											label :editor.lang.common.cssStyle,
+											'default' :editor.config.div_defaultInlineStyle
+										} 
+								]
+							},
+							{
+								type :'hbox',
+								children : 
+								[
+										{
+											type :'text',
+											id :'title',
+											style :'width: 100%;',
+											label :editor.lang.common.advisoryTitle,
+											'default' :editor.config.div_defaultAdvisoryTitle
+										} 
+								]
+							},
+							{
+								type :'select',
+								id :'dir',
+								style :'width: 100%;',
+								label :editor.lang.common.langDir,
+								'default' :editor.config.div_defaultLangDirLabel,
+								items : 
+								[
+									[
+										editor.lang.common.langDirLtr,
+										'ltr' 
+									],
+									[
+										editor.lang.common.langDirRtl,
+										'rtl' 
+									] 
+								]
+							} 
+						]
+					} 
+					]
+				} 
+			],
+			onLoad : function()
+			{
+				setupFields.call(this);
+			},
+			onShow : function()
+			{
+				containers = [];
+				// Whether always create new container regardless of existed
+				// ones.
+				if ( command == 'editdiv' )
+				{
+					if( CKEDITOR.env.ie )
+						this.restoreSelection();
+						
+					// Try to discover the containers that already existed in
+					// ranges
+					containers = applyDiv( editor );
+					if( containers.length )
+					{
+						this._element = containers[ 0 ];
+						// update dialog field values
+						this.setupContent( this._element );
+					}
+				}
+			},
+			onOk : function()
+			{
+				if( CKEDITOR.env.ie )
+					this.restoreSelection();
+				containers = applyDiv( editor, true );
+				
+				// update elements attributes
+				var i, l = containers.length;
+				for( i = 0 ; i < l ; i++ )
+				{
+					this.commitContent( containers[ i ] );
+				}
+				this.hide();
+			}
+		};
+	}
+	
+	CKEDITOR.dialog.add( 'creatediv', function( editor )
+		{
+			return divDialog( editor, 'creatediv' );
+		} );
+	CKEDITOR.dialog.add( 'editdiv', function( editor )
+		{
+			return divDialog( editor, 'editdiv' );
+		} );
+})();
\ No newline at end of file
Index: _source/plugins/div/plugin.js
===================================================================
--- _source/plugins/div/plugin.js	(revision 0)
+++ _source/plugins/div/plugin.js	(revision 0)
@@ -0,0 +1,52 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+/**
+ * @fileOverview The "div" plugin. It wraps the selected block level elements with a 'div' element with specified styles and attributes.
+ * 
+ */
+
+CKEDITOR.plugins.add( 'div', 
+{
+	requires : [ 'editingblock', 'domiterator', 'elementspath' ],
+
+	init : function( editor ){
+	
+		editor.addCommand( 'creatediv', new CKEDITOR.dialogCommand(
+			'creatediv' ) );
+		editor.addCommand( 'editdiv', new CKEDITOR.dialogCommand(
+			'editdiv' ) );
+			
+		editor.ui.addButton( 'CreateDiv', {
+			label :editor.lang.div.toolbar,
+			command :'creatediv'
+		} );
+		// TODO: Adding 'editdiv' command button.
+		editor.ui.addButton( 'EditDiv', {
+			label :editor.lang.div.toolbar,
+			command :'editdiv'
+		} );
+		
+		CKEDITOR.dialog.add( 'creatediv',
+			this.path + 'dialogs/div.js' );
+		CKEDITOR.dialog.add( 'editdiv',
+			this.path + 'dialogs/div.js' );
+	}
+} );
+
+CKEDITOR.tools.extend(CKEDITOR.config, 
+{
+	/**
+	 * Whether wrapping the whole table when created 'div' in table cell.
+	 */
+	div_wrapTable : false,
+	div_defaultCssClass :'',
+	div_defaultStyle :'',
+	div_defaultId :'',
+	div_defaultLanguageCode :'',
+	div_defaultInlineStyle :'',
+	div_defaultAdvisoryTitle :'',
+	div_defaultLangDir :''
+});
Index: _source/plugins/toolbar/plugin.js
===================================================================
--- _source/plugins/toolbar/plugin.js	(revision 3116)
+++ _source/plugins/toolbar/plugin.js	(working copy)
@@ -217,7 +217,7 @@
 	['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'],
 	'/',
 	['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],
-	['NumberedList','BulletedList','-','Outdent','Indent','Blockquote'],
+	['NumberedList','BulletedList','-','Outdent','Indent','Blockquote','CreateDiv'],
 	['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],
 	['Link','Unlink','Anchor'],	['Image','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak'],
 	'/',
Index: _source/lang/en.js
===================================================================
--- _source/lang/en.js	(revision 3116)
+++ _source/lang/en.js	(working copy)
@@ -453,5 +453,20 @@
 		tag_h5 : 'Heading 5',
 		tag_h6 : 'Heading 6',
 		tag_div : 'Normal (DIV)'
+	},
+	
+	div :
+	{
+		title: 'Create Div Container',
+		toolbar: 'Create Div Container',
+		cssClassInputLabel : 'Stylesheet Classes',
+		styleSelectLabel : 'Style',
+		IdInputLabel: 'Id',
+		languageCodeInputLabel : ' Language Code',
+		inlineStyleInputLabel : 'Inline Style',
+		advisoryTitleInputLabel : 'Advisory Title',
+		langDirLabel : 'Language Direction',
+		langDirLTRLabel : 'Left to Right (LTR)',
+		langDirRTLLabel : 'Right to Left (RTL)'
 	}
 };
Index: _source/skins/default/toolbar.css
===================================================================
--- _source/skins/default/toolbar.css	(revision 3116)
+++ _source/skins/default/toolbar.css	(working copy)
@@ -415,3 +415,8 @@
 {
 	background-position: 0 -160px;
 }
+
+.cke_skin_default a.cke_button_creatediv .cke_icon
+{
+	background-position: 0 -1168px;
+}
Index: _source/core/config.js
===================================================================
--- _source/core/config.js	(revision 3116)
+++ _source/core/config.js	(working copy)
@@ -147,7 +147,7 @@
 	 * config.plugins = 'basicstyles,button,htmldataprocessor,toolbar,wysiwygarea';
 	 */
 
-	plugins : 'basicstyles,blockquote,button,clipboard,elementspath,find,flash,format,forms,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,newpage,pagebreak,pastefromword,pastetext,preview,print,removeformat,smiley,showblocks,sourcearea,table,specialchar,tab,templates,toolbar,undo,wysiwygarea',
+	plugins : 'basicstyles,blockquote,button,clipboard,elementspath,find,flash,format,forms,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,div,newpage,pagebreak,pastefromword,pastetext,preview,print,removeformat,smiley,showblocks,sourcearea,table,specialchar,tab,templates,toolbar,undo,wysiwygarea',
 
 	/**
 	 * The theme to be used to build the UI.
Index: _source/core/dom/elementpath.js
===================================================================
--- _source/core/dom/elementpath.js	(revision 3116)
+++ _source/core/dom/elementpath.js	(working copy)
@@ -74,6 +74,9 @@
 		this.blockLimit = blockLimit;
 		this.elements = elements;
 	};
+	//Make bocklimit elements definition public visitable.
+	CKEDITOR.dom.elementPath.pathBlockLimitElements = pathBlockLimitElements;
+	
 })();
 
 CKEDITOR.dom.elementPath.prototype =
Index: _source/core/dom/element.js
===================================================================
--- _source/core/dom/element.js	(revision 3116)
+++ _source/core/dom/element.js	(working copy)
@@ -409,6 +409,26 @@
 		{
 			return new CKEDITOR.dom.nodeList( this.$.childNodes );
 		},
+		
+		/**
+		 * Same as CKEDITOR.dom.element::getChildren except this method ignore
+		 * text nodes which contains only blank characters.
+		 * @return {Array}  
+		 */
+		getNonEmptyChildren : function()
+		{
+			var resultsChilds = [];
+			var children = this.getChildren();
+			var i, l = children.count(), child;
+			for( i = 0 ; i < l ; i++ )
+			{
+				child = children.getItem( i );
+				if( ! ( child.type === CKEDITOR.NODE_TEXT 
+					&& /^[ \t\n\r]+$/.test( child.getText() ) ) )
+					resultsChilds.push( child );
+			}
+			return resultsChilds;
+		},
 
 		/**
 		 * Gets the current computed value of one of the element CSS style
