5 * Used to represent an upload in progress on the frontend.
6 * Most of the functionality is implemented in mw.Api.plugin.upload,
7 * but this model class will tie it together as well as let you perform
8 * actions in a logical way.
12 * var file = new OO.ui.SelectFileWidget(),
13 * button = new OO.ui.ButtonWidget( { label: 'Save' } ),
14 * upload = new mw.Upload;
16 * button.on( 'click', function () {
17 * upload.setFile( file.getValue() );
18 * upload.setFilename( file.getValue().name );
22 * $( 'body' ).append( file.$element, button.$element );
24 * You can also choose to {@link #uploadToStash stash the upload} and
25 * {@link #finishStashUpload finalize} it later:
27 * var file, // Some file object
28 * upload = new mw.Upload,
29 * stashPromise = $.Deferred();
31 * upload.setFile( file );
32 * upload.uploadToStash().then( function () {
33 * stashPromise.resolve();
36 * stashPromise.then( function () {
37 * upload.setFilename( 'foo' );
38 * upload.setText( 'bar' );
39 * upload.finishStashUpload().then( function () {
40 * console.log( 'Done!' );
47 * @param {Object|mw.Api} [apiconfig] A mw.Api object (or subclass), or configuration
48 * to pass to the constructor of mw.Api.
50 function Upload( apiconfig
) {
51 this.api
= ( apiconfig
instanceof mw
.Api
) ? apiconfig
: new mw
.Api( apiconfig
);
53 this.watchlist
= false;
58 this.setState( Upload
.State
.NEW
);
60 this.imageinfo
= undefined;
63 UP
= Upload
.prototype;
66 * Get the mw.Api instance used by this Upload object.
68 * @return {jQuery.Promise}
69 * @return {Function} return.done
70 * @return {mw.Api} return.done.api
72 UP
.getApi = function () {
73 return $.Deferred().resolve( this.api
).promise();
77 * Set the text of the file page, to be created on file upload.
79 * @param {string} text
81 UP
.setText = function ( text
) {
86 * Set the filename, to be finalized on upload.
88 * @param {string} filename
90 UP
.setFilename = function ( filename
) {
91 this.filename
= filename
;
95 * Set the stashed file to finish uploading.
97 * @param {string} filekey
99 UP
.setFilekey = function ( filekey
) {
102 this.setState( Upload
.State
.STASHED
);
103 this.stashPromise
= $.Deferred().resolve( function ( data
) {
104 return upload
.api
.uploadFromStash( filekey
, data
);
109 * Sets the filename based on the filename as it was on the upload.
111 UP
.setFilenameFromFile = function () {
112 var file
= this.getFile();
116 if ( file
.nodeType
&& file
.nodeType
=== Node
.ELEMENT_NODE
) {
117 // File input element, use getBasename to cut out the path
118 this.setFilename( this.getBasename( file
.value
) );
119 } else if ( file
.name
) {
120 // HTML5 FileAPI File object, but use getBasename to be safe
121 this.setFilename( this.getBasename( file
.name
) );
123 // If we ever implement uploading files from clipboard, they might not have a name
124 this.setFilename( '?' );
129 * Set the file to be uploaded.
131 * @param {HTMLInputElement|File|Blob} file
133 UP
.setFile = function ( file
) {
138 * Set whether the file should be watchlisted after upload.
140 * @param {boolean} watchlist
142 UP
.setWatchlist = function ( watchlist
) {
143 this.watchlist
= watchlist
;
147 * Set the edit comment for the upload.
149 * @param {string} comment
151 UP
.setComment = function ( comment
) {
152 this.comment
= comment
;
156 * Get the text of the file page, to be created on file upload.
160 UP
.getText = function () {
165 * Get the filename, to be finalized on upload.
169 UP
.getFilename = function () {
170 return this.filename
;
174 * Get the file being uploaded.
176 * @return {HTMLInputElement|File|Blob}
178 UP
.getFile = function () {
183 * Get the boolean for whether the file will be watchlisted after upload.
187 UP
.getWatchlist = function () {
188 return this.watchlist
;
192 * Get the current value of the edit comment for the upload.
196 UP
.getComment = function () {
201 * Gets the base filename from a path name.
203 * @param {string} path
206 UP
.getBasename = function ( path
) {
207 if ( path
=== undefined || path
=== null ) {
211 // Find the index of the last path separator in the
212 // path, and add 1. Then, take the entire string after that.
215 path
.lastIndexOf( '/' ),
216 path
.lastIndexOf( '\\' )
222 * Sets the state and state details (if any) of the upload.
224 * @param {mw.Upload.State} state
225 * @param {Object} stateDetails
227 UP
.setState = function ( state
, stateDetails
) {
229 this.stateDetails
= stateDetails
;
233 * Gets the state of the upload.
235 * @return {mw.Upload.State}
237 UP
.getState = function () {
242 * Gets details of the current state.
246 UP
.getStateDetails = function () {
247 return this.stateDetails
;
251 * Get the imageinfo object for the finished upload.
252 * Only available once the upload is finished! Don't try to get it
255 * @return {Object|undefined}
257 UP
.getImageInfo = function () {
258 return this.imageinfo
;
262 * Upload the file directly.
264 * @return {jQuery.Promise}
266 UP
.upload = function () {
269 if ( !this.getFile() ) {
270 return $.Deferred().reject( 'No file to upload. Call setFile to add one.' );
273 if ( !this.getFilename() ) {
274 return $.Deferred().reject( 'No filename set. Call setFilename to add one.' );
277 this.setState( Upload
.State
.UPLOADING
);
279 return this.api
.upload( this.getFile(), {
280 watchlist
: ( this.getWatchlist() ) ? 1 : undefined,
281 comment
: this.getComment(),
282 filename
: this.getFilename(),
284 } ).then( function ( result
) {
285 upload
.setState( Upload
.State
.UPLOADED
);
286 upload
.imageinfo
= result
.upload
.imageinfo
;
288 }, function ( errorCode
, result
) {
289 if ( result
&& result
.upload
&& result
.upload
.warnings
) {
290 upload
.setState( Upload
.State
.WARNING
, result
);
292 upload
.setState( Upload
.State
.ERROR
, result
);
294 return $.Deferred().reject( errorCode
, result
);
299 * Upload the file to the stash to be completed later.
301 * @return {jQuery.Promise}
303 UP
.uploadToStash = function () {
306 if ( !this.getFile() ) {
307 return $.Deferred().reject( 'No file to upload. Call setFile to add one.' );
310 if ( !this.getFilename() ) {
311 this.setFilenameFromFile();
314 this.setState( Upload
.State
.UPLOADING
);
316 this.stashPromise
= this.api
.uploadToStash( this.getFile(), {
317 filename
: this.getFilename()
318 } ).then( function ( finishStash
) {
319 upload
.setState( Upload
.State
.STASHED
);
321 }, function ( errorCode
, result
) {
322 if ( result
&& result
.upload
&& result
.upload
.warnings
) {
323 upload
.setState( Upload
.State
.WARNING
, result
);
325 upload
.setState( Upload
.State
.ERROR
, result
);
327 return $.Deferred().reject( errorCode
, result
);
330 return this.stashPromise
;
334 * Finish a stash upload.
336 * @return {jQuery.Promise}
338 UP
.finishStashUpload = function () {
341 if ( !this.stashPromise
) {
342 return $.Deferred().reject( 'This upload has not been stashed, please upload it to the stash first.' );
345 return this.stashPromise
.then( function ( finishStash
) {
346 upload
.setState( Upload
.State
.UPLOADING
);
348 return finishStash( {
349 watchlist
: ( upload
.getWatchlist() ) ? 1 : undefined,
350 comment
: upload
.getComment(),
351 filename
: upload
.getFilename(),
352 text
: upload
.getText()
353 } ).then( function ( result
) {
354 upload
.setState( Upload
.State
.UPLOADED
);
355 upload
.imageinfo
= result
.upload
.imageinfo
;
357 }, function ( errorCode
, result
) {
358 if ( result
&& result
.upload
&& result
.upload
.warnings
) {
359 upload
.setState( Upload
.State
.WARNING
, result
);
361 upload
.setState( Upload
.State
.ERROR
, result
);
363 return $.Deferred().reject( errorCode
, result
);
369 * @enum mw.Upload.State
370 * State of uploads represented in simple terms.
373 /** Upload not yet started */
376 /** Upload finished, but there was a warning */
379 /** Upload finished, but there was an error */
382 /** Upload in progress */
385 /** Upload finished, but not published, call #finishStashUpload */
388 /** Upload finished and published */
393 }( mediaWiki
, jQuery
) );