Index: /CKEditor/trunk/_source/plugins/div/dialogs/div.js
===================================================================
--- /CKEditor/trunk/_source/plugins/div/dialogs/div.js	(revision 4565)
+++ /CKEditor/trunk/_source/plugins/div/dialogs/div.js	(revision 4565)
@@ -0,0 +1,433 @@
+/*
+ * 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 )
+	{
+		// 1. IE doesn't support customData on text nodes;
+		// 2. Text nodes never get chance to appear twice;
+		if ( !element.is || !element.getCustomData( 'block_processed' ) )
+		{
+			element.is && CKEDITOR.dom.element.setMarker( database, element, 'block_processed', true );
+			collection.push( element );
+		}
+	}
+	
+	function getNonEmptyChildren( element )
+	{
+		var retval = [];
+		var children = element.getChildren();
+		for( var i = 0 ; i < children.count() ; i++ )
+		{
+			var child = children.getItem( i );
+			if( ! ( child.type === CKEDITOR.NODE_TEXT 
+				&& /^[ \t\n\r]+$/.test( child.getText() ) ) )
+				retval.push( child );
+		}
+		return retval;
+	}
+
+
+	/**
+	 * 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 divLimitDefinition = ( function(){
+			
+			// Customzie from specialize blockLimit elements
+			var definition = CKEDITOR.tools.extend( {}, CKEDITOR.dtd.$blockLimit );
+
+			// 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 divLimit;
+			for ( var i = 0; i < pathElements.length ; i++ ) 
+			{
+				if ( pathElements[ i ].getName() in divLimitDefinition ) 
+				{
+					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 );
+							else
+								element.removeAttribute( field.id );
+						};
+					}
+				}
+			} );
+		}
+		
+		/**
+		 * Wrapping 'div' element around appropriate blocks among the selected ranges.
+		 * @param {Object} editor
+		 */
+		function createDiv( editor )
+		{
+			// new adding containers OR detected pre-existed containers.
+			var containers = [];
+			// node markers store.
+			var database = {};
+			// All block level elements which contained by the ranges.
+			var containedBlocks = [], block;
+
+			// Get all ranges from the selection.
+			var selection = editor.document.getSelection();
+			var ranges = selection.getRanges();
+			var bookmarks = selection.createBookmarks();
+			var i, iterator;
+
+			// Calcualte a default block tag if we need to create blocks.
+			var blockTag = editor.config.enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p';
+
+			// collect all included elements from dom-iterator
+			for( i = 0 ; i < ranges.length ; i++ )
+			{
+				iterator = ranges[ i ].createIterator();
+				while( ( block = iterator.getNextParagraph() ) )
+				{
+					// include contents of blockLimit elements.
+					if( block.getName() in divLimitDefinition )
+					{
+						var j, childNodes = block.getChildren();
+						for ( j = 0 ; j < childNodes.count() ; 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 );
+			var ancestor, blockEl, divElement;
+
+			for( i = 0 ; i < blockGroups.length ; i++ )
+			{
+				var currentNode = blockGroups[ i ][ 0 ];
+
+				// Calculate the common parent node of all contained elements.
+				ancestor = currentNode.getParent();
+				for ( var j = 1 ; j < blockGroups[ i ].length; j++ )
+					ancestor = ancestor.getCommonAncestor( blockGroups[ i ][ j ] );
+
+				divElement = new CKEDITOR.dom.element( 'div', editor.document );
+				
+				// Normalize the blocks in each group to a common parent.
+				for( var j = 0; j < blockGroups[ i ].length ; j++ )
+				{
+					currentNode = blockGroups[ i ][ j ];
+
+					while( !currentNode.getParent().equals( ancestor ) )
+						currentNode = currentNode.getParent();
+
+					// This could introduce some duplicated elements in array.
+					blockGroups[ i ][ j ] = currentNode;
+				}
+
+				// Wrapped blocks counting
+				var fixedBlock = null;
+				for ( var j = 0 ; j < blockGroups[ i ].length ; j++ )
+				{
+					currentNode = blockGroups[ i ][ j ];
+
+					// Avoid DUP elements introduced by grouping.
+					if ( !( currentNode.getCustomData && currentNode.getCustomData( 'block_processed' ) ) )
+					{
+						currentNode.is && CKEDITOR.dom.element.setMarker( database, currentNode, 'block_processed', true );
+
+						// Establish new container, wrapping all elements in this group.
+						if ( j == 0 )
+							divElement.insertBefore( currentNode );
+
+						divElement.append( currentNode );
+					}
+				}
+
+				CKEDITOR.dom.element.clearAllMarkers( database );
+				containers.push( divElement );
+			}
+
+			selection.selectBookmarks( bookmarks );
+			return containers;
+		}
+
+		function getDiv( editor )
+		{
+			var path = new CKEDITOR.dom.elementPath( editor.getSelection().getStartElement() ),
+				blockLimit = path.blockLimit,
+				div = blockLimit && blockLimit.getAscendant( 'div', true );
+			return div;
+		}
+		/**
+		 * 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;
+		}
+		
+		/**
+		 * Hold a collection of created block container elements.  
+		 */
+		var containers = [];
+		/**
+		 * @type divDialog
+		 */ 
+		return {
+			title : editor.lang.div.title,
+			minWidth : 400,
+			minHeight : 165,
+			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' : '',
+								items : [],
+								setup : function( element )
+								{
+									this.setValue( element.$.style.cssText || '' );
+								},
+								commit: function( element )
+								{
+									if ( this.getValue() )
+										element.$.style.cssText = this.getValue();
+									else
+										element.removeAttribute( 'style' );
+								}
+							},
+							{
+								id :'class',
+								type :'text',
+								label :editor.lang.common.cssClass,
+								'default' : ''
+							} 
+						]
+					} 
+				]
+			},
+			{
+					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' : ''
+									},
+									{
+										type :'text',
+										id :'lang',
+										label :editor.lang.link.langCode,
+										'default' : ''
+									} 
+								]
+							},
+							{
+								type :'hbox',
+								children : 
+								[
+										{
+											type :'text',
+											id :'style',
+											style :'width: 100%;',
+											label :editor.lang.common.cssStyle,
+											'default' : ''
+										} 
+								]
+							},
+							{
+								type :'hbox',
+								children : 
+								[
+										{
+											type :'text',
+											id :'title',
+											style :'width: 100%;',
+											label :editor.lang.common.advisoryTitle,
+											'default' : ''
+										} 
+								]
+							},
+							{
+								type :'select',
+								id :'dir',
+								style :'width: 100%;',
+								label :editor.lang.common.langDir,
+								'default' : '',
+								items : 
+								[
+									[
+										editor.lang.common.langDirLtr,
+										'ltr' 
+									],
+									[
+										editor.lang.common.langDirRtl,
+										'rtl' 
+									] 
+								]
+							} 
+						]
+					} 
+					]
+				} 
+			],
+			onLoad : function()
+			{
+				setupFields.call(this);
+			},
+			onShow : function()
+			{
+				// Whether always create new container regardless of existed
+				// ones.
+				if ( command == 'editdiv' )
+				{
+					// Try to discover the containers that already existed in
+					// ranges
+					var div = getDiv( editor );
+					// update dialog field values
+					div && this.setupContent( this._element = div );
+				}
+			},
+			onOk : function()
+			{
+				if( command == 'editdiv' )
+					containers = [ this._element ];
+				else
+					containers = createDiv( editor, true );
+				
+				// Update elements attributes
+				for( var i = 0 ; i < containers.length ; 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' );
+		} );
+} )();
Index: /CKEditor/trunk/_source/plugins/div/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/div/plugin.js	(revision 4565)
+++ /CKEditor/trunk/_source/plugins/div/plugin.js	(revision 4565)
@@ -0,0 +1,129 @@
+/*
+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.
+ * 
+ */
+
+(function()
+{
+	CKEDITOR.plugins.add( 'div',
+	{
+		requires : [ 'editingblock', 'domiterator' ],
+
+		init : function( editor )
+		{
+			var lang = editor.lang.div;
+
+			editor.addCommand( 'creatediv', new CKEDITOR.dialogCommand( 'creatediv' ) );
+			editor.addCommand( 'editdiv', new CKEDITOR.dialogCommand( 'editdiv' ) );
+			editor.addCommand( 'removediv',
+				{
+					exec : function( editor )
+					{
+						var selection = editor.getSelection(),
+							ranges = selection && selection.getRanges(),
+							range,
+							bookmarks = selection.createBookmarks(),
+							walker,
+							toRemove = [];
+
+						function findDiv( node )
+						{
+							var path = new CKEDITOR.dom.elementPath( node ),
+								blockLimit = path.blockLimit,
+								div = blockLimit.is( 'div' ) && blockLimit;
+
+							if ( div && !div.getAttribute( '_cke_div_added' ) )
+							{
+								toRemove.push( div );
+								div.setAttribute( '_cke_div_added' );
+							}
+						}
+
+						for ( var i = 0 ; i < ranges.length ; i++ )
+						{
+							range = ranges[ i ];
+							if( range.collapsed )
+								findDiv( selection.getStartElement() );
+							else
+							{
+								walker = new CKEDITOR.dom.walker( range );
+								walker.evaluator = findDiv;
+								walker.lastForward();
+							}
+						}
+
+						for ( var i = 0 ; i < toRemove.length ; i++ )
+							toRemove[ i ].remove( true );
+
+						selection.selectBookmarks( bookmarks );
+					}
+				} );
+				
+			editor.ui.addButton( 'CreateDiv',
+			{
+				label : lang.toolbar,
+				command :'creatediv'
+			} );
+
+			if ( editor.addMenuItems )
+			{
+				editor.addMenuItems(
+					{
+						editdiv :
+						{
+							label : lang.edit,
+							command : 'editdiv',
+							group : 'div',
+							order : 1
+						},
+
+						removediv:
+						{
+							label : lang.remove,
+							command : 'removediv',
+							group : 'div',
+							order : 5
+						}
+					} );
+
+				if ( editor.contextMenu )
+				{
+					editor.contextMenu.addListener( function( element, selection )
+						{
+							if ( !element )
+								return null;
+
+							var elementPath = new CKEDITOR.dom.elementPath( element ),
+								blockLimit = elementPath.blockLimit;
+
+							if ( blockLimit && blockLimit.getAscendant( 'div', true ) )
+							{
+								return {
+									editdiv : CKEDITOR.TRISTATE_OFF,
+									removediv : CKEDITOR.TRISTATE_OFF
+								}
+							}
+
+							return null;
+						} );
+				}
+			}
+			
+			CKEDITOR.dialog.add( 'creatediv', this.path + 'dialogs/div.js' );
+			CKEDITOR.dialog.add( 'editdiv', this.path + 'dialogs/div.js' );
+		}
+	} );
+})();
+
+/*
+ * @name CKEDITOR.config.div_wrapTable
+ * Whether to wrap the whole table instead of indivisual cells when created 'div' in table cell.
+ * @type Boolean
+ * @default false
+ * @example config.div_wrapTable = true;
+ */
Index: /CKEditor/trunk/_source/skins/kama/icons.css
===================================================================
--- /CKEditor/trunk/_source/skins/kama/icons.css	(revision 4564)
+++ /CKEditor/trunk/_source/skins/kama/icons.css	(revision 4565)
@@ -321,6 +321,2 @@
 	background-position: 0 -1040px;
 }
-.cke_skin_office2003 .cke_button_editdiv .cke_icon
-{
-	background-position: 0 -1184px;
-}
