/**
 * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.md or http://ckeditor.com/license
 */
/**
 * @fileOverview The "dialogui" plugin.
 */
CKEDITOR.plugins.add( 'dialogui', {
	onLoad: function() {
		var initPrivateObject = function( elementDefinition ) {
				this._ || ( this._ = {} );
				this._[ 'default' ] = this._.initValue = elementDefinition[ 'default' ] || '';
				this._.required = elementDefinition[ 'required' ] || false;
				var args = [ this._ ];
				for ( var i = 1; i < arguments.length; i++ )
					args.push( arguments[ i ] );
				args.push( true );
				CKEDITOR.tools.extend.apply( CKEDITOR.tools, args );
				return this._;
			},
			textBuilder = {
				build: function( dialog, elementDefinition, output ) {
					return new CKEDITOR.ui.dialog.textInput( dialog, elementDefinition, output );
				}
			},
			commonBuilder = {
				build: function( dialog, elementDefinition, output ) {
					return new CKEDITOR.ui.dialog[ elementDefinition.type ]( dialog, elementDefinition, output );
				}
			},
			containerBuilder = {
				build: function( dialog, elementDefinition, output ) {
					var children = elementDefinition.children,
						child,
						childHtmlList = [],
						childObjList = [];
					for ( var i = 0;
					( i < children.length && ( child = children[ i ] ) ); i++ ) {
						var childHtml = [];
						childHtmlList.push( childHtml );
						childObjList.push( CKEDITOR.dialog._.uiElementBuilders[ child.type ].build( dialog, child, childHtml ) );
					}
					return new CKEDITOR.ui.dialog[ elementDefinition.type ]( dialog, childObjList, childHtmlList, output, elementDefinition );
				}
			},
			commonPrototype = {
				isChanged: function() {
					return this.getValue() != this.getInitValue();
				},
				reset: function( noChangeEvent ) {
					this.setValue( this.getInitValue(), noChangeEvent );
				},
				setInitValue: function() {
					this._.initValue = this.getValue();
				},
				resetInitValue: function() {
					this._.initValue = this._[ 'default' ];
				},
				getInitValue: function() {
					return this._.initValue;
				}
			},
			commonEventProcessors = CKEDITOR.tools.extend( {}, CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors, {
				onChange: function( dialog, func ) {
					if ( !this._.domOnChangeRegistered ) {
						dialog.on( 'load', function() {
							this.getInputElement().on( 'change', function() {
								// Make sure 'onchange' doesn't get fired after dialog closed. (#5719)
								if ( !dialog.parts.dialog.isVisible() )
									return;
								this.fire( 'change', { value: this.getValue() } );
							}, this );
						}, this );
						this._.domOnChangeRegistered = true;
					}
					this.on( 'change', func );
				}
			}, true ),
			eventRegex = /^on([A-Z]\w+)/,
			cleanInnerDefinition = function( def ) {
				// An inner UI element should not have the parent's type, title or events.
				for ( var i in def ) {
					if ( eventRegex.test( i ) || i == 'title' || i == 'type' )
						delete def[ i ];
				}
				return def;
			};
		CKEDITOR.tools.extend( CKEDITOR.ui.dialog, {
			/**
			 * Base class for all dialog elements with a textual label on the left.
			 *
			 * @class CKEDITOR.ui.dialog.labeledElement
			 * @extends CKEDITOR.ui.dialog.uiElement
			 * @constructor Creates a labeledElement class instance.
			 * @param {CKEDITOR.dialog} dialog Parent dialog object.
			 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
			 * The element definition. Accepted fields:
			 *
			 * * `label` (Required) The label string.
			 * * `labelLayout` (Optional) Put 'horizontal' here if the
			 *     label element is to be layed out horizontally. Otherwise a vertical
			 *     layout will be used.
			 * * `widths` (Optional) This applies only for horizontal
			 *     layouts - an 2-element array of lengths to specify the widths of the
			 *     label and the content element.
			 *
			 * @param {Array} htmlList List of HTML code to output to.
			 * @param {Function} contentHtml
			 * A function returning the HTML code string to be added inside the content
			 * cell.
			 */
			labeledElement: function( dialog, elementDefinition, htmlList, contentHtml ) {
				if ( arguments.length < 4 )
					return;
				var _ = initPrivateObject.call( this, elementDefinition );
				_.labelId = CKEDITOR.tools.getNextId() + '_label';
				var children = this._.children = [];
				var innerHTML = function() {
						var html = [],
							requiredClass = elementDefinition.required ? ' cke_required' : '';
						if ( elementDefinition.labelLayout != 'horizontal' ) {
							html.push(
								'',
								'