jenkins-bot has submitted this change and it was merged. Change subject: Add OO.ui.SelectFileWidget ......................................................................
Add OO.ui.SelectFileWidget Bug: T91146 Change-Id: Ic4db04daf11f3ab461a16ed3a1e9561e82351bc5 --- M build/modules.json M demos/pages/widgets.js M i18n/en.json M i18n/qqq.json M jsduck.json M src/core.js M src/styles/core.less M src/styles/theme.less A src/styles/widgets/SelectFileWidget.less M src/themes/apex/widgets.less M src/themes/blank/widgets.less M src/themes/mediawiki/widgets.less A src/widgets/SelectFileWidget.js 13 files changed, 732 insertions(+), 4 deletions(-) Approvals: Trevor Parscal: Looks good to me, approved jenkins-bot: Verified diff --git a/build/modules.json b/build/modules.json index 5aa773f..c83dc3d 100644 --- a/build/modules.json +++ b/build/modules.json @@ -72,6 +72,7 @@ "src/widgets/PopupButtonWidget.js", "src/widgets/ToggleButtonWidget.js", "src/widgets/DropdownWidget.js", + "src/widgets/SelectFileWidget.js", "src/widgets/IconWidget.js", "src/widgets/IndicatorWidget.js", "src/widgets/InputWidget.js", diff --git a/demos/pages/widgets.js b/demos/pages/widgets.js index 52c6ee8..93f4cf1 100644 --- a/demos/pages/widgets.js +++ b/demos/pages/widgets.js @@ -817,6 +817,41 @@ } ), new OO.ui.FieldLayout( + new OO.ui.SelectFileWidget( {} ), + { + label: 'SelectFileWidget\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.SelectFileWidget( { accept: [ 'image/png', 'image/jpeg' ] } ), + { + label: 'SelectFileWidget (accept PNG and JPEG)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.SelectFileWidget( { + icon: 'tag', + indicator: 'required' + } ), + { + label: 'SelectFileWidget (icon, indicator)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.SelectFileWidget( { + icon: 'tag', + indicator: 'required', + disabled: true + } ), + { + label: 'SelectFileWidget (disabled)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( new OO.ui.DropdownWidget( { label: 'Select one', menu: { diff --git a/i18n/en.json b/i18n/en.json index 1db3fd8..9812ec6 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -27,5 +27,8 @@ "ooui-dialog-process-error": "Something went wrong", "ooui-dialog-process-dismiss": "Dismiss", "ooui-dialog-process-retry": "Try again", - "ooui-dialog-process-continue": "Continue" + "ooui-dialog-process-continue": "Continue", + "ooui-selectfile-not-supported": "File selection is not supported", + "ooui-selectfile-placeholder": "No file is selected", + "ooui-semicolon-separator": "; " } diff --git a/i18n/qqq.json b/i18n/qqq.json index c1b794a..bef65ed 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -31,5 +31,8 @@ "ooui-dialog-process-error": "Title for process dialog error description", "ooui-dialog-process-dismiss": "Label for process dialog dismiss error button, visible when describing errors\n{{Identical|Dismiss}}", "ooui-dialog-process-retry": "Label for process dialog retry action button, visible when describing recoverable errors\n{{Identical|Try again}}", - "ooui-dialog-process-continue": "Label for process dialog retry action button, visible when describing only warnings\n{{Identical|Continue}}" + "ooui-dialog-process-continue": "Label for process dialog retry action button, visible when describing only warnings\n{{Identical|Continue}}", + "ooui-selectfile-not-supported": "Label for the file selection dialog if file selection is not supported", + "ooui-selectfile-placeholder": "Label for the file selection dialog when no file is currently selected", + "ooui-semicolon-separator": "{{optional}} Semicolon used as a separator" } diff --git a/jsduck.json b/jsduck.json index 918b570..2eae6e6 100644 --- a/jsduck.json +++ b/jsduck.json @@ -6,7 +6,7 @@ "--processes": "0", "--warnings-exit-nonzero": true, "--builtin-classes": true, - "--external": "HTMLDocument,Window,MouseEvent,KeyboardEvent", + "--external": "HTMLDocument,Window,MouseEvent,KeyboardEvent,File", "--warnings": ["-nodoc(class,public)"], "--": [ "jsduck.external.js", diff --git a/src/core.js b/src/core.js index 1331f5c..6aad59e 100644 --- a/src/core.js +++ b/src/core.js @@ -216,7 +216,13 @@ // Label for process dialog retry action button, visible when describing only recoverable errors 'ooui-dialog-process-retry': 'Try again', // Label for process dialog retry action button, visible when describing only warnings - 'ooui-dialog-process-continue': 'Continue' + 'ooui-dialog-process-continue': 'Continue', + // Default placeholder for file selection widgets + 'ooui-selectfile-not-supported': 'File selection is not supported', + // Default placeholder for file selection widgets + 'ooui-selectfile-placeholder': 'No file is selected', + // Semicolon separator + 'ooui-semicolon-separator': '; ' }; /** diff --git a/src/styles/core.less b/src/styles/core.less index fc1c91f..6c65853 100644 --- a/src/styles/core.less +++ b/src/styles/core.less @@ -95,6 +95,7 @@ @import 'widgets/MenuSectionOptionWidget.less'; @import 'widgets/TextInputMenuSelectWidget.less'; @import 'widgets/DropdownWidget.less'; +@import 'widgets/SelectFileWidget.less'; @import 'widgets/OutlineSelectWidget.less'; @import 'widgets/OutlineOptionWidget.less'; diff --git a/src/styles/theme.less b/src/styles/theme.less index 2cd4c0e..92d3252 100644 --- a/src/styles/theme.less +++ b/src/styles/theme.less @@ -63,6 +63,7 @@ .theme-oo-ui-iconWidget () {} .theme-oo-ui-indicatorWidget () {} .theme-oo-ui-dropdownWidget () {} +.theme-oo-ui-selectFileWidget () {} .theme-oo-ui-inputWidget () {} .theme-oo-ui-buttonInputWidget () {} .theme-oo-ui-checkboxInputWidget () {} diff --git a/src/styles/widgets/SelectFileWidget.less b/src/styles/widgets/SelectFileWidget.less new file mode 100644 index 0000000..c912cdf --- /dev/null +++ b/src/styles/widgets/SelectFileWidget.less @@ -0,0 +1,63 @@ +@import '../common'; + +.oo-ui-selectFileWidget { + display: inline-block; + position: relative; + vertical-align: middle; + + &-handle { + width: 100%; + display: inline-block; + cursor: pointer; + overflow: hidden; + + .oo-ui-unselectable(); + .oo-ui-box-sizing(border-box); + + > .oo-ui-indicatorElement-indicator, + > .oo-ui-iconElement-icon, + > .oo-ui-selectFileWidget-clearButton { + position: absolute; + background-position: center center; + background-repeat: no-repeat; + } + + > input[type="file"] { + position: absolute; + margin: 0; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 100%; + height: 100%; + opacity: 0; + z-index: 1; + cursor: pointer; + } + + > .oo-ui-selectFileWidget-clearButton { + z-index: 2; + } + } + + &.oo-ui-widget-disabled, + &-notsupported { + .oo-ui-selectFileWidget-handle { + cursor: default; + + > input[type="file"] { + display: none; + } + } + } + + &-empty, + &-notsupported { + .oo-ui-selectFileWidget-clearButton { + display: none; + } + } + + .theme-oo-ui-selectFileWidget(); +} diff --git a/src/themes/apex/widgets.less b/src/themes/apex/widgets.less index f415b6d..21c64fa 100644 --- a/src/themes/apex/widgets.less +++ b/src/themes/apex/widgets.less @@ -166,6 +166,121 @@ } } +.theme-oo-ui-selectFileWidget () { + margin: 0.25em 0; + width: 100%; + max-width: 50em; + + .oo-ui-inline-spacing(0.5em); + + &-handle { + height: 2.5em; + border: 1px solid rgba(0,0,0,0.1); + border-radius: 0.25em; + padding: 0 0.5em; + + > .oo-ui-indicatorElement-indicator { + right: 0; + } + + > .oo-ui-iconElement-icon { + left: 0.25em; + } + + .oo-ui-selectFileWidget-label { + line-height: 2.5em; + margin: 0; + display: inline-block; + overflow: hidden; + width: 100%; + white-space: nowrap; + .oo-ui-box-sizing( border-box ); + text-overflow: ellipsis; + } + + .oo-ui-selectFileWidget-clearButton { + top: 0; + width: @icon-size; + height: @icon-size; + margin: 0.3em; + } + + > .oo-ui-indicatorElement-indicator { + top: 0; + width: @indicator-size; + height: @indicator-size; + margin: 0.775em; + } + + > .oo-ui-iconElement-icon { + top: 0; + width: @icon-size; + height: @icon-size; + margin: 0.3em; + } + } + + &:hover .oo-ui-selectFileWidget-handle { + border-color: #aaa; + } + + &.oo-ui-widget-disabled { + .oo-ui-selectFileWidget-handle { + color: #ccc; + text-shadow: 0 1px 1px #fff; + border-color: #ddd; + background-color: #f3f3f3; + + > .oo-ui-iconElement-icon, + > .oo-ui-indicatorElement-indicator { + opacity: 0.2; + } + } + } + + &-empty { + .oo-ui-selectFileWidget-label { + color: #ccc; + } + } + + &.oo-ui-iconElement .oo-ui-selectFileWidget-handle { + padding-left: 3em; + } + + // With close, no indicator: + & .oo-ui-selectFileWidget-handle { + padding-right: 3em; + + .oo-ui-selectFileWidget-clearButton { + right: 0; + } + } + + // With close, with indicator: + &.oo-ui-indicatorElement .oo-ui-selectFileWidget-handle { + padding-right: 5em; + + .oo-ui-selectFileWidget-clearButton { + right: 2em; + } + } + + // No close, no indicator: + &-empty, &-notsupported { + .oo-ui-selectFileWidget-handle { + padding-right: 1em; + } + } + + // No close, with indicator: + &-empty.oo-ui-indicatorElement, &-notsupported.oo-ui-indicatorElement { + .oo-ui-selectFileWidget-handle { + padding-right: 2em; + } + } +} + .theme-oo-ui-inputWidget () { .oo-ui-inline-spacing(0.5em); } diff --git a/src/themes/blank/widgets.less b/src/themes/blank/widgets.less index 68c64cd..a23ea99 100644 --- a/src/themes/blank/widgets.less +++ b/src/themes/blank/widgets.less @@ -22,6 +22,8 @@ .theme-oo-ui-dropdownWidget () {} +.theme-oo-ui-selectFileWidget () {} + .theme-oo-ui-inputWidget () {} .theme-oo-ui-buttonInputWidget () {} diff --git a/src/themes/mediawiki/widgets.less b/src/themes/mediawiki/widgets.less index 2f07287..1ce4cdc 100644 --- a/src/themes/mediawiki/widgets.less +++ b/src/themes/mediawiki/widgets.less @@ -170,6 +170,121 @@ } } +.theme-oo-ui-selectFileWidget () { + margin: 0.25em 0; + width: 100%; + max-width: 50em; + + .oo-ui-inline-spacing(0.5em); + + &-handle { + height: 2.5em; + border: 1px solid #ccc; + border-radius: 0.1em; + padding: 0 1em; + + > .oo-ui-indicatorElement-indicator { + right: 0; + } + + > .oo-ui-iconElement-icon { + left: 0.25em; + } + + .oo-ui-selectFileWidget-label { + line-height: 2.5em; + margin: 0; + display: inline-block; + overflow: hidden; + width: 100%; + white-space: nowrap; + .oo-ui-box-sizing( border-box ); + text-overflow: ellipsis; + } + + .oo-ui-selectFileWidget-clearButton { + top: 0; + width: @icon-size; + height: @icon-size; + margin: 0.3em; + } + + > .oo-ui-indicatorElement-indicator { + top: 0; + width: @indicator-size; + height: @indicator-size; + margin: 0.775em; + } + + > .oo-ui-iconElement-icon { + top: 0; + width: @icon-size; + height: @icon-size; + margin: 0.3em; + } + } + + &:hover .oo-ui-selectFileWidget-handle { + border-color: #aaa; + } + + &.oo-ui-widget-disabled { + .oo-ui-selectFileWidget-handle { + color: #ccc; + text-shadow: 0 1px 1px #fff; + border-color: #ddd; + background-color: #f3f3f3; + + > .oo-ui-iconElement-icon, + > .oo-ui-indicatorElement-indicator { + opacity: 0.2; + } + } + } + + &-empty { + .oo-ui-selectFileWidget-label { + color: #ccc; + } + } + + &.oo-ui-iconElement .oo-ui-selectFileWidget-handle { + padding-left: 3em; + } + + // With close, no indicator: + & .oo-ui-selectFileWidget-handle { + padding-right: 3em; + + .oo-ui-selectFileWidget-clearButton { + right: 0; + } + } + + // With close, with indicator: + &.oo-ui-indicatorElement .oo-ui-selectFileWidget-handle { + padding-right: 5em; + + .oo-ui-selectFileWidget-clearButton { + right: 2em; + } + } + + // No close, no indicator: + &-empty, &-notsupported { + .oo-ui-selectFileWidget-handle { + padding-right: 1em; + } + } + + // No close, with indicator: + &-empty.oo-ui-indicatorElement, &-notsupported.oo-ui-indicatorElement { + .oo-ui-selectFileWidget-handle { + padding-right: 2em; + } + } +} + .theme-oo-ui-inputWidget () { .oo-ui-inline-spacing(0.5em); } diff --git a/src/widgets/SelectFileWidget.js b/src/widgets/SelectFileWidget.js new file mode 100644 index 0000000..afe822a --- /dev/null +++ b/src/widgets/SelectFileWidget.js @@ -0,0 +1,383 @@ +/** + * SelectFileWidgets allow for selecting files, using the HTML5 File API. These + * widgets can be configured with {@link OO.ui.IconElement icons} and {@link + * OO.ui.IndicatorElement indicators}. + * Please see the [OOjs UI documentation on MediaWiki] [1] for more information and examples. + * + * @example + * // Example of a file select widget + * var selectFile = new OO.ui.SelectFileWidget(); + * $( 'body' ).append( selectFile.$element ); + * + * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets + * + * @class + * @extends OO.ui.Widget + * @mixins OO.ui.IconElement + * @mixins OO.ui.IndicatorElement + * @mixins OO.ui.PendingElement + * @mixins OO.ui.LabelElement + * @mixins OO.ui.TabIndexedElement + * + * @constructor + * @param {Object} [config] Configuration options + * @cfg {string[]|null} [accept=null] MIME types to accept. null accepts all types. + * @cfg {string} [placeholder] Text to display when no file is selected. + * @cfg {string} [notsupported] Text to display when file support is missing in the browser. + * @cfg {boolean} [droppable=true] Whether to accept files by drag and drop. + */ +OO.ui.SelectFileWidget = function OoUiSelectFileWidget( config ) { + var dragHandler; + + // Configuration initialization + config = $.extend( { + accept: null, + placeholder: OO.ui.msg( 'ooui-selectfile-placeholder' ), + notsupported: OO.ui.msg( 'ooui-selectfile-not-supported' ), + droppable: true + }, config ); + + // Parent constructor + OO.ui.SelectFileWidget.super.call( this, config ); + + // Properties (must be set before TabIndexedElement constructor call) + this.$handle = $( '<span>' ); + + // Mixin constructors + OO.ui.IconElement.call( this, config ); + OO.ui.IndicatorElement.call( this, config ); + OO.ui.PendingElement.call( this, config ); + OO.ui.LabelElement.call( this, $.extend( config, { autoFitLabel: true } ) ); + OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$handle } ) ); + + // Properties + this.isSupported = this.constructor.static.isSupported(); + this.currentFile = null; + if ( Array.isArray( config.accept ) ) { + this.accept = config.accept; + } else { + this.accept = null; + } + this.placeholder = config.placeholder; + this.notsupported = config.notsupported; + this.onFileSelectedHandler = this.onFileSelected.bind( this ); + + this.clearButton = new OO.ui.ButtonWidget( { + classes: [ 'oo-ui-selectFileWidget-clearButton' ], + framed: false, + icon: 'remove', + disabled: this.disabled + } ); + + // Events + this.$handle.on( { + keypress: this.onKeyPress.bind( this ) + } ); + this.clearButton.connect( this, { + click: 'onClearClick' + } ); + if ( config.droppable ) { + dragHandler = this.onDragEnterOrOver.bind( this ); + this.$handle.on( { + dragenter: dragHandler, + dragover: dragHandler, + dragleave: this.onDragLeave.bind( this ), + drop: this.onDrop.bind( this ) + } ); + } + + // Initialization + this.addInput(); + this.updateUI(); + this.$label.addClass( 'oo-ui-selectFileWidget-label' ); + this.$handle + .addClass( 'oo-ui-selectFileWidget-handle' ) + .append( this.$icon, this.$label, this.clearButton.$element, this.$indicator ); + this.$element + .addClass( 'oo-ui-selectFileWidget' ) + .append( this.$handle ); + if ( config.droppable ) { + this.$element.addClass( 'oo-ui-selectFileWidget-droppable' ); + } +}; + +/* Setup */ + +OO.inheritClass( OO.ui.SelectFileWidget, OO.ui.Widget ); +OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.IconElement ); +OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.IndicatorElement ); +OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.PendingElement ); +OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.LabelElement ); +OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.TabIndexedElement ); + +/* Static properties */ + +/** + * Check if this widget is supported + * + * @static + * @return {boolean} + */ +OO.ui.SelectFileWidget.static.isSupported = function () { + var $input; + if ( OO.ui.SelectFileWidget.static.isSupportedCache === null ) { + $input = $( '<input type="file">' ); + OO.ui.SelectFileWidget.static.isSupportedCache = $input[0].files !== undefined; + } + return OO.ui.SelectFileWidget.static.isSupportedCache; +}; + +OO.ui.SelectFileWidget.static.isSupportedCache = null; + +/* Events */ + +/** + * @event change + * + * A change event is emitted when the on/off state of the toggle changes. + * + * @param {File|null} value New value + */ + +/* Methods */ + +/** + * Get the current value of the field + * + * @return {File|null} + */ +OO.ui.SelectFileWidget.prototype.getValue = function () { + return this.currentFile; +}; + +/** + * Set the current value of the field + * + * @param {File|null} file File to select + */ +OO.ui.SelectFileWidget.prototype.setValue = function ( file ) { + if ( this.currentFile !== file ) { + this.currentFile = file; + this.updateUI(); + this.emit( 'change', this.currentFile ); + } +}; + +/** + * Update the user interface when a file is selected or unselected + * + * @protected + */ +OO.ui.SelectFileWidget.prototype.updateUI = function () { + if ( !this.isSupported ) { + this.$element.addClass( 'oo-ui-selectFileWidget-notsupported' ); + this.$element.removeClass( 'oo-ui-selectFileWidget-empty' ); + this.setLabel( this.notsupported ); + } else if ( this.currentFile ) { + this.$element.removeClass( 'oo-ui-selectFileWidget-empty' ); + this.setLabel( this.currentFile.name + + ( this.currentFile.type !== '' ? OO.ui.msg( 'ooui-semicolon-separator' ) + this.currentFile.type : '' ) + ); + } else { + this.$element.addClass( 'oo-ui-selectFileWidget-empty' ); + this.setLabel( this.placeholder ); + } + + if ( this.$input ) { + this.$input.attr( 'title', this.getLabel() ); + } +}; + +/** + * Add the input to the handle + * + * @private + */ +OO.ui.SelectFileWidget.prototype.addInput = function () { + if ( this.$input ) { + this.$input.remove(); + } + + if ( !this.isSupported ) { + this.$input = null; + return; + } + + this.$input = $( '<input type="file">' ); + this.$input.on( 'change', this.onFileSelectedHandler ); + this.$input.attr( { + tabindex: -1, + title: this.getLabel() + } ); + if ( this.accept ) { + this.$input.attr( 'accept', this.accept.join( ', ' ) ); + } + this.$handle.append( this.$input ); +}; + +/** + * Determine if we should accept this file + * + * @private + * @param {File} file + * @return {boolean} + */ +OO.ui.SelectFileWidget.prototype.isFileAcceptable = function ( file ) { + var i, mime, mimeTest; + + if ( !this.accept || file.type === '' ) { + return true; + } + + mime = file.type; + for ( i = 0; i < this.accept.length; i++ ) { + mimeTest = this.accept[i]; + if ( mimeTest === mime ) { + return true; + } else if ( mimeTest.substr( -2 ) === '/*' ) { + mimeTest = mimeTest.substr( 0, mimeTest.length - 1 ); + if ( mime.substr( 0, mimeTest.length ) === mimeTest ) { + return true; + } + } + } + + return false; +}; + +/** + * Handle file selection from the input + * + * @private + * @param {jQuery.Event} e + */ +OO.ui.SelectFileWidget.prototype.onFileSelected = function ( e ) { + var file = null; + + if ( e.target.files && e.target.files[0] ) { + file = e.target.files[0]; + if ( !this.isFileAcceptable( file ) ) { + file = null; + } + } + + this.setValue( file ); + this.addInput(); +}; + +/** + * Handle clear button click events. + * + * @private + */ +OO.ui.SelectFileWidget.prototype.onClearClick = function () { + this.setValue( null ); + return false; +}; + +/** + * Handle key press events. + * + * @private + * @param {jQuery.Event} e Key press event + */ +OO.ui.SelectFileWidget.prototype.onKeyPress = function ( e ) { + if ( this.isSupported && !this.isDisabled() && this.$input && + ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) + ) { + this.$input.click(); + return false; + } +}; + +/** + * Handle drag enter and over events + * + * @private + * @param {jQuery.Event} e Drag event + */ +OO.ui.SelectFileWidget.prototype.onDragEnterOrOver = function ( e ) { + var file = null, + dt = e.originalEvent.dataTransfer; + + e.preventDefault(); + e.stopPropagation(); + + if ( this.isDisabled() || !this.isSupported ) { + this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' ); + dt.dropEffect = 'none'; + return false; + } + + if ( dt && dt.files && dt.files[0] ) { + file = dt.files[0]; + if ( !this.isFileAcceptable( file ) ) { + file = null; + } + } else if ( dt && dt.types && $.inArray( 'Files', dt.types ) ) { + // We know we have files so set 'file' to something truthy, we just + // can't know any details about them. + // * https://bugzilla.mozilla.org/show_bug.cgi?id=640534 + file = 'Files exist, but details are unknown'; + } + if ( file ) { + this.$element.addClass( 'oo-ui-selectFileWidget-canDrop' ); + } else { + this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' ); + dt.dropEffect = 'none'; + } + + return false; +}; + +/** + * Handle drag leave events + * + * @private + * @param {jQuery.Event} e Drag event + */ +OO.ui.SelectFileWidget.prototype.onDragLeave = function () { + this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' ); +}; + +/** + * Handle drop events + * + * @private + * @param {jQuery.Event} e Drop event + */ +OO.ui.SelectFileWidget.prototype.onDrop = function ( e ) { + var file = null, + dt = e.originalEvent.dataTransfer; + + e.preventDefault(); + e.stopPropagation(); + this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' ); + + if ( this.isDisabled() || !this.isSupported ) { + return false; + } + + if ( dt && dt.files && dt.files[0] ) { + file = dt.files[0]; + if ( !this.isFileAcceptable( file ) ) { + file = null; + } + } + if ( file ) { + this.setValue( file ); + } + + return false; +}; + +/** + * @inheritdoc + */ +OO.ui.SelectFileWidget.prototype.setDisabled = function ( state ) { + OO.ui.SelectFileWidget.super.prototype.setDisabled.call( this, state ); + if ( this.clearButton ) { + this.clearButton.setDisabled( state ); + } + return this; +}; -- To view, visit https://gerrit.wikimedia.org/r/213588 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ic4db04daf11f3ab461a16ed3a1e9561e82351bc5 Gerrit-PatchSet: 4 Gerrit-Project: oojs/ui Gerrit-Branch: master Gerrit-Owner: Anomie <bjor...@wikimedia.org> Gerrit-Reviewer: Bartosz DziewoĆski <matma....@gmail.com> Gerrit-Reviewer: Esanders <esand...@wikimedia.org> Gerrit-Reviewer: Trevor Parscal <tpars...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits