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