{\r
dialog.on( 'load', function()\r
{\r
- this.getInputElement().on( 'change', function(){ this.fire( 'change', { value : this.getValue() } ); }, this );\r
+ this.getInputElement().on( 'change', function()\r
+ {\r
+ // Make sure 'onchange' doesn't get fired after dialog closed. (#5719)\r
+ if ( !dialog.parts.dialog.isVisible() )\r
+ return;\r
+\r
+ this.fire( 'change', { value : this.getValue() } );\r
+ }, this );\r
}, this );\r
this._.domOnChangeRegistered = true;\r
}\r
/** @ignore */\r
var innerHTML = function()\r
{\r
- var html = [];\r
+ var html = [],\r
+ requiredClass = elementDefinition.required ? ' cke_required' : '' ;\r
if ( elementDefinition.labelLayout != 'horizontal' )\r
- html.push( '<label class="cke_dialog_ui_labeled_label" ',\r
+ html.push( '<label class="cke_dialog_ui_labeled_label' + requiredClass + '" ',\r
' id="'+ _.labelId + '"',\r
' for="' + _.inputId + '"',\r
' style="' + elementDefinition.labelStyle + '">',\r
[\r
{\r
type : 'html',\r
- html : '<label class="cke_dialog_ui_labeled_label"' +\r
+ html : '<label class="cke_dialog_ui_labeled_label' + requiredClass + '"' +\r
' id="' + _.labelId + '"' +\r
' for="' + _.inputId + '"' +\r
' style="' + elementDefinition.labelStyle + '">' +\r
if ( elementDefinition.size )\r
attributes.size = elementDefinition.size;\r
\r
+ if ( elementDefinition.controlStyle )\r
+ attributes.style = elementDefinition.controlStyle;\r
+\r
// If user presses Enter in a text box, it implies clicking OK for the dialog.\r
var me = this, keyPressedOnMe = false;\r
dialog.on( 'load', function()\r
cleanInnerDefinition( myDefinition );\r
if ( elementDefinition[ 'default' ] )\r
attributes.checked = 'checked';\r
+\r
+ if (typeof myDefinition.controlStyle != 'undefined')\r
+ myDefinition.style = myDefinition.controlStyle;\r
+\r
_.checkbox = new CKEDITOR.ui.dialog.uiElement( dialog, myDefinition, html, 'input', null, attributes );\r
html.push( ' <label id="', labelId, '" for="', attributes.id, '">',\r
CKEDITOR.tools.htmlEncode( elementDefinition.label ),\r
inputAttributes.checked = 'checked';\r
cleanInnerDefinition( inputDefinition );\r
cleanInnerDefinition( labelDefinition );\r
+\r
+ if (typeof inputDefinition.controlStyle != 'undefined')\r
+ inputDefinition.style = inputDefinition.controlStyle;\r
+\r
children.push( new CKEDITOR.ui.dialog.uiElement( dialog, inputDefinition, inputHtml, 'input', null, inputAttributes ) );\r
inputHtml.push( ' ' );\r
new CKEDITOR.ui.dialog.uiElement( dialog, labelDefinition, inputHtml, 'label', null, { id : labelId, 'for' : inputAttributes.id },\r
\r
element.on( 'keydown', function( evt )\r
{\r
- if ( evt.data.getKeystroke() in { 32:1, 13:1 } )\r
+ if ( evt.data.getKeystroke() in { 32:1 } )\r
{\r
me.click();\r
evt.data.preventDefault();\r
CKEDITOR.tools.htmlEncode( item[0] ) );\r
}\r
\r
+ if (typeof myDefinition.controlStyle != 'undefined')\r
+ myDefinition.style = myDefinition.controlStyle;\r
+\r
_.select = new CKEDITOR.ui.dialog.uiElement( dialog, myDefinition, html, 'select', null, attributes, innerHTML.join( '' ) );\r
return html.join( '' );\r
};\r
* @returns {String} The value of the action.\r
* @example\r
*/\r
- getAction : function( action )\r
+ getAction : function()\r
{\r
return this.getInputElement().getParent().$.action;\r
},\r
\r
/**\r
+ * The events must be applied on the inner input element, and\r
+ * that must be done when the iframe & form has been loaded\r
+ */\r
+ registerEvents : function( definition )\r
+ {\r
+ var regex = /^on([A-Z]\w+)/,\r
+ match;\r
+\r
+ var registerDomEvent = function( uiElement, dialog, eventName, func )\r
+ {\r
+ uiElement.on( 'formLoaded', function()\r
+ {\r
+ uiElement.getInputElement().on( eventName, func, uiElement );\r
+ });\r
+ };\r
+\r
+ for ( var i in definition )\r
+ {\r
+ if ( !( match = i.match( regex ) ) )\r
+ continue;\r
+\r
+ if ( this.eventProcessors[i] )\r
+ this.eventProcessors[i].call( this, this._.dialog, definition[i] );\r
+ else\r
+ registerDomEvent( this, this._.dialog, match[1].toLowerCase(), definition[i] );\r
+ }\r
+\r
+ return this;\r
+ },\r
+\r
+ /**\r
* Redraws the file input and resets the file path in the file input.\r
* The redraw logic is necessary because non-IE browsers tend to clear\r
* the <iframe> containing the file input after closing the dialog.\r
var frameElement = CKEDITOR.document.getById( this._.frameId ),\r
frameDocument = frameElement.getFrameDocument(),\r
elementDefinition = this._.definition,\r
- buttons = this._.buttons;\r
+ buttons = this._.buttons,\r
+ callNumber = this.formLoadedNumber,\r
+ unloadNumber = this.formUnloadNumber,\r
+ langDir = this._.dialog._.editor.lang.dir,\r
+ langCode = this._.dialog._.editor.langCode;\r
+\r
+ // The callback function for the iframe, but we must call tools.addFunction only once\r
+ // so we store the function number in this.formLoadedNumber\r
+ if (!callNumber)\r
+ {\r
+ callNumber = this.formLoadedNumber = CKEDITOR.tools.addFunction(\r
+ function()\r
+ {\r
+ // Now we can apply the events to the input type=file\r
+ this.fire( 'formLoaded' ) ;\r
+ }, this ) ;\r
+\r
+ // Remove listeners attached to the content of the iframe (the file input)\r
+ unloadNumber = this.formUnloadNumber = CKEDITOR.tools.addFunction(\r
+ function()\r
+ {\r
+ this.getInputElement().clearCustomData();\r
+ }, this ) ;\r
+\r
+ this.getDialog()._.editor.on( 'destroy', function()\r
+ {\r
+ CKEDITOR.tools.removeFunction( callNumber );\r
+ CKEDITOR.tools.removeFunction( unloadNumber );\r
+ } );\r
+ }\r
\r
function generateFormField()\r
{\r
if ( elementDefinition.size )\r
size = elementDefinition.size - ( CKEDITOR.env.ie ? 7 : 0 ); // "Browse" button is bigger in IE.\r
\r
- frameDocument.$.write( [ '<html><head><title></title></head><body style="margin: 0; overflow: hidden; background: transparent;">',\r
- '<form enctype="multipart/form-data" method="POST" action="',\r
+ frameDocument.$.write( [ '<html dir="' + langDir + '" lang="' + langCode + '"><head><title></title></head><body style="margin: 0; overflow: hidden; background: transparent;">',\r
+ '<form enctype="multipart/form-data" method="POST" dir="' + langDir + '" lang="' + langCode + '" action="',\r
CKEDITOR.tools.htmlEncode( elementDefinition.action ),\r
'">',\r
'<input type="file" name="',\r
CKEDITOR.tools.htmlEncode( size > 0 ? size : "" ),\r
'" />',\r
'</form>',\r
- '</body></html>' ].join( '' ) );\r
+ '</body></html>',\r
+ '<script>window.parent.CKEDITOR.tools.callFunction(' + callNumber + ');',\r
+ 'window.onbeforeunload = function() {window.parent.CKEDITOR.tools.callFunction(' + unloadNumber + ')}</script>' ].join( '' ) );\r
\r
frameDocument.$.close();\r
\r
\r
getValue : function()\r
{\r
- // The file path returned from the input tag is incomplete anyway, so it's\r
- // safe to ignore it and prevent the confirmation dialog from appearing.\r
- // (Part of #3465)\r
- return '';\r
+ return this.getInputElement().$.value;\r
+ },\r
+\r
+ /***\r
+ * The default value of input type="file" is an empty string, but during initialization\r
+ * of this UI element, the iframe still isn't ready so it can't be read from that object\r
+ * Setting it manually prevents later issues about the current value ("") being different\r
+ * of the initial value (undefined as it asked for .value of a div)\r
+ */\r
+ setInitValue : function()\r
+ {\r
+ this._.initValue = '';\r
},\r
\r
/**\r
* @type Object\r
* @example\r
*/\r
- eventProcessors : commonEventProcessors,\r
+ eventProcessors :\r
+ {\r
+ onChange : function( dialog, func )\r
+ {\r
+ // If this method is called several times (I'm not sure about how this can happen but the default\r
+ // onChange processor includes this protection)\r
+ // In order to reapply to the new element, the property is deleted at the beggining of the registerEvents method\r
+ if ( !this._.domOnChangeRegistered )\r
+ {\r
+ // By listening for the formLoaded event, this handler will get reapplied when a new\r
+ // form is created\r
+ this.on( 'formLoaded', function()\r
+ {\r
+ this.getInputElement().on( 'change', function(){ this.fire( 'change', { value : this.getValue() } ); }, this );\r
+ }, this );\r
+ this._.domOnChangeRegistered = true;\r
+ }\r
+\r
+ this.on( 'change', func );\r
+ }\r
+ },\r
\r
keyboardFocusable : true\r
}, true );\r