PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more / trunk
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more vtrunk
4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 trunk 1.0.0 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 2.0.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.2.0 3.2.1 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.7.0 3.7.1 3.7.2 3.7.3 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.14 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.10 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.3.0 4.3.1 4.4.0 4.4.1 4.4.10 4.4.11 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5.0 4.5.1
embedpress / assets / js / pdf-gallery.js
embedpress / assets / js Last commit date
chunks 1 week ago vendor 8 months ago admin.build.js 1 week ago admin.js 3 months ago analytics-tracker.js 4 weeks ago analytics.build.js 1 week ago blocks.build.js 1 week ago carousel.js 1 year ago custom-player.build.js 1 week ago documents-viewer-script.js 3 months ago ep-pdf-lightbox.js 3 months ago ep-view-count.js 1 week ago ep-yt-queue.js 4 weeks ago feature-notices.js 7 months ago front.js 4 weeks ago frontend.build.js 3 months ago gallery-justify.js 1 week ago gutneberg-script.js 1 month ago index.html 7 years ago initCarousel.js 2 years ago initplyr.js 1 month ago instafeed.js 4 weeks ago instagram-shortcode-generator.js 1 month ago lazy-load.js 6 months ago license.js 3 months ago meetup-timezone.js 3 months ago onboarding.build.js 1 week ago pdf-gallery-elementor-editor.js 3 months ago pdf-gallery.js 3 months ago preview.js 8 months ago settings.js 3 months ago sponsored.js 9 months ago
pdf-gallery.js
747 lines
1 /**
2 * EmbedPress PDF Gallery - Frontend Script
3 *
4 * Handles:
5 * - PDF.js thumbnail generation (first page render)
6 * - Carousel layout initialization
7 * - Popup/lightbox with prev/next navigation
8 */
9 (function () {
10 'use strict';
11
12 // =========================================
13 // Module 1: PDF Thumbnail Generator
14 // =========================================
15 var ThumbnailGenerator = {
16 pdfjsLoaded: false,
17 pdfjsLoading: false,
18 loadCallbacks: [],
19
20 /**
21 * Load PDF.js library dynamically
22 */
23 loadPdfJs: function (callback) {
24 if (this.pdfjsLoaded && window.pdfjsLib) {
25 callback();
26 return;
27 }
28
29 this.loadCallbacks.push(callback);
30
31 if (this.pdfjsLoading) return;
32 this.pdfjsLoading = true;
33
34 var self = this;
35 var scriptUrl = (typeof embedpressObj !== 'undefined' && embedpressObj.pluginUrl)
36 ? embedpressObj.pluginUrl + 'assets/pdf/build/script.js'
37 : null;
38
39 if (!scriptUrl) {
40 // Try to find from existing script tags
41 var scripts = document.querySelectorAll('script[src*="embedpress"]');
42 for (var i = 0; i < scripts.length; i++) {
43 var match = scripts[i].src.match(/(.*embedpress[^/]*\/(?:assets|static)\/)/);
44 if (match) {
45 scriptUrl = match[1] + 'pdf/build/script.js';
46 break;
47 }
48 }
49 }
50
51 if (!scriptUrl) {
52 self.pdfjsLoading = false;
53 return;
54 }
55
56 var script = document.createElement('script');
57 script.src = scriptUrl;
58 script.type = 'module';
59 script.onload = function () {
60 // Module scripts set pdfjsLib on globalThis; wait a tick for execution
61 setTimeout(function () {
62 if (window.pdfjsLib || globalThis.pdfjsLib) {
63 if (!window.pdfjsLib) window.pdfjsLib = globalThis.pdfjsLib;
64 var workerUrl = scriptUrl.replace('script.js', 'pdf.worker.js');
65 window.pdfjsLib.GlobalWorkerOptions.workerSrc = workerUrl;
66 self.pdfjsLoaded = true;
67 }
68 self.pdfjsLoading = false;
69 self.loadCallbacks.forEach(function (cb) { cb(); });
70 self.loadCallbacks = [];
71 }, 50);
72 };
73 script.onerror = function () {
74 self.pdfjsLoading = false;
75 self.loadCallbacks = [];
76 };
77 document.head.appendChild(script);
78 },
79
80 /**
81 * Render first page of a PDF to a canvas
82 */
83 renderThumbnail: function (canvas, pdfUrl) {
84 if (!window.pdfjsLib) return;
85
86 canvas.setAttribute('data-loading', 'true');
87
88 var loadingTask = window.pdfjsLib.getDocument(pdfUrl);
89 loadingTask.promise.then(function (pdf) {
90 pdf.getPage(1).then(function (page) {
91 var containerWidth = canvas.parentElement ? canvas.parentElement.offsetWidth : 400;
92 var dpr = Math.min(window.devicePixelRatio || 1, 2);
93 var targetWidth = Math.max(containerWidth * dpr, 400);
94 targetWidth = Math.min(targetWidth, 1200);
95 var scale = targetWidth / page.getViewport({ scale: 1 }).width;
96 scale = Math.max(scale, 0.8);
97 scale = Math.min(scale, 3);
98 var viewport = page.getViewport({ scale: scale });
99
100 canvas.width = viewport.width;
101 canvas.height = viewport.height;
102
103 var ctx = canvas.getContext('2d');
104 page.render({
105 canvasContext: ctx,
106 viewport: viewport
107 }).promise.then(function () {
108 canvas.removeAttribute('data-loading');
109 });
110 });
111 }).catch(function () {
112 // Show fallback placeholder
113 canvas.removeAttribute('data-loading');
114 canvas.style.display = 'none';
115 var wrap = canvas.parentElement;
116 if (wrap && !wrap.querySelector('.ep-pdf-gallery__placeholder')) {
117 var placeholder = document.createElement('div');
118 placeholder.className = 'ep-pdf-gallery__placeholder';
119 placeholder.innerHTML = '<svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6zm-1 2l5 5h-5V4zM6 20V4h5v7h7v9H6z"/></svg>';
120 wrap.appendChild(placeholder);
121 }
122 });
123 },
124
125 /**
126 * Initialize all thumbnails with IntersectionObserver
127 */
128 initAll: function () {
129 var canvases = document.querySelectorAll('.ep-pdf-gallery__canvas[data-pdf-src]');
130 if (!canvases.length) return;
131
132 var self = this;
133 this.loadPdfJs(function () {
134 if (!window.pdfjsLib) return;
135
136 if ('IntersectionObserver' in window) {
137 var observer = new IntersectionObserver(function (entries) {
138 entries.forEach(function (entry) {
139 if (entry.isIntersecting) {
140 var c = entry.target;
141 observer.unobserve(c);
142 self.renderThumbnail(c, c.dataset.pdfSrc);
143 }
144 });
145 }, { rootMargin: '200px' });
146
147 canvases.forEach(function (c) { observer.observe(c); });
148 } else {
149 canvases.forEach(function (c) {
150 self.renderThumbnail(c, c.dataset.pdfSrc);
151 });
152 }
153 });
154 }
155 };
156
157 // =========================================
158 // Module 2: Carousel
159 // =========================================
160 var Carousel = {
161 init: function (gallery) {
162 var carouselEl = gallery.querySelector('.ep-pdf-gallery__carousel');
163 if (!carouselEl) return;
164
165 var track = carouselEl.querySelector('.ep-pdf-gallery__carousel-track');
166 var items = carouselEl.querySelectorAll('.ep-pdf-gallery__item');
167 var prevBtn = carouselEl.querySelector('.ep-pdf-gallery__carousel-prev');
168 var nextBtn = carouselEl.querySelector('.ep-pdf-gallery__carousel-next');
169 var dotsContainer = carouselEl.querySelector('.ep-pdf-gallery__carousel-dots');
170
171 if (!track || !items.length) return;
172
173 var options;
174 try {
175 options = JSON.parse(gallery.dataset.carouselOptions || '{}');
176 } catch (e) {
177 options = {};
178 }
179
180 var slidesPerView = options.slidesPerView || 3;
181 var gap = parseInt(gallery.dataset.gap) || 20;
182 var loop = options.loop !== false;
183 var autoplay = options.autoplay || false;
184 var autoplaySpeed = options.autoplaySpeed || 3000;
185 var showDots = options.dots || false;
186 var currentIndex = 0;
187 var totalSlides = items.length;
188 var autoplayTimer = null;
189
190 // Responsive slides per view
191 function getSlidesPerView() {
192 var w = window.innerWidth;
193 if (w <= 767) return 1;
194 if (w <= 1024) return Math.min(slidesPerView, 2);
195 return slidesPerView;
196 }
197
198 function updateLayout() {
199 var spv = getSlidesPerView();
200 var containerWidth = carouselEl.offsetWidth;
201 var slideWidth = (containerWidth - gap * (spv - 1)) / spv;
202
203 items.forEach(function (item) {
204 item.style.width = slideWidth + 'px';
205 item.style.marginRight = gap + 'px';
206 });
207
208 // Last item no margin
209 if (items.length) {
210 items[items.length - 1].style.marginRight = '0';
211 }
212
213 goTo(currentIndex, false);
214 }
215
216 function goTo(index, animate) {
217 var spv = getSlidesPerView();
218 var maxIndex = Math.max(0, totalSlides - spv);
219
220 if (loop) {
221 if (index > maxIndex) index = 0;
222 if (index < 0) index = maxIndex;
223 } else {
224 index = Math.max(0, Math.min(index, maxIndex));
225 }
226
227 currentIndex = index;
228
229 var containerWidth = carouselEl.offsetWidth;
230 var slideWidth = (containerWidth - gap * (spv - 1)) / spv;
231 var offset = index * (slideWidth + gap);
232
233 track.style.transition = animate !== false ? 'transform 0.4s ease' : 'none';
234 track.style.transform = 'translateX(-' + offset + 'px)';
235
236 updateDots();
237 updateArrows();
238 }
239
240 function updateArrows() {
241 if (!prevBtn || !nextBtn) return;
242 if (loop) return;
243 var spv = getSlidesPerView();
244 var maxIndex = Math.max(0, totalSlides - spv);
245 prevBtn.classList.toggle('ep-hidden', currentIndex <= 0);
246 nextBtn.classList.toggle('ep-hidden', currentIndex >= maxIndex);
247 }
248
249 function updateDots() {
250 if (!dotsContainer || !showDots) return;
251 var spv = getSlidesPerView();
252 var totalDots = Math.max(1, totalSlides - spv + 1);
253
254 dotsContainer.innerHTML = '';
255 for (var i = 0; i < totalDots; i++) {
256 var dot = document.createElement('button');
257 dot.className = 'ep-pdf-gallery__carousel-dot' + (i === currentIndex ? ' active' : '');
258 dot.setAttribute('aria-label', 'Go to slide ' + (i + 1));
259 (function (idx) {
260 dot.addEventListener('click', function () { goTo(idx, true); });
261 })(i);
262 dotsContainer.appendChild(dot);
263 }
264 }
265
266 function startAutoplay() {
267 if (!autoplay) return;
268 stopAutoplay();
269 autoplayTimer = setInterval(function () {
270 goTo(currentIndex + 1, true);
271 }, autoplaySpeed);
272 }
273
274 function stopAutoplay() {
275 if (autoplayTimer) {
276 clearInterval(autoplayTimer);
277 autoplayTimer = null;
278 }
279 }
280
281 // Event listeners
282 if (prevBtn) {
283 prevBtn.addEventListener('click', function (e) {
284 e.stopPropagation();
285 goTo(currentIndex - 1, true);
286 stopAutoplay();
287 startAutoplay();
288 });
289 }
290 if (nextBtn) {
291 nextBtn.addEventListener('click', function (e) {
292 e.stopPropagation();
293 goTo(currentIndex + 1, true);
294 stopAutoplay();
295 startAutoplay();
296 });
297 }
298
299 // Touch/swipe support
300 var touchStartX = 0;
301 var touchDiff = 0;
302 track.addEventListener('touchstart', function (e) {
303 touchStartX = e.touches[0].clientX;
304 stopAutoplay();
305 }, { passive: true });
306 track.addEventListener('touchmove', function (e) {
307 touchDiff = e.touches[0].clientX - touchStartX;
308 }, { passive: true });
309 track.addEventListener('touchend', function () {
310 if (Math.abs(touchDiff) > 50) {
311 if (touchDiff < 0) goTo(currentIndex + 1, true);
312 else goTo(currentIndex - 1, true);
313 }
314 touchDiff = 0;
315 startAutoplay();
316 });
317
318 // Mouse drag support (desktop swipe)
319 var mouseDown = false;
320 var mouseStartX = 0;
321 var mouseDiff = 0;
322 track.addEventListener('mousedown', function (e) {
323 mouseDown = true;
324 mouseStartX = e.clientX;
325 mouseDiff = 0;
326 track.style.cursor = 'grabbing';
327 stopAutoplay();
328 e.preventDefault();
329 });
330 track.addEventListener('mousemove', function (e) {
331 if (!mouseDown) return;
332 mouseDiff = e.clientX - mouseStartX;
333 });
334 track.addEventListener('mouseup', function () {
335 if (!mouseDown) return;
336 mouseDown = false;
337 track.style.cursor = '';
338 if (Math.abs(mouseDiff) > 50) {
339 if (mouseDiff < 0) goTo(currentIndex + 1, true);
340 else goTo(currentIndex - 1, true);
341 }
342 mouseDiff = 0;
343 startAutoplay();
344 });
345 track.addEventListener('mouseleave', function () {
346 if (!mouseDown) return;
347 mouseDown = false;
348 track.style.cursor = '';
349 if (Math.abs(mouseDiff) > 50) {
350 if (mouseDiff < 0) goTo(currentIndex + 1, true);
351 else goTo(currentIndex - 1, true);
352 }
353 mouseDiff = 0;
354 });
355
356 window.addEventListener('resize', function () { updateLayout(); });
357
358 // Init
359 updateLayout();
360 if (showDots) updateDots();
361 startAutoplay();
362 }
363 };
364
365 // =========================================
366 // Module 3: Popup Controller
367 // =========================================
368 var Popup = {
369 popupEl: null,
370 iframe: null,
371 counterEl: null,
372 prevBtn: null,
373 nextBtn: null,
374 currentGallery: null,
375 currentIndex: 0,
376 isOpen: false,
377
378 init: function () {
379 this.createPopupElement();
380 this.bindEvents();
381 },
382
383 createPopupElement: function () {
384 if (document.querySelector('.ep-pdf-gallery__popup')) return;
385
386 var popup = document.createElement('div');
387 popup.className = 'ep-pdf-gallery__popup';
388 popup.innerHTML =
389 '<div class="ep-pdf-gallery__popup-overlay">' +
390 '<button class="ep-pdf-gallery__popup-close" aria-label="Close">&times;</button>' +
391 '<button class="ep-pdf-gallery__popup-prev" aria-label="Previous PDF">' +
392 '<svg viewBox="0 0 24 24"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>' +
393 '</button>' +
394 '<button class="ep-pdf-gallery__popup-next" aria-label="Next PDF">' +
395 '<svg viewBox="0 0 24 24"><path d="M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z"/></svg>' +
396 '</button>' +
397 '<div class="ep-pdf-gallery__popup-counter"></div>' +
398 '<div class="ep-pdf-gallery__popup-viewer">' +
399 '<iframe class="ep-pdf-gallery__popup-iframe" src="" allowfullscreen></iframe>' +
400 '</div>' +
401 '</div>';
402
403 document.body.appendChild(popup);
404
405 this.popupEl = popup;
406 this.iframe = popup.querySelector('.ep-pdf-gallery__popup-iframe');
407 this.counterEl = popup.querySelector('.ep-pdf-gallery__popup-counter');
408 this.prevBtn = popup.querySelector('.ep-pdf-gallery__popup-prev');
409 this.nextBtn = popup.querySelector('.ep-pdf-gallery__popup-next');
410 },
411
412 bindEvents: function () {
413 var self = this;
414
415 // Delegate click on gallery items
416 document.addEventListener('click', function (e) {
417 var item = e.target.closest('.ep-pdf-gallery__item');
418 if (!item) return;
419
420 var gallery = item.closest('.ep-pdf-gallery');
421 if (!gallery) return;
422
423 e.preventDefault();
424 self.currentGallery = gallery;
425 self.currentIndex = parseInt(item.dataset.pdfIndex) || 0;
426 self.open();
427 });
428
429 // Close button
430 if (this.popupEl) {
431 this.popupEl.querySelector('.ep-pdf-gallery__popup-close').addEventListener('click', function () {
432 self.close();
433 });
434
435 // Close on overlay click (not on viewer)
436 this.popupEl.querySelector('.ep-pdf-gallery__popup-overlay').addEventListener('click', function (e) {
437 if (e.target === e.currentTarget) {
438 self.close();
439 }
440 });
441
442 // Prev/Next
443 this.prevBtn.addEventListener('click', function (e) {
444 e.stopPropagation();
445 self.prev();
446 });
447 this.nextBtn.addEventListener('click', function (e) {
448 e.stopPropagation();
449 self.next();
450 });
451 }
452
453 // Keyboard
454 document.addEventListener('keydown', function (e) {
455 if (!self.isOpen) return;
456 if (e.key === 'Escape') self.close();
457 if (e.key === 'ArrowLeft') self.prev();
458 if (e.key === 'ArrowRight') self.next();
459 });
460 },
461
462 open: function () {
463 if (!this.currentGallery || !this.popupEl) return;
464
465 var items = this.currentGallery.querySelectorAll('.ep-pdf-gallery__item');
466 if (this.currentIndex >= items.length) return;
467
468 var item = items[this.currentIndex];
469 var pdfUrl = item.dataset.pdfUrl;
470 if (!pdfUrl) return;
471
472 var viewerSrc = this.buildViewerUrl(pdfUrl);
473 this.iframe.src = viewerSrc;
474
475 this.popupEl.classList.add('ep-pdf-gallery__popup--open');
476 document.body.style.overflow = 'hidden';
477 this.isOpen = true;
478
479 this.updateCounter(items.length);
480 this.updateNavButtons(items.length);
481 },
482
483 close: function () {
484 if (!this.popupEl) return;
485 this.popupEl.classList.remove('ep-pdf-gallery__popup--open');
486 this.iframe.src = '';
487 document.body.style.overflow = '';
488 this.isOpen = false;
489 },
490
491 prev: function () {
492 if (this.currentIndex > 0) {
493 this.currentIndex--;
494 this.iframe.src = '';
495 this.open();
496 }
497 },
498
499 next: function () {
500 var items = this.currentGallery ? this.currentGallery.querySelectorAll('.ep-pdf-gallery__item') : [];
501 if (this.currentIndex < items.length - 1) {
502 this.currentIndex++;
503 this.iframe.src = '';
504 this.open();
505 }
506 },
507
508 updateCounter: function (total) {
509 if (this.counterEl) {
510 this.counterEl.textContent = (this.currentIndex + 1) + ' / ' + total;
511 }
512 },
513
514 updateNavButtons: function (total) {
515 if (this.prevBtn) {
516 this.prevBtn.classList.toggle('ep-hidden', this.currentIndex <= 0);
517 }
518 if (this.nextBtn) {
519 this.nextBtn.classList.toggle('ep-hidden', this.currentIndex >= total - 1);
520 }
521 },
522
523 buildViewerUrl: function (pdfUrl) {
524 if (!this.currentGallery) return pdfUrl;
525
526 var viewerStyle = this.currentGallery.dataset.viewerStyle || 'modern';
527 var viewerParams = this.currentGallery.dataset.viewerParams || '';
528 var encodedFile = encodeURIComponent(pdfUrl);
529
530 // Get viewer base URLs from localized data
531 var pdfRenderer = '';
532 var flipbookRenderer = '';
533
534 if (typeof embedpressObj !== 'undefined') {
535 pdfRenderer = embedpressObj.pdfRenderer || '';
536 flipbookRenderer = embedpressObj.flipbookRenderer || '';
537 }
538
539 if (viewerStyle === 'flip-book' && flipbookRenderer) {
540 return flipbookRenderer + '&file=' + encodedFile + '&key=' + viewerParams;
541 } else if (pdfRenderer) {
542 return pdfRenderer + '&file=' + encodedFile + '#key=' + viewerParams;
543 }
544
545 // Fallback: just open the PDF directly
546 return pdfUrl;
547 }
548 };
549
550 // =========================================
551 // Module 4: Bookshelf — multi-row layout
552 // =========================================
553 var Bookshelf = {
554 DEFAULT_BOOKS_PER_SHELF: 5,
555
556 _getPerShelf: function (gallery) {
557 var w = window.innerWidth;
558 if (w <= 767) {
559 return parseInt(gallery.dataset.columnsMobile, 10) || 1;
560 } else if (w <= 1024) {
561 return parseInt(gallery.dataset.columnsTablet, 10) || 2;
562 }
563 return parseInt(gallery.dataset.columns, 10) || this.DEFAULT_BOOKS_PER_SHELF;
564 },
565
566 _buildRows: function (gallery, container, items) {
567 var perShelf = this._getPerShelf(gallery);
568
569 // Store current perShelf to avoid unnecessary rebuilds
570 if (container._lastPerShelf === perShelf) return;
571 container._lastPerShelf = perShelf;
572
573 // Clear existing rows
574 container.innerHTML = '';
575
576 // Chunk items into rows
577 for (var i = 0; i < items.length; i += perShelf) {
578 var row = document.createElement('div');
579 row.className = 'ep-pdf-gallery__shelf-row';
580
581 var chunk = items.slice(i, i + perShelf);
582 for (var j = 0; j < chunk.length; j++) {
583 row.appendChild(chunk[j]);
584 }
585
586 container.appendChild(row);
587 }
588 },
589
590 init: function (gallery) {
591 var carousel = gallery.querySelector('.ep-pdf-gallery__carousel');
592 var container = gallery.querySelector('.ep-pdf-gallery__bookshelf-container');
593 var items;
594
595 if (carousel) {
596 var track = carousel.querySelector('.ep-pdf-gallery__carousel-track');
597 if (!track) return;
598
599 items = Array.prototype.slice.call(track.querySelectorAll('.ep-pdf-gallery__item'));
600 if (!items.length) return;
601
602 // Create bookshelf container replacing carousel
603 container = document.createElement('div');
604 container.className = 'ep-pdf-gallery__bookshelf-container';
605 carousel.parentNode.replaceChild(container, carousel);
606 } else if (container) {
607 items = Array.prototype.slice.call(container.querySelectorAll('.ep-pdf-gallery__item'));
608 if (!items.length) return;
609 } else {
610 return;
611 }
612
613 // Store items reference for resize rebuilds
614 gallery._bookshelfItems = items;
615 gallery._bookshelfContainer = container;
616
617 var self = this;
618 self._buildRows(gallery, container, items);
619
620 // Rebuild rows on resize for responsive columns
621 if (!gallery._bookshelfResizeListener) {
622 var resizeTimer;
623 gallery._bookshelfResizeListener = function () {
624 clearTimeout(resizeTimer);
625 resizeTimer = setTimeout(function () {
626 self._buildRows(gallery, gallery._bookshelfContainer, gallery._bookshelfItems);
627 }, 150);
628 };
629 window.addEventListener('resize', gallery._bookshelfResizeListener);
630 }
631 }
632 };
633
634 // =========================================
635 // Module 5: Initialization
636 // =========================================
637 function initGalleries() {
638 var galleries = document.querySelectorAll('.ep-pdf-gallery');
639 if (!galleries.length) return;
640
641 // Init thumbnails
642 ThumbnailGenerator.initAll();
643
644 // Init layouts
645 galleries.forEach(function (gallery) {
646 var layout = gallery.dataset.layout;
647
648 // Set CSS custom properties from data attributes
649 var columns = gallery.dataset.columns || 3;
650 var columnsTablet = gallery.dataset.columnsTablet || 2;
651 var columnsMobile = gallery.dataset.columnsMobile || 1;
652 var gap = gallery.dataset.gap || 20;
653 var radius = gallery.dataset.borderRadius;
654
655 gallery.style.setProperty('--ep-gallery-columns-desktop', columns);
656 gallery.style.setProperty('--ep-gallery-columns-tablet', columnsTablet);
657 gallery.style.setProperty('--ep-gallery-columns-mobile', columnsMobile);
658 gallery.style.setProperty('--ep-gallery-gap', gap + 'px');
659 if (radius !== undefined) {
660 gallery.style.setProperty('--ep-gallery-radius', radius + 'px');
661 }
662
663 if (layout === 'carousel') {
664 Carousel.init(gallery);
665 }
666 if (layout === 'bookshelf') {
667 Bookshelf.init(gallery);
668 }
669 });
670
671 // Init popup
672 Popup.init();
673 }
674
675 // Run on DOMContentLoaded
676 if (document.readyState === 'loading') {
677 document.addEventListener('DOMContentLoaded', initGalleries);
678 } else {
679 initGalleries();
680 }
681
682 // Elementor editor: re-initialize when widget is rendered/re-rendered
683 if (typeof jQuery !== 'undefined') {
684 jQuery(window).on('elementor/frontend/init', function () {
685 if (typeof elementorFrontend !== 'undefined') {
686 elementorFrontend.hooks.addAction(
687 'frontend/element_ready/embedpress_pdf_gallery.default',
688 function ($scope) {
689 var gallery = $scope.find('.ep-pdf-gallery')[0];
690 if (!gallery) return;
691
692 // Set CSS custom properties from data attributes
693 var columns = gallery.dataset.columns || 3;
694 var columnsTablet = gallery.dataset.columnsTablet || 2;
695 var columnsMobile = gallery.dataset.columnsMobile || 1;
696 var gap = gallery.dataset.gap || 20;
697 var radius = gallery.dataset.borderRadius;
698
699 gallery.style.setProperty('--ep-gallery-columns-desktop', columns);
700 gallery.style.setProperty('--ep-gallery-columns-tablet', columnsTablet);
701 gallery.style.setProperty('--ep-gallery-columns-mobile', columnsMobile);
702 gallery.style.setProperty('--ep-gallery-gap', gap + 'px');
703 if (radius !== undefined) {
704 gallery.style.setProperty('--ep-gallery-radius', radius + 'px');
705 }
706
707 // Re-init thumbnails within this widget
708 var canvases = gallery.querySelectorAll('.ep-pdf-gallery__canvas[data-pdf-src]');
709 if (canvases.length) {
710 ThumbnailGenerator.loadPdfJs(function () {
711 if (!window.pdfjsLib) return;
712 canvases.forEach(function (c) {
713 ThumbnailGenerator.renderThumbnail(c, c.dataset.pdfSrc);
714 });
715 });
716 }
717
718 // Re-init carousel or bookshelf
719 var layout = gallery.dataset.layout;
720 if (layout === 'carousel') {
721 Carousel.init(gallery);
722 } else if (layout === 'bookshelf') {
723 Bookshelf.init(gallery);
724 }
725
726 // Ensure popup is initialized
727 if (!Popup.popupEl) {
728 Popup.init();
729 }
730
731 // If popup is open, update gallery reference and refresh iframe
732 // so changed viewer controls take effect immediately
733 if (Popup.isOpen && Popup.currentGallery) {
734 var oldGalleryId = Popup.currentGallery.dataset.galleryId;
735 var newGalleryId = gallery.dataset.galleryId;
736 if (oldGalleryId === newGalleryId) {
737 Popup.currentGallery = gallery;
738 Popup.open();
739 }
740 }
741 }
742 );
743 }
744 });
745 }
746 })();
747