Nation Notes module contributed by Z&H Healthcare.
[openemr.git] / library / custom_template / ckeditor / _source / plugins / dialogui / plugin.js
blobde505b0bf23452016bea6e1806897af69280204c
1 /*
2 Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
3 For licensing, see LICENSE.html or http://ckeditor.com/license
4 */
6 /** @fileoverview The "dialogui" plugin. */
8 CKEDITOR.plugins.add( 'dialogui' );
10 (function()
12         var initPrivateObject = function( elementDefinition )
13         {
14                 this._ || ( this._ = {} );
15                 this._['default'] = this._.initValue = elementDefinition['default'] || '';
16                 this._.required = elementDefinition[ 'required' ] || false;
17                 var args = [ this._ ];
18                 for ( var i = 1 ; i < arguments.length ; i++ )
19                         args.push( arguments[i] );
20                 args.push( true );
21                 CKEDITOR.tools.extend.apply( CKEDITOR.tools, args );
22                 return this._;
23         },
24         textBuilder =
25         {
26                 build : function( dialog, elementDefinition, output )
27                 {
28                         return new CKEDITOR.ui.dialog.textInput( dialog, elementDefinition, output );
29                 }
30         },
31         commonBuilder =
32         {
33                 build : function( dialog, elementDefinition, output )
34                 {
35                         return new CKEDITOR.ui.dialog[elementDefinition.type]( dialog, elementDefinition, output );
36                 }
37         },
38         containerBuilder =
39         {
40                 build : function( dialog, elementDefinition, output )
41                 {
42                         var children = elementDefinition.children,
43                                 child,
44                                 childHtmlList = [],
45                                 childObjList = [];
46                         for ( var i = 0 ; ( i < children.length && ( child = children[i] ) ) ; i++ )
47                         {
48                                 var childHtml = [];
49                                 childHtmlList.push( childHtml );
50                                 childObjList.push( CKEDITOR.dialog._.uiElementBuilders[ child.type ].build( dialog, child, childHtml ) );
51                         }
52                         return new CKEDITOR.ui.dialog[ elementDefinition.type ]( dialog, childObjList, childHtmlList, output, elementDefinition );
53                 }
54         },
55         commonPrototype =
56         {
57                 isChanged : function()
58                 {
59                         return this.getValue() != this.getInitValue();
60                 },
62                 reset : function( noChangeEvent )
63                 {
64                         this.setValue( this.getInitValue(), noChangeEvent );
65                 },
67                 setInitValue : function()
68                 {
69                         this._.initValue = this.getValue();
70                 },
72                 resetInitValue : function()
73                 {
74                         this._.initValue = this._['default'];
75                 },
77                 getInitValue : function()
78                 {
79                         return this._.initValue;
80                 }
81         },
82         commonEventProcessors = CKEDITOR.tools.extend( {}, CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors,
83                 {
84                         onChange : function( dialog, func )
85                         {
86                                 if ( !this._.domOnChangeRegistered )
87                                 {
88                                         dialog.on( 'load', function()
89                                                 {
90                                                         this.getInputElement().on( 'change', function()
91                                                         {
92                                                                 // Make sure 'onchange' doesn't get fired after dialog closed. (#5719)
93                                                                 if ( !dialog.parts.dialog.isVisible() )
94                                                                         return;
96                                                                 this.fire( 'change', { value : this.getValue() } );
97                                                         }, this );
98                                                 }, this );
99                                         this._.domOnChangeRegistered = true;
100                                 }
102                                 this.on( 'change', func );
103                         }
104                 }, true ),
105         eventRegex = /^on([A-Z]\w+)/,
106         cleanInnerDefinition = function( def )
107         {
108                 // An inner UI element should not have the parent's type, title or events.
109                 for ( var i in def )
110                 {
111                         if ( eventRegex.test( i ) || i == 'title' || i == 'type' )
112                                 delete def[i];
113                 }
114                 return def;
115         };
117         CKEDITOR.tools.extend( CKEDITOR.ui.dialog,
118                 /** @lends CKEDITOR.ui.dialog */
119                 {
120                         /**
121                          * Base class for all dialog elements with a textual label on the left.
122                          * @constructor
123                          * @example
124                          * @extends CKEDITOR.ui.dialog.uiElement
125                          * @param {CKEDITOR.dialog} dialog
126                          * Parent dialog object.
127                          * @param {CKEDITOR.dialog.uiElementDefinition} elementDefinition
128                          * The element definition. Accepted fields:
129                          * <ul>
130                          *      <li><strong>label</strong> (Required) The label string.</li>
131                          *      <li><strong>labelLayout</strong> (Optional) Put 'horizontal' here if the
132                          *      label element is to be layed out horizontally. Otherwise a vertical
133                          *      layout will be used.</li>
134                          *      <li><strong>widths</strong> (Optional) This applies only for horizontal
135                          *      layouts - an 2-element array of lengths to specify the widths of the
136                          *      label and the content element.</li>
137                          * </ul>
138                          * @param {Array} htmlList
139                          * List of HTML code to output to.
140                          * @param {Function} contentHtml
141                          * A function returning the HTML code string to be added inside the content
142                          * cell.
143                          */
144                         labeledElement : function( dialog, elementDefinition, htmlList, contentHtml )
145                         {
146                                 if ( arguments.length < 4 )
147                                         return;
149                                 var _ = initPrivateObject.call( this, elementDefinition );
150                                 _.labelId = CKEDITOR.tools.getNextId() + '_label';
151                                 var children = this._.children = [];
152                                 /** @ignore */
153                                 var innerHTML = function()
154                                 {
155                                         var html = [],
156                                                 requiredClass = elementDefinition.required ? ' cke_required' : '' ;
157                                         if ( elementDefinition.labelLayout != 'horizontal' )
158                                                 html.push( '<label class="cke_dialog_ui_labeled_label' + requiredClass + '" ',
159                                                                 ' id="'+  _.labelId + '"',
160                                                                 ' for="' + _.inputId + '"',
161                                                                 ' style="' + elementDefinition.labelStyle + '">',
162                                                                 elementDefinition.label,
163                                                                 '</label>',
164                                                                 '<div class="cke_dialog_ui_labeled_content" role="presentation">',
165                                                                 contentHtml.call( this, dialog, elementDefinition ),
166                                                                 '</div>' );
167                                         else
168                                         {
169                                                 var hboxDefinition = {
170                                                         type : 'hbox',
171                                                         widths : elementDefinition.widths,
172                                                         padding : 0,
173                                                         children :
174                                                         [
175                                                                 {
176                                                                         type : 'html',
177                                                                         html : '<label class="cke_dialog_ui_labeled_label' + requiredClass + '"' +
178                                                                                 ' id="' + _.labelId + '"' +
179                                                                                 ' for="' + _.inputId + '"' +
180                                                                                 ' style="' + elementDefinition.labelStyle + '">' +
181                                                                                    CKEDITOR.tools.htmlEncode( elementDefinition.label ) +
182                                                                                 '</span>'
183                                                                 },
184                                                                 {
185                                                                         type : 'html',
186                                                                         html : '<span class="cke_dialog_ui_labeled_content">' +
187                                                                                 contentHtml.call( this, dialog, elementDefinition ) +
188                                                                                 '</span>'
189                                                                 }
190                                                         ]
191                                                 };
192                                                 CKEDITOR.dialog._.uiElementBuilders.hbox.build( dialog, hboxDefinition, html );
193                                         }
194                                         return html.join( '' );
195                                 };
196                                 CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition, htmlList, 'div', null, { role : 'presentation' }, innerHTML );
197                         },
199                         /**
200                          * A text input with a label. This UI element class represents both the
201                          * single-line text inputs and password inputs in dialog boxes.
202                          * @constructor
203                          * @example
204                          * @extends CKEDITOR.ui.dialog.labeledElement
205                          * @param {CKEDITOR.dialog} dialog
206                          * Parent dialog object.
207                          * @param {CKEDITOR.dialog.uiElementDefinition} elementDefinition
208                          * The element definition. Accepted fields:
209                          * <ul>
210                          *      <li><strong>default</strong> (Optional) The default value.</li>
211                          *      <li><strong>validate</strong> (Optional) The validation function. </li>
212                          *      <li><strong>maxLength</strong> (Optional) The maximum length of text box
213                          *      contents.</li>
214                          *      <li><strong>size</strong> (Optional) The size of the text box. This is
215                          *      usually overridden by the size defined by the skin, however.</li>
216                          * </ul>
217                          * @param {Array} htmlList
218                          * List of HTML code to output to.
219                          */
220                         textInput : function( dialog, elementDefinition, htmlList )
221                         {
222                                 if ( arguments.length < 3 )
223                                         return;
225                                 initPrivateObject.call( this, elementDefinition );
226                                 var domId = this._.inputId = CKEDITOR.tools.getNextId() + '_textInput',
227                                         attributes = { 'class' : 'cke_dialog_ui_input_' + elementDefinition.type, id : domId, type : 'text' },
228                                         i;
230                                 // Set the validator, if any.
231                                 if ( elementDefinition.validate )
232                                         this.validate = elementDefinition.validate;
234                                 // Set the max length and size.
235                                 if ( elementDefinition.maxLength )
236                                         attributes.maxlength = elementDefinition.maxLength;
237                                 if ( elementDefinition.size )
238                                         attributes.size = elementDefinition.size;
240                                 if ( elementDefinition.controlStyle )
241                                         attributes.style = elementDefinition.controlStyle;
243                                 // If user presses Enter in a text box, it implies clicking OK for the dialog.
244                                 var me = this, keyPressedOnMe = false;
245                                 dialog.on( 'load', function()
246                                         {
247                                                 me.getInputElement().on( 'keydown', function( evt )
248                                                         {
249                                                                 if ( evt.data.getKeystroke() == 13 )
250                                                                         keyPressedOnMe = true;
251                                                         } );
253                                                 // Lower the priority this 'keyup' since 'ok' will close the dialog.(#3749)
254                                                 me.getInputElement().on( 'keyup', function( evt )
255                                                         {
256                                                                 if ( evt.data.getKeystroke() == 13 && keyPressedOnMe )
257                                                                 {
258                                                                         dialog.getButton( 'ok' ) && setTimeout( function ()
259                                                                         {
260                                                                                 dialog.getButton( 'ok' ).click();
261                                                                         }, 0 );
262                                                                         keyPressedOnMe = false;
263                                                                 }
264                                                         }, null, null, 1000 );
265                                         } );
267                                 /** @ignore */
268                                 var innerHTML = function()
269                                 {
270                                         // IE BUG: Text input fields in IE at 100% would exceed a <td> or inline
271                                         // container's width, so need to wrap it inside a <div>.
272                                         var html = [ '<div class="cke_dialog_ui_input_', elementDefinition.type, '" role="presentation"' ];
274                                         if ( elementDefinition.width )
275                                                 html.push( 'style="width:'+ elementDefinition.width +'" ' );
277                                         html.push( '><input ' );
279                                         attributes[ 'aria-labelledby' ] = this._.labelId;
280                                         this._.required && ( attributes[ 'aria-required' ] = this._.required );
281                                         for ( var i in attributes )
282                                                 html.push( i + '="' + attributes[i] + '" ' );
283                                         html.push( ' /></div>' );
284                                         return html.join( '' );
285                                 };
286                                 CKEDITOR.ui.dialog.labeledElement.call( this, dialog, elementDefinition, htmlList, innerHTML );
287                         },
289                         /**
290                          * A text area with a label on the top or left.
291                          * @constructor
292                          * @extends CKEDITOR.ui.dialog.labeledElement
293                          * @example
294                          * @param {CKEDITOR.dialog} dialog
295                          * Parent dialog object.
296                          * @param {CKEDITOR.dialog.uiElementDefinition} elementDefinition
297                          * The element definition. Accepted fields:
298                          * <ul>
299                          *      <li><strong>rows</strong> (Optional) The number of rows displayed.
300                          *      Defaults to 5 if not defined.</li>
301                          *      <li><strong>cols</strong> (Optional) The number of cols displayed.
302                          *      Defaults to 20 if not defined. Usually overridden by skins.</li>
303                          *      <li><strong>default</strong> (Optional) The default value.</li>
304                          *      <li><strong>validate</strong> (Optional) The validation function. </li>
305                          * </ul>
306                          * @param {Array} htmlList
307                          * List of HTML code to output to.
308                          */
309                         textarea : function( dialog, elementDefinition, htmlList )
310                         {
311                                 if ( arguments.length < 3 )
312                                         return;
314                                 initPrivateObject.call( this, elementDefinition );
315                                 var me = this,
316                                         domId = this._.inputId = CKEDITOR.tools.getNextId() + '_textarea',
317                                         attributes = {};
319                                 if ( elementDefinition.validate )
320                                         this.validate = elementDefinition.validate;
322                                 // Generates the essential attributes for the textarea tag.
323                                 attributes.rows = elementDefinition.rows || 5;
324                                 attributes.cols = elementDefinition.cols || 20;
326                                 /** @ignore */
327                                 var innerHTML = function()
328                                 {
329                                         attributes[ 'aria-labelledby' ] = this._.labelId;
330                                         this._.required && ( attributes[ 'aria-required' ] = this._.required );
331                                         var html = [ '<div class="cke_dialog_ui_input_textarea" role="presentation"><textarea class="cke_dialog_ui_input_textarea" id="', domId, '" ' ];
332                                         for ( var i in attributes )
333                                                 html.push( i + '="' + CKEDITOR.tools.htmlEncode( attributes[i] ) + '" ' );
334                                         html.push( '>', CKEDITOR.tools.htmlEncode( me._['default'] ), '</textarea></div>' );
335                                         return html.join( '' );
336                                 };
337                                 CKEDITOR.ui.dialog.labeledElement.call( this, dialog, elementDefinition, htmlList, innerHTML );
338                         },
340                         /**
341                          * A single checkbox with a label on the right.
342                          * @constructor
343                          * @extends CKEDITOR.ui.dialog.uiElement
344                          * @example
345                          * @param {CKEDITOR.dialog} dialog
346                          * Parent dialog object.
347                          * @param {CKEDITOR.dialog.uiElementDefinition} elementDefinition
348                          * The element definition. Accepted fields:
349                          * <ul>
350                          *      <li><strong>checked</strong> (Optional) Whether the checkbox is checked
351                          *      on instantiation. Defaults to false.</li>
352                          *      <li><strong>validate</strong> (Optional) The validation function.</li>
353                          *      <li><strong>label</strong> (Optional) The checkbox label.</li>
354                          * </ul>
355                          * @param {Array} htmlList
356                          * List of HTML code to output to.
357                          */
358                         checkbox : function( dialog, elementDefinition, htmlList )
359                         {
360                                 if ( arguments.length < 3 )
361                                         return;
363                                 var _ = initPrivateObject.call( this, elementDefinition, { 'default' : !!elementDefinition[ 'default' ] } );
365                                 if ( elementDefinition.validate )
366                                         this.validate = elementDefinition.validate;
368                                 /** @ignore */
369                                 var innerHTML = function()
370                                 {
371                                         var myDefinition = CKEDITOR.tools.extend( {}, elementDefinition,
372                                                         {
373                                                                 id : elementDefinition.id ? elementDefinition.id + '_checkbox' : CKEDITOR.tools.getNextId() + '_checkbox'
374                                                         }, true ),
375                                                 html = [];
377                                         var labelId = CKEDITOR.tools.getNextId() + '_label';
378                                         var attributes = { 'class' : 'cke_dialog_ui_checkbox_input', type : 'checkbox', 'aria-labelledby' : labelId };
379                                         cleanInnerDefinition( myDefinition );
380                                         if ( elementDefinition[ 'default' ] )
381                                                 attributes.checked = 'checked';
383                                         if ( typeof myDefinition.controlStyle != 'undefined' )
384                                                 myDefinition.style = myDefinition.controlStyle;
386                                         _.checkbox = new CKEDITOR.ui.dialog.uiElement( dialog, myDefinition, html, 'input', null, attributes );
387                                         html.push( ' <label id="', labelId, '" for="', attributes.id, '">',
388                                                         CKEDITOR.tools.htmlEncode( elementDefinition.label ),
389                                                         '</label>' );
390                                         return html.join( '' );
391                                 };
393                                 CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition, htmlList, 'span', null, null, innerHTML );
394                         },
396                         /**
397                          * A group of radio buttons.
398                          * @constructor
399                          * @example
400                          * @extends CKEDITOR.ui.dialog.labeledElement
401                          * @param {CKEDITOR.dialog} dialog
402                          * Parent dialog object.
403                          * @param {CKEDITOR.dialog.uiElementDefinition} elementDefinition
404                          * The element definition. Accepted fields:
405                          * <ul>
406                          *      <li><strong>default</strong> (Required) The default value.</li>
407                          *      <li><strong>validate</strong> (Optional) The validation function.</li>
408                          *      <li><strong>items</strong> (Required) An array of options. Each option
409                          *      is a 1- or 2-item array of format [ 'Description', 'Value' ]. If 'Value'
410                          *      is missing, then the value would be assumed to be the same as the
411                          *      description.</li>
412                          * </ul>
413                          * @param {Array} htmlList
414                          * List of HTML code to output to.
415                          */
416                         radio : function( dialog, elementDefinition, htmlList )
417                         {
418                                 if ( arguments.length < 3)
419                                         return;
421                                 initPrivateObject.call( this, elementDefinition );
422                                 if ( !this._['default'] )
423                                         this._['default'] = this._.initValue = elementDefinition.items[0][1];
424                                 if ( elementDefinition.validate )
425                                         this.validate = elementDefinition.valdiate;
426                                 var children = [], me = this;
428                                 /** @ignore */
429                                 var innerHTML = function()
430                                 {
431                                         var inputHtmlList = [], html = [],
432                                                 commonAttributes = { 'class' : 'cke_dialog_ui_radio_item', 'aria-labelledby' : this._.labelId },
433                                                 commonName = elementDefinition.id ? elementDefinition.id + '_radio' : CKEDITOR.tools.getNextId() + '_radio';
434                                         for ( var i = 0 ; i < elementDefinition.items.length ; i++ )
435                                         {
436                                                 var item = elementDefinition.items[i],
437                                                         title = item[2] !== undefined ? item[2] : item[0],
438                                                         value = item[1] !== undefined ? item[1] : item[0],
439                                                         inputId = CKEDITOR.tools.getNextId() + '_radio_input',
440                                                         labelId = inputId + '_label',
441                                                         inputDefinition = CKEDITOR.tools.extend( {}, elementDefinition,
442                                                                         {
443                                                                                 id : inputId,
444                                                                                 title : null,
445                                                                                 type : null
446                                                                         }, true ),
447                                                         labelDefinition = CKEDITOR.tools.extend( {}, inputDefinition,
448                                                                         {
449                                                                                 title : title
450                                                                         }, true ),
451                                                         inputAttributes =
452                                                         {
453                                                                 type : 'radio',
454                                                                 'class' : 'cke_dialog_ui_radio_input',
455                                                                 name : commonName,
456                                                                 value : value,
457                                                                 'aria-labelledby' : labelId
458                                                         },
459                                                         inputHtml = [];
460                                                 if ( me._['default'] == value )
461                                                         inputAttributes.checked = 'checked';
462                                                 cleanInnerDefinition( inputDefinition );
463                                                 cleanInnerDefinition( labelDefinition );
465                                                 if ( typeof inputDefinition.controlStyle != 'undefined' )
466                                                         inputDefinition.style = inputDefinition.controlStyle;
468                                                 children.push( new CKEDITOR.ui.dialog.uiElement( dialog, inputDefinition, inputHtml, 'input', null, inputAttributes ) );
469                                                 inputHtml.push( ' ' );
470                                                 new CKEDITOR.ui.dialog.uiElement( dialog, labelDefinition, inputHtml, 'label', null, { id : labelId, 'for' : inputAttributes.id },
471                                                            item[0] );
472                                                 inputHtmlList.push( inputHtml.join( '' ) );
473                                         }
474                                         new CKEDITOR.ui.dialog.hbox( dialog, [], inputHtmlList, html );
475                                         return html.join( '' );
476                                 };
478                                 CKEDITOR.ui.dialog.labeledElement.call( this, dialog, elementDefinition, htmlList, innerHTML );
479                                 this._.children = children;
480                         },
482                         /**
483                          * A button with a label inside.
484                          * @constructor
485                          * @example
486                          * @extends CKEDITOR.ui.dialog.uiElement
487                          * @param {CKEDITOR.dialog} dialog
488                          * Parent dialog object.
489                          * @param {CKEDITOR.dialog.uiElementDefinition} elementDefinition
490                          * The element definition. Accepted fields:
491                          * <ul>
492                          *      <li><strong>label</strong> (Required) The button label.</li>
493                          *      <li><strong>disabled</strong> (Optional) Set to true if you want the
494                          *      button to appear in disabled state.</li>
495                          * </ul>
496                          * @param {Array} htmlList
497                          * List of HTML code to output to.
498                          */
499                         button : function( dialog, elementDefinition, htmlList )
500                         {
501                                 if ( !arguments.length )
502                                         return;
504                                 if ( typeof elementDefinition == 'function' )
505                                         elementDefinition = elementDefinition( dialog.getParentEditor() );
507                                 initPrivateObject.call( this, elementDefinition, { disabled : elementDefinition.disabled || false } );
509                                 // Add OnClick event to this input.
510                                 CKEDITOR.event.implementOn( this );
512                                 var me = this;
514                                 // Register an event handler for processing button clicks.
515                                 dialog.on( 'load', function( eventInfo )
516                                         {
517                                                 var element = this.getElement();
519                                                 (function()
520                                                 {
521                                                         element.on( 'click', function( evt )
522                                                                 {
523                                                                         me.fire( 'click', { dialog : me.getDialog() } );
524                                                                         evt.data.preventDefault();
525                                                                 } );
527                                                         element.on( 'keydown', function( evt )
528                                                                 {
529                                                                         if ( evt.data.getKeystroke() in { 32:1 } )
530                                                                         {
531                                                                                 me.click();
532                                                                                 evt.data.preventDefault();
533                                                                         }
534                                                                 } );
535                                                 })();
537                                                 element.unselectable();
538                                         }, this );
540                                 var outerDefinition = CKEDITOR.tools.extend( {}, elementDefinition );
541                                 delete outerDefinition.style;
543                                 var labelId = CKEDITOR.tools.getNextId() + '_label';
544                                 CKEDITOR.ui.dialog.uiElement.call(
545                                         this,
546                                         dialog,
547                                         outerDefinition,
548                                         htmlList,
549                                         'a',
550                                         null,
551                                         {
552                                                 style : elementDefinition.style,
553                                                 href : 'javascript:void(0)',
554                                                 title : elementDefinition.label,
555                                                 hidefocus : 'true',
556                                                 'class' : elementDefinition['class'],
557                                                 role : 'button',
558                                                 'aria-labelledby' : labelId
559                                         },
560                                         '<span id="' + labelId + '" class="cke_dialog_ui_button">' +
561                                                 CKEDITOR.tools.htmlEncode( elementDefinition.label ) +
562                                         '</span>' );
563                         },
565                         /**
566                          * A select box.
567                          * @extends CKEDITOR.ui.dialog.uiElement
568                          * @example
569                          * @constructor
570                          * @param {CKEDITOR.dialog} dialog
571                          * Parent dialog object.
572                          * @param {CKEDITOR.dialog.uiElementDefinition} elementDefinition
573                          * The element definition. Accepted fields:
574                          * <ul>
575                          *      <li><strong>default</strong> (Required) The default value.</li>
576                          *      <li><strong>validate</strong> (Optional) The validation function.</li>
577                          *      <li><strong>items</strong> (Required) An array of options. Each option
578                          *      is a 1- or 2-item array of format [ 'Description', 'Value' ]. If 'Value'
579                          *      is missing, then the value would be assumed to be the same as the
580                          *      description.</li>
581                          *      <li><strong>multiple</strong> (Optional) Set this to true if you'd like
582                          *      to have a multiple-choice select box.</li>
583                          *      <li><strong>size</strong> (Optional) The number of items to display in
584                          *      the select box.</li>
585                          * </ul>
586                          * @param {Array} htmlList
587                          * List of HTML code to output to.
588                          */
589                         select : function( dialog, elementDefinition, htmlList )
590                         {
591                                 if ( arguments.length < 3 )
592                                         return;
594                                 var _ = initPrivateObject.call( this, elementDefinition );
596                                 if ( elementDefinition.validate )
597                                         this.validate = elementDefinition.validate;
599                                 _.inputId = CKEDITOR.tools.getNextId() + '_select';
600                                 /** @ignore */
601                                 var innerHTML = function()
602                                 {
603                                         var myDefinition = CKEDITOR.tools.extend( {}, elementDefinition,
604                                                         {
605                                                                 id : elementDefinition.id ? elementDefinition.id + '_select' : CKEDITOR.tools.getNextId() + '_select'
606                                                         }, true ),
607                                                 html = [],
608                                                 innerHTML = [],
609                                                 attributes = { 'id' : _.inputId, 'class' : 'cke_dialog_ui_input_select', 'aria-labelledby' : this._.labelId };
611                                         // Add multiple and size attributes from element definition.
612                                         if ( elementDefinition.size != undefined )
613                                                 attributes.size = elementDefinition.size;
614                                         if ( elementDefinition.multiple != undefined )
615                                                 attributes.multiple = elementDefinition.multiple;
617                                         cleanInnerDefinition( myDefinition );
618                                         for ( var i = 0, item ; i < elementDefinition.items.length && ( item = elementDefinition.items[i] ) ; i++ )
619                                         {
620                                                 innerHTML.push( '<option value="',
621                                                         CKEDITOR.tools.htmlEncode( item[1] !== undefined ? item[1] : item[0] ), '" /> ',
622                                                         CKEDITOR.tools.htmlEncode( item[0] ) );
623                                         }
625                                         if ( typeof myDefinition.controlStyle != 'undefined' )
626                                                 myDefinition.style = myDefinition.controlStyle;
628                                         _.select = new CKEDITOR.ui.dialog.uiElement( dialog, myDefinition, html, 'select', null, attributes, innerHTML.join( '' ) );
629                                         return html.join( '' );
630                                 };
632                                 CKEDITOR.ui.dialog.labeledElement.call( this, dialog, elementDefinition, htmlList, innerHTML );
633                         },
635                         /**
636                          * A file upload input.
637                          * @extends CKEDITOR.ui.dialog.labeledElement
638                          * @example
639                          * @constructor
640                          * @param {CKEDITOR.dialog} dialog
641                          * Parent dialog object.
642                          * @param {CKEDITOR.dialog.uiElementDefinition} elementDefinition
643                          * The element definition. Accepted fields:
644                          * <ul>
645                          *      <li><strong>validate</strong> (Optional) The validation function.</li>
646                          * </ul>
647                          * @param {Array} htmlList
648                          * List of HTML code to output to.
649                          */
650                         file : function( dialog, elementDefinition, htmlList )
651                         {
652                                 if ( arguments.length < 3 )
653                                         return;
655                                 if ( elementDefinition['default'] === undefined )
656                                         elementDefinition['default'] = '';
658                                 var _ = CKEDITOR.tools.extend( initPrivateObject.call( this, elementDefinition ), { definition : elementDefinition, buttons : [] } );
660                                 if ( elementDefinition.validate )
661                                         this.validate = elementDefinition.validate;
663                                 /** @ignore */
664                                 var innerHTML = function()
665                                 {
666                                         _.frameId = CKEDITOR.tools.getNextId() + '_fileInput';
668                                         // Support for custom document.domain in IE.
669                                         var isCustomDomain = CKEDITOR.env.isCustomDomain();
671                                         var html = [
672                                                 '<iframe' +
673                                                         ' frameborder="0"' +
674                                                         ' allowtransparency="0"' +
675                                                         ' class="cke_dialog_ui_input_file"' +
676                                                         ' id="', _.frameId, '"' +
677                                                         ' title="', elementDefinition.label, '"' +
678                                                         ' src="javascript:void(' ];
680                                         html.push(
681                                                         isCustomDomain ?
682                                                                 '(function(){' +
683                                                                         'document.open();' +
684                                                                         'document.domain=\'' + document.domain + '\';' +
685                                                                         'document.close();' +
686                                                                 '})()'
687                                                         :
688                                                                 '0' );
690                                         html.push(
691                                                         ')">' +
692                                                 '</iframe>' );
694                                         return html.join( '' );
695                                 };
697                                 // IE BUG: Parent container does not resize to contain the iframe automatically.
698                                 dialog.on( 'load', function()
699                                         {
700                                                 var iframe = CKEDITOR.document.getById( _.frameId ),
701                                                         contentDiv = iframe.getParent();
702                                                 contentDiv.addClass( 'cke_dialog_ui_input_file' );
703                                         } );
705                                 CKEDITOR.ui.dialog.labeledElement.call( this, dialog, elementDefinition, htmlList, innerHTML );
706                         },
708                         /**
709                          * A button for submitting the file in a file upload input.
710                          * @extends CKEDITOR.ui.dialog.button
711                          * @example
712                          * @constructor
713                          * @param {CKEDITOR.dialog} dialog
714                          * Parent dialog object.
715                          * @param {CKEDITOR.dialog.uiElementDefinition} elementDefinition
716                          * The element definition. Accepted fields:
717                          * <ul>
718                          *      <li><strong>for</strong> (Required) The file input's page and element Id
719                          *      to associate to, in a 2-item array format: [ 'page_id', 'element_id' ].
720                          *      </li>
721                          *      <li><strong>validate</strong> (Optional) The validation function.</li>
722                          * </ul>
723                          * @param {Array} htmlList
724                          * List of HTML code to output to.
725                          */
726                         fileButton : function( dialog, elementDefinition, htmlList )
727                         {
728                                 if ( arguments.length < 3 )
729                                         return;
731                                 var _ = initPrivateObject.call( this, elementDefinition ),
732                                         me = this;
734                                 if ( elementDefinition.validate )
735                                         this.validate = elementDefinition.validate;
737                                 var myDefinition = CKEDITOR.tools.extend( {}, elementDefinition );
738                                 var onClick = myDefinition.onClick;
739                                 myDefinition.className = ( myDefinition.className ? myDefinition.className + ' ' : '' ) + 'cke_dialog_ui_button';
740                                 myDefinition.onClick = function( evt )
741                                 {
742                                         var target = elementDefinition[ 'for' ];                // [ pageId, elementId ]
743                                         if ( !onClick || onClick.call( this, evt ) !== false )
744                                         {
745                                                 dialog.getContentElement( target[0], target[1] ).submit();
746                                                 this.disable();
747                                         }
748                                 };
750                                 dialog.on( 'load', function()
751                                                 {
752                                                         dialog.getContentElement( elementDefinition[ 'for' ][0], elementDefinition[ 'for' ][1] )._.buttons.push( me );
753                                                 } );
755                                 CKEDITOR.ui.dialog.button.call( this, dialog, myDefinition, htmlList );
756                         },
758                         html : (function()
759                         {
760                                 var myHtmlRe = /^\s*<[\w:]+\s+([^>]*)?>/,
761                                         theirHtmlRe = /^(\s*<[\w:]+(?:\s+[^>]*)?)((?:.|\r|\n)+)$/,
762                                         emptyTagRe = /\/$/;
763                                 /**
764                                  * A dialog element made from raw HTML code.
765                                  * @extends CKEDITOR.ui.dialog.uiElement
766                                  * @name CKEDITOR.ui.dialog.html
767                                  * @param {CKEDITOR.dialog} dialog Parent dialog object.
768                                  * @param {CKEDITOR.dialog.uiElementDefinition} elementDefinition Element definition.
769                                  * Accepted fields:
770                                  * <ul>
771                                  *      <li><strong>html</strong> (Required) HTML code of this element.</li>
772                                  * </ul>
773                                  * @param {Array} htmlList List of HTML code to be added to the dialog's content area.
774                                  * @example
775                                  * @constructor
776                                  */
777                                 return function( dialog, elementDefinition, htmlList )
778                                 {
779                                         if ( arguments.length < 3 )
780                                                 return;
782                                         var myHtmlList = [],
783                                                 myHtml,
784                                                 theirHtml = elementDefinition.html,
785                                                 myMatch, theirMatch;
787                                         // If the HTML input doesn't contain any tags at the beginning, add a <span> tag around it.
788                                         if ( theirHtml.charAt( 0 ) != '<' )
789                                                 theirHtml = '<span>' + theirHtml + '</span>';
791                                         // Look for focus function in definition.
792                                         var focus = elementDefinition.focus;
793                                         if ( focus )
794                                         {
795                                                 var oldFocus = this.focus;
796                                                 this.focus = function()
797                                                 {
798                                                         oldFocus.call( this );
799                                                         typeof focus == 'function' && focus.call( this );
800                                                         this.fire( 'focus' );
801                                                 };
802                                                 if ( elementDefinition.isFocusable )
803                                                 {
804                                                         var oldIsFocusable = this.isFocusable;
805                                                         this.isFocusable = oldIsFocusable;
806                                                 }
807                                                 this.keyboardFocusable = true;
808                                         }
810                                         CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition, myHtmlList, 'span', null, null, '' );
812                                         // Append the attributes created by the uiElement call to the real HTML.
813                                         myHtml = myHtmlList.join( '' );
814                                         myMatch = myHtml.match( myHtmlRe );
815                                         theirMatch = theirHtml.match( theirHtmlRe ) || [ '', '', '' ];
817                                         if ( emptyTagRe.test( theirMatch[1] ) )
818                                         {
819                                                 theirMatch[1] = theirMatch[1].slice( 0, -1 );
820                                                 theirMatch[2] = '/' + theirMatch[2];
821                                         }
823                                         htmlList.push( [ theirMatch[1], ' ', myMatch[1] || '', theirMatch[2] ].join( '' ) );
824                                 };
825                         })(),
827                         /**
828                          * Form fieldset for grouping dialog UI elements.
829                          * @constructor
830                          * @extends CKEDITOR.ui.dialog.uiElement
831                          * @param {CKEDITOR.dialog} dialog Parent dialog object.
832                          * @param {Array} childObjList
833                          * Array of {@link CKEDITOR.ui.dialog.uiElement} objects inside this
834                          * container.
835                          * @param {Array} childHtmlList
836                          * Array of HTML code that correspond to the HTML output of all the
837                          * objects in childObjList.
838                          * @param {Array} htmlList
839                          * Array of HTML code that this element will output to.
840                          * @param {CKEDITOR.dialog.uiElementDefinition} elementDefinition
841                          * The element definition. Accepted fields:
842                          * <ul>
843                          *      <li><strong>label</strong> (Optional) The legend of the this fieldset.</li>
844                          *      <li><strong>children</strong> (Required) An array of dialog field definitions which will be grouped inside this fieldset. </li>
845                          * </ul>
846                          */
847                         fieldset : function( dialog, childObjList, childHtmlList, htmlList, elementDefinition )
848                         {
849                                 var legendLabel = elementDefinition.label;
850                                 /** @ignore */
851                                 var innerHTML = function()
852                                 {
853                                         var html = [];
854                                         legendLabel && html.push( '<legend>' + legendLabel + '</legend>' );
855                                         for ( var i = 0; i < childHtmlList.length; i++ )
856                                                 html.push( childHtmlList[ i ] );
857                                         return html.join( '' );
858                                 };
860                                 this._ = { children : childObjList };
861                                 CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition, htmlList, 'fieldset', null, null, innerHTML );
862                         }
864                 }, true );
866         CKEDITOR.ui.dialog.html.prototype = new CKEDITOR.ui.dialog.uiElement;
868         CKEDITOR.ui.dialog.labeledElement.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement,
869                         /** @lends CKEDITOR.ui.dialog.labeledElement.prototype */
870                         {
871                                 /**
872                                  * Sets the label text of the element.
873                                  * @param {String} label The new label text.
874                                  * @returns {CKEDITOR.ui.dialog.labeledElement} The current labeled element.
875                                  * @example
876                                  */
877                                 setLabel : function( label )
878                                 {
879                                         var node = CKEDITOR.document.getById( this._.labelId );
880                                         if ( node.getChildCount() < 1 )
881                                                 ( new CKEDITOR.dom.text( label, CKEDITOR.document ) ).appendTo( node );
882                                         else
883                                                 node.getChild( 0 ).$.nodeValue = label;
884                                         return this;
885                                 },
887                                 /**
888                                  * Retrieves the current label text of the elment.
889                                  * @returns {String} The current label text.
890                                  * @example
891                                  */
892                                 getLabel : function()
893                                 {
894                                         var node = CKEDITOR.document.getById( this._.labelId );
895                                         if ( !node || node.getChildCount() < 1 )
896                                                 return '';
897                                         else
898                                                 return node.getChild( 0 ).getText();
899                                 },
901                                 /**
902                                  * Defines the onChange event for UI element definitions.
903                                  * @field
904                                  * @type Object
905                                  * @example
906                                  */
907                                 eventProcessors : commonEventProcessors
908                         }, true );
910         CKEDITOR.ui.dialog.button.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement,
911                         /** @lends CKEDITOR.ui.dialog.button.prototype */
912                         {
913                                 /**
914                                  * Simulates a click to the button.
915                                  * @example
916                                  * @returns {Object} Return value of the 'click' event.
917                                  */
918                                 click : function()
919                                 {
920                                         if ( !this._.disabled )
921                                                 return this.fire( 'click', { dialog : this._.dialog } );
922                                         this.getElement().$.blur();
923                                         return false;
924                                 },
926                                 /**
927                                  * Enables the button.
928                                  * @example
929                                  */
930                                 enable : function()
931                                 {
932                                         this._.disabled = false;
933                                         var element = this.getElement();
934                                         element && element.removeClass( 'cke_disabled' );
935                                 },
937                                 /**
938                                  * Disables the button.
939                                  * @example
940                                  */
941                                 disable : function()
942                                 {
943                                         this._.disabled = true;
944                                         this.getElement().addClass( 'cke_disabled' );
945                                 },
947                                 isVisible : function()
948                                 {
949                                         return this.getElement().getFirst().isVisible();
950                                 },
952                                 isEnabled : function()
953                                 {
954                                         return !this._.disabled;
955                                 },
957                                 /**
958                                  * Defines the onChange event and onClick for button element definitions.
959                                  * @field
960                                  * @type Object
961                                  * @example
962                                  */
963                                 eventProcessors : CKEDITOR.tools.extend( {}, CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors,
964                                         {
965                                                 /** @ignore */
966                                                 onClick : function( dialog, func )
967                                                 {
968                                                         this.on( 'click', func );
969                                                 }
970                                         }, true ),
972                                 /**
973                                  * Handler for the element's access key up event. Simulates a click to
974                                  * the button.
975                                  * @example
976                                  */
977                                 accessKeyUp : function()
978                                 {
979                                         this.click();
980                                 },
982                                 /**
983                                  * Handler for the element's access key down event. Simulates a mouse
984                                  * down to the button.
985                                  * @example
986                                  */
987                                 accessKeyDown : function()
988                                 {
989                                         this.focus();
990                                 },
992                                 keyboardFocusable : true
993                         }, true );
995         CKEDITOR.ui.dialog.textInput.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.labeledElement,
996                         /** @lends CKEDITOR.ui.dialog.textInput.prototype */
997                         {
998                                 /**
999                                  * Gets the text input DOM element under this UI object.
1000                                  * @example
1001                                  * @returns {CKEDITOR.dom.element} The DOM element of the text input.
1002                                  */
1003                                 getInputElement : function()
1004                                 {
1005                                         return CKEDITOR.document.getById( this._.inputId );
1006                                 },
1008                                 /**
1009                                  * Puts focus into the text input.
1010                                  * @example
1011                                  */
1012                                 focus : function()
1013                                 {
1014                                         var me = this.selectParentTab();
1016                                         // GECKO BUG: setTimeout() is needed to workaround invisible selections.
1017                                         setTimeout( function()
1018                                                 {
1019                                                         var element = me.getInputElement();
1020                                                         element && element.$.focus();
1021                                                 }, 0 );
1022                                 },
1024                                 /**
1025                                  * Selects all the text in the text input.
1026                                  * @example
1027                                  */
1028                                 select : function()
1029                                 {
1030                                         var me = this.selectParentTab();
1032                                         // GECKO BUG: setTimeout() is needed to workaround invisible selections.
1033                                         setTimeout( function()
1034                                                 {
1035                                                         var e = me.getInputElement();
1036                                                         if ( e )
1037                                                         {
1038                                                                 e.$.focus();
1039                                                                 e.$.select();
1040                                                         }
1041                                                 }, 0 );
1042                                 },
1044                                 /**
1045                                  * Handler for the text input's access key up event. Makes a select()
1046                                  * call to the text input.
1047                                  * @example
1048                                  */
1049                                 accessKeyUp : function()
1050                                 {
1051                                         this.select();
1052                                 },
1054                                 /**
1055                                  * Sets the value of this text input object.
1056                                  * @param {Object} value The new value.
1057                                  * @returns {CKEDITOR.ui.dialog.textInput} The current UI element.
1058                                  * @example
1059                                  * uiElement.setValue( 'Blamo' );
1060                                  */
1061                                 setValue : function( value )
1062                                 {
1063                                         !value && ( value = '' );
1064                                         return CKEDITOR.ui.dialog.uiElement.prototype.setValue.apply( this, arguments );
1065                                 },
1067                                 keyboardFocusable : true
1068                         }, commonPrototype, true );
1070         CKEDITOR.ui.dialog.textarea.prototype = new CKEDITOR.ui.dialog.textInput();
1072         CKEDITOR.ui.dialog.select.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.labeledElement,
1073                         /** @lends CKEDITOR.ui.dialog.select.prototype */
1074                         {
1075                                 /**
1076                                  * Gets the DOM element of the select box.
1077                                  * @returns {CKEDITOR.dom.element} The &lt;select&gt; element of this UI
1078                                  * element.
1079                                  * @example
1080                                  */
1081                                 getInputElement : function()
1082                                 {
1083                                         return this._.select.getElement();
1084                                 },
1086                                 /**
1087                                  * Adds an option to the select box.
1088                                  * @param {String} label Option label.
1089                                  * @param {String} value (Optional) Option value, if not defined it'll be
1090                                  * assumed to be the same as the label.
1091                                  * @param {Number} index (Optional) Position of the option to be inserted
1092                                  * to. If not defined the new option will be inserted to the end of list.
1093                                  * @example
1094                                  * @returns {CKEDITOR.ui.dialog.select} The current select UI element.
1095                                  */
1096                                 add : function( label, value, index )
1097                                 {
1098                                         var option = new CKEDITOR.dom.element( 'option', this.getDialog().getParentEditor().document ),
1099                                                 selectElement = this.getInputElement().$;
1100                                         option.$.text = label;
1101                                         option.$.value = ( value === undefined || value === null ) ? label : value;
1102                                         if ( index === undefined || index === null )
1103                                         {
1104                                                 if ( CKEDITOR.env.ie )
1105                                                         selectElement.add( option.$ );
1106                                                 else
1107                                                         selectElement.add( option.$, null );
1108                                         }
1109                                         else
1110                                                 selectElement.add( option.$, index );
1111                                         return this;
1112                                 },
1114                                 /**
1115                                  * Removes an option from the selection list.
1116                                  * @param {Number} index Index of the option to be removed.
1117                                  * @example
1118                                  * @returns {CKEDITOR.ui.dialog.select} The current select UI element.
1119                                  */
1120                                 remove : function( index )
1121                                 {
1122                                         var selectElement = this.getInputElement().$;
1123                                         selectElement.remove( index );
1124                                         return this;
1125                                 },
1127                                 /**
1128                                  * Clears all options out of the selection list.
1129                                  * @returns {CKEDITOR.ui.dialog.select} The current select UI element.
1130                                  */
1131                                 clear : function()
1132                                 {
1133                                         var selectElement = this.getInputElement().$;
1134                                         while ( selectElement.length > 0 )
1135                                                 selectElement.remove( 0 );
1136                                         return this;
1137                                 },
1139                                 keyboardFocusable : true
1140                         }, commonPrototype, true );
1142         CKEDITOR.ui.dialog.checkbox.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement,
1143                         /** @lends CKEDITOR.ui.dialog.checkbox.prototype */
1144                         {
1145                                 /**
1146                                  * Gets the checkbox DOM element.
1147                                  * @example
1148                                  * @returns {CKEDITOR.dom.element} The DOM element of the checkbox.
1149                                  */
1150                                 getInputElement : function()
1151                                 {
1152                                         return this._.checkbox.getElement();
1153                                 },
1155                                 /**
1156                                  * Sets the state of the checkbox.
1157                                  * @example
1158                                  * @param {Boolean} true to tick the checkbox, false to untick it.
1159                                  * @param {Boolean} noChangeEvent Internal commit, to supress 'change' event on this element.
1160                                  */
1161                                 setValue : function( checked, noChangeEvent )
1162                                 {
1163                                         this.getInputElement().$.checked = checked;
1164                                         !noChangeEvent && this.fire( 'change', { value : checked } );
1165                                 },
1167                                 /**
1168                                  * Gets the state of the checkbox.
1169                                  * @example
1170                                  * @returns {Boolean} true means the checkbox is ticked, false means it's not ticked.
1171                                  */
1172                                 getValue : function()
1173                                 {
1174                                         return this.getInputElement().$.checked;
1175                                 },
1177                                 /**
1178                                  * Handler for the access key up event. Toggles the checkbox.
1179                                  * @example
1180                                  */
1181                                 accessKeyUp : function()
1182                                 {
1183                                         this.setValue( !this.getValue() );
1184                                 },
1186                                 /**
1187                                  * Defines the onChange event for UI element definitions.
1188                                  * @field
1189                                  * @type Object
1190                                  * @example
1191                                  */
1192                                 eventProcessors :
1193                                 {
1194                                         onChange : function( dialog, func )
1195                                         {
1196                                                 if ( !CKEDITOR.env.ie )
1197                                                         return commonEventProcessors.onChange.apply( this, arguments );
1198                                                 else
1199                                                 {
1200                                                         dialog.on( 'load', function()
1201                                                                 {
1202                                                                         var element = this._.checkbox.getElement();
1203                                                                         element.on( 'propertychange', function( evt )
1204                                                                                 {
1205                                                                                         evt = evt.data.$;
1206                                                                                         if ( evt.propertyName == 'checked' )
1207                                                                                                 this.fire( 'change', { value : element.$.checked } );
1208                                                                                 }, this );
1209                                                                 }, this );
1210                                                         this.on( 'change', func );
1211                                                 }
1212                                                 return null;
1213                                         }
1214                                 },
1216                                 keyboardFocusable : true
1217                         }, commonPrototype, true );
1219         CKEDITOR.ui.dialog.radio.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement,
1220                         /** @lends CKEDITOR.ui.dialog.radio.prototype */
1221                         {
1222                                 /**
1223                                  * Checks one of the radio buttons in this button group.
1224                                  * @example
1225                                  * @param {String} value The value of the button to be chcked.
1226                                  * @param {Boolean} noChangeEvent Internal commit, to supress 'change' event on this element.
1227                                  */
1228                                 setValue : function( value, noChangeEvent )
1229                                 {
1230                                         var children = this._.children,
1231                                                 item;
1232                                         for ( var i = 0 ; ( i < children.length ) && ( item = children[i] ) ; i++ )
1233                                                 item.getElement().$.checked = ( item.getValue() == value );
1234                                         !noChangeEvent && this.fire( 'change', { value : value } );
1235                                 },
1237                                 /**
1238                                  * Gets the value of the currently checked radio button.
1239                                  * @example
1240                                  * @returns {String} The currently checked button's value.
1241                                  */
1242                                 getValue : function()
1243                                 {
1244                                         var children = this._.children;
1245                                         for ( var i = 0 ; i < children.length ; i++ )
1246                                         {
1247                                                 if ( children[i].getElement().$.checked )
1248                                                         return children[i].getValue();
1249                                         }
1250                                         return null;
1251                                 },
1253                                 /**
1254                                  * Handler for the access key up event. Focuses the currently
1255                                  * selected radio button, or the first radio button if none is
1256                                  * selected.
1257                                  * @example
1258                                  */
1259                                 accessKeyUp : function()
1260                                 {
1261                                         var children = this._.children, i;
1262                                         for ( i = 0 ; i < children.length ; i++ )
1263                                         {
1264                                                 if ( children[i].getElement().$.checked )
1265                                                 {
1266                                                         children[i].getElement().focus();
1267                                                         return;
1268                                                 }
1269                                         }
1270                                         children[0].getElement().focus();
1271                                 },
1273                                 /**
1274                                  * Defines the onChange event for UI element definitions.
1275                                  * @field
1276                                  * @type Object
1277                                  * @example
1278                                  */
1279                                 eventProcessors :
1280                                 {
1281                                         onChange : function( dialog, func )
1282                                         {
1283                                                 if ( !CKEDITOR.env.ie )
1284                                                         return commonEventProcessors.onChange.apply( this, arguments );
1285                                                 else
1286                                                 {
1287                                                         dialog.on( 'load', function()
1288                                                                 {
1289                                                                         var children = this._.children, me = this;
1290                                                                         for ( var i = 0 ; i < children.length ; i++ )
1291                                                                         {
1292                                                                                 var element = children[i].getElement();
1293                                                                                 element.on( 'propertychange', function( evt )
1294                                                                                         {
1295                                                                                                 evt = evt.data.$;
1296                                                                                                 if ( evt.propertyName == 'checked' && this.$.checked )
1297                                                                                                         me.fire( 'change', { value : this.getAttribute( 'value' ) } );
1298                                                                                         } );
1299                                                                         }
1300                                                                 }, this );
1301                                                         this.on( 'change', func );
1302                                                 }
1303                                                 return null;
1304                                         }
1305                                 },
1307                                 keyboardFocusable : true
1308                         }, commonPrototype, true );
1310         CKEDITOR.ui.dialog.file.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.labeledElement,
1311                         commonPrototype,
1312                         /** @lends CKEDITOR.ui.dialog.file.prototype */
1313                         {
1314                                 /**
1315                                  * Gets the &lt;input&gt; element of this file input.
1316                                  * @returns {CKEDITOR.dom.element} The file input element.
1317                                  * @example
1318                                  */
1319                                 getInputElement : function()
1320                                 {
1321                                         var frameDocument = CKEDITOR.document.getById( this._.frameId ).getFrameDocument();
1322                                         return frameDocument.$.forms.length > 0 ?
1323                                                 new CKEDITOR.dom.element( frameDocument.$.forms[0].elements[0] ) :
1324                                                 this.getElement();
1325                                 },
1327                                 /**
1328                                  * Uploads the file in the file input.
1329                                  * @returns {CKEDITOR.ui.dialog.file} This object.
1330                                  * @example
1331                                  */
1332                                 submit : function()
1333                                 {
1334                                         this.getInputElement().getParent().$.submit();
1335                                         return this;
1336                                 },
1338                                 /**
1339                                  * Get the action assigned to the form.
1340                                  * @returns {String} The value of the action.
1341                                  * @example
1342                                  */
1343                                 getAction : function()
1344                                 {
1345                                         return this.getInputElement().getParent().$.action;
1346                                 },
1348                                 /**
1349                                  * The events must be applied on the inner input element, and
1350                                  * that must be done when the iframe & form has been loaded
1351                                  */
1352                                 registerEvents : function( definition )
1353                                 {
1354                                         var regex = /^on([A-Z]\w+)/,
1355                                                 match;
1357                                         var registerDomEvent = function( uiElement, dialog, eventName, func )
1358                                         {
1359                                                 uiElement.on( 'formLoaded', function()
1360                                                 {
1361                                                         uiElement.getInputElement().on( eventName, func, uiElement );
1362                                                 });
1363                                         };
1365                                         for ( var i in definition )
1366                                         {
1367                                                 if ( !( match = i.match( regex ) ) )
1368                                                         continue;
1370                                                 if ( this.eventProcessors[i] )
1371                                                         this.eventProcessors[i].call( this, this._.dialog, definition[i] );
1372                                                 else
1373                                                         registerDomEvent( this, this._.dialog, match[1].toLowerCase(), definition[i] );
1374                                         }
1376                                         return this;
1377                                 },
1379                                 /**
1380                                  * Redraws the file input and resets the file path in the file input.
1381                                  * The redraw logic is necessary because non-IE browsers tend to clear
1382                                  * the &lt;iframe&gt; containing the file input after closing the dialog.
1383                                  * @example
1384                                  */
1385                                 reset : function()
1386                                 {
1387                                         var _ = this._,
1388                                                 frameElement = CKEDITOR.document.getById( _.frameId ),
1389                                                 frameDocument = frameElement.getFrameDocument(),
1390                                                 elementDefinition = _.definition,
1391                                                 buttons = _.buttons,
1392                                                 callNumber = this.formLoadedNumber,
1393                                                 unloadNumber = this.formUnloadNumber,
1394                                                 langDir = _.dialog._.editor.lang.dir,
1395                                                 langCode = _.dialog._.editor.langCode;
1397                                         // The callback function for the iframe, but we must call tools.addFunction only once
1398                                         // so we store the function number in this.formLoadedNumber
1399                                         if ( !callNumber )
1400                                         {
1401                                                 callNumber = this.formLoadedNumber = CKEDITOR.tools.addFunction(
1402                                                         function()
1403                                                         {
1404                                                                 // Now we can apply the events to the input type=file
1405                                                                 this.fire( 'formLoaded' ) ;
1406                                                         }, this ) ;
1408                                                 // Remove listeners attached to the content of the iframe (the file input)
1409                                                 unloadNumber = this.formUnloadNumber = CKEDITOR.tools.addFunction(
1410                                                         function()
1411                                                         {
1412                                                                 this.getInputElement().clearCustomData();
1413                                                         }, this ) ;
1415                                                 this.getDialog()._.editor.on( 'destroy', function()
1416                                                                 {
1417                                                                         CKEDITOR.tools.removeFunction( callNumber );
1418                                                                         CKEDITOR.tools.removeFunction( unloadNumber );
1419                                                                 } );
1420                                         }
1422                                         function generateFormField()
1423                                         {
1424                                                 frameDocument.$.open();
1426                                                 // Support for custom document.domain in IE.
1427                                                 if ( CKEDITOR.env.isCustomDomain() )
1428                                                         frameDocument.$.domain = document.domain;
1430                                                 var size = '';
1431                                                 if ( elementDefinition.size )
1432                                                         size = elementDefinition.size - ( CKEDITOR.env.ie  ? 7 : 0 );   // "Browse" button is bigger in IE.
1434                                                 frameDocument.$.write( [ '<html dir="' + langDir + '" lang="' + langCode + '"><head><title></title></head><body style="margin: 0; overflow: hidden; background: transparent;">',
1435                                                                 '<form enctype="multipart/form-data" method="POST" dir="' + langDir + '" lang="' + langCode + '" action="',
1436                                                                 CKEDITOR.tools.htmlEncode( elementDefinition.action ),
1437                                                                 '">',
1438                                                                 '<input type="file" name="',
1439                                                                 CKEDITOR.tools.htmlEncode( elementDefinition.id || 'cke_upload' ),
1440                                                                 '" size="',
1441                                                                 CKEDITOR.tools.htmlEncode( size > 0 ? size : "" ),
1442                                                                 '" />',
1443                                                                 '</form>',
1444                                                                 '</body></html>',
1445                                                                 '<script>window.parent.CKEDITOR.tools.callFunction(' + callNumber + ');',
1446                                                                 'window.onbeforeunload = function() {window.parent.CKEDITOR.tools.callFunction(' + unloadNumber + ')}</script>' ].join( '' ) );
1448                                                 frameDocument.$.close();
1450                                                 for ( var i = 0 ; i < buttons.length ; i++ )
1451                                                         buttons[i].enable();
1452                                         }
1454                                         // #3465: Wait for the browser to finish rendering the dialog first.
1455                                         if ( CKEDITOR.env.gecko )
1456                                                 setTimeout( generateFormField, 500 );
1457                                         else
1458                                                 generateFormField();
1459                                 },
1461                                 getValue : function()
1462                                 {
1463                                         return this.getInputElement().$.value || '';
1464                                 },
1466                                 /***
1467                                  * The default value of input type="file" is an empty string, but during initialization
1468                                  * of this UI element, the iframe still isn't ready so it can't be read from that object
1469                                  * Setting it manually prevents later issues about the current value ("") being different
1470                                  * of the initial value (undefined as it asked for .value of a div)
1471                                  */
1472                                 setInitValue : function()
1473                                 {
1474                                         this._.initValue = '';
1475                                 },
1477                                 /**
1478                                  * Defines the onChange event for UI element definitions.
1479                                  * @field
1480                                  * @type Object
1481                                  * @example
1482                                  */
1483                                 eventProcessors :
1484                                 {
1485                                         onChange : function( dialog, func )
1486                                         {
1487                                                 // If this method is called several times (I'm not sure about how this can happen but the default
1488                                                 // onChange processor includes this protection)
1489                                                 // In order to reapply to the new element, the property is deleted at the beggining of the registerEvents method
1490                                                 if ( !this._.domOnChangeRegistered )
1491                                                 {
1492                                                         // By listening for the formLoaded event, this handler will get reapplied when a new
1493                                                         // form is created
1494                                                         this.on( 'formLoaded', function()
1495                                                         {
1496                                                                 this.getInputElement().on( 'change', function(){ this.fire( 'change', { value : this.getValue() } ); }, this );
1497                                                         }, this );
1498                                                         this._.domOnChangeRegistered = true;
1499                                                 }
1501                                                 this.on( 'change', func );
1502                                         }
1503                                 },
1505                                 keyboardFocusable : true
1506                         }, true );
1508         CKEDITOR.ui.dialog.fileButton.prototype = new CKEDITOR.ui.dialog.button;
1510         CKEDITOR.ui.dialog.fieldset.prototype = CKEDITOR.tools.clone( CKEDITOR.ui.dialog.hbox.prototype );
1512         CKEDITOR.dialog.addUIElement( 'text', textBuilder );
1513         CKEDITOR.dialog.addUIElement( 'password', textBuilder );
1514         CKEDITOR.dialog.addUIElement( 'textarea', commonBuilder );
1515         CKEDITOR.dialog.addUIElement( 'checkbox', commonBuilder );
1516         CKEDITOR.dialog.addUIElement( 'radio', commonBuilder );
1517         CKEDITOR.dialog.addUIElement( 'button', commonBuilder );
1518         CKEDITOR.dialog.addUIElement( 'select', commonBuilder );
1519         CKEDITOR.dialog.addUIElement( 'file', commonBuilder );
1520         CKEDITOR.dialog.addUIElement( 'fileButton', commonBuilder );
1521         CKEDITOR.dialog.addUIElement( 'html', commonBuilder );
1522         CKEDITOR.dialog.addUIElement( 'fieldset', containerBuilder );
1523 })();
1526  * Fired when the value of the uiElement is changed
1527  * @name CKEDITOR.ui.dialog.uiElement#change
1528  * @event
1529  */
1532  * Fired when the inner frame created by the element is ready.
1533  * Each time the button is used or the dialog is loaded a new
1534  * form might be created.
1535  * @name CKEDITOR.ui.dialog.fileButton#formLoaded
1536  * @event
1537  */