diff --git a/basicswap/static/js/coin_icons.js b/basicswap/static/js/coin_icons.js index 7c03819..f8db7e7 100644 --- a/basicswap/static/js/coin_icons.js +++ b/basicswap/static/js/coin_icons.js @@ -14,7 +14,7 @@ document.addEventListener('DOMContentLoaded', () => { const image = selectedOption.getAttribute('data-image') || ''; const name = selectedOption.textContent.trim(); select.style.backgroundImage = image ? `url(${image}?${new Date().getTime()})` : ''; - + const selectImage = select.nextElementSibling.querySelector('.select-image'); if (selectImage) { selectImage.src = image; diff --git a/basicswap/static/js/main.js b/basicswap/static/js/main.js index 72291b2..38f6e4e 100644 --- a/basicswap/static/js/main.js +++ b/basicswap/static/js/main.js @@ -19,8 +19,8 @@ document.addEventListener('DOMContentLoaded', function() { const backdrop = document.querySelectorAll('.navbar-backdrop'); if (close.length) { - for (var i = 0; i < close.length; i++) { - close[i].addEventListener('click', function() { + for (var k = 0; k < close.length; k++) { + close[k].addEventListener('click', function() { for (var j = 0; j < menu.length; j++) { menu[j].classList.toggle('hidden'); } @@ -29,12 +29,12 @@ document.addEventListener('DOMContentLoaded', function() { } if (backdrop.length) { - for (var i = 0; i < backdrop.length; i++) { - backdrop[i].addEventListener('click', function() { + for (var l = 0; l < backdrop.length; l++) { + backdrop[l].addEventListener('click', function() { for (var j = 0; j < menu.length; j++) { menu[j].classList.toggle('hidden'); } }); } } -}); \ No newline at end of file +}); diff --git a/basicswap/static/js/new_offer.js b/basicswap/static/js/new_offer.js index 9472cc3..058e8dc 100644 --- a/basicswap/static/js/new_offer.js +++ b/basicswap/static/js/new_offer.js @@ -1,5 +1,5 @@ -window.addEventListener('DOMContentLoaded', (event) => { - let err_msgs = document.querySelectorAll('p.error_msg'); +window.addEventListener('DOMContentLoaded', () => { + const err_msgs = document.querySelectorAll('p.error_msg'); for (let i = 0; i < err_msgs.length; i++) { err_msg = err_msgs[i].innerText; if (err_msg.indexOf('coin_to') >= 0 || err_msg.indexOf('Coin To') >= 0) { @@ -29,9 +29,9 @@ window.addEventListener('DOMContentLoaded', (event) => { } // remove error class on input or select focus - let inputs = document.querySelectorAll('input.error'); - let selects = document.querySelectorAll('select.error'); - let elements = [...inputs, ...selects]; + const inputs = document.querySelectorAll('input.error'); + const selects = document.querySelectorAll('select.error'); + const elements = [...inputs, ...selects]; elements.forEach((element) => { element.addEventListener('focus', (event) => { event.target.classList.remove('error'); diff --git a/basicswap/static/js/offerstable.js b/basicswap/static/js/offerstable.js index 385b120..2652780 100644 --- a/basicswap/static/js/offerstable.js +++ b/basicswap/static/js/offerstable.js @@ -5,16 +5,16 @@ const EventManager = { if (!this.listeners.has(element)) { this.listeners.set(element, new Map()); } - + const elementListeners = this.listeners.get(element); if (!elementListeners.has(type)) { elementListeners.set(type, new Set()); } - + const handlerInfo = { handler, options }; elementListeners.get(type).add(handlerInfo); element.addEventListener(type, handler, options); - + return handlerInfo; }, @@ -74,14 +74,10 @@ let filterTimeout = null; // CONFIGURATION CONSTANTS // Time Constants -const MIN_REFRESH_INTERVAL = 60; // 60 sec const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes -const FALLBACK_CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 hours // Application Constants const itemsPerPage = 50; -const PRICE_INIT_RETRIES = 3; -const PRICE_INIT_RETRY_DELAY = 2000; const isSentOffers = window.offersTableConfig.isSentOffers; const offersConfig = { @@ -111,12 +107,6 @@ const coinNameToSymbol = { 'Bitcoin Cash': 'bitcoin-cash' }; -const symbolToCoinName = { - ...Object.fromEntries(Object.entries(coinNameToSymbol).map(([key, value]) => [value, key])), - 'zcoin': 'Firo', - 'firo': 'Firo' -}; - const coinNameToDisplayName = { 'Bitcoin': 'Bitcoin', 'Litecoin': 'Litecoin', @@ -152,76 +142,6 @@ const totalPagesSpan = document.getElementById('totalPages'); const lastRefreshTimeSpan = document.getElementById('lastRefreshTime'); const newEntriesCountSpan = document.getElementById('newEntriesCount'); -const ScrollOptimizer = { - scrollTimeout: null, - isScrolling: false, - tooltipCache: new WeakMap(), - - init() { - window.addEventListener('scroll', this.handleScroll.bind(this), { passive: true }); - - document.body.addEventListener('mouseenter', this.handleTooltipEnter.bind(this), true); - document.body.addEventListener('mouseleave', this.handleTooltipLeave.bind(this), true); - }, - - handleScroll() { - if (this.scrollTimeout) { - window.cancelAnimationFrame(this.scrollTimeout); - } - - if (!this.isScrolling) { - requestAnimationFrame(() => { - document.body.classList.add('is-scrolling'); - this.isScrolling = true; - }); - } - - this.scrollTimeout = window.requestAnimationFrame(() => { - document.body.classList.remove('is-scrolling'); - this.isScrolling = false; - }); - }, - - handleTooltipEnter(e) { - const tooltipTrigger = e.target.closest('[data-tooltip-target]'); - if (!tooltipTrigger) return; - - const tooltipId = tooltipTrigger.getAttribute('data-tooltip-target'); - let tooltip = this.tooltipCache.get(tooltipTrigger); - - if (!tooltip) { - tooltip = document.getElementById(tooltipId); - if (tooltip) { - this.tooltipCache.set(tooltipTrigger, tooltip); - } - } - - if (tooltip) { - tooltip.classList.remove('invisible', 'opacity-0'); - } - }, - - handleTooltipLeave(e) { - const tooltipTrigger = e.target.closest('[data-tooltip-target]'); - if (!tooltipTrigger) return; - - const tooltip = this.tooltipCache.get(tooltipTrigger); - if (tooltip) { - tooltip.classList.add('invisible', 'opacity-0'); - } - }, - - cleanup() { - if (this.scrollTimeout) { - window.cancelAnimationFrame(this.scrollTimeout); - } - window.removeEventListener('scroll', this.handleScroll); - document.body.removeEventListener('mouseenter', this.handleTooltipEnter); - document.body.removeEventListener('mouseleave', this.handleTooltipLeave); - this.tooltipCache = null; - } -}; - // MANAGER OBJECTS const WebSocketManager = { ws: null, @@ -259,7 +179,7 @@ const WebSocketManager = { this.handlePageVisible(); } }; - + document.addEventListener('visibilitychange', this.handlers.visibilityChange); }, @@ -550,8 +470,8 @@ const CacheManager = { try { localStorage.setItem(key, JSON.stringify(item)); return true; - } catch (retryError) { - //console.error('Storage quota exceeded even after cleanup'); + } catch (error) { + console.error('Storage quota exceeded even after cleanup:', error.message); return false; } } @@ -577,6 +497,7 @@ const CacheManager = { localStorage.removeItem(key); } catch (error) { + console.error("An error occured:", error.message); localStorage.removeItem(key); } return null; @@ -612,6 +533,7 @@ const CacheManager = { totalSize += size; itemCount++; } catch (error) { + console.error("An error occured:", error.message); localStorage.removeItem(key); } } @@ -662,6 +584,7 @@ const CacheManager = { expiredCount++; } } catch (error) { + console.error("An error occured:", error.message); } } @@ -721,14 +644,15 @@ const IdentityManager = { const response = await fetch(`/json/identities/${address}`, { signal: AbortSignal.timeout(5000) }); - + if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } - + return await response.json(); } catch (error) { if (attempt >= this.maxRetries) { + console.error("An error occured:", error.message); console.warn(`Failed to fetch identity for ${address} after ${attempt} attempts`); return null; } @@ -856,10 +780,6 @@ window.tableRateModule = { }; // CORE SYSTEM FUNCTIONS -function initializeWebSocket() { - return WebSocketManager.initialize(); -} - function initializeTableRateModule() { if (typeof window.tableRateModule !== 'undefined') { tableRateModule = window.tableRateModule; @@ -871,53 +791,12 @@ function initializeTableRateModule() { } } -async function initializePriceData() { - //console.log('Initializing price data...'); - let retryCount = 0; - let prices = null; - - const PRICES_CACHE_KEY = 'prices_coingecko'; - const cachedPrices = CacheManager.get(PRICES_CACHE_KEY); - if (cachedPrices && cachedPrices.value) { - console.log('Using cached price data'); - latestPrices = cachedPrices.value; - return true; - } - - while (retryCount < PRICE_INIT_RETRIES) { - try { - prices = await fetchLatestPrices(); - - if (prices && Object.keys(prices).length > 0) { - console.log('Successfully fetched initial price data'); - latestPrices = prices; - CacheManager.set(PRICES_CACHE_KEY, prices, CACHE_DURATION); - return true; - } - - retryCount++; - - if (retryCount < PRICE_INIT_RETRIES) { - await new Promise(resolve => setTimeout(resolve, PRICE_INIT_RETRY_DELAY)); - } - } catch (error) { - console.error(`Error fetching prices (attempt ${retryCount + 1}):`, error); - retryCount++; - - if (retryCount < PRICE_INIT_RETRIES) { - await new Promise(resolve => setTimeout(resolve, PRICE_INIT_RETRY_DELAY)); - } - } - } - - return false; -} - function continueInitialization() { updateCoinFilterImages(); fetchOffers().then(() => { applyFilters(); if (!isSentOffers) { + return; } }); @@ -928,32 +807,6 @@ function continueInitialization() { //console.log('Initialization completed'); } -function checkOfferAgainstFilters(offer, filters) { - if (filters.coin_to !== 'any' && !coinMatches(offer.coin_to, filters.coin_to)) { - return false; - } - if (filters.coin_from !== 'any' && !coinMatches(offer.coin_from, filters.coin_from)) { - return false; - } - if (filters.status && filters.status !== 'any') { - const currentTime = Math.floor(Date.now() / 1000); - const isExpired = offer.expire_at <= currentTime; - const isRevoked = Boolean(offer.is_revoked); - - switch (filters.status) { - case 'active': - return !isExpired && !isRevoked; - case 'expired': - return isExpired && !isRevoked; - case 'revoked': - return isRevoked; - default: - return true; - } - } - return true; -} - function initializeFlowbiteTooltips() { if (typeof Tooltip === 'undefined') { console.warn('Tooltip is not defined. Make sure the required library is loaded.'); @@ -971,65 +824,6 @@ function initializeFlowbiteTooltips() { } // DATA PROCESSING FUNCTIONS -async function checkExpiredAndFetchNew() { - if (isSentOffers) return Promise.resolve(); - - console.log('Starting checkExpiredAndFetchNew'); - const OFFERS_CACHE_KEY = 'offers_received'; - - try { - const response = await fetch('/json/offers'); - const data = await response.json(); - let newListings = Array.isArray(data) ? data : Object.values(data); - - newListings = newListings.map(offer => ({ - ...offer, - offer_id: String(offer.offer_id || ''), - swap_type: String(offer.swap_type || 'N/A'), - addr_from: String(offer.addr_from || ''), - coin_from: String(offer.coin_from || ''), - coin_to: String(offer.coin_to || ''), - amount_from: String(offer.amount_from || '0'), - amount_to: String(offer.amount_to || '0'), - rate: String(offer.rate || '0'), - created_at: Number(offer.created_at || 0), - expire_at: Number(offer.expire_at || 0), - is_own_offer: Boolean(offer.is_own_offer), - amount_negotiable: Boolean(offer.amount_negotiable), - unique_id: `${offer.offer_id}_${offer.created_at}_${offer.coin_from}_${offer.coin_to}` - })); - - newListings = newListings.filter(offer => !isOfferExpired(offer)); - originalJsonData = newListings; - - CacheManager.set(OFFERS_CACHE_KEY, newListings, CACHE_DURATION); - - const currentFilters = new FormData(filterForm); - const hasActiveFilters = currentFilters.get('coin_to') !== 'any' || - currentFilters.get('coin_from') !== 'any'; - - if (hasActiveFilters) { - jsonData = filterAndSortData(); - } else { - jsonData = [...newListings]; - } - - updateOffersTable(); - updateJsonView(); - updatePaginationInfo(); - - if (jsonData.length === 0) { - handleNoOffersScenario(); - } - - return jsonData.length; - } catch (error) { - //console.error('Error fetching new listings:', error); - nextRefreshCountdown = 60; - return Promise.reject(error); - } -} - function getValidOffers() { if (!jsonData) { //console.warn('jsonData is undefined or null'); @@ -1182,7 +976,7 @@ async function calculateProfitLoss(fromCoin, toCoin, fromAmount, toAmount, isOwn const fromPriceUSD = latestPrices[fromSymbol]?.usd; const toPriceUSD = latestPrices[toSymbol]?.usd; - if (fromPriceUSD === null || toPriceUSD === null || + if (fromPriceUSD === null || toPriceUSD === null || fromPriceUSD === undefined || toPriceUSD === undefined) { resolve(null); return; @@ -1202,42 +996,6 @@ async function calculateProfitLoss(fromCoin, toCoin, fromAmount, toAmount, isOwn }); } -async function getMarketRate(fromCoin, toCoin) { - return new Promise((resolve) => { - //console.log(`Attempting to get market rate for ${fromCoin} to ${toCoin}`); - if (!latestPrices) { - //console.warn('Latest prices object is not available'); - resolve(null); - return; - } - - const getPriceKey = (coin) => { - const lowerCoin = coin.toLowerCase(); - if (lowerCoin === 'firo' || lowerCoin === 'zcoin') { - return 'zcoin'; - } - if (lowerCoin === 'bitcoin cash') { - return 'bitcoin-cash'; - } - return coinNameToSymbol[coin] || lowerCoin; - }; - - const fromSymbol = getPriceKey(fromCoin); - const toSymbol = getPriceKey(toCoin); - - const fromPrice = latestPrices[fromSymbol]?.usd; - const toPrice = latestPrices[toSymbol]?.usd; - if (!fromPrice || !toPrice) { - //console.warn(`Missing price data for ${!fromPrice ? fromCoin : toCoin}`); - resolve(null); - return; - } - const rate = toPrice / fromPrice; - //console.log(`Market rate calculated: ${rate} ${toCoin}/${fromCoin}`); - resolve(rate); - }); -} - function getEmptyPriceData() { return { 'bitcoin': { usd: null, btc: null }, @@ -1259,7 +1017,7 @@ async function fetchLatestPrices() { const PRICES_CACHE_KEY = 'prices_coingecko'; const RETRY_DELAY = 5000; const MAX_RETRIES = 3; - + const cachedData = CacheManager.get(PRICES_CACHE_KEY); if (cachedData && cachedData.remainingTime > 30000) { console.log('Using cached price data'); @@ -1268,7 +1026,7 @@ async function fetchLatestPrices() { } const baseUrl = `${offersConfig.apiEndpoints.coinGecko}/simple/price?ids=bitcoin,bitcoin-cash,dash,dogecoin,decred,litecoin,particl,pivx,monero,zcoin,zano,wownero&vs_currencies=USD,BTC`; - + let retryCount = 0; let data = null; @@ -1282,7 +1040,7 @@ async function fetchLatestPrices() { try { console.log('Attempting price fetch with API key...'); const urlWithKey = `${baseUrl}&api_key=${offersConfig.apiKeys.coinGecko}`; - + const response = await fetch('/json/readurl', { method: 'POST', headers: { @@ -1306,9 +1064,9 @@ async function fetchLatestPrices() { continue; } - const hasValidPrices = Object.values(responseData).some(coin => - coin && typeof coin === 'object' && - typeof coin.usd === 'number' && + const hasValidPrices = Object.values(responseData).some(coin => + coin && typeof coin === 'object' && + typeof coin.usd === 'number' && !isNaN(coin.usd) ); @@ -1343,11 +1101,11 @@ async function fetchLatestPrices() { tableRateModule.setFallbackValue(coin, prices.usd); } }); - + return data; } -async function fetchOffers(manualRefresh = false) { +async function fetchOffers() { const refreshButton = document.getElementById('refreshOffers'); const refreshIcon = document.getElementById('refreshIcon'); const refreshText = document.getElementById('refreshText'); @@ -1557,7 +1315,7 @@ function updateProfitLoss(row, fromCoin, toCoin, fromAmount, toAmount, isOwnOffe } }) .catch(error => { - //console.error('Error in updateProfitLoss:', error); + console.error('Error in updateProfitLoss:', error); profitLossElement.textContent = 'Error'; profitLossElement.className = 'profit-loss text-lg font-bold text-red-500'; }); @@ -1605,7 +1363,7 @@ function updateClearFiltersButton() { function cleanupRow(row) { EventManager.removeAll(row); - + const tooltips = row.querySelectorAll('[data-tooltip-target]'); tooltips.forEach(tooltip => { const tooltipId = tooltip.getAttribute('data-tooltip-target'); @@ -1618,7 +1376,7 @@ function cleanupRow(row) { function cleanupTable() { EventManager.clearAll(); - + if (offersBody) { const existingRows = offersBody.querySelectorAll('tr'); existingRows.forEach(row => { @@ -1686,13 +1444,13 @@ async function updateOffersTable() { const BATCH_SIZE = 5; const identities = []; - + for (let i = 0; i < itemsToDisplay.length; i += BATCH_SIZE) { const batch = itemsToDisplay.slice(i, i + BATCH_SIZE); const batchPromises = batch.map(offer => offer.addr_from ? IdentityManager.getIdentityData(offer.addr_from) : Promise.resolve(null) ); - + const batchResults = await Promise.all(batchPromises); identities.push(...batchResults); @@ -1789,10 +1547,6 @@ function handleTableError() { `; } -async function getIdentityData(address) { - return IdentityManager.getIdentityData(address); -} - function getIdentityInfo(address, identity) { if (!identity) { return { @@ -1928,10 +1682,6 @@ function createTimeColumn(offer, postedTime, expiresIn) { `; } -function shouldShowPublicTag(offers) { - return offers.some(offer => !offer.is_public); -} - function truncateText(text, maxLength = 15) { if (typeof text !== 'string') return ''; return text.length > maxLength @@ -1977,7 +1727,7 @@ function createDetailsColumn(offer, identity = null) { `; } -function createTakerAmountColumn(offer, coinTo, coinFrom) { +function createTakerAmountColumn(offer, coinTo) { const fromAmount = parseFloat(offer.amount_to); const toSymbol = getCoinSymbol(coinTo); return ` @@ -2021,7 +1771,7 @@ function createSwapColumn(offer, coinFromDisplay, coinToDisplay, coinFromSymbol, `; } -function createOrderbookColumn(offer, coinFrom, coinTo) { +function createOrderbookColumn(offer, coinFrom) { const toAmount = parseFloat(offer.amount_from); const fromSymbol = getCoinSymbol(coinFrom); return ` @@ -2055,7 +1805,6 @@ function createRateColumn(offer, coinFrom, coinTo) { return coinNameToSymbol[coin] || lowerCoin; }; - const fromPriceUSD = latestPrices[getPriceKey(coinFrom)]?.usd || 0; const toPriceUSD = latestPrices[getPriceKey(coinTo)]?.usd || 0; const rateInUSD = rate * toPriceUSD; @@ -2126,9 +1875,6 @@ function createActionColumn(offer, isActuallyExpired = false) { // TOOLTIP FUNCTIONS function createTooltips(offer, treatAsSentOffer, coinFrom, coinTo, fromAmount, toAmount, postedTime, expiresIn, isActuallyExpired, isRevoked, identity = null) { - const rate = parseFloat(offer.rate); - const fromSymbol = getCoinSymbolLowercase(coinFrom); - const toSymbol = getCoinSymbolLowercase(coinTo); const uniqueId = `${offer.offer_id}_${offer.created_at}`; const addrFrom = offer.addr_from || ''; @@ -2147,10 +1893,6 @@ function createTooltips(offer, treatAsSentOffer, coinFrom, coinTo, fromAmount, t ((identityInfo.stats.sentBidsSuccessful + identityInfo.stats.recvBidsSuccessful) / totalBids) * 100 ).toFixed(1) : 0; - const fromPriceUSD = latestPrices[fromSymbol]?.usd || 0; - const toPriceUSD = latestPrices[toSymbol]?.usd || 0; - const rateInUSD = rate * toPriceUSD; - const combinedRateTooltip = createCombinedRateTooltip(offer, coinFrom, coinTo, treatAsSentOffer); const percentageTooltipContent = createTooltipContent(treatAsSentOffer, coinFrom, coinTo, fromAmount, toAmount); @@ -2329,8 +2071,8 @@ function createTooltipContent(isSentOffers, coinFrom, coinTo, fromAmount, toAmou const getPriceKey = (coin) => { const lowerCoin = coin.toLowerCase(); - return lowerCoin === 'firo' || lowerCoin === 'zcoin' ? 'zcoin' : - lowerCoin === 'bitcoin cash' ? 'bitcoin-cash' : + return lowerCoin === 'firo' || lowerCoin === 'zcoin' ? 'zcoin' : + lowerCoin === 'bitcoin cash' ? 'bitcoin-cash' : lowerCoin === 'particl anon' || lowerCoin === 'particl blind' ? 'particl' : coinNameToSymbol[coin] || lowerCoin; }; @@ -2340,7 +2082,7 @@ function createTooltipContent(isSentOffers, coinFrom, coinTo, fromAmount, toAmou const fromPriceUSD = latestPrices[fromSymbol]?.usd; const toPriceUSD = latestPrices[toSymbol]?.usd; - if (fromPriceUSD === null || toPriceUSD === null || + if (fromPriceUSD === null || toPriceUSD === null || fromPriceUSD === undefined || toPriceUSD === undefined) { return `
Price Information Unavailable
Current market prices are temporarily unavailable.
@@ -2421,7 +2163,7 @@ function createCombinedRateTooltip(offer, coinFrom, coinTo, treatAsSentOffer) { const fromPriceUSD = latestPrices[fromSymbol]?.usd; const toPriceUSD = latestPrices[toSymbol]?.usd; - if (fromPriceUSD === null || toPriceUSD === null || + if (fromPriceUSD === null || toPriceUSD === null || fromPriceUSD === undefined || toPriceUSD === undefined) { return `Exchange Rate Information
@@ -2526,13 +2268,6 @@ function clearFilters() { } function hasActiveFilters() { - const formData = new FormData(filterForm); - const filters = { - coin_to: formData.get('coin_to'), - coin_from: formData.get('coin_from'), - status: formData.get('status') - }; - const selectElements = filterForm.querySelectorAll('select'); let hasChangedFilters = false; @@ -2622,20 +2357,6 @@ function isOfferExpired(offer) { return isExpired; } -function getTimeUntilNextExpiration() { - const currentTime = Math.floor(Date.now() / 1000); - const nextExpiration = jsonData.reduce((earliest, offer) => { - const timeUntilExpiration = offer.expire_at - currentTime; - return timeUntilExpiration > 0 && timeUntilExpiration < earliest ? timeUntilExpiration : earliest; - }, Infinity); - - return Math.max(MIN_REFRESH_INTERVAL, Math.min(nextExpiration, 300)); -} - -function calculateInverseRate(rate) { - return (1 / parseFloat(rate)).toFixed(8); -} - function formatTime(timestamp, addAgoSuffix = false) { const now = Math.floor(Date.now() / 1000); const diff = Math.abs(now - timestamp); @@ -2796,47 +2517,6 @@ function initializeTableEvents() { } } -const eventListeners = { - listeners: [], - - add(element, eventType, handler, options = false) { - element.addEventListener(eventType, handler, options); - this.listeners.push({ element, eventType, handler, options }); - // console.log(`Added ${eventType} listener to`, element); - }, - - addWindowListener(eventType, handler, options = false) { - window.addEventListener(eventType, handler, options); - this.listeners.push({ element: window, eventType, handler, options }); - // console.log(`Added ${eventType} window listener`); - }, - - removeAll() { - console.log('Removing all event listeners...'); - this.listeners.forEach(({ element, eventType, handler, options }) => { - element.removeEventListener(eventType, handler, options); - //console.log(`Removed ${eventType} listener from`, element); - }); - this.listeners = []; - }, - - removeByElement(element) { - const remainingListeners = []; - this.listeners = this.listeners.filter(listener => { - if (listener.element === element) { - listener.element.removeEventListener( - listener.eventType, - listener.handler, - listener.options - ); - console.log(`✂️ Removed ${listener.eventType} listener from`, element); - return false; - } - return true; - }); - }, -}; - function handleTableSort(columnIndex, header) { if (currentSortColumn === columnIndex) { currentSortDirection = currentSortDirection === 'asc' ? 'desc' : 'asc'; @@ -2870,27 +2550,6 @@ function handleTableSort(columnIndex, header) { applyFilters(); } -function setupRowEventListeners(row, offer) { - const tooltipTriggers = row.querySelectorAll('[data-tooltip-target]'); - tooltipTriggers.forEach(trigger => { - EventManager.add(trigger, 'mouseenter', () => { - const tooltipId = trigger.getAttribute('data-tooltip-target'); - const tooltip = document.getElementById(tooltipId); - if (tooltip) { - tooltip.classList.remove('invisible', 'opacity-0'); - } - }); - - EventManager.add(trigger, 'mouseleave', () => { - const tooltipId = trigger.getAttribute('data-tooltip-target'); - const tooltip = document.getElementById(tooltipId); - if (tooltip) { - tooltip.classList.add('invisible', 'opacity-0'); - } - }); - }); -} - // TIMER MANAGEMENT const timerManager = { intervals: [], @@ -3015,7 +2674,7 @@ async function cleanup() { console.log(`Total cleanup time: ${totalTime}ms`); console.log('Steps completed:', this.steps.length); console.log('Errors encountered:', this.errors.length); - + if (this.steps.length > 0) { console.group('Steps Timeline'); this.steps.forEach(({step, time}) => { @@ -3023,7 +2682,7 @@ async function cleanup() { }); console.groupEnd(); } - + if (this.errors.length > 0) { console.group('Errors'); this.errors.forEach(({step, error, time}) => { diff --git a/basicswap/static/js/pricechart.js b/basicswap/static/js/pricechart.js index 889df3d..a4c63f2 100644 --- a/basicswap/static/js/pricechart.js +++ b/basicswap/static/js/pricechart.js @@ -40,9 +40,9 @@ const config = { // UTILS const utils = { - formatNumber: (number, decimals = 2) => + formatNumber: (number, decimals = 2) => number.toFixed(decimals).replace(/\B(?=(\d{3})+(?!\d))/g, ','), - + formatDate: (timestamp, resolution) => { const date = new Date(timestamp); const options = { @@ -80,7 +80,7 @@ const logger = { // API const api = { makePostRequest: (url, headers = {}) => { - const apiKeys = getAPIKeys(); + // unused // const apiKeys = getAPIKeys(); return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('POST', '/json/readurl'); @@ -114,7 +114,7 @@ const api = { })); }); }, - + fetchCryptoCompareDataXHR: (coin) => { const url = `${config.apiEndpoints.cryptoCompare}?fsyms=${coin}&tsyms=USD,BTC&api_key=${config.apiKeys.cryptoCompare}`; const headers = { @@ -126,10 +126,10 @@ const api = { error: error.message })); }, - + fetchCoinGeckoDataXHR: async () => { const cacheKey = 'coinGeckoOneLiner'; - let cachedData = cache.get(cacheKey); + const cachedData = cache.get(cacheKey); if (cachedData) { console.log('Using cached CoinGecko data'); @@ -143,15 +143,15 @@ const api = { const url = `${config.apiEndpoints.coinGecko}/simple/price?ids=${coinIds}&vs_currencies=usd,btc&include_24hr_vol=true&include_24hr_change=true&api_key=${config.apiKeys.coinGecko}`; //console.log(`Fetching data for multiple coins from CoinGecko: ${url}`); - + try { const data = await api.makePostRequest(url); //console.log(`Raw CoinGecko data:`, data); - + if (typeof data !== 'object' || data === null) { throw new AppError(`Invalid data structure received from CoinGecko`); } - + const transformedData = {}; Object.entries(data).forEach(([id, values]) => { const coinConfig = config.coins.find(coin => coin.name === id); @@ -164,7 +164,7 @@ const api = { displayName: coinConfig?.displayName || coinConfig?.symbol || id }; }); - + //console.log(`Transformed CoinGecko data:`, transformedData); cache.set(cacheKey, transformedData); return transformedData; @@ -202,7 +202,7 @@ const api = { //console.error(`Unexpected data structure for WOW:`, response); } } catch (error) { - //console.error(`Error fetching CoinGecko data for WOW:`, error); + console.error(`Error fetching CoinGecko data for WOW:`, error); } } else { const resolution = config.resolutions[config.currentResolution]; @@ -225,7 +225,7 @@ const api = { //console.error(`Unexpected data structure for ${coin}:`, response); } } catch (error) { - //console.error(`Error fetching CryptoCompare data for ${coin}:`, error); + console.error(`Error fetching CryptoCompare data for ${coin}:`, error); } } }); @@ -266,8 +266,8 @@ const cache = { //console.log(`Cache expired for ${key}`); localStorage.removeItem(key); } - } catch (e) { - //console.error('Error parsing cache item:', e); + } catch (error) { + console.error('Error parsing cache item:', error.message); localStorage.removeItem(key); } return null; @@ -288,7 +288,6 @@ const cache = { // UI const ui = { displayCoinData: (coin, data) => { - const coinConfig = config.coins.find(c => c.symbol === coin); let priceUSD, priceBTC, priceChange1d, volume24h; const updateUI = (isError = false) => { const priceUsdElement = document.querySelector(`#${coin.toLowerCase()}-price-usd`); @@ -296,16 +295,16 @@ displayCoinData: (coin, data) => { const volumeElement = document.querySelector(`#${coin.toLowerCase()}-volume-24h`); const btcPriceDiv = document.querySelector(`#${coin.toLowerCase()}-btc-price-div`); const priceBtcElement = document.querySelector(`#${coin.toLowerCase()}-price-btc`); - + if (priceUsdElement) { priceUsdElement.textContent = isError ? 'N/A' : `$ ${ui.formatPrice(coin, priceUSD)}`; } - + if (volumeDiv && volumeElement) { volumeElement.textContent = isError ? 'N/A' : `${utils.formatNumber(volume24h, 0)} USD`; volumeDiv.style.display = volumeToggle.isVisible ? 'flex' : 'none'; } - + if (btcPriceDiv && priceBtcElement) { if (coin === 'BTC') { btcPriceDiv.style.display = 'none'; @@ -314,10 +313,10 @@ displayCoinData: (coin, data) => { btcPriceDiv.style.display = 'flex'; } } - + ui.updatePriceChangeContainer(coin, isError ? null : priceChange1d); }; - + try { if (data.error) { throw new Error(data.error); @@ -325,51 +324,51 @@ displayCoinData: (coin, data) => { if (!data || !data.current_price) { throw new Error(`Invalid CoinGecko data structure for ${coin}`); } - + priceUSD = data.current_price; priceBTC = coin === 'BTC' ? 1 : data.price_btc || (data.current_price / app.btcPriceUSD); priceChange1d = data.price_change_percentage_24h; volume24h = data.total_volume; - + if (isNaN(priceUSD) || isNaN(priceBTC) || isNaN(volume24h)) { throw new Error(`Invalid numeric values in data for ${coin}`); } - + updateUI(false); } catch (error) { - //console.error(`Error displaying data for ${coin}:`, error.message); + console.error(`Error displaying data for ${coin}:`, error.message); updateUI(true); } }, - + showLoader: () => { const loader = document.getElementById('loader'); if (loader) { loader.classList.remove('hidden'); } }, - + hideLoader: () => { const loader = document.getElementById('loader'); if (loader) { loader.classList.add('hidden'); } }, - + showCoinLoader: (coinSymbol) => { const loader = document.getElementById(`${coinSymbol.toLowerCase()}-loader`); if (loader) { loader.classList.remove('hidden'); } }, - + hideCoinLoader: (coinSymbol) => { const loader = document.getElementById(`${coinSymbol.toLowerCase()}-loader`); if (loader) { loader.classList.add('hidden'); } }, - + updateCacheStatus: (isCached) => { const cacheStatusElement = document.getElementById('cache-status'); if (cacheStatusElement) { @@ -378,15 +377,15 @@ displayCoinData: (coin, data) => { cacheStatusElement.classList.toggle('text-blue-500', !isCached); } }, - + updateLoadTimeAndCache: (loadTime, cachedData) => { const loadTimeElement = document.getElementById('load-time'); const cacheStatusElement = document.getElementById('cache-status'); - + if (loadTimeElement) { loadTimeElement.textContent = `Load time: ${loadTime}ms`; } - + if (cacheStatusElement) { if (cachedData && cachedData.remainingTime) { const remainingMinutes = Math.ceil(cachedData.remainingTime / 60000); @@ -402,7 +401,7 @@ displayCoinData: (coin, data) => { ui.updateLastRefreshedTime(); }, - + updatePriceChangeContainer: (coin, priceChange) => { const container = document.querySelector(`#${coin.toLowerCase()}-price-change-container`); if (container) { @@ -411,7 +410,7 @@ displayCoinData: (coin, data) => { 'N/A'; } }, - + updateLastRefreshedTime: () => { const lastRefreshedElement = document.getElementById('last-refreshed-time'); if (lastRefreshedElement && app.lastRefreshedTime) { @@ -419,7 +418,7 @@ displayCoinData: (coin, data) => { lastRefreshedElement.textContent = `Last Refreshed: ${formattedTime}`; } }, - + positivePriceChangeHTML: (value) => `