Esanders has uploaded a new change for review. https://gerrit.wikimedia.org/r/234556
Change subject: [BREAKING CHANGE] Redesign select file widget to use a clearly clickable button ...................................................................... [BREAKING CHANGE] Redesign select file widget to use a clearly clickable button The drop target (showDropTarget) is show in addition to the rest of the widget above it. Drop target and select button are disabled if the widget is disabled or file upload is not supported. setActive and related code removed as it served no purpose. Change-Id: Ieb66b56534dfe08df3307c7861dbe79daf30f7b4 --- M demos/pages/widgets.js M i18n/en.json M i18n/qqq.json M src/core.js M src/styles/widgets/SelectFileWidget.less M src/themes/apex/widgets.less M src/themes/mediawiki/widgets.less M src/widgets/SelectFileWidget.js 8 files changed, 212 insertions(+), 168 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/oojs/ui refs/changes/56/234556/1 diff --git a/demos/pages/widgets.js b/demos/pages/widgets.js index 9aa7eac..a531d7f 100644 --- a/demos/pages/widgets.js +++ b/demos/pages/widgets.js @@ -114,6 +114,15 @@ return items; }; + function UnsupportedSelectFileWidget() { + // Parent constructor + UnsupportedSelectFileWidget.parent.apply( this, arguments ); + } + OO.inheritClass( UnsupportedSelectFileWidget, OO.ui.SelectFileWidget ); + UnsupportedSelectFileWidget.static.isSupported = function () { + return false; + }; + capsulePopupWidget = new OO.ui.NumberInputWidget( { isInteger: true } ); @@ -952,9 +961,35 @@ } ), new OO.ui.FieldLayout( - new OO.ui.SelectFileWidget( { dragDropUI: true } ), + new UnsupportedSelectFileWidget(), { - label: 'SelectFileWidget (drag drop UI)\u200E', + label: 'SelectFileWidget (no browser support)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.SelectFileWidget( { showDropTarget: true } ), + { + label: 'SelectFileWidget (with drop target)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.SelectFileWidget( { + showDropTarget: true, + disabled: true + } ), + { + label: 'SelectFileWidget (with drop target, disabled)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new UnsupportedSelectFileWidget( { + showDropTarget: true + } ), + { + label: 'SelectFileWidget (with drop target, no browser support)\u200E', align: 'top' } ), diff --git a/i18n/en.json b/i18n/en.json index db2399f..7cf2eb1 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -28,8 +28,9 @@ "ooui-dialog-process-dismiss": "Dismiss", "ooui-dialog-process-retry": "Try again", "ooui-dialog-process-continue": "Continue", + "ooui-selectfile-button-select": "Select a file", "ooui-selectfile-not-supported": "File selection is not supported", "ooui-selectfile-placeholder": "No file is selected", - "ooui-selectfile-dragdrop-placeholder": "Drop file here (or click to browse)", + "ooui-selectfile-dragdrop-placeholder": "Drop file here", "ooui-semicolon-separator": "; " } diff --git a/i18n/qqq.json b/i18n/qqq.json index 607229d..cd9c0c2 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -32,8 +32,9 @@ "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-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-selectfile-dragdrop-placeholder": "Label for the file selection dialog when no file is currently selected in the drag drop UI. Suggests clicking to open the browse dialog.", + "ooui-selectfile-button-select": "Label for the file selection widget's select file button", + "ooui-selectfile-not-supported": "Label for the file selection widget if file selection is not supported", + "ooui-selectfile-placeholder": "Label for the file selection widget when no file is currently selected", + "ooui-selectfile-dragdrop-placeholder": "Label for the file selection widget's drop target", "ooui-semicolon-separator": "{{optional}} Semicolon used as a separator" } diff --git a/src/core.js b/src/core.js index 988480e..3bdd807 100644 --- a/src/core.js +++ b/src/core.js @@ -265,12 +265,14 @@ 'ooui-dialog-process-retry': 'Try again', // Label for process dialog retry action button, visible when describing only warnings 'ooui-dialog-process-continue': 'Continue', - // Default placeholder for file selection widgets + // Label for the file selection widget's select file button + 'ooui-selectfile-button-select': 'Select a file', + // Label for the file selection widget if file selection is not supported 'ooui-selectfile-not-supported': 'File selection is not supported', - // Default placeholder for file selection widgets + // Label for the file selection widget when no file is currently selected 'ooui-selectfile-placeholder': 'No file is selected', - // Default placeholder for file selection widgets when using drag drop UI - 'ooui-selectfile-dragdrop-placeholder': 'Drop file here (or click to browse)', + // Label for the file selection widget's drop target + 'ooui-selectfile-dragdrop-placeholder': 'Drop file here', // Semicolon separator 'ooui-semicolon-separator': '; ' }; diff --git a/src/styles/widgets/SelectFileWidget.less b/src/styles/widgets/SelectFileWidget.less index 0aee532..a0f7a10 100644 --- a/src/styles/widgets/SelectFileWidget.less +++ b/src/styles/widgets/SelectFileWidget.less @@ -2,16 +2,48 @@ .oo-ui-selectFileWidget { display: inline-block; - position: relative; vertical-align: middle; - &-handle { + &-selectButton { + display: table-cell; + vertical-align: middle; + + > .oo-ui-buttonElement-button { + position: relative; + overflow: hidden; + + > 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; + /* Push the button part of the native control out of view, as it changes the cursor */ + padding-top: 100px; + } + } + + &.oo-ui-widget-disabled { + & > .oo-ui-buttonElement-button > input[type="file"] { + display: none; + } + } + + } + + &-info { width: 100%; - display: inline-block; - cursor: pointer; + display: table-cell; + vertical-align: middle; + position: relative; overflow: hidden; - .oo-ui-unselectable(); .oo-ui-box-sizing(border-box); > .oo-ui-indicatorElement-indicator, @@ -20,33 +52,18 @@ position: absolute; } - > 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; + &-dropTarget { + cursor: default; + } - > input[type="file"] { - display: none; - } + &-supported.oo-ui-widget-enabled { + .oo-ui-selectFileWidget-dropTarget { + cursor: pointer; } } diff --git a/src/themes/apex/widgets.less b/src/themes/apex/widgets.less index 8c459fe..099d5e6 100644 --- a/src/themes/apex/widgets.less +++ b/src/themes/apex/widgets.less @@ -171,8 +171,14 @@ .oo-ui-inline-spacing(0.5em); - &-handle { - height: 2.5em; + &-selectButton { + > .oo-ui-buttonElement-button { + margin: 0 0 0 0.5em; + } + } + + &-info { + height: 2.4em; border: 1px solid rgba(0,0,0,0.1); border-radius: 0.25em; padding: 0 0.5em; @@ -186,9 +192,8 @@ } .oo-ui-selectFileWidget-label { - line-height: 2.5em; + line-height: 2.3em; margin: 0; - display: inline-block; overflow: hidden; width: 100%; white-space: nowrap; @@ -218,12 +223,8 @@ } } - &:hover .oo-ui-selectFileWidget-handle { - border-color: #aaa; - } - &.oo-ui-widget-disabled { - .oo-ui-selectFileWidget-handle { + .oo-ui-selectFileWidget-info { color: #ccc; text-shadow: 0 1px 1px #fff; border-color: #ddd; @@ -242,12 +243,12 @@ } } - &.oo-ui-iconElement .oo-ui-selectFileWidget-handle { + &.oo-ui-iconElement .oo-ui-selectFileWidget-info { padding-left: 3em; } // With close, no indicator: - & .oo-ui-selectFileWidget-handle { + & .oo-ui-selectFileWidget-info { padding-right: 3em; .oo-ui-selectFileWidget-clearButton { @@ -256,7 +257,7 @@ } // With close, with indicator: - &.oo-ui-indicatorElement .oo-ui-selectFileWidget-handle { + &.oo-ui-indicatorElement .oo-ui-selectFileWidget-info { padding-right: 5em; .oo-ui-selectFileWidget-clearButton { @@ -266,38 +267,43 @@ // No close, no indicator: &-empty, &-notsupported { - .oo-ui-selectFileWidget-handle { + .oo-ui-selectFileWidget-info { padding-right: 1em; } } // No close, with indicator: &-empty.oo-ui-indicatorElement, &-notsupported.oo-ui-indicatorElement { - .oo-ui-selectFileWidget-handle { + .oo-ui-selectFileWidget-info { padding-right: 2em; } } - &.oo-ui-selectFileWidget-dragdrop-ui &-handle { - height: 3.5em; + &-dropTarget { + line-height: 3.5em; border: 1px dashed #aaa; padding: 0.5em 1em; + margin-bottom: 0.5em; background: #fff; text-align: center; vertical-align: middle; + } - .oo-ui-iconElement-icon { - margin: 0.6em 0; - } - - .oo-ui-selectFileWidget-label { - color: #000; + &-supported.oo-ui-widget-enabled { + .oo-ui-selectFileWidget-dropTarget:hover, + &.oo-ui-selectFileWidget-canDrop oo-ui-selectFileWidget-dropTarget { + background-color: #e1f3ff; } } - &.oo-ui-selectFileWidget-dragdrop-ui &-handle:hover, - &.oo-ui-selectFileWidget-dragdrop-ui.oo-ui-selectFileWidget-canDrop &-handle { - background-color: #eee; + &.oo-ui-widget-disabled, + &-notsupported { + .oo-ui-selectFileWidget-dropTarget { + color: #ccc; + text-shadow: 0 1px 1px #fff; + border-color: #ddd; + background-color: #f3f3f3; + } } } diff --git a/src/themes/mediawiki/widgets.less b/src/themes/mediawiki/widgets.less index 58062b6..7c8d8cc 100644 --- a/src/themes/mediawiki/widgets.less +++ b/src/themes/mediawiki/widgets.less @@ -172,12 +172,17 @@ .oo-ui-inline-spacing(0.5em); - &-handle { - height: 2.5em; + &-selectButton { + > .oo-ui-buttonElement-button { + margin: 0 0 0 0.5em; + } + } + + &-info { + height: 2.4em; border: 1px solid #ccc; border-radius: 0.1em; padding: 0 1em; - background: #fff; > .oo-ui-indicatorElement-indicator { right: 0; @@ -188,9 +193,8 @@ } .oo-ui-selectFileWidget-label { - line-height: 2.5em; + line-height: 2.3em; margin: 0; - display: inline-block; overflow: hidden; width: 100%; white-space: nowrap; @@ -220,12 +224,8 @@ } } - &:hover .oo-ui-selectFileWidget-handle { - border-color: #aaa; - } - &.oo-ui-widget-disabled { - .oo-ui-selectFileWidget-handle { + .oo-ui-selectFileWidget-info { color: #ccc; text-shadow: 0 1px 1px #fff; border-color: #ddd; @@ -244,12 +244,12 @@ } } - &.oo-ui-iconElement .oo-ui-selectFileWidget-handle { + &.oo-ui-iconElement .oo-ui-selectFileWidget-info { padding-left: 3em; } // With close, no indicator: - & .oo-ui-selectFileWidget-handle { + & .oo-ui-selectFileWidget-info { padding-right: 3em; .oo-ui-selectFileWidget-clearButton { @@ -258,7 +258,7 @@ } // With close, with indicator: - &.oo-ui-indicatorElement .oo-ui-selectFileWidget-handle { + &.oo-ui-indicatorElement .oo-ui-selectFileWidget-info { padding-right: 5em; .oo-ui-selectFileWidget-clearButton { @@ -268,39 +268,43 @@ // No close, no indicator: &-empty, &-notsupported { - .oo-ui-selectFileWidget-handle { + .oo-ui-selectFileWidget-info { padding-right: 1em; } } // No close, with indicator: &-empty.oo-ui-indicatorElement, &-notsupported.oo-ui-indicatorElement { - .oo-ui-selectFileWidget-handle { + .oo-ui-selectFileWidget-info { padding-right: 2em; } } - &.oo-ui-selectFileWidget-dragdrop-ui &-handle { - height: 3.5em; + &-dropTarget { + line-height: 3.5em; border: 1px dashed #ccc; - border-radius: 0em; padding: 0.5em 1em; + margin-bottom: 0.5em; background: #fff; text-align: center; vertical-align: middle; + } - .oo-ui-iconElement-icon { - margin: 0.6em 0; - } - - .oo-ui-selectFileWidget-label { - color: #000; + &-supported.oo-ui-widget-enabled { + .oo-ui-selectFileWidget-dropTarget:hover, + &.oo-ui-selectFileWidget-canDrop oo-ui-selectFileWidget-dropTarget { + background-color: #eee; } } - &.oo-ui-selectFileWidget-dragdrop-ui &-handle:hover, - &.oo-ui-selectFileWidget-dragdrop-ui.oo-ui-selectFileWidget-canDrop &-handle { - background-color: #eee; + &.oo-ui-widget-disabled, + &-notsupported { + .oo-ui-selectFileWidget-dropTarget { + color: #ccc; + text-shadow: 0 1px 1px #fff; + border-color: #ddd; + background-color: #f3f3f3; + } } } diff --git a/src/widgets/SelectFileWidget.js b/src/widgets/SelectFileWidget.js index c34d5fb..87e802a 100644 --- a/src/widgets/SelectFileWidget.js +++ b/src/widgets/SelectFileWidget.js @@ -17,7 +17,6 @@ * @mixins OO.ui.mixin.IndicatorElement * @mixins OO.ui.mixin.PendingElement * @mixins OO.ui.mixin.LabelElement - * @mixins OO.ui.mixin.TabIndexedElement * * @constructor * @param {Object} [config] Configuration options @@ -25,39 +24,34 @@ * @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. - * @cfg {boolean} [dragDropUI=false] Whether to render the drag and drop UI. + * @cfg {boolean} [showDropTarget=false] Whether to show a drop target. Requires droppable to be true. */ OO.ui.SelectFileWidget = function OoUiSelectFileWidget( config ) { - var dragHandler, - placeholderMsg = ( config && config.dragDropUI ) ? - 'ooui-selectfile-dragdrop-placeholder' : - 'ooui-selectfile-placeholder'; + var dragHandler; // Configuration initialization config = $.extend( { accept: null, - placeholder: OO.ui.msg( placeholderMsg ), + placeholder: OO.ui.msg( 'ooui-selectfile-placeholder' ), notsupported: OO.ui.msg( 'ooui-selectfile-not-supported' ), droppable: true, - dragDropUI: false + showDropTarget: false }, config ); // Parent constructor OO.ui.SelectFileWidget.parent.call( this, config ); - // Properties (must be set before TabIndexedElement constructor call) - this.$handle = $( '<span>' ); - // Mixin constructors OO.ui.mixin.IconElement.call( this, config ); OO.ui.mixin.IndicatorElement.call( this, config ); - OO.ui.mixin.PendingElement.call( this, $.extend( {}, config, { $pending: this.$handle } ) ); + OO.ui.mixin.PendingElement.call( this, $.extend( {}, config, { $pending: this.$info } ) ); OO.ui.mixin.LabelElement.call( this, $.extend( {}, config, { autoFitLabel: true } ) ); - OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$handle } ) ); // Properties - this.active = false; - this.dragDropUI = config.dragDropUI; + this.$info = $( '<span>' ); + + // Properties + this.showDropTarget = config.showDropTarget; this.isSupported = this.constructor.static.isSupported(); this.currentFile = null; if ( Array.isArray( config.accept ) ) { @@ -69,6 +63,12 @@ this.notsupported = config.notsupported; this.onFileSelectedHandler = this.onFileSelected.bind( this ); + this.selectButton = new OO.ui.ButtonWidget( { + classes: [ 'oo-ui-selectFileWidget-selectButton' ], + label: 'Select a file', + disabled: this.disabled || !this.isSupported + } ); + this.clearButton = new OO.ui.ButtonWidget( { classes: [ 'oo-ui-selectFileWidget-clearButton' ], framed: false, @@ -77,7 +77,7 @@ } ); // Events - this.$handle.on( { + this.selectButton.$button.on( { keypress: this.onKeyPress.bind( this ) } ); this.clearButton.connect( this, { @@ -85,7 +85,7 @@ } ); if ( config.droppable ) { dragHandler = this.onDragEnterOrOver.bind( this ); - this.$handle.on( { + this.$element.on( { dragenter: dragHandler, dragover: dragHandler, dragleave: this.onDragLeave.bind( this ), @@ -97,22 +97,20 @@ this.addInput(); this.updateUI(); this.$label.addClass( 'oo-ui-selectFileWidget-label' ); - this.$handle - .addClass( 'oo-ui-selectFileWidget-handle' ) + this.$info + .addClass( 'oo-ui-selectFileWidget-info' ) .append( this.$icon, this.$label, this.clearButton.$element, this.$indicator ); this.$element .addClass( 'oo-ui-selectFileWidget' ) - .append( this.$handle ); - if ( config.droppable ) { - if ( config.dragDropUI ) { - this.$element.addClass( 'oo-ui-selectFileWidget-dragdrop-ui' ); - this.$element.on( { - mouseover: this.onMouseOver.bind( this ), - mouseleave: this.onMouseLeave.bind( this ) + .append( this.$info, this.selectButton.$element ); + if ( config.droppable && config.showDropTarget ) { + this.$dropTarget = $( '<div>' ) + .addClass( 'oo-ui-selectFileWidget-dropTarget' ) + .text( OO.ui.msg( 'ooui-selectfile-dragdrop-placeholder' ) ) + .on( { + click: this.onDropTargetClick.bind( this ) } ); - } else { - this.$element.addClass( 'oo-ui-selectFileWidget-droppable' ); - } + this.$element.prepend( this.$dropTarget ); } }; @@ -123,7 +121,6 @@ OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.IndicatorElement ); OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.PendingElement ); OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.LabelElement ); -OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.TabIndexedElement ); /* Static Properties */ @@ -188,14 +185,17 @@ 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 ); + this.$element.addClass( 'oo-ui-selectFileWidget-supported' ); + 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 ) { @@ -204,7 +204,7 @@ }; /** - * Add the input to the handle + * Add the input to the widget * * @private */ @@ -227,7 +227,7 @@ if ( this.accept ) { this.$input.attr( 'accept', this.accept.join( ', ' ) ); } - this.$handle.append( this.$input ); + this.selectButton.$button.append( this.$input ); }; /** @@ -302,6 +302,19 @@ }; /** + * Handle drop target click events. + * + * @private + * @param {jQuery.Event} e Key press event + */ +OO.ui.SelectFileWidget.prototype.onDropTargetClick = function () { + if ( this.isSupported && !this.isDisabled() && this.$input ) { + this.$input.click(); + return false; + } +}; + +/** * Handle drag enter and over events * * @private @@ -317,7 +330,6 @@ if ( this.isDisabled() || !this.isSupported ) { this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' ); - this.setActive( false ); dt.dropEffect = 'none'; return false; } @@ -338,7 +350,6 @@ } this.$element.toggleClass( 'oo-ui-selectFileWidget-canDrop', droppbaleFile ); - this.setActive( droppbaleFile ); if ( !droppbaleFile ) { dt.dropEffect = 'none'; } @@ -354,7 +365,6 @@ */ OO.ui.SelectFileWidget.prototype.onDragLeave = function () { this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' ); - this.setActive( false ); }; /** @@ -370,7 +380,6 @@ e.preventDefault(); e.stopPropagation(); this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' ); - this.setActive( false ); if ( this.isDisabled() || !this.isSupported ) { return false; @@ -388,46 +397,15 @@ }; /** - * Handle mouse over events. - * - * @private - * @param {jQuery.Event} e Mouse over event - */ -OO.ui.SelectFileWidget.prototype.onMouseOver = function () { - this.setActive( true ); -}; - -/** - * Handle mouse leave events. - * - * @private - * @param {jQuery.Event} e Mouse over event - */ -OO.ui.SelectFileWidget.prototype.onMouseLeave = function () { - this.setActive( false ); -}; - -/** * @inheritdoc */ -OO.ui.SelectFileWidget.prototype.setDisabled = function ( state ) { - OO.ui.SelectFileWidget.parent.prototype.setDisabled.call( this, state ); - if ( this.clearButton ) { - this.clearButton.setDisabled( state ); +OO.ui.SelectFileWidget.prototype.setDisabled = function ( disabled ) { + OO.ui.SelectFileWidget.parent.prototype.setDisabled.call( this, disabled ); + if ( this.selectButton ) { + this.selectButton.setDisabled( disabled ); } - return this; -}; - -/** - * Set 'active' (hover) state, only matters for widgets with `dragDropUI: true`. - * - * @param {boolean} value Whether widget is active - * @chainable - */ -OO.ui.SelectFileWidget.prototype.setActive = function ( value ) { - if ( this.dragDropUI ) { - this.active = value; - this.updateThemeClasses(); + if ( this.clearButton ) { + this.clearButton.setDisabled( disabled ); } return this; }; -- To view, visit https://gerrit.wikimedia.org/r/234556 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ieb66b56534dfe08df3307c7861dbe79daf30f7b4 Gerrit-PatchSet: 1 Gerrit-Project: oojs/ui Gerrit-Branch: master Gerrit-Owner: Esanders <esand...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits