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
- Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
/**
* MediaWiki:Gadget-WetterGenerator.js (Ausbaustufe 2)
* =====================================================================
* Formular zum Erstellen von Wetterwidget-Bausteinen für Gemeindeseiten
* – jetzt zusätzlich mit:
*
* A) WIKIMAP-EXPORT: Ein Klick holt die aktuelle Stationsliste live von
* GeoSphere und erzeugt fertige Einträge für WikiMap-Orte.json
* (Kategorie "Wetterstation", einstellbarer Umkreis, leer = ganz
* Österreich). Die Einträge werden in die Liste "orte" der Datei
* kopiert – am besten VOR einen bestehenden Eintrag, dann stimmen
* die Kommas. Einmalig im Block "kategorien" ergänzen:
* "Wetterstation": "#2a6fb8"
*
* B) KARTEN-RÜCKSPRUNG: Die exportierten Einträge verweisen im Feld
* "seite" auf diese Generator-Seite samt Adress-Parametern
* (ws_station, ws_name, ws_lat, ws_lon, ws_hoehe). Öffnet jemand
* einen Stationsmarker auf der WikiMap und folgt dem Link, steht
* hier sofort der fertige {{Wetterwidget|...}}-Baustein bereit.
*
* Datenquelle: GeoSphere Austria Dataset-API (Open Data, CC BY 4.0),
* kein API-Schlüssel nötig. Doku: https://dataset.api.hub.geosphere.at/v1/docs/
*
* EINRICHTUNG: unverändert gegenüber Ausbaustufe 1 – dieser Code ersetzt
* einfach den bisherigen Inhalt von [[MediaWiki:Gadget-WetterGenerator.js]].
* Der Eintrag in [[MediaWiki:Gadgets-definition]] bleibt gleich:
* * WetterGenerator[ResourceLoader|default|hidden]|WetterGenerator.js
* Die Generator-Seite enthält weiterhin nur:
* <div id="wetter-generator"></div>
* =====================================================================
*/
( function () {
'use strict';
/* Stationsliste der 10-Minuten-Messstationen (TAWES) samt Metadaten */
var META_URL = 'https://dataset.api.hub.geosphere.at/v1/' +
'station/current/tawes-v1-10min/metadata';
/* So viele nächstgelegene Stationen werden zur Auswahl angeboten */
var MAX_STATIONEN = 5;
/* Bezugspunkt für den Export-Umkreis: grobe Mitte des Schwarzatals
* (Raum Payerbach/Gloggnitz). */
var EXPORT_ZENTRUM = { lat: 47.70, lon: 15.95 };
var EXPORT_RADIUS_VORGABE = '50';
var stationen = null; /* geladene Stationsliste (wird nur 1x geholt) */
var topStationen = []; /* Ergebnis der letzten Suche, sortiert */
var letzteSuche = null; /* { lat, lon } der letzten Suche */
var el = {}; /* Referenzen auf die Formularelemente */
$( function () {
var container = document.getElementById( 'wetter-generator' );
if ( container ) {
baueFormular( $( container ) );
uebernimmAusKarte();
}
} );
/* ------------------------------------------------------------------
* Formular aufbauen
* ------------------------------------------------------------------ */
function baueFormular( $container ) {
el.ort = $( '<input>' )
.attr( { type: 'text', placeholder: 'z. B. Reichenau an der Rax' } )
.css( 'width', '20em' )
.on( 'input', aktualisiereBaustein );
el.lat = $( '<input>' )
.attr( { type: 'text', placeholder: 'z. B. 47,6969' } )
.css( 'width', '10em' );
el.lon = $( '<input>' )
.attr( { type: 'text', placeholder: 'z. B. 15,8446' } )
.css( 'width', '10em' );
el.suchen = $( '<button>' )
.attr( 'type', 'button' )
.text( 'Stationen suchen' )
.on( 'click', sucheStationen );
el.status = $( '<div>' ).css( 'margin', '0.7em 0' );
el.liste = $( '<div>' ).css( 'margin', '0.5em 0' );
el.ausgabe = $( '<textarea>' )
.attr( { rows: 8, readonly: 'readonly' } )
.css( textFeldStil() );
el.kopieren = $( '<button>' )
.attr( 'type', 'button' )
.text( 'Baustein kopieren' )
.css( 'display', 'none' )
.on( 'click', function () {
kopiereFeld( el.ausgabe, setzeStatus,
'Baustein kopiert – jetzt auf der Zielseite einfügen.' );
} );
/* --- Export-Bereich (WikiMap) --- */
el.exportRadius = $( '<input>' )
.attr( { type: 'text' } )
.val( EXPORT_RADIUS_VORGABE )
.css( 'width', '6em' );
el.exportKnopf = $( '<button>' )
.attr( 'type', 'button' )
.text( 'Stationen exportieren' )
.on( 'click', exportiereStationen );
el.exportStatus = $( '<div>' ).css( 'margin', '0.7em 0' );
el.exportAusgabe = $( '<textarea>' )
.attr( { rows: 10, readonly: 'readonly' } )
.css( textFeldStil() );
el.exportKopieren = $( '<button>' )
.attr( 'type', 'button' )
.text( 'Einträge kopieren' )
.css( 'display', 'none' )
.on( 'click', function () {
kopiereFeld( el.exportAusgabe, setzeExportStatus,
'Einträge kopiert – jetzt in WikiMap-Orte.json einfügen.' );
} );
el.exportHinweis = $( '<div>' )
.css( { 'margin-top': '0.5em', 'font-size': '85%', color: '#54595d',
display: 'none' } )
.text( 'Einmalig im Block "kategorien" von WikiMap-Orte.json ' +
'ergänzen: "Wetterstation": "#2a6fb8" – dann bekommen die ' +
'Stationen ihre eigene Pinfarbe und ihren Filter.' );
$container.empty().append(
kasten().append(
$( '<p>' ).text(
'Ort und Koordinaten eingeben – das Formular sucht die ' +
'nächstgelegenen GeoSphere-Wetterstationen und erstellt ' +
'den fertigen Baustein für die Gemeindeseite.'
),
feld( 'Ortsname', el.ort ),
feld( 'Breitengrad (Dezimalgrad)', el.lat ),
feld( 'Längengrad (Dezimalgrad)', el.lon ),
$( '<div>' ).css( 'margin', '0.7em 0' ).append( el.suchen ),
el.status,
el.liste,
el.ausgabe,
$( '<div>' ).css( 'margin', '0.5em 0' ).append( el.kopieren )
),
kasten().css( 'margin-top', '1em' ).append(
$( '<div>' )
.css( { 'font-weight': 'bold', 'margin-bottom': '0.3em' } )
.text( 'Stationen für die WikiMap' ),
$( '<p>' ).css( 'margin', '0.3em 0' ).text(
'Erzeugt fertige Einträge für WikiMap-Orte.json – alle ' +
'derzeit aktiven Wetterstationen im gewählten Umkreis. ' +
'Der Klick auf einen Stationsmarker der Karte führt ' +
'danach hierher zurück und liefert sofort den passenden ' +
'Widget-Baustein.'
),
feld( 'Umkreis in km (leer = ganz Österreich)', el.exportRadius ),
$( '<div>' ).css( 'margin', '0.7em 0' ).append( el.exportKnopf ),
el.exportStatus,
el.exportAusgabe,
$( '<div>' ).css( 'margin', '0.5em 0' ).append( el.exportKopieren ),
el.exportHinweis
),
$( '<div>' )
.css( { 'margin-top': '0.8em', 'font-size': '85%', color: '#54595d' } )
.text( 'Stationsdaten: GeoSphere Austria, Dataset-API (CC BY 4.0)' )
);
}
function kasten() {
return $( '<div>' ).css( {
border: '1px solid #a2a9b1',
background: '#f8f9fa',
padding: '1em',
'max-width': '42em'
} );
}
function feld( beschriftung, $eingabe ) {
return $( '<div>' ).css( 'margin', '0.5em 0' ).append(
$( '<label>' )
.css( { display: 'block', 'font-weight': 'bold' } )
.text( beschriftung ),
$eingabe
);
}
function textFeldStil() {
return {
width: '100%',
'max-width': '38em',
'font-family': 'monospace',
display: 'none'
};
}
/* ------------------------------------------------------------------
* Stationsliste laden (gemeinsam für Suche und Export)
* ------------------------------------------------------------------ */
function ladeStationsliste( beiErfolg, beiFehler ) {
if ( stationen ) {
beiErfolg();
return;
}
$.getJSON( META_URL )
.done( function ( daten ) {
stationen = lesbareStationen( daten );
if ( !stationen.length ) {
stationen = null;
beiFehler( 'Die Antwort der GeoSphere-API enthielt keine ' +
'Stationen. Bitte später erneut versuchen.' );
return;
}
beiErfolg();
} )
.fail( function ( antwort ) {
beiFehler( ladeFehlerText( antwort ) );
} );
}
function ladeFehlerText( antwort ) {
if ( !antwort || antwort.status === 0 ) {
return 'Die Stationsliste konnte nicht geladen werden: Der Browser ' +
'hat die Anfrage blockiert oder es besteht keine ' +
'Internetverbindung.';
}
return 'Die Stationsliste konnte nicht geladen werden (Serverantwort ' +
antwort.status + '). Bitte später erneut versuchen.';
}
/* API-Antwort in eine einheitliche Stationsliste umwandeln */
function lesbareStationen( daten ) {
var roh = ( daten && daten.stations ) || [];
var ergebnis = [];
$.each( roh, function ( i, st ) {
var lat = holeZahl( st, [ 'lat', 'latitude' ] );
var lon = holeZahl( st, [ 'lon', 'longitude' ] );
var name;
if ( lat === null || lon === null ) {
return; /* ohne Koordinaten unbrauchbar */
}
if ( st.is_active === false ) {
return; /* stillgelegte Stationen ausblenden */
}
name = String( st.name || 'Unbenannte Station' );
ergebnis.push( {
id: String( st.id ),
name: name,
anzeige: huebscherName( name ),
bundesland: st.state ? String( st.state ) : '',
lat: lat,
lon: lon,
hoehe: holeZahl( st, [ 'altitude', 'elevation' ] )
} );
} );
return ergebnis;
}
/* ------------------------------------------------------------------
* Einzel-Suche (unverändertes Verhalten)
* ------------------------------------------------------------------ */
function sucheStationen() {
var lat = parseKoordinate( el.lat.val() );
var lon = parseKoordinate( el.lon.val() );
if ( lat === null || lon === null ) {
setzeStatus( 'Bitte beide Koordinaten in Dezimalgrad eingeben, ' +
'z. B. 47,6969 und 15,8446.', true );
return;
}
letzteSuche = { lat: lat, lon: lon };
setzeStatus( 'Stationsliste wird geladen …', false );
ladeStationsliste( werteAus, function ( fehlerText ) {
setzeStatus( fehlerText, true );
} );
}
function werteAus() {
var i;
for ( i = 0; i < stationen.length; i++ ) {
stationen[ i ].entfernung = entfernungKm(
letzteSuche.lat, letzteSuche.lon,
stationen[ i ].lat, stationen[ i ].lon
);
}
topStationen = stationen.slice().sort( function ( a, b ) {
return a.entfernung - b.entfernung;
} ).slice( 0, MAX_STATIONEN );
var hinweis = 'Nächstgelegene Stationen – die erste ist vorausgewählt:';
if ( !imBereichOesterreich( letzteSuche.lat, letzteSuche.lon ) ) {
hinweis = 'Achtung: Die Koordinaten liegen außerhalb Österreichs – ' +
'bitte prüfen. ' + hinweis;
}
setzeStatus( hinweis, false );
el.liste.empty();
$.each( topStationen, function ( idx, st ) {
el.liste.append( radioZeile( idx, st.anzeige +
( st.bundesland ? ' (' + st.bundesland + ')' : '' ) +
' – ' + formatKm( st.entfernung ) + ' entfernt, ' +
( st.hoehe !== null ?
Math.round( st.hoehe ) + ' m Seehöhe' : 'Höhe unbekannt' ),
idx === 0 ) );
} );
el.ausgabe.show();
el.kopieren.show();
aktualisiereBaustein();
}
function radioZeile( idx, beschreibung, angehakt ) {
return $( '<label>' )
.css( { display: 'block', margin: '0.25em 0' } )
.append(
$( '<input>' )
.attr( { type: 'radio', name: 'wg-station' } )
.val( idx )
.prop( 'checked', angehakt )
.on( 'change', aktualisiereBaustein ),
document.createTextNode( ' ' + beschreibung )
);
}
/* ------------------------------------------------------------------
* Rücksprung von der WikiMap: ?ws_station=...&ws_lat=...
* ------------------------------------------------------------------ */
function uebernimmAusKarte() {
var id = leseUrlParameter( 'ws_station' );
var lat = parseKoordinate( leseUrlParameter( 'ws_lat' ) || '' );
var lon = parseKoordinate( leseUrlParameter( 'ws_lon' ) || '' );
var name, hoehe;
if ( !id || lat === null || lon === null ) {
return;
}
name = leseUrlParameter( 'ws_name' ) || ( 'Nr. ' + id );
hoehe = parseKoordinate( leseUrlParameter( 'ws_hoehe' ) || '' );
el.ort.val( name );
el.lat.val( String( lat ).replace( '.', ',' ) );
el.lon.val( String( lon ).replace( '.', ',' ) );
letzteSuche = { lat: lat, lon: lon };
topStationen = [ {
id: id, name: name, anzeige: name, bundesland: '',
lat: lat, lon: lon, hoehe: hoehe, entfernung: 0
} ];
setzeStatus( 'Station aus der Karte übernommen – der Baustein steht ' +
'unten bereit. Für andere Vorschläge einfach „Stationen suchen" ' +
'klicken.', false );
el.liste.empty().append( radioZeile( 0, name +
( hoehe !== null ? ', ' + Math.round( hoehe ) + ' m Seehöhe' : '' ) +
' (aus der Karte übernommen)', true ) );
el.ausgabe.show();
el.kopieren.show();
aktualisiereBaustein();
}
function leseUrlParameter( name ) {
var treffer = new RegExp( '[?&]' + name + '=([^&#]*)' )
.exec( location.search );
if ( !treffer ) {
return null;
}
try {
return decodeURIComponent( treffer[ 1 ].replace( /\+/g, ' ' ) );
} catch ( e ) {
return null;
}
}
/* ------------------------------------------------------------------
* Export für WikiMap-Orte.json
* ------------------------------------------------------------------ */
function exportiereStationen() {
var radiusText = $.trim( el.exportRadius.val() );
var radius = radiusText === '' ? null : parseKoordinate( radiusText );
if ( radiusText !== '' && ( radius === null || radius <= 0 ) ) {
setzeExportStatus( 'Bitte einen Umkreis in Kilometern angeben – ' +
'oder das Feld leeren für ganz Österreich.', true );
return;
}
setzeExportStatus( 'Stationsliste wird geladen …', false );
ladeStationsliste( function () {
baueExport( radius );
}, function ( fehlerText ) {
setzeExportStatus( fehlerText, true );
} );
}
function baueExport( radius ) {
var treffer = [];
var zeilen = [];
var i, st;
for ( i = 0; i < stationen.length; i++ ) {
st = stationen[ i ];
if ( radius === null || entfernungKm( EXPORT_ZENTRUM.lat,
EXPORT_ZENTRUM.lon, st.lat, st.lon ) <= radius ) {
treffer.push( st );
}
}
if ( !treffer.length ) {
setzeExportStatus( 'Keine Station im gewählten Umkreis gefunden – ' +
'bitte den Umkreis vergrößern.', true );
return;
}
treffer.sort( function ( a, b ) {
return a.anzeige.localeCompare( b.anzeige );
} );
for ( i = 0; i < treffer.length; i++ ) {
st = treffer[ i ];
zeilen.push( ' { "id": ' +
JSON.stringify( 'Wetterstation ' + st.anzeige ) +
', "lat": ' + st.lat.toFixed( 4 ) +
', "lon": ' + st.lon.toFixed( 4 ) +
', "kategorie": "Wetterstation"' +
', "seite": ' + JSON.stringify( urlFuerStation( st ) ) +
' },' );
}
el.exportAusgabe.val( zeilen.join( '\n' ) ).show();
el.exportKopieren.show();
el.exportHinweis.show();
setzeExportStatus( treffer.length + ' Stationen bereit. Den Block in ' +
'die Liste "orte" von WikiMap-Orte.json einfügen – am besten VOR ' +
'einen bestehenden Eintrag, dann stimmen die Kommas. Die ' +
'JSON-Seite meldet beim Speichern selbst, falls eines fehlt.',
false );
}
/* Absolute Adresse dieser Generator-Seite samt Stations-Parametern.
* Absolut deshalb, weil die WikiMap externe Ziele (http/https)
* unverändert übernimmt – Wiki-Seitennamen dagegen könnten keine
* Parameter tragen. */
function urlFuerStation( st ) {
return location.protocol + '//' + location.host +
mw.config.get( 'wgScript' ) +
'?title=' + encodeURIComponent( mw.config.get( 'wgPageName' ) ) +
'&ws_station=' + encodeURIComponent( st.id ) +
'&ws_name=' + encodeURIComponent( st.anzeige ) +
'&ws_lat=' + st.lat.toFixed( 4 ) +
'&ws_lon=' + st.lon.toFixed( 4 ) +
( st.hoehe !== null ? '&ws_hoehe=' + Math.round( st.hoehe ) : '' );
}
/* ------------------------------------------------------------------
* Baustein erzeugen und kopieren
* ------------------------------------------------------------------ */
function aktualisiereBaustein() {
var gewaehlt = el.liste.find( 'input:checked' ).val();
if ( gewaehlt === undefined || !letzteSuche ) {
return;
}
var st = topStationen[ parseInt( gewaehlt, 10 ) ];
if ( !st ) {
return;
}
el.ausgabe.val(
'{{Wetterwidget\n' +
'|ort = ' + $.trim( el.ort.val() ) + '\n' +
'|lat = ' + letzteSuche.lat.toFixed( 4 ) + '\n' +
'|lon = ' + letzteSuche.lon.toFixed( 4 ) + '\n' +
'|station = ' + st.id + '\n' +
'|stationsname = ' + ( st.anzeige || st.name ) + '\n' +
'|stationshoehe = ' + ( st.hoehe !== null ? Math.round( st.hoehe ) : '' ) + '\n' +
'}}'
);
}
function kopiereFeld( $feld, statusSetzer, erfolgsMeldung ) {
var text = $feld.val();
if ( !text ) {
statusSetzer( 'Noch nichts zu kopieren vorhanden.', true );
return;
}
function fallback() {
try {
$feld[ 0 ].select();
document.execCommand( 'copy' );
statusSetzer( erfolgsMeldung, false );
} catch ( e ) {
statusSetzer( 'Kopieren nicht möglich – bitte den Text im ' +
'Feld markieren und manuell kopieren.', true );
}
}
if ( navigator.clipboard && navigator.clipboard.writeText ) {
navigator.clipboard.writeText( text ).then( function () {
statusSetzer( erfolgsMeldung, false );
}, fallback );
} else {
fallback();
}
}
/* ------------------------------------------------------------------
* Kleine Helfer
* ------------------------------------------------------------------ */
/* GROSSSCHREIBUNG der API hübsch umwandeln: "WIEN/HOHE WARTE" wird zu
* "Wien/Hohe Warte", "LUNZ AM SEE" zu "Lunz am See". Umlaut-
* Umschreibungen (OE/UE/AE) werden nur zurückgewandelt, wenn kein
* Vokal davorsteht – so bleibt "Feuerkogel" verschont. Heuristik:
* Einzelfälle lassen sich im JSON-Export nachträglich anpassen. */
function huebscherName( roh ) {
var fuellwoerter = [ 'am', 'an', 'im', 'in', 'bei', 'ob', 'auf',
'unter', 'der', 'die', 'das', 'und', 'zu' ];
var text = String( roh || '' ).toLowerCase()
.replace( /(^|[^aeiouq])ae/g, '$1ä' )
.replace( /(^|[^aeiouq])oe/g, '$1ö' )
.replace( /(^|[^aeiouq])ue/g, '$1ü' )
.replace( /(^|[\s\/\-.(])([a-zäöü])/g, function ( ganz, davor, buchstabe ) {
return davor + buchstabe.toUpperCase();
} );
var teile = text.split( ' ' );
var i;
for ( i = 1; i < teile.length; i++ ) {
if ( $.inArray( teile[ i ].toLowerCase(), fuellwoerter ) !== -1 ) {
teile[ i ] = teile[ i ].toLowerCase();
}
}
return teile.join( ' ' );
}
function parseKoordinate( text ) {
var bereinigt = String( text || '' )
.replace( /,/g, '.' )
.replace( /[^0-9.\-]/g, '' );
var wert = parseFloat( bereinigt );
return isFinite( wert ) ? wert : null;
}
function holeZahl( objekt, namen ) {
var i, wert;
for ( i = 0; i < namen.length; i++ ) {
wert = parseFloat( objekt[ namen[ i ] ] );
if ( isFinite( wert ) ) {
return wert;
}
}
return null;
}
/* Luftlinie in Kilometern (Haversine-Formel) */
function entfernungKm( lat1, lon1, lat2, lon2 ) {
var rad = Math.PI / 180;
var dLat = ( lat2 - lat1 ) * rad;
var dLon = ( lon2 - lon1 ) * rad;
var a = Math.sin( dLat / 2 ) * Math.sin( dLat / 2 ) +
Math.cos( lat1 * rad ) * Math.cos( lat2 * rad ) *
Math.sin( dLon / 2 ) * Math.sin( dLon / 2 );
return 6371 * 2 * Math.atan2( Math.sqrt( a ), Math.sqrt( 1 - a ) );
}
function imBereichOesterreich( lat, lon ) {
return lat >= 46.3 && lat <= 49.1 && lon >= 9.4 && lon <= 17.3;
}
function formatKm( km ) {
return km.toFixed( 1 ).replace( '.', ',' ) + ' km';
}
function setzeStatus( text, istFehler ) {
el.status
.text( text )
.css( 'color', istFehler ? '#b32424' : '#202122' );
}
function setzeExportStatus( text, istFehler ) {
el.exportStatus
.text( text )
.css( 'color', istFehler ? '#b32424' : '#202122' );
}
}() );