ApiSandbox: Visual separation of fields
[mediawiki.git] / resources / src / mediawiki.messagePoster / mediawiki.messagePoster.factory.js
blob68fb2aae0e92c98b4db071e51378c1942118a547
1 /*global OO */
2 ( function ( mw, $ ) {
3         /**
4          * Factory for MessagePoster objects. This provides a pluggable to way to script the action
5          * of adding a message to someone's talk page.
6          *
7          * @class mw.messagePoster.factory
8          * @singleton
9          */
10         function MessagePosterFactory() {
11                 this.contentModelToClass = {};
12         }
14         OO.initClass( MessagePosterFactory );
16         // Note: This registration scheme is currently not compatible with LQT, since that doesn't
17         // have its own content model, just islqttalkpage. LQT pages will be passed to the wikitext
18         // MessagePoster.
19         /**
20          * Register a MessagePoster subclass for a given content model.
21          *
22          * @param {string} contentModel Content model of pages this MessagePoster can post to
23          * @param {Function} constructor Constructor of a MessagePoster subclass
24          */
25         MessagePosterFactory.prototype.register = function ( contentModel, constructor ) {
26                 if ( this.contentModelToClass[ contentModel ] !== undefined ) {
27                         throw new Error( 'Content model "' + contentModel + '" is already registered' );
28                 }
30                 this.contentModelToClass[ contentModel ] = constructor;
31         };
33         /**
34          * Unregister a given content model.
35          * This is exposed for testing and should not normally be used.
36          *
37          * @param {string} contentModel Content model to unregister
38          */
39         MessagePosterFactory.prototype.unregister = function ( contentModel ) {
40                 delete this.contentModelToClass[ contentModel ];
41         };
43         /**
44          * Create a MessagePoster for given a title.
45          *
46          * A promise for this is returned. It works by determining the content model, then loading
47          * the corresponding module (which registers the MessagePoster class), and finally constructing
48          * an object for the given title.
49          *
50          * This does not require the message and should be called as soon as possible, so that the
51          * API and ResourceLoader requests run in the background.
52          *
53          * @param {mw.Title} title Title that will be posted to
54          * @param {string} [apiUrl] api.php URL if the title is on another wiki
55          * @return {jQuery.Promise} Promise resolving to a mw.messagePoster.MessagePoster.
56          *   For failure, rejected with up to three arguments:
57          *
58          *   - errorCode Error code string
59          *   - error Error explanation
60          *   - details Further error details
61          */
62         MessagePosterFactory.prototype.create = function ( title, apiUrl ) {
63                 var factory = this,
64                         api = apiUrl ? new mw.ForeignApi( apiUrl ) : new mw.Api();
66                 return api.get( {
67                         action: 'query',
68                         prop: 'info',
69                         indexpageids: true,
70                         titles: title.getPrefixedDb()
71                 } ).then( function ( data ) {
72                         var pageId, page, contentModel, moduleName;
73                         if ( !data.query.pageids[ 0 ] ) {
74                                 return $.Deferred().reject( 'unexpected-response', 'Unexpected API response' );
75                         }
76                         pageId = data.query.pageids[ 0 ];
77                         page = data.query.pages[ pageId ];
79                         contentModel = page.contentmodel;
80                         moduleName = 'mediawiki.messagePoster.' + contentModel;
81                         return mw.loader.using( moduleName ).then( function () {
82                                 return factory.createForContentModel(
83                                         contentModel,
84                                         title,
85                                         api
86                                 );
87                         }, function () {
88                                 return $.Deferred().reject( 'failed-to-load-module', 'Failed to load "' + moduleName + '"' );
89                         } );
90                 }, function ( error, details ) {
91                         return $.Deferred().reject( 'content-model-query-failed', error, details );
92                 } );
93         };
95         /**
96          * Creates a MessagePoster instance, given a title and content model
97          *
98          * @private
99          * @param {string} contentModel Content model of title
100          * @param {mw.Title} title Title being posted to
101          * @param {mw.Api} api mw.Api instance that the instance should use
102          * @return {mw.messagePoster.MessagePoster}
103          *
104          */
105         MessagePosterFactory.prototype.createForContentModel = function ( contentModel, title, api ) {
106                 return new this.contentModelToClass[ contentModel ]( title, api );
107         };
109         mw.messagePoster = {
110                 factory: new MessagePosterFactory()
111         };
112 }( mediaWiki, jQuery ) );