Extension:PhotoSwipe

Category:Extensions without an imageCategory:Extensions without a compatibility policyCategory:GPL licensed extensions
MediaWiki extensions manual
PhotoSwipe
Release status: betaCategory:Beta status extensions
Implementation Tag Category:Tag extensions
Description Provides a front-endf JavaScript image gallery and lightbox using PhotoSwipe
Author(s) Jason Khanlar (Jasonkhanlartalk)
Latest version 1.0.0
MediaWiki >= 1.37.2Category:Extensions with manual MediaWiki version
PHP 7.4.x
Database changes No
Composer mediawiki/photoswipe Category:Extensions supporting Composer
License GNU General Public License 3.0 or later
Download Category:Extensions in Wikimedia version control
  • $wgPhotoSwipeConfig
Quarterly downloads 1 (Ranked 115th)
Translate the PhotoSwipe extension if it is available at translatewiki.net
Issues Open tasks · Report a bug
Category:All extensions

The PhotoSwipe extension provides a front-end JavaScript image gallery and lightbox using Photoswipe.

Installation

  • Download and move the extracted PhotoSwipe folder to your extensions/ directory.
    Developers and code contributors should install the extension from Git instead, using:cd extensions/
    git clone https://gerrit.wikimedia.org/r/mediawiki/extensions/PhotoSwipe
  • Only when installing from Git, run Composer to install PHP dependencies, by issuing composer install --no-dev in the extension directory. (See T173141 for potential complications.)Category:Extensions requiring Composer with git
  • Add the following code at the bottom of your LocalSettings.php file:
    wfLoadExtension( 'PhotoSwipe' );
    
  • run ./bin/build.sh or npm run build-lib to prepopulate the JS libraries.
  • Configure as required.
  • Yes Done – Navigate to Special:Version on your wiki to verify that the extension is successfully installed.

Configuration

$wgPhotoSwipeConfig

This defines values for each section of configuration. $wgPhotoSwipeConfig</tvar> is an associative array of mixed values, with each sub-value having zero or more of the following parameters.


parameter type description
mode string Adjusts the usage of PhotoSwipe library. Possible values: ['recommended'](https://photoswipe.com/getting-started/#initialization), ['withoutDynamicImport'](https://photoswipe.com/getting-started/#without-dynamic-import), ['withoutLightbox'](https://photoswipe.com/data-sources/#without-lightbox-module)
options object The options object passed into the PhotoSwipeLightbox instance.
addBeginning string Additional JavaScript to add in the beginning.
array of strings An array of strings of JavaScript to add.
addEventables string Additional JavaScript to add in the middle.
array of strings An array of strings of JavaScript to add.
addEnd string Additional JavaScript to add in the end.
array of strings An array of strings of JavaScript to add.
plugins array of strings An array of strings of names of plugins to enable with default options. See PhotoSwipeVendorList.
object of options An object of keys of plugins to enable with custom options. The values are the options object passed to the plugin library.

For example, in your LocalSettings.php: (note: make sure to \ escape all $ in string values containing JavaScript)

all-in-one associative array

$wgPhotoSwipeConfig = [
	"mode" => "recommended",
	"options" => [
		"gallery" => "table.gallery",
		"children" => "a.img",
		"thumbSelector" => "a.img",
		"pswpModule" => "() => require( 'js.photoswipe' )",
		// Recommended PhotoSwipe options for this plugin
		"allowPanToNext" => false, // prevent swiping to the next slide when image is zoomed
		"allowMouseDrag" => true, // display dragging cursor at max zoom level
		"wheelToZoom" => true, // enable wheel-based zoom
		"zoom" => false // disable default zoom button
	],
	"addBeginning" => [
		"document.querySelectorAll( 'table.gallery img' ).forEach( ( e, i ) => {
			if ( e.parentElement.tagName !== 'A' ) {
				document.querySelectorAll( 'img' )[ i ].outerHTML = `<a class='img' href='\${e.src}'; data-my-size='\${e.naturalWidth}x\${e.naturalHeight}'>\${e.outerHTML}</a>`;
			}
		} );"
	],
	"addEventables" => [
		"const backEasing = {
			in: 'cubic-bezier(0.6, -0.28, 0.7, 1)',
			out: 'cubic-bezier(0.3, 0, 0.32, 1.275)',
			inOut: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)'
		}",
		"lightbox.on( 'firstUpdate', () => { lightbox.pswp.options.easing = backEasing.out; } );",
		"lightbox.on( 'initialZoomInEnd', () => { lightbox.pswp.options.easing = backEasing.inOut; } );",
		"lightbox.on( 'close', () => { lightbox.pswp.options.easing = backEasing.in; } );",
		"lightbox.addFilter( 'domItemData', ( itemData, element, linkEl ) => {
			if ( linkEl ) {
				const sizeAttr = linkEl.dataset.mySize;
				itemData.src = linkEl.href;
				itemData.w = Number( sizeAttr.split( 'x' )[ 0 ] );
				itemData.h = Number( sizeAttr.split( 'x' )[ 1 ] );
				itemData.msrc = linkEl.dataset.thumbSrc;
				itemData.thumbCropped = true;
			}
			return itemData;
		} );"
	],
	"addEnd" => [],
	"plugins" => [
		"DeepZoomPlugin" => [
			"enabled" => true,
			"options" => [
				"tileSize" => 256
			]
		],
		"DynamicCaption" => [
			"enabled" => true,
			"options" => [
				"captionContent" => ".pswp-caption-content",
				"horizontalEdgeThreshold" => 20,
				"mobileCaptionOverlapRatio" => 0.3,
				"mobileLayoutBreakpoint" => 600,
				"type" => "auto"
			]
		],
		"VideoPlugin" => [
			"enabled" => true,
			"options" => []
		]
	]
];

individual key values of associative array

$wgPhotoSwipeConfig["mode"] = "recommended";
$wgPhotoSwipeConfig["options"]["gallery"] = "table.gallery";
$wgPhotoSwipeConfig["options"]["children"] = "a.img";
$wgPhotoSwipeConfig["options"]["thumbSelector"] = "a.img";
$wgPhotoSwipeConfig["options"]["pswpModule"] = "() => require( 'js.photoswipe' )";
// Recommended PhotoSwipe options for this plugin
$wgPhotoSwipeConfig["options"]["allowPanToNext"] = false; // prevent swiping to the next slide when image is zoomed
$wgPhotoSwipeConfig["options"]["allowMouseDrag"] = true; // display dragging cursor at max zoom level
$wgPhotoSwipeConfig["options"]["wheelToZoom"] = true; // enable wheel-based zoom
$wgPhotoSwipeConfig["options"]["zoom"] = false; // disable default zoom button
$wgPhotoSwipeConfig["addBeginning"] = [
	"document.querySelectorAll( 'table.gallery img' ).forEach( ( e, i ) => {
		if ( e.parentElement.tagName !== 'A' ) {
			document.querySelectorAll( 'img' )[ i ].outerHTML = `<a class='img' href='\${e.src}'; data-my-size='\${e.naturalWidth}x\${e.naturalHeight}'>\${e.outerHTML}</a>`;
		}
	} );"
];
$wgPhotoSwipeConfig["addEventables"] = [
	"const backEasing = {
		in: 'cubic-bezier(0.6, -0.28, 0.7, 1)',
		out: 'cubic-bezier(0.3, 0, 0.32, 1.275)',
		inOut: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)'
	}",
	"lightbox.on( 'firstUpdate', () => { lightbox.pswp.options.easing = backEasing.out; } );",
	"lightbox.on( 'initialZoomInEnd', () => { lightbox.pswp.options.easing = backEasing.inOut; } );",
	"lightbox.on( 'close', () => { lightbox.pswp.options.easing = backEasing.in; } );",
	"lightbox.addFilter( 'domItemData', ( itemData, element, linkEl ) => {
		if ( linkEl ) {
			const sizeAttr = linkEl.dataset.mySize;
			itemData.src = linkEl.href;
			itemData.w = Number( sizeAttr.split( 'x' )[ 0 ] );
			itemData.h = Number( sizeAttr.split( 'x' )[ 1 ] );
			itemData.msrc = linkEl.dataset.thumbSrc;
			itemData.thumbCropped = true;
		}
		return itemData;
	} );"
];
$wgPhotoSwipeConfig["addEnd"] = [];
$wgPhotoSwipeConfig["plugins"]["DeepZoomPlugin"]["enabled"] = true;
$wgPhotoSwipeConfig["plugins"]["DeepZoomPlugin"]["options"]["tileSize"] = 256;
$wgPhotoSwipeConfig["plugins"]["DynamicCaption"]["enabled"] = true;
$wgPhotoSwipeConfig["plugins"]["DynamicCaption"]["options"]["captionContent"] = ".pswp-caption-content";
$wgPhotoSwipeConfig["plugins"]["DynamicCaption"]["options"]["horizontalEdgeThreshold"] = 20;
$wgPhotoSwipeConfig["plugins"]["DynamicCaption"]["options"]["mobileCaptionOverlapRatio"] = 0.3;
$wgPhotoSwipeConfig["plugins"]["DynamicCaption"]["options"]["mobileLayoutBreakpoint"] = 600;
$wgPhotoSwipeConfig["plugins"]["DynamicCaption"]["options"]["type"] = "auto";
$wgPhotoSwipeConfig["plugins"]["VideoPlugin"]["enabled"] = true;
$wgPhotoSwipeConfig["plugins"]["VideoPlugin"]["options"] = [];

