(function() {
'use strict';
const USERSCRIPT_NAME = 'Unsigned generator';
const VERSION = 2;
const locale = {
portletText: "Unsigned gen", // short to keep the "Tools" menu narrow
portletTooltip: "Generate template for unsigned discussion messages",
template: "subst:Unsigned", // see [[Template:Unsigned]]
templateIp: "subst:Unsigned IP", // see [[Template:Unsigned IP]]
prefixText: "Unsigned wikitext: ",
copyButtonText: "Copy",
errorTimestamp: "Cannot find the timestamp of the edit. Aborting.",
errorAuthor: "Cannot find the author of the edit. Aborting.",
}
// <nowiki>
const LOG_PREFIX = `[${USERSCRIPT_NAME} v${VERSION}]:`;
const mw = window.mw; // a hack to trick my JS editor into believing that `mw` exists
const USERSCRIPT_OUTPUT_ID = 'userscript-unsigned-generator';
function error(...toLog) {
console.error(LOG_PREFIX, ...toLog);
}
function warn(...toLog) {
console.warn(LOG_PREFIX, ...toLog);
}
function info(...toLog) {
console.info(LOG_PREFIX, ...toLog);
}
function debug(...toLog) {
console.debug(LOG_PREFIX, ...toLog);
}
function notify(notificationMessage) {
mw.notify(notificationMessage, {
title: USERSCRIPT_NAME
});
}
function errorAndNotify(errorMessage, exception) {
error(errorMessage, exception);
notify(errorMessage);
}
function createTimestampWikitext(timestamp) {
// https://www.mediawiki.org/wiki/Help:Extension:ParserFunctions##time_format_like_in_signatures
return '{{' + `subst:#time:H:i, j xg Y "(UTC)"|${timestamp}}}`;
}
function createWikitext(template, user, timestamp) {
const timestampWikitext = createTimestampWikitext(timestamp);
return `{{${template}|${user}|${timestampWikitext}}}`;
}
/*
* Adapted from [[User:Enterprisey/diff-permalink.js]]
* https://en.wikipedia.org/wiki/User:Enterprisey/diff-permalink.js
*/
function showWikitextAboveDiff(wikitext) {
const wikitextInput = document.createElement('input');
wikitextInput.id = USERSCRIPT_OUTPUT_ID;
wikitextInput.value = wikitext;
wikitextInput.style.fontFamily = 'monospace';
wikitextInput.setAttribute('size', wikitext.length);
const copyButton = document.createElement('button');
copyButton.textContent = locale.copyButtonText;
copyButton.style.padding = '0.5em';
copyButton.style.cursor = 'pointer';
copyButton.style.marginLeft = '0.5em';
copyButton.onclick = () => {
document.getElementById(USERSCRIPT_OUTPUT_ID).select();
document.execCommand('copy');
};
const container = document.createElement('div');
container.appendChild(document.createTextNode(locale.prefixText));
container.appendChild(wikitextInput);
container.appendChild(copyButton);
document.getElementById('bodyContent').prepend(container);
}
/*
* The main function of the script.
*/
function runPortlet() {
/*
* Reference documentation about keys and values in mw.config:
* https://www.mediawiki.org/wiki/Manual:Interface/JavaScript#mw.config
*/
const diffTimestampElement = document.querySelector('#mw-diff-ntitle1 .mw-diff-timestamp');
if (!diffTimestampElement) {
errorAndNotify(locale.errorTimestamp);
return;
}
const mwUserlink = document.querySelector('#mw-diff-ntitle2 .mw-userlink');
if (!mwUserlink) {
errorAndNotify(locale.errorAuthor);
return;
}
const template = mwUserlink.classList.contains('mw-anonuserlink') ? locale.templateIp : locale.template;
const usernameOrIp = mwUserlink.innerText;
const isoTimestamp = diffTimestampElement.getAttribute('data-timestamp');
const wikitext = createWikitext(template, usernameOrIp, isoTimestamp);
info(wikitext);
showWikitextAboveDiff(wikitext);
}
function wait(message) {
info(message);
setTimeout(lazyLoadUnsignedGenerator, 200);
}
/*
* Infrastructure to ensure the script can run.
*/
function lazyLoadUnsignedGenerator() {
if (mw.config.get('wgDiffNewId') == null && mw.config.get('wgDiffOldId') == null) {
/*
* TODO: Not supported is the use case of the talk page being
* created with an unsigned message.
* It's harder in such cases to get to the diff view via the GUI.
*/
info('Not a diff view. Aborting.');
return;
}
const namespaceId = mw.config.get("wgNamespaceNumber");
if (namespaceId % 2 == 0 && namespaceId != 4) {
// not a talk page and not project namespace
info('Not a discussion namespace. Aborting.');
return;
}
if (!mw.loader.using) {
wait('Function mw.loader.using is no loaded yet. Waiting...');
return;
}
debug('Loading...');
mw.loader.using(
['mediawiki.util'],
() => {
const link = mw.util.addPortletLink('p-cactions', '#', locale.portletText, 'ca-unsigned-generator', locale.portletTooltip);
if (!link) {
info('Cannot create portlet link (mw.util.addPortletLink). Assuming unsupported skin. Aborting.');
return;
}
link.onclick = event => {
mw.loader.using('mediawiki.api', runPortlet);
};
},
(e) => {
error('Cannot add portlet link', e);
}
);
}
if (document.readyState !== 'loading') {
lazyLoadUnsignedGenerator();
} else {
warn('Cannot load yet. Setting up a listener...');
document.addEventListener('DOMContentLoaded', lazyLoadUnsignedGenerator);
}
// </nowiki>
})();