PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.49
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.49
51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 51.1.45 51.1.46 51.1.47 51.1.49 All 37 releases
king-addons / includes / admin / js / templates.js

templates.js in King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder 51.1.49, at includes/admin/js/templates.js

1,175 lines 46.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // noinspection DuplicatedCode,JSUnresolvedReference,JSValidateTypes
2
3 jQuery(document).ready(function ($) {
4 $(document).on('click', '.template-item', function () {
5 let templateKey = $(this).data('template-key');
6 let templatePlan = $(this).data('template-plan');
7 let templateBtn = $('#install-template');
8 templateBtn.attr('data-template-key', templateKey);
9 templateBtn.attr('data-template-plan', templatePlan);
10 let planActive = templateBtn.attr('data-plan-active');
11
12 if (templatePlan === 'premium') {
13 if (planActive === 'premium') {
14 templateBtn.text('Import Premium Template');
15 } else {
16 templateBtn.text('Import Premium Template');
17 }
18 } else {
19 templateBtn.text('Import Free Template');
20 }
21
22 $('#template-preview-iframe').attr('src', 'https://demo.kingaddons.com/' + templateKey);
23 $('#template-preview-link').attr('href', 'https://demo.kingaddons.com/' + templateKey);
24 $('#template-preview-popup').fadeIn();
25 });
26
27 // Listen for clicks on any button inside .preview-mode-switcher
28 $('.preview-mode-switcher button').on('click', function () {
29 // Remove the .active class from all buttons
30 $('.preview-mode-switcher button').removeClass('active');
31 // Add .active to the clicked button
32 $(this).addClass('active');
33
34 // Determine which mode was clicked: desktop, tablet, or mobile
35 let mode = $(this).data('mode');
36
37 // Select the preview iframe
38 let $iframe = $('#template-preview-iframe');
39
40 // Remove any previous mode classes
41 $iframe.removeClass('preview-tablet preview-mobile');
42
43 // If tablet, add .preview-tablet class
44 if (mode === 'tablet') {
45 $iframe.addClass('preview-tablet');
46 }
47 // If mobile, add .preview-mobile class
48 else if (mode === 'mobile') {
49 $iframe.addClass('preview-mobile');
50 }
51 // If desktop, no extra class (width:100% by default).
52 });
53
54 $(document).on('click', '#close-popup', function () {
55 $('#template-preview-popup').fadeOut();
56 });
57
58 $(document).on('click', '#activate-license-btn', function () {
59 $('#templates-catalog').addClass('kng-whole-overlay');
60 $('#license-activating-popup').fadeIn();
61 });
62
63 $(document).on('click', '#close-license-activating-popup', function () {
64 $('#templates-catalog').removeClass('kng-whole-overlay');
65 $('#license-activating-popup').fadeOut();
66 });
67
68 $(document).on('click', '#close-premium-promo-popup', function () {
69 $('#templates-catalog').removeClass('kng-whole-overlay');
70 $('#premium-promo-popup').fadeOut();
71 });
72
73 $(document).on('click', '#close-installing-popup', function () {
74 $('#templates-catalog').removeClass('kng-whole-overlay');
75 $('#template-installing-popup').fadeOut();
76 $('#go-to-imported-page').fadeOut();
77 $('#close-installing-popup').fadeOut();
78 document.getElementById('final_response').innerText = '';
79 document.getElementById('progress').innerText = '';
80 document.getElementById('progress-bar').style.width = '0%';
81 document.getElementById('progress-bar').innerText = '0%';
82 });
83
84 $(document).on('click', '#install-template', function () {
85
86 $('#templates-catalog').addClass('kng-whole-overlay');
87 $('#template-preview-popup').fadeOut();
88
89 let templateBtn = $('#install-template');
90 let templateKey = templateBtn.attr('data-template-key');
91 let templatePlan = templateBtn.attr('data-template-plan');
92 let planActive = templateBtn.attr('data-plan-active');
93
94 let api_request_url;
95 let installId;
96
97 if (planActive === 'premium') {
98 if (templatePlan === 'premium') {
99 api_request_url = 'https://api.kingaddons.com/get-template.php';
100 installId = window.kingAddons.installId;
101 } else {
102 api_request_url = 'https://api.kingaddons.com/get-template-free.php';
103 installId = 0;
104 }
105 } else {
106 if (templatePlan === 'free') {
107 api_request_url = 'https://api.kingaddons.com/get-template-free.php';
108 installId = 0;
109 } else {
110 $('#premium-promo-popup').fadeIn();
111 return;
112 }
113 }
114
115 fetch(api_request_url, {
116 method: 'POST',
117 headers: {
118 'Content-Type': 'application/json',
119 },
120 body: JSON.stringify({
121 key: templateKey,
122 install: installId,
123 }),
124 })
125 .then(response => {
126 if (!response.ok) {
127 // The server returned a 4xx or 5xx, read the text and throw an error
128 return response.text().then(html => {
129 console.error('Server error:\n' + html);
130 throw new Error('Server error (not JSON).');
131 });
132 }
133 // If ok, parse JSON
134 return response.json();
135 })
136 .then(data => {
137 if (!data.success) {
138 console.error('API error:', data);
139 }
140 if (data.success) {
141 $('#template-installing-popup').fadeIn();
142 doImport(data);
143 } else {
144 $('#premium-promo-popup').fadeIn();
145 }
146 })
147 .catch(error => {
148 console.error('Fetch error:', error);
149 alert('Connection error: ' + error);
150 });
151 });
152
153 function doImport(data) {
154 document.getElementById('progress').innerText = 'Starting import...';
155 document.getElementById('image-list').innerHTML = '';
156 document.getElementById('progress').innerText = 'Import initialized.';
157 document.getElementById('progress-bar').style.width = '10%';
158 document.getElementById('progress-bar').innerText = '10%';
159
160 let images = data.landing.images;
161
162 if (images && images.length > 0) {
163 let imageList = images.map(function (img) {
164 return '<li data-id="' + img.id + '" data-url="' + img.url + '">' + img.url + ' (ID: ' + img.id + ')</li>';
165 }).join('');
166
167 document.getElementById('image-list').innerHTML = '<ul>' + imageList + '</ul>';
168
169 startImport(data.landing);
170 } else {
171 document.getElementById('final_response').innerText = 'No images to import.';
172 }
173 }
174
175 function startImport(initial_data) {
176 fetch(kingAddonsData.ajaxUrl, {
177 method: 'POST',
178 body: new URLSearchParams({
179 action: 'import_elementor_page_with_images',
180 nonce: kingAddonsData.nonce,
181 data: JSON.stringify(initial_data)
182 })
183 })
184 .then(response => {
185 if (!response.ok) {
186 // The server returned a 4xx or 5xx, read the text and throw an error
187 return response.text().then(html => {
188 console.error('Server error:\n' + html);
189 throw new Error('Server error:\n' + html);
190 });
191 }
192 // If ok, parse JSON
193 return response.json();
194 })
195 .then(data => {
196 if (data.success) {
197 processNextImage();
198 } else {
199 alert('Error getting template: ' + data.message);
200 }
201 })
202 .catch(error => {
203 alert('Error: ' + error);
204 });
205 }
206
207 function processNextImage() {
208 const maxRetries = 3;
209 let currentRetry = 0;
210 let retryTimeout = 1000;
211
212 function attemptProcessImage() {
213 fetch(kingAddonsData.ajaxUrl, {
214 method: 'POST',
215 body: new URLSearchParams({
216 action: 'process_import_images',
217 nonce: kingAddonsData.nonce
218 })
219 })
220 .then(response => {
221 if (!response.ok) {
222 // The server returned a 4xx or 5xx, read the text and throw an error
223 return response.text().then(html => {
224 console.error('Server error:\n' + html);
225 throw new Error('Server error:\n' + html);
226 });
227 }
228 // If ok, parse JSON
229 return response.json();
230 })
231 .then(data => {
232 if (data.success) {
233 if (data.data.progress !== undefined) {
234
235 let progressBar = document.getElementById('progress-bar');
236 let progress = data.data.progress;
237 progressBar.style.width = progress + '%';
238 progressBar.innerText = progress + '%';
239
240 document.getElementById('progress').innerText = data.data.message;
241
242 let imageUrlElement = document.querySelector('li[data-url="' + data.data.image_url + '"]');
243 if (imageUrlElement) {
244 imageUrlElement.innerHTML += ' - done';
245 }
246 currentRetry = 0;
247 retryTimeout = 1000;
248 processNextImage();
249 } else {
250 // Both templates and sections from main admin catalog create new pages
251 document.getElementById('final_response').innerText = data.data.message;
252 document.getElementById('progress').innerText = 'Import completed.';
253 document.getElementById('progress-bar').style.width = '100%';
254 document.getElementById('progress-bar').innerText = '100%';
255 let goToPage = $('#go-to-imported-page');
256 goToPage.attr('href', data.data.page_url);
257 goToPage.fadeIn();
258 $('#close-installing-popup').fadeIn();
259 }
260 } else {
261 console.error('Process image issue:', data);
262 // Skip image
263 if (data.data && data.data.retry) {
264 processNextImage();
265 }
266 }
267 })
268 .catch(error => {
269 console.error('Catch Error:', error);
270 if (currentRetry < maxRetries) {
271 currentRetry++;
272 retryTimeout *= 2;
273 setTimeout(attemptProcessImage, retryTimeout);
274 } else {
275 let imageUrlElement = document.querySelector('li[data-url="unknown"]');
276 if (imageUrlElement) {
277 imageUrlElement.innerHTML += ' - SKIPPED';
278 }
279 console.error('Error:', error);
280 document.getElementById('final_response').innerText = 'Error: ' + error.message;
281 currentRetry = 0;
282 retryTimeout = 1000;
283 processNextImage();
284 }
285 });
286 }
287
288 attemptProcessImage();
289 }
290
291 $(document).on('click', '.pagination a', function (e) {
292 e.preventDefault();
293 let page = $(this).attr('href').split('paged=')[1];
294 filterTemplates(page);
295 });
296
297 let templateSearch = $('#template-search');
298 let templateCategory = $('#template-category');
299 let templateCollection = $('#template-collection');
300
301 function filterTemplates(page = 1) {
302 let searchQuery = templateSearch.val().toLowerCase();
303 let selectedCategory = templateCategory.val();
304 let selectedCollection = templateCollection.val();
305 let selectedTags = [];
306
307 $('#template-tags input:checked').each(function () {
308 selectedTags.push($(this).val());
309 });
310
311 $.ajax({
312 url: kingAddonsData.ajaxUrl,
313 type: 'POST',
314 data: {
315 action: 'filter_templates',
316 s: searchQuery,
317 category: selectedCategory,
318 collection: selectedCollection,
319 tags: selectedTags.join(','),
320 paged: page
321 },
322 success: function (response) {
323 if (response.success) {
324
325 // Scroll to top after the new content is loaded with admin bar offset
326 const scrollOffset = $('#king-addons-templates-top').offset().top - 32; // Subtract 32px for admin bar
327 $('html, body').animate({scrollTop: scrollOffset}, 0);
328
329 $('.templates-grid').html(response.data.grid_html);
330 $('.pagination').html(response.data.pagination_html);
331 } else {
332 alert('Error: ' + response.data);
333 }
334 },
335 error: function (xhr, status, error) {
336 console.error('AJAX Error: ', status, error);
337 }
338 });
339 }
340
341 templateSearch.on('keyup', function () {
342 templateCategory.val('');
343 templateCollection.val('');
344 $('#template-tags input:checked').prop('checked', false);
345 filterTemplates();
346 });
347
348 templateCategory.on('change', function () {
349 templateSearch.val('');
350 templateCollection.val('');
351 $('#template-tags input:checked').prop('checked', false);
352 filterTemplates();
353 });
354
355 templateCollection.on('change', function () {
356 templateSearch.val('');
357 templateCategory.val('');
358 $('#template-tags input:checked').prop('checked', false);
359 filterTemplates();
360 });
361
362 $('#template-tags input').on('change', function () {
363 templateSearch.val('');
364 templateCategory.val('');
365 templateCollection.val('');
366 if ($(this).is(':checked')) {
367 $('#template-tags input').not(this).prop('checked', false);
368 }
369 filterTemplates();
370 });
371
372 $('#reset-filters').on('click', function () {
373 templateSearch.val('');
374 templateCategory.val('');
375 templateCollection.val('');
376 $('#template-tags input:checked').prop('checked', false);
377 filterTemplates();
378 });
379
380 // Load sections count on page load
381 if ($('#sections-count').length) {
382 loadSectionsCount();
383 }
384
385 // ===== TABS FUNCTIONALITY =====
386
387 // Tab switching
388 $('.king-addons-tab-button').on('click', function() {
389 var tabId = $(this).data('tab');
390
391 // Remove active class from all tabs and content
392 $('.king-addons-tab-button').removeClass('active');
393 $('.king-addons-tab-content').removeClass('active');
394
395 // Add active class to clicked tab and corresponding content
396 $(this).addClass('active');
397 $('#' + tabId + '-catalog').addClass('active');
398
399 // Load sections on first visit to sections tab
400 if (tabId === 'sections' && !window.sectionsLoaded) {
401 loadSections();
402 }
403
404 // Collections: List View only
405 if (tabId === 'collections') {
406 $('#collection-details-view').hide();
407 $('.collections-toolbar').show();
408 $('.collections-rows-wrapper').show();
409 if (!window.collectionRowsLoaded) {
410 loadCollectionRows(1);
411 }
412 }
413 });
414
415 // ===== COLLECTIONS FUNCTIONALITY =====
416
417 function openCollectionDetails(collectionId) {
418 if (!collectionId) return;
419
420 $('.collections-toolbar').hide();
421 $('.collections-rows-wrapper').hide();
422 $('#collection-details-view').show();
423 $('.collection-details-content').html('<div class="collection-loading">Loading collection...</div>');
424 $('#collection-search').val('');
425
426 $.ajax({
427 url: window.kingAddonsData.ajaxUrl,
428 type: 'POST',
429 data: {
430 action: 'king_addons_get_collection_details',
431 nonce: window.kingAddonsData.nonce || '',
432 collection_id: collectionId
433 },
434 success: function(response) {
435 if (response.success) {
436 var data = response.data;
437 var html = '';
438
439 if (data.templates_count > 0) {
440 html += '<div class="collection-section-title"><h3>Templates (' + data.templates_count + ')</h3></div>';
441 html += '<div class="templates-grid collection-templates-grid">' + data.templates_html + '</div>';
442 }
443
444 if (data.sections_count > 0) {
445 html += '<div class="collection-section-title"><h3>Sections (' + data.sections_count + ')</h3></div>';
446 html += '<div class="sections-grid collection-sections-grid">' + data.sections_html + '</div>';
447 }
448
449 if (data.templates_count === 0 && data.sections_count === 0) {
450 html = '<div class="collection-empty">No items found in this collection.</div>';
451 }
452
453 $('.collection-details-content').html(html);
454 } else {
455 $('.collection-details-content').html('<div class="collection-error">Error loading collection: ' + (response.data || 'Unknown error') + '</div>');
456 }
457 },
458 error: function() {
459 $('.collection-details-content').html('<div class="collection-error">Failed to load collection. Please try again.</div>');
460 }
461 });
462 }
463
464 // (Optional) If legacy grid cards ever exist, keep them working.
465 $(document).on('click', '.ka-collection-card', function () {
466 openCollectionDetails($(this).data('collection-id') || '');
467 });
468
469 // Back button
470 $(document).on('click', '.ka-back-button', function() {
471 $('#collection-details-view').hide();
472 $('.collections-toolbar').show();
473 $('.collections-rows-wrapper').fadeIn();
474 });
475
476 // Search in collection
477 $(document).on('keyup', '#collection-search', function() {
478 var value = $(this).val().toLowerCase();
479
480 // Filter templates
481 $('.collection-templates-grid .template-item').filter(function() {
482 $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
483 });
484
485 // Filter sections
486 $('.collection-sections-grid .section-item').filter(function() {
487 $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
488 });
489 });
490
491 // ===== SECTIONS FUNCTIONALITY =====
492
493 window.sectionsLoaded = false;
494 window.sectionsData = null;
495 window.sectionsPage = 1;
496 window.sectionsFilters = {};
497
498 function loadSections(page = 1) {
499 if (!window.kingAddonsData || !window.kingAddonsData.ajaxUrl) {
500 console.error('King Addons data not available');
501 return;
502 }
503
504 var searchQuery = $('#sections-search').val() || '';
505 var selectedCategory = $('#sections-category').val() || '';
506 var selectedType = $('#sections-type').val() || '';
507 var selectedPlan = $('#sections-plan').val() || '';
508
509 $('.sections-grid').html(`
510 <div class="sections-loading">
511 Loading sections...
512 </div>
513 `);
514
515 $.ajax({
516 url: window.kingAddonsData.ajaxUrl,
517 type: 'POST',
518 data: {
519 action: 'king_addons_get_sections_catalog',
520 nonce: window.kingAddonsData.nonce || '',
521 search: searchQuery,
522 category: selectedCategory,
523 section_type: selectedType,
524 plan: selectedPlan,
525 page: page
526 },
527 success: function(response) {
528 if (response.success) {
529 // Scroll to top after new content is loaded with admin bar offset (same as templates)
530 const scrollOffset = $('#king-addons-templates-top').offset().top - 32; // Subtract 32px for admin bar
531 $('html, body').animate({scrollTop: scrollOffset}, 0);
532
533 window.sectionsData = response.data;
534 window.sectionsLoaded = true;
535 renderSections();
536 updateSectionsFilters();
537 updateSectionsCount();
538 } else {
539 $('.sections-grid').html(`
540 <div class="sections-loading">
541 Error loading sections: ${response.data || 'Unknown error'}
542 </div>
543 `);
544 }
545 },
546 error: function(xhr, status, error) {
547 console.error('AJAX Error loading sections:', status, error);
548 $('.sections-grid').html(`
549 <div class="sections-loading">
550 Failed to load sections. Please try again.
551 </div>
552 `);
553 }
554 });
555 }
556
557 function renderSections() {
558 if (!window.sectionsData || !window.sectionsData.sections) {
559 $('.sections-grid').html(`
560 <div class="sections-loading">
561 <p>No sections found. Try adjusting your search or filters to find more sections.</p>
562 </div>
563 `);
564 return;
565 }
566
567 var sectionsHtml = '';
568 var sections = window.sectionsData.sections;
569
570 sections.forEach(function(section) {
571 // Use the correct screenshot URL pattern with plan-based paths
572 var screenshotUrl = `https://thumbnails.kingaddons.com/sections/${section.plan}/${section.section_key}.png?v=4`;
573
574 sectionsHtml += `
575 <div class="section-item"
576 data-section-key="${section.section_key}"
577 data-section-plan="${section.plan}"
578 data-category="${section.category || ''}"
579 data-tags="${(section.tags || []).join(',')}"
580 data-section-type="${section.section_type || ''}">
581 <div class="section-preview">
582 <img src="${screenshotUrl}"
583 alt="${section.title}"
584 loading="lazy"
585 onerror="this.src='data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAwIiBoZWlnaHQ9IjE4MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImciIHgxPSIwJSIgeTE9IjAlIiB4Mj0iMTAwJSIgeTI9IjEwMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiNmOGY5ZmEiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNlNWU3ZWIiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2cpIi8+PGNpcmNsZSBjeD0iMTUwIiBjeT0iNzAiIHI9IjE2IiBmaWxsPSIjOWNhM2FmIiBvcGFjaXR5PSIwLjQiLz48cmVjdCB4PSIxMzQiIHk9Ijg2IiB3aWR0aD0iMzIiIGhlaWdodD0iNCIgZmlsbD0iIzljYTNhZiIgb3BhY2l0eT0iMC40IiByeD0iMiIvPjxyZWN0IHg9IjEyNiIgeT0iOTQiIHdpZHRoPSI0OCIgaGVpZ2h0PSI0IiBmaWxsPSIjOWNhM2FmIiBvcGFjaXR5PSIwLjMiIHJ4PSIyIi8+PHRleHQgeD0iNTAlIiB5PSIxMjAiIGZvbnQtZmFtaWx5PSItYXBwbGUtc3lzdGVtLCBCbGlua01hY1N5c3RlbUZvbnQsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGZpbGw9IiM2Yjc1ODQiIHRleHQtYW5jaG9yPSJtaWRkbGUiIG9wYWNpdHk9IjAuNyI+U2VjdGlvbiBQcmV2aWV3PC90ZXh0Pjwvc3ZnPg=='">
586 <div class="section-actions">
587 <button class="import-section-btn" data-section-key="${section.section_key}" data-section-plan="${section.plan}">
588 <i class="eicon-file-download"></i> Import
589 </button>
590 <a href="https://sections.kingaddons.com/${section.section_key}" class="live-preview-btn" target="_blank">
591 <i class="eicon-preview-medium"></i> Live Preview
592 </a>
593 </div>
594 ${section.plan === 'premium' ? '<span class="section-badge-pro">PRO</span>' : ''}
595 </div>
596 <div class="section-info">
597 <h4>${section.title}</h4>
598 </div>
599 </div>
600 `;
601 });
602
603 $('.sections-grid').html(sectionsHtml);
604
605 // Render pagination if available
606 if (window.sectionsData.pagination) {
607 renderSectionsPagination();
608 }
609 }
610
611
612
613 function renderSectionsPagination() {
614 var pagination = window.sectionsData.pagination;
615 var paginationHtml = '';
616
617 if (pagination.total_pages > 1) {
618 paginationHtml += '<div class="pagination-inner">';
619
620 var current = pagination.current_page;
621 var total = pagination.total_pages;
622 var endSize = 3; // Show 3 pages at beginning and end
623 var midSize = 2; // Show 2 pages around current
624
625 // Previous page
626 if (current > 1) {
627 paginationHtml += `<a class="page-numbers" href="#" data-page="${current - 1}">&larr; Previous</a>`;
628 }
629
630 // Smart pagination logic with proper ellipsis
631 var pages = [];
632
633 // Always show first pages
634 for (var i = 1; i <= Math.min(endSize, total); i++) {
635 pages.push(i);
636 }
637
638 // Calculate middle range around current page
639 var start = Math.max(current - midSize, 1);
640 var end = Math.min(current + midSize, total);
641
642 // Add first ellipsis if there's a gap
643 if (start > endSize + 1) {
644 pages.push('...');
645 }
646
647 // Add middle pages around current (avoid duplicates with start/end)
648 for (var i = Math.max(start, endSize + 1); i <= Math.min(end, total - endSize); i++) {
649 if (pages.indexOf(i) === -1) {
650 pages.push(i);
651 }
652 }
653
654 // Add second ellipsis if there's a gap
655 if (end < total - endSize) {
656 pages.push('...');
657 }
658
659 // Always show last pages (avoid duplicates)
660 for (var i = Math.max(total - endSize + 1, endSize + 1); i <= total; i++) {
661 if (pages.indexOf(i) === -1) {
662 pages.push(i);
663 }
664 }
665
666 // Render pages
667 pages.forEach(function(page) {
668 if (page === '...') {
669 paginationHtml += `<span class="page-numbers dots">…</span>`;
670 } else if (page === current) {
671 paginationHtml += `<span class="page-numbers current">${page}</span>`;
672 } else {
673 paginationHtml += `<a class="page-numbers" href="#" data-page="${page}">${page}</a>`;
674 }
675 });
676
677 // Next page
678 if (current < total) {
679 paginationHtml += `<a class="page-numbers" href="#" data-page="${current + 1}">Next &rarr;</a>`;
680 }
681
682 paginationHtml += '</div>';
683 }
684
685 $('.sections-pagination').html(paginationHtml);
686 }
687
688 function updateSectionsFilters() {
689 if (!window.sectionsData) return;
690
691 // Update categories dropdown
692 var categoriesHtml = '<option value="">All Categories</option>';
693 if (window.sectionsData.categories) {
694 window.sectionsData.categories.forEach(function(category) {
695 var displayName = category.charAt(0).toUpperCase() + category.slice(1).replace(/-/g, ' ');
696 categoriesHtml += `<option value="${category}">${displayName}</option>`;
697 });
698 }
699 $('#sections-category').html(categoriesHtml);
700
701 // Update types dropdown
702 var typesHtml = '<option value="">All Types</option>';
703 if (window.sectionsData.section_types) {
704 window.sectionsData.section_types.forEach(function(type) {
705 var displayName = type.charAt(0).toUpperCase() + type.slice(1).replace(/-/g, ' ');
706 typesHtml += `<option value="${type}">${displayName}</option>`;
707 });
708 }
709 $('#sections-type').html(typesHtml);
710 }
711
712 function updateSectionsCount() {
713 if (window.sectionsData && window.sectionsData.pagination) {
714 $('#sections-count').text(window.sectionsData.pagination.total_sections);
715 }
716 }
717
718 // Sections filters event handlers - Same logic as templates
719 var sectionsSearch = $('#sections-search');
720 var sectionsCategory = $('#sections-category');
721 var sectionsType = $('#sections-type');
722 var sectionsPlan = $('#sections-plan');
723
724 sectionsSearch.on('keyup', function() {
725 // Reset other filters when searching (same as templates)
726 sectionsCategory.val('');
727 sectionsType.val('');
728 sectionsPlan.val('');
729
730 clearTimeout(window.sectionsSearchTimeout);
731 window.sectionsSearchTimeout = setTimeout(function() {
732 loadSections(1);
733 }, 500);
734 });
735
736 sectionsCategory.on('change', function() {
737 // Reset search and other filters (same as templates)
738 sectionsSearch.val('');
739 sectionsType.val('');
740 sectionsPlan.val('');
741 loadSections(1);
742 });
743
744 sectionsType.on('change', function() {
745 // Reset search and other filters (same as templates)
746 sectionsSearch.val('');
747 sectionsCategory.val('');
748 sectionsPlan.val('');
749 loadSections(1);
750 });
751
752 sectionsPlan.on('change', function() {
753 // Reset search and other filters (same as templates)
754 sectionsSearch.val('');
755 sectionsCategory.val('');
756 sectionsType.val('');
757 loadSections(1);
758 });
759
760 $('#sections-reset-filters').on('click', function() {
761 sectionsSearch.val('');
762 sectionsCategory.val('');
763 sectionsType.val('');
764 sectionsPlan.val('');
765 loadSections(1);
766 });
767
768 // Sections pagination handler
769 $(document).on('click', '.sections-pagination .page-numbers', function(e) {
770 e.preventDefault();
771 var page = $(this).data('page');
772 if (page) {
773 loadSections(page);
774 }
775 });
776
777 // Section Import Popup Logic
778 let pendingSectionImport = null;
779
780 // Open Import Popup
781 $(document).on('click', '.import-section-btn', function(e) {
782 e.preventDefault();
783 e.stopPropagation();
784
785 let sectionKey = $(this).data('section-key');
786 let sectionPlan = $(this).data('section-plan');
787 let sectionTitle = $(this).closest('.section-item').find('h4').text();
788
789 // Check premium
790 let planActive = $('#install-template').attr('data-plan-active');
791 if (sectionPlan === 'premium' && planActive !== 'premium') {
792 $('#templates-catalog').addClass('kng-whole-overlay');
793 $('#premium-promo-popup').fadeIn();
794 return;
795 }
796
797 // Store pending import data
798 pendingSectionImport = {
799 key: sectionKey,
800 plan: sectionPlan
801 };
802
803 // Populate and show popup
804 $('#popup-section-name').text(sectionTitle);
805 $('#popup-section-plan').text(sectionPlan.charAt(0).toUpperCase() + sectionPlan.slice(1));
806 $('#section-import-popup').css('display', 'flex').hide().fadeIn(10, function() {
807 $(this).addClass('active');
808 });
809 });
810
811 // Live Preview Button - Stop Propagation
812 $(document).on('click', '.live-preview-btn', function(e) {
813 e.stopPropagation();
814 });
815
816 // Close Popup
817 function closeSectionPopup() {
818 $('#section-import-popup').removeClass('active');
819 setTimeout(function() {
820 $('#section-import-popup').fadeOut();
821 }, 300);
822 pendingSectionImport = null;
823 }
824
825 $(document).on('click', '#close-section-popup, #cancel-section-import', function(e) {
826 e.preventDefault();
827 closeSectionPopup();
828 });
829
830 // Confirm Import
831 $(document).on('click', '#confirm-section-import', function(e) {
832 e.preventDefault();
833 if (pendingSectionImport) {
834 importSection(pendingSectionImport.key, pendingSectionImport.plan);
835 closeSectionPopup();
836 }
837 });
838
839 // Close on click outside
840 $(document).on('click', '#section-import-popup', function(e) {
841 if ($(e.target).is('#section-import-popup')) {
842 closeSectionPopup();
843 }
844 });
845
846 // Section item click handler - now only for general clicks (not on buttons)
847 $(document).on('click', '.section-item', function(e) {
848 // Don't trigger if clicking on buttons or overlay
849 if ($(e.target).closest('.section-overlay, .import-section-btn, .live-preview-btn').length) {
850 return;
851 }
852
853 var sectionKey = $(this).data('section-key');
854 var sectionPlan = $(this).data('section-plan');
855 var sectionTitle = $(this).find('h4').text();
856
857 // Check if this is a premium section and user doesn't have premium
858 var planActive = $('#install-template').attr('data-plan-active');
859
860 if (sectionPlan === 'premium' && planActive !== 'premium') {
861 // Show premium promo popup
862 $('#templates-catalog').addClass('kng-whole-overlay');
863 $('#premium-promo-popup').fadeIn();
864 return;
865 }
866
867 // Open the custom popup instead of confirm()
868 pendingSectionImport = {
869 key: sectionKey,
870 plan: sectionPlan
871 };
872
873 $('#popup-section-name').text(sectionTitle);
874 $('#popup-section-plan').text(sectionPlan.charAt(0).toUpperCase() + sectionPlan.slice(1));
875 $('#section-import-popup').css('display', 'flex').hide().fadeIn(10, function() {
876 $(this).addClass('active');
877 });
878 });
879
880 // Function to import section from main catalog
881 function importSection(sectionKey, sectionPlan) {
882 // Show importing popup
883 $('#templates-catalog').addClass('kng-whole-overlay');
884 $('#template-installing-popup').fadeIn();
885
886 // Initialize progress
887 document.getElementById('progress').innerText = 'Loading section data...';
888 document.getElementById('progress-bar').style.width = '5%';
889 document.getElementById('progress-bar').innerText = '5%';
890
891 // Get section data
892 $.ajax({
893 url: window.kingAddonsData.ajaxUrl,
894 type: 'POST',
895 data: {
896 action: 'king_addons_import_section_admin',
897 nonce: window.kingAddonsData.nonce,
898 section_key: sectionKey,
899 section_plan: sectionPlan
900 },
901 success: function(response) {
902 if (response.success) {
903 var sectionData = response.data.section_data;
904 var imageCount = sectionData.images ? sectionData.images.length : 0;
905
906 document.getElementById('progress').innerText = 'Section loaded! Found ' + imageCount + ' images to process...';
907 document.getElementById('progress-bar').style.width = '25%';
908 document.getElementById('progress-bar').innerText = '25%';
909
910 // Process section import (use existing system)
911 processSectionImport(sectionData);
912 } else {
913 document.getElementById('progress').innerText = 'Error: ' + (response.data || 'Failed to load section');
914 $('#close-installing-popup').fadeIn();
915 }
916 },
917 error: function(xhr, status, error) {
918 document.getElementById('progress').innerText = 'Network error: ' + error;
919 $('#close-installing-popup').fadeIn();
920 }
921 });
922 }
923
924 // Process section import using existing Templates system
925 function processSectionImport(sectionData) {
926 document.getElementById('progress').innerText = 'Preparing section import...';
927 document.getElementById('progress-bar').style.width = '45%';
928 document.getElementById('progress-bar').innerText = '45%';
929
930 // Use existing Templates import system
931 var importData = {
932 content: sectionData.content,
933 images: sectionData.images || [],
934 title: sectionData.title || 'Imported Section',
935 elementor_version: sectionData.elementor_version || '3.0.0',
936 existing_page_id: 0,
937 create_new_page: true // Create new page for sections from main admin catalog
938 };
939
940 // Call Templates import system
941 $.ajax({
942 url: window.kingAddonsData.ajaxUrl,
943 type: 'POST',
944 data: {
945 action: 'import_elementor_page_with_images',
946 nonce: window.kingAddonsData.nonce,
947 data: JSON.stringify(importData)
948 },
949 success: function(result) {
950 if (result.success) {
951 document.getElementById('progress').innerText = 'Section import initialized! Processing images...';
952 document.getElementById('progress-bar').style.width = '65%';
953 document.getElementById('progress-bar').innerText = '65%';
954
955 // Start processing images using existing system
956 processNextImage();
957 } else {
958 document.getElementById('progress').innerText = 'Error: ' + (result.data || 'Failed to initialize section import');
959 $('#close-installing-popup').fadeIn();
960 }
961 },
962 error: function(xhr, status, error) {
963 document.getElementById('progress').innerText = 'Import error: ' + error;
964 $('#close-installing-popup').fadeIn();
965 }
966 });
967 }
968
969 // Load sections count for tab
970 function loadSectionsCount() {
971 $.ajax({
972 url: window.kingAddonsData.ajaxUrl,
973 type: 'POST',
974 data: {
975 action: 'king_addons_get_sections_catalog',
976 nonce: window.kingAddonsData.nonce || '',
977 search: '',
978 category: '',
979 section_type: '',
980 plan: '',
981 page: 1
982 },
983 success: function(response) {
984 if (response.success && response.data.pagination) {
985 $('#sections-count').text(response.data.pagination.total_sections);
986 }
987 },
988 error: function(xhr, status, error) {
989 console.log('Failed to load sections count:', error);
990 }
991 });
992 }
993
994 // ===== COLLECTIONS (LIST VIEW ONLY) =====
995
996 window.collectionRowsLoaded = false;
997 window.collectionRowsData = null;
998 window.collectionRowsPage = 1;
999 window.collectionRowsSearch = '';
1000
1001 function loadCollectionRows(page = 1) {
1002 $('.collections-rows-container').html('<div class="collections-loading">Loading collections...</div>');
1003 window.collectionRowsPage = page;
1004
1005 $.ajax({
1006 url: window.kingAddonsData.ajaxUrl,
1007 type: 'POST',
1008 data: {
1009 action: 'king_addons_get_collections_rows',
1010 nonce: window.kingAddonsData.nonce || '',
1011 page: page,
1012 search: window.collectionRowsSearch || ''
1013 },
1014 success: function(response) {
1015 if (response.success) {
1016 window.collectionRowsData = response.data;
1017 window.collectionRowsLoaded = true;
1018 renderCollectionRows();
1019 } else {
1020 $('.collections-rows-container').html('<div class="collections-error">Error loading collections.</div>');
1021 }
1022 },
1023 error: function() {
1024 $('.collections-rows-container').html('<div class="collections-error">Failed to load collections.</div>');
1025 }
1026 });
1027 }
1028
1029 function renderCollectionRows() {
1030 if (!window.collectionRowsData || !window.collectionRowsData.collections) {
1031 $('.collections-rows-container').html('<div class="collections-empty">No collections found.</div>');
1032 return;
1033 }
1034
1035 var html = '';
1036 var collections = window.collectionRowsData.collections;
1037
1038 collections.forEach(function(collection) {
1039 if (collection.templates.length === 0) return; // Skip empty collections
1040
1041 var templatesCount = collection.templates_count || 0;
1042 var sectionsCount = collection.sections_count || 0;
1043
1044 html += `
1045 <div class="collection-row">
1046 <div class="collection-row-header">
1047 <div class="collection-row-title-wrap">
1048 <h3 class="collection-row-title">${collection.name}</h3>
1049 <div class="collection-row-counts">
1050 <span class="collection-row-count" title="Templates">
1051 <i class="eicon-document-file"></i> ${templatesCount}
1052 </span>
1053 <span class="collection-row-count" title="Sections">
1054 <i class="eicon-section"></i> ${sectionsCount}
1055 </span>
1056 </div>
1057 </div>
1058 <a href="#" class="collection-row-view-all" data-collection-id="${collection.id}">
1059 View All <i class="eicon-arrow-right"></i>
1060 </a>
1061 </div>
1062 <div class="collection-row-scroll-wrap">
1063 <div class="collection-row-scroll">
1064 `;
1065
1066 collection.templates.forEach(function(template) {
1067 var thumbUrl = `https://thumbnails.kingaddons.com/${template.key}.png?v=4`;
1068 html += `
1069 <div class="collection-row-item template-item"
1070 data-template-key="${template.key}"
1071 data-template-plan="${template.plan}">
1072 <img src="${thumbUrl}" alt="${template.title}" loading="lazy">
1073 <div class="collection-row-item-info">
1074 <h4 class="collection-row-item-title">${template.title}</h4>
1075 <div class="collection-row-item-meta">
1076 <span class="template-plan template-plan-${template.plan}">${template.plan}</span>
1077 </div>
1078 </div>
1079 </div>
1080 `;
1081 });
1082
1083 html += `
1084 </div>
1085 </div>
1086 </div>
1087 `;
1088 });
1089
1090 if (!html || html.trim() === '') {
1091 $('.collections-rows-container').html('<div class="collection-row-empty">No collections found.</div>');
1092 $('.collections-rows-pagination').html('');
1093 return;
1094 }
1095
1096 $('.collections-rows-container').html(html);
1097
1098 // Render Pagination
1099 var pagination = window.collectionRowsData.pagination;
1100 var paginationHtml = '';
1101
1102 if (pagination && pagination.pages > 1) {
1103 paginationHtml += '<div class="pagination-inner">';
1104
1105 // Previous
1106 if (pagination.current > 1) {
1107 paginationHtml += `<a class="page-numbers collection-rows-page" href="#" data-page="${pagination.current - 1}"><i class="eicon-chevron-left"></i></a>`;
1108 }
1109
1110 // Smart Pagination Logic (1 2 3 ... 10)
1111 var startPage = Math.max(1, pagination.current - 2);
1112 var endPage = Math.min(pagination.pages, pagination.current + 2);
1113
1114 if (startPage > 1) {
1115 paginationHtml += `<a class="page-numbers collection-rows-page" href="#" data-page="1">1</a>`;
1116 if (startPage > 2) {
1117 paginationHtml += `<span class="page-numbers dots">...</span>`;
1118 }
1119 }
1120
1121 for (var i = startPage; i <= endPage; i++) {
1122 if (i === pagination.current) {
1123 paginationHtml += `<span class="page-numbers current">${i}</span>`;
1124 } else {
1125 paginationHtml += `<a class="page-numbers collection-rows-page" href="#" data-page="${i}">${i}</a>`;
1126 }
1127 }
1128
1129 if (endPage < pagination.pages) {
1130 if (endPage < pagination.pages - 1) {
1131 paginationHtml += `<span class="page-numbers dots">...</span>`;
1132 }
1133 paginationHtml += `<a class="page-numbers collection-rows-page" href="#" data-page="${pagination.pages}">${pagination.pages}</a>`;
1134 }
1135
1136 // Next
1137 if (pagination.current < pagination.pages) {
1138 paginationHtml += `<a class="page-numbers collection-rows-page" href="#" data-page="${pagination.current + 1}"><i class="eicon-chevron-right"></i></a>`;
1139 }
1140
1141 paginationHtml += '</div>';
1142 }
1143
1144 $('.collections-rows-pagination').html(paginationHtml);
1145
1146 // Handle pagination click
1147 $('.collection-rows-page').off('click').on('click', function(e) {
1148 e.preventDefault();
1149 var page = $(this).data('page');
1150 loadCollectionRows(page);
1151 $('html, body').animate({scrollTop: $('#collections-catalog').offset().top - 50}, 500);
1152 });
1153
1154 // Handle "View All" click to switch to details view
1155 $('.collection-row-view-all').off('click').on('click', function(e) {
1156 e.preventDefault();
1157 var collectionId = $(this).data('collection-id');
1158 openCollectionDetails(collectionId);
1159 });
1160 }
1161
1162 // Collections search (List View)
1163 var collectionsSearchTimer = null;
1164 $(document).on('input', '#collections-search', function() {
1165 var value = $(this).val() || '';
1166 window.collectionRowsSearch = value;
1167 clearTimeout(collectionsSearchTimer);
1168 collectionsSearchTimer = setTimeout(function() {
1169 window.collectionRowsLoaded = false;
1170 loadCollectionRows(1);
1171 }, 250);
1172 });
1173 });
1174
1175