yoohoo! hot sauce please

10:27, 7 September 2026 (UTC)

MediaWiki:Gadget-twinklewelcome.js

From 2swagg wiki
Jump to navigationJump to search

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)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
// <nowiki>

(function() {

/*
 ****************************************
 *** twinklewelcome.js: Welcome module
 ****************************************
 * Mode of invocation:     Tab ("Wel"), or from links on diff pages
 * Active on:              Any page with relevant user name (userspace,
 *                         contribs, etc.) and diff pages
 */

Twinkle.welcome = function twinklewelcome() {
	if (Twinkle.getPrefill('twinklewelcome')) {
		if (Twinkle.getPrefill('twinklewelcome') === 'auto') {
			Twinkle.welcome.auto();
		} else {
			Twinkle.welcome.semiauto();
		}
	} else {
		Twinkle.welcome.normal();
	}
};

Twinkle.welcome.auto = function() {
	if (mw.util.getParamValue('action') !== 'edit') {
		// userpage not empty, aborting auto-welcome
		return;
	}

	Twinkle.welcome.welcomeUser();
};

Twinkle.welcome.semiauto = function() {
	Twinkle.welcome.callback(mw.config.get('wgRelevantUserName'));
};

Twinkle.welcome.normal = function() {
	const isDiff = mw.util.getParamValue('diff');
	if (isDiff) {
		// check whether the contributors' talk pages exist yet
		const $oldDiffUsernameLine = $('#mw-diff-otitle2');
		const $newDiffUsernameLine = $('#mw-diff-ntitle2');
		const $oldDiffHasRedlinkedTalkPage = $oldDiffUsernameLine.find('span.mw-usertoollinks a.new:contains(talk)').first();
		const $newDiffHasRedlinkedTalkPage = $newDiffUsernameLine.find('span.mw-usertoollinks a.new:contains(talk)').first();

		const diffHasRedlinkedTalkPage = $oldDiffHasRedlinkedTalkPage.length > 0 || $newDiffHasRedlinkedTalkPage.length > 0;
		if (diffHasRedlinkedTalkPage) {
			const spanTag = function(color, content) {
				const span = document.createElement('span');
				span.style.color = color;
				span.appendChild(document.createTextNode(content));
				return span;
			};

			const welcomeNode = document.createElement('strong');
			const welcomeLink = document.createElement('a');
			welcomeLink.appendChild(spanTag('Black', '['));
			welcomeLink.appendChild(spanTag('Goldenrod', 'welcome'));
			welcomeLink.appendChild(spanTag('Black', ']'));
			welcomeNode.appendChild(welcomeLink);

			if ($oldDiffHasRedlinkedTalkPage.length > 0) {
				const oHref = $oldDiffHasRedlinkedTalkPage.attr('href');

				const oWelcomeNode = welcomeNode.cloneNode(true);
				oWelcomeNode.firstChild.setAttribute('href', oHref + '&' + $.param({
					twinklewelcome: Twinkle.getPref('quickWelcomeMode') === 'auto' ? 'auto' : 'norm',
					vanarticle: Morebits.pageNameNorm
				}));
				$oldDiffHasRedlinkedTalkPage[0].parentNode.parentNode.appendChild(document.createTextNode(' '));
				$oldDiffHasRedlinkedTalkPage[0].parentNode.parentNode.appendChild(oWelcomeNode);
			}

			if ($newDiffHasRedlinkedTalkPage.length > 0) {
				const nHref = $newDiffHasRedlinkedTalkPage.attr('href');

				const nWelcomeNode = welcomeNode.cloneNode(true);
				nWelcomeNode.firstChild.setAttribute('href', nHref + '&' + $.param({
					twinklewelcome: Twinkle.getPref('quickWelcomeMode') === 'auto' ? 'auto' : 'norm',
					vanarticle: Morebits.pageNameNorm
				}));
				$newDiffHasRedlinkedTalkPage[0].parentNode.parentNode.appendChild(document.createTextNode(' '));
				$newDiffHasRedlinkedTalkPage[0].parentNode.parentNode.appendChild(nWelcomeNode);
			}
		}
	}
	// Users and IPs but not IP ranges
	if (mw.config.exists('wgRelevantUserName') && !Morebits.ip.isRange(mw.config.get('wgRelevantUserName'))) {
		Twinkle.addPortletLink(() => {
			Twinkle.welcome.callback(mw.config.get('wgRelevantUserName'));
		}, 'Wel', 'twinkle-welcome', 'Welcome user');
	}
};

Twinkle.welcome.welcomeUser = function welcomeUser() {
	Morebits.Status.init(document.getElementById('mw-content-text'));
	$('#catlinks').remove();

	const params = {
		template: Twinkle.getPref('quickWelcomeTemplate'),
		article: Twinkle.getPrefill('vanarticle') || '',
		mode: 'auto'
	};

	const userTalkPage = mw.config.get('wgFormattedNamespaces')[3] + ':' + mw.config.get('wgRelevantUserName');
	Morebits.wiki.actionCompleted.redirect = userTalkPage;
	Morebits.wiki.actionCompleted.notice = 'Welcoming complete, reloading talk page in a few seconds';

	const wikipedia_page = new Morebits.wiki.Page(userTalkPage, 'User talk page modification');
	wikipedia_page.setFollowRedirect(true);
	wikipedia_page.setCallbackParameters(params);
	wikipedia_page.load(Twinkle.welcome.callbacks.main);
};

Twinkle.welcome.callback = function twinklewelcomeCallback(uid) {
	if (uid === mw.config.get('wgUserName') && !confirm('Are you really sure you want to welcome yourself?...')) {
		return;
	}

	const Window = new Morebits.SimpleWindow(600, 420);
	Window.setTitle('Welcome user');
	Window.setScriptName('Twinkle');
	Window.addFooterLink('Welcoming Committee', 'WP:WC');
	Window.addFooterLink('Welcome prefs', 'WP:TW/PREF#welcome');
	Window.addFooterLink('Twinkle help', 'WP:TW/DOC#welcome');
	Window.addFooterLink('Give feedback', 'WT:TW');

	const form = new Morebits.QuickForm(Twinkle.welcome.callback.evaluate);

	form.append({
		type: 'select',
		name: 'type',
		label: 'Type of welcome:',
		event: Twinkle.welcome.populateWelcomeList,
		list: [
			{ type: 'option', value: 'standard', label: 'Standard welcomes', selected: !mw.util.isIPAddress(mw.config.get('wgRelevantUserName')) },
			{ type: 'option', value: 'unregistered', label: 'IP user welcomes', selected: mw.util.isIPAddress(mw.config.get('wgRelevantUserName')) },
			{ type: 'option', value: 'wikiProject', label: 'WikiProject welcomes' },
			{ type: 'option', value: 'nonEnglish', label: 'Non-English welcomes' }
		]
	});

	form.append({
		type: 'div',
		id: 'welcomeWorkArea',
		className: 'morebits-scrollbox'
	});

	form.append({
		type: 'input',
		name: 'article',
		label: '* Linked article (if supported by template):',
		value: Twinkle.getPrefill('vanarticle') || '',
		tooltip: 'An article might be linked from within the welcome if the template supports it. Leave empty for no article to be linked.  Templates that support a linked article are marked with an asterisk.'
	});

	const previewlink = document.createElement('a');
	$(previewlink).on('click', () => {
		Twinkle.welcome.callbacks.preview(result); // |result| is defined below
	});
	previewlink.style.cursor = 'pointer';
	previewlink.textContent = 'Preview';
	form.append({ type: 'div', name: 'welcomepreview', label: [ previewlink ] });

	form.append({ type: 'submit' });

	var result = form.render();
	Window.setContent(result);
	Window.display();

	// initialize the welcome list
	const evt = document.createEvent('Event');
	evt.initEvent('change', true, true);
	result.type.dispatchEvent(evt);
};

Twinkle.welcome.populateWelcomeList = function(e) {
	const type = e.target.value;

	const container = new Morebits.QuickForm.Element({ type: 'fragment' });

	if ((type === 'standard' || type === 'unregistered') && Twinkle.getPref('customWelcomeList').length) {
		container.append({ type: 'header', label: 'Custom welcome templates' });
		container.append({
			type: 'radio',
			name: 'template',
			list: Twinkle.getPref('customWelcomeList'),
			event: function() {
				e.target.form.article.disabled = false;
			}
		});
	}

	const sets = Twinkle.welcome.templates[type];
	$.each(sets, (label, templates) => {
		container.append({ type: 'header', label: label });
		container.append({
			type: 'radio',
			name: 'template',
			list: $.map(templates, (properties, template) => ({
					value: template,
					label: '{{' + template + '}}: ' + properties.description + (properties.linkedArticle ? '\u00A0*' : ''), // U+00A0 NO-BREAK SPACE
					tooltip: properties.tooltip // may be undefined
				})),
			event: function(ev) {
				ev.target.form.article.disabled = !templates[ev.target.value].linkedArticle;
			}
		});
	});

	const rendered = container.render();
	$(e.target.form).find('div#welcomeWorkArea').empty().append(rendered);

	const firstRadio = e.target.form.template[0];
	firstRadio.checked = true;
	const vals = Object.values(sets)[0];
	e.target.form.article.disabled = vals[firstRadio.value] ? !vals[firstRadio.value].linkedArticle : true;
};

// A list of welcome templates and their properties and syntax

// The four fields that are available are "description", "linkedArticle", "syntax", and "tooltip".
// The three magic words that can be used in the "syntax" field are:
//   - $USERNAME$  - replaced by the welcomer's username, depending on user's preferences
//   - $ARTICLE$   - replaced by an article name, if "linkedArticle" is true
//   - $HEADER$    - adds a level 2 header (most templates already include this)
//   - $EXTRA$     - custom message to be added at the end of the template. not implemented yet.

Twinkle.welcome.templates = {
	standard: {
		'General welcome templates': {
			welcome: {
				description: 'standard welcome',
				linkedArticle: true,
				syntax: '{{subst:welcome|$USERNAME$}} ~~~~'
			},
			'welcomebelated': {
				description: 'belated welcome',
				linkedArticle: true,
				syntax: '{{subst:welcomebelated|$USERNAME$}} ~~~~'
			},

			'welcomeback': {
				description: 'welcome for returning old users',
				linkedArticle: true,
				syntax: '{{subst:welcomeback|$USERNAME$}} ~~~~'
			},
			
			'welcomeapprover': {
				description: 'welcome for new approvers',
				linkedArticle: true,
				syntax: '{{subst:welcomeapprover|$USERNAME$}} ~~~~'
			},
			
			'welcomehelper': {
				description: 'welcome for new helpers',
				linkedArticle: true,
				syntax: '{{subst:welcomehelper|$USERNAME$}} ~~~~'
			},
		},
	},
};

Twinkle.welcome.getTemplateWikitext = function(type, template, article) {
	// the iteration is required as the type=standard has two groups
	let properties;
	$.each(Twinkle.welcome.templates[type], (label, templates) => {
		properties = templates[template];
		if (properties) {
			return false; // break
		}
	});
	if (properties) {
		return properties.syntax
			.replace('$USERNAME$', Twinkle.getPref('insertUsername') ? mw.config.get('wgUserName') : '')
			.replace('$ARTICLE$', article || '')
			.replace(/\$HEADER\$\s*/, '== Welcome ==\n\n')
			.replace('$EXTRA$', ''); // EXTRA is not implemented yet
	}
	return '{{subst:' + template + (article ? '|art=' + article : '') + '}}' +
			(Twinkle.getPref('customWelcomeSignature') ? ' ~~~~' : '');
};

Twinkle.welcome.callbacks = {
	preview: function(form) {
		const previewDialog = new Morebits.SimpleWindow(750, 400);
		previewDialog.setTitle('Welcome template preview');
		previewDialog.setScriptName('Welcome user');
		previewDialog.setModality(true);

		const previewdiv = document.createElement('div');
		previewdiv.style.marginLeft = previewdiv.style.marginRight = '0.5em';
		previewdiv.style.fontSize = 'small';
		previewDialog.setContent(previewdiv);

		const previewer = new Morebits.wiki.Preview(previewdiv);
		const input = Morebits.QuickForm.getInputData(form);
		previewer.beginRender(Twinkle.welcome.getTemplateWikitext(input.type, input.template, input.article), 'User talk:' + mw.config.get('wgRelevantUserName')); // Force wikitext/correct username

		const submit = document.createElement('input');
		submit.setAttribute('type', 'submit');
		submit.setAttribute('value', 'Close');
		previewDialog.addContent(submit);

		previewDialog.display();

		$(submit).on('click', () => {
			previewDialog.close();
		});
	},
	main: function(pageobj) {
		const params = pageobj.getCallbackParameters();
		let text = pageobj.getPageText();

		// abort if mode is auto and form is not empty
		if (pageobj.exists() && params.mode === 'auto') {
			Morebits.Status.info('Warning', 'User talk page not empty; aborting automatic welcome');
			Morebits.wiki.actionCompleted.event();
			return;
		}

		const welcomeText = Twinkle.welcome.getTemplateWikitext(params.type, params.template, params.article);

		if (Twinkle.getPref('topWelcomes')) {
			const hasTalkHeader = /^\{\{Talk ?header\}\}/i.test(text);
			if (hasTalkHeader) {
				text = text.replace(/^\{\{Talk ?header\}\}\n{0,2}/i, '');
				text = '{{Talk header}}\n\n' + welcomeText + '\n\n' + text;
				text = text.trim();
			} else {
				text = welcomeText + '\n\n' + text;
			}
		} else {
			text += '\n' + welcomeText;
		}

		const summaryText = 'Welcome to der ki.';
		pageobj.setPageText(text);
		pageobj.setEditSummary(summaryText);
		pageobj.setChangeTags(Twinkle.changeTags);
		pageobj.setWatchlist(Twinkle.getPref('watchWelcomes'));
		pageobj.setCreateOption('recreate');
		pageobj.save();
	}
};

Twinkle.welcome.callback.evaluate = function twinklewelcomeCallbackEvaluate(e) {
	const form = e.target;

	const params = Morebits.QuickForm.getInputData(form); // : type, template, article
	params.mode = 'manual';

	Morebits.SimpleWindow.setButtonsEnabled(false);
	Morebits.Status.init(form);

	const userTalkPage = mw.config.get('wgFormattedNamespaces')[3] + ':' + mw.config.get('wgRelevantUserName');
	Morebits.wiki.actionCompleted.redirect = userTalkPage;
	Morebits.wiki.actionCompleted.notice = 'Welcoming complete, reloading talk page in a few seconds';

	const wikipedia_page = new Morebits.wiki.Page(userTalkPage, 'User talk page modification');
	wikipedia_page.setFollowRedirect(true);
	wikipedia_page.setCallbackParameters(params);
	wikipedia_page.load(Twinkle.welcome.callbacks.main);
};

Twinkle.addInitCallback(Twinkle.welcome, 'welcome');
}());

// </nowiki>