Usage

Note: Images and gallery content not included.

Use extension configuration by default

<photoswipe/>

Use argument configuration (overrides extension configuration)

<photoswipe
  mode=recommended
  options="{
    &quot;gallery&quot;: &quot;table.gallery&quot;,
    &quot;children&quot;: &quot;a.img&quot;,
    &quot;thumbSelector&quot;: &quot;a.img&quot;,
    &quot;pswpModule&quot;: &quot;() =&gt; require(&apos;js.photoswipe&apos;)&quot;,
    &quot;allowPanToNext&quot;: false,
    &quot;allowMouseDrag&quot;: true,
    &quot;wheelToZoom&quot;: true,
    &quot;zoom&quot;: false
  }"
  addBeginning="document.querySelectorAll( &apos;table.gallery img&apos; ).forEach( ( e, i ) =&gt; {
    if ( e.parentElement.tagName !== &apos;A&apos; ) {
      document.querySelectorAll( &apos;img&apos; )[ i ].outerHTML = `&lt;a class='img' href=&quot;${e.src}&quot; data-my-size=&quot;${e.naturalWidth}x${e.naturalHeight}&quot;&gt;${e.outerHTML}&lt;/a&gt;`;
    }
  } );"
  addEventables="[
    &quot;const backEasing = { in: &apos;cubic-bezier(0.6, -0.28, 0.7, 1)&apos;, out: &apos;cubic-bezier(0.3, 0, 0.32, 1.275)&apos;, inOut: &apos;cubic-bezier(0.68, -0.55, 0.265, 1.55)&apos; }&quot;,
    &quot;lightbox.on( &apos;firstUpdate&apos;, () =&gt; { lightbox.pswp.options.easing = backEasing.out; } );&quot;,
    &quot;lightbox.on( &apos;initialZoomInEnd&apos;, () =&gt; { lightbox.pswp.options.easing = backEasing.inOut; } );&quot;,
    &quot;lightbox.on( &apos;close&apos;, () =&gt; { lightbox.pswp.options.easing = backEasing.in; } );&quot;,
    &quot;lightbox.addFilter( &apos;domItemData&apos;, ( itemData, element, linkEl ) =&gt; { if ( linkEl ) { const sizeAttr = linkEl.dataset.mySize; itemData.src = linkEl.href; itemData.w = Number( sizeAttr.split( &apos;x&apos; )[ 0 ] ); itemData.h = Number( sizeAttr.split( &apos;x&apos; )[ 1 ] ); itemData.msrc = linkEl.dataset.thumbSrc; itemData.thumbCropped = true; } return itemData; } );&quot;
  ]"
  addEnd="[]"
  plugins="{
    &quot;DeepZoomPlugin&quot;: {
      &quot;enabled&quot;: true,
      &quot;options&quot;: {
        &quot;tileSize&quot;: 256
      }
    },
    &quot;DynamicCaption&quot;: {
      &quot;enabled&quot;: true,
      &quot;options&quot;: {
        &quot;captionContent&quot;: &quot;.pswp-caption-content&quot;,
        &quot;horizontalEdgeThreshold&quot;: 20,
        &quot;mobileCaptionOverlapRatio&quot;: 0.3,
        &quot;mobileLayoutBreakpoint&quot;: 600,
        &quot;type&quot;: &quot;auto&quot;
      }
    },
    &quot;VideoPlugin&quot;: {
      &quot;enabled&quot;: true,
      &quot;options&quot;: {}
    }
  }"
