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