User:Sohom Datta/PageTriageUserspaceLogger.js

( => {   const branding = 'using 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 =  + 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 = `Nominated this attack page`; }           return `# ${titleText}: CSD ${c.code} (${c.tag}); ${serializeParams(c.code, c.params)} via PageTriage ${'~'}`; }       let titleText = `${csd[0].title}`; if (isAttack(csd)) { titleText = `Nominated this attack page`; }       let csdText = ''; for(let i = 0; i < csd.length; i++) { csdText += `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} (db-multiple); ${additionInfoString} via 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 ${a.venue}` : `nominated at ${a.venue}`; return `# ${a.title}: ${venueText}; notified via 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} ([ log]): ${p.blp ? 'BLP PROD' : 'PROD'} notified via 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 speedy deletion nominations made by this user using Twinkle's CSD module.\n\n" + 'If you no longer wish to keep this log, you can turn it off using the preferences panel, and ' + 'nominate this page for speedy deletion under 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 Articles for deletion/${title}`; usl.initialText = "This is a log of all deletion discussion nominations made by this user using Twinkle's XfD module.\n\n" + 'If you no longer wish to keep this log, you can turn it off using the preferences panel, and ' + 'nominate this page for speedy deletion under CSD U1.' + (Morebits.userIsSysop ? '\n\nThis log does not track XfD-related deletions made using Twinkle.' : ''); allLoggingActions.push( usl.log(logText, `Logging ${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 proposed deletion tags applied or endorsed by this user using Twinkle's PROD module.\n\n" + 'If you no longer wish to keep this log, you can turn it off using the preferences panel, and ' + 'nominate this page for speedy deletion under 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 ); } );       } );    } ); });