(() => {
const branding = 'using [[User:Sohom_Datta/PageTriageUserspaceLogger|PTUL]]';
function normalizeParams( params ) {
const keys = Object.keys(params);
let np = {};
for(let i =0; i < keys.length; i++) {
np[ keys[ i ] ] = params[ keys[ i ] ]['value'];
}
return np;
}
// https://github.com/wikimedia-gadgets/twinkle/blob/e6e05d914f8d226dcb670e81677e5530cae84175/modules/twinklespeedy.js#L1519-L1536
function formatCSDParamForLog(normalize, csdparam, input) {
if ((normalize === 'G4' && csdparam === 'xfd') ||
(normalize === 'G6' && csdparam === 'page') ||
(normalize === 'G6' && csdparam === 'fullvotepage') ||
(normalize === 'G6' && csdparam === 'sourcepage') ||
(normalize === 'A2' && csdparam === 'source') ||
(normalize === 'A10' && csdparam === 'article') ||
(normalize === 'F1' && csdparam === 'filename')) {
input = '[[:' + input + ']]';
} else if (normalize === 'G5' && csdparam === 'user') {
input = '[[:User:' + input + ']]';
} else if (normalize === 'G12' && csdparam.lastIndexOf('url', 0) === 0 && input.lastIndexOf('http', 0) === 0) {
input = '[' + input + ' ' + input + ']';
} else if (normalize === 'F8' && csdparam === 'filename') {
input = '[[commons:' + input + ']]';
}
return ' {' + normalize + ' ' + csdparam + ': ' + input + '}';
}
function serializeParams(code, params) {
let additionInfoString = '';
for ( const [key, val] of Object.entries(params) ) {
additionInfoString += formatCSDParamForLog(code, key, val);
}
return additionInfoString;
}
function serializeCSDTags( csd ) {
if ( csd.length === 1 ) {
const c = csd[0];
let titleText = `[[:${c.title}]]`;
if (c.code === 'G10') {
titleText = `[[:${c.title}|Nominated this attack page]]`;
}
return `# ${titleText}: [[WP:CSD#${c.code}|CSD ${c.code}]] ({{tl|${c.tag}}}); ${serializeParams(c.code, c.params)} {{small|via [[mw:Extension:PageTriage|PageTriage]]}} ~~${'~'}~~`;
}
let titleText = `[[:${csd[0].title}]]`;
if (isAttack(csd)) {
titleText = `[[:${csd[0].title}|Nominated this attack page]]`;
}
let csdText = '';
for(let i = 0; i < csd.length; i++) {
csdText += `[[WP:CSD#${csd[i].code}|CSD ${csd[i].code}]] `;
}
let additionInfoString = '';
for(let i = 0; i < csd.length; i++) {
additionInfoString += ` ${serializeParams(csd[i].code, csd[i].params)}`;
}
return `# ${titleText}: ${csdText} ({{tl|db-multiple}}); ${additionInfoString} {{small|via [[mw:Extension:PageTriage|PageTriage]]}} ~~${'~'}~~`;
}
function serializeXFDTags( xfd ) {
if ( xfd.length > 1 ) {
console.error('More than one AFD tag encountered, this is not normal, something is wrong');
throw new Error('too-many-afd-tags');
}
const a = xfd[0];
const venueText = a.venue === 'RfD' ? `at [[WP:${a.venue}|${a.venue}]]` : `[[Wikipedia:Articles for deletion/${a.title}|nominated]] at [[WP:${a.venue}|${a.venue}]]`;
return `# [[:${a.title}]]: ${venueText}; notified {{user|${a.creator}}} {{small|via [[mw:Extension:PageTriage|PageTriage]]}} ~~${'~'}~~` +
`\n#* '''Reason''': ${a.params['1']}`;
}
function serializePRODTags( prod ) {
if ( prod.length > 1 ) {
console.error('More than one prod tag, this is not normal something has gone wrong');
throw new Error('too-many-prod-tags');
}
const p = prod[0];
return `# [[:${p.title}]] ([{{fullurl:Special:Log|page=${p.title}}} log]): ${p.blp ? 'BLP PROD' : 'PROD'} notified {{user|${p.creator}}} {{small|via [[mw:Extension:PageTriage|PageTriage]]}} at ~~${'~'}~~` +
(p.blp ? '' : `\n#* '''Reason''': ${p.params['1']}` );
}
function getVenue( xfd ) {
return (xfd[0] && xfd[0].venue) || 'NOT A VENUE';
}
function isAttack(csd) {
for(let i = 0; i < csd.length; i++) {
if ( csd[i].code === 'G10' ) return true;
}
return false;
}
function isBlp(prod) {
return prod[0].blp;
}
function canLogCSD(csd) {
let canLog = Twinkle.getPref('logSpeedyNominations');
let shouldLog = false;
for(let i = 0; i < csd.length; i++) {
if ( Twinkle.getPref('noLogOnSpeedyNomination').indexOf(csd[i].code.toLowerCase()) !== -1 ) {
shouldLog = shouldLog || false;
} else {
shouldLog = shouldLog || true;
}
}
return canLog && shouldLog;
}
function processLogActions( logActions, title ) {
let allLoggingActions = [];
const allowCSDLogging = canLogCSD(logActions.csd);
if ( logActions.csd.length > 0 && allowCSDLogging) {
const logText = serializeCSDTags(logActions.csd);
const attack = isAttack(logActions.csd);
const usl = new Morebits.userspaceLogger(Twinkle.getPref('speedyLogPageName'));
usl.initialText =
"This is a log of all [[WP:CSD|speedy deletion]] nominations made by this user using [[WP:TW|Twinkle]]'s CSD module.\n\n" +
'If you no longer wish to keep this log, you can turn it off using the [[Wikipedia:Twinkle/Preferences|preferences panel]], and ' +
'nominate this page for speedy deletion under [[WP:CSD#U1|CSD U1]].' +
(Morebits.userIsSysop ? '\n\nThis log does not track outright speedy deletions made using Twinkle.' : '');
const editSummary = `Logging speedy deletion nomination of ${ attack ? `a attack page`: `[[:${title}]]` } ${branding}`;
allLoggingActions.push( usl.log(logText, editSummary) );
}
const allowXfdLogging = !(!Twinkle.getPref('logXfdNominations') || Twinkle.getPref('noLogOnXfdNomination').indexOf(getVenue(logActions.xfd)) !== -1);
if ( logActions.xfd.length > 0 && allowXfdLogging) {
const logText = serializeXFDTags(logActions.xfd);
const usl = new Morebits.userspaceLogger(Twinkle.getPref('xfdLogPageName'));
const venue = getVenue(logActions.xfd);
const subPageText = venue === 'RfD' ? '' : ` at [[Wikipedia:Articles for deletion/${title}]]`;
usl.initialText =
"This is a log of all [[WP:XFD|deletion discussion]] nominations made by this user using [[WP:TW|Twinkle]]'s XfD module.\n\n" +
'If you no longer wish to keep this log, you can turn it off using the [[Wikipedia:Twinkle/Preferences|preferences panel]], and ' +
'nominate this page for speedy deletion under [[WP:CSD#U1|CSD U1]].' +
(Morebits.userIsSysop ? '\n\nThis log does not track XfD-related deletions made using Twinkle.' : '');
allLoggingActions.push( usl.log(logText, `Logging [[WP:${venue}|${venue}]] nomination of [[:${title}]]${subPageText} ${branding}`) );
}
const allowProdLogging = Twinkle.getPref('logProdPages');
if (logActions.prod.length > 0 && allowProdLogging) {
const logText = serializePRODTags(logActions.prod);
const usl = new Morebits.userspaceLogger(Twinkle.getPref('prodLogPageName'));
const blp = isBlp(logActions.prod);
usl.initialText =
"This is a log of all [[WP:PROD|proposed deletion]] tags applied or endorsed by this user using [[WP:TW|Twinkle]]'s PROD module.\n\n" +
'If you no longer wish to keep this log, you can turn it off using the [[Wikipedia:Twinkle/Preferences|preferences panel]], and ' +
'nominate this page for speedy deletion under [[WP:CSD#U1|CSD U1]].';
allLoggingActions.push( usl.log( logText, `Logging ${blp ? 'BLP PROD' : 'PROD'} nomation for [[:${title}]] ${branding}` ) );
}
return $.when.apply($, allLoggingActions );
}
mw.loader.using( [ 'ext.gadget.Twinkle' ] ).then( function () {
mw.hook( 'ext.pageTriage.toolbar.ready' ).add( function ( queue ) {
if ( !window['Morebits'] ) {
console.error('PageTriageUserspaceLogger -- Crucial dependency "morebits" failed to load, aborting any further execution as it might lead to breakages');
return;
}
if ( !window['Twinkle'] ) {
console.error('PageTriageUserspaceLogger -- Crucial dependency "Twinkle" failed to load, aborting any further execution as it might lead to breakages');
return;
}
queue.add( 'delete', function ( data ) {
const { tags } = data;
const keys = Object.keys(tags);
const logActions = { csd: [], prod: [], xfd: [] };
for ( let i = 0; i < keys.length; i++ ) {
const tag = tags[ keys[ i ] ];
if ( tag.tag.startsWith( 'speedy deletion' ) || tag.tag.startsWith( 'db-' ) || tag.tag.startsWith( 'Db-' ) ) {
logActions.csd.push( { tag: tag.tag, params: normalizeParams( tag.params ), code: tag.code, creator: data.creator, title: data.title } );
} else if ( tag.tag === 'subst:prod' || tag.tag === 'subst:blp-prod' ) {
logActions.prod.push( { blp: tag.tag === 'subst:blp-prod', params: normalizeParams( tag.params ), creator: data.creator, title: data.title } );
} else {
let venue = 'AfD';
if ( tag.tag === 'rfd-NPF' ) venue = 'RfD';
logActions.xfd.push( { venue, params: normalizeParams( tag.params ), creator: data.creator, title: data.title } );
}
}
return processLogActions( logActions, data.title );
} );
} );
} );
})();