MediaWiki:Common.js: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung Markierungen: Manuelle Zurücksetzung Zurückgesetzt |
Keine Bearbeitungszusammenfassung Markierungen: Manuelle Zurücksetzung Zurückgesetzt |
||
| Zeile 1: | Zeile 1: | ||
/* Eigene Sprachleiste: manuelles Umschalten + | /* Eigene Sprachleiste: manuelles Umschalten + stabile Navigation über Special:MyLanguage */ | ||
mw.loader.using(['mediawiki.util', 'mediawiki.api'], function () { | mw.loader.using(['mediawiki.util', 'mediawiki.api'], function () { | ||
| Zeile 26: | Zeile 26: | ||
code = String(code).toLowerCase().split('-')[0]; | code = String(code).toLowerCase().split('-')[0]; | ||
return ALLOWED.indexOf(code) > -1 ? code : FALLBACK; | return ALLOWED.indexOf(code) > -1 ? code : FALLBACK; | ||
} | |||
function getCurrentLang() { | |||
var u = new URL(window.location.href); | |||
var fromUrl = u.searchParams.get('uselang'); | |||
return normalize(fromUrl || null); | |||
} | } | ||
| Zeile 36: | Zeile 42: | ||
} | } | ||
// --- | // --- Falls uselang ungültig (z. B. ?uselang=frok) → einmalig auf gültig korrigieren --- | ||
(function fixInvalidUselangOnce() { | |||
var u = new URL(window.location.href); | |||
var raw = u.searchParams.get('uselang'); | |||
if (raw && normalize(raw) !== raw.toLowerCase().split('-')[0]) { | |||
u.searchParams.set('uselang', normalize(raw)); | |||
window.history.replaceState(null, '', u.toString()); // kein Reload, nur URL bereinigen | |||
(function | |||
var | |||
} | } | ||
})(); | })(); | ||
| Zeile 63: | Zeile 56: | ||
bar.id = 'custom-langbar'; | bar.id = 'custom-langbar'; | ||
var current = | var current = getCurrentLang() || | ||
normalize(mw.config.get('wgUserLanguage') || mw.config.get('wgContentLanguage') || FALLBACK); | |||
LANGS.forEach(function (lang) { | LANGS.forEach(function (lang) { | ||
| Zeile 96: | Zeile 84: | ||
} | } | ||
// Sprachwechsel: eingeloggte speichern; Gäste per | // Sprachwechsel: eingeloggte speichern; Gäste nur per URL-Parameter | ||
function switchLanguage(code) { | function switchLanguage(code) { | ||
code = normalize(code); | code = normalize(code); | ||
if (mw.config.get('wgUserName')) { | if (mw.config.get('wgUserName')) { | ||
| Zeile 112: | Zeile 99: | ||
} | } | ||
} | } | ||
// ---------- Link-Rewriting im Artikeltext ---------- | |||
// Alle internen Content-Links auf Special:MyLanguage/<Ziel> + aktuellen uselang umbiegen, | |||
// damit nicht auf falsche /xx-Unterseiten gesprungen wird. | |||
(function rewriteContentLinks() { | |||
var root = document.querySelector('.mw-parser-output'); | |||
if (!root) return; | |||
var curLang = getCurrentLang() || current; | |||
// Namespaces/Pattern, die wir NICHT anfassen | |||
var skipPrefixes = [ | |||
'Special:', 'Spezial:', 'File:', 'Datei:', 'Image:', 'Media:', 'MediaWiki:', | |||
'Template:', 'Vorlage:', 'Category:', 'Kategorie:', 'Help:', 'Hilfe:', | |||
'User:', 'Benutzer:', 'Talk:', 'Diskussion:' | |||
]; | |||
function shouldSkipTitle(title) { | |||
if (!title) return true; | |||
var t = title.replace(/_/g, ' '); | |||
return skipPrefixes.some(function (p) { return t.startsWith(p); }); | |||
} | |||
function getTitleFromHref(href) { | |||
try { | |||
var url = new URL(href, window.location.origin); | |||
// Extern? | |||
if (url.origin !== window.location.origin) return null; | |||
// Anchors | |||
if (url.hash && (url.pathname === window.location.pathname) && !url.searchParams.get('title')) return null; | |||
// /wiki/Title | |||
var m = url.pathname.match(/\/wiki\/(.+)$/); | |||
if (m && m[1]) { | |||
return decodeURIComponent(m[1]); | |||
} | |||
// /index.php?title=Title | |||
var t = url.searchParams.get('title'); | |||
if (t) return t; | |||
return null; | |||
} catch (e) { | |||
return null; | |||
} | |||
} | |||
function stripLangSuffix(title) { | |||
// Sprachsuffix am Ende entfernen (…/de, …/en, …/fr) | |||
return title.replace(/\/([a-z]{2})(?:-[a-z]{2})?$/i, ''); | |||
} | |||
root.querySelectorAll('a[href]').forEach(function (a) { | |||
var href = a.getAttribute('href'); | |||
if (!href || href.startsWith('#')) return; | |||
var title = getTitleFromHref(href); | |||
if (!title || shouldSkipTitle(title)) return; | |||
// Edit/History/Action-Links nicht anfassen | |||
if (/\b(action|oldid|diff)=/.test(href)) return; | |||
// Wenn Link bereits Special:MyLanguage ist, nur uselang sicherstellen | |||
if (/Special:MyLanguage\//i.test(title)) { | |||
var url = new URL(a.href, window.location.origin); | |||
if (!url.searchParams.get('uselang')) { | |||
url.searchParams.set('uselang', curLang); | |||
a.href = url.toString(); | |||
} | |||
return; | |||
} | |||
// Sprachsuffix entfernen und zu Special:MyLanguage umschreiben | |||
var base = stripLangSuffix(title); | |||
var newUrl = mw.util.getUrl('Special:MyLanguage/' + base.replace(/_/g, ' ')); | |||
newUrl += (newUrl.includes('?') ? '&' : '?') + 'uselang=' + curLang; | |||
// Fragment (#anchor) beibehalten | |||
try { | |||
var old = new URL(a.href, window.location.origin); | |||
if (old.hash) newUrl += old.hash; | |||
} catch (e) {} | |||
a.href = newUrl; | |||
}); | |||
})(); | |||
// Anonyme markieren (falls du CSS darauf hast) | // Anonyme markieren (falls du CSS darauf hast) | ||
Version vom 8. August 2025, 14:29 Uhr
/* Eigene Sprachleiste: manuelles Umschalten + stabile Navigation über Special:MyLanguage */
mw.loader.using(['mediawiki.util', 'mediawiki.api'], function () {
// --- Nur im Lesemodus + im Haupt-Namensraum (0) anzeigen ---
var action = mw.config.get('wgAction');
var ns = mw.config.get('wgNamespaceNumber');
if (action !== 'view' || ns !== 0) return;
// --- Sprachen definieren ---
var LANGS = [
{ code: 'de', label: 'Deutsch' },
{ code: 'en', label: 'English' },
{ code: 'fr', label: 'Français' }
];
var ALLOWED = ['de', 'en', 'fr'];
var FALLBACK = 'en';
// Doppelte Einbindung vermeiden
if (document.getElementById('custom-langbar')) return;
var pageName = mw.config.get('wgPageName'); // mit _ statt Leerzeichen
var baseTitle = pageName.replace(/\/[a-z]{2}(?:-[a-z]{2})?$/i, ''); // ggf. /de,/en,… abschneiden
function normalize(code) {
if (!code) return FALLBACK;
code = String(code).toLowerCase().split('-')[0];
return ALLOWED.indexOf(code) > -1 ? code : FALLBACK;
}
function getCurrentLang() {
var u = new URL(window.location.href);
var fromUrl = u.searchParams.get('uselang');
return normalize(fromUrl || null);
}
// Ziel-URL: gleiche Seite in gewünschter Sprache über Special:MyLanguage + uselang
function targetUrl(code) {
code = normalize(code);
var title = 'Special:MyLanguage/' + baseTitle.replace(/_/g, ' ');
var url = mw.util.getUrl(title);
return url + (url.includes('?') ? '&' : '?') + 'uselang=' + code;
}
// --- Falls uselang ungültig (z. B. ?uselang=frok) → einmalig auf gültig korrigieren ---
(function fixInvalidUselangOnce() {
var u = new URL(window.location.href);
var raw = u.searchParams.get('uselang');
if (raw && normalize(raw) !== raw.toLowerCase().split('-')[0]) {
u.searchParams.set('uselang', normalize(raw));
window.history.replaceState(null, '', u.toString()); // kein Reload, nur URL bereinigen
}
})();
// --- Bar bauen ---
var bar = document.createElement('div');
bar.id = 'custom-langbar';
var current = getCurrentLang() ||
normalize(mw.config.get('wgUserLanguage') || mw.config.get('wgContentLanguage') || FALLBACK);
LANGS.forEach(function (lang) {
var a = document.createElement('a');
a.href = '#';
a.textContent = lang.label;
if (current === lang.code) a.className = 'active-lang';
a.addEventListener('click', function (e) {
e.preventDefault();
switchLanguage(lang.code);
});
bar.appendChild(a);
});
// Sicher ins DOM hängen (Minerva/Vector kompatibel)
var mount =
document.querySelector('.minerva-header') ||
document.querySelector('.vector-header') ||
document.getElementById('content') ||
document.body;
if (mount && mount.parentNode) {
mount.parentNode.insertBefore(bar, mount.nextSibling);
} else {
document.body.insertBefore(bar, document.body.firstChild);
}
// Sprachwechsel: eingeloggte speichern; Gäste nur per URL-Parameter
function switchLanguage(code) {
code = normalize(code);
if (mw.config.get('wgUserName')) {
new mw.Api().postWithToken('csrf', {
action: 'options',
change: 'language=' + code
}).always(function () {
location.href = targetUrl(code);
});
} else {
location.href = targetUrl(code);
}
}
// ---------- Link-Rewriting im Artikeltext ----------
// Alle internen Content-Links auf Special:MyLanguage/<Ziel> + aktuellen uselang umbiegen,
// damit nicht auf falsche /xx-Unterseiten gesprungen wird.
(function rewriteContentLinks() {
var root = document.querySelector('.mw-parser-output');
if (!root) return;
var curLang = getCurrentLang() || current;
// Namespaces/Pattern, die wir NICHT anfassen
var skipPrefixes = [
'Special:', 'Spezial:', 'File:', 'Datei:', 'Image:', 'Media:', 'MediaWiki:',
'Template:', 'Vorlage:', 'Category:', 'Kategorie:', 'Help:', 'Hilfe:',
'User:', 'Benutzer:', 'Talk:', 'Diskussion:'
];
function shouldSkipTitle(title) {
if (!title) return true;
var t = title.replace(/_/g, ' ');
return skipPrefixes.some(function (p) { return t.startsWith(p); });
}
function getTitleFromHref(href) {
try {
var url = new URL(href, window.location.origin);
// Extern?
if (url.origin !== window.location.origin) return null;
// Anchors
if (url.hash && (url.pathname === window.location.pathname) && !url.searchParams.get('title')) return null;
// /wiki/Title
var m = url.pathname.match(/\/wiki\/(.+)$/);
if (m && m[1]) {
return decodeURIComponent(m[1]);
}
// /index.php?title=Title
var t = url.searchParams.get('title');
if (t) return t;
return null;
} catch (e) {
return null;
}
}
function stripLangSuffix(title) {
// Sprachsuffix am Ende entfernen (…/de, …/en, …/fr)
return title.replace(/\/([a-z]{2})(?:-[a-z]{2})?$/i, '');
}
root.querySelectorAll('a[href]').forEach(function (a) {
var href = a.getAttribute('href');
if (!href || href.startsWith('#')) return;
var title = getTitleFromHref(href);
if (!title || shouldSkipTitle(title)) return;
// Edit/History/Action-Links nicht anfassen
if (/\b(action|oldid|diff)=/.test(href)) return;
// Wenn Link bereits Special:MyLanguage ist, nur uselang sicherstellen
if (/Special:MyLanguage\//i.test(title)) {
var url = new URL(a.href, window.location.origin);
if (!url.searchParams.get('uselang')) {
url.searchParams.set('uselang', curLang);
a.href = url.toString();
}
return;
}
// Sprachsuffix entfernen und zu Special:MyLanguage umschreiben
var base = stripLangSuffix(title);
var newUrl = mw.util.getUrl('Special:MyLanguage/' + base.replace(/_/g, ' '));
newUrl += (newUrl.includes('?') ? '&' : '?') + 'uselang=' + curLang;
// Fragment (#anchor) beibehalten
try {
var old = new URL(a.href, window.location.origin);
if (old.hash) newUrl += old.hash;
} catch (e) {}
a.href = newUrl;
});
})();
// Anonyme markieren (falls du CSS darauf hast)
if (!mw.config.get('wgUserName')) {
document.documentElement.classList.add('bv-anon');
}
// Gäste nicht auf Diskussionsseiten lassen → zurück zur Inhaltseite
if (!mw.config.get('wgUserName')) {
var nsNum = mw.config.get('wgNamespaceNumber');
if (nsNum % 2 === 1) {
var subject = mw.util.getUrl(mw.config.get('wgPageName').replace(/^Talk:/, ''));
window.location.href = subject;
}
}
});