MediaWiki:Gadget-ScrollGallery.js

Aus Wikivoyage

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
/***************************************************************************
 * scrollGallery v2.0, 2023-08-30
 * Scrolling through Image Galleries
 * Original author: Roland Unger
 * Support of desktop and mobile views
 * Documentation: https://de.wikivoyage.org/wiki/Wikivoyage:Gadget-ScrollGallery.js
 * License: GPL-2.0+, CC-by-sa 3.0
 ***************************************************************************/
/* eslint-disable mediawiki/class-doc */

( function ( mw, $ ) {
	'use strict';

	var scrollGalleries = function() {
		const str = {
			prev   : '◀',
			next   : '▶',
			counter: '$1/$2'
		};

		// preloadImages() is only used in mobile view. It substitutes the lazy
		// image mode which prevents loading hidden images.

		function preloadImages() {
			$( 'noscript' ).each( function() {
				var p = $( this ).next(); // <span class="lazy-image-placeholder" ...>
				if ( p.hasClass( 'lazy-image-placeholder' ) ) {
					var img = $( '<img />', {
						src   : p.attr( 'data-src' ),
						width : p.attr( 'data-width' ),
						height: p.attr( 'data-height' ),
						alt   : p.attr( 'data-alt' )
					} );
					p.replaceWith( img );
				}
			} );
		}

		function processEvent( event, diff ) {
			var target = $( event.target ),
				unit   = target.closest( '.voy-ImageGrUnit' ),
				group  = target.closest( '.voy-ImageGroup' ),
				imgs   = $( '.voy-ImageGrUnit', group ),
				which  = 0;

			imgs.each( function( index ) {
				if ( $( this ).is( unit ) ) {
					which = index;
					return false; // breaks
				}
			} );
			which += diff;
			if ( which < 0 ) {
				which = imgs.length - 1;
			} else if ( which > imgs.length - 1 ) {
				which = 0;
			}

			imgs.each( function( index ) {
				$( this ).toggle( index == which );
			} );
		}

		function hideButton( button ) {
			button.attr( { class: 'voy-ImageNoLoop', title: '' } );
		}

		function setButtonAttr( button, imgIndex, imgs, diff ) {
			button.attr( { class: 'voy-ImageButton',
					title: mw.format( str.counter, imgIndex, imgs.length ) } )
				.click( function( event ) {
					processEvent( event, diff );
				} );
		}

		function makeImageHeaders( imgs, firstImg, showUnitHeader, noLoop ) {
			// for multiple images in a single scroll gallery
			imgs.each( function( index ) {
				var $this = $( this ), imgIndex;

				// add scroll buttons to the header
				if ( showUnitHeader ) {
					// setting link to the previous image
					var prevLink = $( '<span>' + str.prev + '</span>' );
					// preventing loops at the first or large image
					if ( index === 0 && noLoop ) {
						hideButton( prevLink );
					} else {
						imgIndex = ( index === 0 ) ? imgs.length : index;
						setButtonAttr( prevLink, imgIndex, imgs, -1 );
					}

					// setting link to the next image
					var nextLink = $( '<span>' + str.next + '</span>' );
					if ( index === imgs.length - 1 && noLoop ) {
						hideButton( nextLink );
					} else {
						imgIndex = ( index === imgs.length - 1 ) ? 1 : index + 2;
						setButtonAttr( nextLink, imgIndex, imgs, 1 );
					}

					// setting counter values between previous and next links
					var counter = mw.format( str.counter, index + 1, imgs.length ),
						imgHead = $( '<div class="voy-ImageGrUnitHeader voy-timeless-no-emoji"> ' +
							counter + ' </div>' )
							.prepend( prevLink )
							.append( nextLink );
					$this.prepend( imgHead );
				}

				$this.toggle( index == firstImg );
			} );
		}

		function makeScrollGalleryHeaders( galleries ) {
			// for multiple scroll galleries
			galleries.each( function() {
				var $this = $( this ),
					imgs = $( '.voy-ImageGrUnit', $this );
				if ( imgs.length < 2 ) {
					return;
				}

				// getting gallery width excluding width of the header from
				// a (right) floated clone
				var clone = $this.clone();
				$( '.voy-ImageGrUnit', clone ).show();
				$( '.voy-ImageGroupHeader', clone ).hide();
				clone.show()
					.css( { visibility: 'hidden', float: 'right' } )
					.appendTo( $( 'body' ) );
				$this.css( 'width', clone.width() + 'px' );
				clone.remove();

				var firstImg = 0;
				// starting with time-depending image
				var timeDependent = $this.hasClass( 'voy-timeDependent' );
				if ( timeDependent ) {
					var timeNow = new Date();
					timeNow = timeNow.getHours() + timeNow.getMinutes() / 60;
					firstImg = Math.floor( timeNow * imgs.length / 24 );
					firstImg = Math.min( firstImg, imgs.length - 1 );
				}

				var showUnitHeader = !$this.hasClass( 'voy-hideUnitHeader' ),
					noLoop = $this.hasClass( 'voy-noLoop' );
				makeImageHeaders( imgs, firstImg, showUnitHeader, noLoop );
			} );
		}

		function init() {
			// for VisualEditor and Realtime Preview
			mw.hook( 'wikipage.content' ).add( function ( $content ) {
				// getting all scroll galleries
				var galleries = $( '.voy-ImageGroup', $content );
				if ( !galleries.length ) {
					return;
				}

				preloadImages();
				makeScrollGalleryHeaders( galleries );
			} );
		}

		return { init: init };
	} ();

	$( scrollGalleries.init );

} ( mediaWiki, jQuery ) );