Merge "Update docs/hooks.txt for ShowSearchHitTitle"
[mediawiki.git] / resources / src / mediawiki / mediawiki.ForeignStructuredUpload.js
blob0c572d49913a5dbab9cc523f5ee0e97f6a189124
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 = [];
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' );
30                 mw.ForeignUpload.call( this, target, apiconfig );
31         }
33         OO.inheritClass( ForeignStructuredUpload, mw.ForeignUpload );
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;
45                 if ( this.configPromise ) {
46                         return this.configPromise;
47                 }
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                 }
80                 return this.configPromise;
81         };
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                 var i, category;
91                 for ( i = 0; i < categories.length; i++ ) {
92                         category = categories[ i ];
93                         this.categories.push( category );
94                 }
95         };
97         /**
98          * Empty the list of categories for the upload.
99          */
100         ForeignStructuredUpload.prototype.clearCategories = function () {
101                 this.categories = [];
102         };
104         /**
105          * Add a description to the upload.
106          *
107          * @param {string} language The language code for the description's language. Must have a template on the target wiki to work properly.
108          * @param {string} description The description of the file.
109          */
110         ForeignStructuredUpload.prototype.addDescription = function ( language, description ) {
111                 this.descriptions.push( {
112                         language: language,
113                         text: description
114                 } );
115         };
117         /**
118          * Empty the list of descriptions for the upload.
119          */
120         ForeignStructuredUpload.prototype.clearDescriptions = function () {
121                 this.descriptions = [];
122         };
124         /**
125          * Set the date of creation for the upload.
126          *
127          * @param {Date} date
128          */
129         ForeignStructuredUpload.prototype.setDate = function ( date ) {
130                 this.date = date;
131         };
133         /**
134          * Get the text of the file page, to be created on upload. Brings together
135          * several different pieces of information to create useful text.
136          *
137          * @return {string}
138          */
139         ForeignStructuredUpload.prototype.getText = function () {
140                 return this.config.format.filepage
141                         // Replace "named parameters" with the given information
142                         .replace( '$DESCRIPTION', this.getDescriptions() )
143                         .replace( '$DATE', this.getDate() )
144                         .replace( '$SOURCE', this.getSource() )
145                         .replace( '$AUTHOR', this.getUser() )
146                         .replace( '$LICENSE', this.getLicense() )
147                         .replace( '$CATEGORIES', this.getCategories() );
148         };
150         /**
151          * @inheritdoc
152          */
153         ForeignStructuredUpload.prototype.getComment = function () {
154                 var
155                         isLocal = this.target === 'local',
156                         comment = typeof this.config.comment === 'string' ?
157                                 this.config.comment :
158                                 this.config.comment[ isLocal ? 'local' : 'foreign' ];
159                 return comment
160                         .replace( '$PAGENAME', mw.config.get( 'wgPageName' ) )
161                         .replace( '$HOST', location.host );
162         };
164         /**
165          * Gets the wikitext for the creation date of this upload.
166          *
167          * @private
168          * @return {string}
169          */
170         ForeignStructuredUpload.prototype.getDate = function () {
171                 if ( !this.date ) {
172                         return '';
173                 }
175                 return this.date.toString();
176         };
178         /**
179          * Fetches the wikitext for any descriptions that have been added
180          * to the upload.
181          *
182          * @private
183          * @return {string}
184          */
185         ForeignStructuredUpload.prototype.getDescriptions = function () {
186                 var i, desc, templateCalls = [];
188                 for ( i = 0; i < this.descriptions.length; i++ ) {
189                         desc = this.descriptions[ i ];
190                         templateCalls.push(
191                                 this.config.format.description
192                                         .replace( '$LANGUAGE', desc.language )
193                                         .replace( '$TEXT', desc.text )
194                         );
195                 }
197                 return templateCalls.join( '\n' );
198         };
200         /**
201          * Fetches the wikitext for the categories to which the upload will
202          * be added.
203          *
204          * @private
205          * @return {string}
206          */
207         ForeignStructuredUpload.prototype.getCategories = function () {
208                 var i, cat, categoryLinks = [];
210                 if ( this.categories.length === 0 ) {
211                         return this.config.format.uncategorized;
212                 }
214                 for ( i = 0; i < this.categories.length; i++ ) {
215                         cat = this.categories[ i ];
216                         categoryLinks.push( '[[Category:' + cat + ']]' );
217                 }
219                 return categoryLinks.join( '\n' );
220         };
222         /**
223          * Gets the wikitext for the license of the upload.
224          *
225          * @private
226          * @return {string}
227          */
228         ForeignStructuredUpload.prototype.getLicense = function () {
229                 return this.config.format.license;
230         };
232         /**
233          * Get the source. This should be some sort of localised text for "Own work".
234          *
235          * @private
236          * @return {string}
237          */
238         ForeignStructuredUpload.prototype.getSource = function () {
239                 return this.config.format.ownwork;
240         };
242         /**
243          * Get the username.
244          *
245          * @private
246          * @return {string}
247          */
248         ForeignStructuredUpload.prototype.getUser = function () {
249                 var username, namespace;
250                 // Do not localise, we don't know the language of target wiki
251                 namespace = 'User';
252                 username = mw.config.get( 'wgUserName' );
253                 if ( !username ) {
254                         // The user is not logged in locally. However, they might be logged in on the foreign wiki.
255                         // We should record their username there. (If they're not logged in there either, this will
256                         // record the IP address.) It's also possible that the user opened this dialog, got an error
257                         // about not being logged in, logged in in another browser tab, then continued uploading.
258                         username = '{{subst:REVISIONUSER}}';
259                 }
260                 return '[[' + namespace + ':' + username + '|' + username + ']]';
261         };
263         mw.ForeignStructuredUpload = ForeignStructuredUpload;
264 }( mediaWiki, jQuery, OO ) );