Index: /CKEditor/branches/versions/3.5.x/CHANGES.html
===================================================================
--- /CKEditor/branches/versions/3.5.x/CHANGES.html	(revision 6187)
+++ /CKEditor/branches/versions/3.5.x/CHANGES.html	(revision 6188)
@@ -41,4 +41,5 @@
 	<ul>
 		<li><a href="http://dev.ckeditor.com/ticket/4090">#4090</a> : Full Adobe AIR support.</li>
+		<li><a href="http://dev.ckeditor.com/ticket/5084">#5084</a> : Dialogs are now resizable with a grip in the bottom of the dialog.</li>
 		<li><a href="http://dev.ckeditor.com/ticket/5755">#5755</a> : Introduced the <a href="http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html#.dialog_buttonsOrder">dialog_buttonsOrder</a> setting, making it possible to control the buttons order.</li>
 		<li><a href="http://dev.ckeditor.com/ticket/4648">#4648</a> : Added the new Iframe plugin.</li>
Index: /CKEditor/branches/versions/3.5.x/_source/core/dom/element.js
===================================================================
--- /CKEditor/branches/versions/3.5.x/_source/core/dom/element.js	(revision 6187)
+++ /CKEditor/branches/versions/3.5.x/_source/core/dom/element.js	(revision 6188)
@@ -1539,34 +1539,4 @@
 
 		/**
-		 *  Update the element's size with box model awareness.
-		 * @name CKEDITOR.dom.element.setSize
-		 * @param {String} type [width|height]
-		 * @param {Number} size The length unit in px.
-		 * @param isBorderBox Apply the {@param width} and {@param height} based on border box model.
-		 */
-		setSize : ( function()
-		{
-			var sides = {
-				width : [ "border-left-width", "border-right-width","padding-left", "padding-right" ],
-				height : [ "border-top-width", "border-bottom-width", "padding-top",  "padding-bottom" ]
-			};
-
-			return function( type, size, isBorderBox )
-				{
-					if ( typeof size == 'number' )
-					{
-						if ( isBorderBox && !( CKEDITOR.env.ie && CKEDITOR.env.quirks ) )
-						{
-							var	adjustment = 0;
-							for ( var i = 0, len = sides[ type ].length; i < len; i++ )
-								adjustment += parseInt( this.getComputedStyle( sides [ type ][ i ] ) || 0, 10 ) || 0;
-							size -= adjustment;
-						}
-						this.setStyle( type, size + 'px' );
-					}
-				};
-		})(),
-
-		/**
 		 * Gets element's direction. Supports both CSS 'direction' prop and 'dir' attr.
 		 */
@@ -1593,2 +1563,53 @@
 		}
 	});
+
+( function()
+{
+	var sides = {
+		width : [ "border-left-width", "border-right-width","padding-left", "padding-right" ],
+		height : [ "border-top-width", "border-bottom-width", "padding-top",  "padding-bottom" ]
+	};
+
+	function marginAndPaddingSize( type )
+	{
+		var adjustment = 0;
+		for ( var i = 0, len = sides[ type ].length; i < len; i++ )
+			adjustment += parseInt( this.getComputedStyle( sides [ type ][ i ] ) || 0, 10 ) || 0;
+		return adjustment;
+	}
+
+	/**
+	 * Update the element's size with box model awareness.
+	 * @name CKEDITOR.dom.element.setSize
+	 * @param {String} type [width|height]
+	 * @param {Number} size The length unit in px.
+	 * @param isBorderBox Apply the {@param width} and {@param height} based on border box model.
+	 */
+	CKEDITOR.dom.element.prototype.setSize = function( type, size, isBorderBox )
+		{
+			if ( typeof size == 'number' )
+			{
+				if ( isBorderBox && !( CKEDITOR.env.ie && CKEDITOR.env.quirks ) )
+					size -= marginAndPaddingSize.call( this, type );
+
+				this.setStyle( type, size + 'px' );
+			}
+		};
+
+	/**
+	 * Get the element's size, possibly with box model awareness.
+	 * @name CKEDITOR.dom.element.getSize
+	 * @param {String} type [width|height]
+	 * @param {Boolean} contentSize Get the {@param width} or {@param height} based on border box model.
+	 */
+	CKEDITOR.dom.element.prototype.getSize = function( type, contentSize )
+		{
+			var size = Math.max( this.$[ 'offset' + CKEDITOR.tools.capitalize( type )  ],
+				this.$[ 'client' + CKEDITOR.tools.capitalize( type )  ] ) || 0;
+
+			if ( contentSize )
+				size -= marginAndPaddingSize.call( this, type );
+
+			return size;
+		};
+})();
Index: /CKEditor/branches/versions/3.5.x/_source/plugins/dialog/plugin.js
===================================================================
--- /CKEditor/branches/versions/3.5.x/_source/plugins/dialog/plugin.js	(revision 6187)
+++ /CKEditor/branches/versions/3.5.x/_source/plugins/dialog/plugin.js	(revision 6188)
@@ -127,5 +127,4 @@
 		definition = new definitionObject( this, definition );
 
