Merge "Fix sessionfailure i18n message during authentication"
[lhc/web/wiklou.git] / resources / src / mediawiki / mediawiki.ForeignStructuredUpload.js
1 ( function ( mw, $, OO ) {
2 /**
3 * Used to represent an upload in progress on the frontend.
4 *
5 * This subclass will upload to a wiki using a structured metadata
6 * system similar to (or identical to) the one on Wikimedia Commons.
7 *
8 * See <https://commons.wikimedia.org/wiki/Commons:Structured_data> for
9 * a more detailed description of how that system works.
10 *
11 * **TODO: This currently only supports uploads under CC-BY-SA 4.0,
12 * and should really have support for more licenses.**
13 *
14 * @class mw.ForeignStructuredUpload
15 * @extends mw.ForeignUpload
16 *
17 * @constructor
18 * @param {string} [target]
19 * @param {Object} [apiconfig]
20 */
21 function ForeignStructuredUpload( target, apiconfig ) {
22 this.date = undefined;
23 this.descriptions = [];
24 this.categories = [];
25
26 // Config for uploads to local wiki.
27 // Can be overridden with foreign wiki config when #loadConfig is called.
28 this.config = mw.config.get( 'wgUploadDialog' );
29
30 mw.ForeignUpload.call( this, target, apiconfig );
31 }
32
33 OO.inheritClass( ForeignStructuredUpload, mw.ForeignUpload );
34
35 /**
36 * Get the configuration for the form and filepage from the foreign wiki, if any, and use it for
37 * this upload.
38 *
39 * @return {jQuery.Promise} Promise returning config object
40 */
41 ForeignStructuredUpload.prototype.loadConfig = function () {
42 var deferred,
43 upload = this;
44
45 if ( this.configPromise ) {
46 return this.configPromise;
47 }
48
49 if ( this.target === 'local' ) {
50 deferred = $.Deferred();
51 setTimeout( function () {
52 // Resolve asynchronously, so that it's harder to accidentally write synchronous code that
53 // will break for cross-wiki uploads
54 deferred.resolve( upload.config );
55 } );
56 this.configPromise = deferred.promise();
57 } else {
58 this.configPromise = this.apiPromise.then( function ( api ) {
59 // Get the config from the foreign wiki
60 return api.get( {
61 action: 'query',
62 meta: 'siteinfo',
63 siprop: 'uploaddialog',
64 // For convenient true/false booleans
65 formatversion: 2
66 } ).then( function ( resp ) {
67 // Foreign wiki might be running a pre-1.27 MediaWiki, without support for this
68 if ( resp.query && resp.query.uploaddialog ) {
69 upload.config = resp.query.uploaddialog;
70 return upload.config;
71 } else {
72 return $.Deferred().reject( 'upload-foreign-cant-load-config' );
73 }
74 }, function () {
75 return $.Deferred().reject( 'upload-foreign-cant-load-config' );
76 } );
77 } );
78 }
79
80 return this.configPromise;
81 };
82
83 /**
84 * Add categories to the upload.
85 *
86 * @param {string[]} categories Array of categories to which this upload will be added.
87 */
88 ForeignStructuredUpload.prototype.addCategories = function ( categories ) {
89 // The length of the array must be less than 10000.
90 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push#Merging_two_arrays
91 Array.prototype.push.apply( this.categories, categories );
92 };
93
94 /**
95 * Empty the list of categories for the upload.
96 */
97 ForeignStructuredUpload.prototype.clearCategories = function () {
98 this.categories = [];
99 };
100
101 /**
102 * Add a description to the upload.
103 *
104 * @param {string} language The language code for the description's language. Must have a template on the target wiki to work properly.
105 * @param {string} description The description of the file.
106 */
107 ForeignStructuredUpload.prototype.addDescription = function ( language, description ) {
108 this.descriptions.push( {
109 language: language,
110 text: description
111 } );
112 };
113
114 /**
115 * Empty the list of descriptions for the upload.
116 */
117 ForeignStructuredUpload.prototype.clearDescriptions = function () {
118 this.descriptions = [];
119 };
120
121 /**
122 * Set the date of creation for the upload.
123 *
124 * @param {Date} date
125 */
126 ForeignStructuredUpload.prototype.setDate = function ( date ) {
127 this.date = date;
128 };
129
130 /**
131 * Get the text of the file page, to be created on upload. Brings together
132 * several different pieces of information to create useful text.
133 *
134 * @return {string}
135 */
136 ForeignStructuredUpload.prototype.getText = function () {
137 return this.config.format.filepage
138 // Replace "named parameters" with the given information
139 .replace( '$DESCRIPTION', this.getDescriptions() )
140 .replace( '$DATE', this.getDate() )
141 .replace( '$SOURCE', this.getSource() )
142 .replace( '$AUTHOR', this.getUser() )
143 .replace( '$LICENSE', this.getLicense() )
144 .replace( '$CATEGORIES', this.getCategories() );
145 };
146
147 /**
148 * @inheritdoc
149 */
150 ForeignStructuredUpload.prototype.getComment = function () {
151 var
152 isLocal = this.target === 'local',
153 comment = typeof this.config.comment === 'string' ?
154 this.config.comment :
155 this.config.comment[ isLocal ? 'local' : 'foreign' ];
156 return comment
157 .replace( '$PAGENAME', mw.config.get( 'wgPageName' ) )
158 .replace( '$HOST', location.host );
159 };
160
161 /**
162 * Gets the wikitext for the creation date of this upload.
163 *
164 * @private
165 * @return {string}
166 */
167 ForeignStructuredUpload.prototype.getDate = function () {
168 if ( !this.date ) {
169 return '';
170 }
171
172 return this.date.toString();
173 };
174
175 /**
176 * Fetches the wikitext for any descriptions that have been added
177 * to the upload.
178 *
179 * @private
180 * @return {string}
181 */
182 ForeignStructuredUpload.prototype.getDescriptions = function () {
183 return this.descriptions.map( function ( desc ) {
184 return this.config.format.description
185 .replace( '$LANGUAGE', desc.language )
186 .replace( '$TEXT', desc.text );
187 } ).join( '\n' );
188 };
189
190 /**
191 * Fetches the wikitext for the categories to which the upload will
192 * be added.
193 *
194 * @private
195 * @return {string}
196 */
197 ForeignStructuredUpload.prototype.getCategories = function () {
198 if ( this.categories.length === 0 ) {
199 return this.config.format.uncategorized;
200 }
201
202 return this.categories.map( function ( cat ) {
203 return '[[Category:' + cat + ']]';
204 } ).join( '\n' );
205 };
206
207 /**
208 * Gets the wikitext for the license of the upload.
209 *
210 * @private
211 * @return {string}
212 */
213 ForeignStructuredUpload.prototype.getLicense = function () {
214 return this.config.format.license;
215 };
216
217 /**
218 * Get the source. This should be some sort of localised text for "Own work".
219 *
220 * @private
221 * @return {string}
222 */
223 ForeignStructuredUpload.prototype.getSource = function () {
224 return this.config.format.ownwork;
225 };
226
227 /**
228 * Get the username.
229 *
230 * @private
231 * @return {string}
232 */
233 ForeignStructuredUpload.prototype.getUser = function () {
234 var username, namespace;
235 // Do not localise, we don't know the language of target wiki
236 namespace = 'User';
237 username = mw.config.get( 'wgUserName' );
238 if ( !username ) {
239 // The user is not logged in locally. However, they might be logged in on the foreign wiki.
240 // We should record their username there. (If they're not logged in there either, this will
241 // record the IP address.) It's also possible that the user opened this dialog, got an error
242 // about not being logged in, logged in in another browser tab, then continued uploading.
243 username = '{{subst:REVISIONUSER}}';
244 }
245 return '[[' + namespace + ':' + username + '|' + username + ']]';
246 };
247
248 mw.ForeignStructuredUpload = ForeignStructuredUpload;
249 }( mediaWiki, jQuery, OO ) );