نکته: پس از انتشار ممکن است برای دیدن تغییرات نیاز باشد که حافظهٔ نهانی مرورگر خود را پاک کنید.

  • فایرفاکس / سافاری: کلید Shift را نگه دارید و روی دکمهٔ Reload کلیک کنید، یا کلید‌های Ctrl-F5 یا Ctrl-R را با هم فشار دهید (در رایانه‌های اپل مکینتاش کلید‌های ⌘-R)
  • گوگل کروم: کلیدهای Ctrl+Shift+R را با هم فشار دهید (در رایانه‌های اپل مکینتاش کلید‌های ⌘-Shift-R)
  • Edge: کلید Ctrl را نگه‌دارید و روی دکمهٔ Refresh کلیک کنید، یا کلید‌های Ctrl-F5 را با هم فشار دهید
// <source lang="javascript"> // // Cat-A-Lot // Changes category of multiple files (or pages) // // Originally by Magnus Manske // RegExes by Ilmari Karonen // Completely rewritten by DieBuche // // Modified to work on regular pages instead of files, + Hebrew translation: קיפודנחש // // READ THIS PAGE IF YOU WANT TO TRANSLATE OR USE THIS ON ANOTHER SITE: // http://commons.wikimedia.org/wiki/MediaWiki_talk:Gadget-Cat-a-lot.js/translating // var catALot = { 	apiUrl: mw.config.get('wgScriptPath') + "/api.php", 	searchmode: false, 	version: 2.18, 	setHeight: 450, 	init: function () { 		$("body") 		.append('<div id="cat_a_lot">' + '<div id="cat_a_lot_data"><div>' + '<input type="text" id="cat_a_lot_searchcatname" placeholder="' + this.i18n.enterName + '"/>' 		+ '</div><div id="cat_a_lot_category_list"style="white-space:nowrap;"></div>' + '<div id="cat_a_lot_mark_counter"> </div>' + '<div id="cat_a_lot_selections">' + this.i18n.select 		+ ' <a id="cat_a_lot_select_all">' + this.i18n.all + '</a> / ' + '<a id="cat_a_lot_select_none">' + this.i18n.none + '</a>' 		+ '</div></div><div id="cat_a_lot_head">' + '<a id="cat_a_lot_toggle">Cat-a-lot</a></div></div>');  		if (!this.searchmode) $('#cat_a_lot_selections').append('<br><a id="cat_a_lot_remove"><b>' + this.i18n.removeFromCat + '</b></a>'); 		$('#cat_a_lot_remove').click(function () { 			catALot.remove(); 		}); 		$('#cat_a_lot_select_all').click(function () { 			catALot.toggleAll(true); 		}); 		$('#cat_a_lot_select_none').click(function () { 			catALot.toggleAll(false); 		}); 		$('#cat_a_lot_toggle').click(function () { 			$(this).toggleClass('cat_a_lot_enabled'); 			catALot.run(); 		}); 		$('#cat_a_lot_searchcatname') 			.keypress(function (e) { 				if (e.which == 13) 					catALot.updateCats($(this).val()); 			}) 			.autocomplete({ 				source: function(request, response) { 					catALot.doAPICall({action:'opensearch', search: request.term, namespace: 14}, 						function(data){ 							if(data[1]) 								response($(data[1]).map(function(index,item){return item.replace(/.*:/, '');})); 						} 					); 				}, 				open:function(){ 					$(".ui-autocomplete") 						.position({ 							my: "left bottom", 							at: "left top", 							of: $('#cat_a_lot_searchcatname') 						}); 				} 		}); 		importStylesheet('MediaWiki:Gadget-Cat-a-lot.css'); 		this.localCatName = mw.config.get('wgFormattedNamespaces')[14]; 	}, 	findAllLabels: function () { 		this.labels = $('#mw-pages').find('li'); 		var subCats =  $('#mw-subcategories').find('.CategoryTreeItem'); 		for (var sub = 0; sub < subCats.length; sub++) { 			var a = $(subCats[sub]).find('a'); 			if (a.length) { 				a[0]['title'] = catALot.localCatName + ":" + a[0].innerHTML; 				this.labels.push(subCats[sub]); 			} 		} 		$('li a, .CategoryTreeLabel', mw.util.$content).attr({href: '#noSuchAnchor'}); 	},  	getMarkedLabels: function () { 		var marked = []; 		this.selectedLabels = this.labels.filter('.cat_a_lot_selected'); 		this.selectedLabels.each(function () { 			var file = $(this).find('a[title]'); 			marked.push([file.attr('title'), $(this)]); 		}); 		return marked; 	},  	updateSelectionCounter: function () { 		this.selectedLabels = this.labels.filter('.cat_a_lot_selected'); 		$('#cat_a_lot_mark_counter').show().html(this.selectedLabels.length + this.i18n.filesSelected ); 	},  	makeClickable: function () { 		this.findAllLabels(); 		this.labels.click(function () { 			$(this).toggleClass('cat_a_lot_selected'); 			catALot.updateSelectionCounter(); 		}); 	},  	toggleAll: function (select) { 		this.labels.toggleClass('cat_a_lot_selected', select); 		this.updateSelectionCounter(); 	},  	getSubCats: function (cmcontinue) { 		var data = { 			action: 'query', 			list: 'categorymembers', 			cmnamespace: 14, 			cmlimit: 50, 			cmtitle: this.localCatName + ':' + this.currentCategory 		}; 		if (cmcontinue) 			data.cmcontinue = cmcontinue; 		else 			this.subCats = [];  		this.doAPICall(data, function (result) {  			var cats = result.query.categorymembers;  			for (var i = 0; i < cats.length; i++) { 				catALot.subCats.push(cats[i].title.replace(/^[^:]+:/, "")); 			} 			if (result['query-continue']) 				catALot.getSubCats(result['query-continue'].categorymembers.cmcontinue); 			else { 				catALot.catCounter++; 				if (catALot.catCounter == 2) catALot.showCategoryList(); 			} 		}); 	},   	getParentCats: function () { 		var data = { 			action: 'query', 			prop: 'categories', 			cllimit: 500, 			titles: this.localCatName + ':' + this.currentCategory 		}; 		this.doAPICall(data, function (result) { 			catALot.parentCats = []; 			var pages = result.query ? result.query.pages : []; 			if (pages[-1] && pages[-1].missing == '') { 				catALot.catlist.html('<span id="cat_a_lot_no_found">' + catALot.i18n.catNotFound + '</span>'); 				document.body.style.cursor = 'auto';  				catALot.catlist.append('<ul></ul>'); 				catALot.createCatLinks("→", [catALot.currentCategory]); 				return; 			} 			// there should be only one, but we don't know its ID 			for (var id in pages) { 				var cats = pages[id].categories; 			} 			if (cats !== undefined) { 				for (var i = 0; i < cats.length; i++) { 					catALot.parentCats.push(cats[i].title.replace(/^[^:]+:/, "")); 				} 			}  			catALot.catCounter++; 			if (catALot.catCounter == 2) catALot.showCategoryList(); 		}); 	}, 	regexBuilder: function (category) { 		var catname = ( this.localCatName == 'Category' ) ? this.localCatName: this.localCatName + '|Category'; 		catname = '(' + catname + ')';  		// Build a regexp string for matching the given category: 		// trim leading/trailing whitespace and underscores 		category = category.replace(/^[\s_]+/, "").replace(/[\s_]+$/, "");  		// escape regexp metacharacters (= any ASCII punctuation except _) 		category = category.replace(/([!-\/:-@\[-^`{-~])/g, '\\$1');  		// any sequence of spaces and underscores should match any other 		category = category.replace(/[\s_]+/g, '[\\s_]+');  		// Make the first character case-insensitive: 		var first = category.substr(0, 1); 		if (first.toUpperCase() != first.toLowerCase()) category = '[' + first.toUpperCase() + first.toLowerCase() + ']' + category.substr(1);  		// Compile it into a RegExp that matches MediaWiki category syntax (yeah, it looks ugly): 		// XXX: the first capturing parens are assumed to match the sortkey, if present, including the | but excluding the ]] 		return new RegExp('\\[\\[[\\s_]*' + catname + '[\\s_]*:[\\s_]*' + category + '[\\s_]*(\\|[^\\]]*(?:\\][^\\]]+)*)?\\]\\]', 'ig'); 	},  	getContent: function (file, targetcat, mode) {  		var data = { 			action: 'query', 			prop: 'info|revisions', 			rvprop: 'content|timestamp', 			intoken: 'edit', 			titles: file[0] 		};  		this.doAPICall(data, function (result) { 			catALot.editCategories(result, file, targetcat, mode); 		}); 	},  	editCategories: function (result, file, targetcat, mode) {  		if (result == null) { 			//Happens on unstable wifi connections.. 			this.connectionError.push(file[0]); 			this.updateCounter(); 			return; 		} 		var pages = result.query ? result.query.pages : [];  		// there should be only one, but we don't know its ID 		for (var id in pages) { 			// The edittoken only changes between logins 			this.edittoken = pages[id].edittoken; 			var otext = pages[id].revisions[0]['*']; 			var starttimestamp = pages[id].starttimestamp; 			var timestamp = pages[id].revisions[0]['timestamp']; 		}   		var sourcecat = mw.config.get('wgTitle');  		// Check if that file is already in that category 		if (mode != "remove" && this.regexBuilder(targetcat).test(otext)) { 			//If the new cat is already there, just remove the old one. 			if (mode == 'move') { 				mode='remove'; 			} else { 				this.alreadyThere.push(file[0]); 				this.updateCounter(); 				return; 			} 		}  		var text = otext; 		var comment;  		// Fix text 		switch (mode) { 		case 'add': 			text += "\n[[" + this.localCatName + ":" + targetcat.replace("رده:","") + "]]\n";                         text=text.replace("رده:رده:","رده:"); 			comment = this.i18n.summaryAdd + targetcat.replace("رده:","") + "]]"; 			break; 		case 'copy': 			text = text.replace(this.regexBuilder(sourcecat), "[[" + this.localCatName + ":" + sourcecat + "$2]]\n[[" + this.localCatName + ":" + targetcat.replace("رده:","") + "$2]]");                         text=text.replace("رده:رده:","رده:"); 			comment = this.i18n.summaryCopy + sourcecat + "]] " + this.i18n.to + targetcat.replace("رده:","") + "]]"; 			break; 		case 'move': 			text = text.replace(this.regexBuilder(sourcecat), "[[" + this.localCatName + ":" + targetcat.replace("رده:","") + "$2]]");                         text=text.replace("رده:رده:","رده:"); 			comment = this.i18n.summaryMove + sourcecat + "]] " + this.i18n.to + targetcat.replace("رده:","") + "]]"; 			break; 		case 'remove': 			text = text.replace(this.regexBuilder(sourcecat), "");                         text=text.replace("رده:رده:","رده:"); 			comment = this.i18n.summaryRemove + sourcecat + "]]"; 			break; 		}  		if (text == otext) { 			this.notFound.push(file[0]); 			this.updateCounter(); 			return; 		}  		var data = { 			action: 'edit', 			summary: comment, 			title: file[0], 			token: this.edittoken, 			starttimestamp: starttimestamp, 			basetimestamp: timestamp, 			text: text 		};  		var isBot=$.inArray('bot', mw.config.get('wgUserGroups'))>-1; 		if(isBot) 			data.bot = '1';  		this.doAPICall(data, function (ret) { 			catALot.updateCounter(); 		}); 		this.markAsDone(file[1], mode, targetcat); 	}, 	markAsDone: function (label, mode, targetcat) {  		label.addClass('cat_a_lot_markAsDone'); 		switch (mode) { 		case 'add': 			label.append('<br>' + this.i18n.addedCat + ' ' + targetcat); 			break; 		case 'copy': 			label.append('<br>' + this.i18n.copiedCat + ' ' + targetcat); 			break; 		case 'move': 			label.append('<br>' + this.i18n.movedCat + ' ' + targetcat); 			break; 		case 'remove': 			label.append('<br>' + this.i18n.movedCat ); 			break; 		} 	}, 	updateCounter: function () {  		this.counterCurrent++; 		if (this.counterCurrent > this.counterNeeded) this.displayResult(); 		else this.domCounter.text(this.counterCurrent); 	},  	displayResult: function () {  		document.body.style.cursor = 'auto'; 		$('.cat_a_lot_feedback').addClass('cat_a_lot_done'); 		$('.ui-dialog-content').height('auto'); 		var rep = this.domCounter.parent(); 		rep.html('<h3>' + this.i18n.done + '</h3>'); 		rep.append( this.i18n.allDone + '<br />');  		var close = $('<a>').append( this.i18n.returnToPage ); 		close.click(function () { 			catALot.progressDialog.remove(); 			catALot.toggleAll(false); 		}); 		rep.append(close); 		if (this.alreadyThere.length) { 			rep.append( this.i18n.skippedAlready ); 			rep.append(this.alreadyThere.join('<br>')); 		} 		if (this.notFound.length) { 			rep.append( this.i18n.skippedNotFound ); 			rep.append(this.notFound.join('<br>')); 		} 		if (this.connectionError.length) { 			rep.append( this.i18n.skippedServer ); 			rep.append(this.connectionError.join('<br>')); 		}  	},  	moveHere: function (targetcat) { 		this.doSomething(targetcat, 'move'); 	},  	copyHere: function (targetcat) { 		this.doSomething(targetcat, 'copy'); 	},  	addHere: function (targetcat) { 		this.doSomething(targetcat, 'add'); 	},  	remove: function () { 		this.doSomething('', 'remove'); 	},  	doSomething: function (targetcat, mode) { 		var files = this.getMarkedLabels(); 		if (files.length == 0) { 			alert( this.i18n.noneSelected ); 			return; 		} 		this.notFound = []; 		this.alreadyThere = []; 		this.connectionError = []; 		this.counterCurrent = 1; 		this.counterNeeded = files.length; 		this.showProgress(); 		for (var i = 0; i < files.length; i++) { 			this.getContent(files[i], targetcat, mode); 		} 	},  	doAPICall: function (params, callback) {  		params.format = 'json'; 		$.ajax({ 			url: this.apiUrl, 			cache: false, 			dataType: 'json', 			data: params, 			type: 'POST', 			success: callback 		}); 	},  	createCatLinks: function (symbol, list) { 		list.sort(); 		var domlist = this.catlist.find('ul'); 		for (var i = 0; i < list.length; i++) { 			var li = $('<li></li>');  			var link = $('<a></a>'); 			link.text(list[i]); 			li.data('cat', list[i]); 			link.click(function () { 				catALot.updateCats($(this).parent().data('cat')); 			});  			if (this.searchmode) { 				var add = $('<a class="cat_a_lot_action"><b>' + this.i18n.add + '</b></a>'); 				add.click(function () { 					catALot.addHere($(this).parent().data('cat')); 				}); 			} else { 				var move = $('<a class="cat_a_lot_move"><b>' + this.i18n.move + '</b></a>'); 				move.click(function () { 					catALot.moveHere($(this).parent().data('cat')); 				});  				var copy = $('<a class="cat_a_lot_action"><b>' + this.i18n.copy + '</b></a>'); 				copy.click(function () { 					catALot.copyHere($(this).parent().data('cat')); 				}); 			}  			// Can't move to source category 			if (list[i] != mw.config.get('wgTitle') && this.searchmode) li.append(' ').append(add); 			else if (list[i] != mw.config.get('wgTitle') && !this.searchmode) li.append(' ').append(move).append(' ').append(copy); 			li.append(symbol).append(' ').append(link);  			domlist.append(li); 		} 	},  	getCategoryList: function () { 		this.catCounter = 0; 		this.getParentCats(); 		this.getSubCats(); 	},  	showCategoryList: function () { 		var thiscat = [this.currentCategory];  		this.catlist.empty(); 		this.catlist.append('<ul></ul>');  		this.createCatLinks("↑", this.parentCats); 		this.createCatLinks("→", thiscat); 		this.createCatLinks("↓", this.subCats);  		document.body.style.cursor = 'auto'; 		//Reset width 		var cat = $('#cat_a_lot'); 		cat.width(''); 		cat.height(''); 		cat.width( cat.width() * 1.05 ); 		var list = $('#cat_a_lot_category_list'); 		list.css({maxHeight: this.setHeight+'px', height: ''}); 	},  	updateCats: function (newcat) { 		document.body.style.cursor = 'wait';  		this.currentCategory = newcat; 		this.catlist = $('#cat_a_lot_category_list'); 		this.catlist.html('<div class="cat_a_lot_loading">' + this.i18n.loading + '</div>'); 		this.getCategoryList(); 	}, 	showProgress: function () { 		document.body.style.cursor = 'wait';  		this.progressDialog = $('<div></div>') 		.html( this.i18n.editing + ' <span id="cat_a_lot_current">' + this.counterCurrent + '</span> ' + this.i18n.of + this.counterNeeded) 		.dialog({ 			width: 450, 			height: 90, 			minHeight: 90, 			modal: true, 			resizable: false, 			draggable: false, 			closeOnEscape: false, 			dialogClass: "cat_a_lot_feedback" 		}); 		$('.ui-dialog-titlebar').hide(); 		this.domCounter = $('#cat_a_lot_current');  	},  	run: function () { 		if ($('.cat_a_lot_enabled').length) { 			this.makeClickable(); 			$("#cat_a_lot_data").show(); 			$('#cat_a_lot').resizable({ 				handles: 'n',  				alsoResize: '#cat_a_lot_category_list', 				resize: function(event, ui) { 					$(this).css({left:"", top:""}); 					catALot.setHeight = $(this).height(); 					$('#cat_a_lot_category_list').css({maxHeight: '', width: ''}); 				}  			}); 			$('#cat_a_lot_category_list').css({maxHeight: '450px'}); 			if (this.searchmode) this.updateCats("Pictures and images"); 			else this.updateCats(mw.config.get('wgTitle'));  		} else { 			$("#cat_a_lot_data").hide(); 			$("#cat_a_lot").resizable( "destroy" ); 			//Unbind click handlers 			this.labels.off('click'); 		} 	}, 	i18n: (mw.config.get('wgUserLanguage' == "fa") ? {                 loading: 'بارگیری...', 		editing: 'ویرایش صفحه', 		of: ' ', 		skippedAlready: '<h5>صفحهٔ انتخاب شده رها شد، چون صفحه در همان رده قرار دارد.:</h5>', 		skippedNotFound: '<h5>صفحهٔ انتخاب شده رها شد چون رده قدیمی پیدا نشد!:</h5>', 		skippedServer: '<h5>صفحه‌های انتخاب شده را نمی‌توان تغییر داد چون ارتباط با سرور فعلا برقرار نیست:</h5>', 		allDone: 'درخواست برای تمام صفحه‌ها انجام شدند.', 		done: 'انجام شد!', 		addedCat: 'افزودن رده', 		copiedCat: 'کپی به ردهٔ', 		movedCat: 'انتقال به ردهٔ', 		removedCat: 'حذف از ردهٔ', 		returnToPage: 'بازگشت به صفحه', 		catNotFound: 'رده یافت نشد.',   		//as in 17 files selected 		filesSelected: ' صفحه انتخاب شده.',  		//Actions 		copy: 'کپی', 		move: 'انتقال', 		add: 'افزودن', 		removeFromCat: 'حذف از رده', 		enterName: 'نام رده مورد نظر را بنویسید', 		select: 'انتخاب', 		all: 'همه', 		none: 'هیچکدام',  		noneSelected: 'صفحه‌ای انتخاب نشده‌است!',  		//Summaries: 		summaryAdd: '[[:w:fa:وپ:رده انبوه|رده‌انبوه]]: افزودن [[رده:', 		summaryCopy: '[[:w:fa:وپ:رده انبوه|رده‌انبوه]]: کپی از [[رده:', 		to: 'به [[رده:', 		summaryMove: '[[:w:fa:وپ:رده انبوه|رده‌انبوه]]: انتقال از [[رده:', 		summaryRemove: '[[:w:fa:وپ:رده انبوه|رده‌انبوه]]: حذف از [[رده:' 	}:	{ 		//Progress 		loading: 'Loading...', 		editing: 'Editing page', 		of: 'of ', 		skippedAlready: '<h5>The following pages were skipped, because the page was already in the category:</h5>', 		skippedNotFound: '<h5>The following pages were skipped, because the old category could not be found:</h5>', 		skippedServer: '<h5>The following pages couldn\'t be changed, since there were problems connecting to the server:</h5>', 		allDone: 'All pages are processed.', 		done: 'Done!', 		addedCat: 'Added category', 		copiedCat: 'Copied to category', 		movedCat: 'Moved to category', 		removedCat: 'Removed from category', 		returnToPage: 'Return to page', 		catNotFound: 'Category not found.',   		//as in 17 files selected 		filesSelected: ' files selected.',  		//Actions 		copy: 'Copy', 		move: 'Move', 		add: 'Add', 		removeFromCat: 'Remove from this category', 		enterName: 'Enter category name', 		select: 'Select', 		all: 'all', 		none: 'none',  		noneSelected: 'No files selected!',  		//Summaries: 		summaryAdd: 'Cat-a-lot: Adding [[Category:', 		summaryCopy: 'Cat-a-lot: Copying from [[Category:', 		to: 'to [[Category:', 		summaryMove: 'Cat-a-lot: Moving from [[Category:', 		summaryRemove: 'Cat-a-lot: Removing from [[Category:' 	} };   if ((mw.config.get('wgNamespaceNumber') == -1 && mw.config.get('wgCanonicalSpecialPageName') == "Search") || mw.config.get('wgNamespaceNumber') == 14) { 	if ( mw.config.get('wgNamespaceNumber') == -1 ) catALot.searchmode = true; 	mediaWiki.loader.using(['jquery.ui'], function () { 		$(function () { 			catALot.init(); 		}); 	}); }  // </source>