/** * jpictures.js * JavaScript functions for the pictures galleries. */ "use strict"; // Import PhotoSwipe Lightbox import PhotoSwipe from './photoswipe/photoswipe.esm.min.js'; import PhotoSwipeLightbox from './photoswipe/photoswipe-lightbox.esm.min.js'; import PhotoSwipeDynamicCaption from './photoswipe/photoswipe-dynamic-caption-plugin.esm.js' // Import internationalization support import i18n from './../i18n.js'; class PhotoSwipePictureGallery { constructor(items) { // Create PhotoSwipe Lightbox const lightboxOptions = { dataSource: items, pswpModule: PhotoSwipe, bgOpacity: 0.95, closeOnVerticalDrag: false, closeTitle: i18n.viewer_close + ' (Esc)', zoomTitle: i18n.viewer_zoom + ' (z)', arrowPrevTitle: i18n.viewer_previous, arrowNextTitle: i18n.viewer_next, }; this.lightbox = new PhotoSwipeLightbox(lightboxOptions); // Initialize caption plugin const captionPluginOptions = { type: 'below', mobileLayoutBreakpoint: 800, captionContent: (slide) => { return this._captionContent(slide) }, }; this.captionPlugin = new PhotoSwipeDynamicCaption(this.lightbox, captionPluginOptions); // Add custom 'Info' button, see https://photoswipe.com/v5/docs/adding-custom-buttons/ // Info menu button const infoButton = { name: 'info', title: i18n.viewer_toggle_caption, order: 15, // Insert button between zoom & close buttons isButton: true, html: { isCustomSVG: true, inner: '<path d="M7 16a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" id="pswp__icn-info"/>' + '<path fill="currentColor" d="M17 15h-2v6h2z"/>' + '<path fill="currentColor" d="M17 11h-2v2h2z"/>', outlineID: 'pswp__icn-info', }, onClick: (ev, el, pswp) => { this._toggleInfoPannel(ev, el, pswp); }, }; this.lightbox.on('uiRegister', () => { this.lightbox.pswp.ui.registerElement(infoButton); }); this.lightbox.on('calcSlideSize', (e) => { /* When using mobile layout for caption, hide the Info button since the caption is fixed * at the bottom. */ if (this.captionPlugin.useMobileLayout()) { document.querySelector('.pswp__button--info').style.display = 'none'; } else { document.querySelector('.pswp__button--info').style.display = ''; } }); } // Open gallery at the given slide index (starting at 0) open(index) { this.lightbox.init(); this.lightbox.loadAndOpen(index); } // Switch between regular caption (below image) and info pannel (aside) _toggleInfoPannel(ev, el, pswp) { if (this.captionPlugin.options.type === 'below') { this.captionPlugin.options.type = 'aside'; } else if (this.captionPlugin.options.type === 'aside') { this.captionPlugin.options.type = 'below'; } /* Force updating size of all PhotoSwipe elements. This will trigger the 'calcSlideSize' event * on each loaded slide, causing update of the caption text (see handler above). */ this.lightbox.pswp.updateSize(true); } _convertDate(iso8601_date) { const d = new Date(iso8601_date); const str = d.toLocaleDateString() + ' ' + d.toLocaleTimeString().replace(/(\d{2}):(\d{2}):(\d{2})/, '$1h$2'); return str; } // Get caption content, according to current image & caption layout _captionContent(slide) { const slideTitle = slide.data.title; const slideDateTime = this._convertDate(slide.data.datetime, true); if (this.captionPlugin.options.type === 'aside' && !this.captionPlugin.useMobileLayout()) { var caption = '<strong>' + slideTitle + '</strong><hr />' + '<p class="pswp__caption__exif pswp__caption__exif_datetime">' + slideDateTime + '</p>'; if (slide.data.artist) { caption += '<p class="pswp__caption__exif pswp__caption__exif_author">' + slide.data.artist + '</p>'; } if (slide.data.event) { caption += '<p class="pswp__caption__exif pswp__caption__exif_event">' + slide.data.event + '</p>'; } if (slide.data.city || slide.data.region) { caption += '<p class="pswp__caption__exif pswp__caption__exif_location">'; if (slide.data.city) { caption += slide.data.city; } if (slide.data.city && slide.data.region) { caption += ', '; } if (slide.data.region) { caption += slide.data.region; } caption += '</p>'; } if (slide.data.model) { caption += '<p class="pswp__caption__exif pswp__caption__exif_camera">' + slide.data.model + '</p>'; } if (slide.data.focallength) { caption += '<p class="pswp__caption__exif pswp__caption__exif_focal">' + slide.data.focallength + '</p>'; } if (slide.data.fnumber) { caption += '<p class="pswp__caption__exif pswp__caption__exif_fstop">' + slide.data.fnumber + '</p>'; } if (slide.data.exposure) { caption += '<p class="pswp__caption__exif pswp__caption__exif_shutter">' + slide.data.exposure + '</p>'; } if (slide.data.isospeed) { caption += '<p class="pswp__caption__exif pswp__caption__exif_iso">' + 'ISO ' + slide.data.isospeed + '</p>'; } return caption; } else { return '<strong>' + slideDateTime + '</strong> — ' + slideTitle; } } } function createImageGallery(json) { var items = []; for (let i = 0; i < json.length; i++) { var imageData = json[i]; imageData.src = 'api/picture?id=' + json[i].id; // Add 'src' field required by PhotoSwipe items.push(imageData); } const gallery = new PhotoSwipePictureGallery(items); gallery.open(0); // start at first slide } // Export this function so that it may be called from HTML function openImagesGallery(selectors) { fetch('api/pictures?' + selectors) // selectors is not empty .then(response => response.json()) .then(data => createImageGallery(data)); } window.openImagesGallery = openImagesGallery;