MediaWiki:Gadget-eventform.js: Unterschied zwischen den Versionen
Admin (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
Admin (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
||
| (13 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
/** | /** | ||
* Eventform-Gadget: Komfortables Anlegen von Veranstaltungsseiten | * Eventform-Gadget: Komfortables Anlegen von Veranstaltungsseiten | ||
* Aktiv auf der Seite " | * Aktiv auf der Seite "Veranstaltungen" | ||
*/ | */ | ||
( function () { | ( function () { | ||
'use strict'; | 'use strict'; | ||
// Konfiguration | // Konfiguration: auf welcher Seite soll der Button erscheinen? | ||
var TRIGGER_PAGE = ' | var TRIGGER_PAGE = 'Veranstaltungen'; | ||
if ( mw.config.get( 'wgPageName' ) !== TRIGGER_PAGE ) { | if ( mw.config.get( 'wgPageName' ) !== TRIGGER_PAGE ) { | ||
return; | return; | ||
} | } | ||
if ( !mw.config.get( 'wgUserName' ) ) { | if ( !mw.config.get( 'wgUserName' ) ) { | ||
return; | return; | ||
} | } | ||
var | function v( val ) { | ||
return ( val || '' ).trim(); | |||
} | |||
/** | |||
* Parst gängige Koordinaten-Formate. | |||
* Gibt { lat, lng } zurück oder null bei ungültiger Eingabe. | |||
*/ | |||
function parseCoordinates( input ) { | |||
if ( !input ) { | |||
return null; | |||
} | |||
var s = input.trim(); | |||
var m; | |||
// Deutsches Format: Komma als Dezimaltrenner | |||
// "47,7073132, 15,9934565" / "47,7073132; 15,9934565" / "47,7073132 15,9934565" | |||
m = /^(-?\d+,\d+)\s*[;\s]\s*(-?\d+,\d+)$/.exec( s ) || | |||
/^(-?\d+,\d+),\s+(-?\d+,\d+)$/.exec( s ); | |||
if ( m ) { | |||
var latDE = parseFloat( m[ 1 ].replace( ',', '.' ) ); | |||
var lngDE = parseFloat( m[ 2 ].replace( ',', '.' ) ); | |||
if ( isFinite( latDE ) && isFinite( lngDE ) && | |||
Math.abs( latDE ) <= 90 && Math.abs( lngDE ) <= 180 ) { | |||
return { lat: latDE, lng: lngDE }; | |||
} | |||
} | |||
// Internationales Dezimal: "47.75,15.68" / "47.75 15.68" / "47.75; 15.68" / "-47.75,15.68" | |||
m = /^(-?\d+(?:\.\d+)?)\s*[,;\s]\s*(-?\d+(?:\.\d+)?)$/.exec( s ); | |||
if ( m ) { | |||
var lat = parseFloat( m[ 1 ] ); | |||
var lng = parseFloat( m[ 2 ] ); | |||
if ( isFinite( lat ) && isFinite( lng ) && | |||
Math.abs( lat ) <= 90 && Math.abs( lng ) <= 180 ) { | |||
return { lat: lat, lng: lng }; | |||
} | |||
} | |||
// Dezimal mit NSEW: "47.75N 15.68E" / "47.75°N, 15.68°E" (auch mit Dezimal-Komma: "47,75N 15,68E") | |||
// | m = /^(\d+(?:[.,]\d+)?)\s*°?\s*([NS])\s*[,;\s]?\s*(\d+(?:[.,]\d+)?)\s*°?\s*([EW])$/i.exec( s ); | ||
if ( m ) { | |||
var lat2 = parseFloat( m[ 1 ].replace( ',', '.' ) ); | |||
if ( m[ 2 ].toUpperCase() === 'S' ) { lat2 = -lat2; } | |||
var lng2 = parseFloat( m[ 3 ].replace( ',', '.' ) ); | |||
if ( m[ 4 ].toUpperCase() === 'W' ) { lng2 = -lng2; } | |||
if ( isFinite( lat2 ) && isFinite( lng2 ) && | |||
Math.abs( lat2 ) <= 90 && Math.abs( lng2 ) <= 180 ) { | |||
return { lat: lat2, lng: lng2 }; | |||
} | |||
} | |||
// DMS: 47°45'00.0"N 15°40'48.0"E | |||
// Akzeptiert gerade (' ") und typografische (’ ” ″ ′) Zeichen | |||
m = /^(\d+)\s*°\s*(\d+)\s*['\u2019\u2032]\s*(\d+(?:[.,]\d+)?)\s*["\u201D\u2033]\s*([NS])\s*[,;\s]?\s*(\d+)\s*°\s*(\d+)\s*['\u2019\u2032]\s*(\d+(?:[.,]\d+)?)\s*["\u201D\u2033]\s*([EW])$/i.exec( s ); | |||
if ( m ) { | |||
var lat3 = parseInt( m[ 1 ], 10 ) + parseInt( m[ 2 ], 10 ) / 60 + parseFloat( m[ 3 ].replace( ',', '.' ) ) / 3600; | |||
if ( m[ 4 ].toUpperCase() === 'S' ) { lat3 = -lat3; } | |||
var lng3 = parseInt( m[ 5 ], 10 ) + parseInt( m[ 6 ], 10 ) / 60 + parseFloat( m[ 7 ].replace( ',', '.' ) ) / 3600; | |||
if ( m[ 8 ].toUpperCase() === 'W' ) { lng3 = -lng3; } | |||
if ( Math.abs( lat3 ) <= 90 && Math.abs( lng3 ) <= 180 ) { | |||
return { lat: lat3, lng: lng3 }; | |||
} | |||
} | |||
// DM: 47°45.000'N 15°40.800'E (auch typografische Zeichen) | |||
m = /^(\d+)\s*°\s*(\d+(?:[.,]\d+)?)\s*['\u2019\u2032]\s*([NS])\s*[,;\s]?\s*(\d+)\s*°\s*(\d+(?:[.,]\d+)?)\s*['\u2019\u2032]\s*([EW])$/i.exec( s ); | |||
if ( m ) { | |||
var lat4 = parseInt( m[ 1 ], 10 ) + parseFloat( m[ 2 ].replace( ',', '.' ) ) / 60; | |||
if ( m[ 3 ].toUpperCase() === 'S' ) { lat4 = -lat4; } | |||
var lng4 = parseInt( m[ 4 ], 10 ) + parseFloat( m[ 5 ].replace( ',', '.' ) ) / 60; | |||
if ( m[ 6 ].toUpperCase() === 'W' ) { lng4 = -lng4; } | |||
if ( Math.abs( lat4 ) <= 90 && Math.abs( lng4 ) <= 180 ) { | |||
return { lat: lat4, lng: lng4 }; | |||
} | |||
} | |||
return null; | |||
} | } | ||
function | function fmtCoord( n ) { | ||
return ( | return n.toFixed( 7 ); | ||
} | |||
function buildOsmUrl( c ) { | |||
var lat = fmtCoord( c.lat ); | |||
var lng = fmtCoord( c.lng ); | |||
return 'https://www.openstreetmap.org/?mlat=' + lat + '&mlon=' + lng + '#map=17/' + lat + '/' + lng; | |||
} | |||
function buildGoogleMapsUrl( c ) { | |||
return 'https://www.google.com/maps?q=' + fmtCoord( c.lat ) + ',' + fmtCoord( c.lng ); | |||
} | |||
function buildCoMapsUrl( c ) { | |||
// CoMaps (und Organic Maps) öffnen Koordinaten über das standardisierte | |||
// geo:-URI-Schema (RFC 5870). Das https://comaps.at/... -Format | |||
// existiert nicht. geo: öffnet auf Android die Karten-App mit Pin. | |||
return 'geo:' + fmtCoord( c.lat ) + ',' + fmtCoord( c.lng ); | |||
} | } | ||
| Zeile 38: | Zeile 121: | ||
var lines = []; | var lines = []; | ||
lines.push( '[[Hauptseite]] > [[Hauptseite#Kultur & Events|Kultur & Events]] > [[Veranstaltungen]]' ); | lines.push( '[[Hauptseite]] > [[Hauptseite#Kultur & Events|Kultur & Events]] > [[Veranstaltungen]]' ); | ||
// Zeit | |||
lines.push( '==Zeit==' ); | lines.push( '==Zeit==' ); | ||
lines.push( '🗓️ ' + | lines.push( '🗓️ ' + f.datum ); | ||
if ( f.uhrzeit ) { | |||
lines.push( '' ); | |||
lines.push( '⏰ ' + f.uhrzeit ); | |||
} | |||
lines.push( '<br>' ); | lines.push( '<br>' ); | ||
lines.push( '<br>' ); | lines.push( '<br>' ); | ||
lines.push( '<br>' ); | lines.push( '<br>' ); | ||
lines.push( '<br>' ); | lines.push( '<br>' ); | ||
// Event | |||
lines.push( '==Event==' ); | lines.push( '==Event==' ); | ||
if ( f.bild ) { | if ( f.bild ) { | ||
lines.push( '[[file:' + f.bild + '|frameless|upright=3.0]]' ); | lines.push( '[[file:' + f.bild + '|frameless|upright=3.0]]' ); | ||
lines.push( '' ); | |||
} | } | ||
if ( f.websiteUrl ) { | if ( f.websiteUrl ) { | ||
lines.push( '🌐 | lines.push( '🌐 ' + f.websiteUrl ); | ||
} | } | ||
lines.push( '<br>' ); | lines.push( '<br>' ); | ||
| Zeile 56: | Zeile 147: | ||
lines.push( '<br>' ); | lines.push( '<br>' ); | ||
lines.push( '<br>' ); | lines.push( '<br>' ); | ||
// Location - jede Symbol-Zeile in eigenem Absatz (Leerzeile dazwischen) | |||
lines.push( '==Location==' ); | lines.push( '==Location==' ); | ||
if ( f. | // Karte mit dem Veranstaltungsort als einzigem Pin (WikiMap-Gadget). | ||
lines.push( ' | // Nutzt die geparsten Koordinaten, damit alle Eingabeformate | ||
// (deutsches Format, DMS, ...) funktionieren. | |||
if ( f.coords ) { | |||
lines.push( '<div class="wikimap" data-pin="' + | |||
fmtCoord( f.coords.lat ) + ',' + fmtCoord( f.coords.lng ) + | |||
'" data-pin-name="' + ( f.Adresse || f.titel || 'Veranstaltungsort' ) + | |||
'"></div>' ); | |||
lines.push( '' ); | |||
} | |||
var locFirst = true; | |||
function addLocLine( line ) { | |||
if ( !locFirst ) { | |||
lines.push( '' ); | |||
} | |||
lines.push( line ); | |||
locFirst = false; | |||
} | |||
if ( f.Adresse ) { | |||
addLocLine( '📍 ' + f.Adresse ); | |||
} | } | ||
if ( f.osmUrl ) { | if ( f.osmUrl ) { | ||
addLocLine( '[[file:osm.png|24px|link=]] ' + f.osmUrl ); | |||
} | } | ||
if ( f.koordinaten ) { | if ( f.koordinaten ) { | ||
addLocLine( '🧭 ' + f.koordinaten ); | |||
} | } | ||
if ( f.comapsUrl ) { | if ( f.comapsUrl ) { | ||
addLocLine( '[[file:CoMaps.png|24px|link=]] ' + f.comapsUrl ); | |||
} | } | ||
if ( f.gmapsUrl ) { | if ( f.gmapsUrl ) { | ||
addLocLine( '[[file:GoogleMaps.png|24px|link=]] ' + f.gmapsUrl ); | |||
} | } | ||
lines.push( '<br>' ); | lines.push( '<br>' ); | ||
| Zeile 76: | Zeile 187: | ||
lines.push( '<br>' ); | lines.push( '<br>' ); | ||
lines.push( '<br>' ); | lines.push( '<br>' ); | ||
// Photos & Videos | |||
lines.push( '==Photos & Videos==' ); | lines.push( '==Photos & Videos==' ); | ||
lines.push( 'Bitte hier verlinken.' ); | lines.push( 'Bitte hier verlinken.' ); | ||
return lines.join( '\n' ); | return lines.join( '\n' ); | ||
} | } | ||
| Zeile 110: | Zeile 224: | ||
} ); | } ); | ||
this.datumInput = new OO.ui.TextInputWidget( { type: 'date', required: true } ); | this.datumInput = new OO.ui.TextInputWidget( { type: 'date', required: true } ); | ||
this.uhrzeitInput = new OO.ui.TextInputWidget( { type: 'time', value: '17:00' | this.uhrzeitInput = new OO.ui.TextInputWidget( { type: 'time', value: '17:00' } ); | ||
this.bildInput = new OO.ui.TextInputWidget( { placeholder: 'sommerfest.jpg' } ); | this.bildInput = new OO.ui.TextInputWidget( { placeholder: 'sommerfest.jpg' } ); | ||
this.websiteUrlInput = new OO.ui.TextInputWidget( { placeholder: 'https://...' } ); | this.websiteUrlInput = new OO.ui.TextInputWidget( { placeholder: 'https://...' } ); | ||
this. | this.AdresseInput = new OO.ui.TextInputWidget( { placeholder: 'Nussbaum Straße ' } ); | ||
this.osmUrlInput = new OO.ui.TextInputWidget( { placeholder: 'https://www.openstreetmap.org/way/...' } ); | this.osmUrlInput = new OO.ui.TextInputWidget( { placeholder: 'https://www.openstreetmap.org/way/...' } ); | ||
this.koordinatenInput = new OO.ui.TextInputWidget( { placeholder: '47.7500000,15.6800000' } ); | this.koordinatenInput = new OO.ui.TextInputWidget( { placeholder: '47.7500000,15.6800000' } ); | ||
this.comapsUrlInput = new OO.ui.TextInputWidget( { placeholder: 'https://comaps.at/...' } ); | this.comapsUrlInput = new OO.ui.TextInputWidget( { placeholder: 'https://comaps.at/...' } ); | ||
this.gmapsUrlInput = new OO.ui.TextInputWidget( { placeholder: 'https://maps.app.goo.gl/...' } ); | this.gmapsUrlInput = new OO.ui.TextInputWidget( { placeholder: 'https://maps.app.goo.gl/...' } ); | ||
var fsBasis = new OO.ui.FieldsetLayout( { label: 'Pflichtfelder' } ); | var fsBasis = new OO.ui.FieldsetLayout( { label: 'Pflichtfelder' } ); | ||
| Zeile 133: | Zeile 242: | ||
} ), | } ), | ||
new OO.ui.FieldLayout( this.datumInput, { label: 'Datum', align: 'left' } ), | new OO.ui.FieldLayout( this.datumInput, { label: 'Datum', align: 'left' } ), | ||
new OO.ui.FieldLayout( this.uhrzeitInput, { label: 'Uhrzeit', align: 'left' } ) | new OO.ui.FieldLayout( this.uhrzeitInput, { | ||
label: 'Uhrzeit', align: 'left', | |||
help: 'Optional. Leer lassen wenn keine Uhrzeit gewünscht.' | |||
} ) | |||
] ); | ] ); | ||
| Zeile 140: | Zeile 252: | ||
new OO.ui.FieldLayout( this.bildInput, { | new OO.ui.FieldLayout( this.bildInput, { | ||
label: 'Bild (Dateiname)', align: 'left', | label: 'Bild (Dateiname)', align: 'left', | ||
help: ' | help: 'Wenn man die Dateiendung weiß (z.B. jpg), wähle einen sinnvollen Namen mit der richtigen Datei-Endung (z.B. Sommerfest2026.jpg ) wenn mann dann später auf der fertigen Seite darauf klickt, kann man auch das Bild hochladen. Leer lassen, wenn kein Bild.' | ||
} ), | } ), | ||
new OO.ui.FieldLayout( this.websiteUrlInput, { label: 'Website URL | new OO.ui.FieldLayout( this.websiteUrlInput, { label: 'Website URL', align: 'left' } ) | ||
] ); | ] ); | ||
var fsLoc = new OO.ui.FieldsetLayout( { label: 'Location (alles optional)' } ); | var fsLoc = new OO.ui.FieldsetLayout( { label: 'Location (alles optional)' } ); | ||
fsLoc.addItems( [ | fsLoc.addItems( [ | ||
new OO.ui.FieldLayout( this. | new OO.ui.FieldLayout( this.AdresseInput, { label: 'Adresse', align: 'left' } ), | ||
new OO.ui.FieldLayout( this. | new OO.ui.FieldLayout( this.osmUrlInput, { | ||
label: 'OpenStreetMap URL', align: 'left', | |||
new OO.ui.FieldLayout( this. | help: 'Leer lassen, dann wird bei gegebenen Koordinaten automatisch ein Link generiert.' | ||
} ), | |||
new OO.ui.FieldLayout( this.comapsUrlInput, { label: 'CoMaps URL', align: 'left' | new OO.ui.FieldLayout( this.koordinatenInput, { | ||
label: 'GPS-Koordinaten', align: 'left', | |||
new OO.ui.FieldLayout( this.gmapsUrlInput, { label: 'Google Maps URL', align: 'left' | help: 'Akzeptiert u.a.: 47.75,15.68 · 47,7073132, 15,9934565 (deutsches Format) · 47.75N 15.68E · 47°45\'00"N 15°40\'48"E. Wenn gesetzt, werden für leere OSM/CoMaps/Google Maps Felder automatisch Links generiert und eine Karte auf der Seite eingebunden.' | ||
} ), | |||
new OO.ui.FieldLayout( this.comapsUrlInput, { | |||
label: 'CoMaps URL', align: 'left', | |||
help: 'Leer lassen, dann wird bei gegebenen Koordinaten automatisch ein Link generiert.' | |||
} ), | |||
new OO.ui.FieldLayout( this.gmapsUrlInput, { | |||
label: 'Google Maps URL', align: 'left', | |||
help: 'Leer lassen, dann wird bei gegebenen Koordinaten automatisch ein Link generiert.' | |||
} ) | |||
] ); | ] ); | ||
| Zeile 171: | Zeile 290: | ||
var uhrzeit = v( dialog.uhrzeitInput.getValue() ); | var uhrzeit = v( dialog.uhrzeitInput.getValue() ); | ||
if ( !titel || !datum | if ( !titel || !datum ) { | ||
return $.Deferred().reject( new OO.ui.Error( | return $.Deferred().reject( new OO.ui.Error( | ||
'Bitte | 'Bitte Seitentitel und Datum ausfüllen.', | ||
{ recoverable: true } | { recoverable: true } | ||
) ).promise(); | ) ).promise(); | ||
| Zeile 183: | Zeile 302: | ||
bild: v( dialog.bildInput.getValue() ), | bild: v( dialog.bildInput.getValue() ), | ||
websiteUrl: v( dialog.websiteUrlInput.getValue() ), | websiteUrl: v( dialog.websiteUrlInput.getValue() ), | ||
Adresse: v( dialog.AdresseInput.getValue() ), | |||
osmUrl: v( dialog.osmUrlInput.getValue() ), | osmUrl: v( dialog.osmUrlInput.getValue() ), | ||
koordinaten: v( dialog.koordinatenInput.getValue() ), | koordinaten: v( dialog.koordinatenInput.getValue() ), | ||
comapsUrl: v( dialog.comapsUrlInput.getValue() ), | comapsUrl: v( dialog.comapsUrlInput.getValue() ), | ||
gmapsUrl: v( dialog.gmapsUrlInput.getValue() ) | |||
gmapsUrl: v( dialog.gmapsUrlInput | |||
}; | }; | ||
// Auto-URL-Generierung aus Koordinaten für leere Felder | |||
var coords = parseCoordinates( fields.koordinaten ); | |||
fields.coords = coords; | |||
fields.titel = titel; | |||
if ( coords ) { | |||
if ( !fields.osmUrl ) { | |||
fields.osmUrl = buildOsmUrl( coords ); | |||
} | |||
if ( !fields.comapsUrl ) { | |||
fields.comapsUrl = buildCoMapsUrl( coords ); | |||
} | |||
if ( !fields.gmapsUrl ) { | |||
fields.gmapsUrl = buildGoogleMapsUrl( coords ); | |||
} | |||
} | |||
var wikitext = buildWikitext( fields ); | var wikitext = buildWikitext( fields ); | ||
var api = new mw.Api(); | var api = new mw.Api(); | ||
return api.get( { | return api.get( { | ||
action: 'query', | action: 'query', | ||
| Zeile 238: | Zeile 367: | ||
}; | }; | ||
var $container = $( '#event-form-container' ); | var $container = $( '#event-form-container' ); | ||
if ( !$container.length ) { | if ( !$container.length ) { | ||
Aktuelle Version vom 3. Juli 2026, 09:46 Uhr
/**
* Eventform-Gadget: Komfortables Anlegen von Veranstaltungsseiten
* Aktiv auf der Seite "Veranstaltungen"
*/
( function () {
'use strict';
// Konfiguration: auf welcher Seite soll der Button erscheinen?
var TRIGGER_PAGE = 'Veranstaltungen';
if ( mw.config.get( 'wgPageName' ) !== TRIGGER_PAGE ) {
return;
}
if ( !mw.config.get( 'wgUserName' ) ) {
return;
}
function v( val ) {
return ( val || '' ).trim();
}
/**
* Parst gängige Koordinaten-Formate.
* Gibt { lat, lng } zurück oder null bei ungültiger Eingabe.
*/
function parseCoordinates( input ) {
if ( !input ) {
return null;
}
var s = input.trim();
var m;
// Deutsches Format: Komma als Dezimaltrenner
// "47,7073132, 15,9934565" / "47,7073132; 15,9934565" / "47,7073132 15,9934565"
m = /^(-?\d+,\d+)\s*[;\s]\s*(-?\d+,\d+)$/.exec( s ) ||
/^(-?\d+,\d+),\s+(-?\d+,\d+)$/.exec( s );
if ( m ) {
var latDE = parseFloat( m[ 1 ].replace( ',', '.' ) );
var lngDE = parseFloat( m[ 2 ].replace( ',', '.' ) );
if ( isFinite( latDE ) && isFinite( lngDE ) &&
Math.abs( latDE ) <= 90 && Math.abs( lngDE ) <= 180 ) {
return { lat: latDE, lng: lngDE };
}
}
// Internationales Dezimal: "47.75,15.68" / "47.75 15.68" / "47.75; 15.68" / "-47.75,15.68"
m = /^(-?\d+(?:\.\d+)?)\s*[,;\s]\s*(-?\d+(?:\.\d+)?)$/.exec( s );
if ( m ) {
var lat = parseFloat( m[ 1 ] );
var lng = parseFloat( m[ 2 ] );
if ( isFinite( lat ) && isFinite( lng ) &&
Math.abs( lat ) <= 90 && Math.abs( lng ) <= 180 ) {
return { lat: lat, lng: lng };
}
}
// Dezimal mit NSEW: "47.75N 15.68E" / "47.75°N, 15.68°E" (auch mit Dezimal-Komma: "47,75N 15,68E")
m = /^(\d+(?:[.,]\d+)?)\s*°?\s*([NS])\s*[,;\s]?\s*(\d+(?:[.,]\d+)?)\s*°?\s*([EW])$/i.exec( s );
if ( m ) {
var lat2 = parseFloat( m[ 1 ].replace( ',', '.' ) );
if ( m[ 2 ].toUpperCase() === 'S' ) { lat2 = -lat2; }
var lng2 = parseFloat( m[ 3 ].replace( ',', '.' ) );
if ( m[ 4 ].toUpperCase() === 'W' ) { lng2 = -lng2; }
if ( isFinite( lat2 ) && isFinite( lng2 ) &&
Math.abs( lat2 ) <= 90 && Math.abs( lng2 ) <= 180 ) {
return { lat: lat2, lng: lng2 };
}
}
// DMS: 47°45'00.0"N 15°40'48.0"E
// Akzeptiert gerade (' ") und typografische (’ ” ″ ′) Zeichen
m = /^(\d+)\s*°\s*(\d+)\s*['\u2019\u2032]\s*(\d+(?:[.,]\d+)?)\s*["\u201D\u2033]\s*([NS])\s*[,;\s]?\s*(\d+)\s*°\s*(\d+)\s*['\u2019\u2032]\s*(\d+(?:[.,]\d+)?)\s*["\u201D\u2033]\s*([EW])$/i.exec( s );
if ( m ) {
var lat3 = parseInt( m[ 1 ], 10 ) + parseInt( m[ 2 ], 10 ) / 60 + parseFloat( m[ 3 ].replace( ',', '.' ) ) / 3600;
if ( m[ 4 ].toUpperCase() === 'S' ) { lat3 = -lat3; }
var lng3 = parseInt( m[ 5 ], 10 ) + parseInt( m[ 6 ], 10 ) / 60 + parseFloat( m[ 7 ].replace( ',', '.' ) ) / 3600;
if ( m[ 8 ].toUpperCase() === 'W' ) { lng3 = -lng3; }
if ( Math.abs( lat3 ) <= 90 && Math.abs( lng3 ) <= 180 ) {
return { lat: lat3, lng: lng3 };
}
}
// DM: 47°45.000'N 15°40.800'E (auch typografische Zeichen)
m = /^(\d+)\s*°\s*(\d+(?:[.,]\d+)?)\s*['\u2019\u2032]\s*([NS])\s*[,;\s]?\s*(\d+)\s*°\s*(\d+(?:[.,]\d+)?)\s*['\u2019\u2032]\s*([EW])$/i.exec( s );
if ( m ) {
var lat4 = parseInt( m[ 1 ], 10 ) + parseFloat( m[ 2 ].replace( ',', '.' ) ) / 60;
if ( m[ 3 ].toUpperCase() === 'S' ) { lat4 = -lat4; }
var lng4 = parseInt( m[ 4 ], 10 ) + parseFloat( m[ 5 ].replace( ',', '.' ) ) / 60;
if ( m[ 6 ].toUpperCase() === 'W' ) { lng4 = -lng4; }
if ( Math.abs( lat4 ) <= 90 && Math.abs( lng4 ) <= 180 ) {
return { lat: lat4, lng: lng4 };
}
}
return null;
}
function fmtCoord( n ) {
return n.toFixed( 7 );
}
function buildOsmUrl( c ) {
var lat = fmtCoord( c.lat );
var lng = fmtCoord( c.lng );
return 'https://www.openstreetmap.org/?mlat=' + lat + '&mlon=' + lng + '#map=17/' + lat + '/' + lng;
}
function buildGoogleMapsUrl( c ) {
return 'https://www.google.com/maps?q=' + fmtCoord( c.lat ) + ',' + fmtCoord( c.lng );
}
function buildCoMapsUrl( c ) {
// CoMaps (und Organic Maps) öffnen Koordinaten über das standardisierte
// geo:-URI-Schema (RFC 5870). Das https://comaps.at/... -Format
// existiert nicht. geo: öffnet auf Android die Karten-App mit Pin.
return 'geo:' + fmtCoord( c.lat ) + ',' + fmtCoord( c.lng );
}
function buildWikitext( f ) {
var lines = [];
lines.push( '[[Hauptseite]] > [[Hauptseite#Kultur & Events|Kultur & Events]] > [[Veranstaltungen]]' );
// Zeit
lines.push( '==Zeit==' );
lines.push( '🗓️ ' + f.datum );
if ( f.uhrzeit ) {
lines.push( '' );
lines.push( '⏰ ' + f.uhrzeit );
}
lines.push( '<br>' );
lines.push( '<br>' );
lines.push( '<br>' );
lines.push( '<br>' );
// Event
lines.push( '==Event==' );
if ( f.bild ) {
lines.push( '[[file:' + f.bild + '|frameless|upright=3.0]]' );
lines.push( '' );
}
if ( f.websiteUrl ) {
lines.push( '🌐 ' + f.websiteUrl );
}
lines.push( '<br>' );
lines.push( '<br>' );
lines.push( '<br>' );
lines.push( '<br>' );
// Location - jede Symbol-Zeile in eigenem Absatz (Leerzeile dazwischen)
lines.push( '==Location==' );
// Karte mit dem Veranstaltungsort als einzigem Pin (WikiMap-Gadget).
// Nutzt die geparsten Koordinaten, damit alle Eingabeformate
// (deutsches Format, DMS, ...) funktionieren.
if ( f.coords ) {
lines.push( '<div class="wikimap" data-pin="' +
fmtCoord( f.coords.lat ) + ',' + fmtCoord( f.coords.lng ) +
'" data-pin-name="' + ( f.Adresse || f.titel || 'Veranstaltungsort' ) +
'"></div>' );
lines.push( '' );
}
var locFirst = true;
function addLocLine( line ) {
if ( !locFirst ) {
lines.push( '' );
}
lines.push( line );
locFirst = false;
}
if ( f.Adresse ) {
addLocLine( '📍 ' + f.Adresse );
}
if ( f.osmUrl ) {
addLocLine( '[[file:osm.png|24px|link=]] ' + f.osmUrl );
}
if ( f.koordinaten ) {
addLocLine( '🧭 ' + f.koordinaten );
}
if ( f.comapsUrl ) {
addLocLine( '[[file:CoMaps.png|24px|link=]] ' + f.comapsUrl );
}
if ( f.gmapsUrl ) {
addLocLine( '[[file:GoogleMaps.png|24px|link=]] ' + f.gmapsUrl );
}
lines.push( '<br>' );
lines.push( '<br>' );
lines.push( '<br>' );
lines.push( '<br>' );
// Photos & Videos
lines.push( '==Photos & Videos==' );
lines.push( 'Bitte hier verlinken.' );
return lines.join( '\n' );
}
mw.loader.using( [
'oojs-ui-core',
'oojs-ui-windows',
'oojs-ui.styles.icons-interactions',
'mediawiki.api',
'mediawiki.util'
] ).then( function () {
function EventDialog( config ) {
EventDialog.super.call( this, config );
}
OO.inheritClass( EventDialog, OO.ui.ProcessDialog );
EventDialog.static.name = 'eventDialog';
EventDialog.static.title = 'Neue Veranstaltung anlegen';
EventDialog.static.actions = [
{ action: 'save', label: 'Seite anlegen', flags: [ 'primary', 'progressive' ] },
{ label: 'Abbrechen', flags: 'safe' }
];
EventDialog.prototype.initialize = function () {
EventDialog.super.prototype.initialize.apply( this, arguments );
this.panel = new OO.ui.PanelLayout( { padded: true, expanded: false } );
this.titelInput = new OO.ui.TextInputWidget( {
placeholder: 'z.B. Sommerfest 2026', required: true
} );
this.datumInput = new OO.ui.TextInputWidget( { type: 'date', required: true } );
this.uhrzeitInput = new OO.ui.TextInputWidget( { type: 'time', value: '17:00' } );
this.bildInput = new OO.ui.TextInputWidget( { placeholder: 'sommerfest.jpg' } );
this.websiteUrlInput = new OO.ui.TextInputWidget( { placeholder: 'https://...' } );
this.AdresseInput = new OO.ui.TextInputWidget( { placeholder: 'Nussbaum Straße ' } );
this.osmUrlInput = new OO.ui.TextInputWidget( { placeholder: 'https://www.openstreetmap.org/way/...' } );
this.koordinatenInput = new OO.ui.TextInputWidget( { placeholder: '47.7500000,15.6800000' } );
this.comapsUrlInput = new OO.ui.TextInputWidget( { placeholder: 'https://comaps.at/...' } );
this.gmapsUrlInput = new OO.ui.TextInputWidget( { placeholder: 'https://maps.app.goo.gl/...' } );
var fsBasis = new OO.ui.FieldsetLayout( { label: 'Pflichtfelder' } );
fsBasis.addItems( [
new OO.ui.FieldLayout( this.titelInput, {
label: 'Seitentitel', align: 'left',
help: 'Wird der Name der neuen Wiki-Seite. Muss eindeutig sein.'
} ),
new OO.ui.FieldLayout( this.datumInput, { label: 'Datum', align: 'left' } ),
new OO.ui.FieldLayout( this.uhrzeitInput, {
label: 'Uhrzeit', align: 'left',
help: 'Optional. Leer lassen wenn keine Uhrzeit gewünscht.'
} )
] );
var fsEvent = new OO.ui.FieldsetLayout( { label: 'Event' } );
fsEvent.addItems( [
new OO.ui.FieldLayout( this.bildInput, {
label: 'Bild (Dateiname)', align: 'left',
help: 'Wenn man die Dateiendung weiß (z.B. jpg), wähle einen sinnvollen Namen mit der richtigen Datei-Endung (z.B. Sommerfest2026.jpg ) wenn mann dann später auf der fertigen Seite darauf klickt, kann man auch das Bild hochladen. Leer lassen, wenn kein Bild.'
} ),
new OO.ui.FieldLayout( this.websiteUrlInput, { label: 'Website URL', align: 'left' } )
] );
var fsLoc = new OO.ui.FieldsetLayout( { label: 'Location (alles optional)' } );
fsLoc.addItems( [
new OO.ui.FieldLayout( this.AdresseInput, { label: 'Adresse', align: 'left' } ),
new OO.ui.FieldLayout( this.osmUrlInput, {
label: 'OpenStreetMap URL', align: 'left',
help: 'Leer lassen, dann wird bei gegebenen Koordinaten automatisch ein Link generiert.'
} ),
new OO.ui.FieldLayout( this.koordinatenInput, {
label: 'GPS-Koordinaten', align: 'left',
help: 'Akzeptiert u.a.: 47.75,15.68 · 47,7073132, 15,9934565 (deutsches Format) · 47.75N 15.68E · 47°45\'00"N 15°40\'48"E. Wenn gesetzt, werden für leere OSM/CoMaps/Google Maps Felder automatisch Links generiert und eine Karte auf der Seite eingebunden.'
} ),
new OO.ui.FieldLayout( this.comapsUrlInput, {
label: 'CoMaps URL', align: 'left',
help: 'Leer lassen, dann wird bei gegebenen Koordinaten automatisch ein Link generiert.'
} ),
new OO.ui.FieldLayout( this.gmapsUrlInput, {
label: 'Google Maps URL', align: 'left',
help: 'Leer lassen, dann wird bei gegebenen Koordinaten automatisch ein Link generiert.'
} )
] );
this.panel.$element.append( fsBasis.$element, fsEvent.$element, fsLoc.$element );
this.$body.append( this.panel.$element );
};
EventDialog.prototype.getActionProcess = function ( action ) {
var dialog = this;
if ( action === 'save' ) {
return new OO.ui.Process( function () {
var titel = v( dialog.titelInput.getValue() );
var datum = v( dialog.datumInput.getValue() );
var uhrzeit = v( dialog.uhrzeitInput.getValue() );
if ( !titel || !datum ) {
return $.Deferred().reject( new OO.ui.Error(
'Bitte Seitentitel und Datum ausfüllen.',
{ recoverable: true }
) ).promise();
}
var fields = {
datum: datum,
uhrzeit: uhrzeit,
bild: v( dialog.bildInput.getValue() ),
websiteUrl: v( dialog.websiteUrlInput.getValue() ),
Adresse: v( dialog.AdresseInput.getValue() ),
osmUrl: v( dialog.osmUrlInput.getValue() ),
koordinaten: v( dialog.koordinatenInput.getValue() ),
comapsUrl: v( dialog.comapsUrlInput.getValue() ),
gmapsUrl: v( dialog.gmapsUrlInput.getValue() )
};
// Auto-URL-Generierung aus Koordinaten für leere Felder
var coords = parseCoordinates( fields.koordinaten );
fields.coords = coords;
fields.titel = titel;
if ( coords ) {
if ( !fields.osmUrl ) {
fields.osmUrl = buildOsmUrl( coords );
}
if ( !fields.comapsUrl ) {
fields.comapsUrl = buildCoMapsUrl( coords );
}
if ( !fields.gmapsUrl ) {
fields.gmapsUrl = buildGoogleMapsUrl( coords );
}
}
var wikitext = buildWikitext( fields );
var api = new mw.Api();
return api.get( {
action: 'query',
titles: titel,
formatversion: 2
} ).then( function ( data ) {
var page = data.query.pages[ 0 ];
if ( !page.missing ) {
return $.Deferred().reject( new OO.ui.Error(
'Eine Seite mit dem Titel „' + titel + '" existiert bereits.',
{ recoverable: true }
) ).promise();
}
return api.postWithToken( 'csrf', {
action: 'edit',
title: titel,
text: wikitext,
createonly: true,
summary: 'Veranstaltung über Eventform-Gadget angelegt'
} );
} ).then( function () {
window.location.href = mw.util.getUrl( titel );
}, function ( err ) {
if ( err instanceof OO.ui.Error ) {
return $.Deferred().reject( err ).promise();
}
return $.Deferred().reject( new OO.ui.Error(
'Fehler beim Anlegen: ' + ( err && err.toString ? err.toString() : 'unbekannt' ),
{ recoverable: true }
) ).promise();
} );
} );
}
return EventDialog.super.prototype.getActionProcess.call( this, action );
};
EventDialog.prototype.getBodyHeight = function () {
return 600;
};
var $container = $( '#event-form-container' );
if ( !$container.length ) {
$container = $( '<div id="event-form-container"></div>' )
.appendTo( '#mw-content-text .mw-parser-output' );
}
var button = new OO.ui.ButtonWidget( {
label: 'Neue Veranstaltung anlegen',
flags: [ 'primary', 'progressive' ],
icon: 'add'
} );
var windowManager = new OO.ui.WindowManager();
$( document.body ).append( windowManager.$element );
var dialog = new EventDialog( { size: 'large' } );
windowManager.addWindows( [ dialog ] );
button.on( 'click', function () {
windowManager.openWindow( dialog );
} );
$container.empty().append( button.$element );
} );
}() );