'mediawiki.user',
'mediawiki.Upload',
'mediawiki.jqueryMsg',
+ 'mediawiki.widgets.StashedFileWidget'
],
'messages' => [
'upload-form-label-infoform-title',
'position' => 'top',
'targets' => [ 'desktop', 'mobile' ],
],
-
+ 'mediawiki.widgets.StashedFileWidget' => [
+ 'scripts' => [
+ 'resources/src/mediawiki.widgets/mw.widgets.StashedFileWidget.js',
+ ],
+ 'skinStyles' => [
+ 'default' => [
+ 'resources/src/mediawiki.widgets/mw.widgets.StashedFileWidget.less',
+ ],
+ ],
+ 'dependencies' => [
+ 'oojs-ui-core',
+ ],
+ ],
/* es5-shim */
'es5-shim' => [
'scripts' => [
--- /dev/null
+/*!
+ * MediaWiki Widgets - StashedFileWidget class.
+ *
+ * @copyright 2011-2016 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw, OO ) {
+
+ /**
+ * Accepts a stashed file and displays the information for purposes of
+ * publishing the file at the behest of the user.
+ *
+ * Example use:
+ * var widget = new mw.widgets.StashedFileWidget( {
+ * filekey: '12r9e4rugeec.ddtmmp.1.jpg',
+ * } );
+ *
+ * widget.getValue(); // '12r9e4rugeec.ddtmmp.1.jpg'
+ * widget.setValue( '12r9epfbnskk.knfiy7.1.jpg' );
+ * widget.getValue(); // '12r9epfbnskk.knfiy7.1.jpg'
+ *
+ * Note that this widget will not finish an upload for you. Use mw.Upload
+ * and mw.Upload#setFilekey, then mw.Upload#finishStashUpload to accomplish
+ * that.
+ *
+ * @class mw.widgets.StashedFileWidget
+ * @extends OO.ui.Widget
+ */
+
+ /**
+ * @constructor
+ * @param {Object} config Configuration options
+ * @cfg {string} filekey The filekey of the stashed file.
+ * @cfg {Object} [api] API to use for thumbnails.
+ */
+ mw.widgets.StashedFileWidget = function MWWStashedFileWidget( config ) {
+ if ( !config.api ) {
+ config.api = new mw.Api();
+ }
+
+ // Parent constructor
+ mw.widgets.StashedFileWidget.parent.call( this, config );
+
+ // Mixin constructors
+ OO.ui.mixin.IconElement.call( this, config );
+ OO.ui.mixin.LabelElement.call( this, config );
+ OO.ui.mixin.PendingElement.call( this, config );
+
+ // Properties
+ this.api = config.api;
+ this.$info = $( '<span>' );
+ this.setValue( config.filekey );
+ this.$label.addClass( 'mw-widgets-stashedFileWidget-label' );
+ this.$info
+ .addClass( 'mw-widgets-stashedFileWidget-info' )
+ .append( this.$icon, this.$label );
+
+ this.$thumbnail = $( '<div>' ).addClass( 'mw-widgets-stashedFileWidget-thumbnail' );
+ this.setPendingElement( this.$thumbnail );
+
+ this.$thumbContain = $( '<div>' )
+ .addClass( 'mw-widgets-stashedFileWidget-thumbnail-container' )
+ .append( this.$thumbnail, this.$info );
+
+ this.$element
+ .addClass( 'mw-widgets-stashedFileWidget' )
+ .append( this.$thumbContain );
+
+ this.updateUI();
+ };
+
+ OO.inheritClass( mw.widgets.StashedFileWidget, OO.ui.Widget );
+ OO.mixinClass( mw.widgets.StashedFileWidget, OO.ui.mixin.IconElement );
+ OO.mixinClass( mw.widgets.StashedFileWidget, OO.ui.mixin.LabelElement );
+ OO.mixinClass( mw.widgets.StashedFileWidget, OO.ui.mixin.PendingElement );
+
+ /**
+ * Get the current filekey.
+ *
+ * @return {string|null}
+ */
+ mw.widgets.StashedFileWidget.prototype.getValue = function () {
+ return this.filekey;
+ };
+
+ /**
+ * Set the filekey.
+ *
+ * @param {string|null} filekey
+ */
+ mw.widgets.StashedFileWidget.prototype.setValue = function ( filekey ) {
+ if ( filekey !== this.filekey ) {
+ this.filekey = filekey;
+ this.updateUI();
+ this.emit( 'change', this.filekey );
+ }
+ };
+
+ mw.widgets.StashedFileWidget.prototype.updateUI = function () {
+ var $label, $filetype;
+
+ if ( this.filekey ) {
+ this.$element.removeClass( 'mw-widgets-stashedFileWidget-empty' );
+ $label = $( [] );
+ $filetype = $( '<span>' )
+ .addClass( 'mw-widgets-stashedFileWidget-fileType' );
+
+ $label = $label.add(
+ $( '<span>' )
+ .addClass( 'mw-widgets-stashedFileWidget-filekey' )
+ .text( this.filekey )
+ ).add( $filetype );
+
+ this.setLabel( $label );
+
+ this.pushPending();
+ this.loadAndGetImageUrl().done( function ( url, mime ) {
+ this.$thumbnail.css( 'background-image', 'url( ' + url + ' )' );
+ if ( mime ) {
+ $filetype.text( mime );
+ this.setLabel( $label );
+ }
+ }.bind( this ) ).fail( function () {
+ this.$thumbnail.append(
+ new OO.ui.IconWidget( {
+ icon: 'attachment',
+ classes: [ 'mw-widgets-stashedFileWidget-noThumbnail-icon' ]
+ } ).$element
+ );
+ }.bind( this ) ).always( function () {
+ this.popPending();
+ }.bind( this ) );
+ } else {
+ this.$element.addClass( 'mw-widgets-stashedFileWidget-empty' );
+ this.setLabel( '' );
+ }
+ };
+
+ mw.widgets.StashedFileWidget.prototype.loadAndGetImageUrl = function () {
+ var filekey = this.filekey;
+
+ if ( filekey ) {
+ return this.api.get( {
+ action: 'query',
+ prop: 'stashimageinfo',
+ siifilekey: filekey,
+ siiprop: [ 'size', 'url', 'mime' ],
+ siiurlwidth: 220
+ } ).then( function ( data ) {
+ var sii = data.query.stashimageinfo[ 0 ];
+
+ return $.Deferred().resolve( sii.thumburl, sii.mime );
+ } );
+ }
+
+ return $.Deferred().reject( 'No filekey' );
+ };
+}( jQuery, mediaWiki, OO ) );
--- /dev/null
+.mw-widgets-stashedFileWidget {
+ display: inline-block;
+ vertical-align: middle;
+ width: 100%;
+ max-width: 50em;
+ margin-right: 0.5em;
+
+ &:last-child {
+ margin-right: 0;
+ }
+
+ &.oo-ui-iconElement .mw-widgets-stashedFileWidget-info .mw-widgets-stashedFileWidget-label {
+ left: 2.875em;
+ }
+
+ &.oo-ui-indicatorElement .mw-widgets-stashedFileWidget-info .mw-widgets-stashedFileWidget-label {
+ right: 4.4625em;
+ }
+}
+
+.mw-widgets-stashedFileWidget-info {
+ height: 2.4em;
+ background-color: #ffffff;
+ border: 1px solid #cccccc;
+ border-radius: 2px;
+ width: 100%;
+ display: table-cell;
+ vertical-align: middle;
+ position: relative;
+ overflow: hidden;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+
+ > .mw-widgets-stashedFileWidget-label {
+ line-height: 2.3em;
+ margin: 0;
+ overflow: hidden;
+ white-space: nowrap;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ text-overflow: ellipsis;
+ left: 0.5em;
+ right: 2.375em;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+
+ > .mw-widgets-stashedFileWidget-fileName {
+ float: left;
+ }
+ > .mw-widgets-stashedFileWidget-fileType {
+ color: #888888;
+ float: right;
+ }
+ }
+
+ > .oo-ui-indicatorElement-indicator,
+ > .oo-ui-iconElement-icon {
+ position: absolute;
+ }
+
+ > .oo-ui-indicatorElement-indicator {
+ right: 0;
+ top: 0;
+ width: 0.9375em;
+ height: 2.3em;
+ margin-right: 0.775em;
+ }
+
+ > .oo-ui-iconElement-icon {
+ top: 0;
+ width: 1.875em;
+ height: 2.3em;
+ margin-left: 0.5em;
+ left: 0;
+ }
+
+ &.oo-ui-widget-disabled {
+ .mw-widgets-stashedFileWidget-info {
+ color: #cccccc;
+ text-shadow: 0 1px 1px #ffffff;
+ border-color: #dddddd;
+ background-color: #f3f3f3;
+
+ > .oo-ui-iconElement-icon,
+ > .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+ }
+ }
+ }
+}
+
+.mw-widgets-stashedFileWidget-thumbnail-container {
+ cursor: default;
+ height: 5.5em;
+ text-align: left;
+ padding: 0;
+ background-color: #ffffff;
+ border: 1px solid #cccccc;
+ margin-bottom: 0.5em;
+ vertical-align: middle;
+ overflow: hidden;
+ border-radius: 2px;
+
+ .mw-widgets-stashedFileWidget-thumbnail {
+ height: 5.5em;
+ width: 5.5em;
+ position: absolute;
+ background-size: cover;
+ background-position: center center;
+
+ &.oo-ui-pendingElement-pending {
+ background-size: auto;
+ }
+
+ > .mw-widgets-stashedFileWidget-noThumbnail-icon {
+ opacity: 0.4;
+ background-color: #cccccc;
+ height: 5.5em;
+ width: 5.5em;
+ }
+ }
+
+ .mw-widgets-stashedFileWidget-info {
+ border: none;
+ background: none;
+ display: block;
+ height: 100%;
+ width: auto;
+ margin-left: 5.5em;
+
+ > .mw-widgets-stashedFileWidget-label {
+ position: relative;
+
+ > .mw-widgets-stashedFileWidget-fileName {
+ display: block;
+ float: none;
+ }
+
+ > .mw-widgets-stashedFileWidget-fileType {
+ display: block;
+ float: none;
+ }
+ }
+ }
+}
+
+
+.mw-widgets-stashedFileWidget-empty {
+ .mw-widgets-stashedFileWidget-thumbnail-container {
+ text-align: center;
+
+ .mw-widgets-stashedFileWidget-thumbnail,
+ .mw-widgets-stashedFileWidget-info {
+ margin: 0;
+ display: none;
+ }
+ }
+
+ .mw-widgets-stashedFileWidget-label {
+ color: #cccccc;
+ right: 0.5em;
+ }
+
+ &.oo-ui-indicatorElement {
+ .mw-widgets-stashedFileWidget-label {
+ right: 2em;
+ }
+ }
+}
}
function finishUpload( moreData ) {
- data = $.extend( data, moreData );
- data.filekey = filekey;
- data.action = 'upload';
- data.format = 'json';
-
- if ( !data.filename ) {
- throw new Error( 'Filename not included in file data.' );
- }
-
- return api.postWithEditToken( data ).then( function ( result ) {
- if ( result.upload && result.upload.warnings ) {
- return $.Deferred().reject( getFirstKey( result.upload.warnings ), result ).promise();
- }
- return result;
- } );
+ api.uploadFromStash( filekey, $.extend( data, moreData ) );
}
return this.upload( file, { stash: true, filename: data.filename } ).then(
);
},
+ /**
+ * Finish an upload in the stash.
+ *
+ * @param {string} filekey
+ * @param {Object} data
+ */
+ uploadFromStash: function ( filekey, data ) {
+ data.filekey = filekey;
+ data.action = 'upload';
+ data.format = 'json';
+
+ if ( !data.filename ) {
+ throw new Error( 'Filename not included in file data.' );
+ }
+
+ return this.postWithEditToken( data ).then( function ( result ) {
+ if ( result.upload && result.upload.warnings ) {
+ return $.Deferred().reject( getFirstKey( result.upload.warnings ), result ).promise();
+ }
+ return result;
+ } );
+ },
+
needToken: function () {
return true;
}
* @constructor
* @param {Object} config Configuration options
* @cfg {jQuery} [$overlay] Overlay to use for widgets in the booklet
+ * @cfg {string} [filekey] Sets the stashed file to finish uploading. Overrides most of the file selection process, and fetches a thumbnail from the server.
*/
mw.Upload.BookletLayout = function ( config ) {
// Parent constructor
this.$overlay = config.$overlay;
+ this.filekey = config.filekey;
+
this.renderUploadForm();
this.renderInfoForm();
this.renderInsertForm();
this.clear();
this.upload = this.createUpload();
+
this.setPage( 'upload' );
+ if ( this.filekey ) {
+ this.setFilekey( this.filekey );
+ }
+
return this.upload.getApi().then(
function ( api ) {
// If the user can't upload anything, don't give them the option to.
layout = this,
file = this.getFile();
- this.setFilename( file.name );
-
this.setPage( 'info' );
+ if ( this.filekey ) {
+ if ( file === null ) {
+ // Someone gonna get-a hurt real bad
+ throw new Error( 'filekey not passed into file select widget, which is impossible. Quitting while we\'re behind.' );
+ }
+
+ // Stashed file already uploaded.
+ deferred.resolve();
+ this.uploadPromise = deferred;
+ this.emit( 'fileUploaded' );
+ return deferred;
+ }
+
+ this.setFilename( file.name );
+
this.upload.setFile( file );
// The original file name might contain invalid characters, so use our sanitized one
this.upload.setFilename( this.getFilename() );
var fieldset,
layout = this;
- this.selectFileWidget = new OO.ui.SelectFileWidget( {
- showDropTarget: true
- } );
+ this.selectFileWidget = this.getFileWidget();
fieldset = new OO.ui.FieldsetLayout();
fieldset.addItems( [ this.selectFileWidget ] );
this.uploadForm = new OO.ui.FormLayout( { items: [ fieldset ] } );
- // Validation
+ // Validation (if the SFW is for a stashed file, this never fires)
this.selectFileWidget.on( 'change', this.onUploadFormChange.bind( this ) );
this.selectFileWidget.on( 'change', function () {
return this.uploadForm;
};
+ /**
+ * Gets the widget for displaying or inputting the file to upload.
+ *
+ * @return {OO.ui.SelectFileWidget|mw.widgets.StashedFileWidget}
+ */
+ mw.Upload.BookletLayout.prototype.getFileWidget = function () {
+ if ( this.filekey ) {
+ return new mw.widgets.StashedFileWidget( {
+ filekey: this.filekey
+ } );
+ }
+
+ return new OO.ui.SelectFileWidget( {
+ showDropTarget: true
+ } );
+ };
+
/**
* Updates the file preview on the info form when a file is added.
*
this.selectFileWidget.setValue( file );
};
+ /**
+ * Sets the filekey of a file already stashed on the server
+ * as the target of this upload operation.
+ *
+ * @protected
+ * @param {string} filekey
+ */
+ mw.Upload.BookletLayout.prototype.setFilekey = function ( filekey ) {
+ this.upload.setFilekey( this.filekey );
+ this.selectFileWidget.setValue( filekey );
+
+ this.onUploadFormChange();
+ };
+
/**
* Clear the values of all fields
*
this.filename = filename;
};
+ /**
+ * Set the stashed file to finish uploading.
+ *
+ * @param {string} filekey
+ */
+ UP.setFilekey = function ( filekey ) {
+ var upload = this;
+
+ this.setState( Upload.State.STASHED );
+ this.stashPromise = $.Deferred().resolve( function ( data ) {
+ return upload.api.uploadFromStash( filekey, data );
+ } );
+ };
+
/**
* Sets the filename based on the filename as it was on the upload.
*/