From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.

//jshint maxerr:512

// Watchlist cleaner

function cleanWatchlist() {

	var millisDay = 24*60*60*1000;

	var cleanMiss = confirm("Remove redlinked (missing) pages from Watchlist?\n\n(OK for yes, Cancel for no)");

	if (cleanMiss) {

		var keepMissTalk = confirm("Skip removing redlinked pages if talk page exists?\n\n(OK for yes, Cancel for no)");

	}

	var cleanRedir = confirm("Remove redirects from Watchlist?\n\n(OK for yes, Cancel for no)");

	var cleanOld = confirm("Remove pages from Watchlist you haven't recently edited (slow)?\n\n(OK for yes, Cancel for no)");

	if (cleanOld) { 

		cleanOld = prompt("Minimum number of days since your last edit:");

		cleanOld = Number(cleanOld) ?

			new Date(new Date() - (Number(cleanOld)*millisDay)) :

			false;

	}

	var cleanNever = confirm("Remove pages from Watchlist you have never edited (slow)?\n\n(OK for yes, Cancel for no)");

	var keepCreations = confirm("Skip removing pages you created (slow)?\n\n(OK for yes, Cancel for no)");

	

	var potentialUnwatch = [], unwatchPages = [], unwatchPagesCount = 0;

	var potentiallyStale = [], potentiallyStaleCount = 0, potentiallyStalePercent = -1;

	var statusText = "Fetching watchlist...";



	function doUnwatch() { // Recursively unwatch pages in batches of 50

		if (unwatchPages.length > 0) { // Still have pages to unwatch

			console.log("Pages to unwatch: ");

			console.log(unwatchPages);

			statusText = "Removing " + unwatchPages.length + " pages from watchlist...";

			mw.notify(statusText, {type: 'info', tag: 'status', autoHide: false});

			

			var uwTitles = unwatchPages.splice(0,50).join("|"); // Remove 50 items from top of list

			var params = {

				action: "watch",

				unwatch: "true",

				titles: uwTitles

			};

			

			new mw.Api().postWithToken("watch", params ).done( function(reslt) {

				console.log("Unwatch successful: ");

				console.log(reslt);

				doUnwatch();

			} ).fail( function(code, reslt) {

				console.error("API error when unwatching pages: ");

				console.error(reslt);

				statusText = "API error when unwatching pages: " + code;

				mw.notify(statusText, {type: 'error', tag: 'error'});

				return;

			} );

		} else { // No more pages to unwatch

			statusText = "Done. Removed " + unwatchPagesCount + " pages from watchlist";

			mw.notify(statusText, {type: 'success', tag: 'status', autoHide: true});

		}

	}

	

	function doWlBackup() {

		unwatchPagesCount = unwatchPages.length;

		var foundText = "Found " + unwatchPagesCount + " pages to remove.";

		if (unwatchPagesCount == 0) {

			mw.notify(foundText, {type: 'success', tag: 'found'});

			return;

		} else if ( !confirm("Remove " + unwatchPagesCount + " pages from watchlist?") ) {

			mw.notify("Watchlist cleaner cancelled.", {type: 'error', tag: 'status', autoHide: true});

			return;

		} else if ( confirm("Backup removed pages?\n\n(OK for yes, Cancel for no)") ) {

			var wlBackupLocation = mw.config.get('wgFormattedNamespaces')[2

				+ ":" + mw.config.get('wgUserName') + "/Watchlist_backup";

								

			var params = {

				action: 'edit',

				title: wlBackupLocation,

				section: 'new',

				sectiontitle: new Date().toISOString(),

				text: '* [[:' + unwatchPages.join("]]\n* [[:") + ']]',

				summary: 'Backup pages removed from watchlist ([[User:Ahecht/Scripts/watchlistcleaner|Watchlist cleaner]])'

			};

			

			new mw.Api().postWithToken("csrf", params ).done( function(reslt) {

				console.log(wlBackupLocation + " updated:");

				console.log(reslt);

				statusText = unwatchPagesCount + " pages saved to "

					+ wlBackupLocation + ".";

				mw.notify(statusText, {type: 'success', tag: 'status', autoHide: true});

				doUnwatch();

			} ).fail( function(code, error) {

				console.error("API error when saving backup: ");

				console.error(error);

				statusText = "API error when saving backup: " + code;

				mw.notify(statusText, {type: 'error', tag: 'error'});

				return;

			} );

		} else {

			mw.notify(foundText, {type: 'warn', tag: 'found'});

			doUnwatch();

		}

	}

	

	function removeCreations(potentialUnwatchCount = 0, potentialUnwatchPercent = -1) {

		if (!keepCreations) { // Don't filter page creations

			unwatchPages = potentialUnwatch;

			doWlBackup();

		} else if (potentialUnwatch.length == 0)  { // Done filtering

			doWlBackup();

		} else { // Filter page creations

			if(!potentialUnwatchCount) {

				potentialUnwatchCount = potentialUnwatch.length;

			}

			var tempPUPercent = 100 - Math.ceil(100 * potentialUnwatch.length / potentialUnwatchCount);

			if (tempPUPercent != potentialUnwatchPercent) {

				potentialUnwatchPercent = tempPUPercent;

				var statusText = "Checking for your pages you created... ("+ tempPUPercent + "%)";

				mw.notify(statusText, {type: 'info', tag: 'status', autoHide: false});

			}

			var query = {

				prop: 'revisions',

				titles: potentialUnwatch.shift(),

				rvprop: 'user',

				rvlimit: '1',

				rvdir: 'newer',

				formatversion: "2"

			};

			

			new mw.Api().get( query )

				.done (function (d) {

					if(d && d.query && d.query.pages && d.query.pages0 &&

						d.query.pages0].revisions && d.query.pages0].revisions0]) { // Page found

						d=d.query.pages0].revisions0];

						if(d.user && d.user == mw.config.get('wgUserName')) {

							console.log("Keeping page " + query.titles + ", which you created.");

							foundText = "Keeping page [[" + query.titles + "]], which you created.";

							mw.notify(foundText, {type: 'warn', tag: 'found'});

						} else {

							unwatchPages.push(query.titles);

						}

					} else {

						unwatchPages.push(query.titles);

					}

					removeCreations(potentialUnwatchCount, potentialUnwatchPercent);

				} ).fail (function(code, error) {

					console.error("API error when fetching page creator: ");

					console.error(error);

					statusText = "API error fetching page creator: " + code;

					mw.notify(statusText, {type: 'error', tag: 'error'});

					unwatchPages.push(query.titles);

					removeCreations(potentialUnwatchCount, potentialUnwatchPercent);

				} );

		}

	}

	

	function isPageStale(checkPage, checkAssoc, pageStatus = {exists: false, newEdit: false, everEdit: false}) {

		var query = {

			prop: 'revisions',

			titles: checkPage,

			rvprop: 'timestamp',

			rvlimit: '1',

			rvuser: mw.config.get('wgUserName'),

			formatversion: "2"

		};



		new mw.Api().get( query )

			.done (function (d) {

				if (d && d.query && d.query.pages && d.query.pages0]) { //API query returned pages

					pageStatus.exists = true;

					if (d.query.pages0].revisions && d.query.pages0].revisions0].timestamp) { //User edit found

						pageStatus.everEdit = true;

						if (cleanOld) {

							var revDate = new Date(d.query.pages0].revisions0].timestamp);

							if ( revDate > cleanOld ) { // New revision found

								if (!checkAssoc) {

									console.log ("User edit on " + checkPage + " is new enough.");

								}

								pageStatus.newEdit = true;

							} else { // Last revision exists but is too old

								console.log ("Old user edit found on " + checkPage + " from " + revDate);

							}

						} else if ( (pageStatus.everEdit === false) && !checkAssoc ) {

							console.log("User edit found on " + checkPage);

						}

					} else { // No user edits found

						console.log ("No user edits found on " + checkPage);

					}

				} // No page returned by API

				

				if ( (cleanOld && pageStatus.newEdit === false) ||

					(cleanNever && pageStatus.everEdit === false) ) {

					if (checkAssoc) { // Talk page exists to check

						console.log("Checking talk page...");

						isPageStale(checkAssoc, false, pageStatus);

					} else { //already on talk page

						checkStalePages(pageStatus);

					}

				} else { // Page passed

					checkStalePages(pageStatus);

				}

			} ).fail (function(code, error) {

				console.error("API error when fetching revisions: ");

				console.error(error);

				statusText = "API error fetching revisions: " + code;

				mw.notify(statusText, {type: 'error', tag: 'error'});

				removeCreations();

			} );

	}

	

	function checkStalePages(pageStatus) {

		var tempPSPercent = 100 - Math.ceil(100 * potentiallyStale.length / potentiallyStaleCount);

		if (tempPSPercent != potentiallyStalePercent) {

			potentiallyStalePercent = tempPSPercent;

			var statusText = "Checking for your last edit... ("+ tempPSPercent + "%)";

			mw.notify(statusText, {type: 'info', tag: 'status', autoHide: false});

		}



		var currentPage = potentiallyStale.shift();

		if(currentPage) {

			if(pageStatus.exists) { // Page exists

				if (cleanNever && pageStatus.everEdit === false) { // No user edits found

					foundText = "[[" + currentPage0 + "]] has not been edited by you ever.";

					mw.notify(foundText, {type: 'warn', tag: 'found'});		

					potentialUnwatch.push(currentPage0]);

				} else if (cleanOld && pageStatus.everEdit === true && pageStatus.newEdit === false) { // No new edits found

					foundText = "[[" + currentPage0 + "]] has not been edited by you recently.";

					mw.notify(foundText, {type: 'warn', tag: 'found'});		

					potentialUnwatch.push(currentPage0]);

				} // Page is okay

			} // Page doesn't exist

			if (potentiallyStale0]) {

				isPageStale(potentiallyStale0][0], potentiallyStale0][1]);

			} else { // No more pages in list

				console.log("Finished checking for old and unedited pages");

				removeCreations();

			}

		} else { // No more pages in list

			console.log("Finished checking for old and unedited pages");

			removeCreations();

		}

	}

	

	function fetchWatchlist(cont) { // Recursively fetch watchlist

		var query = {

			action: "query",

			prop: "info",

			inprop: "associatedpage|talkid",

			generator: "watchlistraw",

			gwrlimit: "max",

			formatversion: "2"

		};

		if (cont) {

			query = Object.assign(query, cont);

		}

		mw.notify(statusText, {type: 'info', tag: 'status', autoHide: false});

		statusText = statusText + ".";

		new mw.Api().get( query )

			.done (function (d) {

				if (d && d.query && d.query.pages) { //API query returned pages

					d.query.pages.forEach( function(i) {

						if(i.ns % 2 == 0) { // Page isn't a talk page

							if(cleanMiss && i.missing){ // Add missing page to list

								mw.notify("Found missing page [[" + i.title + "]].", {type: 'warn', tag: 'found'});

								if (keepMissTalk && !i.talkid) {

									mw.notify("Talk page of [[" + i.title + "]] exists, skipping.", {type: 'warn', tag: 'found'});

								} else {

									potentialUnwatch.push(i.title);

								}

							} else if (cleanRedir && i.redirect) { // Add redirect to list

								mw.notify("Found redirect [[" + i.title + "]].", {type: 'warn', tag: 'found'});

								potentialUnwatch.push(i.title);

							} else if (cleanOld || cleanNever) { // Add pages to check revisions

								potentiallyStale.push([i.title, i.associatedpage]);

							}

						}

					} );

				}

				if (d && d.continue) { // More results are available

					fetchWatchlist(d.continue);

				} else if (potentiallyStale0 && (cleanOld || cleanNever)) {

					// No more results, check stale and missing

					potentiallyStaleCount = potentiallyStale.length;

					isPageStale(potentiallyStale0][0], potentiallyStale0][1]);

				} else { // No more results, no potentially stale pages or not checking

					removeCreations();

				}

			} ).fail (function(code, error) {

				console.error("API error when fetching watchlist: ");

				console.error(error);

				statusText = "API error fetching watchlist: " + code;

				mw.notify(statusText, {type: 'error', tag: 'error'});

			} );

		return;

	}

	

	if (cleanMiss || cleanRedir || cleanOld || cleanNever) { // Cancel wasn't selected for all options

		fetchWatchlist();

	}

}



