Note: You may have to bypass your browser’s cache to see the changes. In addition, after saving a sitewide CSS file such as MediaWiki:Common.css, it will take 5-10 minutes before the changes take effect, even if you clear your cache.

  • Mozilla / Firefox / Safari: hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (Command-R on a Macintosh);
  • Konqueror and Chrome: click Reload or press F5;
  • Opera: clear the cache in Tools → Preferences;
  • Internet Explorer: hold Ctrl while clicking Refresh, or press Ctrl-F5.


// <nowiki>
// Initialize preferred languages from local storage.
let preferredLanguages = new Set(JSON.parse(localStorage.getItem("minitocLangs")));

// Empty and filled-in bookmark icons.
const unselectedIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18" height="17" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor" style="vertical-align: text-top; cursor: pointer"><g><path d="M5 1a2 2 0 00-2 2v16l7-5 7 5V3a2 2 0 00-2-2zm10 14.25-5-3.5-5 3.5V3h10z"></path></g></svg>`;
const selectedIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18" height="17" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor" style="vertical-align: text-top; cursor: pointer"><g><path d="M5 1a2 2 0 00-2 2v16l7-5 7 5V3a2 2 0 00-2-2z"></path></g></svg>`;

function displayLanguages() {
	// Clear out previously displayed languages.
	document.querySelectorAll(".minitoc-linked-languages").forEach(elem => elem.remove());

	for (let minitoc of document.querySelectorAll(".minitoc")) {
		let linkedLanguages = document.createElement("span");
		linkedLanguages.className = "minitoc-linked-languages";

		for (let languageLink of minitoc.querySelectorAll(".NavContent > a")) {
			if (preferredLanguages.has(languageLink.textContent)) {
				let link = document.createElement("a");
				link.textContent = "→ " + languageLink.textContent;
				link.href = languageLink.href;
				link.style.whiteSpace = "nowrap";
				linkedLanguages.append(" ", link);
			}
		}

		if (linkedLanguages.childElementCount)
			minitoc.querySelector(".NavHead").append(linkedLanguages);
	}
}

// Setup.
// Note: the code is generic and can handle multiple miniTOCs on one page, although this probably isn't necessary.
for (let minitoc of document.querySelectorAll(".minitoc")) {
	minitoc.querySelector(".NavContent").insertAdjacentHTML("beforeend",
		`<span style="font-size: 85%" class="minitoc-button-container">
			&#32;
			[<a class="minitoc-button-select" role="button">
				Select preferred languages
			</a>]
			<span style="display: none">
				&#32;
				[<a class="minitoc-button-clear" role="button">
					Clear all
				</a>]
			</span>
		</span>`
		.replace(/[\n\t]/g, "")
	);

	let selectButton = minitoc.querySelector(".minitoc-button-select");
	let clearButton = minitoc.querySelector(".minitoc-button-clear");

	selectButton.addEventListener("click", () => {
		// The button can be in two states: "select" and "save".
		if (selectButton.textContent === "Select preferred languages") {
			clearButton.parentElement.style.display = "";

			// Make sure you can't have multiple miniTOCs in "select" mode simultaneously.
			for (let button of document.querySelectorAll(".minitoc-button-select")) {
				if (button.textContent === "Save preferred languages") {
					// Trigger the saving procedure.
					button.click();
				}
			}

			selectButton.textContent = "Save preferred languages";

			for (let languageLink of minitoc.querySelectorAll(".NavContent > a")) {
				let iconContainer = document.createElement("span");
				iconContainer.role = "button";
				languageLink.insertAdjacentElement("beforebegin", iconContainer);

				if (preferredLanguages.has(languageLink.textContent)) {
					iconContainer.className = "minitoc-icon-selected";
					iconContainer.innerHTML = selectedIcon;
				} else {
					iconContainer.className = "minitoc-icon-unselected";
					iconContainer.innerHTML = unselectedIcon;
				}

				iconContainer.addEventListener("click", () => {
					if (preferredLanguages.has(languageLink.textContent)) {
						preferredLanguages.delete(languageLink.textContent);
						iconContainer.className = "minitoc-icon-unselected";
						iconContainer.innerHTML = unselectedIcon;
					} else {
						preferredLanguages.add(languageLink.textContent);
						iconContainer.className = "minitoc-icon-selected";
						iconContainer.innerHTML = selectedIcon;
					}
				});
			}
		} else {
			// Save to local storage.
			localStorage.setItem("minitocLangs", JSON.stringify(Array.from(preferredLanguages)));

			// Reset state.
			minitoc.querySelectorAll(".minitoc-icon-selected, .minitoc-icon-unselected").forEach(elem => elem.remove());
			selectButton.textContent = "Select preferred languages";
			clearButton.parentElement.style.display = "none";
			displayLanguages();
		}
	});

	clearButton.addEventListener("click", () => {
		preferredLanguages = new Set();
		minitoc.querySelectorAll(".minitoc-icon-selected").forEach(iconContainer => {
			iconContainer.innerHTML = unselectedIcon;
			iconContainer.className = "minitoc-icon-unselected";
		});
	});
}

displayLanguages();
// </nowiki>