3 * @classdesc Factory for MessagePoster objects. This provides a pluggable to way to script the
4 * action of adding a message to someone's talk page.
6 * The constructor is not publicly accessible; use [mw.messagePoster.factory]{@link mw.messagePoster} instead.
8 * @class MessagePosterFactory
12 function MessagePosterFactory() {
13 this.contentModelToClass = Object.create( null );
16 OO.initClass( MessagePosterFactory );
18 // Note: This registration scheme is currently not compatible with LQT, since that doesn't
19 // have its own content model, just islqttalkpage. LQT pages will be passed to the wikitext
22 * Register a MessagePoster subclass for a given content model.
27 * function MyExamplePoster() {}
28 * OO.inheritClass( MyExamplePoster, mw.messagePoster.MessagePoster );
30 * mw.messagePoster.factory.register( 'mycontentmodel', MyExamplePoster );
33 * The JavaScript files(s) that register message posters for additional content
34 * models must be registered with MediaWiki via the `MessagePosterModule`
35 * extension attribute, like follows:
38 * "MessagePosterModule": {
39 * "localBasePath": "", // (required)
40 * "scripts": [], // relative file path(s) (required)
41 * "dependencies": [], // module name(s) (optional)
45 * @memberof MessagePosterFactory
46 * @param {string} contentModel Content model of pages this MessagePoster can post to
47 * @param {Function} constructor Constructor of a MessagePoster subclass
49 MessagePosterFactory.prototype.register = function ( contentModel, constructor ) {
50 if ( this.contentModelToClass[ contentModel ] ) {
51 throw new Error( 'Content model "' + contentModel + '" is already registered' );
54 this.contentModelToClass[ contentModel ] = constructor;
58 * Unregister a given content model.
59 * This is exposed for testing and should not normally be used.
61 * @memberof MessagePosterFactory
62 * @param {string} contentModel Content model to unregister
64 MessagePosterFactory.prototype.unregister = function ( contentModel ) {
65 delete this.contentModelToClass[ contentModel ];
69 * Create a MessagePoster for given a title.
71 * A promise for this is returned. It works by determining the content model, then loading
72 * the corresponding module (which registers the MessagePoster class), and finally constructing
73 * an object for the given title.
75 * This does not require the message and should be called as soon as possible, so that the
76 * API and ResourceLoader requests run in the background.
78 * @memberof MessagePosterFactory
79 * @param {mw.Title} title Title that will be posted to
80 * @param {string} [apiUrl] api.php URL if the title is on another wiki
81 * @return {jQuery.Promise} Promise resolving to a mw.messagePoster.MessagePoster.
82 * For failure, rejected with up to three arguments:
84 * - errorCode Error code string
85 * - error Error explanation
86 * - details Further error details
88 MessagePosterFactory.prototype.create = function ( title, apiUrl ) {
89 const api = apiUrl ? new mw.ForeignApi( apiUrl ) : new mw.Api();
95 titles: title.getPrefixedDb()
96 } ).then( ( data ) => {
97 const page = data.query.pages[ 0 ];
99 return $.Deferred().reject( 'unexpected-response', 'Unexpected API response' );
101 const contentModel = page.contentmodel;
102 if ( !this.contentModelToClass[ contentModel ] ) {
103 return $.Deferred().reject( 'content-model-unknown', 'No handler for "' + contentModel + '"' );
105 return new this.contentModelToClass[ contentModel ]( title, api );
106 }, ( error, details ) => $.Deferred().reject( 'content-model-query-failed', error, details ) );
110 * Library for posting messages to talk pages.
112 * @namespace mw.messagePoster
115 /** @type {MessagePosterFactory} */
116 factory: new MessagePosterFactory()