מדיה ויקי:Gadget-Cat-a-lot.js
מתוך ויקירפואה
גרסה מ־04:09, 20 באוגוסט 2013 מאת ערן רוזנטל (שיחה | תרומות) (גרסה אחת: יבוא מויקיפדיה. http://he.wikipedia.org/w/index.php?title=%D7%9E%D7%93%D7%99%D7%94_%D7%95%D7%99%D7%A7%D7%99:Gadget-Cat-a-lot.js&action=history)
הערה: לאחר השמירה, ייתכן שיהיה צורך לנקות את זיכרון המטמון (cache) של הדפדפן כדי להבחין בשינויים.
- פיירפוקס / ספארי: להחזיק את המקש Shift בעת לחיצה על טעינה מחדש (Reload), או ללחוץ על צירוף המקשים Ctrl-F5 או Ctrl-R (במחשב מק: ⌘-R).
- גוגל כרום: ללחוץ על צירוף המקשים Ctrl-Shift-R (במחשב מק: ⌘-Shift-R).
- אינטרנט אקספלורר: להחזיק את המקש Ctrl בעת לחיצה על רענן (Refresh), או ללחוץ על צירוף המקשים Ctrl-F5.
- אופרה: לפתוח תפריט ← הגדרות (במחשב מק: Opera ← העדפות) ואז ללחוץ על פרטיות ואבטחה ← מחק היסטוריית גלישה ← Cached images and files.
// <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: 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 = 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 + "]]\n"; comment = this.i18n.summaryAdd + targetcat + "]]"; break; case 'copy': text = text.replace(this.regexBuilder(sourcecat), "[[" + this.localCatName + ":" + sourcecat + "$2]]\n[[" + this.localCatName + ":" + targetcat + "$2]]"); comment = this.i18n.summaryCopy + sourcecat + "]] " + this.i18n.to + targetcat + "]]"; break; case 'move': text = text.replace(this.regexBuilder(sourcecat), "[[" + this.localCatName + ":" + targetcat + "$2]]"); comment = this.i18n.summaryMove + sourcecat + "]] " + this.i18n.to + targetcat + "]]"; break; case 'remove': text = text.replace(this.regexBuilder(sourcecat), ""); 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', 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] != wgTitle && this.searchmode) li.append(' ').append(add); else if (list[i] != 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(wgTitle); } else { $("#cat_a_lot_data").hide(); $("#cat_a_lot").resizable( "destroy" ); //Unbind click handlers this.labels.unbind('click'); } }, i18n: (wgUserLanguage == "he") ? { //Progress loading: 'טוען...', editing: 'עורך דף', of: 'מתוך ', skippedAlready: '<h5>הדפים להלן לא שונו, משום שכבר הכילו את הקטגוריה:</h5>', skippedNotFound: '<h5>הדפים להלן לא שונו, משום שהקטגוריה לא נמצאה:</h5>', skippedServer: '<h5>Tהדפים להלן לא שונו, בגלל בעית תקשורת/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: 'Cat-a-lot: הוסיף ל[[קטגוריה:', summaryCopy: 'Cat-a-lot: העתיק מ[[קטגוריה:', to: 'ל[[קטגוריה:', summaryMove: 'Cat-a-lot: העביר מ[[קטגוריה:', summaryRemove: 'Cat-a-lot: הסיר מ[[קטגוריה:' }: { //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 ((wgNamespaceNumber == -1 && wgCanonicalSpecialPageName == "Search") || wgNamespaceNumber == 14) { if ( wgNamespaceNumber == -1 ) catALot.searchmode = true; mediaWiki.loader.using(['jquery.ui.dialog', 'jquery.ui.autocomplete'], function () { $(function () { catALot.init(); }); }); } // </source>