]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - resources/src/mediawiki/page/watch.js
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / resources / src / mediawiki / page / watch.js
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         var watch,
9                 // The name of the page to watch or unwatch
10                 title = mw.config.get( 'wgRelevantPageName' );
11
12         /**
13          * Update the link text, link href attribute and (if applicable)
14          * "loading" class.
15          *
16          * @param {jQuery} $link Anchor tag of (un)watch link
17          * @param {string} action One of 'watch', 'unwatch'
18          * @param {string} [state="idle"] 'idle' or 'loading'. Default is 'idle'
19          */
20         function updateWatchLink( $link, action, state ) {
21                 var msgKey, $li, otherAction;
22
23                 // A valid but empty jQuery object shouldn't throw a TypeError
24                 if ( !$link.length ) {
25                         return;
26                 }
27
28                 // Invalid actions shouldn't silently turn the page in an unrecoverable state
29                 if ( action !== 'watch' && action !== 'unwatch' ) {
30                         throw new Error( 'Invalid action' );
31                 }
32
33                 // message keys 'watch', 'watching', 'unwatch' or 'unwatching'.
34                 msgKey = state === 'loading' ? action + 'ing' : action;
35                 otherAction = action === 'watch' ? 'unwatch' : 'watch';
36                 $li = $link.closest( 'li' );
37
38                 // Trigger a 'watchpage' event for this List item.
39                 // Announce the otherAction value as the first param.
40                 // Used to monitor the state of watch link.
41                 // TODO: Revise when system wide hooks are implemented
42                 if ( state === undefined ) {
43                         $li.trigger( 'watchpage.mw', otherAction );
44                 }
45
46                 $link
47                         .text( mw.msg( msgKey ) )
48                         .attr( 'title', mw.msg( 'tooltip-ca-' + action ) )
49                         .updateTooltipAccessKeys()
50                         .attr( 'href', mw.util.getUrl( title, { action: action } ) );
51
52                 // Most common ID style
53                 if ( $li.prop( 'id' ) === 'ca-' + otherAction ) {
54                         $li.prop( 'id', 'ca-' + action );
55                 }
56
57                 if ( state === 'loading' ) {
58                         $link.addClass( 'loading' );
59                 } else {
60                         $link.removeClass( 'loading' );
61                 }
62         }
63
64         /**
65          * TODO: This should be moved somewhere more accessible.
66          *
67          * @private
68          * @param {string} url
69          * @return {string} The extracted action, defaults to 'view'
70          */
71         function mwUriGetAction( url ) {
72                 var action, actionPaths, key, i, m, parts;
73
74                 // TODO: Does MediaWiki give action path or query param
75                 // precedence? If the former, move this to the bottom
76                 action = mw.util.getParamValue( 'action', url );
77                 if ( action !== null ) {
78                         return action;
79                 }
80
81                 actionPaths = mw.config.get( 'wgActionPaths' );
82                 for ( key in actionPaths ) {
83                         if ( actionPaths.hasOwnProperty( key ) ) {
84                                 parts = actionPaths[ key ].split( '$1' );
85                                 for ( i = 0; i < parts.length; i++ ) {
86                                         parts[ i ] = mw.RegExp.escape( parts[ i ] );
87                                 }
88                                 m = new RegExp( parts.join( '(.+)' ) ).exec( url );
89                                 if ( m && m[ 1 ] ) {
90                                         return key;
91                                 }
92
93                         }
94                 }
95
96                 return 'view';
97         }
98
99         // Expose public methods
100         watch = {
101                 updateWatchLink: updateWatchLink
102         };
103         module.exports = watch;
104
105         // Deprecated since 1.30
106         mw.log.deprecate( mw, 'page',
107                 { watch: watch },
108                 'Use require( \'mediawiki.page.watch.ajax\' ) instead.',
109                 'mw.page'
110         );
111
112         $( function () {
113                 var $links = $( '.mw-watchlink a[data-mw="interface"], a.mw-watchlink[data-mw="interface"]' );
114                 if ( !$links.length ) {
115                         // Fallback to the class-based exclusion method for backwards-compatibility
116                         $links = $( '.mw-watchlink a, a.mw-watchlink' );
117                         // Restrict to core interfaces, ignore user-generated content
118                         $links = $links.filter( ':not( #bodyContent *, #content * )' );
119                 }
120
121                 $links.click( function ( e ) {
122                         var mwTitle, action, api, $link;
123
124                         mwTitle = mw.Title.newFromText( title );
125                         action = mwUriGetAction( this.href );
126
127                         if ( !mwTitle || ( action !== 'watch' && action !== 'unwatch' ) ) {
128                                 // Let native browsing handle the link
129                                 return true;
130                         }
131                         e.preventDefault();
132                         e.stopPropagation();
133
134                         $link = $( this );
135
136                         if ( $link.hasClass( 'loading' ) ) {
137                                 return;
138                         }
139
140                         updateWatchLink( $link, action, 'loading' );
141
142                         // Preload the notification module for mw.notify
143                         mw.loader.load( 'mediawiki.notification' );
144
145                         api = new mw.Api();
146
147                         api[ action ]( title )
148                                 .done( function ( watchResponse ) {
149                                         var message, otherAction = action === 'watch' ? 'unwatch' : 'watch';
150
151                                         if ( mwTitle.getNamespaceId() > 0 && mwTitle.getNamespaceId() % 2 === 1 ) {
152                                                 message = action === 'watch' ? 'addedwatchtext-talk' : 'removedwatchtext-talk';
153                                         } else {
154                                                 message = action === 'watch' ? 'addedwatchtext' : 'removedwatchtext';
155                                         }
156
157                                         mw.notify( mw.message( message, mwTitle.getPrefixedText() ).parseDom(), {
158                                                 tag: 'watch-self'
159                                         } );
160
161                                         // Set link to opposite
162                                         updateWatchLink( $link, otherAction );
163
164                                         // Update the "Watch this page" checkbox on action=edit when the
165                                         // page is watched or unwatched via the tab (T14395).
166                                         $( '#wpWatchthis' ).prop( 'checked', watchResponse.watched === true );
167                                 } )
168                                 .fail( function () {
169                                         var msg, link;
170
171                                         // Reset link to non-loading mode
172                                         updateWatchLink( $link, action );
173
174                                         // Format error message
175                                         link = mw.html.element(
176                                                 'a', {
177                                                         href: mw.util.getUrl( title ),
178                                                         title: mwTitle.getPrefixedText()
179                                                 }, mwTitle.getPrefixedText()
180                                         );
181                                         msg = mw.message( 'watcherrortext', link );
182
183                                         // Report to user about the error
184                                         mw.notify( msg, {
185                                                 tag: 'watch-self',
186                                                 type: 'error'
187                                         } );
188                                 } );
189                 } );
190         } );
191
192 }( mediaWiki, jQuery ) );