-// dependencies:
-// * ajax.js:
- /*extern sajax_init_object, sajax_do_call */
-// * wikibits.js:
- /*extern changeText, akeytt, hookEvent, jsMsg */
+/**
+ * Animate watch/unwatch links to use asynchronous API requests to
+ * watch pages, rather than clicking on links. Requires jQuery.
+ * Uses jsMsg() from wikibits.js.
+ */
-// These should have been initialized in the generated js
-/*extern wgAjaxWatch, wgPageName */
-
-if(typeof wgAjaxWatch === "undefined" || !wgAjaxWatch) {
+if( typeof wgAjaxWatch === 'undefined' || !wgAjaxWatch ) {
var wgAjaxWatch = {
- watchMsg: "Watch",
- unwatchMsg: "Unwatch",
- watchingMsg: "Watching...",
- unwatchingMsg: "Unwatching..."
+ watchMsg: 'Watch',
+ unwatchMsg: 'Unwatch',
+ watchingMsg: 'Watching...',
+ unwatchingMsg: 'Unwatching...',
+ 'tooltip-ca-watchMsg': 'Add this page to your watchlist',
+ 'tooltip-ca-unwatchMsg': 'Remove this page from your watchlist'
};
}
-wgAjaxWatch.supported = true; // supported on current page and by browser
-wgAjaxWatch.watching = false; // currently watching page
-wgAjaxWatch.inprogress = false; // ajax request in progress
-wgAjaxWatch.timeoutID = null; // see wgAjaxWatch.ajaxCall
-wgAjaxWatch.watchLinks = []; // "watch"/"unwatch" links
-wgAjaxWatch.iconMode = false; // new icon driven functionality
-wgAjaxWatch.imgBasePath = ""; // base img path derived from icons on load
-
-wgAjaxWatch.setLinkText = function(newText) {
- if(wgAjaxWatch.iconMode){
- for (i = 0; i < wgAjaxWatch.watchLinks.length; i++) {
- wgAjaxWatch.watchLinks[i].firstChild.alt = newText;
- if(newText==wgAjaxWatch.watchingMsg||newText==wgAjaxWatch.unwatchingMsg){
- wgAjaxWatch.watchLinks[i].firstChild.src = wgAjaxWatch.imgBasePath+"/skins/common/images/spinner.gif";
- }else if(newText==wgAjaxWatch.watchMsg){
- wgAjaxWatch.watchLinks[i].firstChild.src = wgAjaxWatch.imgBasePath+"/skins/vector/images/watch_off.gif";
- }else if(newText==wgAjaxWatch.unwatchMsg){
- wgAjaxWatch.watchLinks[i].firstChild.src = wgAjaxWatch.imgBasePath+"/skins/vector/images/watch_on.gif";
- }
- }
- }else{
- for (i = 0; i < wgAjaxWatch.watchLinks.length; i++) {
- changeText(wgAjaxWatch.watchLinks[i], newText);
- }
- }
-};
-
-wgAjaxWatch.setLinkID = function(newId) {
- // We can only set the first one
- wgAjaxWatch.watchLinks[0].setAttribute( 'id', newId );
- akeytt(newId); // update tooltips for Monobook
-};
-
-wgAjaxWatch.setHref = function( string ) {
- for( i = 0; i < wgAjaxWatch.watchLinks.length; i++ ) {
- if( string == 'watch' ) {
- wgAjaxWatch.watchLinks[i].href = wgAjaxWatch.watchLinks[i].href
- .replace( /&action=unwatch/, '&action=watch' );
- } else if( string == 'unwatch' ) {
- wgAjaxWatch.watchLinks[i].href = wgAjaxWatch.watchLinks[i].href
- .replace( /&action=watch/, '&action=unwatch' );
- }
+wgAjaxWatch.setLinkText = function( $link, action ) {
+ if( action == 'watch' || action == 'unwatch' ) {
+ // save the accesskey from the title
+ var keyCommand = $link.attr( 'title' ).match( /\[.*?\]$/ )
+ ? $link.attr( 'title' ).match( /\[.*?\]$/ )[0]
+ : '';
+ $link.attr( 'title', wgAjaxWatch['tooltip-ca-' + action + 'Msg'] + ' ' + keyCommand );
}
-}
-
-wgAjaxWatch.ajaxCall = function() {
- if(!wgAjaxWatch.supported) {
- return true;
- } else if (wgAjaxWatch.inprogress) {
- return false;
- }
- if(!wfSupportsAjax()) {
- // Lazy initialization so we don't toss up
- // ActiveX warnings on initial page load
- // for IE 6 users with security settings.
- wgAjaxWatch.supported = false;
- return true;
+ if( $link.data( 'icon' ) ) {
+ $link.attr( 'alt', wgAjaxWatch[action + 'Msg'] );
+ if ( action == 'watching' || action == 'unwatching' ) {
+ $link.addClass( 'loading' );
+ } else {
+ $link.removeClass( 'loading' );
+ }
+ } else {
+ $link.html( wgAjaxWatch[action + 'Msg'] );
}
-
- wgAjaxWatch.inprogress = true;
- wgAjaxWatch.setLinkText( wgAjaxWatch.watching
- ? wgAjaxWatch.unwatchingMsg : wgAjaxWatch.watchingMsg);
- sajax_do_call(
- "wfAjaxWatch",
- [wgPageName, (wgAjaxWatch.watching ? "u" : "w")],
- wgAjaxWatch.processResult
- );
- // if the request isn't done in 10 seconds, allow user to try again
- wgAjaxWatch.timeoutID = window.setTimeout(
- function() { wgAjaxWatch.inprogress = false; },
- 10000
- );
- return false;
};
-wgAjaxWatch.processResult = function(request) {
- if(!wgAjaxWatch.supported) {
- return;
- }
- var response = request.responseText;
- if( response.match(/^<w#>/) ) {
- wgAjaxWatch.watching = true;
- wgAjaxWatch.setLinkText(wgAjaxWatch.unwatchMsg);
- wgAjaxWatch.setLinkID("ca-unwatch");
- wgAjaxWatch.setHref( 'unwatch' );
- } else if( response.match(/^<u#>/) ) {
- wgAjaxWatch.watching = false;
- wgAjaxWatch.setLinkText(wgAjaxWatch.watchMsg);
- wgAjaxWatch.setLinkID("ca-watch");
- wgAjaxWatch.setHref( 'watch' );
+wgAjaxWatch.processResult = function( response ) {
+ response = response.watch;
+ var $link = $j( this );
+ // To ensure we set the same status for all watch links with the
+ // same target we trigger a custom event on *all* watch links.
+ if( response.watched !== undefined ) {
+ wgAjaxWatch.$links.trigger( 'mw-ajaxwatch', [response.title, 'watch'] );
+ } else if ( response.unwatched !== undefined ) {
+ wgAjaxWatch.$links.trigger( 'mw-ajaxwatch', [response.title, 'unwatch'] );
} else {
- // Either we got a <err#> error code or it just plain broke.
- window.location.href = wgAjaxWatch.watchLinks[0].href;
+ // Either we got an error code or it just plain broke.
+ window.location.href = $link.attr( 'href' );
return;
}
- jsMsg( response.substr(4), 'watch' );
- wgAjaxWatch.inprogress = false;
- if(wgAjaxWatch.timeoutID) {
- window.clearTimeout(wgAjaxWatch.timeoutID);
- }
- // Bug 12395 - avoid some watch link confusion on edit
- var watchthis = document.getElementById("wpWatchthis");
- if( watchthis && response.match(/^<[uw]#>/) ) {
- watchthis.checked = response.match(/^<w#>/) ? "checked" : "";
+
+ jsMsg( response.message, 'watch' );
+
+ // Bug 12395 - update the watch checkbox on edit pages when the
+ // page is watched or unwatched via the tab.
+ if( response.watched !== undefined ) {
+ $j( '#wpWatchthis' ).attr( 'checked', '1' );
+ } else {
+ $j( '#wpWatchthis' ).removeAttr( 'checked' );
}
- return;
};
-wgAjaxWatch.onLoad = function() {
- // This document structure hardcoding sucks. We should make a class and
- // toss all this out the window.
-
- var el1 = document.getElementById("ca-unwatch");
- var el2 = null;
- if (!el1) {
- el1 = document.getElementById("mw-unwatch-link1");
- el2 = document.getElementById("mw-unwatch-link2");
- }
- if(el1) {
- wgAjaxWatch.watching = true;
- } else {
- wgAjaxWatch.watching = false;
- el1 = document.getElementById("ca-watch");
- if (!el1) {
- el1 = document.getElementById("mw-watch-link1");
- el2 = document.getElementById("mw-watch-link2");
- }
- if(!el1) {
- wgAjaxWatch.supported = false;
- return;
+$j( document ).ready( function() {
+ var $links = $j( '.mw-watchlink a, a.mw-watchlink' );
+ // BC with older skins
+ $links = $links
+ .add( $j( '#ca-watch a, #ca-unwatch a, a#mw-unwatch-link1' ) )
+ .add( $j( 'a#mw-unwatch-link2, a#mw-watch-link2, a#mw-watch-link1' ) );
+ // allowing people to add inline animated links is a little scary
+ $links = $links.filter( ':not( #bodyContent *, #content * )' );
+
+ $links.each( function() {
+ var $link = $j( this );
+ $link
+ .data( 'icon', $link.parents( 'li' ).hasClass( 'icon' ) )
+ .data( 'action', $link.attr( 'href' ).match( /[\?\&]action=unwatch/i ) ? 'unwatch' : 'watch' );
+ var title = $link.attr( 'href' ).match( /[\?\&]title=(.*?)&/i )[1];
+ $link.data( 'target', decodeURIComponent( title ).replace( /_/g, ' ' ) );
+ });
+
+ $links.click( function( event ) {
+ var $link = $j( this );
+
+ if( wgAjaxWatch.supported === false || !wgEnableWriteAPI || !wfSupportsAjax() ) {
+ // Lazy initialization so we don't toss up
+ // ActiveX warnings on initial page load
+ // for IE 6 users with security settings.
+ wgAjaxWatch.$links.unbind( 'click' );
+ return true;
}
- }
-
- // If we're using the icon, add rollover affects
- try{
- if(el1.firstChild.firstChild.tagName.match(/img/i)){
- wgAjaxWatch.iconMode = true;
- wgAjaxWatch.imgBasePath = el1.firstChild.firstChild.src.replace(/\/skins\/vector\/images\/watch_(off|on).gif/, "");
- el1.firstChild.onmouseover = function(e){
- this.firstChild.src = (wgAjaxWatch.watching ? this.firstChild.src.replace(/_on/, "_off") : this.firstChild.src.replace(/_off/, "_on"));
- }
- el1.firstChild.onmouseout = function(e){
- this.firstChild.src = (wgAjaxWatch.watching ? this.firstChild.src.replace(/_off/, "_on") : this.firstChild.src.replace(/_on/, "_off"));
- }
- }
- }catch(e){
- // not using the icon
- }
+ wgAjaxWatch.setLinkText( $link, $link.data( 'action' ) + 'ing' );
+ $j.get( wgScriptPath
+ + '/api' + wgScriptExtension + '?action=watch&format=json&title='
+ + encodeURIComponent( $link.data( 'target' ) )
+ + ( $link.data( 'action' ) == 'unwatch' ? '&unwatch' : '' ),
+ {},
+ wgAjaxWatch.processResult,
+ 'json'
+ );
- // The id can be either for the parent (Monobook-based) or the element
- // itself (non-Monobook)
- wgAjaxWatch.watchLinks.push( el1.tagName.toLowerCase() == "a"
- ? el1 : el1.firstChild );
+ return false;
+ });
- if( el2 ) {
- wgAjaxWatch.watchLinks.push( el2 );
- }
+ // When a request returns, a custom event 'mw-ajaxwatch' is triggered
+ // on *all* watch links, so they can be updated if necessary
+ $links.bind( 'mw-ajaxwatch', function( event, target, action ) {
+ var $link = $j( this );
+ var foo = $link.data( 'target' );
+ if( $link.data( 'target' ) == target ) {
+ var otheraction = action == 'watch'
+ ? 'unwatch'
+ : 'watch';
- // I couldn't get for (watchLink in wgAjaxWatch.watchLinks) to work, if
- // you can be my guest.
- for( i = 0; i < wgAjaxWatch.watchLinks.length; i++ ) {
- wgAjaxWatch.watchLinks[i].onclick = wgAjaxWatch.ajaxCall;
- }
- return;
-};
+ $link.data( 'action', otheraction );
+ wgAjaxWatch.setLinkText( $link, otheraction );
+ $link.attr( 'href', $link.attr( 'href' ).replace( '/&action=' + action + '/', '&action=' + otheraction ) );
+ if( $link.parents( 'li' ).attr( 'id' ) == 'ca-' + action ) {
+ $link.parents( 'li' ).attr( 'id', 'ca-' + otheraction );
+ }
+ };
+ return false;
+ });
-hookEvent("load", wgAjaxWatch.onLoad);
+ wgAjaxWatch.$links = $links;
+});