UNPKG

bootstrap-lightbox-gallery

Version:

A nice lightbox gallery component for Bootstrap 5

129 lines (120 loc) 5.88 kB
/** * Author and copyright: Stefan Haack (https://shaack.com) * Repository: https://github.com/shaack/bootstrap-lightbox-gallery * License: MIT, see file 'LICENSE' */ import {DomUtils} from "cm-web-modules/src/utils/DomUtils.js" import "bootstrap-show-modal/src/ShowModal.js" export class LightboxGallery { constructor(elements, props = {}) { this.props = { id: "lightboxGallery", // change this if you have multiple galleries on one page. The id must be unique per gallery. title: "Lightbox Gallery", // set the name, it will be displayed theme: "dark", // set to "light" if you want to display the images on a light background useArrowKeys: true // set to false if you don't want to use the arrow keys to navigate the images } Object.assign(this.props, props) this.props.isDark = props.theme === "dark" this.state = { title: props.title, carousel: undefined, itemCount: 0, currentIndex: undefined } this.init(elements) } init(elements) { let carouselItems = "" elements.forEach((element) => { const img = element.querySelector("img") const itemData = { url: element.href, alt: img.alt, title: img.title, caption: element.querySelector("figcaption").innerHTML.trim() } element.addEventListener("click", (event) => { event.preventDefault() const targetLink = event.target.closest("a") this.open(targetLink) }) let caption = "" if (itemData.caption) { caption = `<div class="rounded carousel-caption p-2 ${this.props.isDark ? "bg-dark" : "bg-light"} bg-opacity-75"> ${itemData.caption} </div>` } const carouselItem = ` <div class="carousel-item h-100" data-bs-index="${this.state.itemCount}"> <div class="d-flex align-items-center h-100 w-100 ${this.props.isDark ? "bg-dark" : "bg-white"}"> <img src="${itemData.url}" class="d-block mx-auto img-fluid" style="max-height: 100%" title="${itemData.title}" alt="${itemData.alt}"/> ${caption} </div> </div>` carouselItems += carouselItem this.state.itemCount++ }) this.state.carouselElement = DomUtils.createElement(` <div id="${this.props.id}" ${this.props.isDark ? 'data-bs-theme="light"' : 'data-bs-theme="dark"' } class="carousel slide h-100 carousel-fade"> <div class="carousel-inner h-100"> ${carouselItems} </div> <button class="carousel-control-prev" type="button" data-bs-target="#${this.props.id}" data-bs-slide="prev"> <span class="carousel-control-prev-icon" aria-hidden="true"></span> <span class="visually-hidden">Vorheriges Bild</span> </button> <button class="carousel-control-next" type="button" data-bs-target="#${this.props.id}" data-bs-slide="next"> <span class="carousel-control-next-icon" aria-hidden="true"></span> <span class="visually-hidden">Nächstes Bild</span> </button> </div>`) } open(targetLink) { const carouselItems = this.state.carouselElement.querySelectorAll(".carousel-item") carouselItems.forEach((carouselItem) => { carouselItem.classList.remove("active") }) const image = this.state.carouselElement.querySelector(`[src="${targetLink.href}"]`) const activeItem = image.closest(".carousel-item") activeItem.classList.add("active") this.state.currentIndex = parseInt(activeItem.getAttribute("data-bs-index")) if (targetLink) { this.modal = bootstrap.showModal({ theme: this.props.isDark ? "dark" : undefined, title: "<span class='text-body-secondary'>" + this.state.title + "</span> <small class='text-body-tertiary ms-3 pb-1 carousel-index'></small>", headerClass: "border-0", bodyClass: "overflow-hidden h-100", // fix for Safari body: this.state.carouselElement.outerHTML, modalDialogClass: "modal-fullscreen modal-bootstrap-lightbox-gallery" }) const carouselElement = this.modal.element.querySelector(".carousel") carouselElement.addEventListener('slide.bs.carousel', event => { this.state.currentIndex = event.to this.updateIndex() }) // Add keyboard navigation if (this.props.useArrowKeys) { this.keyboardHandler = (event) => { if (event.key === 'ArrowLeft') { event.preventDefault() const prevButton = this.modal.element.querySelector('.carousel-control-prev') prevButton.click() } else if (event.key === 'ArrowRight') { event.preventDefault() const nextButton = this.modal.element.querySelector('.carousel-control-next') nextButton.click() } } document.addEventListener('keydown', this.keyboardHandler) // Remove keyboard listener when modal is hidden this.modal.element.addEventListener('hidden.bs.modal', () => { document.removeEventListener('keydown', this.keyboardHandler) }) } } this.updateIndex() } updateIndex() { this.modal.titleElement.querySelector(".carousel-index").innerText = `${this.state.currentIndex + 1} / ${this.state.itemCount}` } }