MediaWiki:Common.js
Aus quickguide.bitcointoolz.com
Zur Navigation springenZur Suche springen
Hinweis: Leere nach dem Veröffentlichen den Browser-Cache, um die Änderungen sehen zu können.
- Firefox/Safari: Umschalttaste drücken und gleichzeitig Aktualisieren anklicken oder entweder Strg+F5 oder Strg+R (⌘+R auf dem Mac) drücken
- Google Chrome: Umschalttaste+Strg+R (⌘+Umschalttaste+R auf dem Mac) drücken
- Internet Explorer/Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
- Opera: Strg+F5
console.log('[Common.js] My Common.js is running');
/* Das folgende JavaScript wird für alle Benutzer geladen. */
// Funktion, ob JavaScript geladen wird
//console.log('Common.js wird geladen');
// Funktion, um Benutzergruppen zu erkennen
mw.loader.using('mediawiki.user', function () {
mw.user.getGroups().done(function (groups) {
// Überprüfe, ob der Benutzer ein Admin ist (sysop-Gruppe)
if (groups.indexOf('sysop') === -1) {
// Verstecke den Link zu den Spezialseiten
$('a[href*="Special:SpecialPages"]').parent().hide();
// Verstecke den Link zu den Seiteninformationen
$('a[href*="Special:PageInformation"]').parent().hide();
// Verstecke den Link zu Änderungen an verlinkten Seiten
$('#t-recentchangeslinked').hide();
// Verstecke den Link zur Druckversion
$('#t-print').hide();
// Verstecke den Link zu Links auf diese Seite
$('#t-whatlinkshere').hide();
// Verstecke den Link zu den Spezialseiten (deutsch)
$('a[href*="Spezial:Spezialseiten"]').parent().hide();
// Verstecke den Link zu den Seiteninformationen (deutsch)
$('a[href*="Spezial:Seiteninformationen"]').parent().hide();
// Verstecke den Link zu Änderungen an verlinkten Seiten (deutsch)
$('a[href*="Spezial:Änderungen an verlinkten Seiten"]').parent().hide();
// Verstecke den Link zur Druckversion (deutsch)
$('#t-print').hide();
// Verstecke den Link zu Links auf diese Seite (deutsch)
$('a[href*="Spezial:Linkliste"]').parent().hide();
// Verstecke den Link zum permanenten Link (deutsch)
$('a[href*="Spezial:Permanenter_Link"]').parent().hide();
// Verstecke den Link zum permanenten Link (deutsch)
$('a[href*="oldid"]').parent().hide();
// Verstecke den Link zu Letzte Änderungen (deutsch)
$('a[href*="Spezial:Letzte_Änderungen"]').parent().hide();
$('#n-recentchanges').hide(); // Verstecke den Link zu Letzte Änderungen (ID)
}
});
});
// ********************************************************************************************************************
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// ********************************************************************************************************************
// *START************************ Fügt den CSS-Code für das schlagende Herz hinzu *************************************
mw.loader.using( 'mediawiki.util', function () {
var css = '.red-heart {' +
'color: #FB0000;' +
'font-size: 17px;' +
'animation: heartbeat 1.8s infinite ease-in-out;' +
'display: inline-block;' +
'vertical-align: middle;' +
'}' +
'@keyframes heartbeat {' +
'0%, 100% {' +
'transform: scale(0.8) translateY(-1px);' +
'opacity: 0.5;' +
'}' +
'25%, 75% {' +
'transform: scale(1.0) translateY(-1px);' +
'opacity: 1;' +
'}' +
'}';
var style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
document.getElementsByTagName('head')[0].appendChild(style);
});
// *************************************************************
mw.loader.using('mediawiki.util', function () {
// Erstelle das neue Element für den Text unter dem Logo
var logoText = document.createElement('div');
logoText.innerHTML = '<strong>We <span class="red-heart" style="position: relative; top: -3px;">❤️</span><span style="color: #ff5000; font-size: 17px;"> ₿</span>itcoin</strong>'; // Setzt das ₿-Symbol in Orange und größer
logoText.style.textAlign = 'center'; // Zentriert den Text
logoText.style.marginTop = '-20px'; // Fügt Abstand zum Logo hinzu
logoText.style.marginLeft = '-5px'; // Verschiebt den Text 10px nach links
// Füge das Element unter dem Logo hinzu
var logoContainer = document.getElementById('p-logo');
if (logoContainer) {
logoContainer.appendChild(logoText);
}
});
// *****************************************
mw.loader.using('mediawiki.util', function () {
// Finde den Container des Logos (#p-logo)
var logoContainer = document.getElementById('p-logo');
// Wenn das Logo existiert, verschiebe es um 5px nach oben und 10px nach rechts
if (logoContainer) {
logoContainer.style.marginTop = '-5px'; // Verschiebt das Logo um -5px nach oben
logoContainer.style.marginLeft = '5px'; // Verschiebt das Logo um 5px nach rechts
}
});
// *ENDE************************* Fügt den CSS-Code für das schlagende Herz hinzu *************************************
// ********************************************************************************************************************
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// ********************************************************************************************************************
// *START*********************************** ₿-Rakete "To the Moon" ***************************************************
(function($, mw) {
$(function() {
// Überprüfen, ob der "Nach oben"-Container bereits existiert
if ($('#back-to-top-container').length === 0) {
// Erstelle den Container für den Button und die Animationen
var $backToTopContainer = $('<div id="back-to-top-container"></div>').css({
position: 'fixed', // Fixiert den Container am Bildschirm
bottom: '20px', // Abstand vom unteren Bildschirmrand
right: '20px', // Abstand vom rechten Bildschirmrand
width: '50px', // Breite des Containers
textAlign: 'center', // Zentriert den Inhalt horizontal
zIndex: '1000' // Platzierung über anderen Elementen
}).appendTo('body');
// Initialer Text "To the Top"
var $backToTopText = $('<div id="back-to-top-text">To <br>the<br>Top</div>').css({
fontSize: '12pt', // Schriftgröße des Textes
color: 'rgba(255, 96, 0, 0.8)', // Schriftfarbe mit Transparenz
backgroundColor: 'rgba(255, 255, 255, 0.8)', // Hintergrundfarbe mit Transparenz
padding: '5px', // Innenabstand des Textcontainers
borderRadius: '15px', // Abgerundete Ecken
marginBottom: '10px', // Abstand nach unten
marginLeft: '-3px', // Leichte Verschiebung nach links
position: 'relative', // Relative Positionierung
zIndex: '1' // Niedriger z-index für die z-Achsen-Ordnung
}).appendTo($backToTopContainer);
// Bitcoin-Symbol für die Animation
var $bitcoin = $('<div id="bitcoin">₿</div>').css({
position: 'absolute', // Absolute Positionierung für freie Bewegung
bottom: '75px', // Startposition von unten
left: '50%', // Horizontale Zentrierung
transform: 'translateX(-50%)', // Korrekte Zentrierung
fontSize: '28px', // Schriftgröße
fontWeight: 'bold', // Fettschrift
color: '#FF6000', // Bitcoin Orange
opacity: '0', // Unsichtbar bis zur Animation
zIndex: '2' // Höherer z-index für Vordergrund
}).appendTo($backToTopContainer);
// Raketen-Symbol für die Animation
var $rocket = $('<div id="rocket">🚀</div>').css({
position: 'absolute', // Absolute Positionierung für freie Bewegung
bottom: '42px', // Startposition von unten
left: '50%', // Horizontale Zentrierung
transform: 'translateX(-50%) rotate(-45deg)', // Zentrierung und Drehung
fontSize: '24px', // Schriftgröße
opacity: '0', // Unsichtbar bis zur Animation
zIndex: '2' // Höherer z-index für Vordergrund
}).appendTo($backToTopContainer);
// "Nach oben"-Button
var $backToTopButton = $('<div id="back-to-top">▲</div>').css({
width: '50px', // Breite des Buttons
height: '50px', // Höhe des Buttons
backgroundColor: 'rgba(255, 96, 0, 0.5)', // Hintergrundfarbe mit Transparenz
color: '#fff', // Schriftfarbe
lineHeight: '50px', // Vertikale Zentrierung des Pfeils
fontSize: '22px', // Schriftgröße des Pfeils
fontWeight: 'bold', // Schriftart des Pfeils
borderRadius: '50%', // Runde Form
cursor: 'pointer', // Hand-Cursor bei Hover
opacity: '0.6', // Anfangs-Transparenz
textAlign: 'center', // Zentrierung des Pfeils
position: 'relative', // Relative Positionierung
zIndex: '1' // Gleicher z-index wie der Text
}).appendTo($backToTopContainer);
// Klick-Ereignis für den Button (scrollt nach oben)
$backToTopButton.on('click', function() {
$('html, body').animate({ scrollTop: 0 }, 'slow');
});
// Variable, um den Animationsstatus zu verfolgen
var isAnimating = false;
// Hover-Ereignis für den Button
$backToTopButton.hover(
function() {
$(this).css('opacity', '0.9');
// Prüfen, ob bereits eine Animation läuft
if (!isAnimating) {
isAnimating = true; // Animation wird gestartet
// Text zu "To the Moon" ändern
$backToTopText.fadeOut('slow', function() {
$backToTopText.html('„To <br>the<br>Moon!“').fadeIn('slow');
});
// Bitcoin-Symbol animieren
$bitcoin.stop(true, true).css({ bottom: '75px', opacity: '1' }).animate(
{ bottom: '485px', opacity: '0' },
3000
);
// Rakete animieren
$rocket.stop(true, true).css({ bottom: '42px', opacity: '1' }).animate(
{ bottom: '360px', opacity: '0' },
3000,
function() {
// Nach Abschluss der Raketenanimation
$rocket.css({ bottom: '42px', opacity: '0' });
$bitcoin.css({ bottom: '75px', opacity: '0' });
// Text langsam zurück zu "To the Top" ändern
$backToTopText.fadeOut('slow', function() {
$backToTopText.html('To <br>the<br>Top').fadeIn('slow');
});
isAnimating = false; // Animation ist beendet
}
);
}
},
function() {
// Zurücksetzen der Button-Transparenz beim Verlassen des Hover-Effekts
$(this).css('opacity', '0.6');
}
);
// Button anzeigen
$backToTopButton.show();
}
});
})(jQuery, mediaWiki);
// *ENDE************************************ ₿-Rakete "To the Moon" ***************************************************
// ********************************************************************************************************************
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// ********************************************************************************************************************
// *START********************* Script zum täglichen Abruf und Einfügen des Bitcoin-Kurses 2024-10-05 ******************
$(document).ready(function() {
console.log("Document is ready - Starting Bitcoin price script");
// Variable zum Zwischenspeichern der zuletzt abgerufenen Bitcoin-Kursdaten
var cachedBitcoinData = null;
var lastUpdateTime = null;
// Funktion zum Abrufen des Bitcoin-Kurses von der CoinGecko API mit Ratenbegrenzung
function fetchWithRateLimit(url) {
console.log("[fetchWithRateLimit] URL: ", url);
const maxRequestsPerMinute = 3;
if (!window.requestCount) {
window.requestCount = 0;
}
if (!window.requestTimer) {
window.requestTimer = setInterval(function () {
window.requestCount = 0; // Reset alle 60 Sekunden
console.log("[fetchWithRateLimit] Request count reset");
}, 60000);
}
if (window.requestCount >= maxRequestsPerMinute) {
console.warn("[fetchWithRateLimit] Max requests per minute reached");
return Promise.reject(new Error('Maximale Anfragenanzahl erreicht. Bitte warten.'));
}
window.requestCount++;
console.log("[fetchWithRateLimit] Request count incremented: ", window.requestCount);
return fetch(url).then(function(response) {
console.log("[fetchWithRateLimit] Fetch response status: ", response.status);
if (!response.ok) {
throw new Error('Fehler bei der Anfrage: ' + response.statusText);
}
return response;
}).catch(function(error) {
console.error('[fetchWithRateLimit] Fehler bei der Anfrage:', error);
throw error; // Fehler weiterreichen, um sicherzustellen, dass sie ordnungsgemäß behandelt werden
});
}
// Funktion zum Abrufen des Bitcoin-Kurses über die CoinGecko-API
function getBitcoinPrice(callback) {
console.log("[getBitcoinPrice] Fetching Bitcoin price from CoinGecko...");
fetchWithRateLimit('https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd,eur')
.then(function(response) {
console.log("[getBitcoinPrice] Response received");
if (!response.ok) {
if (response.status === 429) {
throw new Error('[getBitcoinPrice] Zu viele Anfragen - Bitte versuche es später erneut');
} else {
throw new Error('[getBitcoinPrice] Netzwerkantwort war nicht ok');
}
}
return response.json();
})
.then(function(data) {
console.log("[getBitcoinPrice] Response data: ", data);
if (data && data.bitcoin && typeof data.bitcoin.usd === 'number' && typeof data.bitcoin.eur === 'number') {
console.log("[getBitcoinPrice] Bitcoin price successfully fetched");
cachedBitcoinData = data;
lastUpdateTime = formatTime();
callback(null, data);
} else {
throw new Error("[getBitcoinPrice] Unerwartete Datenstruktur von der API");
}
})
.catch(function(error) {
console.error('[getBitcoinPrice] Fehler beim Abrufen des ₿itcoin-Kurses:', error);
callback(new Error('[getBitcoinPrice] Abruf fehlgeschlagen'), null);
});
}
// Funktion zum Formatieren der Kurswerte in Euro und Dollar
function formatCurrency(value, currency) {
console.log("[formatCurrency] Formatting value: ", value, " Currency: ", currency);
return value.toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' ' + currency;
}
// Funktion zum Formatieren von Datum und Zeit
function formatTime() {
var now = new Date();
var year = now.getFullYear();
var month = (now.getMonth() + 1).toString().padStart(2, '0');
var day = now.getDate().toString().padStart(2, '0');
var hours = now.getHours().toString().padStart(2, '0');
var minutes = now.getMinutes().toString().padStart(2, '0');
var formattedTime = year + '-' + month + '-' + day + '; ' + hours + ':' + minutes + ' Uhr';
console.log("[formatTime] Formatted time: ", formattedTime);
return formattedTime;
}
// Funktion zum Setzen des Bitcoin-Kurses im MediaWiki
function setBitcoinPrice() {
console.log("[setBitcoinPrice] Setting Bitcoin price...");
var placeholders = document.querySelectorAll('.bitcoin-price-placeholder');
if (placeholders.length === 0) {
console.warn("[setBitcoinPrice] Kein Platzhalter für Bitcoin-Kurs gefunden, Abbruch...");
return;
}
placeholders.forEach(function (placeholder) {
placeholder.textContent = 'Lade ₿itcoin-Kurs...';
});
getBitcoinPrice(function (error, data) {
if (!error && data && data.bitcoin) {
var bitcoinPriceUSD = data.bitcoin.usd;
var bitcoinPriceEUR = data.bitcoin.eur;
var currentTime = formatTime();
var formattedPrice = "<strong>₿itcoin-Kurs: $ " + formatCurrency(bitcoinPriceUSD, '') + " = " + formatCurrency(bitcoinPriceEUR, '€') + "</strong>";
formattedPrice += "<br><span style=\"font-size:10px; color: #555555;\">(Stand: " + currentTime + " von <a href='https://www.coingecko.com/' target='_blank' style='color:black;'>CoinGecko</a>; ohne Gewähr)</span>";
placeholders.forEach(function (placeholder) {
placeholder.innerHTML = formattedPrice;
});
} else {
console.error("[setBitcoinPrice] Fehler beim Abrufen des Bitcoin-Kurses, Daten nicht verfügbar");
placeholders.forEach(function (placeholder) {
placeholder.textContent = 'Fehler beim Abrufen des ₿itcoin-Kurses. Bitte später erneut versuchen.';
});
}
});
}
// Funktion zum Starten des täglichen Updates des Bitcoin-Kurses
function startDailyBitcoinUpdate() {
console.log("[startDailyBitcoinUpdate] Starting daily Bitcoin update...");
setBitcoinPrice();
var now = new Date();
var nextMidnight = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 0);
var timeToMidnight = nextMidnight - now;
console.log("[startDailyBitcoinUpdate] Time to midnight: ", timeToMidnight);
setTimeout(function () {
console.log("[startDailyBitcoinUpdate] Updating Bitcoin price at midnight...");
setBitcoinPrice();
setInterval(setBitcoinPrice, 24 * 60 * 60 * 1000);
}, timeToMidnight);
}
// Funktion zum Anzeigen des Bitcoin-Kurses als Tooltip beim Überfahren des Logos
function addTooltipForLogo() {
function applyTooltipStyles() {
var tooltip = document.getElementById('bitcoin-price-tooltip');
if (tooltip) {
tooltip.style.position = 'absolute';
tooltip.style.display = 'none';
tooltip.style.border = '1px solid black';
tooltip.style.backgroundColor = '#696969';
tooltip.style.borderRadius = '5%';
tooltip.style.padding = '10px';
tooltip.style.color = 'white';
tooltip.style.zIndex = '1000';
tooltip.style.pointerEvents = 'none';
console.log("[applyTooltipStyles] Tooltip styles applied");
}
}
var logoElement = document.querySelector('#p-logo a, #p-logo img');
if (!logoElement) {
console.error('[addTooltipForLogo] Logo-Element nicht gefunden.');
return;
}
var tooltip = document.createElement('div');
tooltip.id = 'bitcoin-price-tooltip';
tooltip.className = 'bitcoin-tooltip';
document.body.appendChild(tooltip);
applyTooltipStyles();
logoElement.addEventListener('mouseenter', function(event) {
console.log("[addTooltipForLogo] Mouse entered logo");
if (cachedBitcoinData) {
updateTooltipContent(event, cachedBitcoinData);
tooltip.style.display = 'block';
} else {
getBitcoinPrice(function (error, data) {
if (!error && data) {
updateTooltipContent(event, data);
tooltip.style.display = 'block';
}
});
}
});
logoElement.addEventListener('mousemove', function(event) {
tooltip.style.left = (event.pageX + 10) + 'px';
tooltip.style.top = (event.pageY + 10) + 'px';
console.log("[addTooltipForLogo] Tooltip position updated");
});
logoElement.addEventListener('mouseleave', function() {
console.log("[addTooltipForLogo] Mouse left logo");
tooltip.style.display = 'none';
});
function updateTooltipContent(event, data) {
var bitcoinPriceUSD = data.bitcoin.usd;
var bitcoinPriceEUR = data.bitcoin.eur;
var tooltipContent = "<div style='text-align:center;'>" +
"<span style='font-size:18px; font-weight:bold;'>₿itcoin-Kurs: $ </span>" +
"<span style='font-size:18px; color:orange;'>" + bitcoinPriceUSD.toLocaleString('de-DE', { minimumFractionDigits: 0, maximumFractionDigits: 0 }) + "</span>" +
"<span style='font-size:18px; color:white; padding: 0 5px;'> = </span>" +
"<span style='font-size:18px; color:orange;'>" + bitcoinPriceEUR.toLocaleString('de-DE', { minimumFractionDigits: 0, maximumFractionDigits: 0 }) + "</span>" +
"<span style='font-size:18px; font-weight:bold;'> € </span></div>" +
"<br><div style='font-size:10px; text-align:right;'>(Stand: " + lastUpdateTime + " von <a href='https://www.coingecko.com/' target='_blank' style='color:black;'>CoinGecko</a>; ohne Gewähr)</div>";
tooltip.innerHTML = tooltipContent;
tooltip.style.left = (event.pageX + 10) + 'px';
tooltip.style.top = (event.pageY + 10) + 'px';
console.log("[updateTooltipContent] Tooltip content updated");
}
}
// Starte das tägliche Update, um den Bitcoin-Kurs automatisch zu aktualisieren
startDailyBitcoinUpdate();
// Füge die Tooltip-Funktionalität zum Logo hinzu
addTooltipForLogo();
});
// *ENDE********************* Script zum täglichen Abruf und Einfügen des Bitcoin-Kurses 2024-10-05 *******************
// ********************************************************************************************************************
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// ********************************************************************************************************************
// *START************************** Übersetzungen mit Google-API OHNE iframe-Einbindungen *****************************
// ********************************************************************************************************************
// Google API Übersetzung Dropdown mit Benutzerspracheinstellungen
var selectImportant, selectAll;
// Funktion zur Erstellung der Dropdown-Menüs für wichtige und alle weiteren Sprachen
function createTranslateDropdowns() {
// Container für die Dropdown-Menüs erstellen
var container = document.createElement('div');
container.id = 'translate_container';
container.style.position = 'fixed'; // Fixierte Position, damit der Container immer sichtbar bleibt
container.style.top = '5px'; // Abstand vom oberen Rand des Fensters
container.style.left = '0px'; // Abstand vom linken Rand des Fensters
container.style.width = '95%'; // Passt die Breite des Containers an, um auf mobilen Geräten sichtbar zu sein
container.style.maxWidth = '380px'; // Maximale Breite für größere Bildschirme
container.style.height = 'auto'; // Höhe wird automatisch basierend auf dem Inhalt angepasst
container.style.backgroundColor = 'rgba(255, 255, 255, 0.8)'; // Halbtransparente Hintergrundfarbe für bessere Lesbarkeit
container.style.border = '1px solid #aaa'; // Rahmen um den Container in hellem Grau (#aaa)
container.style.padding = '5px'; // Innenabstand innerhalb des Containers (5px auf allen Seiten)
container.style.zIndex = '1000'; // Stellt sicher, dass der Container über anderen Elementen auf der Seite liegt
container.style.display = 'flex'; // Flexbox für einfaches Layout der Dropdown-Elemente
container.style.flexDirection = 'row'; // Elemente im Container werden horizontal nebeneinander angezeigt
container.style.flexWrap = 'wrap'; // Wenn die Breite nicht ausreicht, werden die Elemente umgebrochen
container.style.justifyContent = 'space-between'; // Die Dropdowns werden mit gleichem Abstand dazwischen verteilt
document.body.appendChild(container);
// Wrapper für die wichtigen Sprachen erstellen
var importantWrapper = document.createElement('div');
importantWrapper.style.display = 'inline-block';
importantWrapper.style.marginBottom = '0px'; // Kein Abstand nach unten
// Label für wichtige Sprachen erstellen
var importantLabel = document.createElement('label');
importantLabel.textContent = 'Translate to:'; // Beschriftung für das Dropdown-Menü
importantLabel.classList.add('no-translate'); // Klasse, damit das Label nicht übersetzt wird
importantLabel.style.fontWeight = 'bold'; // Fettschrift für bessere Lesbarkeit
importantLabel.style.marginRight = '2px'; // Abstand zwischen Label und Dropdown
importantLabel.style.fontSize = '0.8em';
importantLabel.style.fontFamily = 'Arial, sans-serif';
importantWrapper.appendChild(importantLabel);
// Dropdown für wichtige Sprachen erstellen
selectImportant = createDropdown('important_languages', 'Main Languages', getImportantLanguages());
selectImportant.style.width = '100px'; // Breite des Dropdowns
selectImportant.style.padding = '2px'; // Innenabstand innerhalb des Dropdowns
selectImportant.style.marginRight = '2px'; // Abstand zwischen Dropdown und weiteren Elementen
selectImportant.style.borderRadius = '1px'; // Leichte Abrundung der Ecken
selectImportant.style.fontFamily = 'Arial, sans-serif';
selectImportant.style.fontSize = '0.8em';
importantWrapper.appendChild(selectImportant);
container.appendChild(importantWrapper);
// Wrapper für alle Sprachen erstellen
var allWrapper = document.createElement('div');
allWrapper.style.display = 'inline-block';
allWrapper.style.marginLeft = '5px'; // Abstand links zwischen dem Wrapper und anderen Elementen
allWrapper.style.marginBottom = '0px'; // Kein Abstand nach unten
// Label für alle Sprachen erstellen
var allLabel = document.createElement('label');
allLabel.textContent = 'All:'; // Beschriftung für das Dropdown-Menü
allLabel.classList.add('no-translate'); // Klasse, damit das Label nicht übersetzt wird
allLabel.style.fontWeight = 'bold'; // Fettschrift für bessere Lesbarkeit
allLabel.style.marginRight = '2px'; // Abstand zwischen Label und Dropdown
allLabel.style.fontSize = '0.8em';
allLabel.style.fontFamily = 'Arial, sans-serif';
allWrapper.appendChild(allLabel);
// Dropdown für alle Sprachen erstellen
selectAll = createDropdown('all_languages', 'Select Of All', getAllLanguages());
selectAll.style.width = '115px'; // Breite des Dropdowns
selectAll.style.padding = '2px'; // Innenabstand innerhalb des Dropdowns
selectAll.style.marginRight = '4px'; // Abstand rechts vom Dropdown zum nächsten Element
selectAll.style.borderRadius = '2px'; // Leichte Abrundung der Ecken
selectAll.style.fontFamily = 'Arial, sans-serif';
selectAll.style.fontSize = '0.8em';
allWrapper.appendChild(selectAll);
container.appendChild(allWrapper);
// Event Listener für Sprachänderungen hinzufügen
selectImportant.addEventListener('change', function () {
if (selectImportant.value !== 'de') {
handleLanguageChange(selectImportant.value)
.then(function() {
localStorage.setItem('selectedLanguage', selectImportant.value); // Speichert die ausgewählte Sprache lokal
syncDropdowns(selectImportant.value); // Synchronisiert die Dropdowns
})
.catch(function(error) {
console.error("[selectImportant] Fehler bei der Sprachänderung: ", error);
});
} else {
resetToDefaultLanguage(); // Setzt die Sprache auf Deutsch zurück, wenn 'de' ausgewählt ist
}
});
selectAll.addEventListener('change', function () {
if (selectAll.value !== 'de') {
handleLanguageChange(selectAll.value)
.then(function() {
localStorage.setItem('selectedLanguage', selectAll.value); // Speichert die ausgewählte Sprache lokal
syncDropdowns(selectAll.value); // Synchronisiert die Dropdowns
})
.catch(function(error) {
console.error("[selectAll] Fehler bei der Sprachänderung: ", error);
});
} else {
resetToDefaultLanguage(); // Setzt die Sprache auf Deutsch zurück, wenn 'de' ausgewählt ist
}
});
}
// Erstellt ein Dropdown-Menü
function createDropdown(id, placeholderText, languages) {
var select = document.createElement('select');
select.id = id;
select.style.padding = '2px'; // Innenabstand des Dropdowns
select.style.marginRight = '4px'; // Abstand rechts vom Dropdown, um Platz zwischen Elementen zu schaffen
select.style.borderRadius = '0'; // Keine abgerundeten Ecken, um das Dropdown rechteckig zu halten
select.style.fontFamily = 'Arial, sans-serif'; // Konsistente Schriftart
select.style.fontSize = '0.8em'; // Schriftgröße reduziert für ein kompakteres Layout
// Platzhalteroption erstellen
var placeholderOption = document.createElement('option');
placeholderOption.value = '';
placeholderOption.textContent = placeholderText; // Platzhaltertext, der angezeigt wird, bevor eine Auswahl getroffen wird
placeholderOption.disabled = true; // Platzhalteroption kann nicht ausgewählt werden
placeholderOption.selected = true; // Platzhalter ist standardmäßig ausgewählt
select.appendChild(placeholderOption);
// Optionen für Sprachen hinzufügen
for (var i = 0; i < languages.length; i++) {
var lang = languages[i];
var option = document.createElement('option');
option.value = lang.lang;
option.textContent = lang.name; // Name der Sprache, die im Dropdown angezeigt wird
option.style.fontFamily = 'Arial, sans-serif';
option.style.fontSize = '1.0em';
select.appendChild(option);
}
return select;
}
// Wichtige Sprachen - Rückgabe einer Liste der wichtigsten Sprachen
function getImportantLanguages() {
return [
{ lang: 'de', name: '⟶ German (orig.)' },
{ lang: 'en', name: 'English' },
{ lang: 'es', name: 'Spanish' },
{ lang: 'zh-CN', name: 'Chinese (Simp.)' },
{ lang: 'fr', name: 'French' },
{ lang: 'pt', name: 'Portuguese' },
{ lang: 'ru', name: 'Russian' },
{ lang: 'ja', name: 'Japanese' },
{ lang: 'ko', name: 'Korean' },
{ lang: 'it', name: 'Italian' }
];
}
// Alle Sprachen - Rückgabe einer Liste aller unterstützten Sprachen
function getAllLanguages() {
return [
{ lang: 'af', name: 'Afrikaans' }, { lang: 'am', name: 'Amharic' }, { lang: 'ar', name: 'Arabic' },
{ lang: 'az', name: 'Azerbaijani' }, { lang: 'be', name: 'Belarusian' }, { lang: 'bg', name: 'Bulgarian' },
{ lang: 'bn', name: 'Bengali' }, { lang: 'bs', name: 'Bosnian' }, { lang: 'ca', name: 'Catalan' },
{ lang: 'zh-CN', name: 'Chinese (Simp.)' }, { lang: 'zh-TW', name: 'Chinese (Trad.)' },
{ lang: 'hr', name: 'Croatian' }, { lang: 'cs', name: 'Czech' }, { lang: 'da', name: 'Danish' },
{ lang: 'nl', name: 'Dutch' }, { lang: 'en', name: 'English' }, { lang: 'et', name: 'Estonian' },
{ lang: 'tl', name: 'Filipino' }, { lang: 'fi', name: 'Finnish' }, { lang: 'fr', name: 'French' },
{ lang: 'de', name: '⟶ German (orig.)' }, { lang: 'el', name: 'Greek' }, { lang: 'gu', name: 'Gujarati' },
{ lang: 'he', name: 'Hebrew' }, { lang: 'hi', name: 'Hindi' }, { lang: 'hu', name: 'Hungarian' },
{ lang: 'is', name: 'Icelandic' }, { lang: 'id', name: 'Indonesian' }, { lang: 'it', name: 'Italian' },
{ lang: 'ja', name: 'Japanese' }, { lang: 'kn', name: 'Kannada' }, { lang: 'ko', name: 'Korean' },
{ lang: 'lv', name: 'Latvian' }, { lang: 'lt', name: 'Lithuanian' }, { lang: 'ms', name: 'Malay' },
{ lang: 'ml', name: 'Malayalam' }, { lang: 'mr', name: 'Marathi' }, { lang: 'ne', name: 'Nepali' },
{ lang: 'no', name: 'Norwegian' }, { lang: 'fa', name: 'Persian' }, { lang: 'pl', name: 'Polish' },
{ lang: 'pt', name: 'Portuguese' }, { lang: 'pa', name: 'Punjabi' }, { lang: 'ro', name: 'Romanian' },
{ lang: 'ru', name: 'Russian' }, { lang: 'sr', name: 'Serbian' }, { lang: 'sk', name: 'Slovak' },
{ lang: 'sl', name: 'Slovenian' }, { lang: 'es', name: 'Spanish' }, { lang: 'sw', name: 'Swahili' },
{ lang: 'sv', name: 'Swedish' }, { lang: 'ta', name: 'Tamil' }, { lang: 'te', name: 'Telugu' },
{ lang: 'th', name: 'Thai' }, { lang: 'tr', name: 'Turkish' }, { lang: 'uk', name: 'Ukrainian' },
{ lang: 'ur', name: 'Urdu' }, { lang: 'vi', name: 'Vietnamese' }, { lang: 'cy', name: 'Welsh' },
{ lang: 'zu', name: 'Zulu' }
];
}
// Sprachänderungsfunktion mit Google Translate API
function handleLanguageChange(selectedLang) {
return new Promise(function(resolve, reject) {
var googleTranslateApiUrl = "https://translation.googleapis.com/language/translate/v2";
var apiKey = "AIzaSyBe4xJokSKneAvA_7_aaU984vS2R8gSFtM";
if (selectedLang !== "" && selectedLang !== "de") {
var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);
var nodes = [];
var node;
// Durchlaufen aller Textknoten im Dokument
while ((node = walker.nextNode())) {
if (node.nodeValue.trim() !== "") {
nodes.push(node); // Füge alle Textknoten hinzu, die nicht leer sind
}
}
var maxTextLength = 500; // Maximal erlaubte Textlänge für eine Anfrage
var textGroups = [];
var currentGroup = [];
var currentLength = 0;
// Gruppiere die Textknoten basierend auf der maximalen Textlänge
nodes.forEach(function (textNode) {
if (currentLength + textNode.nodeValue.length > maxTextLength) {
textGroups.push(currentGroup);
currentGroup = [];
currentLength = 0;
}
currentGroup.push(textNode);
currentLength += textNode.nodeValue.length;
});
if (currentGroup.length > 0) {
textGroups.push(currentGroup);
}
// Sende jede Textgruppe zur Übersetzung
var groupPromises = textGroups.map(function (group) {
var textToTranslateArray = group.map(function (textNode) {
return textNode.nodeValue;
});
return fetch(googleTranslateApiUrl + "?key=" + apiKey, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
q: textToTranslateArray,
source: "de",
target: selectedLang,
format: "text"
})
}).then(function (response) {
if (!response.ok) {
throw new Error("Netzwerkantwort war nicht ok");
}
return response.json();
}).then(function (data) {
if (data.data && data.data.translations) {
for (var i = 0; i < data.data.translations.length; i++) {
group[i].nodeValue = " " + data.data.translations[i].translatedText + " "; // Leerzeichen erhalten
}
console.log("Übersetzung erfolgreich");
} else {
throw new Error("Fehlerhafte Antwort von der Übersetzungs-API");
}
});
});
Promise.all(groupPromises).then(function() {
resolve();
}).catch(function (error) {
console.error("Fehler bei der Übersetzung: ", error);
reject(error);
});
} else {
resolve();
}
});
}
// Setzt die Sprache zurück auf die Standardsprache Deutsch
function resetToDefaultLanguage() {
localStorage.removeItem('selectedLanguage'); // Entfernt die gespeicherte Sprache
window.location.reload(); // Lädt die Seite neu, um die Standard-Sprache anzuwenden
}
// Synchronisiert beide Dropdowns
function syncDropdowns(selectedLang) {
if (selectImportant) selectImportant.value = selectedLang;
if (selectAll) selectAll.value = selectedLang;
}
// Google Translate Script laden und Dropdown-Menü erstellen
function initializeTranslationFeature() {
createTranslateDropdowns(); // Erstellt die Dropdown-Menüs
var savedLanguage = localStorage.getItem('selectedLanguage'); // Holt die gespeicherte Sprache
if (savedLanguage && savedLanguage !== 'de') {
handleLanguageChange(savedLanguage).then(function() {
syncDropdowns(savedLanguage); // Synchronisiert die Dropdowns
}).catch(function(error) {
console.error("[initializeTranslationFeature] Fehler bei der Sprachänderung: ", error);
});
} else {
syncDropdowns('de'); // Setzt die Dropdowns auf die Standardsprache
}
}
// Document ready
$(document).ready(function () {
document.body.style.paddingTop = '75px'; // Abstand vom oberen Rand der Seite, um sicherzustellen, dass der Inhalt nicht überlagert wird
initializeTranslationFeature(); // Initialisiert die Übersetzungsfunktion
});
// *ENDE*************************** Übersetzungen mit Google-API OHNE iframe-Einbindungen *****************************
// ********************************************************************************************************************
// ********************************************************************************************************************
// *START********************* Script zum dynamischen Aufbau des E-Mail-Share-Links 2025-05-28 *********************
mw.loader.using('mediawiki.util', function() {
$(function(){
var title = mw.config.get('wgTitle'),
page = mw.config.get('wgPageName'),
server = mw.config.get('wgServer'),
script = mw.config.get('wgScriptPath'),
fullUrl = server + script + '/index.php?title=' + encodeURIComponent(page),
subject = encodeURIComponent(
'Entdecke den tollen Bitcoin-Wiki-Artikel zum Thema »' + title + '«'
),
body = encodeURIComponent(
'Hey, du Krypto-Fan! Entdecke jetzt den tollen Bitcoin-Wiki-Artikel zum Thema »'
+ title
+ '« unter '
+ fullUrl
),
mailto = 'mailto:info@example.org?subject=' + subject + '&body=' + body,
link = '<a href="' + mailto + '">Jetzt per E-Mail teilen✉</a>';
$('#share-email-placeholder').html(link);
});
});
// *ENDE********************* Script zum dynamischen Aufbau des E-Mail-Share-Links 2025-05-28 *******************
// ********************************************************************************************************************
/**
* Unmined-Bitcoin-Skript für MediaWiki:Common.js
*
* Dieses Skript holt alle fünf Minuten die aktuelle Anzahl der bereits geminten Bitcoins von der CoinGecko-API (serverseitig via PHP-Proxy)
* ab, berechnet daraus die verbleibende Anzahl bis zur Obergrenze von 21 000 000, formatiert das Ergebnis in deutscher Schreibweise
* mit Punkten als Tausender-Trennzeichen und gibt es in einem DIV-Container im Wiki-Artikel aus.
*
* Ablauf:
* 1. Sobald der DOM fertig geladen ist (jQuery(document).ready), wird geprüft, ob der DIV-Container mit der ID "unmined-btc-widget" existiert.
* Ist der Container nicht vorhanden, bricht das Skript ab.
*
* 2. Über die Funktion fetchRemainingBTC() wird via jQuery.ajax eine JSON-Anfrage an den PHP-Proxy auf Deinem Server gestellt:
* URL: https://test.toepperwien.de/unmined_bitcoin/unmined_btc.php
*
* Der PHP-Proxy:
* • Ruft serverseitig die CoinGecko-API ab (https://api.coingecko.com/api/v3/coins/bitcoin).
* • Berechnet auf dem Server den verbleibenden Bitcoin-Betrag (21 000 000 − circulating_supply) und gibt ein JSON zurück:
* {
* "circulating_supply": 19xxxxxx,
* "remaining": 1xxxxxx
* }
* • Setzt in der HTTP-Antwort zwingend den Header Access-Control-Allow-Origin: *,
* damit der Browser keine CORS-Fehler wirft.
*
* 3. Im success-Callback von jQuery.ajax wird das zurückgelieferte JSON geparst. Falls das JSON ein Feld "error" enthält, wird
* „Fehler: <Fehlermeldung>“ ins DIV geschrieben. Andernfalls werden die Felder "circulating_supply" und "remaining" ausgelesen.
* Der Wert „remaining“ wird dann in deutscher Tausender-Notation formatiert und in das DIV geschrieben als:
* Noch <formatted> Bitcoin
*
* 4. Sollte die AJAX-Anfrage (z. B. beim Netzwerkausfall) scheitern, wird im error-Callback „Fehler beim Laden“ angezeigt.
*
* 5. Direkt nach DOM-ready wird im DIV zunächst „Lade Daten…“ angezeigt, dann der erste Aufruf von fetchRemainingBTC() durchgeführt.
* Mit setInterval(fetchRemainingBTC, 10 * 60 * 1000) wird das Skript alle 10 Minuten (300 000 ms) erneut ausgeführt.
*/
jQuery(function () {
// Debug: Prüfen, ob Common.js geladen wird
console.log('[UnminedBTC] Starting fetch script');
// 1) Container per jQuery abrufen
// Dieser DIV muss im Artikel stehen: <div id="unmined-btc-widget">Lade Daten…</div>
var $container = jQuery('#unmined-btc-widget');
if ($container.length === 0) {
// Falls das DIV nicht existiert, brechen wir ab
console.warn('[UnminedBTC] Kein Container #unmined-btc-widget gefunden, Abbruch.');
return;
}
// 2) Konstanten: Maximale Gesamtmenge aller Bitcoins
var TOTAL_SUPPLY = 21000000;
/**
* formatThousand(num)
*
* Formatiert eine Zahl in deutsche Tausender-Notation mit Punkten als Trennzeichen.
* Beispiel: 2500000 → "2.500.000"
*
* @param {number} num - Die zu formatierende Zahl (wird auf ganze Zahl abgerundet).
* @return {string} - Die formatierte Zahl als String mit Punkt-Trennungen.
*/
function formatThousand(num) {
// Ganzzahl-String erzeugen
var s = Math.floor(num).toString();
var parts = [];
var rest = s;
// Solange mehr als drei Ziffern übrig sind, letzten drei Ziffern extrahieren
while (rest.length > 3) {
var idx = rest.length - 3;
parts.unshift(rest.slice(idx)); // Letzte 3 Ziffern ins Array vorne einfügen
rest = rest.slice(0, idx); // Rest ohne die letzten 3 Ziffern
}
parts.unshift(rest); // Übrigen Teil (1–3 Ziffern) ebenfalls ins Array einfügen
// Array mit Punkten verbinden, z. B. ["1", "126", "085"] → "1.126.085"
return parts.join('.');
}
/**
* fetchRemainingBTC()
*
* Ruft per AJAX den eigenen PHP-Proxy auf, der serverseitig die CoinGecko-API
* abfragt und die verbleibenden Bitcoins bis 21 000 000 berechnet. Anschließend
* wird das Ergebnis ins DIV-Element (ID "unmined-btc-widget") geschrieben.
*
* Der PHP-Proxy liefert ein JSON-Objekt in folgender Struktur:
* {
* "circulating_supply": <Number>,
* "remaining": <Number>
* }
*
* Oder bei Fehlern:
* {
* "error": "<Fehlermeldung>"
* }
*/
function fetchRemainingBTC() {
// 4a) URL zu deinem PHP-Proxy auf deinem Server
// Der Proxy muss CORS erlauben (Access-Control-Allow-Origin: *) und gibt JSON zurück.
var url = 'https://test.toepperwien.de/unmined_bitcoin/unmined_btc.php';
console.log('[UnminedBTC] AJAX-Request an URL:', url);
// 4b) AJAX-Aufruf mit jQuery.ajax (ES5)
jQuery.ajax({
url: url,
dataType: 'json', // Erwartet JSON-Antwort
timeout: 5000, // Timeout nach 5 Sekunden
success: function (data) {
console.log('[UnminedBTC] AJAX success, rohes JSON:', data);
// 4c) Prüfen, ob der Proxy einen Fehler zurückliefert
if (data.error) {
console.error('[UnminedBTC] PHP-Proxy-Fehler:', data.error);
// Zeige Fehlermeldung im DIV an
$container.text('Fehler: ' + data.error);
return;
}
// 4d) Auslesen von remaining und circulating_supply
var remaining = data.remaining;
var circ = data.circulating_supply;
console.log('[UnminedBTC] circulating_supply:', circ, 'remaining:', remaining);
// 4e) Validierung: remaining muss eine Zahl sein
if (typeof remaining !== 'number' || isNaN(remaining)) {
$container.text('Fehler: ungültige Daten');
return;
}
// 4f) Ausgabe im DIV: "<formatted> Bitcoin"
// Beispiel: "Noch 1.126.085 Bitcoin"
var formatted = formatThousand(remaining);
$container.text(formatted);
},
error: function (xhr, status, error) {
console.error('[UnminedBTC] AJAX-Fehler:', status, error);
// Zeige generische Fehlermeldung im DIV
$container.text('Fehler beim Laden');
}
});
}
// 5) Initialisierung: Zuerst "Lade Daten…" ins DIV schreiben
$container.text('Lade Daten…');
// 5a) Ersten Abruf sofort starten
fetchRemainingBTC();
// 5b) Alle 10 Minuten (10 * 60 * 1000 ms) erneut abrufen
setInterval(fetchRemainingBTC, 10 * 60 * 1000);
});
// --------------------------------------------------------------------------------------------------------------------
/* Anonymer Song-Zähler + Cover-Play (ohne Cookies/PII) */
(function () {
function ajaxGET(url, done) {
try {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
var ok = (xhr.status >= 200 && xhr.status < 300);
done(ok, ok ? xhr.responseText : null);
}
};
xhr.send(null);
} catch (e) { done(false, null); }
}
function initSongBlocks() {
var wrappers = document.querySelectorAll ? document.querySelectorAll('.wiki-song') : [];
var playedOnce = window.__wikiSongPlayedOnce || (window.__wikiSongPlayedOnce = {});
for (var i = 0; i < wrappers.length; i++) {
(function (wrap) {
var id = wrap.getAttribute('data-song-id') || '';
var audio = wrap.querySelector ? wrap.querySelector('.wiki-song-audio') : null;
var countEl = wrap.querySelector ? wrap.querySelector('[data-song-count]') : null;
var coverBtn = wrap.querySelector ? wrap.querySelector('.wiki-song-cover-play') : null;
// 1) aktuellen Zählerstand laden
if (id && countEl) {
ajaxGET('/audio/count.php?song=' + encodeURIComponent(id), function (ok, text) {
if (!ok || !text) { return; }
try {
var ob = JSON.parse(text);
if (ob && typeof ob.plays === 'number') { countEl.textContent = String(ob.plays); }
} catch (e) {}
});
}
// 2) einmalig bumpen beim ersten Play
if (id && audio) {
audio.addEventListener('play', function () {
wrap.classList && wrap.classList.add('is-playing');
if (!playedOnce[id]) {
playedOnce[id] = true;
ajaxGET('/audio/bump.php?song=' + encodeURIComponent(id), function () {});
if (countEl) {
var n = parseInt(countEl.textContent, 10);
if (!isNaN(n)) { countEl.textContent = String(n + 1); }
}
}
}, false);
audio.addEventListener('pause', function () { wrap.classList && wrap.classList.remove('is-playing'); }, false);
audio.addEventListener('ended', function () { wrap.classList && wrap.classList.remove('is-playing'); }, false);
}
// 3) Cover-Button steuert Play/Pause
if (coverBtn && audio) {
coverBtn.addEventListener('click', function () {
try {
if (audio.paused) { audio.play(); } else { audio.pause(); }
} catch (e) {}
}, false);
}
})(wrappers[i]);
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initSongBlocks, false);
} else {
initSongBlocks();
}
})();
/* Inline-Anzeige der Song-Aufrufe hinter "Wiki-Song" */
(function () {
function ajaxGET(url, done) {
try {
var x = new XMLHttpRequest();
x.open('GET', url, true);
x.onreadystatechange = function(){ if (x.readyState === 4) done(x.status>=200&&x.status<300, x.responseText); };
x.send(null);
} catch (e) { done(false, null); }
}
function updateInlineCounts() {
var nodes = document.querySelectorAll ? document.querySelectorAll('.wiki-song-inline-count') : [];
if (!nodes.length) return;
// ggf. mehrere IDs auf einer Seite unterstützen
var byId = {};
for (var i=0;i<nodes.length;i++) {
var id = nodes[i].getAttribute('data-song-id') || '';
if (!id) continue;
(byId[id] = byId[id] || []).push(nodes[i]);
}
for (var id in byId) if (byId.hasOwnProperty(id)) {
(function(songId, targets){
ajaxGET('/audio/count.php?song=' + encodeURIComponent(songId), function(ok, text){
var n = 0;
if (ok && text) { try { var ob = JSON.parse(text); if (ob && typeof ob.plays === 'number') n = ob.plays|0; } catch(e){} }
for (var j = 0; j < targets.length; j++) {
var el = targets[j].querySelector ? targets[j].querySelector('.count') : null;
if (el) {
el.textContent = String(n); // nur die Zahl austauschen
} else {
// Fallback, falls mal kein .count drin ist:
targets[j].innerHTML = '<em>Bislang ' + String(n) + ' Aufrufe</em>';
}
}
});
})(id, byId[id]);
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', updateInlineCounts, false);
} else {
updateInlineCounts();
}
})();
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------