-
 		var doc = CKEDITOR.document;
 
@@ -140,5 +139,4 @@
 			contentSize : { width : 0, height : 0 },
 			size : { width : 0, height : 0 },
-			updateSize : false,
 			contents : {},
 			buttons : {},
@@ -639,5 +637,4 @@
 
 				this._.contentSize = { width : width, height : height };
-				this._.updateSize = true;
 			};
 		})(),
@@ -651,13 +648,6 @@
 		getSize : function()
 		{
-			if ( !this._.updateSize )
-				return this._.size;
 			var element = this._.element.getFirst();
-			var size = this._.size = { width : element.$.offsetWidth || 0, height : element.$.offsetHeight || 0};
-
-			// If either the offsetWidth or offsetHeight is 0, the element isn't visible.
-			this._.updateSize = !size.width || !size.height;
-
-			return size;
+			return { width : element.$.offsetWidth || 0, height : element.$.offsetHeight || 0};
 		},
 
@@ -667,4 +657,5 @@
 		 * @param {Number} x The target x-coordinate.
 		 * @param {Number} y The target y-coordinate.
+		 * @param {Boolean} save Flag indicate whether the dialog position should be remembered on next open up.
 		 * @example
 		 * dialogObj.move( 10, 40 );
@@ -673,5 +664,5 @@
 		{
 			var isFixed;
-			return function( x, y )
+			return function( x, y, save )
 			{
 				// The dialog may be fixed positioned or absolute positioned. Ask the
@@ -700,4 +691,6 @@
 							'top'	: ( y > 0 ? y : 0 ) + 'px'
 						});
+
+				save && ( this._.moved = 1 );
 			};
 		})(),
@@ -747,5 +740,6 @@
 
 			// First, set the dialog to an appropriate size.
-			this.resize( definition.minWidth, definition.minHeight );
+			this.resize( this._.contentSize && this._.contentSize.width || definition.minWidth,
+					this._.contentSize && this._.contentSize.height || definition.minHeight );
 
 			// Reset all inputs back to their default value.
@@ -792,14 +786,7 @@
 			this._.hasFocus = false;
 
-			// Rearrange the dialog to the middle of the window.
 			CKEDITOR.tools.setTimeout( function()
 				{
-					var viewSize = CKEDITOR.document.getWindow().getViewPaneSize();
-					var dialogSize = this.getSize();
-
-					// We're using definition size for initial position because of
-					// offten corrupted data in offsetWidth at this point. (#4084)
-					this.move( ( viewSize.width - definition.minWidth ) / 2, ( viewSize.height - dialogSize.height ) / 2 );
-
+					this.layout();
 					this.parts.dialog.setStyle( 'visibility', '' );
 
@@ -814,4 +801,17 @@
 				},
 				100, this );
+		},
+
+		/**
+		 * Rearrange the dialog to its previous position or the middle of the window.
+		 * @since 3.5
+		 */
+		layout : function()
+		{
+			var viewSize = CKEDITOR.document.getWindow().getViewPaneSize(),
+					dialogSize = this.getSize();
+
+			this.move( this._.moved ? this._.position.x : ( viewSize.width - dialogSize.width ) / 2,
+					this._.moved ? this._.position.y : ( viewSize.height - dialogSize.height ) / 2 );
 		},
 
@@ -1649,5 +1649,5 @@
 				realX = - margins[3];
 			else if ( abstractDialogCoords.x - margins[1] > viewPaneSize.width - dialogSize.width - magnetDistance )
-				realX = viewPaneSize.width - dialogSize.width + margins[1];
+				realX = viewPaneSize.width - dialogSize.width + ( editor.lang.dir == 'rtl' ? 0 : margins[1] );
 			else
 				realX = abstractDialogCoords.x;
@@ -1660,5 +1660,5 @@
 				realY = abstractDialogCoords.y;
 
-			dialog.move( realX, realY );
+			dialog.move( realX, realY, 1 );
 
 			evt.data.preventDefault();
