Index: /CKEditor/branches/prototype/_source/plugins/dialog/plugin.js
===================================================================
--- /CKEditor/branches/prototype/_source/plugins/dialog/plugin.js	(revision 2445)
+++ /CKEditor/branches/prototype/_source/plugins/dialog/plugin.js	(revision 2446)
@@ -20,10 +20,5 @@
  */
 
-CKEDITOR.plugins.add( 'dialog',
-	{
-		init : function( editor, pluginPath )
-		{
-		}
-	});
+CKEDITOR.plugins.add( 'dialog' );
 
 CKEDITOR.DIALOG_RESIZE_NONE = 0;
@@ -32,153 +27,87 @@
 CKEDITOR.DIALOG_RESIZE_RESIZE_BOTH = 3;
 
-CKEDITOR.dialog =
+CKEDITOR.dialog = function( editor, dialogName )
 {
-	add: function( name, callback )
-	{
-	},
-
-	okButton : null,
-
-	cancelButton : null,
-
-	addUIElement: null,
-
-	dialogDefinitions : {
-		testOnly : function()
-		{
-			return {
-				title : 'Test Dialog',
-				resizable : CKEDITOR.DIALOG_RESIZE_NONE,
-				minWidth : 500,
-				minHeight : 400,
-				contents : [
-					{
-						id : 'tab1',
-						label : 'First Tab',
-						title : 'First Tab Title',
-						accessKey : 'Q',
-						elements : []
-					},
-
-					{
-						id : 'tab2',
-						label : 'Second Tab',
-						title : 'Second Tab Title',
-						accessKey : 'W',
-						elements : []
-					},
-
-					{
-						id : 'tab3',
-						label : 'Third Tab',
-						title : 'Third Tab Title',
-						accessKey : 'E',
-						elements : []
-					}
-				]
-			};
-		}
-	},
-
-	storedDialogs : {},
-
-	construct : function( editor, dialogName )
-	{
-		if ( arguments.length < 2 )
-			return;
-
-		// Load the dialog definition.
-		var definition = CKEDITOR.dialog.dialogDefinitions[dialogName];
-		if ( typeof( definition ) != 'function' )
-		{
-			alert( 'Error: The dialog "' + dialogName + '" is not defined.' );
-			return;
-		}
-		definition = CKEDITOR.tools.extend( {}, CKEDITOR.dialog._.defaultDialogDefinition, definition() );
-		if ( !( definition.title && definition.contents ) )
-		{
-			alert( 'Error: The dialog "' + dialogName + '" is missing its title or contents.' );
-			return;
-		}
-		if ( definition.contents.length < 1 )
-		{
-			alert( 'Error: The dialog "' + dialogName + '" has no contents.' );
-			return;
-		}
-
-		// Initialize some basic parameters.
-		this._ = {
-			editor : editor,
-			element : editor.theme.buildDialog( editor ),
-			name : dialogName,
-			definition : definition,
-			isShown : false,
-			size : { width : 0, height : 0 }
-		};
-
-		// Initialize the parts map.
-		var element = this._.element.getFirst();
-		this._.parts = {
-			'tl' : [0,0],
-			't' : [0,1],
-			'tr' : [0,2],
-			'l' : [1,0],
-			'c' : [1,1],
-			'r' : [1,2],
-			'bl' : [2,0],
-			'b' : [2,1],
-			'br' : [2,2],
-			'title' : [1,1,0],
-			'tabs' : [1,1,1],
-			'bridge' : [1,1,2],
-			'contents' : [1,1,3],
-			'buttons' : [1,1,4]
-		};
-		for ( var i in this._.parts )
-			this._.parts[i] = element.getChild( this._.parts[i] );
-
-		// Initialize the tab and page map.
-		this._.tabs = {};
-
-		// Insert the title.
-		( new CKEDITOR.dom.text( definition.title, CKEDITOR.document ) ).appendTo( this._.parts.title );
-
-		// Insert the tabs and contents.
-		for ( var i = 0 ; i < definition.contents.length ; i++ )
-			this.addPage( definition.contents[i] );
-
-		var classRegex = /cke_dialog_tab(\s|$|_)/;
-		this._.parts['tabs'].on( 'click', function( evt )
-				{
-					var target = evt.data.getTarget(), firstNode = target, id, page;
-
-					// If we aren't inside a tab, bail out.
-					if ( !classRegex.test( target.$.className ) )
-						return;
-
-					// Find the outer <span> container of the tab.
-					while ( target.getName() == 'div' && classRegex.test( target.$.className ) )
-						target = target.getParent();
-					id = target.$.id.substr( 0, target.$.id.lastIndexOf( '_' ) );
-					this.selectPage( id );
-				}, this );
+	if ( arguments.length < 2 )
+		return;
+
+	// Load the dialog definition.
+	var definition = CKEDITOR.dialog.dialogDefinitions[dialogName];
+	if ( typeof( definition ) != 'function' )
+	{
+		alert( 'Error: The dialog "' + dialogName + '" is not defined.' );
+		return;
 	}
-};
-
-CKEDITOR.dialog._ = {
-	defaultDialogDefinition :
-	{
-		resizable : CKEDITOR.DIALOG_RESIZE_NONE,
-		minWidth : 600,
-		minHeight : 400,
-		buttons : [CKEDITOR.dialog.okButton, CKEDITOR.dialog.cancelButton],
-		onOk : function(){alert('ok called');},
-		onCancel : function(){alert('cancel caled');},
-		onLoad : function(){alert('onload called');}
+	definition = CKEDITOR.tools.extend( {}, CKEDITOR.dialog._.defaultDialogDefinition, definition() );
+	if ( !( definition.title && definition.contents ) )
+	{
+		alert( 'Error: The dialog "' + dialogName + '" is missing its title or contents.' );
+		return;
 	}
+	if ( definition.contents.length < 1 )
+	{
+		alert( 'Error: The dialog "' + dialogName + '" has no contents.' );
+		return;
+	}
+
+	// Initialize some basic parameters.
+	this._ = {
+		editor : editor,
+		element : editor.theme.buildDialog( editor ),
+		name : dialogName,
+		definition : definition,
+		isShown : false,
+		size : { width : 0, height : 0 }
+	};
+
+	// Initialize the parts map.
+	var element = this._.element.getFirst();
+	this._.parts = {
+		'tl' : [0,0],
+		't' : [0,1],
+		'tr' : [0,2],
+		'l' : [1,0],
+		'c' : [1,1],
+		'r' : [1,2],
+		'bl' : [2,0],
+		'b' : [2,1],
+		'br' : [2,2],
+		'title' : [1,1,0],
+		'tabs' : [1,1,1],
+		'bridge' : [1,1,2],
+		'contents' : [1,1,3],
+		'buttons' : [1,1,4]
+	};
+	for ( var i in this._.parts )
+		this._.parts[i] = element.getChild( this._.parts[i] );
+
+	// Initialize the tab and page map.
+	this._.tabs = {};
+
+	// Insert the title.
+	( new CKEDITOR.dom.text( definition.title, CKEDITOR.document ) ).appendTo( this._.parts.title );
+
+	// Insert the tabs and contents.
+	for ( var i = 0 ; i < definition.contents.length ; i++ )
+		this.addPage( definition.contents[i] );
+
+	var classRegex = /cke_dialog_tab(\s|$|_)/;
+	this._.parts['tabs'].on( 'click', function( evt )
+			{
+				var target = evt.data.getTarget(), firstNode = target, id, page;
+
+				// If we aren't inside a tab, bail out.
+				if ( !classRegex.test( target.$.className ) )
+					return;
+
+				// Find the outer <span> container of the tab.
+				while ( target.getName() == 'div' && classRegex.test( target.$.className ) )
+					target = target.getParent();
+				id = target.$.id.substr( 0, target.$.id.lastIndexOf( '_' ) );
+				this.selectPage( id );
+			}, this );
 }
 
-
-CKEDITOR.dialog.construct.prototype = {
+CKEDITOR.dialog.prototype = {
 	resize : (function()
 	{
@@ -261,14 +190,29 @@
 	addPage : function( contents, index )
 	{
-		var page = CKEDITOR.dom.element.createFromHtml( '<div class="cke_dialog_page_contents"></div>' );
-		var tab = CKEDITOR.dom.element.createFromHtml( [
-					'<span><div class="cke_dialog_tab">',
-						'<div class="cke_dialog_tab_left"></div>',
-						'<div class="cke_dialog_tab_center">',
-							CKEDITOR.tools.htmlEncode( contents.label ),
-						'</div>',
-						'<div class="cke_dialog_tab_right"></div>',
-					'</div></span>'
-				].join( '' ) );
+		var pageHtml = [ '<div class="cke_dialog_page_contents">' ],
+			page,
+			tab,
+			elements = contents.elements;
+
+		for ( var i = 0 ; i < elements.length ; i++ )
+		{
+			var item = elements[i],
+				builder = CKEDITOR.dialog._.uiElementBuilders[ item.type ];
+			if ( !builder )
+				continue;
+			builder.build( item, pageHtml );
+		}
+		pageHtml.push( '</div>' );
+
+		page = CKEDITOR.dom.element.createFromHtml( pageHtml.join( '' ) );
+		tab = CKEDITOR.dom.element.createFromHtml( [
+				'<span><div class="cke_dialog_tab">',
+					'<div class="cke_dialog_tab_left"></div>',
+					'<div class="cke_dialog_tab_center">',
+						CKEDITOR.tools.htmlEncode( contents.label ),
+					'</div>',
+					'<div class="cke_dialog_tab_right"></div>',
+				'</div></span>'
+			].join( '' ) );
 		this._.tabs[ contents.id ] = [ tab, page ];
 		tab.getFirst().unselectable();
@@ -276,4 +220,5 @@
 		tab.appendTo( this._.parts['tabs'] );
 		tab.setAttribute( 'id', contents.id + '_' + CKEDITOR.tools.getNextNumber() );
+
 	},
 
@@ -307,4 +252,90 @@
 };
 
+CKEDITOR.tools.extend( CKEDITOR.dialog,
+	{
+		add: function( name, callback )
+		{
+			this.dialogDefinitions[name] = callback;
+		},
+
+		okButton : null,
+
+		cancelButton : null,
+
+		addUIElement: function( typeName, builder )
+		{
+			this._.uiElementBuilders[typeName] = builder;
+		},
+
+		dialogDefinitions : {
+			testOnly : function()
+			{
+				return {
+					title : 'Test Dialog',
+					resizable : CKEDITOR.DIALOG_RESIZE_NONE,
+					minWidth : 500,
+					minHeight : 400,
+					contents : [
+						{
+							id : 'tab1',
+							label : 'First Tab',
+							title : 'First Tab Title',
+							accessKey : 'Q',
+							elements : [
+								{
+									type : 'hbox',
+									children : []
+								}
+							]
+						},
+
+						{
+							id : 'tab2',
+							label : 'Second Tab',
+							title : 'Second Tab Title',
+							accessKey : 'W',
+							elements : [
+								{
+									type : 'hbox',
+									children : []
+								}
+							]
+						},
+
+						{
+							id : 'tab3',
+							label : 'Third Tab',
+							title : 'Third Tab Title',
+							accessKey : 'E',
+							elements : [
+								{
+									type : 'hbox',
+									children : []
+								}
+							]
+						}
+					]
+				};
+			}
+		},
+
+		storedDialogs : {}
+	});
+
+CKEDITOR.dialog._ = {
+	defaultDialogDefinition :
+	{
+		resizable : CKEDITOR.DIALOG_RESIZE_NONE,
+		minWidth : 600,
+		minHeight : 400,
+		buttons : [ CKEDITOR.dialog.okButton, CKEDITOR.dialog.cancelButton ],
+		onOk : function(){ alert( 'ok called' ); },
+		onCancel : function(){ alert( 'cancel caled' ); },
+		onLoad : function(){ alert( 'onload called' ); }
+	},
+
+	uiElementBuilders : {},
+};
+
 (function()
 {
@@ -313,5 +344,5 @@
 			'openDialog' : function( dialogName )
 			{
-				var dialog = CKEDITOR.dialog.storedDialogs[dialogName] || new CKEDITOR.dialog.construct( this, dialogName );
+				var dialog = CKEDITOR.dialog.storedDialogs[dialogName] || new CKEDITOR.dialog( this, dialogName );
 				CKEDITOR.dialog.storedDialogs[dialogName] = dialog;
 				dialog.show();
@@ -320,2 +351,68 @@
 		});
 })();
+
+CKEDITOR.dialog.addUIElement( 'hbox',
+		{
+			build : function( elementDefinition, output )
+			{
+				var id = 'cke_dialog_hbox_' + CKEDITOR.tools.getNextNumber(),
+					html = [ '<div id="', id, '">' ],
+					children = [];
+				for ( var i = 0 ; i < elementDefinition.children.length ; i++ )
+				{
+					var child = elementDefinition.children[i],
+						type = child.type;
+					html.push( '<div style="float:left;' );
+					if ( elementDefinition.widths && isFinite( parseFloat( elementDefinition.widths[i] ) ) )
+						html.push( 'width:', elementDefinition.widths[i], 'px;' );
+					if ( elementDefinition.height && isFinite( parseFloat( elementDefinition.height ) ) )
+						html.push( 'height:', elementDefinition.height, 'px;' )
+					html.push( '">' );
+					children.push( this._.uiElementBuilders[type].build( child, html ) );
+					html.push( '</div>' );
+				}
+				html.push( '</div>' );
+				output.push( html.join( '' ) );
+				return {
+					setValue : function( value )
+					{
+						var len = Math.min( value.length, children.length );
+						for ( var i = 0 ; i < len ; i++ )
+							children[i].setValue( value[i] );
+					},
+
+					getValue : function()
+					{
+						var retval = [];
+						for ( var i = 0 ; i < children.length ; i++ )
+							retval.push( children[i].getValue() );
+						return retval;
+					},
+
+					isChanged : function()
+					{
+						var retval = false;
+						for ( var i = 0 ; i < children.length ; i++ )
+							retval |= children[i].isChanged();
+						return retval;
+					},
+
+					focus : function()
+					{
+						CKEDITOR.document.getById( id ).focus();
+					},
+
+					getChild : function( indices )
+					{
+						if ( !indices.splice )
+							indices = [ indices ];
+						if ( indices.length < 2 )
+							return children[ indices[0] ];
+						else
+							return ( children[ indices[0] ] && children[ indices[0] ].getChild ) ?
+								children[ indices[0] ].getChild( indices.slice( 1, indices.length ) ) :
+								null;
+					}
+				};
+			}
+		});
