PageSourceSearch

https://www.luckyred.it/wp-content/themes/luckyredv2/js/lightbox.js?v=1790167678

js luckyred.it collected 2026-10-02 11:17:06 UTC 10,661 bytes, 263 lines download raw bytes

1/* =====================================================================
2   LIGHTBOX (.lrf) — sostituisce swipebox nelle pagine rifatte.
3   Si aggancia ai link con data-lb; quelli con lo stesso data-lb-group
4   formano una galleria navigabile.
5
6   Foto:  <a data-lb data-lb-group="galleria" href="grande.jpg">
7   Video: <a data-lb data-lb-group="video" href="https://youtu.be/ID">
8          (YouTube e Vimeo vengono riconosciuti e aperti a tutto schermo)
9   ===================================================================== */
10(function () {
11	var links = Array.prototype.slice.call(document.querySelectorAll('[data-lb]'));
12	if (!links.length) { return; }
13
14	var reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
15	var box = null;
16	var stage = null;
17	var counter = null;
18	var caption = null;
19	var prevBtn = null;
20	var nextBtn = null;
21	var fsBtn = null;
22	var closeBtn = null;
23	var items = [];
24	var index = 0;
25	var lastFocus = null;
26	var hideTimer = null;
27	var audioBtn = null;
28	var audioOn = false;
29	var closedByKey = false;
30
31	// Chrome e Firefox lasciano partire il video con l'audio, visto che
32	// l'apertura nasce da un clic. Safari no: là parte muto e l'audio si
33	// accende col bottone.
34	var isSafari = /^((?!chrome|android|crios|fxios).)*safari/i.test(navigator.userAgent);
35
36	var ICON = {
37		close: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>',
38		prev: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M15 5l-7 7 7 7" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>',
39		next: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M9 5l7 7-7 7" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>',
40		full: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>',
41		sound: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 9.5h3.5L12 6v12L7.5 14.5H4z M16 9.5a4 4 0 0 1 0 5M18.5 7a7 7 0 0 1 0 10" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>',
42		muted: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 9.5h3.5L12 6v12L7.5 14.5H4z M16 9.5l5 5M21 9.5l-5 5" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>',
43		exit: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M9 4v5H4M15 4v5h5M9 20v-5H4M15 20v-5h5" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>'
44	};
45
46
47	/* -------- sorgente: foto o video -------- */
48	function parse(link) {
49		var url = link.getAttribute('href') || '';
50		var yt = url.match(/(?:youtube\.com\/(?:watch\?(?:.*&)?v=|embed\/|shorts\/)|youtu\.be\/)([\w-]{11})/);
51		var vimeo = url.match(/vimeo\.com\/(?:video\/)?(\d+)/);
52
53		return {
54			url: url,
55			kind: (yt || vimeo) ? 'video' : 'image',
56			embed: yt
57				? 'https://www.youtube-nocookie.com/embed/' + yt[1] + '?autoplay=1&mute=' + (isSafari ? 1 : 0) + '&enablejsapi=1&rel=0&modestbranding=1&playsinline=1'
58				: (vimeo ? 'https://player.vimeo.com/video/' + vimeo[1] + '?autoplay=1&muted=' + (isSafari ? 1 : 0) : ''),
59			title: link.getAttribute('data-lb-title')
60				|| (link.querySelector('.lrf-video__title, .lrf-videos__title') || {}).textContent
61				|| ''
62		};
63	}
64
65
66	/* -------- costruzione -------- */
67	function build() {
68		box = document.createElement('div');
69		box.className = 'lrf-lb';
70		box.setAttribute('role', 'dialog');
71		box.setAttribute('aria-modal', 'true');
72		box.innerHTML =
73			'<div class="lrf-lb__bg" data-lb-close></div>' +
74			'<div class="lrf-lb__hud">' +
75				'<p class="lrf-lb__caption"></p>' +
76				'<div class="lrf-lb__tools">' +
77					'<span class="lrf-lb__counter"></span>' +
78					'<button type="button" class="lrf-lb__btn lrf-lb__audio" data-lb-audio aria-label="Attiva audio">' + ICON.muted + '</button>' +
79					'<button type="button" class="lrf-lb__btn" data-lb-full aria-label="Schermo intero">' + ICON.full + '</button>' +
80					'<button type="button" class="lrf-lb__btn" data-lb-close aria-label="Chiudi">' + ICON.close + '</button>' +
81				'</div>' +
82			'</div>' +
83			'<button type="button" class="lrf-lb__nav is-prev" data-lb-prev aria-label="Precedente">' + ICON.prev + '</button>' +
84			'<button type="button" class="lrf-lb__nav is-next" data-lb-next aria-label="Successivo">' + ICON.next + '</button>' +
85			'<div class="lrf-lb__stage"></div>';
86
87		document.body.appendChild(box);
88
89		stage = box.querySelector('.lrf-lb__stage');
90		counter = box.querySelector('.lrf-lb__counter');
91		caption = box.querySelector('.lrf-lb__caption');
92		prevBtn = box.querySelector('[data-lb-prev]');
93		nextBtn = box.querySelector('[data-lb-next]');
94		fsBtn = box.querySelector('[data-lb-full]');
95		audioBtn = box.querySelector('[data-lb-audio]');
96		closeBtn = box.querySelector('[data-lb-close].lrf-lb__btn');
97
98		box.querySelectorAll('[data-lb-close]').forEach(function (el) {
99			el.addEventListener('click', close);
100		});
101		prevBtn.addEventListener('click', function () { go(index - 1); });
102		nextBtn.addEventListener('click', function () { go(index + 1); });
103		fsBtn.addEventListener('click', toggleFullscreen);
104		audioBtn.addEventListener('click', function () { setAudio(!audioOn); });
105
106		// muovendo il dito o il mouse i comandi riappaiono
107		box.addEventListener('pointermove', wake);
108		box.addEventListener('pointerdown', wake);
109
110		// trascinamento orizzontale per cambiare foto
111		var startX = null;
112		box.addEventListener('pointerdown', function (e) {
113			if (e.pointerType === 'mouse') { return; }
114			startX = e.clientX;
115		});
116		box.addEventListener('pointerup', function (e) {
117			if (startX === null) { return; }
118			var dx = e.clientX - startX;
119			startX = null;
120			if (Math.abs(dx) > 60) { go(index + (dx < 0 ? 1 : -1)); }
121		});
122
123		document.addEventListener('fullscreenchange', function () {
124			var on = !!document.fullscreenElement;
125			box.classList.toggle('is-fullscreen', on);
126			fsBtn.innerHTML = on ? ICON.exit : ICON.full;
127			fsBtn.setAttribute('aria-label', on ? 'Esci da schermo intero' : 'Schermo intero');
128		});
129	}
130
131
132	/* -------- audio del video (comandi YouTube via postMessage) -------- */
133	function command(func) {
134		var frame = stage.querySelector('iframe');
135		if (!frame || !frame.contentWindow) { return; }
136		frame.contentWindow.postMessage(JSON.stringify({ event: 'command', func: func, args: [] }), '*');
137	}
138
139	function setAudio(on) {
140		audioOn = on;
141		command(on ? 'unMute' : 'mute');
142		audioBtn.innerHTML = on ? ICON.sound : ICON.muted;
143		audioBtn.setAttribute('aria-label', on ? 'Disattiva audio' : 'Attiva audio');
144	}
145
146
147	/* -------- comandi che si nascondono da soli -------- */
148	function wake() {
149		box.classList.remove('is-idle');
150		clearTimeout(hideTimer);
151		hideTimer = setTimeout(function () {
152			if (items[index] && items[index].kind === 'video') { box.classList.add('is-idle'); }
153		}, 2600);
154	}
155
156
157	/* -------- apertura, navigazione, chiusura -------- */
158	function render() {
159		var item = items[index];
160		stage.innerHTML = '';
161
162		if (item.kind === 'video') {
163			var frame = document.createElement('div');
164			frame.className = 'lrf-lb__video';
165			frame.innerHTML = '<iframe src="' + item.embed + '" title="' + (item.title || 'Video') + '" allow="autoplay; encrypted-media; picture-in-picture; fullscreen" allowfullscreen frameborder="0"></iframe>';
166			stage.appendChild(frame);
167
168			// su Safari parte muto (lì l'audio bloccherebbe la partenza),
169			// altrove parte con l'audio già acceso
170			audioOn = !isSafari;
171			audioBtn.innerHTML = audioOn ? ICON.sound : ICON.muted;
172			audioBtn.setAttribute('aria-label', audioOn ? 'Disattiva audio' : 'Attiva audio');
173		} else {
174			var img = document.createElement('img');
175			img.className = 'lrf-lb__img';
176			img.alt = item.title || '';
177			img.src = item.url;
178			stage.appendChild(img);
179		}
180
181		box.classList.toggle('is-video', item.kind === 'video');
182		caption.textContent = item.title || '';
183		counter.textContent = items.length > 1 ? (index + 1) + ' / ' + items.length : '';
184		prevBtn.hidden = nextBtn.hidden = items.length < 2;
185
186		// precarico la foto successiva
187		var next = items[(index + 1) % items.length];
188		if (next && next.kind === 'image') { new Image().src = next.url; }
189
190		wake();
191	}
192
193	function go(i) {
194		if (items.length < 2) { return; }
195		index = (i + items.length) % items.length;
196		render();
197	}
198
199	function open(link) {
200		if (!box) { build(); }
201
202		var group = link.getAttribute('data-lb-group');
203		var groupLinks = group
204			? links.filter(function (l) { return l.getAttribute('data-lb-group') === group; })
205			: [link];
206
207		items = groupLinks.map(parse);
208		index = Math.max(0, groupLinks.indexOf(link));
209		lastFocus = document.activeElement;
210
211		var gap = window.innerWidth - document.documentElement.clientWidth;
212		document.body.style.paddingRight = gap > 0 ? gap + 'px' : '';
213		document.body.classList.add('lrf-lb-open');
214		box.classList.add('is-open');
215		if (reduceMotion) { box.classList.add('is-instant'); }
216		render();
217		closeBtn.focus({ preventScroll: true });
218
219		document.addEventListener('keydown', onKey);
220	}
221
222	function close() {
223		if (!box || !box.classList.contains('is-open')) { return; }
224		if (document.fullscreenElement) { document.exitFullscreen(); }
225
226		box.classList.remove('is-open');
227		document.body.classList.remove('lrf-lb-open');
228		document.body.style.paddingRight = '';
229		document.removeEventListener('keydown', onKey);
230		clearTimeout(hideTimer);
231
232		// fermo subito il video
233		setTimeout(function () { stage.innerHTML = ''; }, reduceMotion ? 0 : 260);
234
235		// col mouse non rimetto il fuoco sul link (lascerebbe il contorno
236		// evidenziato); da tastiera invece serve per non perdere il segno.
237		if (closedByKey && lastFocus && lastFocus.focus) { lastFocus.focus({ preventScroll: true }); }
238		closedByKey = false;
239	}
240
241	function toggleFullscreen() {
242		if (document.fullscreenElement) {
243			document.exitFullscreen();
244		} else if (box.requestFullscreen) {
245			box.requestFullscreen().catch(function () { /* niente: resta a schermo pieno nella pagina */ });
246		}
247	}
248
249	function onKey(e) {
250		if (e.key === 'Escape') { closedByKey = true; close(); }
251		if (e.key === 'ArrowRight') { go(index + 1); }
252		if (e.key === 'ArrowLeft') { go(index - 1); }
253	}
254
255
256	links.forEach(function (link) {
257		link.addEventListener('click', function (e) {
258			if (e.metaKey || e.ctrlKey || e.shiftKey || e.button > 0) { return; }
259			e.preventDefault();
260			open(link);
261		});
262	});
263})();

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.