PluginProbe
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder / 51.1.83
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder v51.1.83
51.1.84 51.1.85 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 All 39 releases
← All changes | includes/admin/js/templates.js +1174 -0 51.1.251.1.83 View file →
@@ -1,0 +1,1174 @@
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 +