$(document).ready( function() { // Add "Clean" link to toolbar

	if( /Watchlist$/.test(mw.config.get('wgCanonicalSpecialPageName')) ) {

		var cleanLink = '<a href="#" title="Run cleanwatchlist.js" id="clean-watchlist-link" rel data-event-name="tabs.">Clean the watchlist</a>';

		if ($('.mw-watchlist-toollinks').length > 0) { //Most older skins

			$('.mw-watchlist-toollinks a').last().after(' | ' + cleanLink);

		} else if ($("#p-associated-pages").length > 0) { //Vector-2022 or Minerva

			var lastLi = $("#p-associated-pages li").last();

			lastLi.clone().

				attr("id", (lastLi.attr("id") || "").replace(/(\d+)$/, function(){return arguments1*1+1;}))

				.html(cleanLink).insertAfter(lastLi);

		} else { //Fallback to "Tools" menu

			mw.util.addPortletLink( 'p-tb', '#', 'Clean the watchlist', 'clean-watchlist-link', 'Run cleanwatchlist.js');

		}

		$("#clean-watchlist-link").on("click", cleanWatchlist );

	}

} );
From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.

//jshint maxerr:512

// Watchlist cleaner

function cleanWatchlist() {

	var millisDay = 24*60*60*1000;

	var cleanMiss = confirm("Remove redlinked (missing) pages from Watchlist?\n\n(OK for yes, Cancel for no)");

	if (cleanMiss) {

		var keepMissTalk = confirm("Skip removing redlinked pages if talk page exists?\n\n(OK for yes, Cancel for no)");

	}

	var cleanRedir = confirm("Remove redirects from Watchlist?\n\n(OK for yes, Cancel for no)");

	var cleanOld = confirm("Remove pages from Watchlist you haven't recently edited (slow)?\n\n(OK for yes, Cancel for no)");

	if (cleanOld) { 

		cleanOld = prompt("Minimum number of days since your last edit:");

		cleanOld = Number(cleanOld) ?

			new Date(new Date() - (Number(cleanOld)*millisDay)) :

			false;

	}

	var cleanNever = confirm("Remove pages from Watchlist you have never edited (slow)?\n\n(OK for yes, Cancel for no)");

	var keepCreations = confirm("Skip removing pages you created (slow)?\n\n(OK for yes, Cancel for no)");

	

	var potentialUnwatch = [], unwatchPages = [], unwatchPagesCount = 0;

	var potentiallyStale = [], potentiallyStaleCount = 0, potentiallyStalePercent = -1;

	var statusText = "Fetching watchlist...";



	function doUnwatch() { // Recursively unwatch pages in batches of 50

		if (unwatchPages.length > 0) { // Still have pages to unwatch

			console.log("Pages to unwatch: ");

			console.log(unwatchPages);

			statusText = "Removing " + unwatchPages.length + " pages from watchlist...";

			mw.notify(statusText, {type: 'info', tag: 'status', autoHide: false});

			

			var uwTitles = unwatchPages.splice(0,50).join("|"); // Remove 50 items from top of list

			var params = {

				action: "watch",

				unwatch: "true",

				titles: uwTitles

			};

			

			new mw.Api().postWithToken("watch", params ).done( function(reslt) {

				console.log("Unwatch successful: ");

				console.log(reslt);

				doUnwatch();

			} ).fail( function(code, reslt) {

				console.error("API error when unwatching pages: ");

				console.error(reslt);

				statusText = "API error when unwatching pages: " + code;

				mw.notify(statusText, {type: 'error', tag: 'error'});

				return;

			} );

		} else { // No more pages to unwatch

			statusText = "Done. Removed " + unwatchPagesCount + " pages from watchlist";

			mw.notify(statusText, {type: 'success', tag: 'status', autoHide: true});

		}

	}

	

	function doWlBackup() {

		unwatchPagesCount = unwatchPages.length;

		var foundText = "Found " + unwatchPagesCount + " pages to remove.";

		if (unwatchPagesCount == 0) {

			mw.notify(foundText, {type: 'success', tag: 'found'});

			return;

		} else if ( !confirm("Remove " + unwatchPagesCount + " pages from watchlist?") ) {

			mw.notify("Watchlist cleaner cancelled.", {type: 'error', tag: 'status', autoHide: true});

			return;

		} else if ( confirm("Backup removed pages?\n\n(OK for yes, Cancel for no)") ) {

			var wlBackupLocation = mw.config.get('wgFormattedNamespaces')[2

				+ ":" + mw.config.get('wgUserName') + "/Watchlist_backup";

								

			var params = {

				action: 'edit',

				title: wlBackupLocation,

				section: 'new',

				sectiontitle: new Date().toISOString(),

				text: '* [[:' + unwatchPages.join("]]\n* [[:") + ']]',

				summary: 'Backup pages removed from watchlist ([[User:Ahecht/Scripts/watchlistcleaner|Watchlist cleaner]])'

			};

			

			new mw.Api().postWithToken("csrf", params ).done( function(reslt) {

				console.log(wlBackupLocation + " updated:");

				console.log(reslt);

				statusText = unwatchPagesCount + " pages saved to "

					+ wlBackupLocation + ".";

				mw.notify(statusText, {type: 'success', tag: 'status', autoHide: true});

				doUnwatch();

			} ).fail( function(code, error) {

				console.error("API error when saving backup: ");

				console.error(error);

				statusText = "API error when saving backup: " + code;

				mw.notify(statusText, {type: 'error', tag: 'error'});

				return;

			} );

		} else {

			mw.notify(foundText, {type: 'warn', tag: 'found'});

			doUnwatch();

		}

	}

	

	function removeCreations(potentialUnwatchCount = 0, potentialUnwatchPercent = -1) {

		if (!keepCreations) { // Don't filter page creations

			unwatchPages = potentialUnwatch;

			doWlBackup();

		} else if (potentialUnwatch.length == 0)  { // Done filtering

			doWlBackup();

		} else { // Filter page creations

			if(!potentialUnwatchCount) {

				potentialUnwatchCount = potentialUnwatch.length;

			}

			var tempPUPercent = 100 - Math.ceil(100 * potentialUnwatch.length / potentialUnwatchCount);

			if (tempPUPercent != potentialUnwatchPercent) {

				potentialUnwatchPercent = tempPUPercent;

				var statusText = "Checking for your pages you created... ("+ tempPUPercent + "%)";

				mw.notify(statusText, {type: 'info', tag: 'status', autoHide: false});

			}

			var query = {

				prop: 'revisions',

				titles: potentialUnwatch.shift(),

				rvprop: 'user',

				rvlimit: '1',

				rvdir: 'newer',

				formatversion: "2"

			};

			

			new mw.Api().get( query )

				.done (function (d) {

					if(d && d.query && d.query.pages && d.query.pages0 &&

						d.query.pages0].revisions && d.query.pages0].revisions0]) { // Page found

						d=d.query.pages0].revisions0];

						if(d.user && d.user == mw.config.get('wgUserName')) {

							console.log("Keeping page " + query.titles + ", which you created.");

							foundText = "Keeping page [[" + query.titles + "]], which you created.";

							mw.notify(foundText, {type: 'warn', tag: 'found'});

						} else {

							unwatchPages.push(query.titles);

						}

					} else {

						unwatchPages.push(query.titles);

					}

					removeCreations(potentialUnwatchCount, potentialUnwatchPercent);

				} ).fail (function(code, error) {

					console.error("API error when fetching page creator: ");

					console.error(error);

					statusText = "API error fetching page creator: " + code;

					mw.notify(statusText, {type: 'error', tag: 'error'});

					unwatchPages.push(query.titles);

					removeCreations(potentialUnwatchCount, potentialUnwatchPercent);

				} );

		}

	}

	

	function isPageStale(checkPage, checkAssoc, pageStatus = {exists: false, newEdit: false, everEdit: false}) {

		var query = {

			prop: 'revisions',

			titles: checkPage,

			rvprop: 'timestamp',

			rvlimit: '1',

			rvuser: mw.config.get('wgUserName'),

			formatversion: "2"

		};



		new mw.Api().get( query )

			.done (function (d) {

				if (d && d.query && d.query.pages && d.query.pages0]) { //API query returned pages

					pageStatus.exists = true;

					if (d.query.pages0].revisions && d.query.pages0].revisions0].timestamp) { //User edit found

						pageStatus.everEdit = true;

						if (cleanOld) {

							var revDate = new Date(d.query.pages0].revisions0].timestamp);

							if ( revDate > cleanOld ) { // New revision found

								if (!checkAssoc) {

									console.log ("User edit on " + checkPage + " is new enough.");

								}

								pageStatus.newEdit = true;

							} else { // Last revision exists but is too old

								console.log ("Old user edit found on " + checkPage + " from " + revDate);

							}

						} else if ( (pageStatus.everEdit === false) && !checkAssoc ) {

							console.log("User edit found on " + checkPage);

						}

					} else { // No user edits found

						console.log ("No user edits found on " + checkPage);

					}

				} // No page returned by API

				

				if ( (cleanOld && pageStatus.newEdit === false) ||

					(cleanNever && pageStatus.everEdit === false) ) {

					if (checkAssoc) { // Talk page exists to check

						console.log("Checking talk page...");

						isPageStale(checkAssoc, false, pageStatus);

					} else { //already on talk page

						checkStalePages(pageStatus);

					}

				} else { // Page passed

					checkStalePages(pageStatus);

				}

			} ).fail (function(code, error) {

				console.error("API error when fetching revisions: ");

				console.error(error);

				statusText = "API error fetching revisions: " + code;

				mw.notify(statusText, {type: 'error', tag: 'error'});

				removeCreations();

			} );

	}

	

	function checkStalePages(pageStatus) {

		var tempPSPercent = 100 - Math.ceil(100 * potentiallyStale.length / potentiallyStaleCount);

		if (tempPSPercent != potentiallyStalePercent) {

			potentiallyStalePercent = tempPSPercent;

			var statusText = "Checking for your last edit... ("+ tempPSPercent + "%)";

			mw.notify(statusText, {type: 'info', tag: 'status', autoHide: false});

		}



		var currentPage = potentiallyStale.shift();

		if(currentPage) {

			if(pageStatus.exists) { // Page exists

				if (cleanNever && pageStatus.everEdit === false) { // No user edits found

					foundText = "[[" + currentPage0 + "]] has not been edited by you ever.";

					mw.notify(foundText, {type: 'warn', tag: 'found'});		

					potentialUnwatch.push(currentPage0]);

				} else if (cleanOld && pageStatus.everEdit === true && pageStatus.newEdit === false) { // No new edits found

					foundText = "[[" + currentPage0 + "]] has not been edited by you recently.";

					mw.notify(foundText, {type: 'warn', tag: 'found'});		

					potentialUnwatch.push(currentPage0]);

				} // Page is okay

			} // Page doesn't exist

			if (potentiallyStale0]) {

				isPageStale(potentiallyStale0][0], potentiallyStale0][1]);

			} else { // No more pages in list

				console.log("Finished checking for old and unedited pages");

				removeCreations();

			}

		} else { // No more pages in list

			console.log("Finished checking for old and unedited pages");

			removeCreations();

		}

	}

	

	function fetchWatchlist(cont) { // Recursively fetch watchlist

		var query = {

			action: "query",

			prop: "info",

			inprop: "associatedpage|talkid",

			generator: "watchlistraw",

			gwrlimit: "max",

			formatversion: "2"

		};

		if (cont) {

			query = Object.assign(query, cont);

		}

		mw.notify(statusText, {type: 'info', tag: 'status', autoHide: false});

		statusText = statusText + ".";

		new mw.Api().get( query )

			.done (function (d) {

				if (d && d.query && d.query.pages) { //API query returned pages

					d.query.pages.forEach( function(i) {

						if(i.ns % 2 == 0) { // Page isn't a talk page

							if(cleanMiss && i.missing){ // Add missing page to list

								mw.notify("Found missing page [[" + i.title + "]].", {type: 'warn', tag: 'found'});

								if (keepMissTalk && !i.talkid) {

									mw.notify("Talk page of [[" + i.title + "]] exists, skipping.", {type: 'warn', tag: 'found'});

								} else {

									potentialUnwatch.push(i.title);

								}

							} else if (cleanRedir && i.redirect) { // Add redirect to list

								mw.notify("Found redirect [[" + i.title + "]].", {type: 'warn', tag: 'found'});

								potentialUnwatch.push(i.title);

							} else if (cleanOld || cleanNever) { // Add pages to check revisions

								potentiallyStale.push([i.title, i.associatedpage]);

							}

						}

					} );

				}

				if (d && d.continue) { // More results are available

					fetchWatchlist(d.continue);

				} else if (potentiallyStale0 && (cleanOld || cleanNever)) {

					// No more results, check stale and missing

					potentiallyStaleCount = potentiallyStale.length;

					isPageStale(potentiallyStale0][0], potentiallyStale0][1]);

				} else { // No more results, no potentially stale pages or not checking

					removeCreations();

				}

			} ).fail (function(code, error) {

				console.error("API error when fetching watchlist: ");

				console.error(error);

				statusText = "API error fetching watchlist: " + code;

				mw.notify(statusText, {type: 'error', tag: 'error'});

			} );

		return;

	}

	

	if (cleanMiss || cleanRedir || cleanOld || cleanNever) { // Cancel wasn't selected for all options

		fetchWatchlist();

	}

}