/>

Use content configuration (overrides extension configuration and argument configuration)

Note: Comments and multi-line strings are permitted here

<photoswipe>
{
	"mode": "recommended",
	"options": {
		"gallery": "table.gallery",
		"children": "a.img",
		"thumbSelector": "a.img",
		"pswpModule": "() => require( 'js.photoswipe' )",
		// Recommended PhotoSwipe options for this plugin
		"allowPanToNext": false, // prevent swiping to the next slide when image is zoomed
		"allowMouseDrag": true, // display dragging cursor at max zoom level
		"wheelToZoom": true, // enable wheel-based zoom
		"zoom": false // disable default zoom button
	},
	"addBeginning": [
		"document.querySelectorAll( 'table.gallery img' ).forEach( ( e, i ) => {
			if ( e.parentElement.tagName !== 'A' ) {
				document.querySelectorAll( 'img' )[ i ].outerHTML = `<a class='img' href='${e.src}'; data-my-size='${e.naturalWidth}x${e.naturalHeight}'>${e.outerHTML}</a>`;
			}
		} );"
	],
	"addEventables": [
		"const backEasing = {
			in: 'cubic-bezier(0.6, -0.28, 0.7, 1)',
			out: 'cubic-bezier(0.3, 0, 0.32, 1.275)',
			inOut: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)'
		}",
		"lightbox.on( 'firstUpdate', () => { lightbox.pswp.options.easing = backEasing.out; } );",
		"lightbox.on( 'initialZoomInEnd', () => { lightbox.pswp.options.easing = backEasing.inOut; } );",
		"lightbox.on( 'close', () => { lightbox.pswp.options.easing = backEasing.in; } );",
		"lightbox.addFilter( 'domItemData', ( itemData, element, linkEl ) => {
			if ( linkEl ) {
				const sizeAttr = linkEl.dataset.mySize;
				itemData.src = linkEl.href;
				itemData.w = Number( sizeAttr.split( 'x' )[ 0 ] );
				itemData.h = Number( sizeAttr.split( 'x' )[ 1 ] );
				itemData.msrc = linkEl.dataset.thumbSrc;
				itemData.thumbCropped = true;
			}
			return itemData;
		} );"
	],
	"addEnd": [],
	"plugins": {
		"DeepZoomPlugin": {
			"enabled": true,
			"options": {
				"tileSize": 256
			}
		},
		"DynamicCaption": {
			"enabled": true,
			"options": {
				"captionContent": ".pswp-caption-content",
				"horizontalEdgeThreshold": 20,
				"mobileCaptionOverlapRatio": 0.3,
				"mobileLayoutBreakpoint": 600,
				"type": "auto"
			}
		},
		"VideoPlugin": {
			"enabled": true,
			"options": {}
		}
	}
}
</photoswipe>

See also

Category:Image extensions Category:Image gallery extensions
Category:All extensions Category:Beta status extensions Category:Extensions in Wikimedia version control Category:Extensions requiring Composer with git Category:Extensions supporting Composer Category:Extensions with manual MediaWiki version Category:Extensions without a compatibility policy Category:Extensions without an image Category:GPL licensed extensions Category:Image extensions Category:Image gallery extensions Category:ParserFirstCallInit extensions Category:Tag extensions