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