Move action.watch to a more suitable place and expose updateWatchLink
[lhc/web/wiklou.git] / resources / mediawiki.page / mediawiki.page.watch.ajax.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 ( function ( $, mw, undefined ) {
6 /**
7 * The name of the page to watch or unwatch.
8 */
9 var title = mw.config.get( 'wgRelevantPageName', mw.config.get( 'wgPageName' ) );
10
11 // Expose local methods
12 mw.page.watch = {
13 'updateWatchLink': updateWatchLink
14 };
15 /**
16 * Update the link text, link href attribute and (if applicable)
17 * "loading" class.
18 *
19 * @param $link {jQuery} Anchor tag of (un)watch link.
20 * @param action {String} One of 'watch', 'unwatch'.
21 * @param state {String} [optional] 'idle' or 'loading'. Default is 'idle'.
22 */
23 function updateWatchLink( $link, action, state ) {
24 var accesskeyTip, msgKey, $li, otherAction;
25
26 // message keys 'watch', 'watching', 'unwatch' or 'unwatching'.
27 msgKey = state === 'loading' ? action + 'ing' : action;
28 otherAction = action === 'watch' ? 'unwatch' : 'watch';
29 accesskeyTip = $link.attr( 'title' ).match( mw.util.tooltipAccessKeyRegexp );
30 $li = $link.closest( 'li' );
31 /**
32 * Trigger a 'watch' event for this List item.
33 * Announce the otherAction value as the first param.
34 * Used to monitor the state of watch link.
35 * TODO: Revise when system wide hooks are implemented
36 */
37 if( state === undefined ) {
38 $li.trigger( 'watch.mw', otherAction );
39 }
40
41 $link
42 .text( mw.msg( msgKey ) )
43 .attr( 'title', mw.msg( 'tooltip-ca-' + action ) +
44 ( accesskeyTip ? ' ' + accesskeyTip[0] : '' )
45 )
46 .attr( 'href', mw.util.wikiScript() + '?' + $.param({
47 title: title,
48 action: action
49 })
50 );
51
52 // Most common ID style
53 if ( $li.prop( 'id' ) === 'ca-' + otherAction ) {
54 $li.prop( 'id', 'ca-' + action );
55 }
56
57 // Special case for vector icon
58 if ( $li.hasClass( 'icon' ) ) {
59 if ( state === 'loading' ) {
60 $link.addClass( 'loading' );
61 } else {
62 $link.removeClass( 'loading' );
63 }
64 }
65 }
66
67 /**
68 * @todo This should be moved somewhere more accessible.
69 * @param url {String}
70 * @return {String} The extracted action, defaults to 'view'.
71 */
72 function mwUriGetAction( url ) {
73 var action, actionPaths, key, i, m, parts;
74
75 actionPaths = mw.config.get( 'wgActionPaths' );
76
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 }
83
84 for ( key in actionPaths ) {
85 if ( actionPaths.hasOwnProperty( key ) ) {
86 parts = actionPaths[key].split( '$1' );
87 for ( i = 0; i < parts.length; i += 1 ) {
88 parts[i] = $.escapeRE( parts[i] );
89 }
90 m = new RegExp( parts.join( '(.+)' ) ).exec( url );
91 if ( m && m[1] ) {
92 return key;
93 }
94
95 }
96 }
97
98 return 'view';
99 }
100
101 $( document ).ready( function () {
102 var $links = $( '.mw-watchlink a, a.mw-watchlink, ' +
103 '#ca-watch a, #ca-unwatch a, #mw-unwatch-link1, ' +
104 '#mw-unwatch-link2, #mw-watch-link2, #mw-watch-link1' );
105
106 // Allowing people to add inline animated links is a little scary
107 $links = $links.filter( ':not( #bodyContent *, #content * )' );
108
109 $links.click( function ( e ) {
110 var action, api, $link;
111
112 action = mwUriGetAction( this.href );
113
114 if ( action !== 'watch' && action !== 'unwatch' ) {
115 // Could not extract target action from link url,
116 // let native browsing handle it further
117 return true;
118 }
119 e.preventDefault();
120 e.stopPropagation();
121
122 $link = $( this );
123
124 updateWatchLink( $link, action, 'loading' );
125
126 api = new mw.Api();
127 api[action](
128 title,
129 // Success
130 function ( watchResponse ) {
131 var $li, otherAction;
132
133 otherAction = action === 'watch' ? 'unwatch' : 'watch';
134 $li = $link.closest( 'li' );
135
136 mw.util.jsMessage( watchResponse.message, 'ajaxwatch' );
137
138 // Set link to opposite
139 updateWatchLink( $link, otherAction );
140
141 // Bug 12395 - update the watch checkbox on edit pages when the
142 // page is watched or unwatched via the tab.
143 if ( watchResponse.watched !== undefined ) {
144 $( '#wpWatchthis' ).prop( 'checked', true );
145 } else {
146 $( '#wpWatchthis' ).removeProp( 'checked' );
147 }
148 },
149 // Error
150 function () {
151 var cleanTitle, html, link;
152
153 // Reset link to non-loading mode
154 updateWatchLink( $link, action );
155
156 // Format error message
157 cleanTitle = title.replace( /_/g, ' ' );
158 link = mw.html.element(
159 'a', {
160 href: mw.util.wikiGetlink( title ),
161 title: cleanTitle
162 }, cleanTitle
163 );
164 html = mw.msg( 'watcherrortext', link );
165
166 // Report to user about the error
167 mw.util.jsMessage( html, 'ajaxwatch' );
168
169 }
170 );
171 });
172 });
173
174 }( jQuery, mediaWiki ) );