Implement extension registration from an extension.json file
[mediawiki.git] / resources / src / mediawiki.page / mediawiki.page.watch.ajax.js
blobd252f0e48088de4665535565345506fba47fc746
1 /**
2  * Animate watch/unwatch links to use asynchronous API requests to
3  * watch pages, rather than navigating to a different URI.
4  *
5  * @class mw.page.watch.ajax
6  */
7 ( function ( mw, $ ) {
8         // The name of the page to watch or unwatch
9         var title = mw.config.get( 'wgRelevantPageName' );
11         /**
12          * Update the link text, link href attribute and (if applicable)
13          * "loading" class.
14          *
15          * @param {jQuery} $link Anchor tag of (un)watch link
16          * @param {string} action One of 'watch', 'unwatch'
17          * @param {string} [state="idle"] 'idle' or 'loading'. Default is 'idle'
18          */
19         function updateWatchLink( $link, action, state ) {
20                 var msgKey, $li, otherAction;
22                 // A valid but empty jQuery object shouldn't throw a TypeError
23                 if ( !$link.length ) {
24                         return;
25                 }
27                 // Invalid actions shouldn't silently turn the page in an unrecoverable state
28                 if ( action !== 'watch' && action !== 'unwatch' ) {
29                         throw new Error( 'Invalid action' );
30                 }
32                 // message keys 'watch', 'watching', 'unwatch' or 'unwatching'.
33                 msgKey = state === 'loading' ? action + 'ing' : action;
34                 otherAction = action === 'watch' ? 'unwatch' : 'watch';
35                 $li = $link.closest( 'li' );
37                 // Trigger a 'watchpage' event for this List item.
38                 // Announce the otherAction value as the first param.
39                 // Used to monitor the state of watch link.
40                 // TODO: Revise when system wide hooks are implemented
41                 if ( state === undefined ) {
42                         $li.trigger( 'watchpage.mw', otherAction );
43                 }
45                 $link
46                         .text( mw.msg( msgKey ) )
47                         .attr( 'title', mw.msg( 'tooltip-ca-' + action ) )
48                         .updateTooltipAccessKeys()
49                         .attr( 'href', mw.util.wikiScript() + '?' + $.param( {
50                                         title: title,
51                                         action: action
52                                 } )
53                         );
55                 // Most common ID style
56                 if ( $li.prop( 'id' ) === 'ca-' + otherAction ) {
57                         $li.prop( 'id', 'ca-' + action );
58                 }
60                 if ( state === 'loading' ) {
61                         $link.addClass( 'loading' );
62                 } else {
63                         $link.removeClass( 'loading' );
64                 }
65         }
67         /**
68          * TODO: This should be moved somewhere more accessible.
69          *
70          * @private
71          * @param {string} url
72          * @return {string} The extracted action, defaults to 'view'
73          */
74         function mwUriGetAction( url ) {
75                 var action, actionPaths, key, i, m, parts;
77                 // TODO: Does MediaWiki give action path or query param
78                 // precedence? If the former, move this to the bottom
79                 action = mw.util.getParamValue( 'action', url );
80                 if ( action !== null ) {
81                         return action;
82                 }
84                 actionPaths = mw.config.get( 'wgActionPaths' );
85                 for ( key in actionPaths ) {
86                         if ( actionPaths.hasOwnProperty( key ) ) {
87                                 parts = actionPaths[key].split( '$1' );
88                                 for ( i = 0; i < parts.length; i++ ) {
89                                         parts[i] = $.escapeRE( parts[i] );
90                                 }
91                                 m = new RegExp( parts.join( '(.+)' ) ).exec( url );
92                                 if ( m && m[1] ) {
93                                         return key;
94                                 }
96                         }
97                 }
99                 return 'view';
100         }
102         // Expose public methods
103         mw.page.watch = {
104                 updateWatchLink: updateWatchLink
105         };
107         $( function () {
108                 var $links = $( '.mw-watchlink a, a.mw-watchlink, ' +
109                         '#ca-watch a, #ca-unwatch a, #mw-unwatch-link1, ' +
110                         '#mw-unwatch-link2, #mw-watch-link2, #mw-watch-link1' );
112                 // Allowing people to add inline animated links is a little scary
113                 $links = $links.filter( ':not( #bodyContent *, #content * )' );
115                 $links.click( function ( e ) {
116                         var action, api, $link;
118                         // Start preloading the notification module (normally loaded by mw.notify())
119                         mw.loader.load( ['mediawiki.notification'], null, true );
121                         action = mwUriGetAction( this.href );
123                         if ( action !== 'watch' && action !== 'unwatch' ) {
124                                 // Could not extract target action from link url,
125                                 // let native browsing handle it further
126                                 return true;
127                         }
128                         e.preventDefault();
129                         e.stopPropagation();
131                         $link = $( this );
133                         if ( $link.hasClass( 'loading' ) ) {
134                                 return;
135                         }
137                         updateWatchLink( $link, action, 'loading' );
139                         api = new mw.Api();
141                         api[action]( title )
142                                 .done( function ( watchResponse ) {
143                                         var otherAction = action === 'watch' ? 'unwatch' : 'watch';
145                                         mw.notify( $.parseHTML( watchResponse.message ), {
146                                                 tag: 'watch-self'
147                                         } );
149                                         // Set link to opposite
150                                         updateWatchLink( $link, otherAction );
152                                         // Update the "Watch this page" checkbox on action=edit when the
153                                         // page is watched or unwatched via the tab (bug 12395).
154                                         $( '#wpWatchthis' ).prop( 'checked', watchResponse.watched !== undefined );
155                                 } )
156                                 .fail( function () {
157                                         var cleanTitle, msg, link;
159                                         // Reset link to non-loading mode
160                                         updateWatchLink( $link, action );
162                                         // Format error message
163                                         cleanTitle = title.replace( /_/g, ' ' );
164                                         link = mw.html.element(
165                                                 'a', {
166                                                         href: mw.util.getUrl( title ),
167                                                         title: cleanTitle
168                                                 }, cleanTitle
169                                         );
170                                         msg = mw.message( 'watcherrortext', link );
172                                         // Report to user about the error
173                                         mw.notify( msg, { tag: 'watch-self' } );
174                                 } );
175                 } );
176         } );
178 }( mediaWiki, jQuery ) );