Gebruiker:Robin van der Vliet/Vertaalgadget/Gadget.js

Let op! Nadat u de veranderingen heeft opgeslagen, moet u de cache van uw browser nog legen om ze daadwerkelijk te zien.

Mozilla (incl. Firefox) Ctrl+Shift+R
Internet Explorer Ctrl+F5
Opera F5
Safari Cmd+R
Konqueror F5
/**
 * Een gadget ontwikkeld door Robin van der Vliet voor het Nederlandse
 * WikiWoordenboek. Deze gadget maakt het mogelijk om eenvoudig vertalingen toe
 * te voegen aan pagina's.
 * 
 * Deze gadget is nog in ontwikkeling. Gebruik is op eigen risico. Controleer
 * altijd of je wijziging goed is doorgekomen en dat het niks heeft gesloopt.
 */

//<nowiki>

"use strict";

let addedTranslations = [];
let languages;
let startTime;
let pageData;
$(function () {
	getData();
	addForms();
});

function getTimestamp() {
	const now = new Date();
	return now.getUTCFullYear().toString() + 
		(now.getUTCMonth() + 1).toString().padStart(2, "0") +
		now.getUTCDate().toString().padStart(2, "0") +
		now.getUTCHours().toString().padStart(2, "0") +
		now.getUTCMinutes().toString().padStart(2, "0") +
		now.getUTCSeconds().toString().padStart(2, "0");
}

function getData() {
	fetch("/w/api.php?action=query&format=json&titles=Gebruiker:Robin_van_der_Vliet/Vertaalgadget/Gadget.js/languages.json&prop=revisions&rvprop=content&rvslots=main&formatversion=2")
		.then(response => response.json())
		.then(data => {
			languages = JSON.parse(data.query.pages[0].revisions[0].slots.main.content);
		});

	fetch("/w/api.php?action=query&format=json&titles=" + encodeURIComponent(mw.config.get("wgPageName")) + "&prop=info|revisions&inprop=watched&rvprop=content|timestamp|ids|user&meta=siteinfo|userinfo|tokens&type=csrf&uiprop=options&rvslots=main&formatversion=2")
		.then(response => response.json())
		.then(data => {
			startTime = getTimestamp();
			pageData = data;
		});
}

function addForms() {
	const divContent = '<b>Vertalingen toevoegen</b><hr>' +
		'<ul style="text-align:left"></ul><hr>' +
		'<button id="translations-save">Opslaan</button>' +
		'<button id="translations-cancel">Annuleren</button>';

	let div = document.createElement("div");
	div.innerHTML = divContent;
	div.id = "translations-submit";
	div.style = "position:fixed;top:0;left:0;background-color:#ddf;border-radius:20px;opacity:0.8;padding:10px;text-align:center;z-index:10;display:none";
	document.body.append(div);

	div.querySelector("#translations-save").addEventListener("click", submitTranslations);
	div.querySelector("#translations-cancel").addEventListener("click", function() {
		addedTranslations.length = 0;
		document.querySelector("#translations-submit").style.display = "none";
		document.querySelector("#translations-submit ul").innerHTML = "";
	});

	const formContent = '<p><label><span>Voeg een vertaling toe in het </span>' +
		'<input class="input-language" title="Naam of code van de taal" placeholder="Kies een taal..." pattern="[a-z]{3}" size="10" required></label>: ' +
		'<input class="input-translation" title="Vertaling" placeholder="Voer een vertaling in..." size="30" required></p>' +
		'<p><span class="input-genders"></span><button class="add-translation" type="submit">Toevoegen</button></p>';

	let i = 1;
	document.querySelectorAll(".translations").forEach(translations => {
		let form = document.createElement("form");
		form.innerHTML = formContent;
		form.dataset.number = i++;
		form.addEventListener("submit", submitForm);
		translations.parentNode.append(form);

		form.querySelector(".input-language").addEventListener("blur", updateLanguageField);
	});
}

