Add pluggable talk page poster and use it for mediawiki.feedback
[lhc/web/wiklou.git] / resources / src / mediawiki.messagePoster / mediawiki.messagePoster.factory.js
1 /*global OO*/
2 ( function ( mw, $ ) {
3 /**
4 * This is a factory for MessagePoster objects, which allows a pluggable to way to script leaving a
5 * talk page message.
6 *
7 * @class mw.messagePoster.factory
8 * @singleton
9 */
10 function MwMessagePosterFactory() {
11 this.api = new mw.Api();
12 this.contentModelToClass = {};
13 }
14
15 OO.initClass( MwMessagePosterFactory );
16
17 // Note: This registration scheme is currently not compatible with LQT, since that doesn't
18 // have its own content model, just islqttalkpage. LQT pages will be passed to the wikitext
19 // MessagePoster.
20 /**
21 * Registers a MessagePoster subclass for a given content model.
22 *
23 * @param {string} contentModel Content model of pages this MessagePoster can post to
24 * @param {Function} messagePosterConstructor Constructor for MessagePoster
25 */
26 MwMessagePosterFactory.prototype.register = function ( contentModel, messagePosterConstructor ) {
27 if ( this.contentModelToClass[contentModel] !== undefined ) {
28 throw new Error( 'The content model \'' + contentModel + '\' is already registered.' );
29 }
30
31 this.contentModelToClass[contentModel] = messagePosterConstructor;
32 };
33
34 /**
35 * Unregisters a given content model
36 * This is exposed for testing and should not normally be needed.
37 *
38 * @param {string} contentModel Content model to unregister
39 */
40 MwMessagePosterFactory.prototype.unregister = function ( contentModel ) {
41 delete this.contentModelToClass[contentModel];
42 };
43
44 /**
45 * Creates a MessagePoster, given a title. A promise for this is returned.
46 * This works by determining the content model, then loading the corresponding
47 * module (which will register the MessagePoster class), and finally constructing it.
48 *
49 * This does not require the message and should be called as soon as possible, so it does the
50 * API and ResourceLoader requests in the background.
51 *
52 * @param {mw.Title} title Title that will be posted to
53 * @return {jQuery.Promise} Promise for the MessagePoster
54 * @return {Function} return.done Called if MessagePoster is retrieved
55 * @return {mw.messagePoster.MessagePoster} return.done.poster MessagePoster
56 * @return {Function} return.fail Called if MessagePoster could not be constructed
57 * @return {string} return.fail.errorCode String error code
58 */
59 MwMessagePosterFactory.prototype.create = function ( title ) {
60 var pageId, page, contentModel, moduleName,
61 factory = this;
62
63 return this.api.get( {
64 action: 'query',
65 prop: 'info',
66 indexpageids: 1,
67 titles: title.getPrefixedDb()
68 } ).then( function ( result ) {
69 if ( result.query.pageids.length > 0 ) {
70 pageId = result.query.pageids[0];
71 page = result.query.pages[pageId];
72
73 contentModel = page.contentmodel;
74 moduleName = 'mediawiki.messagePoster.' + contentModel;
75 return mw.loader.using( moduleName ).then( function () {
76 return factory.createForContentModel(
77 contentModel,
78 title
79 );
80 }, function () {
81 return $.Deferred().reject( 'failed-to-load-module', 'Failed to load the \'' + moduleName + '\' module' );
82 } );
83 } else {
84 return $.Deferred().reject( 'unexpected-response', 'Unexpected API response' );
85 }
86 }, function ( errorCode, details ) {
87 return $.Deferred().reject( 'content-model-query-failed', errorCode, details );
88 } ).promise();
89 };
90
91 /**
92 * Creates a MessagePoster instance, given a title and content model
93 *
94 * @private
95 *
96 * @param {string} contentModel Content model of title
97 * @param {mw.Title} title Title being posted to
98 * @return {mw.messagePoster.MessagePoster}
99 *
100 */
101 MwMessagePosterFactory.prototype.createForContentModel = function ( contentModel, title ) {
102 return new this.contentModelToClass[contentModel]( title );
103 };
104
105 mw.messagePoster = {
106 factory: new MwMessagePosterFactory()
107 };
108 }( mediaWiki, jQuery ) );