PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents / 4.5.3
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents v4.5.3
4.6.0 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-elementor-editor.js
embedpress / assets / js Last commit date
chunks 1 month ago vendor 9 months ago admin.build.js 1 month ago admin.js 3 months ago analytics-tracker.js 9 months ago analytics.build.js 1 month ago blocks.build.js 1 month ago carousel.js 1 year ago custom-player.build.js 1 month ago documents-viewer-script.js 3 months ago ep-pdf-lightbox.js 3 months ago feature-notices.js 7 months ago front.js 3 months ago frontend.build.js 3 months ago gallery-justify.js 9 months ago gutneberg-script.js 2 months ago index.html 7 years ago initCarousel.js 2 years ago initplyr.js 2 months ago instafeed.js 1 month 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 month ago pdf-gallery-elementor-editor.js 3 months ago pdf-gallery.js 3 months ago preview.js 9 months ago settings.js 3 months ago sponsored.js 9 months ago
pdf-gallery-elementor-editor.js
650 lines
1 /**
2 * EmbedPress PDF Gallery - Elementor Editor Script
3 * Repeater-style UI with PDF thumbnails, reorder, and custom thumbnail support
4 * Auto-generates thumbnails via WP media sizes or server-side AJAX fallback
5 * Uses $e.run API for proper persistence and widget re-render
6 */
7 (function ($) {
8 'use strict';
9
10 if (typeof elementor === 'undefined') return;
11
12 // Stored references for re-rendering on section switch
13 var _panel = null;
14 var _model = null;
15 var _view = null;
16
17 // Track which PDFs are currently generating thumbnails (by URL)
18 var _generatingThumbs = {};
19
20 // Pro feature check
21 function isProActive() {
22 return !!(window.epPdfGallery && epPdfGallery.isProActive);
23 }
24
25 function showProAlert() {
26 if (isProActive()) return;
27 var alertWrap = document.querySelector('.pro__alert__wrap');
28 if (!alertWrap) {
29 // Build pro alert modal
30 var overlay = document.createElement('div');
31 overlay.className = 'pro__alert__wrap';
32 overlay.style.display = 'block';
33 overlay.innerHTML =
34 '<div class="pro__alert__card">' +
35 '<button class="pro__alert__close">&times;</button>' +
36 '<img src="" alt="">' +
37 '<h2>Starter Plan</h2>' +
38 '<p>You need to upgrade to the starter plan to use this feature.</p>' +
39 '<a href="https://wpdeveloper.com/in/upgrade-embedpress" target="_blank" class="pro__alert__btn">Upgrade to Starter</a>' +
40 '</div>';
41 document.body.appendChild(overlay);
42 // Close handlers
43 overlay.addEventListener('click', function (e) {
44 if (e.target === overlay || e.target.classList.contains('pro__alert__close')) {
45 overlay.style.display = 'none';
46 }
47 });
48 } else {
49 alertWrap.style.display = 'block';
50 }
51 }
52
53 function getPdfItems(model) {
54 var raw = model.getSetting('pdf_items_json');
55 if (!raw) return [];
56 try {
57 var items = JSON.parse(raw);
58 return Array.isArray(items) ? items : [];
59 } catch (e) {
60 return [];
61 }
62 }
63
64 function setPdfItems(view, items) {
65 var container = view.getContainer();
66 $e.run('document/elements/settings', {
67 container: container,
68 settings: {
69 pdf_items_json: JSON.stringify(items)
70 },
71 options: {
72 external: true
73 }
74 });
75
76 // Re-populate list after Elementor re-renders panel controls
77 setTimeout(function () {
78 if (_panel && _model) {
79 renderRepeater(items);
80 }
81 }, 300);
82 }
83
84 // ── PDF.js loader ──────────────────────────────────────────────────
85 var _pdfjsLoaded = false;
86 var _pdfjsLoading = false;
87 var _pdfjsCallbacks = [];
88
89 function loadPdfJs(callback) {
90 if (_pdfjsLoaded && window.pdfjsLib) { callback(true); return; }
91 _pdfjsCallbacks.push(callback);
92 if (_pdfjsLoading) return;
93 _pdfjsLoading = true;
94
95 var assetsUrl = (window.epPdfGallery && epPdfGallery.assetsUrl) ? epPdfGallery.assetsUrl : '';
96 if (!assetsUrl) {
97 console.error('[EP PDF Gallery] No assetsUrl found in epPdfGallery');
98 _pdfjsLoading = false;
99 _pdfjsCallbacks.forEach(function (cb) { cb(false); });
100 _pdfjsCallbacks = [];
101 return;
102 }
103
104 var scriptSrc = assetsUrl + 'pdf/build/script.js';
105 var script = document.createElement('script');
106 script.src = scriptSrc;
107 script.type = 'module';
108 script.onload = function () {
109 // Module scripts execute asynchronously; pdfjsLib is set on globalThis
110 // Give module a tick to execute
111 setTimeout(function () {
112 if (window.pdfjsLib || globalThis.pdfjsLib) {
113 if (!window.pdfjsLib) window.pdfjsLib = globalThis.pdfjsLib;
114 window.pdfjsLib.GlobalWorkerOptions.workerSrc = assetsUrl + 'pdf/build/pdf.worker.js';
115 _pdfjsLoaded = true;
116 } else {
117 console.error('[EP PDF Gallery] Script loaded but pdfjsLib not found');
118 }
119 _pdfjsLoading = false;
120 _pdfjsCallbacks.forEach(function (cb) { cb(_pdfjsLoaded); });
121 _pdfjsCallbacks = [];
122 }, 50);
123 };
124 script.onerror = function () {
125 console.error('[EP PDF Gallery] Failed to load PDF.js from:', scriptSrc);
126 _pdfjsLoading = false;
127 _pdfjsCallbacks.forEach(function (cb) { cb(false); });
128 _pdfjsCallbacks = [];
129 };
130 document.head.appendChild(script);
131 }
132
133 // ── Render first page of PDF to an off-screen canvas, return data-URL ─
134 function renderPdfFirstPage(pdfUrl, callback) {
135 loadPdfJs(function (ok) {
136 if (!ok || !window.pdfjsLib) {
137 console.error('[EP PDF Gallery] PDF.js not available, cannot render:', pdfUrl);
138 callback(null);
139 return;
140 }
141
142 window.pdfjsLib.getDocument(pdfUrl).promise.then(function (pdf) {
143 pdf.getPage(1).then(function (page) {
144 var targetWidth = Math.max(400 * (window.devicePixelRatio || 1), 600);
145 var scale = targetWidth / page.getViewport({ scale: 1 }).width;
146 scale = Math.max(scale, 1);
147 var viewport = page.getViewport({ scale: scale });
148
149 var canvas = document.createElement('canvas');
150 canvas.width = viewport.width;
151 canvas.height = viewport.height;
152 var ctx = canvas.getContext('2d');
153
154 page.render({ canvasContext: ctx, viewport: viewport }).promise.then(function () {
155 try {
156 var dataUrl = canvas.toDataURL('image/png');
157 callback(dataUrl);
158 } catch (e) {
159 console.error('[EP PDF Gallery] toDataURL failed (CORS?):', e.message);
160 callback(null);
161 }
162 }).catch(function (err) {
163 console.error('[EP PDF Gallery] Page render failed:', err);
164 callback(null);
165 });
166 }).catch(function (err) {
167 console.error('[EP PDF Gallery] getPage failed:', err);
168 callback(null);
169 });
170 }).catch(function (err) {
171 console.error('[EP PDF Gallery] getDocument failed:', err);
172 callback(null);
173 });
174 });
175 }
176
177 // ── Upload a base64 image to WordPress via AJAX ─────────────────────
178 function uploadThumbnailImage(dataUrl, pdfUrl, fileName, callback, attachmentId) {
179 if (!window.epPdfGallery || !epPdfGallery.ajaxUrl) {
180 console.error('[EP PDF Gallery] No AJAX URL configured');
181 callback('', 0);
182 return;
183 }
184
185 // Use FormData to handle large base64 payloads reliably
186 var formData = new FormData();
187 formData.append('action', 'ep_upload_pdf_thumbnail');
188 formData.append('nonce', epPdfGallery.nonce);
189 formData.append('image_data', dataUrl);
190 formData.append('pdf_url', pdfUrl);
191 formData.append('file_name', fileName);
192 if (attachmentId) {
193 formData.append('attachment_id', attachmentId);
194 }
195
196 $.ajax({
197 url: epPdfGallery.ajaxUrl,
198 method: 'POST',
199 data: formData,
200 processData: false,
201 contentType: false,
202 success: function (response) {
203 if (response.success && response.data && response.data.url) {
204 callback(response.data.url, response.data.id);
205 } else {
206 console.error('[EP PDF Gallery] Upload failed, response:', response);
207 callback('', 0);
208 }
209 },
210 error: function (xhr, status, err) {
211 console.error('[EP PDF Gallery] Upload AJAX error:', status, err);
212 callback('', 0);
213 }
214 });
215 }
216
217 /**
218 * Helper: apply a generated thumbnail to item data and refresh UI.
219 */
220 function applyThumbToItem(pdfUrl, thumbUrl, thumbId) {
221 if (!_model || !_view) {
222 console.error('[EP PDF Gallery] No model/view to apply thumbnail');
223 return;
224 }
225 var currentItems = getPdfItems(_model);
226 var applied = false;
227 for (var i = 0; i < currentItems.length; i++) {
228 if (currentItems[i].url === pdfUrl && !currentItems[i].autoThumbnailUrl) {
229 currentItems[i].autoThumbnailId = thumbId || 0;
230 currentItems[i].autoThumbnailUrl = thumbUrl;
231 applied = true;
232 break;
233 }
234 }
235 if (applied) {
236 setPdfItems(_view, currentItems);
237 renderRepeater(currentItems);
238 }
239 }
240
241 /**
242 * Auto-generate thumbnails for items that don't have any.
243 * Uses client-side PDF.js to render first page, then uploads as PNG.
244 * Processes sequentially to avoid overloading.
245 */
246 function autoGenerateThumbnails(items) {
247 var queue = [];
248
249 items.forEach(function (item) {
250 if (!item.autoThumbnailUrl && !item.customThumbnailUrl && item.url) {
251 queue.push(item);
252 }
253 });
254
255 if (!queue.length) {
256 return;
257 }
258
259 function processNext(queueIndex) {
260 if (queueIndex >= queue.length) {
261 return;
262 }
263
264 var item = queue[queueIndex];
265 var pdfUrl = item.url;
266
267 // Skip if already generating
268 if (_generatingThumbs[pdfUrl]) {
269 processNext(queueIndex + 1);
270 return;
271 }
272
273 _generatingThumbs[pdfUrl] = true;
274 updateThumbLoading(pdfUrl, true);
275
276 // First check if server already has a cached thumbnail
277 if (item.id && window.epPdfGallery && epPdfGallery.ajaxUrl) {
278 $.post(epPdfGallery.ajaxUrl, {
279 action: 'ep_generate_pdf_thumbnail',
280 nonce: epPdfGallery.nonce,
281 attachment_id: item.id
282 }, function (response) {
283 if (response.success && response.data && response.data.url) {
284 delete _generatingThumbs[pdfUrl];
285 applyThumbToItem(pdfUrl, response.data.url, response.data.id);
286 processNext(queueIndex + 1);
287 return;
288 }
289 // No cached thumbnail, render client-side
290 doClientRender();
291 }).fail(function () {
292 doClientRender();
293 });
294 } else {
295 doClientRender();
296 }
297
298 function doClientRender() {
299 // Render first page via PDF.js client-side
300 renderPdfFirstPage(pdfUrl, function (dataUrl) {
301 if (!dataUrl) {
302 delete _generatingThumbs[pdfUrl];
303 updateThumbLoading(pdfUrl, false);
304 processNext(queueIndex + 1);
305 return;
306 }
307
308 // Upload the rendered PNG to WordPress
309 uploadThumbnailImage(dataUrl, pdfUrl, item.fileName || '', function (uploadedUrl, uploadedId) {
310 delete _generatingThumbs[pdfUrl];
311 if (uploadedUrl) {
312 applyThumbToItem(pdfUrl, uploadedUrl, uploadedId);
313 } else {
314 updateThumbLoading(pdfUrl, false);
315 }
316 processNext(queueIndex + 1);
317 }, item.id);
318 });
319 }
320 }
321
322 processNext(0);
323 }
324
325 /**
326 * Update the loading state of a thumbnail by PDF URL
327 */
328 function updateThumbLoading(pdfUrl, isLoading) {
329 if (!_panel) return;
330 // Find the item by matching data-pdf-url
331 _panel.$el.find('.ep-pdf-gallery-repeater-item').each(function () {
332 var index = parseInt($(this).data('index'), 10);
333 var items = getPdfItems(_model);
334 if (items[index] && items[index].url === pdfUrl) {
335 var $thumb = $(this).find('.ep-pdf-gallery-repeater-item__thumb');
336 if (isLoading) {
337 $thumb.addClass('is-generating');
338 // Replace content with spinner if not already
339 if (!$thumb.find('.ep-pdf-gallery-repeater-item__spinner').length) {
340 $thumb.html('<div class="ep-pdf-gallery-repeater-item__spinner"></div>');
341 }
342 } else {
343 $thumb.removeClass('is-generating');
344 }
345 }
346 });
347 }
348
349 function buildRepeaterItem(item, index, totalCount) {
350 var name = item.fileName || (item.url ? item.url.split('/').pop() : 'PDF');
351 var hasCustomThumb = !!(item.customThumbnailUrl);
352 var hasAutoThumb = !!(item.autoThumbnailUrl);
353 var hasThumb = hasCustomThumb || hasAutoThumb;
354 var thumbUrl = hasCustomThumb ? item.customThumbnailUrl : (hasAutoThumb ? item.autoThumbnailUrl : '');
355 var isGenerating = !!(item.url && _generatingThumbs[item.url]);
356
357 var thumbContent = '';
358 if (hasThumb) {
359 thumbContent =
360 '<img src="' + thumbUrl + '" alt="' + name + '" />' +
361 '<div class="ep-pdf-gallery-repeater-item__thumb-overlay">' +
362 '<i class="eicon-edit"></i>' +
363 '</div>';
364 } else if (isGenerating) {
365 thumbContent =
366 '<div class="ep-pdf-gallery-repeater-item__spinner"></div>';
367 } else {
368 thumbContent =
369 '<div class="ep-pdf-gallery-repeater-item__thumb-placeholder">' +
370 '<svg width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zM6 20V4h7v5h5v11H6z"/></svg>' +
371 '</div>' +
372 '<div class="ep-pdf-gallery-repeater-item__thumb-overlay">' +
373 '<i class="eicon-image"></i>' +
374 '</div>';
375 }
376
377 var thumbActions = '';
378 if (isProActive()) {
379 if (hasCustomThumb) {
380 thumbActions =
381 '<button class="ep-pdf-gallery-repeater-item__thumb-btn ep-pdf-gallery-thumb-change" data-index="' + index + '" type="button">Change</button>' +
382 '<button class="ep-pdf-gallery-repeater-item__thumb-btn ep-pdf-gallery-repeater-item__thumb-btn--remove ep-pdf-gallery-thumb-remove" data-index="' + index + '" type="button">Remove</button>';
383 } else {
384 thumbActions =
385 '<button class="ep-pdf-gallery-repeater-item__thumb-btn ep-pdf-gallery-thumb-set" data-index="' + index + '" type="button">' +
386 '<i class="eicon-image" style="margin-right:3px;font-size:10px;"></i>Custom Thumbnail' +
387 '</button>';
388 }
389 } else {
390 thumbActions =
391 '<button class="ep-pdf-gallery-repeater-item__thumb-btn ep-pdf-gallery-thumb-pro" data-index="' + index + '" type="button">' +
392 '<i class="eicon-image" style="margin-right:3px;font-size:10px;"></i>Custom Thumbnail <span style="color:#ff6b6b;font-size:10px;font-weight:600;margin-left:3px;">Pro</span>' +
393 '</button>';
394 }
395
396 var statusLabel = '';
397 if (isGenerating) {
398 statusLabel = '<span class="ep-pdf-gallery-repeater-item__status">Generating...</span>';
399 } else if (hasAutoThumb && !hasCustomThumb) {
400 statusLabel = '<span class="ep-pdf-gallery-repeater-item__status">Auto-generated</span>';
401 }
402
403 var html =
404 '<div class="ep-pdf-gallery-repeater-item" data-index="' + index + '">' +
405 '<div class="ep-pdf-gallery-repeater-item__thumb ep-pdf-gallery-thumb-click" data-index="' + index + '">' +
406 thumbContent +
407 '</div>' +
408 '<div class="ep-pdf-gallery-repeater-item__content">' +
409 '<div class="ep-pdf-gallery-repeater-item__name" title="' + name + '">' + name + '</div>' +
410 '<div class="ep-pdf-gallery-repeater-item__thumb-label">Thumbnail ' + statusLabel + '</div>' +
411 '<div class="ep-pdf-gallery-repeater-item__thumb-actions">' +
412 thumbActions +
413 '</div>' +
414 '<div class="ep-pdf-gallery-repeater-item__order-actions">' +
415 '<button class="ep-pdf-gallery-repeater-item__order-btn ep-pdf-gallery-move-up" data-index="' + index + '" title="Move Up" type="button"' + (index === 0 ? ' disabled' : '') + '>' +
416 '<svg width="12" height="12" viewBox="0 0 24 24"><path fill="currentColor" d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/></svg>' +
417 '</button>' +
418 '<button class="ep-pdf-gallery-repeater-item__order-btn ep-pdf-gallery-move-down" data-index="' + index + '" title="Move Down" type="button"' + (index === totalCount - 1 ? ' disabled' : '') + '>' +
419 '<svg width="12" height="12" viewBox="0 0 24 24"><path fill="currentColor" d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z"/></svg>' +
420 '</button>' +
421 '</div>' +
422 '</div>' +
423 '<button class="ep-pdf-gallery-repeater-item__remove-btn ep-pdf-gallery-remove-item" data-index="' + index + '" title="Remove" type="button">&times;</button>' +
424 '</div>';
425
426 return html;
427 }
428
429 function renderRepeater(itemsOverride) {
430 if (!_panel) return;
431 var $repeater = _panel.$el.find('.ep-pdf-gallery-repeater');
432 if (!$repeater.length) return;
433
434 var items = itemsOverride || getPdfItems(_model);
435 $repeater.empty();
436
437 if (!items.length) {
438 $repeater.append('<div class="ep-pdf-gallery-empty">No PDF files added yet. Click "Add PDF Files" to get started.</div>');
439 return;
440 }
441
442 items.forEach(function (item, index) {
443 $repeater.append(buildRepeaterItem(item, index, items.length));
444 });
445 }
446
447 function openThumbnailPicker(index) {
448 var frame = wp.media({
449 title: 'Select Custom Thumbnail',
450 library: { type: 'image' },
451 multiple: false,
452 button: { text: 'Set Thumbnail' }
453 });
454
455 frame.on('select', function () {
456 var attachment = frame.state().get('selection').first().toJSON();
457 var items = getPdfItems(_model);
458 if (items[index]) {
459 items[index].customThumbnailId = attachment.id;
460 items[index].customThumbnailUrl = attachment.url;
461 setPdfItems(_view, items);
462 renderRepeater(items);
463 }
464 });
465
466 frame.open();
467 }
468
469 function bindEvents() {
470 if (!_panel) return;
471 var $section = _panel.$el;
472
473 // Add PDF Files button
474 $section.off('click.epPdfSelect').on('click.epPdfSelect', '.ep-pdf-gallery-select-btn', function (e) {
475 e.preventDefault();
476
477 var frame = wp.media({
478 title: 'Select PDF Files',
479 library: { type: 'application/pdf' },
480 multiple: 'add',
481 button: { text: 'Add to Gallery' }
482 });
483
484 frame.on('select', function () {
485 var selection = frame.state().get('selection').toJSON();
486 var currentItems = getPdfItems(_model);
487 var existingUrls = currentItems.map(function (item) { return item.url; });
488
489 var hasNewWithoutThumb = false;
490
491 selection.forEach(function (file) {
492 if (existingUrls.indexOf(file.url) === -1) {
493 // Check if WordPress already generated a preview thumbnail
494 var autoThumbUrl = '';
495 if (file.sizes) {
496 if (file.sizes.medium) {
497 autoThumbUrl = file.sizes.medium.url;
498 } else if (file.sizes.thumbnail) {
499 autoThumbUrl = file.sizes.thumbnail.url;
500 } else if (file.sizes.full) {
501 autoThumbUrl = file.sizes.full.url;
502 }
503 }
504
505 currentItems.push({
506 id: file.id,
507 url: file.url,
508 fileName: file.filename || file.title || '',
509 customThumbnailId: 0,
510 customThumbnailUrl: '',
511 autoThumbnailId: 0,
512 autoThumbnailUrl: autoThumbUrl
513 });
514
515 if (!autoThumbUrl) {
516 hasNewWithoutThumb = true;
517 }
518 }
519 });
520
521 setPdfItems(_view, currentItems);
522 renderRepeater(currentItems);
523
524 // Auto-generate thumbnails for items without one
525 if (hasNewWithoutThumb) {
526 autoGenerateThumbnails(currentItems);
527 }
528 });
529
530 frame.open();
531 });
532
533 // Remove item
534 $section.off('click.epPdfRemove').on('click.epPdfRemove', '.ep-pdf-gallery-remove-item', function (e) {
535 e.preventDefault();
536 var index = parseInt($(this).data('index'), 10);
537 var items = getPdfItems(_model);
538 items.splice(index, 1);
539 setPdfItems(_view, items);
540 renderRepeater(items);
541 });
542
543 // Move up
544 $section.off('click.epMoveUp').on('click.epMoveUp', '.ep-pdf-gallery-move-up', function (e) {
545 e.preventDefault();
546 var index = parseInt($(this).data('index'), 10);
547 if (index <= 0) return;
548 var items = getPdfItems(_model);
549 var temp = items[index];
550 items[index] = items[index - 1];
551 items[index - 1] = temp;
552 setPdfItems(_view, items);
553 renderRepeater(items);
554 });
555
556 // Move down
557 $section.off('click.epMoveDown').on('click.epMoveDown', '.ep-pdf-gallery-move-down', function (e) {
558 e.preventDefault();
559 var index = parseInt($(this).data('index'), 10);
560 var items = getPdfItems(_model);
561 if (index >= items.length - 1) return;
562 var temp = items[index];
563 items[index] = items[index + 1];
564 items[index + 1] = temp;
565 setPdfItems(_view, items);
566 renderRepeater(items);
567 });
568
569 // Pro thumbnail button (show upgrade alert)
570 $section.off('click.epThumbPro').on('click.epThumbPro', '.ep-pdf-gallery-thumb-pro', function (e) {
571 e.preventDefault();
572 e.stopPropagation();
573 showProAlert();
574 });
575
576 // Set custom thumbnail (button click)
577 $section.off('click.epThumbSet').on('click.epThumbSet', '.ep-pdf-gallery-thumb-set', function (e) {
578 e.preventDefault();
579 var index = parseInt($(this).data('index'), 10);
580 openThumbnailPicker(index);
581 });
582
583 // Thumbnail area click (open picker)
584 $section.off('click.epThumbClick').on('click.epThumbClick', '.ep-pdf-gallery-thumb-click', function (e) {
585 e.preventDefault();
586 if (!isProActive()) { showProAlert(); return; }
587 var index = parseInt($(this).data('index'), 10);
588 openThumbnailPicker(index);
589 });
590
591 // Change custom thumbnail
592 $section.off('click.epThumbChange').on('click.epThumbChange', '.ep-pdf-gallery-thumb-change', function (e) {
593 e.preventDefault();
594 e.stopPropagation();
595 var index = parseInt($(this).data('index'), 10);
596 openThumbnailPicker(index);
597 });
598
599 // Remove custom thumbnail
600 $section.off('click.epThumbRemove').on('click.epThumbRemove', '.ep-pdf-gallery-thumb-remove', function (e) {
601 e.preventDefault();
602 e.stopPropagation();
603 var index = parseInt($(this).data('index'), 10);
604 var items = getPdfItems(_model);
605 if (items[index]) {
606 items[index].customThumbnailId = 0;
607 items[index].customThumbnailUrl = '';
608 setPdfItems(_view, items);
609 renderRepeater(items);
610 }
611 });
612
613 // Clear all
614 $section.off('click.epPdfClear').on('click.epPdfClear', '.ep-pdf-gallery-clear-btn', function (e) {
615 e.preventDefault();
616 setPdfItems(_view, []);
617 renderRepeater([]);
618 });
619 }
620
621 // Hook into widget panel open
622 elementor.hooks.addAction('panel/open_editor/widget/embedpress_pdf_gallery', function (panel, model, view) {
623 _panel = panel;
624 _model = model;
625 _view = view;
626
627 setTimeout(function () {
628 renderRepeater();
629 bindEvents();
630
631 // Auto-generate thumbnails for existing items that don't have one
632 var items = getPdfItems(_model);
633 if (items.length) {
634 autoGenerateThumbnails(items);
635 }
636 }, 100);
637 });
638
639 // Re-render the repeater when the "PDF Files" section is activated
640 elementor.channels.editor.on('section:activated', function (sectionName) {
641 if (sectionName === 'section_pdf_files' && _panel && _model) {
642 setTimeout(function () {
643 renderRepeater();
644 bindEvents();
645 }, 100);
646 }
647 });
648
649 })(jQuery);
650