/*!
- * OOjs UI v0.12.6
+ * OOjs UI v0.12.8
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2015 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2015-08-26T00:14:36Z
+ * Date: 2015-09-08T20:55:55Z
*/
( function ( OO ) {
'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': '; '
};
var widget = this,
value = this.getValue();
- if ( this.lookupsDisabled ) {
+ if ( this.lookupsDisabled || this.isReadOnly() ) {
return;
}
// Note: Calling #setReadOnly this way assumes this is mixed into an OO.ui.TextInputWidget
OO.ui.TextInputWidget.prototype.setReadOnly.call( this, readOnly );
- this.setLookupsDisabled( readOnly );
// During construction, #setReadOnly is called before the OO.ui.mixin.LookupElement constructor
- if ( readOnly && this.lookupMenu ) {
+ if ( this.isReadOnly() && this.lookupMenu ) {
this.closeLookupMenu();
}
* This must be called after it is attached to a visible document and before doing anything else.
*/
OO.ui.Toolbar.prototype.initialize = function () {
- this.initialized = true;
- this.narrowThreshold = this.$group.width() + this.$actions.width();
- $( this.getElementWindow() ).on( 'resize', this.onWindowResizeHandler );
- this.onWindowResize();
+ if ( !this.initialized ) {
+ this.initialized = true;
+ this.narrowThreshold = this.$group.width() + this.$actions.width();
+ $( this.getElementWindow() ).on( 'resize', this.onWindowResizeHandler );
+ this.onWindowResize();
+ }
};
/**
* @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
* @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.
+ * @cfg {boolean} [dragDropUI=false] Deprecated alias for showDropTarget
*/
OO.ui.SelectFileWidget = function OoUiSelectFileWidget( config ) {
- var dragHandler,
- placeholderMsg = ( config && config.dragDropUI ) ?
- 'ooui-selectfile-dragdrop-placeholder' :
- 'ooui-selectfile-placeholder';
+ var dragHandler;
+
+ // TODO: Remove in next release
+ if ( config && config.dragDropUI ) {
+ config.showDropTarget = true;
+ }
// 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 ) ) {
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,
} );
// Events
- this.$handle.on( {
+ this.selectButton.$button.on( {
keypress: this.onKeyPress.bind( this )
} );
this.clearButton.connect( this, {
} );
if ( config.droppable ) {
dragHandler = this.onDragEnterOrOver.bind( this );
- this.$handle.on( {
+ this.$element.on( {
dragenter: dragHandler,
dragover: dragHandler,
dragleave: this.onDragLeave.bind( this ),
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 );
}
};
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 */
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 ) {
};
/**
- * Add the input to the handle
+ * Add the input to the widget
*
* @private
*/
if ( this.accept ) {
this.$input.attr( 'accept', this.accept.join( ', ' ) );
}
- this.$handle.append( this.$input );
+ this.selectButton.$button.append( this.$input );
};
/**
* Determine if we should accept this file
*
* @private
- * @param {File} file
+ * @param {string} File MIME type
* @return {boolean}
*/
-OO.ui.SelectFileWidget.prototype.isFileAcceptable = function ( file ) {
- var i, mime, mimeTest;
+OO.ui.SelectFileWidget.prototype.isAllowedType = function ( mimeType ) {
+ var i, mimeTest;
- if ( !this.accept || file.type === '' ) {
+ if ( !this.accept || !mimeType ) {
return true;
}
- mime = file.type;
for ( i = 0; i < this.accept.length; i++ ) {
mimeTest = this.accept[ i ];
- if ( mimeTest === mime ) {
+ if ( mimeTest === mimeType ) {
return true;
} else if ( mimeTest.substr( -2 ) === '/*' ) {
mimeTest = mimeTest.substr( 0, mimeTest.length - 1 );
- if ( mime.substr( 0, mimeTest.length ) === mimeTest ) {
+ if ( mimeType.substr( 0, mimeTest.length ) === mimeTest ) {
return true;
}
}
* @param {jQuery.Event} e
*/
OO.ui.SelectFileWidget.prototype.onFileSelected = function ( e ) {
- var file = null;
+ var file = OO.getProp( e.target, 'files', 0 ) || null;
- if ( e.target.files && e.target.files[ 0 ] ) {
- file = e.target.files[ 0 ];
- if ( !this.isFileAcceptable( file ) ) {
- file = null;
- }
+ if ( file && !this.isAllowedType( file.type ) ) {
+ file = null;
}
this.setValue( file );
}
};
+/**
+ * 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
*
* @param {jQuery.Event} e Drag event
*/
OO.ui.SelectFileWidget.prototype.onDragEnterOrOver = function ( e ) {
- var file = null,
+ var itemOrFile,
+ droppableFile = false,
dt = e.originalEvent.dataTransfer;
e.preventDefault();
if ( this.isDisabled() || !this.isSupported ) {
this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' );
- this.setActive( false );
dt.dropEffect = 'none';
return false;
}
- if ( dt && dt.files && dt.files[ 0 ] ) {
- file = dt.files[ 0 ];
- if ( !this.isFileAcceptable( file ) ) {
- file = null;
+ // DataTransferItem and File both have a type property, but in Chrome files
+ // have no information at this point.
+ itemOrFile = OO.getProp( dt, 'items', 0 ) || OO.getProp( dt, 'files', 0 );
+ if ( itemOrFile ) {
+ if ( this.isAllowedType( itemOrFile.type ) ) {
+ droppableFile = true;
}
- } else if ( dt && dt.types && dt.types.indexOf( 'Files' ) !== -1 ) {
- // 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';
+ // dt.types is Array-like, but not an Array
+ } else if ( Array.prototype.indexOf.call( OO.getProp( dt, 'types' ) || [], 'Files' ) !== -1 ) {
+ // File information is not available at this point for security so just assume
+ // it is acceptable for now.
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=640534
+ droppableFile = true;
}
- if ( file ) {
- this.$element.addClass( 'oo-ui-selectFileWidget-canDrop' );
- this.setActive( true );
- } else {
- this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' );
- this.setActive( false );
+
+ this.$element.toggleClass( 'oo-ui-selectFileWidget-canDrop', droppableFile );
+ if ( !droppableFile ) {
dt.dropEffect = 'none';
}
*/
OO.ui.SelectFileWidget.prototype.onDragLeave = function () {
this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' );
- this.setActive( false );
};
/**
e.preventDefault();
e.stopPropagation();
this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' );
- this.setActive( false );
if ( this.isDisabled() || !this.isSupported ) {
return false;
}
- if ( dt && dt.files && dt.files[ 0 ] ) {
- file = dt.files[ 0 ];
- if ( !this.isFileAcceptable( file ) ) {
- file = null;
- }
+ file = OO.getProp( dt, 'files', 0 );
+ if ( file && !this.isAllowedType( file.type ) ) {
+ file = null;
}
if ( file ) {
this.setValue( file );
return false;
};
-/**
- * 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;
};