initial commit
[namibia] / public / scripts / ckeditor / _source / plugins / dialog / plugin.js
1 /*
2 Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
3 For licensing, see LICENSE.html or http://ckeditor.com/license
4 */
5
6 /**
7  * @fileOverview The floating dialog plugin.
8  */
9
10 /**
11  * No resize for this dialog.
12  * @constant
13  */
14 CKEDITOR.DIALOG_RESIZE_NONE = 0;
15
16 /**
17  * Only allow horizontal resizing for this dialog, disable vertical resizing.
18  * @constant
19  */
20 CKEDITOR.DIALOG_RESIZE_WIDTH = 1;
21
22 /**
23  * Only allow vertical resizing for this dialog, disable horizontal resizing.
24  * @constant
25  */
26 CKEDITOR.DIALOG_RESIZE_HEIGHT = 2;
27
28 /*
29  * Allow the dialog to be resized in both directions.
30  * @constant
31  */
32 CKEDITOR.DIALOG_RESIZE_BOTH = 3;
33
34 (function()
35 {
36         var cssLength = CKEDITOR.tools.cssLength;
37         function isTabVisible( tabId )
38         {
39                 return !!this._.tabs[ tabId ][ 0 ].$.offsetHeight;
40         }
41
42         function getPreviousVisibleTab()
43         {
44                 var tabId = this._.currentTabId,
45                         length = this._.tabIdList.length,
46                         tabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, tabId ) + length;
47
48                 for ( var i = tabIndex - 1 ; i > tabIndex - length ; i-- )
49                 {
50                         if ( isTabVisible.call( this, this._.tabIdList[ i % length ] ) )
51                                 return this._.tabIdList[ i % length ];
52                 }
53
54                 return null;
55         }
56
57         function getNextVisibleTab()
58         {
59                 var tabId = this._.currentTabId,
60                         length = this._.tabIdList.length,
61                         tabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, tabId );
62
63                 for ( var i = tabIndex + 1 ; i < tabIndex + length ; i++ )
64                 {
65                         if ( isTabVisible.call( this, this._.tabIdList[ i % length ] ) )
66                                 return this._.tabIdList[ i % length ];
67                 }
68
69                 return null;
70         }
71
72
73         function clearOrRecoverTextInputValue( container, isRecover )
74         {
75                 var inputs = container.$.getElementsByTagName( 'input' );
76                 for ( var i = 0, length = inputs.length; i < length ; i++ )
77                 {
78                         var item = new CKEDITOR.dom.element( inputs[ i ] );
79
80                         if ( item.getAttribute( 'type' ).toLowerCase() == 'text' )
81                         {
82                                 if ( isRecover )
83                                 {
84                                         item.setAttribute( 'value', item.getCustomData( 'fake_value' ) || '' );
85                                         item.removeCustomData( 'fake_value' );
86                                 }
87                                 else
88                                 {
89                                         item.setCustomData( 'fake_value', item.getAttribute( 'value' ) );
90                                         item.setAttribute( 'value', '' );
91                                 }
92                         }
93                 }
94         }
95
96         // Handle dialog element validation state UI changes.
97         function handleFieldValidated( isValid, msg )
98         {
99                 var input = this.getInputElement();
100                 if ( input )
101                 {
102                         isValid ? input.removeAttribute( 'aria-invalid' )
103                                 : input.setAttribute( 'aria-invalid', true );
104                 }
105
106                 if ( !isValid )
107                 {
108                         if ( this.select )
109                                 this.select();
110                         else
111                                 this.focus();
112                 }
113
114                 msg && alert( msg );
115
116                 this.fire( 'validated', { valid : isValid, msg : msg } );
117         }
118
119         function resetField()
120         {
121                 var input = this.getInputElement();
122                 input && input.removeAttribute( 'aria-invalid' );
123         }
124
125
126         /**
127          * This is the base class for runtime dialog objects. An instance of this
128          * class represents a single named dialog for a single editor instance.
129          * @param {Object} editor The editor which created the dialog.
130          * @param {String} dialogName The dialog's registered name.
131          * @constructor
132          * @example
133          * var dialogObj = new CKEDITOR.dialog( editor, 'smiley' );
134          */
135         CKEDITOR.dialog = function( editor, dialogName )
136         {
137                 // Load the dialog definition.
138                 var definition = CKEDITOR.dialog._.dialogDefinitions[ dialogName ],
139                         defaultDefinition = CKEDITOR.tools.clone( defaultDialogDefinition ),
140                         buttonsOrder = editor.config.dialog_buttonsOrder || 'OS',
141                         dir = editor.lang.dir;
142
143                         if ( ( buttonsOrder == 'OS' && CKEDITOR.env.mac ) ||    // The buttons in MacOS Apps are in reverse order (#4750)
144                                 ( buttonsOrder == 'rtl' && dir == 'ltr' ) ||
145                                 ( buttonsOrder == 'ltr' && dir == 'rtl' ) )
146                                         defaultDefinition.buttons.reverse();
147
148
149                 // Completes the definition with the default values.
150                 definition = CKEDITOR.tools.extend( definition( editor ), defaultDefinition );
151
152                 // Clone a functionally independent copy for this dialog.
153                 definition = CKEDITOR.tools.clone( definition );
154
155                 // Create a complex definition object, extending it with the API
156                 // functions.
157                 definition = new definitionObject( this, definition );
158
159                 var doc = CKEDITOR.document;
160
161                 var themeBuilt = editor.theme.buildDialog( editor );
162
163                 // Initialize some basic parameters.
164                 this._ =
165                 {
166                         editor : editor,
167                         element : themeBuilt.element,
168                         name : dialogName,
169                         contentSize : { width : 0, height : 0 },
170                         size : { width : 0, height : 0 },
171                         contents : {},
172                         buttons : {},
173                         accessKeyMap : {},
174
175                         // Initialize the tab and page map.
176                         tabs : {},
177                         tabIdList : [],
178                         currentTabId : null,
179                         currentTabIndex : null,
180                         pageCount : 0,
181                         lastTab : null,
182                         tabBarMode : false,
183
184                         // Initialize the tab order array for input widgets.
185                         focusList : [],
186                         currentFocusIndex : 0,
187                         hasFocus : false
188                 };
189
190                 this.parts = themeBuilt.parts;
191
192                 CKEDITOR.tools.setTimeout( function()
193                         {
194                                 editor.fire( 'ariaWidget', this.parts.contents );
195                         },
196                         0, this );
197
198                 // Set the startup styles for the dialog, avoiding it enlarging the
199                 // page size on the dialog creation.
200                 var startStyles = {
201                                 position : CKEDITOR.env.ie6Compat ? 'absolute' : 'fixed',
202                                 top : 0,
203                                 visibility : 'hidden'
204                 };
205
206                 startStyles[ dir == 'rtl' ? 'right' : 'left' ] = 0;
207                 this.parts.dialog.setStyles( startStyles );
208
209
210                 // Call the CKEDITOR.event constructor to initialize this instance.
211                 CKEDITOR.event.call( this );
212
213                 // Fire the "dialogDefinition" event, making it possible to customize
214                 // the dialog definition.
215                 this.definition = definition = CKEDITOR.fire( 'dialogDefinition',
216                         {
217                                 name : dialogName,
218                                 definition : definition
219                         }
220                         , editor ).definition;
221
222                 var tabsToRemove = {};
223                 // Cache tabs that should be removed.
224                 if ( !( 'removeDialogTabs' in editor._ ) && editor.config.removeDialogTabs )
225                 {
226                         var removeContents = editor.config.removeDialogTabs.split( ';' );
227
228                         for ( i = 0; i < removeContents.length; i++ )
229                         {
230                                 var parts = removeContents[ i ].split( ':' );
231                                 if ( parts.length == 2 )
232                                 {
233                                         var removeDialogName = parts[ 0 ];
234                                         if ( !tabsToRemove[ removeDialogName ] )
235                                                 tabsToRemove[ removeDialogName ] = [];
236                                         tabsToRemove[ removeDialogName ].push( parts[ 1 ] );
237                                 }
238                         }
239                         editor._.removeDialogTabs = tabsToRemove;
240                 }
241
242                 // Remove tabs of this dialog.
243                 if ( editor._.removeDialogTabs && ( tabsToRemove = editor._.removeDialogTabs[ dialogName ] ) )
244                 {
245                         for ( i = 0; i < tabsToRemove.length; i++ )
246                                 definition.removeContents( tabsToRemove[ i ] );
247                 }
248
249                 // Initialize load, show, hide, ok and cancel events.
250                 if ( definition.onLoad )
251                         this.on( 'load', definition.onLoad );
252
253                 if ( definition.onShow )
254                         this.on( 'show', definition.onShow );
255
256                 if ( definition.onHide )
257                         this.on( 'hide', definition.onHide );
258
259                 if ( definition.onOk )
260                 {
261                         this.on( 'ok', function( evt )
262                                 {
263                                         // Dialog confirm might probably introduce content changes (#5415).
264                                         editor.fire( 'saveSnapshot' );
265                                         setTimeout( function () { editor.fire( 'saveSnapshot' ); }, 0 );
266                                         if ( definition.onOk.call( this, evt ) === false )
267                                                 evt.data.hide = false;
268                                 });
269                 }
270
271                 if ( definition.onCancel )
272                 {
273                         this.on( 'cancel', function( evt )
274                                 {
275                                         if ( definition.onCancel.call( this, evt ) === false )
276                                                 evt.data.hide = false;
277                                 });
278                 }
279
280                 var me = this;
281
282                 // Iterates over all items inside all content in the dialog, calling a
283                 // function for each of them.
284                 var iterContents = function( func )
285                 {
286                         var contents = me._.contents,
287                                 stop = false;
288
289                         for ( var i in contents )
290                         {
291                                 for ( var j in contents[i] )
292                                 {
293                                         stop = func.call( this, contents[i][j] );
294                                         if ( stop )
295                                                 return;
296                                 }
297                         }
298                 };
299
300                 this.on( 'ok', function( evt )
301                         {
302                                 iterContents( function( item )
303                                         {
304                                                 if ( item.validate )
305                                                 {
306                                                         var retval = item.validate( this ),
307                                                                 invalid = typeof ( retval ) == 'string' || retval === false;
308
309                                                         if ( invalid )
310                                                         {
311                                                                 evt.data.hide = false;
312                                                                 evt.stop();
313                                                         }
314
315                                                         handleFieldValidated.call( item, !invalid, typeof retval == 'string' ? retval : undefined );
316                                                         return invalid;
317                                                 }
318                                         });
319                         }, this, null, 0 );
320
321                 this.on( 'cancel', function( evt )
322                         {
323                                 iterContents( function( item )
324                                         {
325                                                 if ( item.isChanged() )
326                                                 {
327                                                         if ( !confirm( editor.lang.common.confirmCancel ) )
328                                                                 evt.data.hide = false;
329                                                         return true;
330                                                 }
331                                         });
332                         }, this, null, 0 );
333
334                 this.parts.close.on( 'click', function( evt )
335                                 {
336                                         if ( this.fire( 'cancel', { hide : true } ).hide !== false )
337                                                 this.hide();
338                                         evt.data.preventDefault();
339                                 }, this );
340
341                 // Sort focus list according to tab order definitions.
342                 function setupFocus()
343                 {
344                         var focusList = me._.focusList;
345                         focusList.sort( function( a, b )
346                                 {
347                                         // Mimics browser tab order logics;
348                                         if ( a.tabIndex != b.tabIndex )
349                                                 return b.tabIndex - a.tabIndex;
350                                         //  Sort is not stable in some browsers,
351                                         // fall-back the comparator to 'focusIndex';
352                                         else
353                                                 return a.focusIndex - b.focusIndex;
354                                 });
355
356                         var size = focusList.length;
357                         for ( var i = 0; i < size; i++ )
358                                 focusList[ i ].focusIndex = i;
359                 }
360
361                 function changeFocus( forward )
362                 {
363                         var focusList = me._.focusList,
364                                 offset = forward ? 1 : -1;
365                         if ( focusList.length < 1 )
366                                 return;
367
368                         var current = me._.currentFocusIndex;
369
370                         // Trigger the 'blur' event of  any input element before anything,
371                         // since certain UI updates may depend on it.
372                         try
373                         {
374                                 focusList[ current ].getInputElement().$.blur();
375                         }
376                         catch( e ){}
377
378                         var startIndex = ( current + offset + focusList.length ) % focusList.length,
379                                 currentIndex = startIndex;
380                         while ( !focusList[ currentIndex ].isFocusable() )
381                         {
382                                 currentIndex = ( currentIndex + offset + focusList.length ) % focusList.length;
383                                 if ( currentIndex == startIndex )
384                                         break;
385                         }
386                         focusList[ currentIndex ].focus();
387
388                         // Select whole field content.
389                         if ( focusList[ currentIndex ].type == 'text' )
390                                 focusList[ currentIndex ].select();
391                 }
392
393                 this.changeFocus = changeFocus;
394
395                 var processed;
396
397                 function focusKeydownHandler( evt )
398                 {
399                         // If I'm not the top dialog, ignore.
400                         if ( me != CKEDITOR.dialog._.currentTop )
401                                 return;
402
403                         var keystroke = evt.data.getKeystroke(),
404                                 rtl = editor.lang.dir == 'rtl';
405
406                         processed = 0;
407                         if ( keystroke == 9 || keystroke == CKEDITOR.SHIFT + 9 )
408                         {
409                                 var shiftPressed = ( keystroke == CKEDITOR.SHIFT + 9 );
410
411                                 // Handling Tab and Shift-Tab.
412                                 if ( me._.tabBarMode )
413                                 {
414                                         // Change tabs.
415                                         var nextId = shiftPressed ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me );
416                                         me.selectPage( nextId );
417                                         me._.tabs[ nextId ][ 0 ].focus();
418                                 }
419                                 else
420                                 {
421                                         // Change the focus of inputs.
422                                         changeFocus( !shiftPressed );
423                                 }
424
425                                 processed = 1;
426                         }
427                         else if ( keystroke == CKEDITOR.ALT + 121 && !me._.tabBarMode && me.getPageCount() > 1 )
428                         {
429                                 // Alt-F10 puts focus into the current tab item in the tab bar.
430                                 me._.tabBarMode = true;
431                                 me._.tabs[ me._.currentTabId ][ 0 ].focus();
432                                 processed = 1;
433                         }
434                         else if ( ( keystroke == 37 || keystroke == 39 ) && me._.tabBarMode )
435                         {
436                                 // Arrow keys - used for changing tabs.
437                                 nextId = ( keystroke == ( rtl ? 39 : 37 ) ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me ) );
438                                 me.selectPage( nextId );
439                                 me._.tabs[ nextId ][ 0 ].focus();
440                                 processed = 1;
441                         }
442                         else if ( ( keystroke == 13 || keystroke == 32 ) && me._.tabBarMode )
443                         {
444                                 this.selectPage( this._.currentTabId );
445                                 this._.tabBarMode = false;
446                                 this._.currentFocusIndex = -1;
447                                 changeFocus( true );
448                                 processed = 1;
449                         }
450
451                         if ( processed )
452                         {
453                                 evt.stop();
454                                 evt.data.preventDefault();
455                         }
456                 }
457
458                 function focusKeyPressHandler( evt )
459                 {
460                         processed && evt.data.preventDefault();
461                 }
462
463                 var dialogElement = this._.element;
464                 // Add the dialog keyboard handlers.
465                 this.on( 'show', function()
466                         {
467                                 dialogElement.on( 'keydown', focusKeydownHandler, this, null, 0 );
468                                 // Some browsers instead, don't cancel key events in the keydown, but in the
469                                 // keypress. So we must do a longer trip in those cases. (#4531)
470                                 if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) )
471                                         dialogElement.on( 'keypress', focusKeyPressHandler, this );
472
473                         } );
474                 this.on( 'hide', function()
475                         {
476                                 dialogElement.removeListener( 'keydown', focusKeydownHandler );
477                                 if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) )
478                                         dialogElement.removeListener( 'keypress', focusKeyPressHandler );
479
480                                 // Reset fields state when closing dialog.
481                                 iterContents( function( item ) { resetField.apply( item ); } );
482                         } );
483                 this.on( 'iframeAdded', function( evt )
484                         {
485                                 var doc = new CKEDITOR.dom.document( evt.data.iframe.$.contentWindow.document );
486                                 doc.on( 'keydown', focusKeydownHandler, this, null, 0 );
487                         } );
488
489                 // Auto-focus logic in dialog.
490                 this.on( 'show', function()
491                         {
492                                 // Setup tabIndex on showing the dialog instead of on loading
493                                 // to allow dynamic tab order happen in dialog definition.
494                                 setupFocus();
495
496                                 if ( editor.config.dialog_startupFocusTab
497                                         && me._.pageCount > 1 )
498                                 {
499                                         me._.tabBarMode = true;
500                                         me._.tabs[ me._.currentTabId ][ 0 ].focus();
501                                 }
502                                 else if ( !this._.hasFocus )
503                                 {
504                                         this._.currentFocusIndex = -1;
505
506                                         // Decide where to put the initial focus.
507                                         if ( definition.onFocus )
508                                         {
509                                                 var initialFocus = definition.onFocus.call( this );
510                                                 // Focus the field that the user specified.
511                                                 initialFocus && initialFocus.focus();
512                                         }
513                                         // Focus the first field in layout order.
514                                         else
515                                                 changeFocus( true );
516
517                                         /*
518                                          * IE BUG: If the initial focus went into a non-text element (e.g. button),
519                                          * then IE would still leave the caret inside the editing area.
520                                          */
521                                         if ( this._.editor.mode == 'wysiwyg' && CKEDITOR.env.ie )
522                                         {
523                                                 var $selection = editor.document.$.selection,
524                                                         $range = $selection.createRange();
525
526                                                 if ( $range )
527                                                 {
528                                                         if ( $range.parentElement && $range.parentElement().ownerDocument == editor.document.$
529                                                           || $range.item && $range.item( 0 ).ownerDocument == editor.document.$ )
530                                                         {
531                                                                 var $myRange = document.body.createTextRange();
532                                                                 $myRange.moveToElementText( this.getElement().getFirst().$ );
533                                                                 $myRange.collapse( true );
534                                                                 $myRange.select();
535                                                         }
536                                                 }
537                                         }
538                                 }
539                         }, this, null, 0xffffffff );
540
541                 // IE6 BUG: Text fields and text areas are only half-rendered the first time the dialog appears in IE6 (#2661).
542                 // This is still needed after [2708] and [2709] because text fields in hidden TR tags are still broken.
543                 if ( CKEDITOR.env.ie6Compat )
544                 {
545                         this.on( 'load', function( evt )
546                                         {
547                                                 var outer = this.getElement(),
548                                                         inner = outer.getFirst();
549                                                 inner.remove();
550                                                 inner.appendTo( outer );
551                                         }, this );
552                 }
553
554                 initDragAndDrop( this );
555                 initResizeHandles( this );
556
557                 // Insert the title.
558                 ( new CKEDITOR.dom.text( definition.title, CKEDITOR.document ) ).appendTo( this.parts.title );
559
560                 // Insert the tabs and contents.
561                 for ( var i = 0 ; i < definition.contents.length ; i++ )
562                 {
563                         var page = definition.contents[i];
564                         page && this.addPage( page );
565                 }
566
567                 this.parts[ 'tabs' ].on( 'click', function( evt )
568                                 {
569                                         var target = evt.data.getTarget();
570                                         // If we aren't inside a tab, bail out.
571                                         if ( target.hasClass( 'cke_dialog_tab' ) )
572                                         {
573                                                 // Get the ID of the tab, without the 'cke_' prefix and the unique number suffix.
574                                                 var id = target.$.id;
575                                                 this.selectPage( id.substring( 4, id.lastIndexOf( '_' ) ) );
576
577                                                 if ( this._.tabBarMode )
578                                                 {
579                                                         this._.tabBarMode = false;
580                                                         this._.currentFocusIndex = -1;
581                                                         changeFocus( true );
582                                                 }
583                                                 evt.data.preventDefault();
584                                         }
585                                 }, this );
586
587                 // Insert buttons.
588                 var buttonsHtml = [],
589                         buttons = CKEDITOR.dialog._.uiElementBuilders.hbox.build( this,
590                                 {
591                                         type : 'hbox',
592                                         className : 'cke_dialog_footer_buttons',
593                                         widths : [],
594                                         children : definition.buttons
595                                 }, buttonsHtml ).getChild();
596                 this.parts.footer.setHtml( buttonsHtml.join( '' ) );
597
598                 for ( i = 0 ; i < buttons.length ; i++ )
599                         this._.buttons[ buttons[i].id ] = buttons[i];
600         };
601
602         // Focusable interface. Use it via dialog.addFocusable.
603         function Focusable( dialog, element, index )
604         {
605                 this.element = element;
606                 this.focusIndex = index;
607                 // TODO: support tabIndex for focusables.
608                 this.tabIndex = 0;
609                 this.isFocusable = function()
610                 {
611                         return !element.getAttribute( 'disabled' ) && element.isVisible();
612                 };
613                 this.focus = function()
614                 {
615                         dialog._.currentFocusIndex = this.focusIndex;
616                         this.element.focus();
617                 };
618                 // Bind events
619                 element.on( 'keydown', function( e )
620                         {
621                                 if ( e.data.getKeystroke() in { 32:1, 13:1 }  )
622                                         this.fire( 'click' );
623                         } );
624                 element.on( 'focus', function()
625                         {
626                                 this.fire( 'mouseover' );
627                         } );
628                 element.on( 'blur', function()
629                         {
630                                 this.fire( 'mouseout' );
631                         } );
632         }
633
634         CKEDITOR.dialog.prototype =
635         {
636                 destroy : function()
637                 {
638                         this.hide();
639                         this._.element.remove();
640                 },
641
642                 /**
643                  * Resizes the dialog.
644                  * @param {Number} width The width of the dialog in pixels.
645                  * @param {Number} height The height of the dialog in pixels.
646                  * @function
647                  * @example
648                  * dialogObj.resize( 800, 640 );
649                  */
650                 resize : (function()
651                 {
652                         return function( width, height )
653                         {
654                                 if ( this._.contentSize && this._.contentSize.width == width && this._.contentSize.height == height )
655                                         return;
656
657                                 CKEDITOR.dialog.fire( 'resize',
658                                         {
659                                                 dialog : this,
660                                                 skin : this._.editor.skinName,
661                                                 width : width,
662                                                 height : height
663                                         }, this._.editor );
664
665                                 this.fire( 'resize',
666                                         {
667                                                 skin : this._.editor.skinName,
668                                                 width : width,
669                                                 height : height
670                                         }, this._.editor );
671
672                                 // Update dialog position when dimension get changed in RTL.
673                                 if ( this._.editor.lang.dir == 'rtl' && this._.position )
674                                         this._.position.x = CKEDITOR.document.getWindow().getViewPaneSize().width -
675                                                 this._.contentSize.width - parseInt( this._.element.getFirst().getStyle( 'right' ), 10 );
676
677                                 this._.contentSize = { width : width, height : height };
678                         };
679                 })(),
680
681                 /**
682                  * Gets the current size of the dialog in pixels.
683                  * @returns {Object} An object with "width" and "height" properties.
684                  * @example
685                  * var width = dialogObj.getSize().width;
686                  */
687                 getSize : function()
688                 {
689                         var element = this._.element.getFirst();
690                         return { width : element.$.offsetWidth || 0, height : element.$.offsetHeight || 0};
691                 },
692
693                 /**
694                  * Moves the dialog to an (x, y) coordinate relative to the window.
695                  * @function
696                  * @param {Number} x The target x-coordinate.
697                  * @param {Number} y The target y-coordinate.
698                  * @param {Boolean} save Flag indicate whether the dialog position should be remembered on next open up.
699                  * @example
700                  * dialogObj.move( 10, 40 );
701                  */
702                 move : (function()
703                 {
704                         var isFixed;
705                         return function( x, y, save )
706                         {
707                                 // The dialog may be fixed positioned or absolute positioned. Ask the
708                                 // browser what is the current situation first.
709                                 var element = this._.element.getFirst(),
710                                         rtl = this._.editor.lang.dir == 'rtl';
711
712                                 if ( isFixed === undefined )
713                                         isFixed = element.getComputedStyle( 'position' ) == 'fixed';
714
715                                 if ( isFixed && this._.position && this._.position.x == x && this._.position.y == y )
716                                         return;
717
718                                 // Save the current position.
719                                 this._.position = { x : x, y : y };
720
721                                 // If not fixed positioned, add scroll position to the coordinates.
722                                 if ( !isFixed )
723                                 {
724                                         var scrollPosition = CKEDITOR.document.getWindow().getScrollPosition();
725                                         x += scrollPosition.x;
726                                         y += scrollPosition.y;
727                                 }
728
729                                 // Translate coordinate for RTL.
730                                 if ( rtl )
731                                 {
732                                         var dialogSize = this.getSize(),
733                                                 viewPaneSize = CKEDITOR.document.getWindow().getViewPaneSize();
734                                         x = viewPaneSize.width - dialogSize.width - x;
735                                 }
736
737                                 var styles = { 'top'    : ( y > 0 ? y : 0 ) + 'px' };
738                                 styles[ rtl ? 'right' : 'left' ] = ( x > 0 ? x : 0 ) + 'px';
739
740                                 element.setStyles( styles );
741
742                                 save && ( this._.moved = 1 );
743                         };
744                 })(),
745
746                 /**
747                  * Gets the dialog's position in the window.
748                  * @returns {Object} An object with "x" and "y" properties.
749                  * @example
750                  * var dialogX = dialogObj.getPosition().x;
751                  */
752                 getPosition : function(){ return CKEDITOR.tools.extend( {}, this._.position ); },
753
754                 /**
755                  * Shows the dialog box.
756                  * @example
757                  * dialogObj.show();
758                  */
759                 show : function()
760                 {
761                         // Insert the dialog's element to the root document.
762                         var element = this._.element;
763                         var definition = this.definition;
764                         if ( !( element.getParent() && element.getParent().equals( CKEDITOR.document.getBody() ) ) )
765                                 element.appendTo( CKEDITOR.document.getBody() );
766                         else
767                                 element.setStyle( 'display', 'block' );
768
769                         // FIREFOX BUG: Fix vanishing caret for Firefox 2 or Gecko 1.8.
770                         if ( CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 )
771                         {
772                                 var dialogElement = this.parts.dialog;
773                                 dialogElement.setStyle( 'position', 'absolute' );
774                                 setTimeout( function()
775                                         {
776                                                 dialogElement.setStyle( 'position', 'fixed' );
777                                         }, 0 );
778                         }
779
780
781                         // First, set the dialog to an appropriate size.
782                         this.resize( this._.contentSize && this._.contentSize.width || definition.width || definition.minWidth,
783                                         this._.contentSize && this._.contentSize.height || definition.height || definition.minHeight );
784
785                         // Reset all inputs back to their default value.
786                         this.reset();
787
788                         // Select the first tab by default.
789                         this.selectPage( this.definition.contents[0].id );
790
791                         // Set z-index.
792                         if ( CKEDITOR.dialog._.currentZIndex === null )
793                                 CKEDITOR.dialog._.currentZIndex = this._.editor.config.baseFloatZIndex;
794                         this._.element.getFirst().setStyle( 'z-index', CKEDITOR.dialog._.currentZIndex += 10 );
795
796                         // Maintain the dialog ordering and dialog cover.
797                         // Also register key handlers if first dialog.
798                         if ( CKEDITOR.dialog._.currentTop === null )
799                         {
800                                 CKEDITOR.dialog._.currentTop = this;
801                                 this._.parentDialog = null;
802                                 showCover( this._.editor );
803
804                                 element.on( 'keydown', accessKeyDownHandler );
805                                 element.on( CKEDITOR.env.opera ? 'keypress' : 'keyup', accessKeyUpHandler );
806
807                                 // Prevent some keys from bubbling up. (#4269)
808                                 for ( var event in { keyup :1, keydown :1, keypress :1 } )
809                                         element.on( event, preventKeyBubbling );
810                         }
811                         else
812                         {
813                                 this._.parentDialog = CKEDITOR.dialog._.currentTop;
814                                 var parentElement = this._.parentDialog.getElement().getFirst();
815                                 parentElement.$.style.zIndex  -= Math.floor( this._.editor.config.baseFloatZIndex / 2 );
816                                 CKEDITOR.dialog._.currentTop = this;
817                         }
818
819                         // Register the Esc hotkeys.
820                         registerAccessKey( this, this, '\x1b', null, function()
821                                         {
822                                                 this.getButton( 'cancel' ) && this.getButton( 'cancel' ).click();
823                                         } );
824
825                         // Reset the hasFocus state.
826                         this._.hasFocus = false;
827
828                         CKEDITOR.tools.setTimeout( function()
829                                 {
830                                         this.layout();
831                                         this.parts.dialog.setStyle( 'visibility', '' );
832
833                                         // Execute onLoad for the first show.
834                                         this.fireOnce( 'load', {} );
835                                         CKEDITOR.ui.fire( 'ready', this );
836
837                                         this.fire( 'show', {} );
838                                         this._.editor.fire( 'dialogShow', this );
839
840                                         // Save the initial values of the dialog.
841                                         this.foreach( function( contentObj ) { contentObj.setInitValue && contentObj.setInitValue(); } );
842
843                                 },
844                                 100, this );
845                 },
846
847                 /**
848                  * Rearrange the dialog to its previous position or the middle of the window.
849                  * @since 3.5
850                  */
851                 layout : function()
852                 {
853                         var viewSize = CKEDITOR.document.getWindow().getViewPaneSize(),
854                                         dialogSize = this.getSize();
855
856                         this.move( this._.moved ? this._.position.x : ( viewSize.width - dialogSize.width ) / 2,
857                                         this._.moved ? this._.position.y : ( viewSize.height - dialogSize.height ) / 2 );
858                 },
859
860                 /**
861                  * Executes a function for each UI element.
862                  * @param {Function} fn Function to execute for each UI element.
863                  * @returns {CKEDITOR.dialog} The current dialog object.
864                  */
865                 foreach : function( fn )
866                 {
867                         for ( var i in this._.contents )
868                         {
869                                 for ( var j in this._.contents[i] )
870                                         fn.call( this, this._.contents[i][j] );
871                         }
872                         return this;
873                 },
874
875                 /**
876                  * Resets all input values in the dialog.
877                  * @example
878                  * dialogObj.reset();
879                  * @returns {CKEDITOR.dialog} The current dialog object.
880                  */
881                 reset : (function()
882                 {
883                         var fn = function( widget ){ if ( widget.reset ) widget.reset( 1 ); };
884                         return function(){ this.foreach( fn ); return this; };
885                 })(),
886
887
888                 /**
889                  * Calls the {@link CKEDITOR.dialog.definition.uiElement#setup} method of each of the UI elements, with the arguments passed through it.
890                  * It is usually being called when the dialog is opened, to put the initial value inside the field.
891                  * @example
892                  * dialogObj.setupContent();
893                  * @example
894                  * var timestamp = ( new Date() ).valueOf();
895                  * dialogObj.setupContent( timestamp );
896                  */
897                 setupContent : function()
898                 {
899                         var args = arguments;
900                         this.foreach( function( widget )
901                                 {
902                                         if ( widget.setup )
903                                                 widget.setup.apply( widget, args );
904                                 });
905                 },
906
907                 /**
908                  * Calls the {@link CKEDITOR.dialog.definition.uiElement#commit} method of each of the UI elements, with the arguments passed through it.
909                  * It is usually being called when the user confirms the dialog, to process the values.
910                  * @example
911                  * dialogObj.commitContent();
912                  * @example
913                  * var timestamp = ( new Date() ).valueOf();
914                  * dialogObj.commitContent( timestamp );
915                  */
916                 commitContent : function()
917                 {
918                         var args = arguments;
919                         this.foreach( function( widget )
920                                 {
921                                         // Make sure IE triggers "change" event on last focused input before closing the dialog. (#7915)
922                                         if ( CKEDITOR.env.ie && this._.currentFocusIndex == widget.focusIndex )
923                                                 widget.getInputElement().$.blur();
924
925                                         if ( widget.commit )
926                                                 widget.commit.apply( widget, args );
927                                 });
928                 },
929
930                 /**
931                  * Hides the dialog box.
932                  * @example
933                  * dialogObj.hide();
934                  */
935                 hide : function()
936                 {
937                         if ( !this.parts.dialog.isVisible() )
938                                 return;
939
940                         this.fire( 'hide', {} );
941                         this._.editor.fire( 'dialogHide', this );
942                         var element = this._.element;
943                         element.setStyle( 'display', 'none' );
944                         this.parts.dialog.setStyle( 'visibility', 'hidden' );
945                         // Unregister all access keys associated with this dialog.
946                         unregisterAccessKey( this );
947
948                         // Close any child(top) dialogs first.
949                         while( CKEDITOR.dialog._.currentTop != this )
950                                 CKEDITOR.dialog._.currentTop.hide();
951
952                         // Maintain dialog ordering and remove cover if needed.
953                         if ( !this._.parentDialog )
954                                 hideCover();
955                         else
956                         {
957                                 var parentElement = this._.parentDialog.getElement().getFirst();
958                                 parentElement.setStyle( 'z-index', parseInt( parentElement.$.style.zIndex, 10 ) + Math.floor( this._.editor.config.baseFloatZIndex / 2 ) );
959                         }
960                         CKEDITOR.dialog._.currentTop = this._.parentDialog;
961
962                         // Deduct or clear the z-index.
963                         if ( !this._.parentDialog )
964                         {
965                                 CKEDITOR.dialog._.currentZIndex = null;
966
967                                 // Remove access key handlers.
968                                 element.removeListener( 'keydown', accessKeyDownHandler );
969                                 element.removeListener( CKEDITOR.env.opera ? 'keypress' : 'keyup', accessKeyUpHandler );
970
971                                 // Remove bubbling-prevention handler. (#4269)
972                                 for ( var event in { keyup :1, keydown :1, keypress :1 } )
973                                         element.removeListener( event, preventKeyBubbling );
974
975                                 var editor = this._.editor;
976                                 editor.focus();
977
978                                 if ( editor.mode == 'wysiwyg' && CKEDITOR.env.ie )
979                                 {
980                                         var selection = editor.getSelection();
981                                         selection && selection.unlock( true );
982                                 }
983                         }
984                         else
985                                 CKEDITOR.dialog._.currentZIndex -= 10;
986
987                         delete this._.parentDialog;
988                         // Reset the initial values of the dialog.
989                         this.foreach( function( contentObj ) { contentObj.resetInitValue && contentObj.resetInitValue(); } );
990                 },
991
992                 /**
993                  * Adds a tabbed page into the dialog.
994                  * @param {Object} contents Content definition.
995                  * @example
996                  */
997                 addPage : function( contents )
998                 {
999                         var pageHtml = [],
1000                                 titleHtml = contents.label ? ' title="' + CKEDITOR.tools.htmlEncode( contents.label ) + '"' : '',
1001                                 elements = contents.elements,
1002                                 vbox = CKEDITOR.dialog._.uiElementBuilders.vbox.build( this,
1003                                                 {
1004                                                         type : 'vbox',
1005                                                         className : 'cke_dialog_page_contents',
1006                                                         children : contents.elements,
1007                                                         expand : !!contents.expand,
1008                                                         padding : contents.padding,
1009                                                         style : contents.style || 'width: 100%;height:100%'
1010                                                 }, pageHtml );
1011
1012                         // Create the HTML for the tab and the content block.
1013                         var page = CKEDITOR.dom.element.createFromHtml( pageHtml.join( '' ) );
1014                         page.setAttribute( 'role', 'tabpanel' );
1015
1016                         var env = CKEDITOR.env;
1017                         var tabId = 'cke_' + contents.id + '_' + CKEDITOR.tools.getNextNumber(),
1018                                  tab = CKEDITOR.dom.element.createFromHtml( [
1019                                         '<a class="cke_dialog_tab"',
1020                                                 ( this._.pageCount > 0 ? ' cke_last' : 'cke_first' ),
1021                                                 titleHtml,
1022                                                 ( !!contents.hidden ? ' style="display:none"' : '' ),
1023                                                 ' id="', tabId, '"',
1024                                                 env.gecko && env.version >= 10900 && !env.hc ? '' : ' href="javascript:void(0)"',
1025                                                 ' tabIndex="-1"',
1026                                                 ' hidefocus="true"',
1027                                                 ' role="tab">',
1028                                                         contents.label,
1029                                         '</a>'
1030                                 ].join( '' ) );
1031
1032                         page.setAttribute( 'aria-labelledby', tabId );
1033
1034                         // Take records for the tabs and elements created.
1035                         this._.tabs[ contents.id ] = [ tab, page ];
1036                         this._.tabIdList.push( contents.id );
1037                         !contents.hidden && this._.pageCount++;
1038                         this._.lastTab = tab;
1039                         this.updateStyle();
1040
1041                         var contentMap = this._.contents[ contents.id ] = {},
1042                                 cursor,
1043                                 children = vbox.getChild();
1044
1045                         while ( ( cursor = children.shift() ) )
1046                         {
1047                                 contentMap[ cursor.id ] = cursor;
1048                                 if ( typeof( cursor.getChild ) == 'function' )
1049                                         children.push.apply( children, cursor.getChild() );
1050                         }
1051
1052                         // Attach the DOM nodes.
1053
1054                         page.setAttribute( 'name', contents.id );
1055                         page.appendTo( this.parts.contents );
1056
1057                         tab.unselectable();
1058                         this.parts.tabs.append( tab );
1059
1060                         // Add access key handlers if access key is defined.
1061                         if ( contents.accessKey )
1062                         {
1063                                 registerAccessKey( this, this, 'CTRL+' + contents.accessKey,
1064                                         tabAccessKeyDown, tabAccessKeyUp );
1065                                 this._.accessKeyMap[ 'CTRL+' + contents.accessKey ] = contents.id;
1066                         }
1067                 },
1068
1069                 /**
1070                  * Activates a tab page in the dialog by its id.
1071                  * @param {String} id The id of the dialog tab to be activated.
1072                  * @example
1073                  * dialogObj.selectPage( 'tab_1' );
1074                  */
1075                 selectPage : function( id )
1076                 {
1077                         if ( this._.currentTabId == id )
1078                                 return;
1079
1080                         // Returning true means that the event has been canceled
1081                         if ( this.fire( 'selectPage', { page : id, currentPage : this._.currentTabId } ) === true )
1082                                 return;
1083
1084                         // Hide the non-selected tabs and pages.
1085                         for ( var i in this._.tabs )
1086                         {
1087                                 var tab = this._.tabs[i][0],
1088                                         page = this._.tabs[i][1];
1089                                 if ( i != id )
1090                                 {
1091                                         tab.removeClass( 'cke_dialog_tab_selected' );
1092                                         page.hide();
1093                                 }
1094                                 page.setAttribute( 'aria-hidden', i != id );
1095                         }
1096
1097                         var selected = this._.tabs[ id ];
1098                         selected[ 0 ].addClass( 'cke_dialog_tab_selected' );
1099
1100                         // [IE] an invisible input[type='text'] will enlarge it's width
1101                         // if it's value is long when it shows, so we clear it's value
1102                         // before it shows and then recover it (#5649)
1103                         if ( CKEDITOR.env.ie6Compat || CKEDITOR.env.ie7Compat )
1104                         {
1105                                 clearOrRecoverTextInputValue( selected[ 1 ] );
1106                                 selected[ 1 ].show();
1107                                 setTimeout( function()
1108                                 {
1109                                         clearOrRecoverTextInputValue( selected[ 1 ], 1 );
1110                                 }, 0 );
1111                         }
1112                         else
1113                                 selected[ 1 ].show();
1114
1115                         this._.currentTabId = id;
1116                         this._.currentTabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, id );
1117                 },
1118
1119                 // Dialog state-specific style updates.
1120                 updateStyle : function()
1121                 {
1122                         // If only a single page shown, a different style is used in the central pane.
1123                         this.parts.dialog[ ( this._.pageCount === 1 ? 'add' : 'remove' ) + 'Class' ]( 'cke_single_page' );
1124                 },
1125
1126                 /**
1127                  * Hides a page's tab away from the dialog.
1128                  * @param {String} id The page's Id.
1129                  * @example
1130                  * dialog.hidePage( 'tab_3' );
1131                  */
1132                 hidePage : function( id )
1133                 {
1134                         var tab = this._.tabs[id] && this._.tabs[id][0];
1135                         if ( !tab || this._.pageCount == 1 || !tab.isVisible() )
1136                                 return;
1137                         // Switch to other tab first when we're hiding the active tab.
1138                         else if ( id == this._.currentTabId )
1139                                 this.selectPage( getPreviousVisibleTab.call( this ) );
1140
1141                         tab.hide();
1142                         this._.pageCount--;
1143                         this.updateStyle();
1144                 },
1145
1146                 /**
1147                  * Unhides a page's tab.
1148                  * @param {String} id The page's Id.
1149                  * @example
1150                  * dialog.showPage( 'tab_2' );
1151                  */
1152                 showPage : function( id )
1153                 {
1154                         var tab = this._.tabs[id] && this._.tabs[id][0];
1155                         if ( !tab )
1156                                 return;
1157                         tab.show();
1158                         this._.pageCount++;
1159                         this.updateStyle();
1160                 },
1161
1162                 /**
1163                  * Gets the root DOM element of the dialog.
1164                  * @returns {CKEDITOR.dom.element} The &lt;span&gt; element containing this dialog.
1165                  * @example
1166                  * var dialogElement = dialogObj.getElement().getFirst();
1167                  * dialogElement.setStyle( 'padding', '5px' );
1168                  */
1169                 getElement : function()
1170                 {
1171                         return this._.element;
1172                 },
1173
1174                 /**
1175                  * Gets the name of the dialog.
1176                  * @returns {String} The name of this dialog.
1177                  * @example
1178                  * var dialogName = dialogObj.getName();
1179                  */
1180                 getName : function()
1181                 {
1182                         return this._.name;
1183                 },
1184
1185                 /**
1186                  * Gets a dialog UI element object from a dialog page.
1187                  * @param {String} pageId id of dialog page.
1188                  * @param {String} elementId id of UI element.
1189                  * @example
1190                  * dialogObj.getContentElement( 'tabId', 'elementId' ).setValue( 'Example' );
1191                  * @returns {CKEDITOR.ui.dialog.uiElement} The dialog UI element.
1192                  */
1193                 getContentElement : function( pageId, elementId )
1194                 {
1195                         var page = this._.contents[ pageId ];
1196                         return page && page[ elementId ];
1197                 },
1198
1199                 /**
1200                  * Gets the value of a dialog UI element.
1201                  * @param {String} pageId id of dialog page.
1202                  * @param {String} elementId id of UI element.
1203                  * @example
1204                  * alert( dialogObj.getValueOf( 'tabId', 'elementId' ) );
1205                  * @returns {Object} The value of the UI element.
1206                  */
1207                 getValueOf : function( pageId, elementId )
1208                 {
1209                         return this.getContentElement( pageId, elementId ).getValue();
1210                 },
1211
1212                 /**
1213                  * Sets the value of a dialog UI element.
1214                  * @param {String} pageId id of the dialog page.
1215                  * @param {String} elementId id of the UI element.
1216                  * @param {Object} value The new value of the UI element.
1217                  * @example
1218                  * dialogObj.setValueOf( 'tabId', 'elementId', 'Example' );
1219                  */
1220                 setValueOf : function( pageId, elementId, value )
1221                 {
1222                         return this.getContentElement( pageId, elementId ).setValue( value );
1223                 },
1224
1225                 /**
1226                  * Gets the UI element of a button in the dialog's button row.
1227                  * @param {String} id The id of the button.
1228                  * @example
1229                  * @returns {CKEDITOR.ui.dialog.button} The button object.
1230                  */
1231                 getButton : function( id )
1232                 {
1233                         return this._.buttons[ id ];
1234                 },
1235
1236                 /**
1237                  * Simulates a click to a dialog button in the dialog's button row.
1238                  * @param {String} id The id of the button.
1239                  * @example
1240                  * @returns The return value of the dialog's "click" event.
1241                  */
1242                 click : function( id )
1243                 {
1244                         return this._.buttons[ id ].click();
1245                 },
1246
1247                 /**
1248                  * Disables a dialog button.
1249                  * @param {String} id The id of the button.
1250                  * @example
1251                  */
1252                 disableButton : function( id )
1253                 {
1254                         return this._.buttons[ id ].disable();
1255                 },
1256
1257                 /**
1258                  * Enables a dialog button.
1259                  * @param {String} id The id of the button.
1260                  * @example
1261                  */
1262                 enableButton : function( id )
1263                 {
1264                         return this._.buttons[ id ].enable();
1265                 },
1266
1267                 /**
1268                  * Gets the number of pages in the dialog.
1269                  * @returns {Number} Page count.
1270                  */
1271                 getPageCount : function()
1272                 {
1273                         return this._.pageCount;
1274                 },
1275
1276                 /**
1277                  * Gets the editor instance which opened this dialog.
1278                  * @returns {CKEDITOR.editor} Parent editor instances.
1279                  */
1280                 getParentEditor : function()
1281                 {
1282                         return this._.editor;
1283                 },
1284
1285                 /**
1286                  * Gets the element that was selected when opening the dialog, if any.
1287                  * @returns {CKEDITOR.dom.element} The element that was selected, or null.
1288                  */
1289                 getSelectedElement : function()
1290                 {
1291                         return this.getParentEditor().getSelection().getSelectedElement();
1292                 },
1293
1294                 /**
1295                  * Adds element to dialog's focusable list.
1296                  *
1297                  * @param {CKEDITOR.dom.element} element
1298                  * @param {Number} [index]
1299                  */
1300                 addFocusable: function( element, index ) {
1301                         if ( typeof index == 'undefined' )
1302                         {
1303                                 index = this._.focusList.length;
1304                                 this._.focusList.push( new Focusable( this, element, index ) );
1305                         }
1306                         else
1307                         {
1308                                 this._.focusList.splice( index, 0, new Focusable( this, element, index ) );
1309                                 for ( var i = index + 1 ; i < this._.focusList.length ; i++ )
1310                                         this._.focusList[ i ].focusIndex++;
1311                         }
1312                 }
1313         };
1314
1315         CKEDITOR.tools.extend( CKEDITOR.dialog,
1316                 /**
1317                  * @lends CKEDITOR.dialog
1318                  */
1319                 {
1320                         /**
1321                          * Registers a dialog.
1322                          * @param {String} name The dialog's name.
1323                          * @param {Function|String} dialogDefinition
1324                          * A function returning the dialog's definition, or the URL to the .js file holding the function.
1325                          * The function should accept an argument "editor" which is the current editor instance, and
1326                          * return an object conforming to {@link CKEDITOR.dialog.definition}.
1327                          * @see CKEDITOR.dialog.definition
1328                          * @example
1329                          * // Full sample plugin, which does not only register a dialog window but also adds an item to the context menu.
1330                          * // To open the dialog window, choose "Open dialog" in the context menu.
1331                          * CKEDITOR.plugins.add( 'myplugin',
1332                          * {
1333                          *      init: function( editor )
1334                          *      {
1335                          *              editor.addCommand( 'mydialog',new CKEDITOR.dialogCommand( 'mydialog' ) );
1336                          *
1337                          *              if ( editor.contextMenu )
1338                          *              {
1339                          *                      editor.addMenuGroup( 'mygroup', 10 );
1340                          *                      editor.addMenuItem( 'My Dialog',
1341                          *                      {
1342                          *                              label : 'Open dialog',
1343                          *                              command : 'mydialog',
1344                          *                              group : 'mygroup'
1345                          *                      });
1346                          *                      editor.contextMenu.addListener( function( element )
1347                          *                      {
1348                          *                              return { 'My Dialog' : CKEDITOR.TRISTATE_OFF };
1349                          *                      });
1350                          *              }
1351                          *
1352                          *              <strong>CKEDITOR.dialog.add</strong>( 'mydialog', function( api )
1353                          *              {
1354                          *                      // CKEDITOR.dialog.definition
1355                          *                      var <strong>dialogDefinition</strong> =
1356                          *                      {
1357                          *                              title : 'Sample dialog',
1358                          *                              minWidth : 390,
1359                          *                              minHeight : 130,
1360                          *                              contents : [
1361                          *                                      {
1362                          *                                              id : 'tab1',
1363                          *                                              label : 'Label',
1364                          *                                              title : 'Title',
1365                          *                                              expand : true,
1366                          *                                              padding : 0,
1367                          *                                              elements :
1368                          *                                              [
1369                          *                                                      {
1370                          *                                                              type : 'html',
1371                          *                                                              html : '&lt;p&gt;This is some sample HTML content.&lt;/p&gt;'
1372                          *                                                      },
1373                          *                                                      {
1374                          *                                                              type : 'textarea',
1375                          *                                                              id : 'textareaId',
1376                          *                                                              rows : 4,
1377                          *                                                              cols : 40
1378                          *                                                      }
1379                          *                                              ]
1380                          *                                      }
1381                          *                              ],
1382                          *                              buttons : [ CKEDITOR.dialog.okButton, CKEDITOR.dialog.cancelButton ],
1383                          *                              onOk : function() {
1384                          *                                      // "this" is now a CKEDITOR.dialog object.
1385                          *                                      // Accessing dialog elements:
1386                          *                                      var textareaObj = this.<strong>getContentElement</strong>( 'tab1', 'textareaId' );
1387                          *                                      alert( "You have entered: " + textareaObj.getValue() );
1388                          *                              }
1389                          *                      };
1390                          *
1391                          *                      return dialogDefinition;
1392                          *              } );
1393                          *      }
1394                          * } );
1395                          *
1396                          * CKEDITOR.replace( 'editor1', { extraPlugins : 'myplugin' } );
1397                          */
1398                         add : function( name, dialogDefinition )
1399                         {
1400                                 // Avoid path registration from multiple instances override definition.
1401                                 if ( !this._.dialogDefinitions[name]
1402                                         || typeof  dialogDefinition == 'function' )
1403                                         this._.dialogDefinitions[name] = dialogDefinition;
1404                         },
1405
1406                         exists : function( name )
1407                         {
1408                                 return !!this._.dialogDefinitions[ name ];
1409                         },
1410
1411                         getCurrent : function()
1412                         {
1413                                 return CKEDITOR.dialog._.currentTop;
1414                         },
1415
1416                         /**
1417                          * The default OK button for dialogs. Fires the "ok" event and closes the dialog if the event succeeds.
1418                          * @static
1419                          * @field
1420                          * @example
1421                          * @type Function
1422                          */
1423                         okButton : (function()
1424                         {
1425                                 var retval = function( editor, override )
1426                                 {
1427                                         override = override || {};
1428                                         return CKEDITOR.tools.extend( {
1429                                                 id : 'ok',
1430                                                 type : 'button',
1431                                                 label : editor.lang.common.ok,
1432                                                 'class' : 'cke_dialog_ui_button_ok',
1433                                                 onClick : function( evt )
1434                                                 {
1435                                                         var dialog = evt.data.dialog;
1436                                                         if ( dialog.fire( 'ok', { hide : true } ).hide !== false )
1437                                                                 dialog.hide();
1438                                                 }
1439                                         }, override, true );
1440                                 };
1441                                 retval.type = 'button';
1442                                 retval.override = function( override )
1443                                 {
1444                                         return CKEDITOR.tools.extend( function( editor ){ return retval( editor, override ); },
1445                                                         { type : 'button' }, true );
1446                                 };
1447                                 return retval;
1448                         })(),
1449
1450                         /**
1451                          * The default cancel button for dialogs. Fires the "cancel" event and closes the dialog if no UI element value changed.
1452                          * @static
1453                          * @field
1454                          * @example
1455                          * @type Function
1456                          */
1457                         cancelButton : (function()
1458                         {
1459                                 var retval = function( editor, override )
1460                                 {
1461                                         override = override || {};
1462                                         return CKEDITOR.tools.extend( {
1463                                                 id : 'cancel',
1464                                                 type : 'button',
1465                                                 label : editor.lang.common.cancel,
1466                                                 'class' : 'cke_dialog_ui_button_cancel',
1467                                                 onClick : function( evt )
1468                                                 {
1469                                                         var dialog = evt.data.dialog;
1470                                                         if ( dialog.fire( 'cancel', { hide : true } ).hide !== false )
1471                                                                 dialog.hide();
1472                                                 }
1473                                         }, override, true );
1474                                 };
1475                                 retval.type = 'button';
1476                                 retval.override = function( override )
1477                                 {
1478                                         return CKEDITOR.tools.extend( function( editor ){ return retval( editor, override ); },
1479                                                         { type : 'button' }, true );
1480                                 };
1481                                 return retval;
1482                         })(),
1483
1484                         /**
1485                          * Registers a dialog UI element.
1486                          * @param {String} typeName The name of the UI element.
1487                          * @param {Function} builder The function to build the UI element.
1488                          * @example
1489                          */
1490                         addUIElement : function( typeName, builder )
1491                         {
1492                                 this._.uiElementBuilders[ typeName ] = builder;
1493                         }
1494                 });
1495
1496         CKEDITOR.dialog._ =
1497         {
1498                 uiElementBuilders : {},
1499
1500                 dialogDefinitions : {},
1501
1502                 currentTop : null,
1503
1504                 currentZIndex : null
1505         };
1506
1507         // "Inherit" (copy actually) from CKEDITOR.event.
1508         CKEDITOR.event.implementOn( CKEDITOR.dialog );
1509         CKEDITOR.event.implementOn( CKEDITOR.dialog.prototype, true );
1510
1511         var defaultDialogDefinition =
1512         {
1513                 resizable : CKEDITOR.DIALOG_RESIZE_BOTH,
1514                 minWidth : 600,
1515                 minHeight : 400,
1516                 buttons : [ CKEDITOR.dialog.okButton, CKEDITOR.dialog.cancelButton ]
1517         };
1518
1519         // Tool function used to return an item from an array based on its id
1520         // property.
1521         var getById = function( array, id, recurse )
1522         {
1523                 for ( var i = 0, item ; ( item = array[ i ] ) ; i++ )
1524                 {
1525                         if ( item.id == id )
1526                                 return item;
1527                         if ( recurse && item[ recurse ] )
1528                         {
1529                                 var retval = getById( item[ recurse ], id, recurse ) ;
1530                                 if ( retval )
1531                                         return retval;
1532                         }
1533                 }
1534                 return null;
1535         };
1536
1537         // Tool function used to add an item into an array.
1538         var addById = function( array, newItem, nextSiblingId, recurse, nullIfNotFound )
1539         {
1540                 if ( nextSiblingId )
1541                 {
1542                         for ( var i = 0, item ; ( item = array[ i ] ) ; i++ )
1543                         {
1544                                 if ( item.id == nextSiblingId )
1545                                 {
1546                                         array.splice( i, 0, newItem );
1547                                         return newItem;
1548                                 }
1549
1550                                 if ( recurse && item[ recurse ] )
1551                                 {
1552                                         var retval = addById( item[ recurse ], newItem, nextSiblingId, recurse, true );
1553                                         if ( retval )
1554                                                 return retval;
1555                                 }
1556                         }
1557
1558                         if ( nullIfNotFound )
1559                                 return null;
1560                 }
1561
1562                 array.push( newItem );
1563                 return newItem;
1564         };
1565
1566         // Tool function used to remove an item from an array based on its id.
1567         var removeById = function( array, id, recurse )
1568         {
1569                 for ( var i = 0, item ; ( item = array[ i ] ) ; i++ )
1570                 {
1571                         if ( item.id == id )
1572                                 return array.splice( i, 1 );
1573                         if ( recurse && item[ recurse ] )
1574                         {
1575                                 var retval = removeById( item[ recurse ], id, recurse );
1576                                 if ( retval )
1577                                         return retval;
1578                         }
1579                 }
1580                 return null;
1581         };
1582
1583         /**
1584          * This class is not really part of the API. It is the "definition" property value
1585          * passed to "dialogDefinition" event handlers.
1586          * @constructor
1587          * @name CKEDITOR.dialog.definitionObject
1588          * @extends CKEDITOR.dialog.definition
1589          * @example
1590          * CKEDITOR.on( 'dialogDefinition', function( evt )
1591          *      {
1592          *              var definition = evt.data.definition;
1593          *              var content = definition.getContents( 'page1' );
1594          *              ...
1595          *      } );
1596          */
1597         var definitionObject = function( dialog, dialogDefinition )
1598         {
1599                 // TODO : Check if needed.
1600                 this.dialog = dialog;
1601
1602                 // Transform the contents entries in contentObjects.
1603                 var contents = dialogDefinition.contents;
1604                 for ( var i = 0, content ; ( content = contents[i] ) ; i++ )
1605                         contents[ i ] = content && new contentObject( dialog, content );
1606
1607                 CKEDITOR.tools.extend( this, dialogDefinition );
1608         };
1609
1610         definitionObject.prototype =
1611         /** @lends CKEDITOR.dialog.definitionObject.prototype */
1612         {
1613                 /**
1614                  * Gets a content definition.
1615                  * @param {String} id The id of the content definition.
1616                  * @returns {CKEDITOR.dialog.definition.content} The content definition
1617                  *              matching id.
1618                  */
1619                 getContents : function( id )
1620                 {
1621                         return getById( this.contents, id );
1622                 },
1623
1624                 /**
1625                  * Gets a button definition.
1626                  * @param {String} id The id of the button definition.
1627                  * @returns {CKEDITOR.dialog.definition.button} The button definition
1628                  *              matching id.
1629                  */
1630                 getButton : function( id )
1631                 {
1632                         return getById( this.buttons, id );
1633                 },
1634
1635                 /**
1636                  * Adds a content definition object under this dialog definition.
1637                  * @param {CKEDITOR.dialog.definition.content} contentDefinition The
1638                  *              content definition.
1639                  * @param {String} [nextSiblingId] The id of an existing content
1640                  *              definition which the new content definition will be inserted
1641                  *              before. Omit if the new content definition is to be inserted as
1642                  *              the last item.
1643                  * @returns {CKEDITOR.dialog.definition.content} The inserted content
1644                  *              definition.
1645                  */
1646                 addContents : function( contentDefinition, nextSiblingId )
1647                 {
1648                         return addById( this.contents, contentDefinition, nextSiblingId );
1649                 },
1650
1651                 /**
1652                  * Adds a button definition object under this dialog definition.
1653                  * @param {CKEDITOR.dialog.definition.button} buttonDefinition The
1654                  *              button definition.
1655                  * @param {String} [nextSiblingId] The id of an existing button
1656                  *              definition which the new button definition will be inserted
1657                  *              before. Omit if the new button definition is to be inserted as
1658                  *              the last item.
1659                  * @returns {CKEDITOR.dialog.definition.button} The inserted button
1660                  *              definition.
1661                  */
1662                 addButton : function( buttonDefinition, nextSiblingId )
1663                 {
1664                         return addById( this.buttons, buttonDefinition, nextSiblingId );
1665                 },
1666
1667                 /**
1668                  * Removes a content definition from this dialog definition.
1669                  * @param {String} id The id of the content definition to be removed.
1670                  * @returns {CKEDITOR.dialog.definition.content} The removed content
1671                  *              definition.
1672                  */
1673                 removeContents : function( id )
1674                 {
1675                         removeById( this.contents, id );
1676                 },
1677
1678                 /**
1679                  * Removes a button definition from the dialog definition.
1680                  * @param {String} id The id of the button definition to be removed.
1681                  * @returns {CKEDITOR.dialog.definition.button} The removed button
1682                  *              definition.
1683                  */
1684                 removeButton : function( id )
1685                 {
1686                         removeById( this.buttons, id );
1687                 }
1688         };
1689
1690         /**
1691          * This class is not really part of the API. It is the template of the
1692          * objects representing content pages inside the
1693          * CKEDITOR.dialog.definitionObject.
1694          * @constructor
1695          * @name CKEDITOR.dialog.definition.contentObject
1696          * @example
1697          * CKEDITOR.on( 'dialogDefinition', function( evt )
1698          *      {
1699          *              var definition = evt.data.definition;
1700          *              var content = definition.getContents( 'page1' );
1701          *              content.remove( 'textInput1' );
1702          *              ...
1703          *      } );
1704          */
1705         function contentObject( dialog, contentDefinition )
1706         {
1707                 this._ =
1708                 {
1709                         dialog : dialog
1710                 };
1711
1712                 CKEDITOR.tools.extend( this, contentDefinition );
1713         }
1714
1715         contentObject.prototype =
1716         /** @lends CKEDITOR.dialog.definition.contentObject.prototype */
1717         {
1718                 /**
1719                  * Gets a UI element definition under the content definition.
1720                  * @param {String} id The id of the UI element definition.
1721                  * @returns {CKEDITOR.dialog.definition.uiElement}
1722                  */
1723                 get : function( id )
1724                 {
1725                         return getById( this.elements, id, 'children' );
1726                 },
1727
1728                 /**
1729                  * Adds a UI element definition to the content definition.
1730                  * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition The
1731                  *              UI elemnet definition to be added.
1732                  * @param {String} nextSiblingId The id of an existing UI element
1733                  *              definition which the new UI element definition will be inserted
1734                  *              before. Omit if the new button definition is to be inserted as
1735                  *              the last item.
1736                  * @returns {CKEDITOR.dialog.definition.uiElement} The element
1737                  *              definition inserted.
1738                  */
1739                 add : function( elementDefinition, nextSiblingId )
1740                 {
1741                         return addById( this.elements, elementDefinition, nextSiblingId, 'children' );
1742                 },
1743
1744                 /**
1745                  * Removes a UI element definition from the content definition.
1746                  * @param {String} id The id of the UI element definition to be
1747                  *              removed.
1748                  * @returns {CKEDITOR.dialog.definition.uiElement} The element
1749                  *              definition removed.
1750                  * @example
1751                  */
1752                 remove : function( id )
1753                 {
1754                         removeById( this.elements, id, 'children' );
1755                 }
1756         };
1757
1758         function initDragAndDrop( dialog )
1759         {
1760                 var lastCoords = null,
1761                         abstractDialogCoords = null,
1762                         element = dialog.getElement().getFirst(),
1763                         editor = dialog.getParentEditor(),
1764                         magnetDistance = editor.config.dialog_magnetDistance,
1765                         margins = editor.skin.margins || [ 0, 0, 0, 0 ];
1766
1767                 if ( typeof magnetDistance == 'undefined' )
1768                         magnetDistance = 20;
1769
1770                 function mouseMoveHandler( evt )
1771                 {
1772                         var dialogSize = dialog.getSize(),
1773                                 viewPaneSize = CKEDITOR.document.getWindow().getViewPaneSize(),
1774                                 x = evt.data.$.screenX,
1775                                 y = evt.data.$.screenY,
1776                                 dx = x - lastCoords.x,
1777                                 dy = y - lastCoords.y,
1778                                 realX, realY;
1779
1780                         lastCoords = { x : x, y : y };
1781                         abstractDialogCoords.x += dx;
1782                         abstractDialogCoords.y += dy;
1783
1784                         if ( abstractDialogCoords.x + margins[3] < magnetDistance )
1785                                 realX = - margins[3];
1786                         else if ( abstractDialogCoords.x - margins[1] > viewPaneSize.width - dialogSize.width - magnetDistance )
1787                                 realX = viewPaneSize.width - dialogSize.width + ( editor.lang.dir == 'rtl' ? 0 : margins[1] );
1788                         else
1789                                 realX = abstractDialogCoords.x;
1790
1791                         if ( abstractDialogCoords.y + margins[0] < magnetDistance )
1792                                 realY = - margins[0];
1793                         else if ( abstractDialogCoords.y - margins[2] > viewPaneSize.height - dialogSize.height - magnetDistance )
1794                                 realY = viewPaneSize.height - dialogSize.height + margins[2];
1795                         else
1796                                 realY = abstractDialogCoords.y;
1797
1798                         dialog.move( realX, realY, 1 );
1799
1800                         evt.data.preventDefault();
1801                 }
1802
1803                 function mouseUpHandler( evt )
1804                 {
1805                         CKEDITOR.document.removeListener( 'mousemove', mouseMoveHandler );
1806                         CKEDITOR.document.removeListener( 'mouseup', mouseUpHandler );
1807
1808                         if ( CKEDITOR.env.ie6Compat )
1809                         {
1810                                 var coverDoc = currentCover.getChild( 0 ).getFrameDocument();
1811                                 coverDoc.removeListener( 'mousemove', mouseMoveHandler );
1812                                 coverDoc.removeListener( 'mouseup', mouseUpHandler );
1813                         }
1814                 }
1815
1816                 dialog.parts.title.on( 'mousedown', function( evt )
1817                         {
1818                                 lastCoords = { x : evt.data.$.screenX, y : evt.data.$.screenY };
1819
1820                                 CKEDITOR.document.on( 'mousemove', mouseMoveHandler );
1821                                 CKEDITOR.document.on( 'mouseup', mouseUpHandler );
1822                                 abstractDialogCoords = dialog.getPosition();
1823
1824                                 if ( CKEDITOR.env.ie6Compat )
1825                                 {
1826                                         var coverDoc = currentCover.getChild( 0 ).getFrameDocument();
1827                                         coverDoc.on( 'mousemove', mouseMoveHandler );
1828                                         coverDoc.on( 'mouseup', mouseUpHandler );
1829                                 }
1830
1831                                 evt.data.preventDefault();
1832                         }, dialog );
1833         }
1834
1835         function initResizeHandles( dialog )
1836         {
1837                 var def = dialog.definition,
1838                         resizable = def.resizable;
1839
1840                 if ( resizable == CKEDITOR.DIALOG_RESIZE_NONE )
1841                         return;
1842
1843                 var editor = dialog.getParentEditor();
1844                 var wrapperWidth, wrapperHeight,
1845                                 viewSize, origin, startSize,
1846                                 dialogCover;
1847
1848                 var mouseDownFn = CKEDITOR.tools.addFunction( function( $event )
1849                 {
1850                         startSize = dialog.getSize();
1851
1852                         var content = dialog.parts.contents,
1853                                 iframeDialog = content.$.getElementsByTagName( 'iframe' ).length;
1854
1855                         // Shim to help capturing "mousemove" over iframe.
1856                         if ( iframeDialog )
1857                         {
1858                                 dialogCover = CKEDITOR.dom.element.createFromHtml( '<div class="cke_dialog_resize_cover" style="height: 100%; position: absolute; width: 100%;"></div>' );
1859                                 content.append( dialogCover );
1860                         }
1861
1862                         // Calculate the offset between content and chrome size.
1863                         wrapperHeight = startSize.height - dialog.parts.contents.getSize( 'height',  ! ( CKEDITOR.env.gecko || CKEDITOR.env.opera || CKEDITOR.env.ie && CKEDITOR.env.quirks ) );
1864                         wrapperWidth = startSize.width - dialog.parts.contents.getSize( 'width', 1 );
1865
1866                         origin = { x : $event.screenX, y : $event.screenY };
1867
1868                         viewSize = CKEDITOR.document.getWindow().getViewPaneSize();
1869
1870                         CKEDITOR.document.on( 'mousemove', mouseMoveHandler );
1871                         CKEDITOR.document.on( 'mouseup', mouseUpHandler );
1872
1873                         if ( CKEDITOR.env.ie6Compat )
1874                         {
1875                                 var coverDoc = currentCover.getChild( 0 ).getFrameDocument();
1876                                 coverDoc.on( 'mousemove', mouseMoveHandler );
1877                                 coverDoc.on( 'mouseup', mouseUpHandler );
1878                         }
1879
1880                         $event.preventDefault && $event.preventDefault();
1881                 });
1882
1883                 // Prepend the grip to the dialog.
1884                 dialog.on( 'load', function()
1885                 {
1886                         var direction = '';
1887                         if ( resizable == CKEDITOR.DIALOG_RESIZE_WIDTH )
1888                                 direction = ' cke_resizer_horizontal';
1889                         else if ( resizable == CKEDITOR.DIALOG_RESIZE_HEIGHT )
1890                                 direction = ' cke_resizer_vertical';
1891                         var resizer = CKEDITOR.dom.element.createFromHtml( '<div' +
1892                                         ' class="cke_resizer' + direction + ' cke_resizer_' + editor.lang.dir + '"' +
1893                                         ' title="' + CKEDITOR.tools.htmlEncode( editor.lang.resize ) + '"' +
1894                                         ' onmousedown="CKEDITOR.tools.callFunction(' + mouseDownFn + ', event )"></div>' );
1895                         dialog.parts.footer.append( resizer, 1 );
1896                 });
1897                 editor.on( 'destroy', function() { CKEDITOR.tools.removeFunction( mouseDownFn ); } );
1898
1899                 function mouseMoveHandler( evt )
1900                 {
1901                         var rtl = editor.lang.dir == 'rtl',
1902                                 dx = ( evt.data.$.screenX - origin.x ) * ( rtl ? -1 : 1 ),
1903                                 dy = evt.data.$.screenY - origin.y,
1904                                 width = startSize.width,
1905                                 height = startSize.height,
1906                                 internalWidth = width + dx * ( dialog._.moved ? 1 : 2 ),
1907                                 internalHeight = height + dy * ( dialog._.moved ? 1 : 2 ),
1908                                 element = dialog._.element.getFirst(),
1909                                 right = rtl && element.getComputedStyle( 'right' ),
1910                                 position = dialog.getPosition();
1911
1912                         if ( position.y + internalHeight > viewSize.height )
1913                                 internalHeight = viewSize.height - position.y;
1914
1915                         if ( ( rtl ? right : position.x ) + internalWidth > viewSize.width )
1916                                 internalWidth = viewSize.width - ( rtl ? right : position.x );
1917
1918                         // Make sure the dialog will not be resized to the wrong side when it's in the leftmost position for RTL.
1919                         if ( ( resizable == CKEDITOR.DIALOG_RESIZE_WIDTH || resizable == CKEDITOR.DIALOG_RESIZE_BOTH ) )
1920                                 width = Math.max( def.minWidth || 0, internalWidth - wrapperWidth );
1921
1922                         if ( resizable == CKEDITOR.DIALOG_RESIZE_HEIGHT || resizable == CKEDITOR.DIALOG_RESIZE_BOTH )
1923                                 height = Math.max( def.minHeight || 0, internalHeight - wrapperHeight );
1924
1925                         dialog.resize( width, height );
1926
1927                         if ( !dialog._.moved )
1928                                 dialog.layout();
1929
1930                         evt.data.preventDefault();
1931                 }
1932
1933                 function mouseUpHandler()
1934                 {
1935                         CKEDITOR.document.removeListener( 'mouseup', mouseUpHandler );
1936                         CKEDITOR.document.removeListener( 'mousemove', mouseMoveHandler );
1937
1938                         if ( dialogCover )
1939                         {
1940                                 dialogCover.remove();
1941                                 dialogCover = null;
1942                         }
1943
1944                         if ( CKEDITOR.env.ie6Compat )
1945                         {
1946                                 var coverDoc = currentCover.getChild( 0 ).getFrameDocument();
1947                                 coverDoc.removeListener( 'mouseup', mouseUpHandler );
1948                                 coverDoc.removeListener( 'mousemove', mouseMoveHandler );
1949                         }
1950                 }
1951         }
1952
1953         var resizeCover;
1954         // Caching resuable covers and allowing only one cover
1955         // on screen.
1956         var covers = {},
1957                 currentCover;
1958
1959         function cancelEvent( ev )
1960         {
1961                 ev.data.preventDefault(1);
1962         }
1963
1964         function showCover( editor )
1965         {
1966                 var win = CKEDITOR.document.getWindow();
1967                 var config = editor.config,
1968                         backgroundColorStyle = config.dialog_backgroundCoverColor || 'white',
1969                         backgroundCoverOpacity = config.dialog_backgroundCoverOpacity,
1970                         baseFloatZIndex = config.baseFloatZIndex,
1971                         coverKey = CKEDITOR.tools.genKey(
1972                                         backgroundColorStyle,
1973                                         backgroundCoverOpacity,
1974                                         baseFloatZIndex ),
1975                         coverElement = covers[ coverKey ];
1976
1977                 if ( !coverElement )
1978                 {
1979                         var html = [
1980                                         '<div tabIndex="-1" style="position: ', ( CKEDITOR.env.ie6Compat ? 'absolute' : 'fixed' ),
1981                                         '; z-index: ', baseFloatZIndex,
1982                                         '; top: 0px; left: 0px; ',
1983                                         ( !CKEDITOR.env.ie6Compat ? 'background-color: ' + backgroundColorStyle : '' ),
1984                                         '" class="cke_dialog_background_cover">'
1985                                 ];
1986
1987                         if ( CKEDITOR.env.ie6Compat )
1988                         {
1989                                 // Support for custom document.domain in IE.
1990                                 var isCustomDomain = CKEDITOR.env.isCustomDomain(),
1991                                         iframeHtml = '<html><body style=\\\'background-color:' + backgroundColorStyle + ';\\\'></body></html>';
1992
1993                                 html.push(
1994                                         '<iframe' +
1995                                                 ' hidefocus="true"' +
1996                                                 ' frameborder="0"' +
1997                                                 ' id="cke_dialog_background_iframe"' +
1998                                                 ' src="javascript:' );
1999
2000                                 html.push( 'void((function(){' +
2001                                                                 'document.open();' +
2002                                                                 ( isCustomDomain ? 'document.domain=\'' + document.domain + '\';' : '' ) +
2003                                                                 'document.write( \'' + iframeHtml + '\' );' +
2004                                                                 'document.close();' +
2005                                                         '})())' );
2006
2007                                 html.push(
2008                                                 '"' +
2009                                                 ' style="' +
2010                                                         'position:absolute;' +
2011                                                         'left:0;' +
2012                                                         'top:0;' +
2013                                                         'width:100%;' +
2014                                                         'height: 100%;' +
2015                                                         'progid:DXImageTransform.Microsoft.Alpha(opacity=0)">' +
2016                                         '</iframe>' );
2017                         }
2018
2019                         html.push( '</div>' );
2020
2021                         coverElement = CKEDITOR.dom.element.createFromHtml( html.join( '' ) );
2022                         coverElement.setOpacity( backgroundCoverOpacity != undefined ? backgroundCoverOpacity : 0.5 );
2023
2024                         coverElement.on( 'keydown', cancelEvent );
2025                         coverElement.on( 'keypress', cancelEvent );
2026                         coverElement.on( 'keyup', cancelEvent );
2027
2028                         coverElement.appendTo( CKEDITOR.document.getBody() );
2029                         covers[ coverKey ] = coverElement;
2030                 }
2031                 else
2032                         coverElement.   show();
2033
2034                 currentCover = coverElement;
2035                 var resizeFunc = function()
2036                 {
2037                         var size = win.getViewPaneSize();
2038                         coverElement.setStyles(
2039                                 {
2040                                         width : size.width + 'px',
2041                                         height : size.height + 'px'
2042                                 } );
2043                 };
2044
2045                 var scrollFunc = function()
2046                 {
2047                         var pos = win.getScrollPosition(),
2048                                 cursor = CKEDITOR.dialog._.currentTop;
2049                         coverElement.setStyles(
2050                                         {
2051                                                 left : pos.x + 'px',
2052                                                 top : pos.y + 'px'
2053                                         });
2054
2055                         if ( cursor )
2056                         {
2057                                 do
2058                                 {
2059                                         var dialogPos = cursor.getPosition();
2060                                         cursor.move( dialogPos.x, dialogPos.y );
2061                                 } while ( ( cursor = cursor._.parentDialog ) );
2062                         }
2063                 };
2064
2065                 resizeCover = resizeFunc;
2066                 win.on( 'resize', resizeFunc );
2067                 resizeFunc();
2068                 // Using Safari/Mac, focus must be kept where it is (#7027)
2069                 if ( !( CKEDITOR.env.mac && CKEDITOR.env.webkit ) )
2070                         coverElement.focus();
2071
2072                 if ( CKEDITOR.env.ie6Compat )
2073                 {
2074                         // IE BUG: win.$.onscroll assignment doesn't work.. it must be window.onscroll.
2075                         // So we need to invent a really funny way to make it work.
2076                         var myScrollHandler = function()
2077                                 {
2078                                         scrollFunc();
2079                                         arguments.callee.prevScrollHandler.apply( this, arguments );
2080                                 };
2081                         win.$.setTimeout( function()
2082                                 {
2083                                         myScrollHandler.prevScrollHandler = window.onscroll || function(){};
2084                                         window.onscroll = myScrollHandler;
2085                                 }, 0 );
2086                         scrollFunc();
2087                 }
2088         }
2089
2090         function hideCover()
2091         {
2092                 if ( !currentCover )
2093                         return;
2094
2095                 var win = CKEDITOR.document.getWindow();
2096                 currentCover.hide();
2097                 win.removeListener( 'resize', resizeCover );
2098
2099                 if ( CKEDITOR.env.ie6Compat )
2100                 {
2101                         win.$.setTimeout( function()
2102                                 {
2103                                         var prevScrollHandler = window.onscroll && window.onscroll.prevScrollHandler;
2104                                         window.onscroll = prevScrollHandler || null;
2105                                 }, 0 );
2106                 }
2107                 resizeCover = null;
2108         }
2109
2110         function removeCovers()
2111         {
2112                 for ( var coverId in covers )
2113                         covers[ coverId ].remove();
2114                 covers = {};
2115         }
2116
2117         var accessKeyProcessors = {};
2118
2119         var accessKeyDownHandler = function( evt )
2120         {
2121                 var ctrl = evt.data.$.ctrlKey || evt.data.$.metaKey,
2122                         alt = evt.data.$.altKey,
2123                         shift = evt.data.$.shiftKey,
2124                         key = String.fromCharCode( evt.data.$.keyCode ),
2125                         keyProcessor = accessKeyProcessors[( ctrl ? 'CTRL+' : '' ) + ( alt ? 'ALT+' : '') + ( shift ? 'SHIFT+' : '' ) + key];
2126
2127                 if ( !keyProcessor || !keyProcessor.length )
2128                         return;
2129
2130                 keyProcessor = keyProcessor[keyProcessor.length - 1];
2131                 keyProcessor.keydown && keyProcessor.keydown.call( keyProcessor.uiElement, keyProcessor.dialog, keyProcessor.key );
2132                 evt.data.preventDefault();
2133         };
2134
2135         var accessKeyUpHandler = function( evt )
2136         {
2137                 var ctrl = evt.data.$.ctrlKey || evt.data.$.metaKey,
2138                         alt = evt.data.$.altKey,
2139                         shift = evt.data.$.shiftKey,
2140                         key = String.fromCharCode( evt.data.$.keyCode ),
2141                         keyProcessor = accessKeyProcessors[( ctrl ? 'CTRL+' : '' ) + ( alt ? 'ALT+' : '') + ( shift ? 'SHIFT+' : '' ) + key];
2142
2143                 if ( !keyProcessor || !keyProcessor.length )
2144                         return;
2145
2146                 keyProcessor = keyProcessor[keyProcessor.length - 1];
2147                 if ( keyProcessor.keyup )
2148                 {
2149                         keyProcessor.keyup.call( keyProcessor.uiElement, keyProcessor.dialog, keyProcessor.key );
2150                         evt.data.preventDefault();
2151                 }
2152         };
2153
2154         var registerAccessKey = function( uiElement, dialog, key, downFunc, upFunc )
2155         {
2156                 var procList = accessKeyProcessors[key] || ( accessKeyProcessors[key] = [] );
2157                 procList.push( {
2158                                 uiElement : uiElement,
2159                                 dialog : dialog,
2160                                 key : key,
2161                                 keyup : upFunc || uiElement.accessKeyUp,
2162                                 keydown : downFunc || uiElement.accessKeyDown
2163                         } );
2164         };
2165
2166         var unregisterAccessKey = function( obj )
2167         {
2168                 for ( var i in accessKeyProcessors )
2169                 {
2170                         var list = accessKeyProcessors[i];
2171                         for ( var j = list.length - 1 ; j >= 0 ; j-- )
2172                         {
2173                                 if ( list[j].dialog == obj || list[j].uiElement == obj )
2174                                         list.splice( j, 1 );
2175                         }
2176                         if ( list.length === 0 )
2177                                 delete accessKeyProcessors[i];
2178                 }
2179         };
2180
2181         var tabAccessKeyUp = function( dialog, key )
2182         {
2183                 if ( dialog._.accessKeyMap[key] )
2184                         dialog.selectPage( dialog._.accessKeyMap[key] );
2185         };
2186
2187         var tabAccessKeyDown = function( dialog, key )
2188         {
2189         };
2190
2191         // ESC, ENTER
2192         var preventKeyBubblingKeys = { 27 :1, 13 :1 };
2193         var preventKeyBubbling = function( e )
2194         {
2195                 if ( e.data.getKeystroke() in preventKeyBubblingKeys )
2196                         e.data.stopPropagation();
2197         };
2198
2199         (function()
2200         {
2201                 CKEDITOR.ui.dialog =
2202                 {
2203                         /**
2204                          * The base class of all dialog UI elements.
2205                          * @constructor
2206                          * @param {CKEDITOR.dialog} dialog Parent dialog object.
2207                          * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition Element
2208                          * definition. Accepted fields:
2209                          * <ul>
2210                          *      <li><strong>id</strong> (Required) The id of the UI element. See {@link
2211                          *      CKEDITOR.dialog#getContentElement}</li>
2212                          *      <li><strong>type</strong> (Required) The type of the UI element. The
2213                          *      value to this field specifies which UI element class will be used to
2214                          *      generate the final widget.</li>
2215                          *      <li><strong>title</strong> (Optional) The popup tooltip for the UI
2216                          *      element.</li>
2217                          *      <li><strong>hidden</strong> (Optional) A flag that tells if the element
2218                          *      should be initially visible.</li>
2219                          *      <li><strong>className</strong> (Optional) Additional CSS class names
2220                          *      to add to the UI element. Separated by space.</li>
2221                          *      <li><strong>style</strong> (Optional) Additional CSS inline styles
2222                          *      to add to the UI element. A semicolon (;) is required after the last
2223                          *      style declaration.</li>
2224                          *      <li><strong>accessKey</strong> (Optional) The alphanumeric access key
2225                          *      for this element. Access keys are automatically prefixed by CTRL.</li>
2226                          *      <li><strong>on*</strong> (Optional) Any UI element definition field that
2227                          *      starts with <em>on</em> followed immediately by a capital letter and
2228                          *      probably more letters is an event handler. Event handlers may be further
2229                          *      divided into registered event handlers and DOM event handlers. Please
2230                          *      refer to {@link CKEDITOR.ui.dialog.uiElement#registerEvents} and
2231                          *      {@link CKEDITOR.ui.dialog.uiElement#eventProcessors} for more
2232                          *      information.</li>
2233                          * </ul>
2234                          * @param {Array} htmlList
2235                          * List of HTML code to be added to the dialog's content area.
2236                          * @param {Function|String} nodeNameArg
2237                          * A function returning a string, or a simple string for the node name for
2238                          * the root DOM node. Default is 'div'.
2239                          * @param {Function|Object} stylesArg
2240                          * A function returning an object, or a simple object for CSS styles applied
2241                          * to the DOM node. Default is empty object.
2242                          * @param {Function|Object} attributesArg
2243                          * A fucntion returning an object, or a simple object for attributes applied
2244                          * to the DOM node. Default is empty object.
2245                          * @param {Function|String} contentsArg
2246                          * A function returning a string, or a simple string for the HTML code inside
2247                          * the root DOM node. Default is empty string.
2248                          * @example
2249                          */
2250                         uiElement : function( dialog, elementDefinition, htmlList, nodeNameArg, stylesArg, attributesArg, contentsArg )
2251                         {
2252                                 if ( arguments.length < 4 )
2253                                         return;
2254
2255                                 var nodeName = ( nodeNameArg.call ? nodeNameArg( elementDefinition ) : nodeNameArg ) || 'div',
2256                                         html = [ '<', nodeName, ' ' ],
2257                                         styles = ( stylesArg && stylesArg.call ? stylesArg( elementDefinition ) : stylesArg ) || {},
2258                                         attributes = ( attributesArg && attributesArg.call ? attributesArg( elementDefinition ) : attributesArg ) || {},
2259                                         innerHTML = ( contentsArg && contentsArg.call ? contentsArg.call( this, dialog, elementDefinition ) : contentsArg ) || '',
2260                                         domId = this.domId = attributes.id || CKEDITOR.tools.getNextId() + '_uiElement',
2261                                         id = this.id = elementDefinition.id,
2262                                         i;
2263
2264                                 // Set the id, a unique id is required for getElement() to work.
2265                                 attributes.id = domId;
2266
2267                                 // Set the type and definition CSS class names.
2268                                 var classes = {};
2269                                 if ( elementDefinition.type )
2270                                         classes[ 'cke_dialog_ui_' + elementDefinition.type ] = 1;
2271                                 if ( elementDefinition.className )
2272                                         classes[ elementDefinition.className ] = 1;
2273                                 if ( elementDefinition.disabled )
2274                                         classes[ 'cke_disabled' ] = 1;
2275
2276                                 var attributeClasses = ( attributes['class'] && attributes['class'].split ) ? attributes['class'].split( ' ' ) : [];
2277                                 for ( i = 0 ; i < attributeClasses.length ; i++ )
2278                                 {
2279                                         if ( attributeClasses[i] )
2280                                                 classes[ attributeClasses[i] ] = 1;
2281                                 }
2282                                 var finalClasses = [];
2283                                 for ( i in classes )
2284                                         finalClasses.push( i );
2285                                 attributes['class'] = finalClasses.join( ' ' );
2286
2287                                 // Set the popup tooltop.
2288                                 if ( elementDefinition.title )
2289                                         attributes.title = elementDefinition.title;
2290
2291                                 // Write the inline CSS styles.
2292                                 var styleStr = ( elementDefinition.style || '' ).split( ';' );
2293
2294                                 // Element alignment support.
2295                                 if ( elementDefinition.align )
2296                                 {
2297                                         var align = elementDefinition.align;
2298                                         styles[ 'margin-left' ] = align == 'left' ? 0 : 'auto';
2299                                         styles[ 'margin-right' ] = align == 'right' ? 0 : 'auto';
2300                                 }
2301
2302                                 for ( i in styles )
2303                                         styleStr.push( i + ':' + styles[i] );
2304                                 if ( elementDefinition.hidden )
2305                                         styleStr.push( 'display:none' );
2306                                 for ( i = styleStr.length - 1 ; i >= 0 ; i-- )
2307                                 {
2308                                         if ( styleStr[i] === '' )
2309                                                 styleStr.splice( i, 1 );
2310                                 }
2311                                 if ( styleStr.length > 0 )
2312                                         attributes.style = ( attributes.style ? ( attributes.style + '; ' ) : '' ) + styleStr.join( '; ' );
2313
2314                                 // Write the attributes.
2315                                 for ( i in attributes )
2316                                         html.push( i + '="' + CKEDITOR.tools.htmlEncode( attributes[i] ) + '" ');
2317
2318                                 // Write the content HTML.
2319                                 html.push( '>', innerHTML, '</', nodeName, '>' );
2320
2321                                 // Add contents to the parent HTML array.
2322                                 htmlList.push( html.join( '' ) );
2323
2324                                 ( this._ || ( this._ = {} ) ).dialog = dialog;
2325
2326                                 // Override isChanged if it is defined in element definition.
2327                                 if ( typeof( elementDefinition.isChanged ) == 'boolean' )
2328                                         this.isChanged = function(){ return elementDefinition.isChanged; };
2329                                 if ( typeof( elementDefinition.isChanged ) == 'function' )
2330                                         this.isChanged = elementDefinition.isChanged;
2331
2332                                 // Overload 'get(set)Value' on definition.
2333                                 if ( typeof( elementDefinition.setValue ) == 'function' )
2334                                 {
2335                                                 this.setValue = CKEDITOR.tools.override( this.setValue, function( org )
2336                                                 {
2337                                                                 return function( val ){ org.call( this, elementDefinition.setValue.call( this, val ) ); };
2338                                                 } );
2339                                 }
2340
2341                                 if ( typeof( elementDefinition.getValue ) == 'function' )
2342                                 {
2343                                                 this.getValue = CKEDITOR.tools.override( this.getValue, function( org )
2344                                                 {
2345                                                                 return function(){ return  elementDefinition.getValue.call( this, org.call( this ) ); };
2346                                                 } );
2347                                 }
2348
2349                                 // Add events.
2350                                 CKEDITOR.event.implementOn( this );
2351
2352                                 this.registerEvents( elementDefinition );
2353                                 if ( this.accessKeyUp && this.accessKeyDown && elementDefinition.accessKey )
2354                                         registerAccessKey( this, dialog, 'CTRL+' + elementDefinition.accessKey );
2355
2356                                 var me = this;
2357                                 dialog.on( 'load', function()
2358                                         {
2359                                                 var input = me.getInputElement();
2360                                                 if ( input )
2361                                                 {
2362                                                         var focusClass = me.type in { 'checkbox' : 1, 'ratio' : 1 } && CKEDITOR.env.ie && CKEDITOR.env.version < 8 ? 'cke_dialog_ui_focused' : '';
2363                                                         input.on( 'focus', function()
2364                                                                 {
2365                                                                         dialog._.tabBarMode = false;
2366                                                                         dialog._.hasFocus = true;
2367                                                                         me.fire( 'focus' );
2368                                                                         focusClass && this.addClass( focusClass );
2369
2370                                                                 });
2371
2372                                                         input.on( 'blur', function()
2373                                                                 {
2374                                                                         me.fire( 'blur' );
2375                                                                         focusClass && this.removeClass( focusClass );
2376                                                                 });
2377                                                 }
2378                                         } );
2379
2380                                 // Register the object as a tab focus if it can be included.
2381                                 if ( this.keyboardFocusable )
2382                                 {
2383                                         this.tabIndex = elementDefinition.tabIndex || 0;
2384
2385                                         this.focusIndex = dialog._.focusList.push( this ) - 1;
2386                                         this.on( 'focus', function()
2387                                                 {
2388                                                         dialog._.currentFocusIndex = me.focusIndex;
2389                                                 } );
2390                                 }
2391
2392                                 // Completes this object with everything we have in the
2393                                 // definition.
2394                                 CKEDITOR.tools.extend( this, elementDefinition );
2395                         },
2396
2397                         /**
2398                          * Horizontal layout box for dialog UI elements, auto-expends to available width of container.
2399                          * @constructor
2400                          * @extends CKEDITOR.ui.dialog.uiElement
2401                          * @param {CKEDITOR.dialog} dialog
2402                          * Parent dialog object.
2403                          * @param {Array} childObjList
2404                          * Array of {@link CKEDITOR.ui.dialog.uiElement} objects inside this
2405                          * container.
2406                          * @param {Array} childHtmlList
2407                          * Array of HTML code that correspond to the HTML output of all the
2408                          * objects in childObjList.
2409                          * @param {Array} htmlList
2410                          * Array of HTML code that this element will output to.
2411                          * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
2412                          * The element definition. Accepted fields:
2413                          * <ul>
2414                          *      <li><strong>widths</strong> (Optional) The widths of child cells.</li>
2415                          *      <li><strong>height</strong> (Optional) The height of the layout.</li>
2416                          *      <li><strong>padding</strong> (Optional) The padding width inside child
2417                          *       cells.</li>
2418                          *      <li><strong>align</strong> (Optional) The alignment of the whole layout
2419                          *      </li>
2420                          * </ul>
2421                          * @example
2422                          */
2423                         hbox : function( dialog, childObjList, childHtmlList, htmlList, elementDefinition )
2424                         {
2425                                 if ( arguments.length < 4 )
2426                                         return;
2427
2428                                 this._ || ( this._ = {} );
2429
2430                                 var children = this._.children = childObjList,
2431                                         widths = elementDefinition && elementDefinition.widths || null,
2432                                         height = elementDefinition && elementDefinition.height || null,
2433                                         styles = {},
2434                                         i;
2435                                 /** @ignore */
2436                                 var innerHTML = function()
2437                                 {
2438                                         var html = [ '<tbody><tr class="cke_dialog_ui_hbox">' ];
2439                                         for ( i = 0 ; i < childHtmlList.length ; i++ )
2440                                         {
2441                                                 var className = 'cke_dialog_ui_hbox_child',
2442                                                         styles = [];
2443                                                 if ( i === 0 )
2444                                                         className = 'cke_dialog_ui_hbox_first';
2445                                                 if ( i == childHtmlList.length - 1 )
2446                                                         className = 'cke_dialog_ui_hbox_last';
2447                                                 html.push( '<td class="', className, '" role="presentation" ' );
2448                                                 if ( widths )
2449                                                 {
2450                                                         if ( widths[i] )
2451                                                                 styles.push( 'width:' + cssLength( widths[i] ) );
2452                                                 }
2453                                                 else
2454                                                         styles.push( 'width:' + Math.floor( 100 / childHtmlList.length ) + '%' );
2455                                                 if ( height )
2456                                                         styles.push( 'height:' + cssLength( height ) );
2457                                                 if ( elementDefinition && elementDefinition.padding != undefined )
2458                                                         styles.push( 'padding:' + cssLength( elementDefinition.padding ) );
2459                                                 // In IE Quirks alignment has to be done on table cells. (#7324)
2460                                                 if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && children[ i ].align )
2461                                                         styles.push( 'text-align:' + children[ i ].align );
2462                                                 if ( styles.length > 0 )
2463                                                         html.push( 'style="' + styles.join('; ') + '" ' );
2464                                                 html.push( '>', childHtmlList[i], '</td>' );
2465                                         }
2466                                         html.push( '</tr></tbody>' );
2467                                         return html.join( '' );
2468                                 };
2469
2470                                 var attribs = { role : 'presentation' };
2471                                 elementDefinition && elementDefinition.align && ( attribs.align = elementDefinition.align );
2472
2473                                 CKEDITOR.ui.dialog.uiElement.call(
2474                                         this,
2475                                         dialog,
2476                                         elementDefinition || { type : 'hbox' },
2477                                         htmlList,
2478                                         'table',
2479                                         styles,
2480                                         attribs,
2481                                         innerHTML );
2482                         },
2483
2484                         /**
2485                          * Vertical layout box for dialog UI elements.
2486                          * @constructor
2487                          * @extends CKEDITOR.ui.dialog.hbox
2488                          * @param {CKEDITOR.dialog} dialog
2489                          * Parent dialog object.
2490                          * @param {Array} childObjList
2491                          * Array of {@link CKEDITOR.ui.dialog.uiElement} objects inside this
2492                          * container.
2493                          * @param {Array} childHtmlList
2494                          * Array of HTML code that correspond to the HTML output of all the
2495                          * objects in childObjList.
2496                          * @param {Array} htmlList
2497                          * Array of HTML code that this element will output to.
2498                          * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
2499                          * The element definition. Accepted fields:
2500                          * <ul>
2501                          *      <li><strong>width</strong> (Optional) The width of the layout.</li>
2502                          *      <li><strong>heights</strong> (Optional) The heights of individual cells.
2503                          *      </li>
2504                          *      <li><strong>align</strong> (Optional) The alignment of the layout.</li>
2505                          *      <li><strong>padding</strong> (Optional) The padding width inside child
2506                          *      cells.</li>
2507                          *      <li><strong>expand</strong> (Optional) Whether the layout should expand
2508                          *      vertically to fill its container.</li>
2509                          * </ul>
2510                          * @example
2511                          */
2512                         vbox : function( dialog, childObjList, childHtmlList, htmlList, elementDefinition )
2513                         {
2514                                 if ( arguments.length < 3 )
2515                                         return;
2516
2517                                 this._ || ( this._ = {} );
2518
2519                                 var children = this._.children = childObjList,
2520                                         width = elementDefinition && elementDefinition.width || null,
2521                                         heights = elementDefinition && elementDefinition.heights || null;
2522                                 /** @ignore */
2523                                 var innerHTML = function()
2524                                 {
2525                                         var html = [ '<table role="presentation" cellspacing="0" border="0" ' ];
2526                                         html.push( 'style="' );
2527                                         if ( elementDefinition && elementDefinition.expand )
2528                                                 html.push( 'height:100%;' );
2529                                         html.push( 'width:' + cssLength( width || '100%' ), ';' );
2530                                         html.push( '"' );
2531                                         html.push( 'align="', CKEDITOR.tools.htmlEncode(
2532                                                 ( elementDefinition && elementDefinition.align ) || ( dialog.getParentEditor().lang.dir == 'ltr' ? 'left' : 'right' ) ), '" ' );
2533
2534                                         html.push( '><tbody>' );
2535                                         for ( var i = 0 ; i < childHtmlList.length ; i++ )
2536                                         {
2537                                                 var styles = [];
2538                                                 html.push( '<tr><td role="presentation" ' );
2539                                                 if ( width )
2540                                                         styles.push( 'width:' + cssLength( width || '100%' ) );
2541                                                 if ( heights )
2542                                                         styles.push( 'height:' + cssLength( heights[i] ) );
2543                                                 else if ( elementDefinition && elementDefinition.expand )
2544                                                         styles.push( 'height:' + Math.floor( 100 / childHtmlList.length ) + '%' );
2545                                                 if ( elementDefinition && elementDefinition.padding != undefined )
2546                                                         styles.push( 'padding:' + cssLength( elementDefinition.padding ) );
2547                                                 // In IE Quirks alignment has to be done on table cells. (#7324)
2548                                                 if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && children[ i ].align )
2549                                                         styles.push( 'text-align:' + children[ i ].align );
2550                                                 if ( styles.length > 0 )
2551                                                         html.push( 'style="', styles.join( '; ' ), '" ' );
2552                                                 html.push( ' class="cke_dialog_ui_vbox_child">', childHtmlList[i], '</td></tr>' );
2553                                         }
2554                                         html.push( '</tbody></table>' );
2555                                         return html.join( '' );
2556                                 };
2557                                 CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition || { type : 'vbox' }, htmlList, 'div', null, { role : 'presentation' }, innerHTML );
2558                         }
2559                 };
2560         })();
2561
2562         CKEDITOR.ui.dialog.uiElement.prototype =
2563         {
2564                 /**
2565                  * Gets the root DOM element of this dialog UI object.
2566                  * @returns {CKEDITOR.dom.element} Root DOM element of UI object.
2567                  * @example
2568                  * uiElement.getElement().hide();
2569                  */
2570                 getElement : function()
2571                 {
2572                         return CKEDITOR.document.getById( this.domId );
2573                 },
2574
2575                 /**
2576                  * Gets the DOM element that the user inputs values.
2577                  * This function is used by setValue(), getValue() and focus(). It should
2578                  * be overrided in child classes where the input element isn't the root
2579                  * element.
2580                  * @returns {CKEDITOR.dom.element} The element where the user input values.
2581                  * @example
2582                  * var rawValue = textInput.getInputElement().$.value;
2583                  */
2584                 getInputElement : function()
2585                 {
2586                         return this.getElement();
2587                 },
2588
2589                 /**
2590                  * Gets the parent dialog object containing this UI element.
2591                  * @returns {CKEDITOR.dialog} Parent dialog object.
2592                  * @example
2593                  * var dialog = uiElement.getDialog();
2594                  */
2595                 getDialog : function()
2596                 {
2597                         return this._.dialog;
2598                 },
2599
2600                 /**
2601                  * Sets the value of this dialog UI object.
2602                  * @param {Object} value The new value.
2603                  * @param {Boolean} noChangeEvent Internal commit, to supress 'change' event on this element.
2604                  * @returns {CKEDITOR.dialog.uiElement} The current UI element.
2605                  * @example
2606                  * uiElement.setValue( 'Dingo' );
2607                  */
2608                 setValue : function( value, noChangeEvent )
2609                 {
2610                         this.getInputElement().setValue( value );
2611                         !noChangeEvent && this.fire( 'change', { value : value } );
2612                         return this;
2613                 },
2614
2615                 /**
2616                  * Gets the current value of this dialog UI object.
2617                  * @returns {Object} The current value.
2618                  * @example
2619                  * var myValue = uiElement.getValue();
2620                  */
2621                 getValue : function()
2622                 {
2623                         return this.getInputElement().getValue();
2624                 },
2625
2626                 /**
2627                  * Tells whether the UI object's value has changed.
2628                  * @returns {Boolean} true if changed, false if not changed.
2629                  * @example
2630                  * if ( uiElement.isChanged() )
2631                  * &nbsp;&nbsp;confirm( 'Value changed! Continue?' );
2632                  */
2633                 isChanged : function()
2634                 {
2635                         // Override in input classes.
2636                         return false;
2637                 },
2638
2639                 /**
2640                  * Selects the parent tab of this element. Usually called by focus() or overridden focus() methods.
2641                  * @returns {CKEDITOR.dialog.uiElement} The current UI element.
2642                  * @example
2643                  * focus : function()
2644                  * {
2645                  *              this.selectParentTab();
2646                  *              // do something else.
2647                  * }
2648                  */
2649                 selectParentTab : function()
2650                 {
2651                         var element = this.getInputElement(),
2652                                 cursor = element,
2653                                 tabId;
2654                         while ( ( cursor = cursor.getParent() ) && cursor.$.className.search( 'cke_dialog_page_contents' ) == -1 )
2655                         { /*jsl:pass*/ }
2656
2657                         // Some widgets don't have parent tabs (e.g. OK and Cancel buttons).
2658                         if ( !cursor )
2659                                 return this;
2660
2661                         tabId = cursor.getAttribute( 'name' );
2662                         // Avoid duplicate select.
2663                         if ( this._.dialog._.currentTabId != tabId )
2664                                 this._.dialog.selectPage( tabId );
2665                         return this;
2666                 },
2667
2668                 /**
2669                  * Puts the focus to the UI object. Switches tabs if the UI object isn't in the active tab page.
2670                  * @returns {CKEDITOR.dialog.uiElement} The current UI element.
2671                  * @example
2672                  * uiElement.focus();
2673                  */
2674                 focus : function()
2675                 {
2676                         this.selectParentTab().getInputElement().focus();
2677                         return this;
2678                 },
2679
2680                 /**
2681                  * Registers the on* event handlers defined in the element definition.
2682                  * The default behavior of this function is:
2683                  * <ol>
2684                  *  <li>
2685                  *      If the on* event is defined in the class's eventProcesors list,
2686                  *      then the registration is delegated to the corresponding function
2687                  *      in the eventProcessors list.
2688                  *  </li>
2689                  *  <li>
2690                  *      If the on* event is not defined in the eventProcessors list, then
2691                  *      register the event handler under the corresponding DOM event of
2692                  *      the UI element's input DOM element (as defined by the return value
2693                  *      of {@link CKEDITOR.ui.dialog.uiElement#getInputElement}).
2694                  *  </li>
2695                  * </ol>
2696                  * This function is only called at UI element instantiation, but can
2697                  * be overridded in child classes if they require more flexibility.
2698                  * @param {CKEDITOR.dialog.definition.uiElement} definition The UI element
2699                  * definition.
2700                  * @returns {CKEDITOR.dialog.uiElement} The current UI element.
2701                  * @example
2702                  */
2703                 registerEvents : function( definition )
2704                 {
2705                         var regex = /^on([A-Z]\w+)/,
2706                                 match;
2707
2708                         var registerDomEvent = function( uiElement, dialog, eventName, func )
2709                         {
2710                                 dialog.on( 'load', function()
2711                                 {
2712                                         uiElement.getInputElement().on( eventName, func, uiElement );
2713                                 });
2714                         };
2715
2716                         for ( var i in definition )
2717                         {
2718                                 if ( !( match = i.match( regex ) ) )
2719                                         continue;
2720                                 if ( this.eventProcessors[i] )
2721                                         this.eventProcessors[i].call( this, this._.dialog, definition[i] );
2722                                 else
2723                                         registerDomEvent( this, this._.dialog, match[1].toLowerCase(), definition[i] );
2724                         }
2725
2726                         return this;
2727                 },
2728
2729                 /**
2730                  * The event processor list used by
2731                  * {@link CKEDITOR.ui.dialog.uiElement#getInputElement} at UI element
2732                  * instantiation. The default list defines three on* events:
2733                  * <ol>
2734                  *  <li>onLoad - Called when the element's parent dialog opens for the
2735                  *  first time</li>
2736                  *  <li>onShow - Called whenever the element's parent dialog opens.</li>
2737                  *  <li>onHide - Called whenever the element's parent dialog closes.</li>
2738                  * </ol>
2739                  * @field
2740                  * @type Object
2741                  * @example
2742                  * // This connects the 'click' event in CKEDITOR.ui.dialog.button to onClick
2743                  * // handlers in the UI element's definitions.
2744                  * CKEDITOR.ui.dialog.button.eventProcessors = CKEDITOR.tools.extend( {},
2745                  * &nbsp;&nbsp;CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors,
2746                  * &nbsp;&nbsp;{ onClick : function( dialog, func ) { this.on( 'click', func ); } },
2747                  * &nbsp;&nbsp;true );
2748                  */
2749                 eventProcessors :
2750                 {
2751                         onLoad : function( dialog, func )
2752                         {
2753                                 dialog.on( 'load', func, this );
2754                         },
2755
2756                         onShow : function( dialog, func )
2757                         {
2758                                 dialog.on( 'show', func, this );
2759                         },
2760
2761                         onHide : function( dialog, func )
2762                         {
2763                                 dialog.on( 'hide', func, this );
2764                         }
2765                 },
2766
2767                 /**
2768                  * The default handler for a UI element's access key down event, which
2769                  * tries to put focus to the UI element.<br />
2770                  * Can be overridded in child classes for more sophisticaed behavior.
2771                  * @param {CKEDITOR.dialog} dialog The parent dialog object.
2772                  * @param {String} key The key combination pressed. Since access keys
2773                  * are defined to always include the CTRL key, its value should always
2774                  * include a 'CTRL+' prefix.
2775                  * @example
2776                  */
2777                 accessKeyDown : function( dialog, key )
2778                 {
2779                         this.focus();
2780                 },
2781
2782                 /**
2783                  * The default handler for a UI element's access key up event, which
2784                  * does nothing.<br />
2785                  * Can be overridded in child classes for more sophisticated behavior.
2786                  * @param {CKEDITOR.dialog} dialog The parent dialog object.
2787                  * @param {String} key The key combination pressed. Since access keys
2788                  * are defined to always include the CTRL key, its value should always
2789                  * include a 'CTRL+' prefix.
2790                  * @example
2791                  */
2792                 accessKeyUp : function( dialog, key )
2793                 {
2794                 },
2795
2796                 /**
2797                  * Disables a UI element.
2798                  * @example
2799                  */
2800                 disable : function()
2801                 {
2802                         var element = this.getElement(),
2803                                 input = this.getInputElement();
2804                         input.setAttribute( 'disabled', 'true' );
2805                         element.addClass( 'cke_disabled' );
2806                 },
2807
2808                 /**
2809                  * Enables a UI element.
2810                  * @example
2811                  */
2812                 enable : function()
2813                 {
2814                         var element = this.getElement(),
2815                                 input = this.getInputElement();
2816                         input.removeAttribute( 'disabled' );
2817                         element.removeClass( 'cke_disabled' );
2818                 },
2819
2820                 /**
2821                  * Determines whether an UI element is enabled or not.
2822                  * @returns {Boolean} Whether the UI element is enabled.
2823                  * @example
2824                  */
2825                 isEnabled : function()
2826                 {
2827                         return !this.getElement().hasClass( 'cke_disabled' );
2828                 },
2829
2830                 /**
2831                  * Determines whether an UI element is visible or not.
2832                  * @returns {Boolean} Whether the UI element is visible.
2833                  * @example
2834                  */
2835                 isVisible : function()
2836                 {
2837                         return this.getInputElement().isVisible();
2838                 },
2839
2840                 /**
2841                  * Determines whether an UI element is focus-able or not.
2842                  * Focus-able is defined as being both visible and enabled.
2843                  * @returns {Boolean} Whether the UI element can be focused.
2844                  * @example
2845                  */
2846                 isFocusable : function()
2847                 {
2848                         if ( !this.isEnabled() || !this.isVisible() )
2849                                 return false;
2850                         return true;
2851                 }
2852         };
2853
2854         CKEDITOR.ui.dialog.hbox.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement,
2855                 /**
2856                  * @lends CKEDITOR.ui.dialog.hbox.prototype
2857                  */
2858                 {
2859                         /**
2860                          * Gets a child UI element inside this container.
2861                          * @param {Array|Number} indices An array or a single number to indicate the child's
2862                          * position in the container's descendant tree. Omit to get all the children in an array.
2863                          * @returns {Array|CKEDITOR.ui.dialog.uiElement} Array of all UI elements in the container
2864                          * if no argument given, or the specified UI element if indices is given.
2865                          * @example
2866                          * var checkbox = hbox.getChild( [0,1] );
2867                          * checkbox.setValue( true );
2868                          */
2869                         getChild : function( indices )
2870                         {
2871                                 // If no arguments, return a clone of the children array.
2872                                 if ( arguments.length < 1 )
2873                                         return this._.children.concat();
2874
2875                                 // If indices isn't array, make it one.
2876                                 if ( !indices.splice )
2877                                         indices = [ indices ];
2878
2879                                 // Retrieve the child element according to tree position.
2880                                 if ( indices.length < 2 )
2881                                         return this._.children[ indices[0] ];
2882                                 else
2883                                         return ( this._.children[ indices[0] ] && this._.children[ indices[0] ].getChild ) ?
2884                                                 this._.children[ indices[0] ].getChild( indices.slice( 1, indices.length ) ) :
2885                                                 null;
2886                         }
2887                 }, true );
2888
2889         CKEDITOR.ui.dialog.vbox.prototype = new CKEDITOR.ui.dialog.hbox();
2890
2891
2892
2893         (function()
2894         {
2895                 var commonBuilder = {
2896                         build : function( dialog, elementDefinition, output )
2897                         {
2898                                 var children = elementDefinition.children,
2899                                         child,
2900                                         childHtmlList = [],
2901                                         childObjList = [];
2902                                 for ( var i = 0 ; ( i < children.length && ( child = children[i] ) ) ; i++ )
2903                                 {
2904                                         var childHtml = [];
2905                                         childHtmlList.push( childHtml );
2906                                         childObjList.push( CKEDITOR.dialog._.uiElementBuilders[ child.type ].build( dialog, child, childHtml ) );
2907                                 }
2908                                 return new CKEDITOR.ui.dialog[elementDefinition.type]( dialog, childObjList, childHtmlList, output, elementDefinition );
2909                         }
2910                 };
2911
2912                 CKEDITOR.dialog.addUIElement( 'hbox', commonBuilder );
2913                 CKEDITOR.dialog.addUIElement( 'vbox', commonBuilder );
2914         })();
2915
2916         /**
2917          * Generic dialog command. It opens a specific dialog when executed.
2918          * @constructor
2919          * @augments CKEDITOR.commandDefinition
2920          * @param {string} dialogName The name of the dialog to open when executing
2921          *              this command.
2922          * @example
2923          * // Register the "link" command, which opens the "link" dialog.
2924          * editor.addCommand( 'link', <b>new CKEDITOR.dialogCommand( 'link' )</b> );
2925          */
2926         CKEDITOR.dialogCommand = function( dialogName )
2927         {
2928                 this.dialogName = dialogName;
2929         };
2930
2931         CKEDITOR.dialogCommand.prototype =
2932         {
2933                 /** @ignore */
2934                 exec : function( editor )
2935                 {
2936                         // Special treatment for Opera. (#8031)
2937                         CKEDITOR.env.opera ?
2938                                 CKEDITOR.tools.setTimeout( function() { editor.openDialog( this.dialogName ) }, 0, this )
2939                                 : editor.openDialog( this.dialogName );
2940                 },
2941
2942                 // Dialog commands just open a dialog ui, thus require no undo logic,
2943                 // undo support should dedicate to specific dialog implementation.
2944                 canUndo: false,
2945
2946                 editorFocus : CKEDITOR.env.ie || CKEDITOR.env.webkit
2947         };
2948
2949         (function()
2950         {
2951                 var notEmptyRegex = /^([a]|[^a])+$/,
2952                         integerRegex = /^\d*$/,
2953                         numberRegex = /^\d*(?:\.\d+)?$/,
2954                         htmlLengthRegex = /^(((\d*(\.\d+))|(\d*))(px|\%)?)?$/,
2955                         cssLengthRegex = /^(((\d*(\.\d+))|(\d*))(px|em|ex|in|cm|mm|pt|pc|\%)?)?$/i,
2956                         inlineStyleRegex = /^(\s*[\w-]+\s*:\s*[^:;]+(?:;|$))*$/;
2957
2958                 CKEDITOR.VALIDATE_OR = 1;
2959                 CKEDITOR.VALIDATE_AND = 2;
2960
2961                 CKEDITOR.dialog.validate =
2962                 {
2963                         functions : function()
2964                         {
2965                                 var args = arguments;
2966                                 return function()
2967                                 {
2968                                         /**
2969                                          * It's important for validate functions to be able to accept the value
2970                                          * as argument in addition to this.getValue(), so that it is possible to
2971                                          * combine validate functions together to make more sophisticated
2972                                          * validators.
2973                                          */
2974                                         var value = this && this.getValue ? this.getValue() : args[ 0 ];
2975
2976                                         var msg = undefined,
2977                                                 relation = CKEDITOR.VALIDATE_AND,
2978                                                 functions = [], i;
2979
2980                                         for ( i = 0 ; i < args.length ; i++ )
2981                                         {
2982                                                 if ( typeof( args[i] ) == 'function' )
2983                                                         functions.push( args[i] );
2984                                                 else
2985                                                         break;
2986                                         }
2987
2988                                         if ( i < args.length && typeof( args[i] ) == 'string' )
2989                                         {
2990                                                 msg = args[i];
2991                                                 i++;
2992                                         }
2993
2994                                         if ( i < args.length && typeof( args[i]) == 'number' )
2995                                                 relation = args[i];
2996
2997                                         var passed = ( relation == CKEDITOR.VALIDATE_AND ? true : false );
2998                                         for ( i = 0 ; i < functions.length ; i++ )
2999                                         {
3000                                                 if ( relation == CKEDITOR.VALIDATE_AND )
3001                                                         passed = passed && functions[i]( value );
3002                                                 else
3003                                                         passed = passed || functions[i]( value );
3004                                         }
3005
3006                                         return !passed ? msg : true;
3007                                 };
3008                         },
3009
3010                         regex : function( regex, msg )
3011                         {
3012                                 /*
3013                                  * Can be greatly shortened by deriving from functions validator if code size
3014                                  * turns out to be more important than performance.
3015                                  */
3016                                 return function()
3017                                 {
3018                                         var value = this && this.getValue ? this.getValue() : arguments[0];
3019                                         return !regex.test( value ) ? msg : true;
3020                                 };
3021                         },
3022
3023                         notEmpty : function( msg )
3024                         {
3025                                 return this.regex( notEmptyRegex, msg );
3026                         },
3027
3028                         integer : function( msg )
3029                         {
3030                                 return this.regex( integerRegex, msg );
3031                         },
3032
3033                         'number' : function( msg )
3034                         {
3035                                 return this.regex( numberRegex, msg );
3036                         },
3037
3038                         'cssLength' : function( msg )
3039                         {
3040                                 return this.functions( function( val ){ return cssLengthRegex.test( CKEDITOR.tools.trim( val ) ); }, msg );
3041                         },
3042
3043                         'htmlLength' : function( msg )
3044                         {
3045                                 return this.functions( function( val ){ return htmlLengthRegex.test( CKEDITOR.tools.trim( val ) ); }, msg );
3046                         },
3047
3048                         'inlineStyle' : function( msg )
3049                         {
3050                                 return this.functions( function( val ){ return inlineStyleRegex.test( CKEDITOR.tools.trim( val ) ); }, msg );
3051                         },
3052
3053                         equals : function( value, msg )
3054                         {
3055                                 return this.functions( function( val ){ return val == value; }, msg );
3056                         },
3057
3058                         notEqual : function( value, msg )
3059                         {
3060                                 return this.functions( function( val ){ return val != value; }, msg );
3061                         }
3062                 };
3063
3064         CKEDITOR.on( 'instanceDestroyed', function( evt )
3065         {
3066                 // Remove dialog cover on last instance destroy.
3067                 if ( CKEDITOR.tools.isEmpty( CKEDITOR.instances ) )
3068                 {
3069                         var currentTopDialog;
3070                         while ( ( currentTopDialog = CKEDITOR.dialog._.currentTop ) )
3071                                 currentTopDialog.hide();
3072                         removeCovers();
3073                 }
3074
3075                 var dialogs = evt.editor._.storedDialogs;
3076                 for ( var name in dialogs )
3077                         dialogs[ name ].destroy();
3078
3079         });
3080
3081         })();
3082
3083         // Extend the CKEDITOR.editor class with dialog specific functions.
3084         CKEDITOR.tools.extend( CKEDITOR.editor.prototype,
3085                 /** @lends CKEDITOR.editor.prototype */
3086                 {
3087                         /**
3088                          * Loads and opens a registered dialog.
3089                          * @param {String} dialogName The registered name of the dialog.
3090                          * @param {Function} callback The function to be invoked after dialog instance created.
3091                          * @see CKEDITOR.dialog.add
3092                          * @example
3093                          * CKEDITOR.instances.editor1.openDialog( 'smiley' );
3094                          * @returns {CKEDITOR.dialog} The dialog object corresponding to the dialog displayed. null if the dialog name is not registered.
3095                          */
3096                         openDialog : function( dialogName, callback )
3097                         {
3098                                 if ( this.mode == 'wysiwyg' && CKEDITOR.env.ie )
3099                                 {
3100                                         var selection = this.getSelection();
3101                                         selection && selection.lock();
3102                                 }
3103
3104                                 var dialogDefinitions = CKEDITOR.dialog._.dialogDefinitions[ dialogName ],
3105                                                 dialogSkin = this.skin.dialog;
3106
3107                                 if ( CKEDITOR.dialog._.currentTop === null )
3108                                         showCover( this );
3109
3110                                 // If the dialogDefinition is already loaded, open it immediately.
3111                                 if ( typeof dialogDefinitions == 'function' && dialogSkin._isLoaded )
3112                                 {
3113                                         var storedDialogs = this._.storedDialogs ||
3114                                                 ( this._.storedDialogs = {} );
3115
3116                                         var dialog = storedDialogs[ dialogName ] ||
3117                                                 ( storedDialogs[ dialogName ] = new CKEDITOR.dialog( this, dialogName ) );
3118
3119                                         callback && callback.call( dialog, dialog );
3120                                         dialog.show();
3121
3122                                         return dialog;
3123                                 }
3124                                 else if ( dialogDefinitions == 'failed' )
3125                                 {
3126                                         hideCover();
3127                                         throw new Error( '[CKEDITOR.dialog.openDialog] Dialog "' + dialogName + '" failed when loading definition.' );
3128                                 }
3129
3130                                 var me = this;
3131
3132                                 function onDialogFileLoaded( success )
3133                                 {
3134                                         var dialogDefinition = CKEDITOR.dialog._.dialogDefinitions[ dialogName ],
3135                                                         skin = me.skin.dialog;
3136
3137                                         // Check if both skin part and definition is loaded.
3138                                         if ( !skin._isLoaded || loadDefinition && typeof success == 'undefined' )
3139                                                 return;
3140
3141                                         // In case of plugin error, mark it as loading failed.
3142                                         if ( typeof dialogDefinition != 'function' )
3143                                                 CKEDITOR.dialog._.dialogDefinitions[ dialogName ] = 'failed';
3144
3145                                         me.openDialog( dialogName, callback );
3146                                 }
3147
3148                                 if ( typeof dialogDefinitions == 'string' )
3149                                 {
3150                                         var loadDefinition = 1;
3151                                         CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( dialogDefinitions ), onDialogFileLoaded, null, 0, 1 );
3152                                 }
3153
3154                                 CKEDITOR.skins.load( this, 'dialog', onDialogFileLoaded );
3155
3156                                 return null;
3157                         }
3158                 });
3159 })();
3160
3161 CKEDITOR.plugins.add( 'dialog',
3162         {
3163                 requires : [ 'dialogui' ]
3164         });
3165
3166 // Dialog related configurations.
3167
3168 /**
3169  * The color of the dialog background cover. It should be a valid CSS color
3170  * string.
3171  * @name CKEDITOR.config.dialog_backgroundCoverColor
3172  * @type String
3173  * @default 'white'
3174  * @example
3175  * config.dialog_backgroundCoverColor = 'rgb(255, 254, 253)';
3176  */
3177
3178 /**
3179  * The opacity of the dialog background cover. It should be a number within the
3180  * range [0.0, 1.0].
3181  * @name CKEDITOR.config.dialog_backgroundCoverOpacity
3182  * @type Number
3183  * @default 0.5
3184  * @example
3185  * config.dialog_backgroundCoverOpacity = 0.7;
3186  */
3187
3188 /**
3189  * If the dialog has more than one tab, put focus into the first tab as soon as dialog is opened.
3190  * @name CKEDITOR.config.dialog_startupFocusTab
3191  * @type Boolean
3192  * @default false
3193  * @example
3194  * config.dialog_startupFocusTab = true;
3195  */
3196
3197 /**
3198  * The distance of magnetic borders used in moving and resizing dialogs,
3199  * measured in pixels.
3200  * @name CKEDITOR.config.dialog_magnetDistance
3201  * @type Number
3202  * @default 20
3203  * @example
3204  * config.dialog_magnetDistance = 30;
3205  */
3206
3207 /**
3208  * The guideline to follow when generating the dialog buttons. There are 3 possible options:
3209  * <ul>
3210  *     <li>'OS' - the buttons will be displayed in the default order of the user's OS;</li>
3211  *     <li>'ltr' - for Left-To-Right order;</li>
3212  *     <li>'rtl' - for Right-To-Left order.</li>
3213  * </ul>
3214  * @name CKEDITOR.config.dialog_buttonsOrder
3215  * @type String
3216  * @default 'OS'
3217  * @since 3.5
3218  * @example
3219  * config.dialog_buttonsOrder = 'rtl';
3220  */
3221
3222 /**
3223  * The dialog contents to removed. It's a string composed by dialog name and tab name with a colon between them.
3224  * Separate each pair with semicolon (see example).
3225  * <b>Note: All names are case-sensitive.</b>
3226  * <b>Note: Be cautious when specifying dialog tabs that are mandatory, like "info", dialog functionality might be broken because of this!</b>
3227  * @name CKEDITOR.config.removeDialogTabs
3228  * @type String
3229  * @since 3.5
3230  * @default ''
3231  * @example
3232  * config.removeDialogTabs = 'flash:advanced;image:Link';
3233  */
3234
3235 /**
3236  * Fired when a dialog definition is about to be used to create a dialog into
3237  * an editor instance. This event makes it possible to customize the definition
3238  * before creating it.
3239  * <p>Note that this event is called only the first time a specific dialog is
3240  * opened. Successive openings will use the cached dialog, and this event will
3241  * not get fired.</p>
3242  * @name CKEDITOR#dialogDefinition
3243  * @event
3244  * @param {CKEDITOR.dialog.definition} data The dialog defination that
3245  *              is being loaded.
3246  * @param {CKEDITOR.editor} editor The editor instance that will use the
3247  *              dialog.
3248  */
3249
3250 /**
3251  * Fired when a tab is going to be selected in a dialog
3252  * @name CKEDITOR.dialog#selectPage
3253  * @event
3254  * @param {String} page The id of the page that it's gonna be selected.
3255  * @param {String} currentPage The id of the current page.
3256  */
3257
3258 /**
3259  * Fired when the user tries to dismiss a dialog
3260  * @name CKEDITOR.dialog#cancel
3261  * @event
3262  * @param {Boolean} hide Whether the event should proceed or not.
3263  */
3264
3265 /**
3266  * Fired when the user tries to confirm a dialog
3267  * @name CKEDITOR.dialog#ok
3268  * @event
3269  * @param {Boolean} hide Whether the event should proceed or not.
3270  */
3271
3272 /**
3273  * Fired when a dialog is shown
3274  * @name CKEDITOR.dialog#show
3275  * @event
3276  */
3277
3278 /**
3279  * Fired when a dialog is shown
3280  * @name CKEDITOR.editor#dialogShow
3281  * @event
3282  */
3283
3284 /**
3285  * Fired when a dialog is hidden
3286  * @name CKEDITOR.dialog#hide
3287  * @event
3288  */
3289
3290 /**
3291  * Fired when a dialog is hidden
3292  * @name CKEDITOR.editor#dialogHide
3293  * @event
3294  */
3295
3296 /**
3297  * Fired when a dialog is being resized. The event is fired on
3298  * both the 'CKEDITOR.dialog' object and the dialog instance
3299  * since 3.5.3, previously it's available only in the global object.
3300  * @name CKEDITOR.dialog#resize
3301  * @since 3.5
3302  * @event
3303  * @param {CKEDITOR.dialog} dialog The dialog being resized (if
3304  * it's fired on the dialog itself, this parameter isn't sent).
3305  * @param {String} skin The skin name.
3306  * @param {Number} width The new width.
3307  * @param {Number} height The new height.
3308  */