(function($) { 'use strict'; const MasscieCryptoEditor = { init: function() { if (typeof jQuery === 'undefined' || !jQuery.fn.select2) { console.warn('jQuery or Select2 not loaded'); return; } this.initializeSelect2(); this.setupEventListeners(); }, initializeSelect2: function() { const $select = $('.elementor-control-crypto_ids select'); if (!$select.length) return; try { $select.select2({ width: '100%', placeholder: 'Select cryptocurrencies', allowClear: true }); } catch (error) { console.error('Error initializing Select2:', error); } }, setupEventListeners: function() { // Handle API key changes to refresh the crypto list $(document).on('change', '.elementor-control-api_key input', function() { const $apiKey = $(this).val().trim(); if ($apiKey) { const $cryptoSelect = $(this).closest('.elementor-control').siblings('.elementor-control-crypto_ids').find('select'); MasscieCryptoEditor.validateApiKey($apiKey, $cryptoSelect, elementor.getPanelView().getCurrentPageView()); } }); }, validateApiKey: function(apiKey, $cryptoSelect, panel) { if (!apiKey) { this.showApiKeyError(panel, 'Please enter a CoinGecko API key'); $cryptoSelect.prop('disabled', true); return; } // CoinGecko API keys start with 'cg_' and are at least 40 chars if (!/^cg_[a-zA-Z0-9]{36,}$/.test(apiKey)) { this.showApiKeyError(panel, 'Invalid API key format. It should start with cg_ and be at least 40 characters.'); $cryptoSelect.prop('disabled', true); return; } // Show loading this.showApiKeyLoading(panel, 'Validating API key...'); // Test API key with a simple request $.ajax({ url: 'https://api.coingecko.com/api/v3/ping', method: 'GET', headers: { 'x-cg-demo-api-key': apiKey }, success: () => { this.showApiKeySuccess(panel, 'API key is valid'); $cryptoSelect.prop('disabled', false); // Refresh crypto list with the valid API key this.refreshCryptoList(apiKey, $cryptoSelect); }, error: (xhr) => { if (xhr.status === 401) { this.showApiKeyError(panel, 'Invalid API key. Please check your key.'); } else if (xhr.status === 429) { this.showApiKeyError(panel, 'API rate limit exceeded. Please try again later.'); } else { this.showApiKeyError(panel, 'Failed to validate API key. Please try again.'); } $cryptoSelect.prop('disabled', true); } }); }, showApiKeyLoading: function(panel, message) { this.showApiKeyMessage(panel, message, 'elementor-control-field-description'); }, showApiKeySuccess: function(panel, message) { this.showApiKeyMessage(panel, message, 'elementor-control-field-description elementor-control-field-description-success'); }, showApiKeyError: function(panel, message) { this.showApiKeyMessage(panel, message, 'elementor-control-field-description elementor-control-field-description-error'); }, showApiKeyMessage: function(panel, message, className) { let $message = panel.$el.find('.api-key-validation-message'); if (!$message.length) { $message = $('
', { class: 'api-key-validation-message ' + className, css: { marginTop: '5px' } }); panel.$el.find('.elementor-control-api_key').append($message); } $message .removeClass('elementor-control-field-description elementor-control-field-description-success elementor-control-field-description-error') .addClass(className) .text(message); }, refreshCryptoList: function(apiKey, $select) { if (!$select.length) return; const $spinner = $('', { class: 'elementor-control-field-description', text: 'Loading cryptocurrencies...', css: { display: 'block', marginTop: '5px' } }); $select.after($spinner); $.ajax({ url: 'https://api.coingecko.com/api/v3/coins/markets', method: 'GET', data: { vs_currency: 'usd', order: 'market_cap_desc', per_page: 100, // Increased to show more options page: 1, sparkline: false, price_change_percentage: '24h' }, headers: { 'x-cg-demo-api-key': apiKey }, success: function(response) { if (Array.isArray(response) && response.length > 0) { MasscieCryptoEditor.populateCryptoSelect($select, response); } else { MasscieCryptoEditor.showApiKeyError( elementor.getPanelView().getCurrentPageView(), 'No cryptocurrencies found. Please try again.' ); $select.prop('disabled', true); } }, error: function(xhr, status, error) { console.error('Error fetching crypto list:', error); let errorMessage = 'Failed to load cryptocurrencies. '; if (xhr.status === 401) { errorMessage = 'Invalid API key. Please check your key.'; } else if (xhr.status === 429) { errorMessage = 'API rate limit exceeded. Please try again later.'; } else if (error === 'timeout') { errorMessage = 'Connection timeout. Please check your internet connection.'; } MasscieCryptoEditor.showApiKeyError( elementor.getPanelView().getCurrentPageView(), errorMessage ); $select.prop('disabled', true); // Don't fall back to default list - we want to enforce API key validation $select.empty().append( $('