Main Page: Difference between revisions
No edit summary |
Fix remaining broken arrow characters on main page |
||
| (8 intermediate revisions by 2 users not shown) | |||
| Line 1: | Line 1: | ||
__NOTOC__ | |||
<html> | <html> | ||
| Line 561: | Line 559: | ||
.vu-people-controls { | .vu-people-controls { | ||
display: grid; | display: grid; | ||
grid-template-columns: auto auto minmax(0, 1fr) auto; | grid-template-columns: auto auto minmax(0, 1fr) auto auto; | ||
align-items: center; | align-items: center; | ||
gap: 8px; | gap: 8px; | ||
| Line 929: | Line 927: | ||
.vu-people-controls { | .vu-people-controls { | ||
grid-template-columns: auto auto minmax(50px, 1fr) auto; | grid-template-columns: auto auto minmax(50px, 1fr) auto auto; | ||
} | } | ||
| Line 1,014: | Line 1,012: | ||
<span class="vu-explore-description">Biographies recorded across the wiki.</span> | <span class="vu-explore-description">Biographies recorded across the wiki.</span> | ||
</span> | </span> | ||
<span class="vu-explore-arrow"> | <span class="vu-explore-arrow">></span> | ||
</a> | </a> | ||
| Line 1,023: | Line 1,021: | ||
<span class="vu-explore-description">Places documented throughout the history.</span> | <span class="vu-explore-description">Places documented throughout the history.</span> | ||
</span> | </span> | ||
<span class="vu-explore-arrow"> | <span class="vu-explore-arrow">></span> | ||
</a> | </a> | ||
| Line 1,032: | Line 1,030: | ||
<span class="vu-explore-description">Family lines and their members.</span> | <span class="vu-explore-description">Family lines and their members.</span> | ||
</span> | </span> | ||
<span class="vu-explore-arrow"> | <span class="vu-explore-arrow">></span> | ||
</a> | </a> | ||
| Line 1,041: | Line 1,039: | ||
<span class="vu-explore-description">Institutions and organized groups.</span> | <span class="vu-explore-description">Institutions and organized groups.</span> | ||
</span> | </span> | ||
<span class="vu-explore-arrow"> | <span class="vu-explore-arrow">></span> | ||
</a> | </a> | ||
| Line 1,050: | Line 1,048: | ||
<span class="vu-explore-description">Events recorded throughout the history.</span> | <span class="vu-explore-description">Events recorded throughout the history.</span> | ||
</span> | </span> | ||
<span class="vu-explore-arrow"> | <span class="vu-explore-arrow">></span> | ||
</a> | </a> | ||
| Line 1,059: | Line 1,057: | ||
<span class="vu-explore-description">The historical periods used by the wiki.</span> | <span class="vu-explore-description">The historical periods used by the wiki.</span> | ||
</span> | </span> | ||
<span class="vu-explore-arrow"> | <span class="vu-explore-arrow">></span> | ||
</a> | </a> | ||
</nav> | </nav> | ||
| Line 1,076: | Line 1,074: | ||
<h2> | <h2> | ||
<a data-wiki-title="Reichsministerium für Bergbau und Rohstoffe" href="/wiki/Reichsministerium_f%C3%BCr_Bergbau_und_Rohstoffe"> | <a data-wiki-title="Reichsministerium für Bergbau und Rohstoffe" href="/wiki/Reichsministerium_f%C3%BCr_Bergbau_und_Rohstoffe"> | ||
Reichsministerium | Reichsministerium für Bergbau und Rohstoffe | ||
</a> | </a> | ||
</h2> | </h2> | ||
<p> | <p> | ||
The Reichsministerium | The Reichsministerium für Bergbau und Rohstoffe was a central ministry of the | ||
<a data-wiki-title="Government of the Tanoa Einsatzgruppen" href="/wiki/Government_of_the_Tanoa_Einsatzgruppen">Government of the Tanoa Einsatzgruppen</a>. | <a data-wiki-title="Government of the Tanoa Einsatzgruppen" href="/wiki/Government_of_the_Tanoa_Einsatzgruppen">Government of the Tanoa Einsatzgruppen</a>. | ||
It administered mining and the state supply of raw materials. | It administered mining and the state supply of raw materials. | ||
| Line 1,119: | Line 1,117: | ||
<section class="vu-people" id="vu-people-slider" aria-label="People slideshow"> | <section class="vu-people" id="vu-people-slider" aria-label="People slideshow"> | ||
<div class="vu-people-status" id="vu-people-status"> | <div class="vu-people-status" id="vu-people-status" hidden></div> | ||
<div class="vu-people-stage"> | <div class="vu-people-stage"> | ||
| Line 1,130: | Line 1,128: | ||
<div class="vu-person-copy"> | <div class="vu-person-copy"> | ||
<h2 class="vu-person-title" id="vu-person-title">Toonio Noord</h2> | <h2 class="vu-person-title" id="vu-person-title">Toonio Noord</h2> | ||
| Line 1,142: | Line 1,139: | ||
id="vu-person-link" | id="vu-person-link" | ||
href="/wiki/Toonio_Noord"> | href="/wiki/Toonio_Noord"> | ||
Open | Open page | ||
</a> | </a> | ||
</div> | </div> | ||
| Line 1,148: | Line 1,145: | ||
<div class="vu-people-controls"> | <div class="vu-people-controls"> | ||
<button class="vu-slide-button" id="vu-person-prev" type="button" aria-label="Previous person"> | <button class="vu-slide-button" id="vu-person-prev" type="button" aria-label="Previous person"><</button> | ||
<button class="vu-slide-button" id="vu-person-toggle" type="button" aria-label="Pause slideshow">Pause</button> | <button class="vu-slide-button" id="vu-person-toggle" type="button" aria-label="Pause slideshow">Pause</button> | ||
| Line 1,157: | Line 1,154: | ||
<div class="vu-slide-count" id="vu-person-count">1 / 1</div> | <div class="vu-slide-count" id="vu-person-count">1 / 1</div> | ||
<button class="vu-slide-button" id="vu-person-next" type="button" aria-label="Next person"> | <button class="vu-slide-button" id="vu-person-next" type="button" aria-label="Next person">></button> | ||
</div> | </div> | ||
</section> | </section> | ||
<div class="vu-heading"> | <div class="vu-heading"> | ||
<div class="vu-heading-title">How to use this wiki</div> | <div class="vu-heading-title">How to use this wiki</div> | ||
| Line 1,236: | Line 1,232: | ||
"use strict"; | "use strict"; | ||
function | function onReady(callback) { | ||
if (document.readyState === "loading") { | if (document.readyState === "loading") { | ||
document.addEventListener("DOMContentLoaded", callback); | document.addEventListener("DOMContentLoaded", callback, { once: true }); | ||
} else { | } else { | ||
callback(); | callback(); | ||
| Line 1,244: | Line 1,240: | ||
} | } | ||
onReady(function () { | |||
var root = document.querySelector(".vu-main"); | var root = document.querySelector(".vu-main"); | ||
var slider = document.getElementById("vu-people-slider"); | |||
var status = document.getElementById("vu-people-status"); | |||
var image = document.getElementById("vu-person-image"); | |||
var title = document.getElementById("vu-person-title"); | |||
var extract = document.getElementById("vu-person-extract"); | |||
var pageLink = document.getElementById("vu-person-link"); | |||
var count = document.getElementById("vu-person-count"); | |||
var previous = document.getElementById("vu-person-prev"); | |||
var next = document.getElementById("vu-person-next"); | |||
var toggle = document.getElementById("vu-person-toggle"); | |||
if (!root || ! | if ( | ||
!root || | |||
!slider || | |||
!status || | |||
!image || | |||
!title || | |||
!extract || | |||
!pageLink || | |||
!count || | |||
!previous || | |||
!next || | |||
!toggle | |||
) { | |||
return; | return; | ||
} | } | ||
var | var fallbackImage = "/wiki/Special:Redirect/file/Vu-logo.png"; | ||
var cacheKey = "vu-main-people-slides-v9"; | |||
var cacheLifetime = 6 * 60 * 60 * 1000; | |||
var slideInterval = 9000; | |||
var apiPath = "/wiki/api.php"; | |||
var people = []; | |||
var currentIndex = 0; | |||
var timer = null; | |||
var playing = false; | |||
previous.disabled = true; | |||
next.disabled = true; | |||
toggle.disabled = true; | |||
count.textContent = "1 / 1"; | |||
toggle.textContent = "Play"; | |||
previous.textContent = "<"; | |||
next.textContent = ">"; | |||
function showStatus(message) { | |||
if (!message) { | |||
status.hidden = true; | |||
status.textContent = ""; | |||
return; | |||
} | |||
function | status.textContent = message; | ||
status.hidden = false; | |||
} | |||
function shuffle(items) { | |||
var result = items.slice(); | |||
for (var index = result.length - 1; index > 0; index--) { | |||
var randomIndex = Math.floor(Math.random() * (index + 1)); | |||
var temporary = result[index]; | |||
result[index] = result[randomIndex]; | |||
result[randomIndex] = temporary; | |||
} | } | ||
return | return result; | ||
} | } | ||
function | function cleanText(value) { | ||
return String(value || "") | |||
.replace(/\[\s*\d+(?:\.\d+)?\s*\]/g, "") | |||
.replace(/\s+/g, " ") | |||
.trim(); | |||
} | } | ||
function shorten(value, limit) { | |||
var cleaned = cleanText(value); | |||
if (!cleaned || cleaned.length <= limit) { | |||
return cleaned; | |||
} | |||
var cut = cleaned.slice(0, limit); | |||
. | var sentenceEnd = Math.max( | ||
cut.lastIndexOf(". "), | |||
cut.lastIndexOf("! "), | |||
cut.lastIndexOf("? ") | |||
); | |||
if (sentenceEnd > 180) { | |||
if ( | return cut.slice(0, sentenceEnd + 1); | ||
return; | |||
} | } | ||
var finalSpace = cut.lastIndexOf(" "); | |||
return cut.slice(0, finalSpace > 0 ? finalSpace : limit) + "..."; | |||
} | |||
function getImage(page) { | |||
if (page.thumbnail && page.thumbnail.source) { | |||
return page.thumbnail.source; | |||
} | |||
if (page.original && page.original.source) { | |||
return page.original.source; | |||
} | |||
return ""; | |||
} | |||
function pageUrl(pageTitle) { | |||
if (window.mw && mw.util) { | |||
return mw.util.getUrl(pageTitle); | |||
} | |||
return "/wiki/" + encodeURIComponent(pageTitle.replace(/ /g, "_")); | |||
} | } | ||
function normalizePages(pages) { | |||
return shuffle( | |||
pages | |||
.filter(function (page) { | |||
return page && !page.missing && page.title; | |||
}) | |||
.map(function (page) { | |||
var pageExtract = shorten(page.extract, 650); | |||
if (!pageExtract) { | |||
pageExtract = | |||
"This page is listed in Category:People. Open the page for the full article."; | |||
} | |||
return { | |||
title: page.title, | |||
extract: pageExtract, | |||
image: getImage(page) || fallbackImage, | |||
url: page.fullurl || pageUrl(page.title) | |||
}; | |||
}) | |||
); | |||
} | |||
function readCache() { | |||
try { | |||
var cached = JSON.parse( | |||
window.sessionStorage.getItem(cacheKey) || "null" | |||
); | |||
if ( | |||
cached && | |||
cached.savedAt && | |||
Date.now() - cached.savedAt < cacheLifetime && | |||
Array.isArray(cached.people) && | |||
cached.people.length > 1 | |||
return; | ) { | ||
return cached.people; | |||
} | |||
} catch (error) { | |||
return null; | |||
} | |||
return null; | |||
} | } | ||
function saveCache(items) { | |||
try { | |||
window.sessionStorage.setItem( | |||
cacheKey, | |||
JSON.stringify({ | |||
savedAt: Date.now(), | |||
function | people: items | ||
}) | |||
); | |||
} catch (error) { | |||
return; | |||
} | } | ||
} | } | ||
function | function preloadNext() { | ||
if ( | if (people.length < 2) { | ||
return | return; | ||
} | } | ||
var | var nextIndex = (currentIndex + 1) % people.length; | ||
var preload = new Image(); | |||
preload.src = people[nextIndex].image; | |||
} | |||
var | |||
} | |||
function restartProgress() { | function restartProgress() { | ||
| Line 1,416: | Line 1,434: | ||
void slider.offsetWidth; | void slider.offsetWidth; | ||
if (playing) { | if (playing && people.length > 1) { | ||
slider.classList.add("is-playing"); | slider.classList.add("is-playing"); | ||
} | } | ||
} | } | ||
function | function scheduleNext() { | ||
if (timer) { | if (timer) { | ||
window.clearTimeout(timer); | window.clearTimeout(timer); | ||
| Line 1,433: | Line 1,451: | ||
timer = window.setTimeout(function () { | timer = window.setTimeout(function () { | ||
showSlide(currentIndex + 1); | |||
}, | }, slideInterval); | ||
} | } | ||
function | function showSlide(index) { | ||
if (!people.length) { | if (!people.length) { | ||
return; | return; | ||
} | } | ||
currentIndex = (index + people.length) % people.length; | |||
var person = people[ | var person = people[currentIndex]; | ||
slider.classList.add("is-changing"); | slider.classList.add("is-changing"); | ||
| Line 1,451: | Line 1,469: | ||
image.alt = person.title; | image.alt = person.title; | ||
title.textContent = person.title; | title.textContent = person.title; | ||
extract.textContent = | extract.textContent = person.extract; | ||
pageLink.href = person.url; | |||
count.textContent = ( | pageLink.textContent = "Open page"; | ||
count.textContent = | |||
String(currentIndex + 1) + " / " + String(people.length); | |||
window.setTimeout(function () { | window.setTimeout(function () { | ||
slider.classList.remove("is-changing"); | slider.classList.remove("is-changing"); | ||
}, 40); | }, 40); | ||
preloadNext(); | |||
}, 140); | |||
scheduleNext(); | |||
} | } | ||
function setPlaying(value) { | function setPlaying(value) { | ||
playing = value; | playing = Boolean(value && people.length > 1); | ||
toggle.textContent = playing ? "Pause" : "Play"; | toggle.textContent = playing ? "Pause" : "Play"; | ||
toggle.setAttribute( | toggle.setAttribute( | ||
| Line 1,472: | Line 1,494: | ||
if (playing) { | if (playing) { | ||
scheduleNext(); | |||
} else { | } else { | ||
if (timer) { | if (timer) { | ||
window.clearTimeout(timer); | window.clearTimeout(timer); | ||
} | } | ||
slider.classList.remove("is-playing"); | slider.classList.remove("is-playing"); | ||
} | } | ||
} | |||
function activateSlides(items) { | |||
if (!Array.isArray(items) || !items.length) { | |||
showStatus("No people pages were loaded."); | |||
return; | |||
} | |||
people = shuffle(items); | |||
currentIndex = 0; | |||
previous.disabled = people.length < 2; | |||
next.disabled = people.length < 2; | |||
toggle.disabled = people.length < 2; | |||
showStatus(""); | |||
showSlide(0); | |||
setPlaying(people.length > 1); | |||
} | } | ||
previous.addEventListener("click", function () { | previous.addEventListener("click", function () { | ||
showSlide(currentIndex - 1); | |||
}); | }); | ||
next.addEventListener("click", function () { | next.addEventListener("click", function () { | ||
showSlide(currentIndex + 1); | |||
}); | }); | ||
| Line 1,502: | Line 1,541: | ||
slider.addEventListener("mouseleave", function () { | slider.addEventListener("mouseleave", function () { | ||
if (playing) { | if (playing) { | ||
scheduleNext(); | |||
} | } | ||
}); | }); | ||
| Line 1,512: | Line 1,551: | ||
}); | }); | ||
function | function buildQuery(params) { | ||
var | var parts = []; | ||
Object.keys(params).forEach(function (key) { | |||
parts.push( | |||
encodeURIComponent(key) + | |||
"=" + | |||
encodeURIComponent(params[key]) | |||
); | ); | ||
}); | |||
return parts.join("&"); | |||
} | |||
return | function requestJson(params) { | ||
return window | |||
.fetch(apiPath + "?" + buildQuery(params), { | |||
credentials: "same-origin" | |||
}) | |||
.then(function (response) { | |||
if (!response.ok) { | |||
throw new Error("API HTTP " + response.status); | |||
} | |||
return response.json(); | |||
}); | |||
} | |||
function copyParams(params) { | |||
var copied = {}; | |||
Object.keys(params).forEach(function (key) { | |||
copied[key] = params[key]; | |||
}); | |||
return copied; | |||
} | |||
function loadCategoryMembers(params, collectedPages) { | |||
return requestJson(params).then(function (data) { | |||
var nextPages = | |||
data && | |||
data.query && | |||
Array.isArray(data.query.categorymembers) | |||
? data.query.categorymembers | |||
: []; | |||
var allPages = collectedPages.concat(nextPages); | |||
if (data && data.continue) { | |||
var nextParams = copyParams(params); | |||
Object.keys(data.continue).forEach(function (key) { | |||
nextParams[key] = data.continue[key]; | |||
}); | |||
showStatus("Loading people... " + String(allPages.length)); | |||
return loadCategoryMembers(nextParams, allPages); | |||
} | |||
return allPages; | |||
}); | }); | ||
} | } | ||
function | function uniqueTitles(items) { | ||
var | var seen = {}; | ||
var | var titles = []; | ||
return | |||
items.forEach(function (item) { | |||
if (!item || !item.title || seen[item.title]) { | |||
return; | |||
} | |||
seen[item.title] = true; | |||
titles.push(item.title); | |||
}); | }); | ||
return titles; | |||
} | |||
function loadPageDetails(titles) { | |||
var groups = []; | |||
for (var index = 0; index < titles.length; index += 1) { | |||
groups.push(titles.slice(index, index + 1)); | |||
} | } | ||
return | return groups | ||
.reduce(function (chain, group) { | |||
return chain.then(function (pages) { | |||
return requestJson({ | |||
action: "query", | |||
titles: group.join("|"), | |||
prop: "extracts|pageimages|info", | |||
exintro: 1, | |||
explaintext: 1, | |||
exchars: 700, | |||
piprop: "thumbnail|original", | |||
pithumbsize: 1000, | |||
inprop: "url", | |||
redirects: 1, | |||
formatversion: 2, | |||
format: "json" | |||
}).then(function (data) { | |||
var nextPages = | |||
data && | |||
data.query && | |||
}) | Array.isArray(data.query.pages) | ||
? data.query.pages | |||
: []; | |||
if ( | |||
(pages.length + nextPages.length) % 10 === 0 || | |||
pages.length + nextPages.length === titles.length | |||
) { | |||
showStatus( | |||
"Loading details... " + | |||
String(pages.length + nextPages.length) + | |||
" / " + | |||
String(titles.length) | |||
); | |||
} | |||
return pages.concat(nextPages); | |||
}); | |||
}); | }); | ||
}, Promise.resolve([])); | |||
} | |||
var cachedPeople = readCache(); | |||
if (cachedPeople) { | |||
activateSlides(cachedPeople); | |||
} | |||
if (!window.fetch) { | |||
showStatus("This browser cannot load the people list."); | |||
return; | |||
} | |||
showStatus("Loading people..."); | |||
loadCategoryMembers( | |||
{ | |||
action: "query", | |||
list: "categorymembers", | |||
cmtitle: "Category:People", | |||
cmnamespace: 0, | |||
cmtype: "page", | |||
cmlimit: "max", | |||
formatversion: 2, | |||
format: "json" | |||
}, | |||
}); | [] | ||
})(); | ) | ||
</script> | .then(function (members) { | ||
var titles = uniqueTitles(members); | |||
showStatus("Loading details... 0 / " + String(titles.length)); | |||
return loadPageDetails(titles); | |||
}) | |||
.then(function (pages) { | |||
var loadedPeople = normalizePages(pages); | |||
saveCache(loadedPeople); | |||
activateSlides(loadedPeople); | |||
}) | |||
.catch(function () { | |||
showStatus("Could not load people list."); | |||
}); | |||
/* | |||
* Raw HTML links need a separate existence check so missing pages | |||
* keep MediaWiki's red-link appearance. | |||
*/ | |||
if (window.mw && mw.loader) { | |||
mw.loader | |||
.using(["mediawiki.api", "mediawiki.util"]) | |||
.then(function () { | |||
var api = new mw.Api(); | |||
var links = Array.prototype.slice.call( | |||
root.querySelectorAll("a[data-wiki-title]") | |||
); | |||
var titles = links | |||
.map(function (item) { | |||
return item.getAttribute("data-wiki-title"); | |||
}) | |||
.filter(function (item, index, allItems) { | |||
return item && allItems.indexOf(item) === index; | |||
}); | |||
if (!titles.length) { | |||
return; | |||
} | |||
return api | |||
.get({ | |||
action: "query", | |||
titles: titles.join("|"), | |||
formatversion: 2 | |||
}) | |||
.then(function (data) { | |||
var missing = {}; | |||
if (data.query && Array.isArray(data.query.pages)) { | |||
data.query.pages.forEach(function (page) { | |||
if (page.missing) { | |||
missing[page.title] = true; | |||
} | |||
}); | |||
} | |||
links.forEach(function (item) { | |||
var pageTitle = | |||
item.getAttribute("data-wiki-title"); | |||
if (!missing[pageTitle]) { | |||
return; | |||
} | |||
item.classList.add("new"); | |||
item.href = mw.util.getUrl(pageTitle, { | |||
action: "edit", | |||
redlink: 1 | |||
}); | |||
item.title = | |||
pageTitle + " (page does not exist)"; | |||
}); | |||
}); | |||
}); | |||
} | |||
}); | |||
})(); | |||
</script> | |||
</html> | </html> | ||
| Line 1,632: | Line 1,792: | ||
[[Category:Reference pages]] | [[Category:Reference pages]] | ||