function submitForm(event) {
	event.preventDefault();

	const languageField = event.target.querySelector(".input-language");
	const translationField = event.target.querySelector(".input-translation");
	const languageCode = languageField.value;

	if (languageCode === "nld" || !languages.names[languageCode]) {
		return;
	}

	const translation = {
		"number": parseInt(event.target.dataset.number),
		"languageName": languages.names[languageCode],
		"languageCode": languageCode,
		"shortestLanguageCode": languages.shortCodes[languageCode] ?? languageCode,
		"translation": translationField.value,
		"genders": [],
		"transliteration": ""
	};

	languageField.value = "";
	translationField.value = "";

	event.target.querySelectorAll(".input-genders input:checked").forEach(gender => {
		gender.checked = false;
		translation.genders.push(gender.value);
	});

	let li = document.createElement("li");
	li.textContent = `[${translation.number}] ${translation.languageName}: ${translation.translation}`;

	addedTranslations.push(translation);
	document.querySelector("#translations-submit").style.display = "block";
	document.querySelector("#translations-submit ul").append(li);
}

function submitTranslations() {
	let page = pageData.query.pages[0].revisions[0].slots.main.content;
	let summary = "";

	addedTranslations.forEach(translation => {
		let newPage = "";
		let canInsert = false;
		let number = translation.number;

		summary += `t+${translation.shortestLanguageCode}:${translation.translation} `;

		let insertTranslation = `{{t|${translation.shortestLanguageCode}|${translation.translation}`;
		translation.genders.forEach(gender => {
			insertTranslation += "|";
			insertTranslation += gender;
		});

		if (translation.transliteration) {
			insertTranslation += "|tr=";
			insertTranslation += translation.transliteration;
		}

		insertTranslation += "}}";

		page.split("\n").forEach(line => {
			let match = line.match(/^\* *{{([a-z]{3})}}:/);

			if (line.startsWith("{{trans-top")) {
				number--;
				canInsert = number === 0;
			} else if (line.startsWith("{{trans-bottom")) {
				if (canInsert) {
					newPage += `*{{${translation.languageCode}}}: ${insertTranslation}\n`;
				}

				canInsert = false;
			} else if (canInsert && match) {
				let matchedLanguageName = languages.names[match[1]] ?? match[1];

				if (match[1] === translation.languageCode) {
					newPage += line.trimEnd() + ", " + insertTranslation + "\n";
					canInsert = false;
					return;
				} else if (matchedLanguageName > translation.languageName) {
					newPage += `*{{${translation.languageCode}}}: ${insertTranslation}\n`;
					canInsert = false;
				}
			}

			newPage += line + "\n";
		});

		page = newPage;
	});

	savePage(page.trim(), summary.trim());
}

function savePage(content, summary) {
	const body = new FormData();
	body.append("wpUnicodeCheck", "ℳ𝒲♥𝓊𝓃𝒾𝒸ℴ𝒹ℯ");
	body.append("wpAutoSummary", "d41d8cd98f00b204e9800998ecf8427e");
	body.append("wpTextbox1", content);
	body.append("wpSummary", "([[Gebruiker:Robin van der Vliet/Vertaalgadget|Vertaalgadget]]) " + summary);
	body.append("wpStarttime", startTime);
	body.append("wpEdittime", pageData.query.pages[0].revisions[0].timestamp.replace(/\D/g, ""));
	body.append("wpEditToken", pageData.query.tokens.csrftoken);
	body.append("format", "text/x-wiki");
	body.append("model", "wikitext");
	body.append("wpSave", "");
	body.append("wpUltimateParam", "1");

	fetch("/w/index.php?title=" + encodeURIComponent(mw.config.get("wgPageName")) + "&action=submit", {
		"method": "post",
		"body": body,
	})
		.then(response => {
			console.log(response);
			console.log(response.status);
			if (response.status !== 200) {
				alert("Er is een fout opgetreden tijdens het opslaan!");
				return;
			}

			location.reload();
		});
}

function updateLanguageField(event) {
	const input = event.target.value.trim().toLowerCase();

	if (languages.names[input]) {
		event.target.value = input;
	} else if (languages.redirects[input]) {
		event.target.value = languages.redirects[input];
	}

	let genderFormContent = "";

	if (languages.genders[event.target.value]) {
		languages.genders[event.target.value].forEach(gender => {
			genderFormContent += `<label><input type="checkbox" value="${gender}">&nbsp;${gender}</label> `;
		});
	}

	event.target.parentNode.parentNode.parentNode.querySelector(".input-genders").innerHTML = genderFormContent;
}

//</nowiki>