Jump to content

User:Edgars2007/tokyo2020.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
var api;
var category = '';
var stopThis = false;

const mapping = {
	'Archery': 'Category:Archers at the 2024 Summer Olympics',
	'Athletics': 'Category:Athletes (track and field) at the 2024 Summer Olympics',
	'Badminton': 'Category:Badminton players at the 2024 Summer Olympics',
	'Basketball': 'Category:Basketball players at the 2024 Summer Olympics',
	'Breaking': 'Category:Breakdancers at the 2024 Summer Olympics',
	'Beach volleyball': 'Category:Beach volleyball players at the 2024 Summer Olympics',
	'Boxing': 'Category:Boxers at the 2024 Summer Olympics',
	'Canoeing': 'Category:Canoeists at the 2024 Summer Olympics',
	'Cycling': 'Category:Cyclists at the 2024 Summer Olympics',
	'Diving': 'Category:Divers at the 2024 Summer Olympics',
	'Equestrian': 'Category:Equestrians at the 2024 Summer Olympics',
	'Fencing': 'Category:Fencers at the 2024 Summer Olympics',
	'Field hockey': 'Category:Field hockey players at the 2024 Summer Olympics',
	'Football': 'Category:Footballers at the 2024 Summer Olympics',
	'Golf': 'Category:Golfers at the 2024 Summer Olympics',
	'Gymnastics': 'Category:Gymnasts at the 2024 Summer Olympics',
	'Handball': 'Category:Handball players at the 2024 Summer Olympics',
	'Judo': 'Category:Judoka at the 2024 Summer Olympics',
	'Modern pentathlon': 'Category:Modern pentathletes at the 2024 Summer Olympics',
	'Rowing': 'Category:Rowers at the 2024 Summer Olympics',
	'Sailing': 'Category:Sailors at the 2024 Summer Olympics',
	'Shooting': 'Category:Shooters at the 2024 Summer Olympics',
	'Swimming': 'Category:Swimmers at the 2024 Summer Olympics',
	'Artistic swimming': 'Category:Artistic swimmers at the 2024 Summer Olympics',
	'Table tennis': 'Category:Table tennis players at the 2024 Summer Olympics',
	'Taekwondo': 'Category:Taekwondo practitioners at the 2024 Summer Olympics',
	'Tennis': 'Category:Tennis players at the 2024 Summer Olympics',
	'Triathlon': 'Category:Triathletes at the 2024 Summer Olympics',
	'Volleyball': 'Category:Volleyball players at the 2024 Summer Olympics',
	'Water polo': 'Category:Water polo players at the 2024 Summer Olympics',
	'Weightlifting': 'Category:Weightlifters at the 2024 Summer Olympics',
	'Wrestling': 'Category:Wrestlers at the 2024 Summer Olympics',
	'Rugby sevens': 'Category:Rugby sevens players at the 2024 Summer Olympics',
	'Surfing': 'Category:Surfers at the 2024 Summer Olympics',
	'Skateboarding': 'Category:Skateboarders at the 2024 Summer Olympics',
	'Baseball': 'Category:Baseball players at the 2024 Summer Olympics',
	'Karate': 'Category:Karateka at the 2024 Summer Olympics',
	'Softball': 'Category:Softball players at the 2024 Summer Olympics',
	'Sport climbing': 'Category:Sport climbers at the 2024 Summer 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 2024 Summer 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 += ` <button class="add-cat" data-canonical="${canonicalTitle}">ADD</button>`;
		}
	}
};

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').replace('_', ' ');
	
	Object.keys(mapping).forEach(title => {
		if (pagetitle.startsWith(title)) {
			category = mapping[title];
			return;
		}
	})
}

// 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();
	});
});