User:Edgars2007/tokyo2020.js

var api; var category = ''; var stopThis = false;

const mapping = { 'Alpine skiing': 'Category:Alpine skiers at the 2022 Winter Olympics', 'Biathlon': 'Category:Biathletes at the 2022 Winter Olympics', 'Bobsleigh': 'Category:Bobsledders at the 2022 Winter Olympics', 'Cross-country skiing': 'Category:Cross-country skiers at the 2022 Winter Olympics', 'Curling': 'Category:Curlers at the 2022 Winter Olympics', 'Figure skating': 'Category:Figure skaters at the 2022 Winter Olympics', 'Freestyle skiing': 'Category:Freestyle skiers at the 2022 Winter Olympics', 'Ice hockey': 'Category:Ice hockey players at the 2022 Winter Olympics', 'Luge': 'Category:Lugers at the 2022 Winter Olympics', 'Nordic combined': 'Category:Nordic combined skiers at the 2022 Winter Olympics', 'Short track speed skating': 'Category:Short track speed skaters at the 2022 Winter Olympics', 'Skeleton': 'Category:Skeleton racers at the 2022 Winter Olympics', 'Ski jumping': 'Category:Ski jumpers at the 2022 Winter Olympics', 'Snowboarding': 'Category:Snowboarders at the 2022 Winter Olympics', 'Speed skating': 'Category:Speed skaters at the 2022 Winter Olympics', };

const addCategory = (wikitext, category) => { if (wikitext.includes(category)) { return null; }	const re = /\[\Cc]ategory\s*:\s*[^\+\]\]/g; let m;	let lastMatch; while ((m = re.exec(wikitext))) { lastMatch = m[0]; }	// console.log('lastMatch', lastMatch) if (!lastMatch) { return `${wikitext}${category}`; }

return wikitext.replace(lastMatch, `${lastMatch}\n${category}`); };

const handleRedirects = (titles) => { return api .get({			formatversion: 2,			titles: titles,			redirects: true,		}) .then(function (data) {			const { redirects } = data.query;

let mapping = {};

redirects.forEach((entry) => {				const { from, to } = entry;				mapping[from] = to;			});

return mapping; }); };

const getCategoryMembers = (category, cmContinue = null) => { if (stopThis) { return; }	let params = { list: 'categorymembers', redirects: 1, formatversion: '2', cmtitle: category, cmnamespace: '0', cmlimit: '500', };

if (cmContinue) { params = { ...params, ...cmContinue, };	}

console.log('MADE API', params);

return api.get(params).then(function (data) {		return data;	}); };

const handleMembers = async (category) => { let flag = true; let cmContinue; const pageResults = []; let counter = 0;

while (flag) { counter++; if (counter === 15) { alert('Too many API requests, maybe something is broken'); }		const resp = await getCategoryMembers(category, cmContinue); if ('continue' in resp) { cmContinue = resp.continue; } else { flag = false; }		console.log(resp); const currpages = resp.query.categorymembers.map((entry) => entry.title); pageResults.push(...currpages); }	console.log(pageResults);

return pageResults; };

const getCategoryMembers_OLD = (category) => { return api .get({			list: 'categorymembers',			redirects: 1,			formatversion: '2',			cmtitle: category,			cmnamespace: '0',			cmlimit: '5',		}) .then(function (data) {			console.log(data);			const { categorymembers } = data.query;

return categorymembers.map((entry) => entry.title); }); };

const getData = async (category, redirects) => { const members = await handleMembers(category); const redirs = redirects.length > 0 ? await handleRedirects(redirects) : {};

return { members, redirects: redirs, }; };

const handlePageEdit = (ev) => { const element = ev.target; const canonical = element.getAttribute('data-canonical'); console.log(element, canonical);

new mw.Api .edit(canonical, function (revision) {			const newText = addCategory(revision.content, category);			if (!newText) {				return Promise.reject('ALREADY');			}			return {				text: newText,				summary: `add ${category}`,				minor: true,			};		}) .then(function {			console.log('Saved!');

var allButtons = document.getElementsByClassName('add-cat'); [...allButtons].forEach((btn) => {				const currCanonical = btn.getAttribute('data-canonical');				if (currCanonical === canonical) {					btn.parentNode.removeChild(btn);				}			}); }); };

const checker = (pageData, pageLinks) => { const { members, redirects } = pageData;

console.log({ members, redirects });

for (const link of pageLinks) { const href = link.getAttribute('href'); if (!href || !href.startsWith('/wiki/')) { continue; }		const title = decodeURIComponent(href.replaceAll('/wiki/', '').replaceAll('_', ' '));

if (title?.endsWith(' at the 2022 Winter Olympics')) { continue; }

const canonicalTitle = redirects[title] ?? title;

const included = members.includes(canonicalTitle);

// console.log(title, included) if (!included) { // link.setAttribute("data-canonical", canonicalTitle); link.outerHTML += ` ADD `; }	} };

function init { api = new mw.Api({		ajax: {			// Use a user agent, so that sysadmins can find you and tell you to fix your tool			headers: { 'Api-User-Agent': 'w:en:User:Edgars2007/tokyo2020.js' },		},	});

var allLinks = document.getElementsByTagName('a'); var redirects = [].filter .call(allLinks, (el) => el.classList.contains('mw-redirect')) .map((element) => decodeURIComponent(element.getAttribute('href').replaceAll('/wiki/', '')));

var redirectNames = [...new Set(redirects)]; console.log(redirectNames);

getData(category, redirectNames).then((resp) => checker(resp, allLinks));

$(document).on('click', '.add-cat', (event) => {		handlePageEdit(event);	}); }

const getCompetitorsName = => { const pagetitle = mw.config.get('wgPageName').replaceAll('_', ' '); console.log(pagetitle) Object.keys(mapping).forEach(title => {		if (pagetitle.startsWith(title)) {			category = mapping[title];			return;		}	}) console.log(category) }

// mw.loader.using(['mediawiki.api', 'mediawiki.util'], init);

mw.loader.using(['mediawiki.api', 'mediawiki.util'], async => {	mw.util.addPortletLink('p-cactions', '#', 'tokyo', 'ca-tokyo', 'Add participation category to articles', '5');

$(document).on('click', '#ca-tokyo', => {		getCompetitorsName;		//category = prompt('Set category name');		init;	}); });