Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
!function (cfg) {
var urlVars = new URLSearchParams(location.search),
mwc = mw.config.get(['wgIsArticle', 'wgCategories', 'wgScript', 'wgScriptPath', 'wgPageName', 'wgFormattedNamespaces', 'wgUserLanguage']);
if (!mwc.wgIsArticle || (mwc.wgCategories && mwc.wgCategories.length === 0)) return;
var $cats = $('#articleCategories'),
msgs = {
cqrARemove: '<cqr-ask-remove>',
cqrARemoveTitle: '<cqr-ask-remove-title>',
cqrSuccess: '<cqr-success>',
cqrNochange: '<cqr-nochange>',
cqrFailRead: '<cqr-fail-read>',
cqrFailWrite: '<cqr-fail-write>',
cqrRemoveSummary: '<cqr-category-removed-summary>',
},
$x = $('<span>', {
class: 'cqr-x',
text:'x',
href: 'cqr-x',
});
function log() {
if (!cfg.debug) return;
var a = [].slice.call(arguments);
a.unshift('cqr');
return console.log.apply(this, a);
}// log
function cook(text) {
// capitalize and despacelize text
if (!text) return '';
var escapeRegex = mw.RegExp.escape || mw.util.escapeRegExp;
return '[' + text.slice(0, 1).toUpperCase() + text.slice(0, 1).toLowerCase() + ']' + escapeRegex(text.slice(1)).replace(/[ _]/g, '[ _]');
}// cook
function getPage(pagename) {
// get page content helper
// not cached in order to minimize edit conflicts
return $.get(mwc.wgScript, {action: 'raw', title: pagename});
}// getData
function savePage(pagename, content) {
// save page content helper
return $.post(mwc.wgScriptPath + '/api.php', {
action: 'edit',
title: pagename,
text: content,
watchlist: 'nochange',
summary: msgs.cqrRemoveSummary,
minor: 'true',
format: 'json',
token: mw.user.tokens.get('csrfToken')
});
}// savePage
function removeCat(cat) {
// remove the cat. returns promise {status, data}
// status: 0=ok, 1=zero replacements, 2=getpage fail, 3=savepage fail
// data by status: 0: new data; 1: old data; 2/3: fail response
var def = $.Deferred();
getPage(mwc.wgPageName)
.done(function(data) {
var re = new RegExp('\\[\\[([Cc]ategory|' + cook(mwc.wgFormattedNamespaces[14]) + '):' + cook(cat) + '(\\|.*?)?' + '\\]\\]', 'g'),
dataNew = data.replace(re, '');
if (data === dataNew) {
log('rc no replacements was made', re, data);
def.reject({status: 1, data: data});
return this;
}
log('rc dump', re, '\n', data, '\n', dataNew);
savePage(mwc.wgPageName, dataNew)
.done(function(data) {
log('rc save done', this, data);
if (!data || data.error) {
data.error = data.error || {};
def.reject({
status: 3,
data: (data.error.code || '') + ' ' + (data.error.info || '') +
((data.error.code && data.error.info) ? '' : (' ' + data))
});
} else {
def.resolve({status: 0, data: dataNew});
}
})// savePage done
.fail(function(data) {
log('rc save fail', data);
def.reject({status: 3, data: data});
});// savePage
return this;
})// getPage done
.fail(function(data) {
log('rc fail', data);
def.reject({status: 2, data: data});
return this;
});// getPage
return def.promise();
}// removeCat
function try2removeCat($container, cat) {
// remove dispatcher
// $container: parent li of the cat; cat: cat
log('t2r', $container, cat);
// we don't need x anymore:
// if success, then nothing to x; if fail, then cat can't be x'ed
$container.find('.cqr-x').remove();
removeCat(cat)
.done(function(d) {
// hide removed cat. not remove, because of reasons
$container.hide();
report(msgs.cqrSuccess, 'confirm');
})
.fail(function(d) {
switch (d.status) {
case 1:
report(msgs.cqrNochange, 'notify');
break;
case 2:
report(msgs.cqrFailRead + '<br>' + d.data, 'warn');
break;
case 3:
report(msgs.cqrFailWrite + '<br>' + d.data, 'warn');
break;
}
});
}// try2removeCat
function report(content, type) {
// report result helper
mw.notify(content, {
autoHideSeconds: 10,
type: type
});
}// report
function ask($container, cat) {
// ask to del the cat. returns promise
// resolve on lmb; reject on anykey (theoretically) or timer
// $container: parent li of the cat; [cat]: cat
var def = $.Deferred(),
$ask = $('<span>', {
class: 'cqr-ask button',
text: msgs.cqrARemove,
title: msgs.cqrARemoveTitle,
}),
timer = setTimeout(function() {
$ask.remove();
def.reject();
}, 10000);
$ask.click(function(e) {
e.preventDefault();
clearTimeout(timer);
$ask.remove();
if (e.which === 1) {
def.resolve();
} else {
def.reject();
}
return !1;
});
// clean up. orphans will be invalidated automatically
$('.cqr-ask').remove();
$ask.width($container.width());
$container.prepend($ask);
return def.promise();
}// ask
function i18nLoad() {
if (cfg.i18nloaded || mwc.wgUserLanguage === 'qqx') return;
cfg.i18nloaded = !0;
mw.hook('dev.i18nbeta').add(function(i18n) {
i18n.loadMessages('CategoryQuickRemove').done(function(i18n) {
msgs.cqrARemove = i18n.msg('cqr-ask-remove')
.lazyUpdate($('.cqr-ask').toArray(), {
type: 'fn',
name: 'text'
})
.plain();
msgs.cqrARemoveTitle = i18n.msg('cqr-ask-remove-title')
.lazyUpdate($('.cqr-ask').toArray(), {
type: 'attr',
name: 'title'
})
.plain();
msgs.cqrSuccess = i18n.msg('cqr-success').plain();
msgs.cqrNochange = i18n.msg('cqr-nochange').plain();
msgs.cqrFailRead = i18n.msg('cqr-fail-read').plain();
msgs.cqrFailWrite = i18n.msg('cqr-fail-write').plain();
msgs.cqrRemoveSummary = i18n.inContentLang().msg('cqr-category-removed-summary').plain();
});
});
if (!window.dev || !window.dev.i18nbeta) importArticle({type: 'script', article: 'u:dev:MediaWiki:I18n-js/beta.js'});
}// i18nLoad
cfg.debug = cfg.debug || urlVars.get('debug') || urlVars.get('debug1');
// unexpected behavior in the debug mode is expected and totally by design
cfg.loaded = cfg.debug ? false : cfg.loaded;
if (cfg.loaded || !$cats.length) return;
cfg.loaded = !0;
$('.cqr-x').remove();
$cats.find('li:not(.tool):not(.last)').append($x.clone());
$cats.find('.cqr-x').click(function(e) {
var $this = $(this),
$container = $this.closest('li'),
cat = $container.find('a:first').text();
log('cat', cat);
i18nLoad();
ask($container, cat).done(try2removeCat.bind(this, $container, cat));
return !1;
});
cfg.exports = {
log: log,
cook: cook,
getPage: getPage,
savePage: savePage,
removeCat: removeCat,
try2removeCat: try2removeCat,
report: report,
ask: ask,
i18nLoad: i18nLoad,
};
importArticle({type: 'style', article: 'u:dev:MediaWiki:CategoryQuickRemove.css'});
mw.loader.using('mediawiki.util');
}((window.fng = window.fng || {}).cqr = window.fng.cqr || {});