PluginProbe ʕ •ᴥ•ʔ
Spider Elements – Premium Elementor Widgets & Addons Library / trunk
Spider Elements – Premium Elementor Widgets & Addons Library vtrunk
trunk 1.0.0 1.1.0 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.7.0 1.8.0 1.9.0
spider-elements / assets / js / admin.js
spider-elements / assets / js Last commit date
admin.js 5 months ago elementor-widgets.js 7 months ago
admin.js
564 lines
1 ; (function ($) {
2
3 "use strict";
4
5 // ===== Toast Notification System =====
6 window.SpelToast = {
7 show: function (title, message, type = 'success') {
8 // Remove existing toasts
9 $('.spel_toast').remove();
10
11 const iconClass = type === 'success' ? 'icon-check' : 'icon-close';
12 const toast = $(`
13 <div class="spel_toast ${type === 'error' ? 'toast_error' : ''}">
14 <span class="toast_icon"><i class="${iconClass}"></i></span>
15 <div class="toast_content">
16 <h4>${title}</h4>
17 <p>${message}</p>
18 </div>
19 <span class="toast_close"><i class="icon-close"></i></span>
20 </div>
21 `);
22
23 $('body').append(toast);
24
25 // Show toast
26 setTimeout(() => toast.addClass('show'), 100);
27
28 // Auto-hide after 4 seconds
29 setTimeout(() => {
30 toast.removeClass('show');
31 setTimeout(() => toast.remove(), 300);
32 }, 4000);
33
34 // Close button
35 toast.find('.toast_close').on('click', function () {
36 toast.removeClass('show');
37 setTimeout(() => toast.remove(), 300);
38 });
39 }
40 };
41
42 // ===== Search Functionality =====
43 function initSearchFunctionality() {
44 // Widget Search
45 $('#spel_widget_search').on('input', function () {
46 const searchTerm = $(this).val().toLowerCase().trim();
47 const $items = $('#elements_list .ezd-colum-space-4');
48 let visibleCount = 0;
49
50 $items.each(function () {
51 const widgetName = $(this).data('widget-name') || '';
52 const isMatch = widgetName.includes(searchTerm);
53
54 if (isMatch || searchTerm === '') {
55 $(this).show().css('opacity', '1');
56 visibleCount++;
57 } else {
58 $(this).hide().css('opacity', '0');
59 }
60 });
61
62 // Update count
63 const totalWidgets = $items.length;
64 const countText = searchTerm
65 ? `${visibleCount} of ${totalWidgets} widgets`
66 : `${totalWidgets} widgets`;
67 $('#spel_search_count').text(countText);
68
69 // Re-apply isotope layout
70 $('#elements_list').isotope('layout');
71 });
72
73 // Feature Search
74 $('#spel_feature_search').on('input', function () {
75 const searchTerm = $(this).val().toLowerCase().trim();
76 const $items = $('#features_gallery .ezd-colum-space-4');
77 let visibleCount = 0;
78
79 $items.each(function () {
80 const featureName = $(this).data('feature-name') || '';
81 const isMatch = featureName.includes(searchTerm);
82
83 if (isMatch || searchTerm === '') {
84 $(this).show().css('opacity', '1');
85 visibleCount++;
86 } else {
87 $(this).hide().css('opacity', '0');
88 }
89 });
90
91 // Update count
92 const totalFeatures = $items.length;
93 const countText = searchTerm
94 ? `${visibleCount} of ${totalFeatures} features`
95 : `${totalFeatures} features`;
96 $('#spel_feature_search_count').text(countText);
97
98 // Re-apply isotope layout
99 $('#features_gallery').isotope('layout');
100 });
101 }
102
103 // Remove svg.radial-progress .complete inline styling
104 $("svg.radial-progress").each(function (index, value) {
105 $(this).find($("circle.complete")).removeAttr("style");
106 });
107
108 $(window).scroll(function () {
109 $("svg.radial-progress").each(function (index, value) {
110 // If svg.radial-progress is approximately 25% vertically into the window when scrolling from the top or the bottom
111 if (
112 $(window).scrollTop() >
113 $(this).offset().top - $(window).height() * 0.75 &&
114 $(window).scrollTop() <
115 $(this).offset().top + $(this).height() - $(window).height() * 0.25
116 ) {
117 // Get percentage of progress
118 let percent = $(value).data("percentage");
119
120 // Get radius of the svg's circle.complete
121 let radius = $(this).find($("circle.complete")).attr("r");
122
123 // Get circumference (2πr)
124 let circumference = 2 * Math.PI * radius;
125
126 // Get stroke-dashoffset value based on the percentage of the circumference
127 let strokeDashOffset =
128 circumference - (percent * circumference) / 100;
129
130 // Transition progress for 1.25 seconds
131 $(this).find($("circle.complete")).animate({ "stroke-dashoffset": strokeDashOffset }, 1250);
132 }
133 });
134 })
135 .trigger("scroll");
136
137 // switcher js
138 document.addEventListener("DOMContentLoaded", function () {
139
140 // Handling for element_switcher
141 let elementDisable = document.getElementById("element_disabled"),
142 elementEnable = document.getElementById("element_enabled"),
143 elementSwitcher = document.getElementById("element_switcher");
144
145 if (elementDisable && elementEnable && elementSwitcher) {
146 elementDisable.addEventListener("click", function () {
147 elementSwitcher.checked = false;
148 elementDisable.classList.add("toggler--is-active");
149 elementEnable.classList.remove("toggler--is-active");
150 });
151
152 elementEnable.addEventListener("click", function () {
153 elementSwitcher.checked = true;
154 elementEnable.classList.add("toggler--is-active");
155 elementDisable.classList.remove("toggler--is-active");
156 });
157
158 elementSwitcher.addEventListener("click", function () {
159 elementEnable.classList.toggle("toggler--is-active");
160 elementDisable.classList.toggle("toggler--is-active");
161 });
162 }
163
164 // Handling for feature_switcher
165 let featureDisable = document.getElementById("features_disabled"),
166 featureEnable = document.getElementById("features_enabled"),
167 featureSwitcher = document.getElementById("features_switcher");
168
169 if (featureDisable && featureEnable && featureSwitcher) {
170 featureDisable.addEventListener("click", function () {
171 featureSwitcher.checked = false;
172 featureDisable.classList.add("toggler--is-active");
173 featureEnable.classList.remove("toggler--is-active");
174 });
175
176 featureEnable.addEventListener("click", function () {
177 featureSwitcher.checked = true;
178 featureEnable.classList.add("toggler--is-active");
179 featureDisable.classList.remove("toggler--is-active");
180 });
181
182 featureSwitcher.addEventListener("click", function () {
183 featureEnable.classList.toggle("toggler--is-active");
184 featureDisable.classList.toggle("toggler--is-active");
185 });
186 }
187
188
189 }); // end switcher js
190
191
192 $(document).ready(function () {
193
194 // Initialize search functionality
195 initSearchFunctionality();
196
197 // Map of tab content names to WordPress admin submenu page slugs
198 const tabToSubmenuMap = {
199 'welcome': 'spider_elements_settings',
200 'elements': 'spider_elements_elements',
201 'features': 'spider_elements_features',
202 'integration': 'spider_elements_integration'
203 };
204
205 // LocalStorage key for tab persistence
206 const STORAGE_KEY = 'spel_active_tab';
207
208 // Function to update WordPress admin menu active state
209 function updateAdminMenuActiveState(tabName) {
210 let submenuSlug = tabToSubmenuMap[tabName];
211 if (submenuSlug) {
212 // Remove current class from all Spider Elements submenu items
213 $('#toplevel_page_spider_elements_settings ul.wp-submenu li').removeClass('current');
214
215 // Add current class to the matching submenu item
216 $('#toplevel_page_spider_elements_settings ul.wp-submenu li a[href*="' + submenuSlug + '"]').parent().addClass('current');
217 }
218 }
219
220 // Function to save active tab to localStorage
221 function saveActiveTab(tabName) {
222 try {
223 localStorage.setItem(STORAGE_KEY, tabName);
224 } catch (e) {
225 console.warn('Spider Elements: Could not save tab state to localStorage', e);
226 }
227 }
228
229 // Function to get active tab from localStorage
230 function getActiveTab() {
231 try {
232 return localStorage.getItem(STORAGE_KEY);
233 } catch (e) {
234 console.warn('Spider Elements: Could not read tab state from localStorage', e);
235 return null;
236 }
237 }
238
239 // Set up event listener for tab click
240 $(".tab-menu li a").on("click", function () {
241 $(this).closest(".tab-menu").find("li a").removeClass("active");
242
243 // Add active class to the clicked tab
244 $(this).addClass("active");
245
246 let target = $(this).attr("href");
247 let tabName = $(this).data('content');
248
249 $(".tab-box")
250 .removeClass("active")
251 .fadeOut(0, function () {
252 $(target).addClass("active").fadeIn(0);
253 });
254
255 // Trigger Isotope filtering after the tab is clicked
256 filterMasonry();
257 filterMasonryTwo();
258 filterMasonryThree();
259
260 // Save active tab to localStorage for persistence after page refresh
261 saveActiveTab(tabName);
262
263 // Update WordPress admin menu active state
264 updateAdminMenuActiveState(tabName);
265
266 // Update hidden input field for form submission
267 $('#spel_active_tab').val(tabName);
268
269 // Update form action URL to redirect to the correct submenu after save
270 let submenuSlug = tabToSubmenuMap[tabName];
271 if (submenuSlug) {
272 let newAction = 'admin.php?page=' + submenuSlug;
273 $('#spel_settings').attr('action', newAction);
274 }
275
276 return false;
277 });
278
279 // Remain the last active settings tab after page refresh
280 function spel_keep_settings_current_tab() {
281 // Check if we're on the Spider Elements dashboard page
282 let spelDashboard = $('#spel_settings');
283 if (!spelDashboard.length) {
284 return;
285 }
286
287 // Priority 1: Server-side data-active-tab (URL-based, from WordPress submenu navigation)
288 // This MUST take priority so that clicking a WordPress submenu always
289 // navigates to the correct tab, regardless of what localStorage says.
290 let serverTab = spelDashboard.data('active-tab');
291 let activeTab = serverTab || 'welcome';
292
293 // Clear localStorage to keep it in sync with the current submenu page.
294 // This prevents stale localStorage values from overriding the URL on
295 // subsequent page loads.
296 saveActiveTab(activeTab);
297
298 // Update sidebar tab-menu active state
299 $('.tab-menu .tab-menu-link').removeClass('active');
300 $('.tab-menu .tab-menu-link[data-content="' + activeTab + '"]').addClass('active');
301
302 // Update tab content active state
303 $('.tab_contents .tab-box').removeClass('active');
304 $('.tab_contents .tab-box#' + activeTab).addClass('active');
305
306 // Sync WordPress admin menu active state
307 updateAdminMenuActiveState(activeTab);
308
309 // Update hidden input field
310 $('#spel_active_tab').val(activeTab);
311 }
312
313 spel_keep_settings_current_tab();
314
315 });
316
317 // filter js
318 /*===========elements isotope js===========*/
319 function filterMasonry() {
320 var filter = $("#elements_list");
321 if (filter.length) {
322 filter.imagesLoaded(function () {
323 // images have loaded
324 // Activate isotope in container
325 filter.isotope({
326 itemSelector: ".ezd-colum-space-4",
327 filter: "*",
328 animationOptions: {
329 duration: 750,
330 easing: 'linear',
331 queue: false
332 }
333 });
334 });
335 }
336 }
337
338 $(document).ready(function () {
339 // Initialize Isotope on page load
340 filterMasonry();
341 let filter = $("#elements_list, #features_gallery");
342
343 // Add isotope click function
344 $("#elements_filter div").on("click", function () {
345 $("#elements_filter div").removeClass("active");
346 $(this).addClass("active");
347
348 // Clear search when filter is clicked
349 $('#spel_widget_search').val('');
350 $('#elements_list .ezd-colum-space-4').show().css('opacity', '1');
351
352 let selector = $(this).attr("data-filter");
353 filter.isotope({
354 filter: selector,
355 });
356
357 // Update count
358 const visibleItems = selector === '*'
359 ? $('#elements_list .ezd-colum-space-4').length
360 : $('#elements_list .ezd-colum-space-4' + selector).length;
361 const totalItems = $('#elements_list .ezd-colum-space-4').length;
362 $('#spel_search_count').text(visibleItems + ' widgets');
363
364 return false;
365 });
366 });
367
368 /*===========elements isotope js===========*/
369
370 /*===========api isotope js===========*/
371 function filterMasonryTwo() {
372 var filters = $("#api_setting");
373 if (filters.length) {
374 filters.imagesLoaded(function () {
375 // images have loaded
376 // Activate isotope in container
377 filters.isotope({
378 itemSelector: ".ezd-colum-space-4",
379 filter: "*",
380 });
381 });
382 }
383 }
384
385 $(document).ready(function () {
386 // Initialize Isotope on page load
387 filterMasonryTwo();
388 var filter = $("#api_setting");
389 // Add isotope click function
390 $("#api_filter div").on("click", function () {
391 $("#api_filter div").removeClass("active");
392 $(this).addClass("active");
393
394 var selector = $(this).attr("data-filter");
395 filter.isotope({
396 filter: selector,
397 });
398 return false;
399 });
400 });
401
402 /*===========api isotope js===========*/
403
404 /* ============features isotope js ============*/
405 function filterMasonryThree() {
406 var filter = $("#features_gallery");
407 if (filter.length) {
408 filter.imagesLoaded(function () {
409 // images have loaded
410 // Activate isotope in container
411 filter.isotope({
412 itemSelector: ".ezd-colum-space-4",
413 filter: "*",
414 animationOptions: {
415 duration: 750,
416 easing: 'linear',
417 queue: false
418 }
419 });
420 });
421 }
422 }
423
424 $(document).ready(function () {
425 // Initialize Isotope on page load
426 filterMasonryThree();
427 var filter = $("#features_gallery");
428
429 // Add isotope click function for features
430 $("#features_filter div").on("click", function () {
431 $("#features_filter div").removeClass("active");
432 $(this).addClass("active");
433
434 // Clear search when filter is clicked
435 $('#spel_feature_search').val('');
436 $('#features_gallery .ezd-colum-space-4').show().css('opacity', '1');
437
438 var selector = $(this).attr("data-filter");
439 filter.isotope({
440 filter: selector,
441 });
442
443 // Update count
444 const visibleItems = selector === '*'
445 ? $('#features_gallery .ezd-colum-space-4').length
446 : $('#features_gallery .ezd-colum-space-4' + selector).length;
447 $('#spel_feature_search_count').text(visibleItems + ' features');
448
449 return false;
450 });
451 });
452
453 $(".pro_popup").on("click", function (e) {
454 $("#elements_popup1").addClass("popup-visible");
455 });
456 $(".pro-close").on("click", function (e) {
457 $("#elements_popup1").removeClass("popup-visible");
458 });
459
460 // Close popup on background click
461 $(".elements_pro_popup").on("click", function (e) {
462 if ($(e.target).hasClass('elements_pro_popup')) {
463 $(this).removeClass("popup-visible");
464 }
465 });
466
467 // Close popup on Escape key
468 $(document).on("keyup", function (e) {
469 if (e.key === "Escape") {
470 $(".elements_pro_popup").removeClass("popup-visible");
471 }
472 });
473
474 if ($(".popup_youtube").length) {
475 $(".popup_youtube").fancybox({
476 type: "iframe", //<--added
477 maxWidth: 800,
478 maxHeight: 600,
479 fitToView: false,
480 width: "70%",
481 height: "70%",
482 autoSize: false,
483 closeClick: false,
484 openEffect: "elastic",
485 closeEffect: "elastic",
486 });
487 }
488
489 // Elements list Save Now Button
490 function elementsSaveNowButton() {
491 let elementsList = $(".element_right .widget-list");
492 elementsList.on("click", function () {
493 // Check if the checkbox is checked
494 if ($(this).is(":checked")) {
495 $(".dashboard_btn.save_btn").addClass("save-now");
496 } else {
497 $(".dashboard_btn.save_btn")
498 .removeClass("save-now")
499 .removeAttr("disabled")
500 .css("cursor", "pointer"
501 );
502 }
503 });
504
505 // Global Switcher for all widgets
506 let globalSwitcher = $('.menu_right_content .element_global_switcher, .menu_right_content .features_global_switcher');
507 globalSwitcher.on("click", function () {
508 let status = $(this).prop("checked");
509 let dataId = $(this).data("id");
510 let alignClass = ".widget_checkbox." + dataId + ":enabled";
511
512 $(alignClass).each(function () {
513 $(this).prop("checked", status).change();
514 });
515
516 $(".dashboard_btn.save_btn")
517 .addClass("save-now")
518 .removeAttr("disabled")
519 .css("cursor", "pointer");
520 });
521
522 // Individual Switcher for each widget
523 let widgetSwitcher = $(".element_right .widget-list:checked");
524 widgetSwitcher.on("click", function () {
525 $(".dashboard_btn.save_btn")
526 .addClass("save-now")
527 .removeAttr("disabled")
528 .css("cursor", "pointer");
529 });
530
531 // Button Setting Switcher Enable/Disable
532 let elementsSettingBtn = $(".elements_tab_menu .menu_right_content .save_btn");
533 elementsSettingBtn.on("click", function (event) {
534 // Show toast on save (optional - form will submit normally)
535 // SpelToast.show('Settings Saved', 'Your settings have been saved successfully.');
536 });
537 }
538
539 elementsSaveNowButton();
540
541 // ===== Keyboard Shortcuts =====
542 $(document).on('keydown', function (e) {
543 // Only work on Spider Elements dashboard
544 if (!$('.spel_dashboard').length) return;
545
546 // Ctrl/Cmd + S to save
547 if ((e.ctrlKey || e.metaKey) && e.key === 's') {
548 e.preventDefault();
549 $('.save_btn:visible').first().trigger('click');
550 }
551
552 // Ctrl/Cmd + F to focus search
553 if ((e.ctrlKey || e.metaKey) && e.key === 'f') {
554 const $activeTab = $('.tab-box.active');
555 const $searchInput = $activeTab.find('input[type="text"]').first();
556 if ($searchInput.length) {
557 e.preventDefault();
558 $searchInput.focus().select();
559 }
560 }
561 });
562
563 })(jQuery);
564