2 Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
3 For licensing, see LICENSE.html or http://ckeditor.com/license
6 /** @fileoverview The "dialogui" plugin. */
8 CKEDITOR
.plugins
.add( 'dialogui' );
12 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
] );
21 CKEDITOR
.tools
.extend
.apply( CKEDITOR
.tools
, args
);
26 build : function( dialog
, elementDefinition
, output
)
28 return new CKEDITOR
.ui
.dialog
.textInput( dialog
, elementDefinition
, output
);
33 build : function( dialog
, elementDefinition
, output
)
35 return new CKEDITOR
.ui
.dialog
[elementDefinition
.type
]( dialog
, elementDefinition
, output
);
40 build : function( dialog
, elementDefinition
, output
)
42 var children
= elementDefinition
.children
,
46 for ( var i
= 0 ; ( i
< children
.length
&& ( child
= children
[i
] ) ) ; i
++ )
49 childHtmlList
.push( childHtml
);
50 childObjList
.push( CKEDITOR
.dialog
._
.uiElementBuilders
[ child
.type
].build( dialog
, child
, childHtml
) );
52 return new CKEDITOR
.ui
.dialog
[ elementDefinition
.type
]( dialog
, childObjList
, childHtmlList
, output
, elementDefinition
);
57 isChanged : function()
59 return this.getValue() != this.getInitValue();
62 reset : function( noChangeEvent
)
64 this.setValue( this.getInitValue(), noChangeEvent
);
67 setInitValue : function()
69 this._
.initValue
= this.getValue();
72 resetInitValue : function()
74 this._
.initValue
= this._
['default'];
77 getInitValue : function()
79 return this._
.initValue
;
82 commonEventProcessors
= CKEDITOR
.tools
.extend( {}, CKEDITOR
.ui
.dialog
.uiElement
.prototype.eventProcessors
,
84 onChange : function( dialog
, func
)
86 if ( !this._
.domOnChangeRegistered
)
88 dialog
.on( 'load', function()
90 this.getInputElement().on( 'change', function()
92 // Make sure 'onchange' doesn't get fired after dialog closed. (#5719)
93 if ( !dialog
.parts
.dialog
.isVisible() )
96 this.fire( 'change', { value
: this.getValue() } );
99 this._
.domOnChangeRegistered
= true;
102 this.on( 'change', func
);
105 eventRegex
= /^on([A-Z]\w+)/,
106 cleanInnerDefinition = function( def
)
108 // An inner UI element should not have the parent's type, title or events.
111 if ( eventRegex
.test( i
) || i
== 'title' || i
== 'type' )
117 CKEDITOR
.tools
.extend( CKEDITOR
.ui
.dialog
,
118 /** @lends CKEDITOR.ui.dialog */
121 * Base class for all dialog elements with a textual label on the left.
124 * @extends CKEDITOR.ui.dialog.uiElement
125 * @param {CKEDITOR.dialog} dialog
126 * Parent dialog object.
127 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
128 * The element definition. Accepted fields:
130 * <li><strong>label</strong> (Required) The label string.</li>
131 * <li><strong>labelLayout</strong> (Optional) Put 'horizontal' here if the
132 * label element is to be layed out horizontally. Otherwise a vertical
133 * layout will be used.</li>
134 * <li><strong>widths</strong> (Optional) This applies only for horizontal
135 * layouts - an 2-element array of lengths to specify the widths of the
136 * label and the content element.</li>
138 * @param {Array} htmlList
139 * List of HTML code to output to.
140 * @param {Function} contentHtml
141 * A function returning the HTML code string to be added inside the content
144 labeledElement : function( dialog
, elementDefinition
, htmlList
, contentHtml
)
146 if ( arguments
.length
< 4 )
149 var _
= initPrivateObject
.call( this, elementDefinition
);
150 _
.labelId
= CKEDITOR
.tools
.getNextId() + '_label';
151 var children
= this._
.children
= [];
153 var innerHTML = function()
156 requiredClass
= elementDefinition
.required
? ' cke_required' : '' ;
157 if ( elementDefinition
.labelLayout
!= 'horizontal' )
158 html
.push( '<label class="cke_dialog_ui_labeled_label' + requiredClass
+ '" ',
159 ' id="'+ _
.labelId
+ '"',
160 ' for="' + _
.inputId
+ '"',
161 ( elementDefinition
.labelStyle
? ' style="' + elementDefinition
.labelStyle
+ '"' : '' ) +'>',
162 elementDefinition
.label
,
164 '<div class="cke_dialog_ui_labeled_content"' + ( elementDefinition
.controlStyle
? ' style="' + elementDefinition
.controlStyle
+ '"' : '' ) + ' role="presentation">',
165 contentHtml
.call( this, dialog
, elementDefinition
),
169 var hboxDefinition
= {
171 widths
: elementDefinition
.widths
,
177 html
: '<label class="cke_dialog_ui_labeled_label' + requiredClass
+ '"' +
178 ' id="' + _
.labelId
+ '"' +
179 ' for="' + _
.inputId
+ '"' +
180 ( elementDefinition
.labelStyle
? ' style="' + elementDefinition
.labelStyle
+ '"' : '' ) +'>' +
181 CKEDITOR
.tools
.htmlEncode( elementDefinition
.label
) +
186 html
: '<span class="cke_dialog_ui_labeled_content"' + ( elementDefinition
.controlStyle
? ' style="' + elementDefinition
.controlStyle
+ '"' : '' ) + '>' +
187 contentHtml
.call( this, dialog
, elementDefinition
) +
192 CKEDITOR
.dialog
._
.uiElementBuilders
.hbox
.build( dialog
, hboxDefinition
, html
);
194 return html
.join( '' );
196 CKEDITOR
.ui
.dialog
.uiElement
.call( this, dialog
, elementDefinition
, htmlList
, 'div', null, { role
: 'presentation' }, innerHTML
);
200 * A text input with a label. This UI element class represents both the
201 * single-line text inputs and password inputs in dialog boxes.
204 * @extends CKEDITOR.ui.dialog.labeledElement
205 * @param {CKEDITOR.dialog} dialog
206 * Parent dialog object.
207 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
208 * The element definition. Accepted fields:
210 * <li><strong>default</strong> (Optional) The default value.</li>
211 * <li><strong>validate</strong> (Optional) The validation function. </li>
212 * <li><strong>maxLength</strong> (Optional) The maximum length of text box
214 * <li><strong>size</strong> (Optional) The size of the text box. This is
215 * usually overridden by the size defined by the skin, however.</li>
217 * @param {Array} htmlList
218 * List of HTML code to output to.
220 textInput : function( dialog
, elementDefinition
, htmlList
)
222 if ( arguments
.length
< 3 )
225 initPrivateObject
.call( this, elementDefinition
);
226 var domId
= this._
.inputId
= CKEDITOR
.tools
.getNextId() + '_textInput',
227 attributes
= { 'class' : 'cke_dialog_ui_input_' + elementDefinition
.type
, id
: domId
, type
: 'text' },
230 // Set the validator, if any.
231 if ( elementDefinition
.validate
)
232 this.validate
= elementDefinition
.validate
;
234 // Set the max length and size.
235 if ( elementDefinition
.maxLength
)
236 attributes
.maxlength
= elementDefinition
.maxLength
;
237 if ( elementDefinition
.size
)
238 attributes
.size
= elementDefinition
.size
;
240 if ( elementDefinition
.inputStyle
)
241 attributes
.style
= elementDefinition
.inputStyle
;
243 // If user presses Enter in a text box, it implies clicking OK for the dialog.
244 var me
= this, keyPressedOnMe
= false;
245 dialog
.on( 'load', function()
247 me
.getInputElement().on( 'keydown', function( evt
)
249 if ( evt
.data
.getKeystroke() == 13 )
250 keyPressedOnMe
= true;
253 // Lower the priority this 'keyup' since 'ok' will close the dialog.(#3749)
254 me
.getInputElement().on( 'keyup', function( evt
)
256 if ( evt
.data
.getKeystroke() == 13 && keyPressedOnMe
)
258 dialog
.getButton( 'ok' ) && setTimeout( function ()
260 dialog
.getButton( 'ok' ).click();
262 keyPressedOnMe
= false;
264 }, null, null, 1000 );
268 var innerHTML = function()
270 // IE BUG: Text input fields in IE at 100% would exceed a <td> or inline
271 // container's width, so need to wrap it inside a <div>.
272 var html
= [ '<div class="cke_dialog_ui_input_', elementDefinition
.type
, '" role="presentation"' ];
274 if ( elementDefinition
.width
)
275 html
.push( 'style="width:'+ elementDefinition
.width
+'" ' );
277 html
.push( '><input ' );
279 attributes
[ 'aria-labelledby' ] = this._
.labelId
;
280 this._
.required
&& ( attributes
[ 'aria-required' ] = this._
.required
);
281 for ( var i
in attributes
)
282 html
.push( i
+ '="' + attributes
[i
] + '" ' );
283 html
.push( ' /></div>' );
284 return html
.join( '' );
286 CKEDITOR
.ui
.dialog
.labeledElement
.call( this, dialog
, elementDefinition
, htmlList
, innerHTML
);
290 * A text area with a label on the top or left.
292 * @extends CKEDITOR.ui.dialog.labeledElement
294 * @param {CKEDITOR.dialog} dialog
295 * Parent dialog object.
296 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
297 * The element definition. Accepted fields:
299 * <li><strong>rows</strong> (Optional) The number of rows displayed.
300 * Defaults to 5 if not defined.</li>
301 * <li><strong>cols</strong> (Optional) The number of cols displayed.
302 * Defaults to 20 if not defined. Usually overridden by skins.</li>
303 * <li><strong>default</strong> (Optional) The default value.</li>
304 * <li><strong>validate</strong> (Optional) The validation function. </li>
306 * @param {Array} htmlList
307 * List of HTML code to output to.
309 textarea : function( dialog
, elementDefinition
, htmlList
)
311 if ( arguments
.length
< 3 )
314 initPrivateObject
.call( this, elementDefinition
);
316 domId
= this._
.inputId
= CKEDITOR
.tools
.getNextId() + '_textarea',
319 if ( elementDefinition
.validate
)
320 this.validate
= elementDefinition
.validate
;
322 // Generates the essential attributes for the textarea tag.
323 attributes
.rows
= elementDefinition
.rows
|| 5;
324 attributes
.cols
= elementDefinition
.cols
|| 20;
326 if ( typeof elementDefinition
.inputStyle
!= 'undefined' )
327 attributes
.style
= elementDefinition
.inputStyle
;
331 var innerHTML = function()
333 attributes
[ 'aria-labelledby' ] = this._
.labelId
;
334 this._
.required
&& ( attributes
[ 'aria-required' ] = this._
.required
);
335 var html
= [ '<div class="cke_dialog_ui_input_textarea" role="presentation"><textarea class="cke_dialog_ui_input_textarea" id="', domId
, '" ' ];
336 for ( var i
in attributes
)
337 html
.push( i
+ '="' + CKEDITOR
.tools
.htmlEncode( attributes
[i
] ) + '" ' );
338 html
.push( '>', CKEDITOR
.tools
.htmlEncode( me
._
['default'] ), '</textarea></div>' );
339 return html
.join( '' );
341 CKEDITOR
.ui
.dialog
.labeledElement
.call( this, dialog
, elementDefinition
, htmlList
, innerHTML
);
345 * A single checkbox with a label on the right.
347 * @extends CKEDITOR.ui.dialog.uiElement
349 * @param {CKEDITOR.dialog} dialog
350 * Parent dialog object.
351 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
352 * The element definition. Accepted fields:
354 * <li><strong>checked</strong> (Optional) Whether the checkbox is checked
355 * on instantiation. Defaults to false.</li>
356 * <li><strong>validate</strong> (Optional) The validation function.</li>
357 * <li><strong>label</strong> (Optional) The checkbox label.</li>
359 * @param {Array} htmlList
360 * List of HTML code to output to.
362 checkbox : function( dialog
, elementDefinition
, htmlList
)
364 if ( arguments
.length
< 3 )
367 var _
= initPrivateObject
.call( this, elementDefinition
, { 'default' : !!elementDefinition
[ 'default' ] } );
369 if ( elementDefinition
.validate
)
370 this.validate
= elementDefinition
.validate
;
373 var innerHTML = function()
375 var myDefinition
= CKEDITOR
.tools
.extend( {}, elementDefinition
,
377 id
: elementDefinition
.id
? elementDefinition
.id
+ '_checkbox' : CKEDITOR
.tools
.getNextId() + '_checkbox'
381 var labelId
= CKEDITOR
.tools
.getNextId() + '_label';
382 var attributes
= { 'class' : 'cke_dialog_ui_checkbox_input', type
: 'checkbox', 'aria-labelledby' : labelId
};
383 cleanInnerDefinition( myDefinition
);
384 if ( elementDefinition
[ 'default' ] )
385 attributes
.checked
= 'checked';
387 if ( typeof myDefinition
.inputStyle
!= 'undefined' )
388 myDefinition
.style
= myDefinition
.inputStyle
;
390 _
.checkbox
= new CKEDITOR
.ui
.dialog
.uiElement( dialog
, myDefinition
, html
, 'input', null, attributes
);
391 html
.push( ' <label id="', labelId
, '" for="', attributes
.id
, '"' + ( elementDefinition
.labelStyle
? ' style="' + elementDefinition
.labelStyle
+ '"' : '' ) + '>',
392 CKEDITOR
.tools
.htmlEncode( elementDefinition
.label
),
394 return html
.join( '' );
397 CKEDITOR
.ui
.dialog
.uiElement
.call( this, dialog
, elementDefinition
, htmlList
, 'span', null, null, innerHTML
);
401 * A group of radio buttons.
404 * @extends CKEDITOR.ui.dialog.labeledElement
405 * @param {CKEDITOR.dialog} dialog
406 * Parent dialog object.
407 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
408 * The element definition. Accepted fields:
410 * <li><strong>default</strong> (Required) The default value.</li>
411 * <li><strong>validate</strong> (Optional) The validation function.</li>
412 * <li><strong>items</strong> (Required) An array of options. Each option
413 * is a 1- or 2-item array of format [ 'Description', 'Value' ]. If 'Value'
414 * is missing, then the value would be assumed to be the same as the
417 * @param {Array} htmlList
418 * List of HTML code to output to.
420 radio : function( dialog
, elementDefinition
, htmlList
)
422 if ( arguments
.length
< 3)
425 initPrivateObject
.call( this, elementDefinition
);
426 if ( !this._
['default'] )
427 this._
['default'] = this._
.initValue
= elementDefinition
.items
[0][1];
428 if ( elementDefinition
.validate
)
429 this.validate
= elementDefinition
.valdiate
;
430 var children
= [], me
= this;
433 var innerHTML = function()
435 var inputHtmlList
= [], html
= [],
436 commonAttributes
= { 'class' : 'cke_dialog_ui_radio_item', 'aria-labelledby' : this._
.labelId
},
437 commonName
= elementDefinition
.id
? elementDefinition
.id
+ '_radio' : CKEDITOR
.tools
.getNextId() + '_radio';
438 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 inputDefinition
= CKEDITOR
.tools
.extend( {}, elementDefinition
,
451 labelDefinition
= CKEDITOR
.tools
.extend( {}, inputDefinition
,
458 'class' : 'cke_dialog_ui_radio_input',
461 'aria-labelledby' : labelId
464 if ( me
._
['default'] == value
)
465 inputAttributes
.checked
= 'checked';
466 cleanInnerDefinition( inputDefinition
);
467 cleanInnerDefinition( labelDefinition
);
469 if ( typeof inputDefinition
.inputStyle
!= 'undefined' )
470 inputDefinition
.style
= inputDefinition
.inputStyle
;
472 children
.push( new CKEDITOR
.ui
.dialog
.uiElement( dialog
, inputDefinition
, inputHtml
, 'input', null, inputAttributes
) );
473 inputHtml
.push( ' ' );
474 new CKEDITOR
.ui
.dialog
.uiElement( dialog
, labelDefinition
, inputHtml
, 'label', null, { id
: labelId
, 'for' : inputAttributes
.id
},
476 inputHtmlList
.push( inputHtml
.join( '' ) );
478 new CKEDITOR
.ui
.dialog
.hbox( dialog
, [], inputHtmlList
, html
);
479 return html
.join( '' );
482 CKEDITOR
.ui
.dialog
.labeledElement
.call( this, dialog
, elementDefinition
, htmlList
, innerHTML
);
483 this._
.children
= children
;
487 * A button with a label inside.
490 * @extends CKEDITOR.ui.dialog.uiElement
491 * @param {CKEDITOR.dialog} dialog
492 * Parent dialog object.
493 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
494 * The element definition. Accepted fields:
496 * <li><strong>label</strong> (Required) The button label.</li>
497 * <li><strong>disabled</strong> (Optional) Set to true if you want the
498 * button to appear in disabled state.</li>
500 * @param {Array} htmlList
501 * List of HTML code to output to.
503 button : function( dialog
, elementDefinition
, htmlList
)
505 if ( !arguments
.length
)
508 if ( typeof elementDefinition
== 'function' )
509 elementDefinition
= elementDefinition( dialog
.getParentEditor() );
511 initPrivateObject
.call( this, elementDefinition
, { disabled
: elementDefinition
.disabled
|| false } );
513 // Add OnClick event to this input.
514 CKEDITOR
.event
.implementOn( this );
518 // Register an event handler for processing button clicks.
519 dialog
.on( 'load', function( eventInfo
)
521 var element
= this.getElement();
525 element
.on( 'click', function( evt
)
527 me
.fire( 'click', { dialog
: me
.getDialog() } );
528 evt
.data
.preventDefault();
531 element
.on( 'keydown', function( evt
)
533 if ( evt
.data
.getKeystroke() in { 32:1 } )
536 evt
.data
.preventDefault();
541 element
.unselectable();
544 var outerDefinition
= CKEDITOR
.tools
.extend( {}, elementDefinition
);
545 delete outerDefinition
.style
;
547 var labelId
= CKEDITOR
.tools
.getNextId() + '_label';
548 CKEDITOR
.ui
.dialog
.uiElement
.call(
556 style
: elementDefinition
.style
,
557 href
: 'javascript:void(0)',
558 title
: elementDefinition
.label
,
560 'class' : elementDefinition
['class'],
562 'aria-labelledby' : labelId
564 '<span id="' + labelId
+ '" class="cke_dialog_ui_button">' +
565 CKEDITOR
.tools
.htmlEncode( elementDefinition
.label
) +
571 * @extends CKEDITOR.ui.dialog.uiElement
574 * @param {CKEDITOR.dialog} dialog
575 * Parent dialog object.
576 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
577 * The element definition. Accepted fields:
579 * <li><strong>default</strong> (Required) The default value.</li>
580 * <li><strong>validate</strong> (Optional) The validation function.</li>
581 * <li><strong>items</strong> (Required) An array of options. Each option
582 * is a 1- or 2-item array of format [ 'Description', 'Value' ]. If 'Value'
583 * is missing, then the value would be assumed to be the same as the
585 * <li><strong>multiple</strong> (Optional) Set this to true if you'd like
586 * to have a multiple-choice select box.</li>
587 * <li><strong>size</strong> (Optional) The number of items to display in
588 * the select box.</li>
590 * @param {Array} htmlList
591 * List of HTML code to output to.
593 select : function( dialog
, elementDefinition
, htmlList
)
595 if ( arguments
.length
< 3 )
598 var _
= initPrivateObject
.call( this, elementDefinition
);
600 if ( elementDefinition
.validate
)
601 this.validate
= elementDefinition
.validate
;
603 _
.inputId
= CKEDITOR
.tools
.getNextId() + '_select';
605 var innerHTML = function()
607 var myDefinition
= CKEDITOR
.tools
.extend( {}, elementDefinition
,
609 id
: elementDefinition
.id
? elementDefinition
.id
+ '_select' : CKEDITOR
.tools
.getNextId() + '_select'
613 attributes
= { 'id' : _
.inputId
, 'class' : 'cke_dialog_ui_input_select', 'aria-labelledby' : this._
.labelId
};
615 // Add multiple and size attributes from element definition.
616 if ( elementDefinition
.size
!= undefined )
617 attributes
.size
= elementDefinition
.size
;
618 if ( elementDefinition
.multiple
!= undefined )
619 attributes
.multiple
= elementDefinition
.multiple
;
621 cleanInnerDefinition( myDefinition
);
622 for ( var i
= 0, item
; i
< elementDefinition
.items
.length
&& ( item
= elementDefinition
.items
[i
] ) ; i
++ )
624 innerHTML
.push( '<option value="',
625 CKEDITOR
.tools
.htmlEncode( item
[1] !== undefined ? item
[1] : item
[0] ).replace( /"/g, '"' ), '" /> ',
626 CKEDITOR.tools.htmlEncode( item[0] ) );
629 if ( typeof myDefinition.inputStyle != 'undefined' )
630 myDefinition.style = myDefinition.inputStyle;
632 _.select = new CKEDITOR.ui.dialog.uiElement( dialog, myDefinition, html, 'select
', null, attributes, innerHTML.join( '' ) );
633 return html.join( '' );
636 CKEDITOR.ui.dialog.labeledElement.call( this, dialog, elementDefinition, htmlList, innerHTML );
640 * A file upload input.
641 * @extends CKEDITOR.ui.dialog.labeledElement
644 * @param {CKEDITOR.dialog} dialog
645 * Parent dialog object.
646 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
647 * The element definition. Accepted fields:
649 * <li><strong>validate</strong> (Optional) The validation function.</li>
651 * @param {Array} htmlList
652 * List of HTML code to output to.
654 file : function( dialog, elementDefinition, htmlList )
656 if ( arguments.length < 3 )
659 if ( elementDefinition['default'] === undefined )
660 elementDefinition['default'] = '';
662 var _ = CKEDITOR.tools.extend( initPrivateObject.call( this, elementDefinition ), { definition : elementDefinition, buttons : [] } );
664 if ( elementDefinition.validate )
665 this.validate = elementDefinition.validate;
668 var innerHTML = function()
670 _.frameId = CKEDITOR.tools.getNextId() + '_fileInput
';
672 // Support for custom document.domain in IE.
673 var isCustomDomain = CKEDITOR.env.isCustomDomain();
678 ' allowtransparency
="0"' +
679 ' class="cke_dialog_ui_input_file"' +
680 ' id
="', _.frameId, '"' +
681 ' title
="', elementDefinition.label, '"' +
682 ' src
="javascript:void(' ];
688 'document.domain=\'' + document.domain + '\';' +
689 'document.close();' +
698 return html.join( '' );
701 // IE BUG: Parent container does not resize to contain the iframe automatically.
702 dialog.on( 'load
', function()
704 var iframe = CKEDITOR.document.getById( _.frameId ),
705 contentDiv = iframe.getParent();
706 contentDiv.addClass( 'cke_dialog_ui_input_file
' );
709 CKEDITOR.ui.dialog.labeledElement.call( this, dialog, elementDefinition, htmlList, innerHTML );
713 * A button for submitting the file in a file upload input.
714 * @extends CKEDITOR.ui.dialog.button
717 * @param {CKEDITOR.dialog} dialog
718 * Parent dialog object.
719 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
720 * The element definition. Accepted fields:
722 * <li><strong>for</strong> (Required) The file input's page and element Id
723 * to associate to
, in a
2-item array format
: [ 'page_id', 'element_id' ].
725 * <li
><strong
>validate
</strong> (Optional) The validation function.</li>
727 * @param
{Array
} htmlList
728 * List
of HTML code to output to
.
730 fileButton : function( dialog
, elementDefinition
, htmlList
)
732 if ( arguments
.length
< 3 )
735 var _
= initPrivateObject
.call( this, elementDefinition
),
738 if ( elementDefinition
.validate
)
739 this.validate
= elementDefinition
.validate
;
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
)
746 var target
= elementDefinition
[ 'for' ]; // [ pageId, elementId ]
747 if ( !onClick
|| onClick
.call( this, evt
) !== false )
749 dialog
.getContentElement( target
[0], target
[1] ).submit();
754 dialog
.on( 'load', function()
756 dialog
.getContentElement( elementDefinition
[ 'for' ][0], elementDefinition
[ 'for' ][1] )._
.buttons
.push( me
);
759 CKEDITOR
.ui
.dialog
.button
.call( this, dialog
, myDefinition
, htmlList
);
764 var myHtmlRe
= /^\s*<[\w:]+\s+([^>]*)?>/,
765 theirHtmlRe
= /^(\s*<[\w:]+(?:\s+[^>]*)?)((?:.|\r|\n)+)$/,
768 * A dialog element made from raw HTML code.
769 * @extends CKEDITOR.ui.dialog.uiElement
770 * @name CKEDITOR.ui.dialog.html
771 * @param {CKEDITOR.dialog} dialog Parent dialog object.
772 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition Element definition.
775 * <li><strong>html</strong> (Required) HTML code of this element.</li>
777 * @param {Array} htmlList List of HTML code to be added to the dialog's content area.
781 return function( dialog
, elementDefinition
, htmlList
)
783 if ( arguments
.length
< 3 )
788 theirHtml
= elementDefinition
.html
,
791 // If the HTML input doesn't contain any tags at the beginning, add a <span> tag around it.
792 if ( theirHtml
.charAt( 0 ) != '<' )
793 theirHtml
= '<span>' + theirHtml
+ '</span>';
795 // Look for focus function in definition.
796 var focus
= elementDefinition
.focus
;
799 var oldFocus
= this.focus
;
800 this.focus = function()
802 oldFocus
.call( this );
803 typeof focus
== 'function' && focus
.call( this );
804 this.fire( 'focus' );
806 if ( elementDefinition
.isFocusable
)
808 var oldIsFocusable
= this.isFocusable
;
809 this.isFocusable
= oldIsFocusable
;
811 this.keyboardFocusable
= true;
814 CKEDITOR
.ui
.dialog
.uiElement
.call( this, dialog
, elementDefinition
, myHtmlList
, 'span', null, null, '' );
816 // Append the attributes created by the uiElement call to the real HTML.
817 myHtml
= myHtmlList
.join( '' );
818 myMatch
= myHtml
.match( myHtmlRe
);
819 theirMatch
= theirHtml
.match( theirHtmlRe
) || [ '', '', '' ];
821 if ( emptyTagRe
.test( theirMatch
[1] ) )
823 theirMatch
[1] = theirMatch
[1].slice( 0, -1 );
824 theirMatch
[2] = '/' + theirMatch
[2];
827 htmlList
.push( [ theirMatch
[1], ' ', myMatch
[1] || '', theirMatch
[2] ].join( '' ) );
832 * Form fieldset for grouping dialog UI elements.
834 * @extends CKEDITOR.ui.dialog.uiElement
835 * @param {CKEDITOR.dialog} dialog Parent dialog object.
836 * @param {Array} childObjList
837 * Array of {@link CKEDITOR.ui.dialog.uiElement} objects inside this
839 * @param {Array} childHtmlList
840 * Array of HTML code that correspond to the HTML output of all the
841 * objects in childObjList.
842 * @param {Array} htmlList
843 * Array of HTML code that this element will output to.
844 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
845 * The element definition. Accepted fields:
847 * <li><strong>label</strong> (Optional) The legend of the this fieldset.</li>
848 * <li><strong>children</strong> (Required) An array of dialog field definitions which will be grouped inside this fieldset. </li>
851 fieldset : function( dialog
, childObjList
, childHtmlList
, htmlList
, elementDefinition
)
853 var legendLabel
= elementDefinition
.label
;
855 var innerHTML = function()
858 legendLabel
&& html
.push( '<legend>' + legendLabel
+ '</legend>' );
859 for ( var i
= 0; i
< childHtmlList
.length
; i
++ )
860 html
.push( childHtmlList
[ i
] );
861 return html
.join( '' );
864 this._
= { children
: childObjList
};
865 CKEDITOR
.ui
.dialog
.uiElement
.call( this, dialog
, elementDefinition
, htmlList
, 'fieldset', null, null, innerHTML
);
870 CKEDITOR
.ui
.dialog
.html
.prototype = new CKEDITOR
.ui
.dialog
.uiElement
;
872 CKEDITOR
.ui
.dialog
.labeledElement
.prototype = CKEDITOR
.tools
.extend( new CKEDITOR
.ui
.dialog
.uiElement
,
873 /** @lends CKEDITOR.ui.dialog.labeledElement.prototype */
876 * Sets the label text of the element.
877 * @param {String} label The new label text.
878 * @returns {CKEDITOR.ui.dialog.labeledElement} The current labeled element.
881 setLabel : function( label
)
883 var node
= CKEDITOR
.document
.getById( this._
.labelId
);
884 if ( node
.getChildCount() < 1 )
885 ( new CKEDITOR
.dom
.text( label
, CKEDITOR
.document
) ).appendTo( node
);
887 node
.getChild( 0 ).$.nodeValue
= label
;
892 * Retrieves the current label text of the elment.
893 * @returns {String} The current label text.
896 getLabel : function()
898 var node
= CKEDITOR
.document
.getById( this._
.labelId
);
899 if ( !node
|| node
.getChildCount() < 1 )
902 return node
.getChild( 0 ).getText();
906 * Defines the onChange event for UI element definitions.
911 eventProcessors
: commonEventProcessors
914 CKEDITOR
.ui
.dialog
.button
.prototype = CKEDITOR
.tools
.extend( new CKEDITOR
.ui
.dialog
.uiElement
,
915 /** @lends CKEDITOR.ui.dialog.button.prototype */
918 * Simulates a click to the button.
920 * @returns {Object} Return value of the 'click' event.
924 if ( !this._
.disabled
)
925 return this.fire( 'click', { dialog
: this._
.dialog
} );
926 this.getElement().$.blur();
931 * Enables the button.
936 this._
.disabled
= false;
937 var element
= this.getElement();
938 element
&& element
.removeClass( 'cke_disabled' );
942 * Disables the button.
947 this._
.disabled
= true;
948 this.getElement().addClass( 'cke_disabled' );
951 isVisible : function()
953 return this.getElement().getFirst().isVisible();
956 isEnabled : function()
958 return !this._
.disabled
;
962 * Defines the onChange event and onClick for button element definitions.
967 eventProcessors
: CKEDITOR
.tools
.extend( {}, CKEDITOR
.ui
.dialog
.uiElement
.prototype.eventProcessors
,
970 onClick : function( dialog
, func
)
972 this.on( 'click', func
);
977 * Handler for the element's access key up event. Simulates a click to
981 accessKeyUp : function()
987 * Handler for the element's access key down event. Simulates a mouse
988 * down to the button.
991 accessKeyDown : function()
996 keyboardFocusable
: true
999 CKEDITOR
.ui
.dialog
.textInput
.prototype = CKEDITOR
.tools
.extend( new CKEDITOR
.ui
.dialog
.labeledElement
,
1000 /** @lends CKEDITOR.ui.dialog.textInput.prototype */
1003 * Gets the text input DOM element under this UI object.
1005 * @returns {CKEDITOR.dom.element} The DOM element of the text input.
1007 getInputElement : function()
1009 return CKEDITOR
.document
.getById( this._
.inputId
);
1013 * Puts focus into the text input.
1018 var me
= this.selectParentTab();
1020 // GECKO BUG: setTimeout() is needed to workaround invisible selections.
1021 setTimeout( function()
1023 var element
= me
.getInputElement();
1024 element
&& element
.$.focus();
1029 * Selects all the text in the text input.
1034 var me
= this.selectParentTab();
1036 // GECKO BUG: setTimeout() is needed to workaround invisible selections.
1037 setTimeout( function()
1039 var e
= me
.getInputElement();
1049 * Handler for the text input's access key up event. Makes a select()
1050 * call to the text input.
1053 accessKeyUp : function()
1059 * Sets the value of this text input object.
1060 * @param {Object} value The new value.
1061 * @returns {CKEDITOR.ui.dialog.textInput} The current UI element.
1063 * uiElement.setValue( 'Blamo' );
1065 setValue : function( value
)
1067 !value
&& ( value
= '' );
1068 return CKEDITOR
.ui
.dialog
.uiElement
.prototype.setValue
.apply( this, arguments
);
1071 keyboardFocusable
: true
1072 }, commonPrototype
, true );
1074 CKEDITOR
.ui
.dialog
.textarea
.prototype = new CKEDITOR
.ui
.dialog
.textInput();
1076 CKEDITOR
.ui
.dialog
.select
.prototype = CKEDITOR
.tools
.extend( new CKEDITOR
.ui
.dialog
.labeledElement
,
1077 /** @lends CKEDITOR.ui.dialog.select.prototype */
1080 * Gets the DOM element of the select box.
1081 * @returns {CKEDITOR.dom.element} The <select> element of this UI
1085 getInputElement : function()
1087 return this._
.select
.getElement();
1091 * Adds an option to the select box.
1092 * @param {String} label Option label.
1093 * @param {String} value (Optional) Option value, if not defined it'll be
1094 * assumed to be the same as the label.
1095 * @param {Number} index (Optional) Position of the option to be inserted
1096 * to. If not defined the new option will be inserted to the end of list.
1098 * @returns {CKEDITOR.ui.dialog.select} The current select UI element.
1100 add : function( label
, value
, index
)
1102 var option
= new CKEDITOR
.dom
.element( 'option', this.getDialog().getParentEditor().document
),
1103 selectElement
= this.getInputElement().$;
1104 option
.$.text
= label
;
1105 option
.$.value
= ( value
=== undefined || value
=== null ) ? label
: value
;
1106 if ( index
=== undefined || index
=== null )
1108 if ( CKEDITOR
.env
.ie
)
1109 selectElement
.add( option
.$ );
1111 selectElement
.add( option
.$, null );
1114 selectElement
.add( option
.$, index
);
1119 * Removes an option from the selection list.
1120 * @param {Number} index Index of the option to be removed.
1122 * @returns {CKEDITOR.ui.dialog.select} The current select UI element.
1124 remove : function( index
)
1126 var selectElement
= this.getInputElement().$;
1127 selectElement
.remove( index
);
1132 * Clears all options out of the selection list.
1133 * @returns {CKEDITOR.ui.dialog.select} The current select UI element.
1137 var selectElement
= this.getInputElement().$;
1138 while ( selectElement
.length
> 0 )
1139 selectElement
.remove( 0 );
1143 keyboardFocusable
: true
1144 }, commonPrototype
, true );
1146 CKEDITOR
.ui
.dialog
.checkbox
.prototype = CKEDITOR
.tools
.extend( new CKEDITOR
.ui
.dialog
.uiElement
,
1147 /** @lends CKEDITOR.ui.dialog.checkbox.prototype */
1150 * Gets the checkbox DOM element.
1152 * @returns {CKEDITOR.dom.element} The DOM element of the checkbox.
1154 getInputElement : function()
1156 return this._
.checkbox
.getElement();
1160 * Sets the state of the checkbox.
1162 * @param {Boolean} true to tick the checkbox, false to untick it.
1163 * @param {Boolean} noChangeEvent Internal commit, to supress 'change' event on this element.
1165 setValue : function( checked
, noChangeEvent
)
1167 this.getInputElement().$.checked
= checked
;
1168 !noChangeEvent
&& this.fire( 'change', { value
: checked
} );
1172 * Gets the state of the checkbox.
1174 * @returns {Boolean} true means the checkbox is ticked, false means it's not ticked.
1176 getValue : function()
1178 return this.getInputElement().$.checked
;
1182 * Handler for the access key up event. Toggles the checkbox.
1185 accessKeyUp : function()
1187 this.setValue( !this.getValue() );
1191 * Defines the onChange event for UI element definitions.
1198 onChange : function( dialog
, func
)
1200 if ( !CKEDITOR
.env
.ie
)
1201 return commonEventProcessors
.onChange
.apply( this, arguments
);
1204 dialog
.on( 'load', function()
1206 var element
= this._
.checkbox
.getElement();
1207 element
.on( 'propertychange', function( evt
)
1210 if ( evt
.propertyName
== 'checked' )
1211 this.fire( 'change', { value
: element
.$.checked
} );
1214 this.on( 'change', func
);
1220 keyboardFocusable
: true
1221 }, commonPrototype
, true );
1223 CKEDITOR
.ui
.dialog
.radio
.prototype = CKEDITOR
.tools
.extend( new CKEDITOR
.ui
.dialog
.uiElement
,
1224 /** @lends CKEDITOR.ui.dialog.radio.prototype */
1227 * Checks one of the radio buttons in this button group.
1229 * @param {String} value The value of the button to be chcked.
1230 * @param {Boolean} noChangeEvent Internal commit, to supress 'change' event on this element.
1232 setValue : function( value
, noChangeEvent
)
1234 var children
= this._
.children
,
1236 for ( var i
= 0 ; ( i
< children
.length
) && ( item
= children
[i
] ) ; i
++ )
1237 item
.getElement().$.checked
= ( item
.getValue() == value
);
1238 !noChangeEvent
&& this.fire( 'change', { value
: value
} );
1242 * Gets the value of the currently checked radio button.
1244 * @returns {String} The currently checked button's value.
1246 getValue : function()
1248 var children
= this._
.children
;
1249 for ( var i
= 0 ; i
< children
.length
; i
++ )
1251 if ( children
[i
].getElement().$.checked
)
1252 return children
[i
].getValue();
1258 * Handler for the access key up event. Focuses the currently
1259 * selected radio button, or the first radio button if none is
1263 accessKeyUp : function()
1265 var children
= this._
.children
, i
;
1266 for ( i
= 0 ; i
< children
.length
; i
++ )
1268 if ( children
[i
].getElement().$.checked
)
1270 children
[i
].getElement().focus();
1274 children
[0].getElement().focus();
1278 * Defines the onChange event for UI element definitions.
1285 onChange : function( dialog
, func
)
1287 if ( !CKEDITOR
.env
.ie
)
1288 return commonEventProcessors
.onChange
.apply( this, arguments
);
1291 dialog
.on( 'load', function()
1293 var children
= this._
.children
, me
= this;
1294 for ( var i
= 0 ; i
< children
.length
; i
++ )
1296 var element
= children
[i
].getElement();
1297 element
.on( 'propertychange', function( evt
)
1300 if ( evt
.propertyName
== 'checked' && this.$.checked
)
1301 me
.fire( 'change', { value
: this.getAttribute( 'value' ) } );
1305 this.on( 'change', func
);
1311 keyboardFocusable
: true
1312 }, commonPrototype
, true );
1314 CKEDITOR
.ui
.dialog
.file
.prototype = CKEDITOR
.tools
.extend( new CKEDITOR
.ui
.dialog
.labeledElement
,
1316 /** @lends CKEDITOR.ui.dialog.file.prototype */
1319 * Gets the <input> element of this file input.
1320 * @returns {CKEDITOR.dom.element} The file input element.
1323 getInputElement : function()
1325 var frameDocument
= CKEDITOR
.document
.getById( this._
.frameId
).getFrameDocument();
1326 return frameDocument
.$.forms
.length
> 0 ?
1327 new CKEDITOR
.dom
.element( frameDocument
.$.forms
[0].elements
[0] ) :
1332 * Uploads the file in the file input.
1333 * @returns {CKEDITOR.ui.dialog.file} This object.
1338 this.getInputElement().getParent().$.submit();
1343 * Get the action assigned to the form.
1344 * @returns {String} The value of the action.
1347 getAction : function()
1349 return this.getInputElement().getParent().$.action
;
1353 * The events must be applied on the inner input element, and
1354 * that must be done when the iframe & form has been loaded
1356 registerEvents : function( definition
)
1358 var regex
= /^on([A-Z]\w+)/,
1361 var registerDomEvent = function( uiElement
, dialog
, eventName
, func
)
1363 uiElement
.on( 'formLoaded', function()
1365 uiElement
.getInputElement().on( eventName
, func
, uiElement
);
1369 for ( var i
in definition
)
1371 if ( !( match
= i
.match( regex
) ) )
1374 if ( this.eventProcessors
[i
] )
1375 this.eventProcessors
[i
].call( this, this._
.dialog
, definition
[i
] );
1377 registerDomEvent( this, this._
.dialog
, match
[1].toLowerCase(), definition
[i
] );
1384 * Redraws the file input and resets the file path in the file input.
1385 * The redraw logic is necessary because non-IE browsers tend to clear
1386 * the <iframe> containing the file input after closing the dialog.
1392 frameElement
= CKEDITOR
.document
.getById( _
.frameId
),
1393 frameDocument
= frameElement
.getFrameDocument(),
1394 elementDefinition
= _
.definition
,
1395 buttons
= _
.buttons
,
1396 callNumber
= this.formLoadedNumber
,
1397 unloadNumber
= this.formUnloadNumber
,
1398 langDir
= _
.dialog
._
.editor
.lang
.dir
,
1399 langCode
= _
.dialog
._
.editor
.langCode
;
1401 // The callback function for the iframe, but we must call tools.addFunction only once
1402 // so we store the function number in this.formLoadedNumber
1405 callNumber
= this.formLoadedNumber
= CKEDITOR
.tools
.addFunction(
1408 // Now we can apply the events to the input type=file
1409 this.fire( 'formLoaded' ) ;
1412 // Remove listeners attached to the content of the iframe (the file input)
1413 unloadNumber
= this.formUnloadNumber
= CKEDITOR
.tools
.addFunction(
1416 this.getInputElement().clearCustomData();
1419 this.getDialog()._
.editor
.on( 'destroy', function()
1421 CKEDITOR
.tools
.removeFunction( callNumber
);
1422 CKEDITOR
.tools
.removeFunction( unloadNumber
);
1426 function generateFormField()
1428 frameDocument
.$.open();
1430 // Support for custom document.domain in IE.
1431 if ( CKEDITOR
.env
.isCustomDomain() )
1432 frameDocument
.$.domain
= document
.domain
;
1435 if ( elementDefinition
.size
)
1436 size
= elementDefinition
.size
- ( CKEDITOR
.env
.ie
? 7 : 0 ); // "Browse" button is bigger in IE.
1438 frameDocument
.$.write( [ '<html dir="' + langDir
+ '" lang="' + langCode
+ '"><head><title></title></head><body style="margin: 0; overflow: hidden; background: transparent;">',
1439 '<form enctype="multipart/form-data" method="POST" dir="' + langDir
+ '" lang="' + langCode
+ '" action="',
1440 CKEDITOR
.tools
.htmlEncode( elementDefinition
.action
),
1442 '<input type="file" name="',
1443 CKEDITOR
.tools
.htmlEncode( elementDefinition
.id
|| 'cke_upload' ),
1445 CKEDITOR
.tools
.htmlEncode( size
> 0 ? size
: "" ),
1449 '<script>window.parent.CKEDITOR.tools.callFunction(' + callNumber
+ ');',
1450 'window.onbeforeunload = function() {window.parent.CKEDITOR.tools.callFunction(' + unloadNumber
+ ')}</script>' ].join( '' ) );
1452 frameDocument
.$.close();
1454 for ( var i
= 0 ; i
< buttons
.length
; i
++ )
1455 buttons
[i
].enable();
1458 // #3465: Wait for the browser to finish rendering the dialog first.
1459 if ( CKEDITOR
.env
.gecko
)
1460 setTimeout( generateFormField
, 500 );
1462 generateFormField();
1465 getValue : function()
1467 return this.getInputElement().$.value
|| '';
1471 * The default value of input type="file" is an empty string, but during initialization
1472 * of this UI element, the iframe still isn't ready so it can't be read from that object
1473 * Setting it manually prevents later issues about the current value ("") being different
1474 * of the initial value (undefined as it asked for .value of a div)
1476 setInitValue : function()
1478 this._
.initValue
= '';
1482 * Defines the onChange event for UI element definitions.
1489 onChange : function( dialog
, func
)
1491 // If this method is called several times (I'm not sure about how this can happen but the default
1492 // onChange processor includes this protection)
1493 // In order to reapply to the new element, the property is deleted at the beggining of the registerEvents method
1494 if ( !this._
.domOnChangeRegistered
)
1496 // By listening for the formLoaded event, this handler will get reapplied when a new
1498 this.on( 'formLoaded', function()
1500 this.getInputElement().on( 'change', function(){ this.fire( 'change', { value
: this.getValue() } ); }, this );
1502 this._
.domOnChangeRegistered
= true;
1505 this.on( 'change', func
);
1509 keyboardFocusable
: true
1512 CKEDITOR
.ui
.dialog
.fileButton
.prototype = new CKEDITOR
.ui
.dialog
.button
;
1514 CKEDITOR
.ui
.dialog
.fieldset
.prototype = CKEDITOR
.tools
.clone( CKEDITOR
.ui
.dialog
.hbox
.prototype );
1516 CKEDITOR
.dialog
.addUIElement( 'text', textBuilder
);
1517 CKEDITOR
.dialog
.addUIElement( 'password', textBuilder
);
1518 CKEDITOR
.dialog
.addUIElement( 'textarea', commonBuilder
);
1519 CKEDITOR
.dialog
.addUIElement( 'checkbox', commonBuilder
);
1520 CKEDITOR
.dialog
.addUIElement( 'radio', commonBuilder
);
1521 CKEDITOR
.dialog
.addUIElement( 'button', commonBuilder
);
1522 CKEDITOR
.dialog
.addUIElement( 'select', commonBuilder
);
1523 CKEDITOR
.dialog
.addUIElement( 'file', commonBuilder
);
1524 CKEDITOR
.dialog
.addUIElement( 'fileButton', commonBuilder
);
1525 CKEDITOR
.dialog
.addUIElement( 'html', commonBuilder
);
1526 CKEDITOR
.dialog
.addUIElement( 'fieldset', containerBuilder
);
1530 * Fired when the value of the uiElement is changed
1531 * @name CKEDITOR.ui.dialog.uiElement#change
1536 * Fired when the inner frame created by the element is ready.
1537 * Each time the button is used or the dialog is loaded a new
1538 * form might be created.
1539 * @name CKEDITOR.ui.dialog.fileButton#formLoaded