diff options
Diffstat (limited to 'resources/mediawiki.page/mediawiki.page.watch.ajax.js')
-rw-r--r-- | resources/mediawiki.page/mediawiki.page.watch.ajax.js | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/resources/mediawiki.page/mediawiki.page.watch.ajax.js b/resources/mediawiki.page/mediawiki.page.watch.ajax.js new file mode 100644 index 00000000..a7e059c4 --- /dev/null +++ b/resources/mediawiki.page/mediawiki.page.watch.ajax.js @@ -0,0 +1,175 @@ +/** + * Animate watch/unwatch links to use asynchronous API requests to + * watch pages, rather than navigating to a different URI. + */ +( function ( mw, $ ) { + /** + * The name of the page to watch or unwatch. + */ + var title = mw.config.get( 'wgRelevantPageName', mw.config.get( 'wgPageName' ) ); + + /** + * Update the link text, link href attribute and (if applicable) + * "loading" class. + * + * @param $link {jQuery} Anchor tag of (un)watch link. + * @param action {String} One of 'watch', 'unwatch'. + * @param state {String} [optional] 'idle' or 'loading'. Default is 'idle'. + */ + function updateWatchLink( $link, action, state ) { + var accesskeyTip, msgKey, $li, otherAction; + + // message keys 'watch', 'watching', 'unwatch' or 'unwatching'. + msgKey = state === 'loading' ? action + 'ing' : action; + otherAction = action === 'watch' ? 'unwatch' : 'watch'; + accesskeyTip = $link.attr( 'title' ).match( mw.util.tooltipAccessKeyRegexp ); + $li = $link.closest( 'li' ); + /** + * Trigger a 'watchpage' event for this List item. + * Announce the otherAction value as the first param. + * Used to monitor the state of watch link. + * TODO: Revise when system wide hooks are implemented + */ + if( state === undefined ) { + $li.trigger( 'watchpage.mw', otherAction ); + } + + $link + .text( mw.msg( msgKey ) ) + .attr( 'title', mw.msg( 'tooltip-ca-' + action ) + + ( accesskeyTip ? ' ' + accesskeyTip[0] : '' ) + ) + .attr( 'href', mw.util.wikiScript() + '?' + $.param({ + title: title, + action: action + }) + ); + + // Most common ID style + if ( $li.prop( 'id' ) === 'ca-' + otherAction ) { + $li.prop( 'id', 'ca-' + action ); + } + + // Special case for vector icon + if ( $li.hasClass( 'icon' ) ) { + if ( state === 'loading' ) { + $link.addClass( 'loading' ); + } else { + $link.removeClass( 'loading' ); + } + } + } + + /** + * @todo This should be moved somewhere more accessible. + * @param url {String} + * @return {String} The extracted action, defaults to 'view'. + */ + function mwUriGetAction( url ) { + var action, actionPaths, key, i, m, parts; + + actionPaths = mw.config.get( 'wgActionPaths' ); + + // @todo: Does MediaWiki give action path or query param + // precedence ? If the former, move this to the bottom + action = mw.util.getParamValue( 'action', url ); + if ( action !== null ) { + return action; + } + + for ( key in actionPaths ) { + if ( actionPaths.hasOwnProperty( key ) ) { + parts = actionPaths[key].split( '$1' ); + for ( i = 0; i < parts.length; i += 1 ) { + parts[i] = $.escapeRE( parts[i] ); + } + m = new RegExp( parts.join( '(.+)' ) ).exec( url ); + if ( m && m[1] ) { + return key; + } + + } + } + + return 'view'; + } + + // Expose local methods + mw.page.watch = { + 'updateWatchLink': updateWatchLink + }; + + $( document ).ready( function () { + var $links = $( '.mw-watchlink a, a.mw-watchlink, ' + + '#ca-watch a, #ca-unwatch a, #mw-unwatch-link1, ' + + '#mw-unwatch-link2, #mw-watch-link2, #mw-watch-link1' ); + + // Allowing people to add inline animated links is a little scary + $links = $links.filter( ':not( #bodyContent *, #content * )' ); + + $links.click( function ( e ) { + var action, api, $link; + + action = mwUriGetAction( this.href ); + + if ( action !== 'watch' && action !== 'unwatch' ) { + // Could not extract target action from link url, + // let native browsing handle it further + return true; + } + e.preventDefault(); + e.stopPropagation(); + + $link = $( this ); + + updateWatchLink( $link, action, 'loading' ); + + api = new mw.Api(); + api[action]( + title, + // Success + function ( watchResponse ) { + var $li, otherAction; + + otherAction = action === 'watch' ? 'unwatch' : 'watch'; + $li = $link.closest( 'li' ); + + mw.notify( $.parseHTML( watchResponse.message ), { tag: 'watch-self' } ); + + // Set link to opposite + updateWatchLink( $link, otherAction ); + + // Bug 12395 - update the watch checkbox on edit pages when the + // page is watched or unwatched via the tab. + if ( watchResponse.watched !== undefined ) { + $( '#wpWatchthis' ).prop( 'checked', true ); + } else { + $( '#wpWatchthis' ).removeProp( 'checked' ); + } + }, + // Error + function () { + var cleanTitle, msg, link; + + // Reset link to non-loading mode + updateWatchLink( $link, action ); + + // Format error message + cleanTitle = title.replace( /_/g, ' ' ); + link = mw.html.element( + 'a', { + href: mw.util.wikiGetlink( title ), + title: cleanTitle + }, cleanTitle + ); + msg = mw.messsage( 'watcherrortext', link ); + + // Report to user about the error + mw.notify( msg, { tag: 'watch-self' } ); + + } + ); + }); + }); + +}( mediaWiki, jQuery ) ); |