PluginProbe
MarqueeAll – Elementor Marquee for Image, Text, Post Grid, Testimonial, Cryptocurrency, Faqs & News Ticker 🌀 / trunk
MarqueeAll – Elementor Marquee for Image, Text, Post Grid, Testimonial, Cryptocurrency, Faqs & News Ticker 🌀 vtrunk
1.2.3 1.2.2 trunk 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1
marqueeall / assets / js / crypto-editor.js

crypto-editor.js in MarqueeAll – Elementor Marquee for Image, Text, Post Grid, Testimonial, Cryptocurrency, Faqs & News Ticker 🌀 trunk, at assets/js/crypto-editor.js

269 lines 11.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function($) {
2 'use strict';
3
4 const MasscieCryptoEditor = {
5 init: function() {
6 if (typeof jQuery === 'undefined' || !jQuery.fn.select2) {
7 console.warn('jQuery or Select2 not loaded');
8 return;
9 }
10
11 this.initializeSelect2();
12 this.setupEventListeners();
13 },
14
15 initializeSelect2: function() {
16 const $select = $('.elementor-control-crypto_ids select');
17 if (!$select.length) return;
18
19 try {
20 $select.select2({
21 width: '100%',
22 placeholder: 'Select cryptocurrencies',
23 allowClear: true
24 });
25 } catch (error) {
26 console.error('Error initializing Select2:', error);
27 }
28 },
29
30 setupEventListeners: function() {
31 // Handle API key changes to refresh the crypto list
32 $(document).on('change', '.elementor-control-api_key input', function() {
33 const $apiKey = $(this).val().trim();
34 if ($apiKey) {
35 const $cryptoSelect = $(this).closest('.elementor-control').siblings('.elementor-control-crypto_ids').find('select');
36 MasscieCryptoEditor.validateApiKey($apiKey, $cryptoSelect, elementor.getPanelView().getCurrentPageView());
37 }
38 });
39 },
40
41 validateApiKey: function(apiKey, $cryptoSelect, panel) {
42 if (!apiKey) {
43 this.showApiKeyError(panel, 'Please enter a CoinGecko API key');
44 $cryptoSelect.prop('disabled', true);
45 return;
46 }
47
48 // CoinGecko API keys start with 'cg_' and are at least 40 chars
49 if (!/^cg_[a-zA-Z0-9]{36,}$/.test(apiKey)) {
50 this.showApiKeyError(panel, 'Invalid API key format. It should start with cg_ and be at least 40 characters.');
51 $cryptoSelect.prop('disabled', true);
52 return;
53 }
54
55 // Show loading
56 this.showApiKeyLoading(panel, 'Validating API key...');
57
58 // Test API key with a simple request
59 $.ajax({
60 url: 'https://api.coingecko.com/api/v3/ping',
61 method: 'GET',
62 headers: { 'x-cg-demo-api-key': apiKey },
63 success: () => {
64 this.showApiKeySuccess(panel, 'API key is valid');
65 $cryptoSelect.prop('disabled', false);
66
67 // Refresh crypto list with the valid API key
68 this.refreshCryptoList(apiKey, $cryptoSelect);
69 },
70 error: (xhr) => {
71 if (xhr.status === 401) {
72 this.showApiKeyError(panel, 'Invalid API key. Please check your key.');
73 } else if (xhr.status === 429) {
74 this.showApiKeyError(panel, 'API rate limit exceeded. Please try again later.');
75 } else {
76 this.showApiKeyError(panel, 'Failed to validate API key. Please try again.');
77 }
78 $cryptoSelect.prop('disabled', true);
79 }
80 });
81 },
82
83 showApiKeyLoading: function(panel, message) {
84 this.showApiKeyMessage(panel, message, 'elementor-control-field-description');
85 },
86
87 showApiKeySuccess: function(panel, message) {
88 this.showApiKeyMessage(panel, message, 'elementor-control-field-description elementor-control-field-description-success');
89 },
90
91 showApiKeyError: function(panel, message) {
92 this.showApiKeyMessage(panel, message, 'elementor-control-field-description elementor-control-field-description-error');
93 },
94
95 showApiKeyMessage: function(panel, message, className) {
96 let $message = panel.$el.find('.api-key-validation-message');
97
98 if (!$message.length) {
99 $message = $('<div>', {
100 class: 'api-key-validation-message ' + className,
101 css: { marginTop: '5px' }
102 });
103 panel.$el.find('.elementor-control-api_key').append($message);
104 }
105
106 $message
107 .removeClass('elementor-control-field-description elementor-control-field-description-success elementor-control-field-description-error')
108 .addClass(className)
109 .text(message);
110 },
111
112 refreshCryptoList: function(apiKey, $select) {
113 if (!$select.length) return;
114
115 const $spinner = $('<span>', {
116 class: 'elementor-control-field-description',
117 text: 'Loading cryptocurrencies...',
118 css: { display: 'block', marginTop: '5px' }
119 });
120
121 $select.after($spinner);
122
123 $.ajax({
124 url: 'https://api.coingecko.com/api/v3/coins/markets',
125 method: 'GET',
126 data: {
127 vs_currency: 'usd',
128 order: 'market_cap_desc',
129 per_page: 100, // Increased to show more options
130 page: 1,
131 sparkline: false,
132 price_change_percentage: '24h'
133 },
134 headers: { 'x-cg-demo-api-key': apiKey },
135 success: function(response) {
136 if (Array.isArray(response) && response.length > 0) {
137 MasscieCryptoEditor.populateCryptoSelect($select, response);
138 } else {
139 MasscieCryptoEditor.showApiKeyError(
140 elementor.getPanelView().getCurrentPageView(),
141 'No cryptocurrencies found. Please try again.'
142 );
143 $select.prop('disabled', true);
144 }
145 },
146 error: function(xhr, status, error) {
147 console.error('Error fetching crypto list:', error);
148 let errorMessage = 'Failed to load cryptocurrencies. ';
149
150 if (xhr.status === 401) {
151 errorMessage = 'Invalid API key. Please check your key.';
152 } else if (xhr.status === 429) {
153 errorMessage = 'API rate limit exceeded. Please try again later.';
154 } else if (error === 'timeout') {
155 errorMessage = 'Connection timeout. Please check your internet connection.';
156 }
157
158 MasscieCryptoEditor.showApiKeyError(
159 elementor.getPanelView().getCurrentPageView(),
160 errorMessage
161 );
162
163 $select.prop('disabled', true);
164
165 // Don't fall back to default list - we want to enforce API key validation
166 $select.empty().append(
167 $('<option>', {
168 value: '',
169 text: 'Failed to load cryptocurrencies',
170 disabled: true,
171 selected: true
172 })
173 );
174 },
175 complete: function() {
176 $spinner.remove();
177 },
178 timeout: 10000 // 10 second timeout
179 });
180 },
181
182 populateCryptoSelect: function($select, cryptos) {
183 if (!$select.length) return;
184
185 try {
186 // Store current values
187 const currentValues = $select.val() || [];
188
189 // Clear and repopulate
190 $select.empty().append(
191 $('<option>', {
192 value: '',
193 text: 'Select Cryptocurrencies'
194 })
195 );
196
197 // Add crypto options
198 cryptos.forEach(function(crypto) {
199 $select.append(
200 $('<option>', {
201 value: crypto.id,
202 text: crypto.name + ' (' + crypto.symbol.toUpperCase() + ')',
203 selected: currentValues.includes(crypto.id)
204 })
205 );
206 });
207
208 // Reinitialize Select2
209 if ($.fn.select2) {
210 $select.select2('destroy').select2({
211 width: '100%',
212 placeholder: 'Select cryptocurrencies',
213 allowClear: true
214 });
215 }
216 } catch (error) {
217 console.error('Error populating select:', error);
218 }
219 },
220
221 setupCryptoControls: function(panel) {
222 // Handle API key changes to refresh the crypto list
223 $(document).on('change', '.elementor-control-api_key input', function() {
224 const $apiKey = $(this).val().trim();
225 if ($apiKey) {
226 MasscieCryptoEditor.validateApiKey($apiKey, panel.$el.find('.elementor-control-crypto_ids select'), panel);
227 }
228 });
229 }
230 };
231
232 // Initialize when Elementor is ready
233 if (typeof elementor !== 'undefined') {
234 elementor.hooks.addAction('panel/init', function() {
235 MasscieCryptoEditor.init();
236
237 // Also initialize when a new widget is added
238 elementor.hooks.addAction('panel/open_editor/widget', function(panel, model, view) {
239 if (model.attributes.widgetType === 'crypto_marquee') {
240 const $apiKeyInput = panel.$el.find('input[data-setting="api_key"]');
241 const $cryptoSelect = panel.$el.find('.elementor-control-crypto_ids select');
242
243 if ($apiKeyInput.length && $cryptoSelect.length) {
244 // Disable crypto select initially
245 $cryptoSelect.prop('disabled', true);
246
247 // Validate API key when it changes
248 $apiKeyInput.off('input').on('input', _.debounce(function() {
249 const apiKey = $(this).val().trim();
250 MasscieCryptoEditor.validateApiKey(apiKey, $cryptoSelect, panel);
251 }, 500));
252
253 // Initial validation if API key exists
254 const initialApiKey = $apiKeyInput.val().trim();
255 if (initialApiKey) {
256 MasscieCryptoEditor.validateApiKey(initialApiKey, $cryptoSelect, panel);
257 }
258 }
259 }
260 });
261 });
262 } else {
263 $(window).on('load', function() {
264 MasscieCryptoEditor.init();
265 });
266 }
267
268 })(jQuery);
269