User:جواد/vector.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
The accompanying .css page for this skin is at User:جواد/vector.css. |
// <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 = new Array();
var pages = 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;
}
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.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("Category:","") + "]]\n";
text=text.replace("Category:Category:","Category:");
comment = this.i18n.summaryAdd + targetcat.replace("Category:","") + "]]";
break;
case 'copy':
text = text.replace(this.regexBuilder(sourcecat), "[[" + this.localCatName + ":" + sourcecat + "$2]]\n[[" + this.localCatName + ":" + targetcat.replace("Category:","") + "$2]]");
text=text.replace("Category:Category:","Category:");
comment = this.i18n.summaryCopy + sourcecat + "]] " + this.i18n.to + targetcat.replace("Category:","") + "]]";
break;
case 'move':
text = text.replace(this.regexBuilder(sourcecat), "[[" + this.localCatName + ":" + targetcat.replace("Category:","") + "$2]]");
text=text.replace("Category:Category:","Category:");
comment = this.i18n.summaryMove + sourcecat + "]] " + this.i18n.to + targetcat.replace("Category:","") + "]]";
break;
case 'remove':
text = text.replace(this.regexBuilder(sourcecat), "");
text=text.replace("Category:Category:","Category:");
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.unbind('click');
}
},
i18n: (mw.config.get('wgUserLanguage') == "fa") ? {
loading: 'بارگیری...',
editing: 'ویرایش صفحه',
of: ' ',
skippedAlready: '<h5>صفحهٔ انتخاب شده رها شد، چون صفحه در همان Category قرار دارد.:</h5>',
skippedNotFound: '<h5>صفحهٔ انتخاب شده رها شد چون Category قدیمی پیدا نشد!:</h5>',
skippedServer: '<h5>صفحههای انتخاب شده را نمیتوان تغییر داد چون ارتباط با سرور فعلا برقرار نیست:</h5>',
allDone: 'درخواست برای تمام صفحهها انجام شدند.',
done: 'انجام شد!',
addedCat: 'افزودن Category',
copiedCat: 'کپی به ردهٔ',
movedCat: 'انتقال به ردهٔ',
removedCat: 'حذف از ردهٔ',
returnToPage: 'بازگشت به صفحه',
catNotFound: 'Category یافت نشد.',
//as in 17 files selected
filesSelected: ' صفحه انتخاب شده.',
//Actions
copy: 'کپی',
move: 'انتقال',
add: 'افزودن',
removeFromCat: 'حذف از Category',
enterName: 'نام Category مورد نظر را بنویسید',
select: 'انتخاب',
all: 'همه',
none: 'هیچکدام',
noneSelected: 'صفحهای انتخاب نشدهاست!',
//Summaries:
summaryAdd: '[[وپ:Category انبوه|Categoryانبوه]]: افزودن [[Category:',
summaryCopy: '[[وپ:Category انبوه|Categoryانبوه]]: کپی از [[Category:',
to: 'به [[Category:',
summaryMove: '[[وپ:Category انبوه|Categoryانبوه]]: انتقال از [[Category:',
summaryRemove: '[[وپ:Category انبوه|Categoryانبوه]]: حذف از [[Category:'
}: {
//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>