MediaWiki:Gadget-imageForeignUseCheck.js

From Terraria Wiki
Jump to navigation Jump 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)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
// Adds a button on "File:" pages that lists the file's usage on foreign wikis
// (which use this wiki's shared media repository)

$(function() {
	var wgAction = mw.config.get('wgAction'),
		wgNamespaceNumber = mw.config.get('wgNamespaceNumber'),
		wgPageName = mw.config.get('wgPageName'),
		wgTitle = mw.config.get('wgTitle');

	// Only continue if the page is in the "File:" namespace and is the normal
	// file page (and not the file history, edit form, etc.)
	if (wgNamespaceNumber !== 6 || wgAction !== 'view') return;

	// Message strings
	var msgForeignUses = 'File usage on other wikis', // header for all foreign use links
		msgImageLink = 'file page', // link to foreign "File:" page of the file
		msgNoUses = 'No foreign uses of this file were detected.',
		msgButtonText = 'Load', // initial button text
		msgButtonText2 = 'Refresh', // button text after it has been clicked once
		msgLocalFileListHeader = 'File usage on this wiki'; // changed header for local uses

	// List of foreign wikis that will be checked
	// (use the "filerepoinfo" API to check whether a wiki uses the shared repo, e.g.:
	// https://terrariamods.wiki.gg/api.php?action=query&meta=filerepoinfo&friprop=name|descBaseUrl
	var foreignWikis = {
		// 'display_name': 'base_url',
		'Chinese': 'terraria.wiki.gg/zh',
		'French': 'terraria.wiki.gg/fr',
		'German': 'terraria.wiki.gg/de',
		'Hungarian': 'terraria.wiki.gg/hu',
		'Korean': 'terraria.wiki.gg/ko',
		'Polish': 'terraria.wiki.gg/pl',
		'Portuguese': 'terraria.wiki.gg/pt',
		'Russian': 'terraria.wiki.gg/ru',
		'Ukrainian': 'terraria.wiki.gg/uk',
		'Terraria Mods': 'terrariamods.wiki.gg',
		'Calamity Mod': 'calamitymod.wiki.gg',
		"Fargo's Mods": 'fargosmods.wiki.gg',
		"Fargo's Mods (Chinese)": 'fargosmods.wiki.gg/zh',
		'Infernum Mod': 'infernummod.wiki.gg',
		'Mod of Redemption': 'modofredemption.wiki.gg',
		'Shadows of Abaddon Mod': 'shadowsofabaddon.wiki.gg',
		'Spirit Mod': 'spiritmod.wiki.gg',
		'Starlight River Mod': 'starlightrivermod.wiki.gg',
		'Thorium Mod': 'thoriummod.wiki.gg',
	};

	// Change the text of the existing "File usage" header, also in TOC
	$('h2#filelinks').text(msgLocalFileListHeader);
	$('ul#filetoc li a[href="#filelinks"]').text(msgLocalFileListHeader);

	// Create new header for the foreign uses
	var $foreignUsesHeader = $('<h2></h2>', { id: 'imageForeignUseCheck-header' }).text(msgForeignUses);
	$foreignUsesHeader.insertBefore('.printfooter');

	// Add TOC link for the foreign uses
	$('ul#filetoc li a[href="#filelinks"]').parent('li').after(
		$('<li></li>', { id: 'imageForeignUseCheck-toclink' }).append(
			$('<a></a>', { href: '#imageForeignUseCheck-header' }).text(msgForeignUses)
		)
	);

	// Create the "load" button with a globe icon
	// Icon source: https://fonts.google.com/icons?selected=Material%20Symbols%20Outlined%3Atravel_explore%3AFILL%400%3Bwght%40400%3BGRAD%400%3Bopsz%4024
	var globeIcon = '<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q146 0 255.5 91.5T872-559h-82q-19-73-68.5-130.5T600-776v16q0 33-23.5 56.5T520-680h-80v80q0 17-11.5 28.5T400-560h-80v80h80v120h-40L168-552q-3 18-5.5 36t-2.5 36q0 131 92 225t228 95v80Zm364-20L716-228q-21 12-45 20t-51 8q-75 0-127.5-52.5T440-380q0-75 52.5-127.5T620-560q75 0 127.5 52.5T800-380q0 27-8 51t-20 45l128 128-56 56ZM620-280q42 0 71-29t29-71q0-42-29-71t-71-29q-42 0-71 29t-29 71q0 42 29 71t71 29Z"/></svg>';
	var buttonLoadForeignUses = new OO.ui.ButtonWidget({
		$icon: $(globeIcon),
		label: msgButtonText,
		icon: 'nonexistent-value-so-that-we-get-an-empty-icon'
	});

	// Create the progress bar
	var progressBar = new OO.ui.ProgressBarWidget({
		progress: 0,
		disabled: true
	});

	var buttonAndBarLayout = new OO.ui.FieldsetLayout({
		items: [
			new OO.ui.FieldLayout(buttonLoadForeignUses),
			new OO.ui.FieldLayout(progressBar)
		]
	});

	// Add the "Load" button and the progress bar to the DOM
	buttonAndBarLayout.$element.insertAfter($foreignUsesHeader);

	// Add a div to the DOM that will hold the output
	var $outputDiv = $('<div></div>', { 'class': 'imageForeignUseCheck-output' });
	$outputDiv.insertAfter(buttonAndBarLayout.$element);

	// Add functionality to the button
	buttonLoadForeignUses.on('click', function() {
		buttonLoadForeignUses.setDisabled(true);
		progressBar.setDisabled(false);
		progressBar.pushPending();
		progressBar.setProgress(0);

		// Clear any potentially existing output added by this gadget
		$('.imageForeignUseCheck-output').empty();

		// Prepare API requests on the foreign wikis
		var getImageInfo = { action: 'query', list: 'allimages', ailimit: '1', aifrom: wgTitle };
		var getImageUsage = { action: 'query', list: 'imageusage', iutitle: wgPageName };

		// Percentage to increase the progress bar by for each foreign wiki
		var progressPerWiki = 100 / Object.keys(foreignWikis).length;

		// Iterate over all foreign wikis
		var deferreds = [];
		$.each(foreignWikis, function(foreignWikiName, foreignWikiBaseUrl) {
			var foreignWikiApi = getForeignApiUrl(foreignWikiBaseUrl);
			var deferred = new $.Deferred();
			// Increase the progress bar's progress when done with this wiki
			deferred.done(function() { progressBar.setProgress(progressBar.getProgress() + progressPerWiki); });
			deferreds.push(deferred);
			// On the foreign wiki, check if the image exists
			$.getJSON(foreignWikiApi, getImageInfo, function(imageInfoResponse) {
				if (
					imageInfoResponse.query.allimages.length === 0 ||
					imageInfoResponse.query.allimages[0].name === wgTitle.replace(/ /g, '_')
				) {
					deferred.resolve();
					return;
				}
				// On the foreign wiki, get the pages that use the image
				$.getJSON(foreignWikiApi, getImageUsage, function(imageUsageResponse) {
					var pagesUsingTheImage = imageUsageResponse.query.imageusage;
					if (pagesUsingTheImage.length > 0) {
						addPageListFromOneForeignWiki(
							$outputDiv,
							{ name: foreignWikiName, baseUrl: foreignWikiBaseUrl },
							pagesUsingTheImage
						);
					}
					deferred.resolve();
				});
			});
		});

		// Wait for all queries to complete. For an explanation of this method, see:
		// https://stackoverflow.com/questions/5627284/pass-in-an-array-of-deferreds-to-when
		// https://stackoverflow.com/questions/4878887/how-do-you-work-with-an-array-of-jquery-deferreds
		$.when.apply(null, deferreds).done(function() {
			// Reset the state of the progress bar and the "load" button
			progressBar.setProgress(100);
			progressBar.popPending();
			buttonLoadForeignUses.setDisabled(false);
			buttonLoadForeignUses.setLabel(msgButtonText2);

			// Add the "no foreign uses" text if necessary
			if ($outputDiv.contents().length === 0) {
				$outputDiv.append(
					$('<div></div>', {
						'class': 'imageForeignUseCheck-noForeignUses',
						'style': 'margin-top:1em;'
					}).text(msgNoUses)
				);
			}
		});
	});

	function addPageListFromOneForeignWiki($outputDiv, foreignWiki, pagesUsingTheImage) {
		// Add header for this foreign wiki
		var $thisWikiHeader = $('<h3></h3>', { text: foreignWiki.name }).append(
			$('<span></span>', { style: 'font-size:85%;' }).append(
				' (',
				$('<a></a>', { href: getForeignPageUrl(foreignWiki.baseUrl, wgPageName) }).text(msgImageLink),
				')'
			)
		);
		$outputDiv.append($thisWikiHeader);

		// Add list of pages that use the image
		var $thisWikiPagelist = $('<ul></ul>');
		$thisWikiPagelist.insertAfter($thisWikiHeader);
		$.each(pagesUsingTheImage, function(_, pageInfo) {
			var urlUse = getForeignPageUrl(foreignWiki.baseUrl, pageInfo.title);
			$thisWikiPagelist.append(
				$('<li></li>').append(
					$('<a></a>', { href: urlUse }).text(pageInfo.title)
				)
			);
		});
	}
});

function getForeignApiUrl(foreignWiki) {
	return 'https://' + foreignWiki + '/api.php?format=json&callback=?';
}

function getForeignPageUrl(foreignWiki, pageName) {
	return 'https://' + foreignWiki + '/wiki/' + pageName;
}