$(document).ready( function() { // Add "Clean" link to toolbar

	if( /Watchlist$/.test(mw.config.get('wgCanonicalSpecialPageName')) ) {

		var cleanLink = '<a href="#" title="Run cleanwatchlist.js" id="clean-watchlist-link" rel data-event-name="tabs.">Clean the watchlist</a>';

		if ($('.mw-watchlist-toollinks').length > 0) { //Most older skins

			$('.mw-watchlist-toollinks a').last().after(' | ' + cleanLink);

		} else if ($("#p-associated-pages").length > 0) { //Vector-2022 or Minerva

			var lastLi = $("#p-associated-pages li").last();

			lastLi.clone().

				attr("id", (lastLi.attr("id") || "").replace(/(\d+)$/, function(){return arguments1*1+1;}))

				.html(cleanLink).insertAfter(lastLi);

		} else { //Fallback to "Tools" menu

			mw.util.addPortletLink( 'p-tb', '#', 'Clean the watchlist', 'clean-watchlist-link', 'Run cleanwatchlist.js');

		}

		$("#clean-watchlist-link").on("click", cleanWatchlist );

	}

} );

Videos

Youtube | Vimeo | Bing

Websites

Google | Yahoo | Bing

Encyclopedia

Google | Yahoo | Bing

Facebook