@@ -1680,6 +1680,4 @@
 		dialog.parts.title.on( 'mousedown', function( evt )
 			{
-				dialog._.updateSize = true;
-
 				lastCoords = { x : evt.data.$.screenX, y : evt.data.$.screenY };
 
@@ -1701,116 +1699,104 @@
 	function initResizeHandles( dialog )
 	{
-		var definition = dialog.definition,
-			minWidth = definition.minWidth || 0,
-			minHeight = definition.minHeight || 0,
-			resizable = definition.resizable,
-			margins = dialog.getParentEditor().skin.margins || [ 0, 0, 0, 0 ];
-
-		function topSizer( coords, dy )
-		{
-			coords.y += dy;
-		}
-
-		function rightSizer( coords, dx )
-		{
-			coords.x2 += dx;
-		}
-
-		function bottomSizer( coords, dy )
-		{
-			coords.y2 += dy;
-		}
-
-		function leftSizer( coords, dx )
-		{
-			coords.x += dx;
-		}
-
-		var lastCoords = null,
-			abstractDialogCoords = null,
-			magnetDistance = dialog._.editor.config.magnetDistance,
-			parts = [ 'tl', 't', 'tr', 'l', 'r', 'bl', 'b', 'br' ];
-
-		function mouseDownHandler( evt )
-		{
-			var partName = evt.listenerData.part, size = dialog.getSize();
-			abstractDialogCoords = dialog.getPosition();
-			CKEDITOR.tools.extend( abstractDialogCoords,
-				{
-					x2 : abstractDialogCoords.x + size.width,
-					y2 : abstractDialogCoords.y + size.height
-				} );
-			lastCoords = { x : evt.data.$.screenX, y : evt.data.$.screenY };
-
-			CKEDITOR.document.on( 'mousemove', mouseMoveHandler, dialog, { part : partName } );
-			CKEDITOR.document.on( 'mouseup', mouseUpHandler, dialog, { part : partName } );
+		var def = dialog.definition,
+			resizable = def.resizable;
+
+		if ( resizable == CKEDITOR.DIALOG_RESIZE_NONE )
+			return;
+
+		var editor = dialog.getParentEditor();
+		var wrapperWidth, wrapperHeight, viewSize, origin, startSize;
+
+		function positionDialog( right )
+		{
+			// Maintain righthand sizing in RTL.
+			if ( dialog._.moved && editor.lang.dir == 'rtl' )
+			{
+				var element = dialog._.element.getFirst();
+				element.setStyle( 'right', right + "px" );
+				element.removeStyle( 'left' );
+			}
+			else if ( !dialog._.moved )
+				dialog.layout();
+		}
+
+		var mouseDownFn = CKEDITOR.tools.addFunction( function( $event )
+		{
+			startSize = dialog.getSize();
+
+			// Calculate the offset between content and chrome size.
+			wrapperHeight = startSize.height - dialog.parts.contents.getSize( 'height',  ! ( CKEDITOR.env.gecko || CKEDITOR.env.opera || CKEDITOR.env.ie && CKEDITOR.env.quirks ) );
+			wrapperWidth = startSize.width - dialog.parts.contents.getSize( 'width', 1 );
+
+			origin = { x : $event.screenX, y : $event.screenY };
+
+			viewSize = CKEDITOR.document.getWindow().getViewPaneSize();
+
+			CKEDITOR.document.on( 'mousemove', mouseMoveHandler );
+			CKEDITOR.document.on( 'mouseup', mouseUpHandler );
 
 			if ( CKEDITOR.env.ie6Compat )
 			{
 				var coverDoc = currentCover.getChild( 0 ).getFrameDocument();
-				coverDoc.on( 'mousemove', mouseMoveHandler, dialog, { part : partName } );
-				coverDoc.on( 'mouseup', mouseUpHandler, dialog, { part : partName } );
-			}
+				coverDoc.on( 'mousemove', mouseMoveHandler );
+				coverDoc.on( 'mouseup', mouseUpHandler );
+			}
+
+			$event.preventDefault && $event.preventDefault();
+		});
+
+		// Prepend the grip to the dialog.
+		dialog.on( 'load', function()
+		{
+			var direction = '';
+			if ( resizable == CKEDITOR.DIALOG_RESIZE_WIDTH )
+				direction = ' cke_resizer_horizontal';
+			else if ( resizable == CKEDITOR.DIALOG_RESIZE_HEIGHT )
+				direction = ' cke_resizer_vertical';
+			var resizer = CKEDITOR.dom.element.createFromHtml( '<div class="cke_resizer' + direction + '"' +
+					' title="' + CKEDITOR.tools.htmlEncode( editor.lang.resize ) + '"' + 
+					' onmousedown="CKEDITOR.tools.callFunction(' + mouseDownFn + ', event )"></div>' );
+			dialog.parts.footer.append( resizer, 1 );
+		});
+		editor.on( 'destroy', function() { CKEDITOR.tools.removeFunction( mouseDownFn ); } );
+
+		function mouseMoveHandler( evt )
+		{
+			var rtl = editor.lang.dir == 'rtl',
+				dx = ( evt.data.$.screenX - origin.x ) * ( rtl ? -1 : 1 ),
+				dy = evt.data.$.screenY - origin.y,
+				width = startSize.width,
+				height = startSize.height,
+				internalWidth = width + dx * ( dialog._.moved ? 1 : 2 ),
+				internalHeight = height + dy * ( dialog._.moved ? 1 : 2 ),
+				element = dialog._.element.getFirst(),
+				right = rtl && element.getComputedStyle( 'right' ),
+				position = dialog.getPosition();
+
+			// IE might return "auto", we need exact position.
+			if ( right )
+				right = right == 'auto' ? viewSize.width - ( position.x || 0 ) - element.getSize( 'width' ) : parseInt( right, 10 );
+
+			if ( position.y + internalHeight > viewSize.height )
+				internalHeight = viewSize.height - position.y;
+
+			if ( ( rtl ? right : position.x ) + internalWidth > viewSize.width )
+				internalWidth = viewSize.width - ( rtl ? right : position.x );
+
+			// Make sure the dialog will not be resized to the wrong side when it's in the leftmost position for RTL.
+			if ( ( resizable == CKEDITOR.DIALOG_RESIZE_WIDTH || resizable == CKEDITOR.DIALOG_RESIZE_BOTH ) && !( rtl && dx > 0 && !position.x ) )
+				width = Math.max( def.minWidth || 0, internalWidth - wrapperWidth );
+
+			if ( resizable == CKEDITOR.DIALOG_RESIZE_HEIGHT || resizable == CKEDITOR.DIALOG_RESIZE_BOTH )
+				height = Math.max( def.minHeight || 0, internalHeight - wrapperHeight );
+
+			dialog.resize( width, height );
+			// The right property might get broken during resizing, so computing it before the resizing.
+			positionDialog( right );
 
 			evt.data.preventDefault();
 		}
 
-		function mouseMoveHandler( evt )
-		{
-			var x = evt.data.$.screenX,
-				y = evt.data.$.screenY,
-				dx = x - lastCoords.x,
-				dy = y - lastCoords.y,
-				viewPaneSize = CKEDITOR.document.getWindow().getViewPaneSize(),
-				partName = evt.listenerData.part;
-
-			if ( partName.search( 't' ) != -1 )
-				topSizer( abstractDialogCoords, dy );
-			if ( partName.search( 'l' ) != -1 )
-				leftSizer( abstractDialogCoords, dx );
-			if ( partName.search( 'b' ) != -1 )
-				bottomSizer( abstractDialogCoords, dy );
-			if ( partName.search( 'r' ) != -1 )
-				rightSizer( abstractDialogCoords, dx );
-
-			lastCoords = { x : x, y : y };
-
-			var realX, realY, realX2, realY2;
-
-			if ( abstractDialogCoords.x + margins[3] < magnetDistance )
-				realX = - margins[3];
-			else if ( partName.search( 'l' ) != -1 && abstractDialogCoords.x2 - abstractDialogCoords.x < minWidth + magnetDistance )
-				realX = abstractDialogCoords.x2 - minWidth;
-			else
-				realX = abstractDialogCoords.x;
-
-			if ( abstractDialogCoords.y + margins[0] < magnetDistance )
-				realY = - margins[0];
-			else if ( partName.search( 't' ) != -1 && abstractDialogCoords.y2 - abstractDialogCoords.y < minHeight + magnetDistance )
-				realY = abstractDialogCoords.y2 - minHeight;
-			else
-				realY = abstractDialogCoords.y;
-
-			if ( abstractDialogCoords.x2 - margins[1] > viewPaneSize.width - magnetDistance )
-				realX2 = viewPaneSize.width + margins[1] ;
-			else if ( partName.search( 'r' ) != -1 && abstractDialogCoords.x2 - abstractDialogCoords.x < minWidth + magnetDistance )
-				realX2 = abstractDialogCoords.x + minWidth;
-			else
-				realX2 = abstractDialogCoords.x2;
-
-			if ( abstractDialogCoords.y2 - margins[2] > viewPaneSize.height - magnetDistance )
-				realY2= viewPaneSize.height + margins[2] ;
-			else if ( partName.search( 'b' ) != -1 && abstractDialogCoords.y2 - abstractDialogCoords.y < minHeight + magnetDistance )
-				realY2 = abstractDialogCoords.y + minHeight;
-			else
-				realY2 = abstractDialogCoords.y2 ;
-
-			dialog.move( realX, realY );
-			dialog.resize( realX2 - realX, realY2 - realY );
-
-			evt.data.preventDefault();
-		}
-
-		function mouseUpHandler( evt )
+		function mouseUpHandler()
 		{
 			CKEDITOR.document.removeListener( 'mouseup', mouseUpHandler );
@@ -1823,21 +1809,23 @@
 				coverDoc.removeListener( 'mousemove', mouseMoveHandler );
 			}
-		}
-
-// TODO : Simplify the resize logic, having just a single resize grip <div>.
-//		var widthTest = /[lr]/,
-//			heightTest = /[tb]/;
-//		for ( var i = 0 ; i < parts.length ; i++ )
-//		{
-//			var element = dialog.parts[ parts[i] + '_resize' ];
-//			if ( resizable == CKEDITOR.DIALOG_RESIZE_NONE ||
-//					resizable == CKEDITOR.DIALOG_RESIZE_HEIGHT && widthTest.test( parts[i] ) ||
-//			  		resizable == CKEDITOR.DIALOG_RESIZE_WIDTH && heightTest.test( parts[i] ) )
-//			{
-//				element.hide();
-//				continue;
-//			}
-//			element.on( 'mousedown', mouseDownHandler, dialog, { part : parts[i] } );
-//		}
+
+			// Switch back to use the left property, if RTL is used.
+			if ( editor.lang.dir == 'rtl' )
+			{
+				var element = dialog._.element.getFirst(),
+					left = element.getComputedStyle( 'left' );
+
+				// IE might return "auto", we need exact position.
+				if ( left == 'auto' )
+					left = viewSize.width - parseInt( element.getStyle( 'right' ), 10 ) - dialog.getSize().width;
+				else
+					left = parseInt( left, 10 );
+
+				element.removeStyle( 'right' );
+				// Make sure the left property gets applied, even if it is the same as previously.
+				dialog._.position.x += 1;
+				dialog.move( left, dialog._.position.y );
+			}
+		}
 	}
 
