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
/* eslint-disable max-len */ // <nowiki> /******************************************************************************  * Zukunft.js  * Gebündelte Anzeige aller mit {{Zukunft}} als veraltet markierten Informationen.  *  * Depends on: .voy-zukunft[data-note], .voy-zukunft[data-timestamp]  * License: CC0  * Maintainer: nw520  ******************************************************************************/  mw.loader.using( 'mw.html', 'mw.util' ).then( function () { 	mw.hook( 'wikipage.content' ).add( function ( $container ) { 		/** 		 * @constant 		 * @type {string} 		 */ 		var NOTE_ATTR = 'data-note';  		/** 		 * @constant 		 * @type {string} 		 */ 		var TIMESTAMP_ATTR = 'data-timestamp';  		/** 		 * @constant 		 * @type {string} 		 */ 		var OUTDATED_CLASS = 'voy-zukunft';  		/** 		 * Dauer in Millisekunden, für welche ein Element hervorgehoben wird, wenn ein Benutzer auf die Warnung geklickt hat. 		 * 0 um zu deaktivieren. 		 * 		 * @constant 		 * @type {number} 		 */ 		var HIGHLIGHT_DURATION = 5000;  		/** 		 * @class 		 * @param {HTMLElement} element 		 * @param {string} h2 		 * @param {string} h3 		 * @param {string} h4 		 * @param {string} h5 		 * @param {string} h6 		 */ 		var SectionedMatch = function ( element, h2, h3, h4, h5, h6 ) { 			this.element = element; 			this.h2 = h2; 			this.h3 = h3; 			this.h4 = h4; 			this.h5 = h5; 			this.h6 = h6;  			return this; 		};  		/** 		 * Gibt einen Brotkrümelpfad für die Abschnitte aus. 		 * @return {string} 		 */ 		SectionedMatch.prototype.getSection = function () { 			if ( this.h2 === null && this.h3 === null && this.h4 === null && this.h5 === null && this.h6 === null ) { 				return null; 			} else { 				var out = [ this.h2, this.h3, this.h4, this.h5, this.h6 ]; 				out = out.filter( function ( item ) { 					return item !== null; 				} ); 				return out.join( ' / ' ); 			} 		};  		/** 		 * @class 		 * @param {SectionedMatch} match Zugehöriges Element, für das die Warnung gilt. 		 * @param {number} reason Begründung der Fehlermeldung, siehe {@link WarningItem.reasons}. 		 * @param {string} note Vom Nutzer hinterlegter Hinweis. 		 */ 		var WarningItem = function ( match, reason, note ) { 			this.match = match; 			this.reason = reason; 			this.note = note || null; 			return this; 		};  		/** 		 * @enum {number} 		 */ 		WarningItem.reasons = { 			UNSPECIFIED: 0, 			OUTDATED: 1, 			ERRORNEOUS_TIMESTAMP: 2 		};  		function main() { 			mw.util.addCSS( '.voy-zukunft { background-color: transparent; transition: background .4s ease-in-out; } .voy-zukunft .mw-redirect { background: none; } .voy-zukunft-highlight { animation: voy-zukunft-pulse .7s infinite alternate; } .voy-zukunft-warnbox { background: #f9f9f9; border: 1px solid #f66; border-left: 10px solid #f66; box-sizing: border-box; margin: .5em 0; overflow: hidden; padding: .5em; text-align: left; width: auto; } @keyframes voy-zukunft-pulse { 0% { background: transparent; } 100% { background: lightsalmon; } }' );  			var warnings = filter( findAndDetermineSection( '.' + OUTDATED_CLASS + '[' + TIMESTAMP_ATTR + ']', $container[ 0 ] ) );  			if ( warnings.length === 0 ) { 				return; 			} 			 			// Cleanup old boxes: Avoid multiple boxes when using RealtimePreview 			document.querySelectorAll( '.voy-zukunft-warnbox' ).forEach( function ( warnbox ) { 				warnbox.remove(); 			} );  			var container = document.createElement( 'div' ); 			container.classList.add( 'voy-zukunft-warnbox' ); 			container.innerHTML = '<p>In diesem Reiseführer finden sich einige veraltete Angaben. Hilf mit, indem du sie aktualisierst:</p>';  			var matchesUl = document.createElement( 'ul' ); 			container.appendChild( matchesUl );  			generateWarnings( warnings ).forEach( function ( match ) { 				matchesUl.appendChild( match ); 			} );  			document.getElementById( 'bodyContent' ).insertAdjacentElement( 'afterbegin', container ); 		}  		/** 		 * Überprüft, ob die Elemente tatsächlich veraltet sind anhand des in {@link TIMESTAMP_ATTR} definierten Attributs und gibt eine Liste an veralteten Elementen aus. Es wird das Format YYYY, YYYY-MM, oder YYYY-MM-DD erwartet. 		 * 		 * @param {Array<SectionedMatch>} matches 		 * @return {Array<WarningItem>} Liste an {@link WarningItem} mit veralteten Werten. 		 */ 		function filter( matches ) { 			var out = [];  			matches.forEach( function ( match ) { 				try { 					var splitTimestamp = match.element.getAttribute( TIMESTAMP_ATTR ).split( '-' ); 					var date = new Date(); 					if ( splitTimestamp.length >= 1 && parseInt( splitTimestamp[ 0 ] ) < date.getFullYear() ) { 						out.push( new WarningItem( match, WarningItem.reasons.OUTDATED, match.element.getAttribute( NOTE_ATTR ) ) ); 					} else if ( parseInt( splitTimestamp[ 0 ] ) === date.getFullYear() ) { 						if ( splitTimestamp.length >= 2 && parseInt( splitTimestamp[ 1 ] ) < date.getMonth() + 1 ) { 							out.push( new WarningItem( match, WarningItem.reasons.OUTDATED, match.element.getAttribute( NOTE_ATTR ) ) ); 						} else if ( parseInt( splitTimestamp[ 1 ] ) === date.getMonth() + 1 ) { 							if ( splitTimestamp.length >= 3 && parseInt( splitTimestamp[ 2 ] ) < date.getDate() ) { 								out.push( new WarningItem( match, WarningItem.reasons.OUTDATED, match.element.getAttribute( NOTE_ATTR ) ) ); 							} 						} 					} 				} catch ( e ) { 					mw.log.warn( e ); 					out.push( new WarningItem( match, WarningItem.reasons.ERRORNEOUS_TIMESTAMP, match.element.getAttribute( NOTE_ATTR ) ) ); 				} 			} ); 			return out; 		}  		/** 		 * @param  {string|Array<string>} selectors Selektoren, mit den Elemente gefunden werden sollen. 		 * @param  {HTMLElement} parent Elternelement, in dem Selektoren gefunden werden sollen. 		 * @return {Array<SectionedMatch>} 		 */ 		function findAndDetermineSection( selectors, parent ) { 			var castedSelectors = typeof selectors === 'string' ? selectors : selectors.join( ',' );  			var itemsAndSections = parent.querySelectorAll( 'h2,h3,h4,h5,h6,' + selectors ); 			var sections = { 				H6: null, 				H5: null, 				H4: null, 				H3: null, 				H2: null 			}; 			var sectionOrder = [ 'H6', 'H5', 'H4', 'H3', 'H2' ];  			var items = []; 			itemsAndSections.forEach( function ( itemOrSection ) { 				if ( itemOrSection.matches( castedSelectors ) ) { // Item 					items.push( new SectionedMatch( itemOrSection, sections.H2, sections.H3, sections.H4, sections.H5, sections.H6 ) ); 				} else { // Section 					if ( itemOrSection.closest( '#toc' ) === null ) { 						for ( var i = 0; i < sectionOrder.length; i++ ) { 							var sectionTag = sectionOrder[ i ]; 							if ( itemOrSection.tagName === sectionTag && itemOrSection.querySelectorAll( '.mw-headline' ).length > 0 ) { // Section 								// Set this section 								sections[ sectionTag ] = itemOrSection.querySelector( '.mw-headline' ).textContent; 								break; 							} else { 								sections[ sectionTag ] = null; 							} 						} 					} 				} 			} ); 			return items; 		}  		/** 		 * Erzeugt aus einer Liste an {@link WarningItem} als Liste von li-Elementen (HTMLElement). 		 * 		 * @param {Array<WarningItem>} warnings Liste an veralteten {@link WarningItem}. 		 * @return {Array<HTMLElement>} Text in Wikimedia-Markup für Ausgabe der Warnungen. 		 */ 		function generateWarnings( warnings ) { 			return warnings.map( function ( warning ) { 				var section = warning.match.getSection(); 				var location = '<a href="#zukunft">' + ( section === null ? 'In der Einleitung' : 'Im Abschnitt „' + mw.html.escape( section ) + '“' ) + '</a>'; 				var note = warning.note !== null ? ': ' + mw.html.escape( warning.note ) : '';  				var matchLi = document.createElement( 'li' ); 				if ( warning.reason === WarningItem.reasons.OUTDATED ) { 					matchLi.innerHTML = '<li>' + location + ' ist eine potentiell veraltete Angabe' + note + '</li>'; 				} else { 					matchLi.innerHTML = '<li>' + location + ' ist eine fehlerhafte Angabe' + note + '</li>'; 				}  				matchLi.querySelector( 'a' ).addEventListener( 'click', function ( e ) { 					e.preventDefault(); 					warning.match.element.scrollIntoView({ 						behavior: 'smooth', 						block: 'center', 						inline: 'center' 			        } ); 					highlightElement( warning.match.element ); 				} );  				return matchLi; 			} ); 		}  		/** 		 * Hebt das gegebene Element {@link HIGHLIGHT_DURATION} lang hervor. 		 * 		 * @param {HTMLElement} element Element, welches hervorgehoben werden soll. 		 */ 		function highlightElement( element ) { 			if ( HIGHLIGHT_DURATION > 0 ) { 				element.classList.add( 'voy-zukunft-highlight' ); 				setTimeout( function () { 					element.classList.remove( 'voy-zukunft-highlight' ); 				}, HIGHLIGHT_DURATION ); 			} 		} 		main(); 	} ); } ); // </nowiki>