PageSourceSearch

https://www.barbiano.eu/system/statV.1789655742/Javascript/bootstrap-lightbox.js

js barbiano.eu collected 2026-10-03 02:45:25 UTC 14,706 bytes, 369 lines download raw bytes

1
2/*!
3 * Lightbox for Bootstrap 5 v1.8.3 (https://trvswgnr.github.io/bs5-lightbox/)
4 * Copyright 2024 Travis Aaron Wagner (https://github.com/trvswgnr/)
5 * Licensed under MIT (https://github.com/trvswgnr/bs5-lightbox/blob/main/LICENSE)
6 */
7(function webpackUniversalModuleDefinition(root, factory) {
8	if (typeof exports === 'object' && typeof module === 'object')
9		module.exports = factory(require("bootstrap"));
10	else if (typeof define === 'function' && define.amd)
11		define("Lightbox", ["bootstrap"], factory);
12	else if (typeof exports === 'object')
13		exports["Lightbox"] = factory(require("bootstrap"));
14	else
15		root["Lightbox"] = factory(root["bootstrap"]);
16})(self, function (__WEBPACK_EXTERNAL_MODULE__814__) {
17	return /******/ (function () { // webpackBootstrap
18/******/ 	"use strict";
19/******/ 	var __webpack_modules__ = ({
20
21/***/ 814:
22/***/ (function (module) {
23
24					module.exports = __WEBPACK_EXTERNAL_MODULE__814__;
25
26					/***/
27})
28
29			/******/
30});
31/************************************************************************/
32/******/ 	// The module cache
33/******/ 	var __webpack_module_cache__ = {};
34/******/
35/******/ 	// The require function
36/******/ 	function __webpack_require__(moduleId) {
37/******/ 		// Check if module is in cache
38/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
39/******/ 		if (cachedModule !== undefined) {
40/******/ 			return cachedModule.exports;
41				/******/
42}
43/******/ 		// Create a new module (and put it into the cache)
44/******/ 		var module = __webpack_module_cache__[moduleId] = {
45/******/ 			// no module.id needed
46/******/ 			// no module.loaded needed
47/******/ 			exports: {}
48				/******/
49};
50/******/
51/******/ 		// Execute the module function
52/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
53/******/
54/******/ 		// Return the exports of the module
55/******/ 		return module.exports;
56			/******/
57}
58/******/
59/************************************************************************/
60/******/ 	/* webpack/runtime/compat get default export */
61/******/ 	!function () {
62/******/ 		// getDefaultExport function for compatibility with non-harmony modules
63/******/ 		__webpack_require__.n = function (module) {
64/******/ 			var getter = module && module.__esModule ?
65/******/ 				function () { return module['default']; } :
66/******/ 				function () { return module; };
67/******/ 			__webpack_require__.d(getter, { a: getter });
68/******/ 			return getter;
69				/******/
70};
71			/******/
72}();
73/******/
74/******/ 	/* webpack/runtime/define property getters */
75/******/ 	!function () {
76/******/ 		// define getter functions for harmony exports
77/******/ 		__webpack_require__.d = function (exports, definition) {
78/******/ 			for (var key in definition) {
79/******/ 				if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
80/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
81						/******/
82}
83					/******/
84}
85				/******/
86};
87			/******/
88}();
89/******/
90/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
91/******/ 	!function () {
92/******/ 		__webpack_require__.o = function (obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
93			/******/
94}();
95		/******/
96		/************************************************************************/
97		var __webpack_exports__ = {};
98/* harmony import */ var bootstrap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(814);
99/* harmony import */ var bootstrap__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(bootstrap__WEBPACK_IMPORTED_MODULE_0__);
100		/**
101		 * Lightbox for Bootstrap 5
102		 *
103		 * @file Creates a modal with a lightbox carousel.
104		 * @module bs5-lightbox
105		 */
106
107
108		const bootstrap = {
109			Modal: bootstrap__WEBPACK_IMPORTED_MODULE_0__.Modal,
110			Carousel: bootstrap__WEBPACK_IMPORTED_MODULE_0__.Carousel
111		};
112		class Lightbox {
113			constructor(el, options = {}) {
114				this.hash = this.randomHash();
115				this.settings = Object.assign(Object.assign(Object.assign({}, bootstrap.Modal.Default), bootstrap.Carousel.Default), {
116					interval: false,
117					target: '[data-toggle="lightbox"]',
118					gallery: '',
119					size: 'xl',
120					constrain: true,
121					type: 'image'
122				});
123				this.settings = Object.assign(Object.assign({}, this.settings), options);
124				this.modalOptions = (() => this.setOptionsFromSettings(bootstrap.Modal.Default))();
125				this.carouselOptions = (() => this.setOptionsFromSettings(bootstrap.Carousel.Default))();
126				if (this.settings.gallery.length == 0) {
127					this.settings.gallery = el.dataset['lbgroup'];
128				}
129				if (typeof el === 'string') {
130					this.settings.target = el;
131					el = document.querySelector(this.settings.target);
132				}
133				this.el = el;
134				this.type = el.dataset.type || this.settings.type;
135
136				this.src = this.getSrc(el);
137				this.sources = this.getGalleryItems();
138				this.createCarousel();
139				this.createModal();
140			}
141			show() {
142				document.body.appendChild(this.modalElement);
143				this.modal.show();
144			}
145			hide() {
146				this.modal.hide();
147			}
148			setOptionsFromSettings(obj) {
149				return Object.keys(obj).reduce((p, c) => Object.assign(p, { [c]: this.settings[c] }), {});
150			}
151			getSrc(el) {
152				let src = el.dataset.src || el.dataset.remote || el.href || 'http://imgs.gem2go.dev/1600x900';
153				if (el.dataset.type === 'html') {
154					return src;
155				}
156				if (!/\:\/\//.test(src)) {
157					src = window.location.origin + src;
158				}
159				const url = new URL(src);
160				if (el.dataset.footer || el.dataset.description) {
161					let description = decodeURIComponent(el.dataset.description);
162					if (el.dataset.copyright)
163						description += ' ' + decodeURIComponent(el.dataset.copyright);
164
165					url.searchParams.set('caption', el.dataset.footer || description);
166				}
167				return url.toString();
168			}
169			getGalleryItems() {
170				let galleryTarget;
171				if (this.settings.gallery) {
172					if (Array.isArray(this.settings.gallery)) {
173						return this.settings.gallery;
174					}
175					galleryTarget = this.settings.gallery;
176				} else if (this.el.dataset.gallery) {
177					galleryTarget = this.el.dataset.gallery;
178				}
179				const gallery = galleryTarget
180					? [...new Set(Array.from(document.querySelectorAll(`[data-lbgroup="${galleryTarget}"]`), (v) => `${v.dataset.type ? v.dataset.type : this.type}${this.getSrc(v)}`))]
181					: [`${this.type ? this.type : ''}${this.src}`];
182				return gallery;
183			}
184			getYoutubeId(src) {
185				if (!src) return false;
186				const matches = src.match(/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/);
187				return matches && matches[2].length === 11 ? matches[2] : false;
188			}
189			getYoutubeLink(src) {
190				const youtubeId = this.getYoutubeId(src);
191				if (!youtubeId) {
192					return false;
193				}
194
195				const arr = src.split('?');
196				let params = arr.length > 1 ? '?' + arr[1] : '';
197
198				return `https://www.youtube.com/embed/${youtubeId}${params}`;
199			}
200			getInstagramEmbed(src) {
201				if (/instagram/.test(src)) {
202					src += /\/embed$/.test(src) ? '' : '/embed';
203					return `<iframe src="${src}" class="start-50 translate-middle-x" style="max-width: 500px" frameborder="0" scrolling="no" allowtransparency="true"></iframe>`;
204				}
205			}
206			isEmbed(src) {
207				const regex = new RegExp('(' + Lightbox.allowedEmbedTypes.join('|') + ')');
208				const isEmbed = regex.test(src);
209				const isImg = /\.(png|jpe?g|gif|svg|webp)/i.test(src) || this.el.dataset.type === 'image';
210
211				return isEmbed || !isImg;
212			}
213			createCarousel() {
214				const template = document.createElement('template');
215				const types = Lightbox.allowedMediaTypes.join('|');
216				const slidesHtml = this.sources
217					.map((src, i) => {
218						src = src.replace(/\/$/, '');
219						const regex = new RegExp(`^(${types})`, 'i');
220						const isHtml = /^html/.test(src);
221						const isForcedImage = /^image/.test(src);
222
223						if (regex.test(src)) {
224							src = src.replace(regex, '');
225						}
226						const imgClasses = this.settings.constrain ? 'mw-100 mh-100 h-auto w-auto m-auto top-0 end-0 bottom-0 start-0' : 'h-100 w-100';
227						const params = new URLSearchParams(src.split('?')[1]);
228						let caption = '';
229						let url = src;
230						if (params.get('caption')) {
231							try {
232								url = new URL(src);
233								url.searchParams.delete('caption');
234								url = url.toString();
235							} catch (e) {
236								url = src;
237							}
238							caption = `<div style="background-color:#fff;" class="lightbox-caption m-0 p-2 text-center small"><em>${params.get('caption')}</em></div>`;
239						}
240						let inner = `<img src="${url}" class="d-block ${imgClasses} img-fluid" style="z-index: 1; object-fit: contain;" />`;
241						let attributes = '';
242						const instagramEmbed = this.getInstagramEmbed(src);
243						const youtubeLink = this.getYoutubeLink(src);
244						if (this.isEmbed(src) && !isForcedImage) {
245							if (youtubeLink) {
246								src = youtubeLink;
247								attributes = 'title="YouTube video player" frameborder="0" allow="accelerometer autoplay clipboard-write encrypted-media gyroscope picture-in-picture"';
248							}
249							inner = instagramEmbed || `<iframe src="${src}" ${attributes} allowfullscreen></iframe>`;
250						}
251						if (isHtml) {
252							inner = src;
253						}
254						const spinner = `<div class="position-absolute top-50 start-50 translate-middle text-white"><div class="spinner-border" style="width: 3rem height: 3rem" role="status"></div></div>`;
255						return `
256				<div class="carousel-item ${!i ? 'active' : ''}" style="min-height: 100px">
257					${spinner}
258					<div class="ratio ratio-16x9 " style="background-color: #fff;">${inner}</div>
259					${caption}
260				</div>`;
261					})
262					.join('');
263				const controlsHtml =
264					this.sources.length < 2
265						? ''
266						: `
267			<button id="#lightboxCarousel-${this.hash}-prev" class="carousel-control carousel-control-prev h-75 m-auto" type="button" data-bs-target="#lightboxCarousel-${this.hash}" data-bs-slide="prev">
268				<span class="carousel-control-prev-icon p-4 rounded-4 bg-black" aria-hidden="true"></span>
269				<span class="visually-hidden">Previous</span>
270			</button>
271			<button id="#lightboxCarousel-${this.hash}-next" class="carousel-control carousel-control-next h-75 m-auto" type="button" data-bs-target="#lightboxCarousel-${this.hash}" data-bs-slide="next">
272				<span class="carousel-control-next-icon p-4 rounded-4 bg-black" aria-hidden="true"></span>
273				<span class="visually-hidden">Next</span>
274			</button>`;
275				let classes = 'lightbox-carousel carousel slide';
276				if (this.settings.size === 'fullscreen') {
277					classes += ' position-absolute w-100 translate-middle top-50 start-50';
278				}
279				const html = `
280			<div id="lightboxCarousel-${this.hash}" class="${classes}" data-bs-ride="carousel" data-bs-interval="${this.carouselOptions.interval}">
281				<div class="carousel-inner">
282					${slidesHtml}
283				</div>
284				${controlsHtml}
285			</div>`;
286				template.innerHTML = html.trim();
287				this.carouselElement = template.content.firstChild;
288				const carouselOptions = Object.assign(Object.assign({}, this.carouselOptions), { keyboard: false });
289				this.carousel = new bootstrap.Carousel(this.carouselElement, carouselOptions);
290				const elSrc = this.type && this.type !== 'image' ? this.type + this.src : this.src;
291				this.carousel.to(this.findGalleryItemIndex(this.sources, elSrc));
292				if (this.carouselOptions.keyboard === true) {
293					document.addEventListener('keydown', (e) => {
294						if (e.code === 'ArrowLeft') {
295							const prev = document.getElementById(`#lightboxCarousel-${this.hash}-prev`);
296							if (prev) {
297								prev.click();
298							}
299							return false;
300						}
301						if (e.code === 'ArrowRight') {
302							const next = document.getElementById(`#lightboxCarousel-${this.hash}-next`);
303							if (next) {
304								next.click();
305							}
306							return false;
307						}
308					});
309				}
310				return this.carousel;
311			}
312			findGalleryItemIndex(haystack, needle) {
313				let index = 0;
314				for (const item of haystack) {
315					if (item.includes(needle)) {
316						return index;
317					}
318					index++;
319				}
320				return 0;
321			}
322			createModal() {
323
324				const template = document.createElement('template');
325				const btnInner =
326					'<svg xmlns="http://www.w3.org/2000/svg" style="position: relative; top: -5px;" viewBox="0 0 16 16" fill="#000"><path d="M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z"/></svg>';
327				const html = `
328			<div class="modal lightbox fade" id="lightboxModal-${this.hash}" tabindex="-1" aria-hidden="true">
329				<div class="modal-dialog modal-dialog-centered modal-${this.settings.size}">
330					<div class="modal-content border-0 bg-white">
331						<div class="modal-body p-2">
332							<button type="button" class="btn-close position-absolute top-0 end-0 p-3" data-bs-dismiss="modal" aria-label="Close" style="z-index: 2; background: none;">${btnInner}</button>
333						</div>
334					</div>
335				</div>
336			</div>`;
337				template.innerHTML = html.trim();
338				this.modalElement = template.content.firstChild;
339				this.modalElement.querySelector('.modal-body').appendChild(this.carouselElement);
340				this.modalElement.addEventListener('hidden.bs.modal', () => this.modalElement.remove());
341				this.modalElement.querySelector('[data-bs-dismiss]').addEventListener('click', () => this.modal.hide());
342				this.modal = new bootstrap.Modal(this.modalElement, this.modalOptions);
343				return this.modal;
344			}
345			randomHash(length = 8) {
346				return Array.from({ length }, () => Math.floor(Math.random() * 36).toString(36)).join('');
347			}
348		}
349		Lightbox.allowedEmbedTypes = ['embed', 'youtube', 'vimeo', 'instagram', 'url'];
350		Lightbox.allowedMediaTypes = [...Lightbox.allowedEmbedTypes, 'image', 'html'];
351		Lightbox.defaultSelector = '[data-toggle="lightbox"]';
352		Lightbox.initialize = function (e) {
353			e.preventDefault();
354			const lightbox = new Lightbox(this);
355			lightbox.show();
356		};
357		document.querySelectorAll(Lightbox.defaultSelector).forEach((el) => el.addEventListener('click', Lightbox.initialize));
358		if (typeof window !== 'undefined' && window.bootstrap) {
359			window.bootstrap.Lightbox = Lightbox;
360		}
361/* harmony default export */ __webpack_exports__["default"] = (Lightbox);
362
363		__webpack_exports__ = __webpack_exports__["default"];
364/******/ 	return __webpack_exports__;
365		/******/
366})()
367		;
368});
369//# sourceMappingURL=index.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.