Index: /CKEditor/branches/versions/3.5.x/_source/plugins/link/dialogs/link.js
===================================================================
--- /CKEditor/branches/versions/3.5.x/_source/plugins/link/dialogs/link.js	(revision 6187)
+++ /CKEditor/branches/versions/3.5.x/_source/plugins/link/dialogs/link.js	(revision 6188)
@@ -76,4 +76,6 @@
 				element.hide();
 		}
+
+		dialog.layout();
 	};
 
Index: /CKEditor/branches/versions/3.5.x/_source/skins/kama/dialog.css
===================================================================
--- /CKEditor/branches/versions/3.5.x/_source/skins/kama/dialog.css	(revision 6187)
+++ /CKEditor/branches/versions/3.5.x/_source/skins/kama/dialog.css	(revision 6188)
@@ -103,4 +103,14 @@
 }
 
+.cke_skin_kama .cke_dialog_footer .cke_resizer
+{
+	margin-top: 20px;
+}
+.cke_skin_kama .cke_browser_iequirks .cke_dialog_footer .cke_resizer,
+.cke_skin_kama .cke_browser_ie6 .cke_dialog_footer .cke_resizer
+{
+	margin-top: 27px;
+}
+
 /* tabs */
 
Index: /CKEditor/branches/versions/3.5.x/_source/skins/office2003/dialog.css
===================================================================
--- /CKEditor/branches/versions/3.5.x/_source/skins/office2003/dialog.css	(revision 6187)
+++ /CKEditor/branches/versions/3.5.x/_source/skins/office2003/dialog.css	(revision 6188)
@@ -201,4 +201,8 @@
 }
 
+.cke_skin_office2003 .cke_dialog_footer .cke_resizer {
+	margin-top: 21px;
+}
+
 /* tabs */
 
Index: /CKEditor/branches/versions/3.5.x/_source/skins/v2/dialog.css
===================================================================
--- /CKEditor/branches/versions/3.5.x/_source/skins/v2/dialog.css	(revision 6187)
+++ /CKEditor/branches/versions/3.5.x/_source/skins/v2/dialog.css	(revision 6188)
@@ -196,4 +196,8 @@
 {
 	text-align: left;
+}
+
+.cke_skin_v2 .cke_dialog_footer .cke_resizer {
+	margin-top: 21px;
 }
 
