Merge "API: Use message-per-value for apihelp-query+recentchanges-param-prop"
[lhc/web/wiklou.git] / resources / src / mediawiki / mediawiki.Upload.js
1 ( function ( mw, $ ) {
2 var UP;
3
4 /**
5 * @class mw.Upload
6 *
7 * Used to represent an upload in progress on the frontend.
8 * Most of the functionality is implemented in mw.Api.plugin.upload,
9 * but this model class will tie it together as well as let you perform
10 * actions in a logical way.
11 *
12 * A simple example:
13 *
14 * var file = new OO.ui.SelectFileWidget(),
15 * button = new OO.ui.ButtonWidget( { label: 'Save' } ),
16 * upload = new mw.Upload;
17 *
18 * button.on( 'click', function () {
19 * upload.setFile( file.getValue() );
20 * upload.setFilename( file.getValue().name );
21 * upload.upload();
22 * } );
23 *
24 * $( 'body' ).append( file.$element, button.$element );
25 *
26 * You can also choose to {@link #uploadToStash stash the upload} and
27 * {@link #finishStashUpload finalize} it later:
28 *
29 * var file, // Some file object
30 * upload = new mw.Upload,
31 * stashPromise = $.Deferred();
32 *
33 * upload.setFile( file );
34 * upload.uploadToStash().then( function () {
35 * stashPromise.resolve();
36 * } );
37 *
38 * stashPromise.then( function () {
39 * upload.setFilename( 'foo' );
40 * upload.setText( 'bar' );
41 * upload.finishStashUpload().then( function () {
42 * console.log( 'Done!' );
43 * } );
44 * } );
45 *
46 * @constructor
47 * @param {Object} apiconfig Passed to the constructor of mw.Api.
48 */
49 function Upload( apiconfig ) {
50 this.api = new mw.Api( apiconfig );
51
52 this.watchlist = false;
53 this.text = '';
54 this.comment = '';
55 this.filename = null;
56 this.file = null;
57 this.state = Upload.State.NEW;
58
59 this.imageinfo = undefined;
60 }
61
62 UP = Upload.prototype;
63
64 /**
65 * Set the text of the file page, to be created on file upload.
66 * @param {string} text
67 */
68 UP.setText = function ( text ) {
69 this.text = text;
70 };
71
72 /**
73 * Set the filename, to be finalized on upload.
74 * @param {string} filename
75 */
76 UP.setFilename = function ( filename ) {
77 this.filename = filename;
78 };
79
80 /**
81 * Sets the filename based on the filename as it was on the upload.
82 */
83 UP.setFilenameFromFile = function () {
84 if ( this.file.nodeType && this.file.nodeType === Node.ELEMENT_NODE ) {
85 // File input element, use getBasename to cut out the path
86 this.setFilename( this.getBasename( this.file.value ) );
87 } else if ( this.file.name && this.file.lastModified ) {
88 // HTML5 FileAPI File object, but use getBasename to be safe
89 this.setFilename( this.getBasename( this.file.name ) );
90 }
91 };
92
93 /**
94 * Set the file to be uploaded.
95 * @param {HTMLInputElement|File} file
96 */
97 UP.setFile = function ( file ) {
98 this.file = file;
99 };
100
101 /**
102 * Set whether the file should be watchlisted after upload.
103 * @param {boolean} watchlist
104 */
105 UP.setWatchlist = function ( watchlist ) {
106 this.watchlist = watchlist;
107 };
108
109 /**
110 * Set the edit comment for the upload.
111 * @param {string} comment
112 */
113 UP.setComment = function ( comment ) {
114 this.comment = comment;
115 };
116
117 /**
118 * Get the text of the file page, to be created on file upload.
119 * @return {string}
120 */
121 UP.getText = function () {
122 return this.text;
123 };
124
125 /**
126 * Get the filename, to be finalized on upload.
127 * @return {string}
128 */
129 UP.getFilename = function () {
130 return this.filename;
131 };
132
133 /**
134 * Get the file being uploaded.
135 * @return {HTMLInputElement|File}
136 */
137 UP.getFile = function () {
138 return this.file;
139 };
140
141 /**
142 * Get the boolean for whether the file will be watchlisted after upload.
143 * @return {boolean}
144 */
145 UP.getWatchlist = function () {
146 return this.watchlist;
147 };
148
149 /**
150 * Get the current value of the edit comment for the upload.
151 * @return {string}
152 */
153 UP.getComment = function () {
154 return this.comment;
155 };
156
157 /**
158 * Gets the base filename from a path name.
159 * @param {string} path
160 * @return {string}
161 */
162 UP.getBasename = function ( path ) {
163 if ( path === undefined || path === null ) {
164 return '';
165 }
166
167 // Find the index of the last path separator in the
168 // path, and add 1. Then, take the entire string after that.
169 return path.slice(
170 Math.max(
171 path.lastIndexOf( '/' ),
172 path.lastIndexOf( '\\' )
173 ) + 1
174 );
175 };
176
177 /**
178 * Gets the state of the upload.
179 * @return {mw.Upload.State}
180 */
181 UP.getState = function () {
182 return this.state;
183 };
184
185 /**
186 * Get the imageinfo object for the finished upload.
187 * Only available once the upload is finished! Don't try to get it
188 * beforehand.
189 * @return {Object|undefined}
190 */
191 UP.getImageInfo = function () {
192 return this.imageinfo;
193 };
194
195 /**
196 * Upload the file directly.
197 * @return {jQuery.Promise}
198 */
199 UP.upload = function () {
200 var upload = this;
201
202 if ( !this.file ) {
203 return $.Deferred().reject( 'No file to upload. Call setFile to add one.' );
204 }
205
206 if ( !this.filename ) {
207 return $.Deferred().reject( 'No filename set. Call setFilename to add one.' );
208 }
209
210 this.state = Upload.State.UPLOADING;
211
212 return this.api.upload( this.file, {
213 watchlist: ( this.watchlist === true ) ? 1 : undefined,
214 comment: this.comment,
215 filename: this.filename,
216 text: this.text
217 } ).then( function ( result ) {
218 upload.state = Upload.State.UPLOADED;
219 upload.imageinfo = result.upload.imageinfo;
220 return result;
221 }, function () {
222 upload.state = Upload.State.ERROR;
223 } );
224 };
225
226 /**
227 * Upload the file to the stash to be completed later.
228 * @return {jQuery.Promise}
229 */
230 UP.uploadToStash = function () {
231 var upload = this;
232
233 if ( !this.file ) {
234 return $.Deferred().reject( 'No file to upload. Call setFile to add one.' );
235 }
236
237 if ( !this.filename ) {
238 this.setFilenameFromFile();
239 }
240
241 this.state = Upload.State.UPLOADING;
242
243 this.stashPromise = this.api.uploadToStash( this.file, {
244 filename: this.filename
245 } ).then( function ( finishStash ) {
246 upload.state = Upload.State.STASHED;
247 return finishStash;
248 }, function () {
249 upload.state = Upload.State.ERROR;
250 } );
251
252 return this.stashPromise;
253 };
254
255 /**
256 * Finish a stash upload.
257 * @return {jQuery.Promise}
258 */
259 UP.finishStashUpload = function () {
260 var upload = this;
261
262 if ( !this.stashPromise ) {
263 return $.Deferred().reject( 'This upload has not been stashed, please upload it to the stash first.' );
264 }
265
266 return this.stashPromise.then( function ( finishStash ) {
267 upload.state = Upload.State.UPLOADING;
268
269 return finishStash( {
270 watchlist: ( upload.watchlist === true ) ? 1 : undefined,
271 comment: upload.getComment(),
272 filename: upload.getFilename(),
273 text: upload.getText()
274 } ).then( function () {
275 upload.state = Upload.State.UPLOADED;
276 }, function () {
277 upload.state = Upload.State.ERROR;
278 } );
279 } );
280 };
281
282 /**
283 * @enum mw.Upload.State
284 * State of uploads represented in simple terms.
285 */
286 Upload.State = {
287 /** Upload not yet started */
288 NEW: 0,
289
290 /** Upload finished, but there was a warning */
291 WARNING: 1,
292
293 /** Upload finished, but there was an error */
294 ERROR: 2,
295
296 /** Upload in progress */
297 UPLOADING: 3,
298
299 /** Upload finished, but not published, call #finishStashUpload */
300 STASHED: 4,
301
302 /** Upload finished and published */
303 UPLOADED: 5
304 };
305
306 mw.Upload = Upload;
307 }( mediaWiki, jQuery ) );