js: eslints

This commit is contained in:
nahuhh 2025-03-26 23:01:30 +00:00
parent d15466f656
commit eeade736a4
18 changed files with 284 additions and 284 deletions

View file

@ -97,7 +97,7 @@ const EventManager = {
add(element, type, handler, options = false) {
if (!element) return null;
if (!this.listeners.has(element)) {
this.listeners.set(element, new Map());
}
@ -116,7 +116,7 @@ const EventManager = {
remove(element, type, handler, options = false) {
if (!element) return;
const elementListeners = this.listeners.get(element);
if (!elementListeners) return;
@ -140,7 +140,7 @@ const EventManager = {
removeAll(element) {
if (!element) return;
const elementListeners = this.listeners.get(element);
if (!elementListeners) return;
@ -167,7 +167,7 @@ const EventManager = {
function cleanup() {
//console.log('Starting comprehensive cleanup process for bids table');
try {
if (searchTimeout) {
clearTimeout(searchTimeout);
@ -184,7 +184,7 @@ function cleanup() {
cleanupTooltips();
forceTooltipDOMCleanup();
if (window.TooltipManager) {
window.TooltipManager.cleanup();
}
@ -237,12 +237,12 @@ function cleanup() {
sent: [],
received: []
};
state.currentPage = {
sent: 1,
received: 1
};
state.isLoading = false;
state.isRefreshing = false;
state.wsConnected = false;
@ -310,7 +310,7 @@ CleanupManager.addListener(document, 'visibilitychange', () => {
if (window.TooltipManager && typeof window.TooltipManager.cleanup === 'function') {
window.TooltipManager.cleanup();
}
// Run memory optimization
if (window.MemoryManager) {
MemoryManager.forceCleanup();
@ -326,7 +326,7 @@ CleanupManager.addListener(document, 'visibilitychange', () => {
const lastUpdateTime = state.lastRefresh || 0;
const now = Date.now();
const refreshInterval = 5 * 60 * 1000; // 5 minutes
if (now - lastUpdateTime > refreshInterval) {
setTimeout(() => {
updateBidsTable();
@ -366,7 +366,7 @@ function cleanupRow(row) {
function optimizeMemoryUsage() {
const MAX_BIDS_IN_MEMORY = 500;
['sent', 'received'].forEach(type => {
if (state.data[type] && state.data[type].length > MAX_BIDS_IN_MEMORY) {
console.log(`Trimming ${type} bids data from ${state.data[type].length} to ${MAX_BIDS_IN_MEMORY}`);
@ -581,7 +581,7 @@ function filterAndSortData(bids) {
} catch (e) {
console.warn('Error accessing identity for search:', e);
}
const matchesLabel = label.toLowerCase().includes(searchStr);
let matchesDisplayedLabel = false;
@ -589,7 +589,7 @@ function filterAndSortData(bids) {
try {
const tableId = state.currentTab === 'sent' ? 'sent' : 'received';
const cells = document.querySelectorAll(`#${tableId} a[href^="/identity/"]`);
for (const cell of cells) {
const href = cell.getAttribute('href');
@ -607,7 +607,7 @@ function filterAndSortData(bids) {
console.warn('Error checking displayed labels:', e);
}
}
if (!(matchesBidId || matchesIdentity || matchesLabel || matchesDisplayedLabel)) {
return false;
}
@ -627,7 +627,7 @@ async function preloadIdentitiesForSearch(bids) {
if (!window.IdentityManager || typeof IdentityManager.getIdentityData !== 'function') {
return;
}
try {
const addresses = new Set();
bids.forEach(bid => {
@ -638,7 +638,7 @@ async function preloadIdentitiesForSearch(bids) {
const BATCH_SIZE = 20;
const addressArray = Array.from(addresses);
for (let i = 0; i < addressArray.length; i += BATCH_SIZE) {
const batch = addressArray.slice(i, i + BATCH_SIZE);
await Promise.all(batch.map(addr => IdentityManager.getIdentityData(addr)));
@ -647,7 +647,7 @@ async function preloadIdentitiesForSearch(bids) {
await new Promise(resolve => setTimeout(resolve, 10));
}
}
console.log(`Preloaded ${addressArray.length} identities for search`);
} catch (error) {
console.error('Error preloading identities:', error);
@ -847,7 +847,7 @@ const createIdentityTooltipContent = (identity) => {
`;
};
let tooltipIdsToCleanup = new Set();
const tooltipIdsToCleanup = new Set();
const cleanupTooltips = () => {
if (window.TooltipManager) {
@ -869,7 +869,7 @@ const forceTooltipDOMCleanup = () => {
foundCount += allTooltipElements.length;
allTooltipElements.forEach(element => {
const isDetached = !document.body.contains(element) ||
const isDetached = !document.body.contains(element) ||
element.classList.contains('hidden') ||
element.style.display === 'none';
@ -877,7 +877,7 @@ const forceTooltipDOMCleanup = () => {
const triggerId = element.id;
const triggerElement = document.querySelector(`[data-tooltip-target="${triggerId}"]`);
if (!triggerElement ||
if (!triggerElement ||
!document.body.contains(triggerElement) ||
triggerElement.classList.contains('hidden')) {
element.remove();
@ -899,7 +899,7 @@ const forceTooltipDOMCleanup = () => {
const tippyRoots = document.querySelectorAll('[data-tippy-root]');
foundCount += tippyRoots.length;
tippyRoots.forEach(element => {
const isOrphan = !element.children.length ||
const isOrphan = !element.children.length ||
element.children[0].classList.contains('hidden') ||
!document.body.contains(element);
@ -926,7 +926,7 @@ const forceTooltipDOMCleanup = () => {
}
});
document.querySelectorAll('.tooltip').forEach(element => {
const isTrulyDetached = !element.parentElement ||
const isTrulyDetached = !element.parentElement ||
!document.body.contains(element.parentElement) ||
element.classList.contains('hidden');
if (isTrulyDetached) {
@ -1108,7 +1108,7 @@ const updateTableContent = async (type) => {
if (currentPageData.length > 0) {
const BATCH_SIZE = 10;
let allRows = [];
for (let i = 0; i < currentPageData.length; i += BATCH_SIZE) {
const batch = currentPageData.slice(i, i + BATCH_SIZE);
const rowPromises = batch.map(bid => createTableRow(bid));
@ -1166,7 +1166,7 @@ const initializeTooltips = () => {
window.TooltipManager.cleanup();
let selector = '#' + state.currentTab + ' [data-tooltip-target]';
const selector = '#' + state.currentTab + ' [data-tooltip-target]';
const tooltipTriggers = document.querySelectorAll(selector);
const tooltipCount = tooltipTriggers.length;
if (tooltipCount > 50) {
@ -1187,7 +1187,7 @@ const initializeTooltips = () => {
});
const offscreenTooltips = Array.from(tooltipTriggers).filter(t => !viewportTooltips.includes(t));
offscreenTooltips.forEach(trigger => {
const createTooltipOnHover = () => {
createTooltipForTrigger(trigger);
@ -1206,7 +1206,7 @@ const initializeTooltips = () => {
const createTooltipForTrigger = (trigger) => {
if (!trigger || !window.TooltipManager) return;
const targetId = trigger.getAttribute('data-tooltip-target');
const tooltipContent = document.getElementById(targetId);
@ -1250,7 +1250,7 @@ function cleanupOffscreenTooltips() {
const farOffscreenTriggers = Array.from(tooltipTriggers).filter(trigger => {
const rect = trigger.getBoundingClientRect();
return (rect.bottom < -window.innerHeight * 2 ||
return (rect.bottom < -window.innerHeight * 2 ||
rect.top > window.innerHeight * 3);
});
@ -1312,7 +1312,7 @@ const fetchBids = async () => {
activeFetchController.abort();
}
}, 30000);
const response = await fetch(endpoint, {
method: 'POST',
headers: {
@ -1328,14 +1328,14 @@ const fetchBids = async () => {
}),
signal: activeFetchController.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
let data = await response.json();
const data = await response.json();
//console.log('Received raw data:', data.length, 'bids');
state.filters.with_expired = includeExpired;
@ -1351,7 +1351,7 @@ const fetchBids = async () => {
} else {
processedData = filterAndSortData(data);
}
return processedData;
} catch (error) {
if (error.name === 'AbortError') {
@ -1375,12 +1375,12 @@ const updateBidsTable = async () => {
updateLoadingState(true);
const bids = await fetchBids();
// Add identity preloading if we're searching
if (state.filters.searchQuery && state.filters.searchQuery.length > 0) {
await preloadIdentitiesForSearch(bids);
}
state.data[state.currentTab] = bids;
state.currentPage[state.currentTab] = 1;
@ -1911,13 +1911,13 @@ function initialize() {
WebSocketManager.initialize();
setupEventListeners();
}, 10);
setTimeout(() => {
setupRefreshButtons();
setupFilterEventListeners();
updateCoinFilterImages();
}, 50);
setTimeout(() => {
updateClearFiltersButton();
state.currentTab = 'sent';

View file

@ -5,7 +5,7 @@ const BidExporter = {
}
const isSent = type === 'sent';
const headers = [
'Date/Time',
'Bid ID',
@ -19,9 +19,9 @@ const BidExporter = {
'Created At',
'Expires At'
];
let csvContent = headers.join(',') + '\n';
bids.forEach(bid => {
const row = [
`"${formatTime(bid.created_at)}"`,
@ -36,17 +36,17 @@ const BidExporter = {
bid.created_at,
bid.expire_at
];
csvContent += row.join(',') + '\n';
});
return csvContent;
},
download(content, filename) {
try {
const blob = new Blob([content], { type: 'text/csv;charset=utf-8;' });
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, filename);
return;
@ -54,48 +54,48 @@ const BidExporter = {
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
setTimeout(() => {
URL.revokeObjectURL(url);
}, 100);
} catch (error) {
console.error('Error downloading CSV:', error);
const csvData = 'data:text/csv;charset=utf-8,' + encodeURIComponent(content);
const link = document.createElement('a');
link.setAttribute('href', csvData);
link.setAttribute('download', filename);
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
},
exportCurrentView() {
const type = state.currentTab;
const data = state.data[type];
if (!data || !data.length) {
alert('No data to export');
return;
}
const csvContent = this.toCSV(data, type);
const now = new Date();
const dateStr = now.toISOString().split('T')[0];
const filename = `bsx_${type}_bids_${dateStr}.csv`;
this.download(csvContent, filename);
}
};
@ -111,7 +111,7 @@ document.addEventListener('DOMContentLoaded', function() {
BidExporter.exportCurrentView();
});
}
const exportReceivedButton = document.getElementById('exportReceivedBids');
if (exportReceivedButton) {
EventManager.add(exportReceivedButton, 'click', (e) => {
@ -127,14 +127,14 @@ document.addEventListener('DOMContentLoaded', function() {
const originalCleanup = window.cleanup || function(){};
window.cleanup = function() {
originalCleanup();
const exportSentButton = document.getElementById('exportSentBids');
const exportReceivedButton = document.getElementById('exportReceivedBids');
if (exportSentButton && typeof EventManager !== 'undefined') {
EventManager.remove(exportSentButton, 'click');
}
if (exportReceivedButton && typeof EventManager !== 'undefined') {
EventManager.remove(exportReceivedButton, 'click');
}

View file

@ -84,7 +84,7 @@ function setupShutdownModal() {
function showShutdownModal() {
closeAllDropdowns();
const activeSwaps = parseInt(shutdownButtons[0].getAttribute('data-active-swaps') || '0');
if (activeSwaps > 0) {
shutdownWarning.classList.remove('hidden');
@ -142,7 +142,7 @@ function setupDarkMode() {
const themeToggleLightIcon = document.getElementById('theme-toggle-light-icon');
if (themeToggleDarkIcon && themeToggleLightIcon) {
if (localStorage.getItem('color-theme') === 'dark' ||
if (localStorage.getItem('color-theme') === 'dark' ||
(!('color-theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
themeToggleLightIcon.classList.remove('hidden');
} else {
@ -167,12 +167,12 @@ function setupDarkMode() {
} else {
setTheme('dark');
}
if (themeToggleDarkIcon && themeToggleLightIcon) {
themeToggleDarkIcon.classList.toggle('hidden');
themeToggleLightIcon.classList.toggle('hidden');
}
toggleImages();
});
}

View file

@ -51,7 +51,7 @@ const ApiManager = (function() {
try {
await this.requestQueue[apiName];
const executeRequest = async () => {
const waitTime = this.getWaitTime(apiName);
if (waitTime > 0) {
@ -69,7 +69,7 @@ const ApiManager = (function() {
return publicAPI.rateLimiter.queueRequest(apiName, requestFn, retryCount + 1);
}
if ((error.message.includes('timeout') || error.name === 'NetworkError') &&
if ((error.message.includes('timeout') || error.name === 'NetworkError') &&
retryCount < this.retryDelays.length) {
const delay = this.retryDelays[retryCount];
console.warn(`Request failed, retrying in ${delay/1000} seconds...`, {
@ -87,10 +87,10 @@ const ApiManager = (function() {
this.requestQueue[apiName] = executeRequest();
return await this.requestQueue[apiName];
} catch (error) {
if (error.message.includes('429') ||
error.message.includes('timeout') ||
if (error.message.includes('429') ||
error.message.includes('timeout') ||
error.name === 'NetworkError') {
const cacheKey = `coinData_${apiName}`;
try {
@ -110,7 +110,7 @@ const ApiManager = (function() {
const publicAPI = {
config,
rateLimiter,
initialize: function(options = {}) {
if (state.isInitialized) {
console.warn('[ApiManager] Already initialized');
@ -158,7 +158,7 @@ const ApiManager = (function() {
}
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
@ -215,18 +215,18 @@ const ApiManager = (function() {
fetchCoinGeckoData: async function() {
return this.rateLimiter.queueRequest('coingecko', async () => {
try {
const coins = (window.config && window.config.coins) ?
const coins = (window.config && window.config.coins) ?
window.config.coins
.filter(coin => coin.usesCoinGecko)
.map(coin => coin.name)
.join(',') :
.join(',') :
'bitcoin,monero,particl,bitcoincash,pivx,firo,dash,litecoin,dogecoin,decred';
//console.log('Fetching coin prices for:', coins);
const response = await this.fetchCoinPrices(coins);
//console.log('Full API response:', response);
if (!response || typeof response !== 'object') {
throw new Error('Invalid response type');
}
@ -249,11 +249,11 @@ const ApiManager = (function() {
fetchVolumeData: async function() {
return this.rateLimiter.queueRequest('coingecko', async () => {
try {
const coins = (window.config && window.config.coins) ?
const coins = (window.config && window.config.coins) ?
window.config.coins
.filter(coin => coin.usesCoinGecko)
.map(coin => getCoinBackendId ? getCoinBackendId(coin.name) : coin.name)
.join(',') :
.join(',') :
'bitcoin,monero,particl,bitcoin-cash,pivx,firo,dash,litecoin,dogecoin,decred';
const url = `https://api.coingecko.com/api/v3/simple/price?ids=${coins}&vs_currencies=usd&include_24hr_vol=true&include_24hr_change=true`;
@ -280,7 +280,7 @@ const ApiManager = (function() {
}
});
},
fetchCryptoCompareData: function(coin) {
return this.rateLimiter.queueRequest('cryptocompare', async () => {
try {
@ -290,7 +290,7 @@ const ApiManager = (function() {
'User-Agent': 'Mozilla/5.0',
'Accept': 'application/json'
};
return await this.makePostRequest(url, headers);
} catch (error) {
console.error(`CryptoCompare request failed for ${coin}:`, error);
@ -324,7 +324,7 @@ const ApiManager = (function() {
try {
const apiKey = window.config?.apiKeys?.cryptoCompare || '';
let url;
if (resolution === 'day') {
url = `https://min-api.cryptocompare.com/data/v2/histohour?fsym=${coin}&tsym=USD&limit=24&api_key=${apiKey}`;
} else if (resolution === 'year') {
@ -351,7 +351,7 @@ const ApiManager = (function() {
await Promise.all(fetchPromises);
return results;
},
dispose: function() {
// Clear any pending requests or resources
rateLimiter.requestQueue = {};

View file

@ -19,7 +19,7 @@ const CacheManager = (function() {
];
const isCacheKey = (key) => {
return CACHE_KEY_PATTERNS.some(pattern => key.startsWith(pattern)) ||
return CACHE_KEY_PATTERNS.some(pattern => key.startsWith(pattern)) ||
key === 'coinGeckoOneLiner' ||
key === PRICES_CACHE_KEY;
};
@ -48,7 +48,7 @@ const CacheManager = (function() {
const ttlConfig = window.config?.cacheConfig?.ttlSettings || {};
return ttlConfig[resourceType] || window.config?.cacheConfig?.defaultTTL || defaults.defaultTTL;
},
set: function(key, value, resourceTypeOrCustomTtl = null) {
try {
this.cleanup();
@ -119,10 +119,10 @@ const CacheManager = (function() {
.filter(k => isCacheKey(k))
.sort((a, b) => memoryCache.get(a).timestamp - memoryCache.get(b).timestamp)
.slice(0, Math.floor(memoryCache.size * 0.2)); // Remove oldest 20%
keysToDelete.forEach(k => memoryCache.delete(k));
}
return true;
}
} catch (error) {
@ -194,7 +194,7 @@ const CacheManager = (function() {
memoryCache.delete(key);
}
}
return null;
} catch (error) {
console.error("Cache retrieval error:", error);
@ -286,7 +286,7 @@ const CacheManager = (function() {
.filter(key => isCacheKey(key))
.sort((a, b) => memoryCache.get(a).timestamp - memoryCache.get(b).timestamp)
.slice(0, Math.floor(memoryCache.size * 0.3)); // Remove oldest 30% during aggressive cleanup
keysToDelete.forEach(key => memoryCache.delete(key));
}
@ -327,7 +327,7 @@ const CacheManager = (function() {
Array.from(memoryCache.keys())
.filter(key => isCacheKey(key))
.forEach(key => memoryCache.delete(key));
console.log("Cache cleared successfully");
return true;
},
@ -368,7 +368,7 @@ const CacheManager = (function() {
let memoryCacheSize = 0;
let memoryCacheItems = 0;
let memoryCacheExpired = 0;
memoryCache.forEach((item, key) => {
if (isCacheKey(key)) {
memoryCacheItems++;
@ -381,7 +381,7 @@ const CacheManager = (function() {
}
}
});
return {
totalSizeMB: (totalSize / 1024 / 1024).toFixed(2),
itemCount,
@ -415,10 +415,10 @@ const CacheManager = (function() {
}
}
});
console.log(`Migrated ${migratedCount} items from memory cache to localStorage.`);
}
return {
available: storageAvailable,
type: storageAvailable ? 'localStorage' : 'memory'
@ -430,7 +430,7 @@ const CacheManager = (function() {
...cacheAPI,
setPrices: function(priceData, customTtl = null) {
return this.set(PRICES_CACHE_KEY, priceData,
return this.set(PRICES_CACHE_KEY, priceData,
customTtl || (typeof customTtl === 'undefined' ? 'prices' : null));
},
@ -447,7 +447,7 @@ const CacheManager = (function() {
const normalizedSymbol = symbol.toLowerCase();
return prices.value[normalizedSymbol] || null;
},
getCompatiblePrices: function(format) {
const prices = this.getPrices();
if (!prices || !prices.value) {
@ -464,7 +464,7 @@ const CacheManager = (function() {
.join(' ')
.toLowerCase()
.replace(' ', '-');
ratesFormat[coinKey] = {
usd: data.price || data.usd,
btc: data.price_btc || data.btc
@ -493,7 +493,7 @@ const CacheManager = (function() {
value: geckoFormat,
remainingTime: prices.remainingTime
};
default:
return prices;
}

View file

@ -111,8 +111,8 @@ const CleanupManager = (function() {
}
state.eventListeners = state.eventListeners.filter(
listener => !(listener.element === element &&
listener.type === type &&
listener => !(listener.element === element &&
listener.type === type &&
listener.handler === handler)
);
},
@ -224,10 +224,10 @@ const CleanupManager = (function() {
intervals: state.intervals.length,
animationFrames: state.animationFrames.length,
resources: state.resources.size,
total: state.eventListeners.length +
state.timeouts.length +
state.intervals.length +
state.animationFrames.length +
total: state.eventListeners.length +
state.timeouts.length +
state.intervals.length +
state.animationFrames.length +
state.resources.size
};
},

View file

@ -4,9 +4,9 @@ const ConfigManager = (function() {
};
function determineWebSocketPort() {
const wsPort =
window.ws_port ||
(typeof getWebSocketConfig === 'function' ? getWebSocketConfig().port : null) ||
const wsPort =
window.ws_port ||
(typeof getWebSocketConfig === 'function' ? getWebSocketConfig().port : null) ||
'11700';
return wsPort;
}
@ -17,10 +17,10 @@ const ConfigManager = (function() {
cacheDuration: 10 * 60 * 1000,
requestTimeout: 60000,
wsPort: selectedWsPort,
cacheConfig: {
defaultTTL: 10 * 60 * 1000,
ttlSettings: {
prices: 5 * 60 * 1000,
chart: 5 * 60 * 1000,
@ -34,7 +34,7 @@ const ConfigManager = (function() {
maxSizeBytes: 10 * 1024 * 1024,
maxItems: 200
},
fallbackTTL: 24 * 60 * 60 * 1000
},
@ -92,7 +92,7 @@ const ConfigManager = (function() {
'Bitcoin Cash': 'BCH',
'Dogecoin': 'DOGE'
},
nameToDisplayName: {
'Bitcoin': 'Bitcoin',
'Litecoin': 'Litecoin',
@ -164,13 +164,13 @@ const ConfigManager = (function() {
if (options) {
Object.assign(this, options);
}
if (window.CleanupManager) {
window.CleanupManager.registerResource('configManager', this, (mgr) => mgr.dispose());
}
this.utils = utils;
state.isInitialized = true;
console.log('ConfigManager initialized');
return this;
@ -205,7 +205,7 @@ const ConfigManager = (function() {
const lowerCoinName = typeof coinName === 'string' ? coinName.toLowerCase() : '';
return nameMap[lowerCoinName] || lowerCoinName;
},
coinMatches: function(offerCoin, filterCoin) {
if (!offerCoin || !filterCoin) return false;
@ -254,7 +254,7 @@ const ConfigManager = (function() {
get: function(path, defaultValue = null) {
const parts = path.split('.');
let current = this;
for (let i = 0; i < parts.length; i++) {
if (current === undefined || current === null) {
return defaultValue;
@ -376,12 +376,12 @@ const ConfigManager = (function() {
'firo': { usd: null, btc: null }
};
},
getCoinSymbol: function(fullName) {
return publicAPI.coinMappings?.nameToSymbol[fullName] || fullName;
}
};
return publicAPI;
})();

View file

@ -60,7 +60,7 @@ const IdentityManager = (function() {
const oldestEntries = [...state.cache.entries()]
.sort((a, b) => a[1].timestamp - b[1].timestamp)
.slice(0, Math.floor(state.config.maxCacheSize * 0.2));
oldestEntries.forEach(([key]) => {
state.cache.delete(key);
log(`Pruned cache entry for ${key}`);
@ -88,10 +88,10 @@ const IdentityManager = (function() {
const entriesToRemove = [...state.cache.entries()]
.sort((a, b) => a[1].timestamp - b[1].timestamp)
.slice(0, state.cache.size - maxSize);
entriesToRemove.forEach(([key]) => state.cache.delete(key));
log(`Limited cache size, removed ${entriesToRemove.length} entries`);
return entriesToRemove.length;
},
@ -138,11 +138,11 @@ const IdentityManager = (function() {
if (options) {
this.configure(options);
}
if (window.CleanupManager) {
window.CleanupManager.registerResource('identityManager', this, (mgr) => mgr.dispose());
}
log('IdentityManager initialized');
return this;
},

View file

@ -65,7 +65,7 @@ const MemoryManager = (function() {
const nodeCount = document.querySelectorAll('*').length;
console.log('DOM node count:', nodeCount);
if (window.CleanupManager) {
const counts = CleanupManager.getResourceCounts();
console.log('Managed resources:', counts);
@ -102,11 +102,11 @@ const MemoryManager = (function() {
state.cleanupInterval = setInterval(() => {
this.forceCleanup();
}, interval);
log('Auto-cleanup enabled every', interval/1000, 'seconds');
return true;
},
disableAutoCleanup: function() {
if (state.cleanupInterval) {
clearInterval(state.cleanupInterval);
@ -155,7 +155,7 @@ const MemoryManager = (function() {
return true;
},
setDebugMode: function(enabled) {
config.debug = Boolean(enabled);
return `Debug mode ${config.debug ? 'enabled' : 'disabled'}`;

View file

@ -30,13 +30,13 @@ const NetworkManager = (function() {
const publicAPI = {
initialize: function(options = {}) {
Object.assign(config, options);
window.addEventListener('online', this.handleOnlineStatus.bind(this));
window.addEventListener('offline', this.handleOfflineStatus.bind(this));
state.isOnline = navigator.onLine;
log(`Network status initialized: ${state.isOnline ? 'online' : 'offline'}`);
if (window.CleanupManager) {
window.CleanupManager.registerResource('networkManager', this, (mgr) => mgr.dispose());
}
@ -61,7 +61,7 @@ const NetworkManager = (function() {
log('Browser reports online status');
state.isOnline = true;
this.notifyHandlers('online');
if (state.reconnectTimer) {
this.scheduleReconnectRefresh();
}
@ -103,7 +103,7 @@ const NetworkManager = (function() {
state.reconnectTimer = null;
}
const delay = config.reconnectDelay * Math.pow(config.reconnectBackoff,
const delay = config.reconnectDelay * Math.pow(config.reconnectBackoff,
Math.min(state.reconnectAttempts, 5));
log(`Scheduling reconnection attempt in ${delay/1000} seconds`);
@ -145,7 +145,7 @@ const NetworkManager = (function() {
this.notifyHandlers('reconnected');
} else {
log('Backend still unavailable');
if (state.reconnectAttempts < config.maxReconnectAttempts) {
this.scheduleReconnectRefresh();
} else {
@ -157,7 +157,7 @@ const NetworkManager = (function() {
.catch(error => {
state.connectionTestInProgress = false;
log('Error during connection test:', error);
if (state.reconnectAttempts < config.maxReconnectAttempts) {
this.scheduleReconnectRefresh();
} else {
@ -210,7 +210,7 @@ const NetworkManager = (function() {
const handlerId = generateHandlerId();
state.eventHandlers[event][handlerId] = handler;
return handlerId;
},
@ -256,9 +256,9 @@ const NetworkManager = (function() {
window.removeEventListener('online', this.handleOnlineStatus);
window.removeEventListener('offline', this.handleOfflineStatus);
state.eventHandlers = {};
log('NetworkManager disposed');
}
};

View file

@ -15,9 +15,9 @@ const SummaryManager = (function() {
function updateElement(elementId, value) {
const element = document.getElementById(elementId);
if (!element) return false;
const safeValue = (value !== undefined && value !== null)
? value
const safeValue = (value !== undefined && value !== null)
? value
: (element.dataset.lastValue || 0);
element.dataset.lastValue = safeValue;
@ -32,8 +32,8 @@ const SummaryManager = (function() {
element.textContent = safeValue;
}
if (['offers-counter', 'bid-requests-counter', 'sent-bids-counter',
'recv-bids-counter', 'swaps-counter', 'network-offers-counter',
if (['offers-counter', 'bid-requests-counter', 'sent-bids-counter',
'recv-bids-counter', 'swaps-counter', 'network-offers-counter',
'watched-outputs-counter'].includes(elementId)) {
element.classList.remove('bg-blue-500', 'bg-gray-400');
element.classList.add(safeValue > 0 ? 'bg-blue-500' : 'bg-gray-400');
@ -57,7 +57,7 @@ const SummaryManager = (function() {
function updateUIFromData(data) {
if (!data) return;
updateElement('network-offers-counter', data.num_network_offers);
updateElement('offers-counter', data.num_sent_active_offers);
updateElement('sent-bids-counter', data.num_sent_active_bids);
@ -65,7 +65,7 @@ const SummaryManager = (function() {
updateElement('bid-requests-counter', data.num_available_bids);
updateElement('swaps-counter', data.num_swapping);
updateElement('watched-outputs-counter', data.num_watched_outputs);
const shutdownButtons = document.querySelectorAll('.shutdown-button');
shutdownButtons.forEach(button => {
button.setAttribute('data-active-swaps', data.num_swapping);
@ -83,7 +83,7 @@ const SummaryManager = (function() {
function cacheSummaryData(data) {
if (!data) return;
localStorage.setItem('summary_data_cache', JSON.stringify({
timestamp: Date.now(),
data: data
@ -92,24 +92,24 @@ const SummaryManager = (function() {
function getCachedSummaryData() {
let cachedData = null;
cachedData = localStorage.getItem('summary_data_cache');
if (!cachedData) return null;
const parsedCache = JSON.parse(cachedData);
const maxAge = 24 * 60 * 60 * 1000;
if (Date.now() - parsedCache.timestamp < maxAge) {
return parsedCache.data;
}
return null;
}
function fetchSummaryDataWithTimeout() {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), config.requestTimeout);
return fetch(config.summaryEndpoint, {
signal: controller.signal,
headers: {
@ -120,11 +120,11 @@ const SummaryManager = (function() {
})
.then(response => {
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.catch(error => {
@ -138,21 +138,21 @@ const SummaryManager = (function() {
webSocket.close();
}
const wsPort = window.config?.wsPort ||
const wsPort = window.config?.wsPort ||
(typeof determineWebSocketPort === 'function' ? determineWebSocketPort() : '11700');
const wsUrl = "ws://" + window.location.hostname + ":" + wsPort;
webSocket = new WebSocket(wsUrl);
webSocket.onopen = () => {
publicAPI.fetchSummaryData()
.then(() => {})
.catch(() => {});
};
webSocket.onmessage = (event) => {
let data;
try {
data = JSON.parse(event.data);
} catch (error) {
@ -161,18 +161,18 @@ const SummaryManager = (function() {
}
return;
}
if (data.event) {
publicAPI.fetchSummaryData()
.then(() => {})
.catch(() => {});
if (window.NotificationManager && typeof window.NotificationManager.handleWebSocketEvent === 'function') {
window.NotificationManager.handleWebSocketEvent(data);
}
}
};
webSocket.onclose = () => {
setTimeout(setupWebSocket, 5000);
};
@ -185,8 +185,8 @@ const SummaryManager = (function() {
template.innerHTML = document.querySelector('[id^="swapContainer"]')?.innerHTML || '';
document.body.appendChild(template);
}
if (!document.getElementById('swap-in-progress-green-template') &&
if (!document.getElementById('swap-in-progress-green-template') &&
document.querySelector('[id^="swapContainer"]')?.innerHTML) {
const greenTemplate = document.createElement('template');
greenTemplate.id = 'swap-in-progress-green-template';
@ -229,7 +229,7 @@ const SummaryManager = (function() {
if (window.WebSocketManager && typeof window.WebSocketManager.initialize === 'function') {
const wsManager = window.WebSocketManager;
if (!wsManager.isConnected()) {
wsManager.connect();
}
@ -239,7 +239,7 @@ const SummaryManager = (function() {
this.fetchSummaryData()
.then(() => {})
.catch(() => {});
if (window.NotificationManager && typeof window.NotificationManager.handleWebSocketEvent === 'function') {
window.NotificationManager.handleWebSocketEvent(data);
}
@ -302,7 +302,7 @@ const SummaryManager = (function() {
}
});
},
startRefreshTimer: function() {
startRefreshTimer();
},

View file

@ -26,14 +26,14 @@ const TooltipManager = (function() {
create(element, content, options = {}) {
if (!element) return null;
this.destroy(element);
if (this.tooltipElementsMap.size > this.maxTooltips * this.cleanupThreshold) {
const oldestEntries = Array.from(this.tooltipElementsMap.entries())
.sort((a, b) => a[1].timestamp - b[1].timestamp)
.slice(0, 20);
oldestEntries.forEach(([el]) => {
this.destroy(el);
});
@ -199,7 +199,7 @@ const TooltipManager = (function() {
instance[0].destroy();
} catch (e) {
console.warn('Error destroying tooltip:', e);
const tippyRoot = document.querySelector(`[data-for-tooltip-id="${id}"]`);
if (tippyRoot && tippyRoot.parentNode) {
tippyRoot.parentNode.removeChild(tippyRoot);
@ -209,7 +209,7 @@ const TooltipManager = (function() {
this.activeTooltips.delete(element);
this.tooltipElementsMap.delete(element);
element.removeAttribute('data-tooltip-trigger-id');
}
@ -355,7 +355,7 @@ const TooltipManager = (function() {
this.handleVisibilityChange = () => {
if (document.hidden) {
this.cleanup();
if (window.MemoryManager) {
window.MemoryManager.forceCleanup();
}
@ -365,7 +365,7 @@ const TooltipManager = (function() {
window.addEventListener('beforeunload', this.boundCleanup);
window.addEventListener('unload', this.boundCleanup);
document.addEventListener('visibilitychange', this.handleVisibilityChange);
if (window.CleanupManager) {
window.CleanupManager.registerResource('tooltipManager', this, (tm) => tm.dispose());
}
@ -471,7 +471,7 @@ const TooltipManager = (function() {
}
});
this.mutationObserver.observe(document.body, {
this.mutationObserver.observe(document.body, {
childList: true,
subtree: true
});
@ -497,7 +497,7 @@ const TooltipManager = (function() {
cancelAnimationFrame(id);
});
this.pendingAnimationFrames.clear();
if (this.mutationObserver) {
this.mutationObserver.disconnect();
this.mutationObserver = null;

View file

@ -37,7 +37,7 @@ const WalletManager = (function() {
'Decred': 'DCR',
'Bitcoin Cash': 'BCH'
},
coingeckoIds: {
'BTC': 'btc',
'PART': 'part',
@ -51,7 +51,7 @@ const WalletManager = (function() {
'DCR': 'dcr',
'BCH': 'bch'
},
shortNames: {
'Bitcoin': 'BTC',
'Particl': 'PART',
@ -99,9 +99,9 @@ const WalletManager = (function() {
try {
const processedData = {};
const currentSource = config.priceSource.primary;
const shouldIncludeWow = currentSource === 'coingecko.com';
const coinsToFetch = Object.values(coinData.symbols)
.filter(symbol => shouldIncludeWow || symbol !== 'WOW')
.map(symbol => coinData.coingeckoIds[symbol] || symbol.toLowerCase())
@ -171,8 +171,8 @@ const WalletManager = (function() {
lastError = error;
console.error(`Price fetch attempt ${attempt + 1} failed:`, error);
if (attempt === config.maxRetries - 1 &&
config.priceSource.fallback &&
if (attempt === config.maxRetries - 1 &&
config.priceSource.fallback &&
config.priceSource.fallback !== config.priceSource.primary) {
const temp = config.priceSource.primary;
config.priceSource.primary = config.priceSource.fallback;
@ -269,14 +269,14 @@ const WalletManager = (function() {
}
const coinId = coinName.toLowerCase().replace(' ', '-');
if (!prices[coinId]) {
return;
}
const price = prices[coinId]?.usd || parseFloat(localStorage.getItem(`${coinId}-price`) || '0');
if (!price) return;
const usdValue = (amount * price).toFixed(2);
if (coinName === 'Particl') {
@ -300,7 +300,7 @@ const WalletManager = (function() {
}
let usdEl = null;
const flexContainer = el.closest('.flex');
if (flexContainer) {
const nextFlex = flexContainer.nextElementSibling;
@ -384,7 +384,7 @@ const WalletManager = (function() {
return false;
}
}
function updateTotalValues(totalUsd, btcPrice) {
const totalUsdEl = document.getElementById('total-usd-value');
if (totalUsdEl) {
@ -439,7 +439,7 @@ const WalletManager = (function() {
const eyeIcon = document.querySelector("#hide-usd-amount-toggle svg");
if (eyeIcon) {
eyeIcon.innerHTML = isVisible ?
eyeIcon.innerHTML = isVisible ?
'<path d="M23.444,10.239C21.905,8.062,17.708,3,12,3S2.1,8.062,.555,10.24a3.058,3.058,0,0,0,0,3.52h0C2.1,15.938,6.292,21,12,21s9.905-5.062,11.445-7.24A3.058,3.058,0,0,0,23.444,10.239ZM12,17a5,5,0,1,1,5-5A5,5,0,0,1,12,17Z"></path>' :
'<path d="M23.444,10.239a22.936,22.936,0,0,0-2.492-2.948l-4.021,4.021A5.026,5.026,0,0,1,17,12a5,5,0,0,1-5,5,5.026,5.026,0,0,1-.688-.069L8.055,20.188A10.286,10.286,0,0,0,12,21c5.708,0,9.905-5.062,11.445-7.24A3.058,3.058,0,0,0,23.444,10.239Z"></path><path d="M12,3C6.292,3,2.1,8.062,.555,10.24a3.058,3.058,0,0,0,0,3.52h0a21.272,21.272,0,0,0,4.784,4.9l3.124-3.124a5,5,0,0,1,7.071-7.072L8.464,15.536l10.2-10.2A11.484,11.484,0,0,0,12,3Z"></path><path data-color="color-2" d="M1,24a1,1,0,0,1-.707-1.707l22-22a1,1,0,0,1,1.414,1.414l-22,22A1,1,0,0,1,1,24Z"></path>';
}
@ -500,7 +500,7 @@ const WalletManager = (function() {
document.querySelectorAll('.coinname-value').forEach(el => {
el.textContent = '****';
});
document.querySelectorAll('.usd-value').forEach(el => {
el.textContent = '****';
});
@ -542,7 +542,7 @@ const WalletManager = (function() {
}
state.lastUpdateTime = parseInt(localStorage.getItem(stateKeys.lastUpdate) || '0');
state.isWalletsPage = document.querySelector('.wallet-list') !== null ||
state.isWalletsPage = document.querySelector('.wallet-list') !== null ||
window.location.pathname.includes('/wallets');
document.querySelectorAll('.usd-value').forEach(el => {
@ -553,7 +553,7 @@ const WalletManager = (function() {
});
storeOriginalValues();
if (localStorage.getItem('balancesVisible') === null) {
localStorage.setItem('balancesVisible', 'true');
}
@ -581,7 +581,7 @@ const WalletManager = (function() {
state.initialized = true;
console.log('WalletManager initialized');
return this;
},
@ -606,7 +606,7 @@ const WalletManager = (function() {
if (fallbackSource) {
config.priceSource.fallback = fallbackSource;
}
return this;
},

View file

@ -43,12 +43,12 @@ const WebSocketManager = (function() {
wsPort = window.ws_port.toString();
return wsPort;
}
if (typeof getWebSocketConfig === 'function') {
const wsConfig = getWebSocketConfig();
wsPort = (wsConfig.port || wsConfig.fallbackPort || '11700').toString();
return wsPort;
}
}
wsPort = '11700';
return wsPort;
@ -62,14 +62,14 @@ const WebSocketManager = (function() {
startHealthCheck();
log('WebSocketManager initialized with options:', options);
if (window.CleanupManager) {
window.CleanupManager.registerResource('webSocketManager', this, (mgr) => mgr.dispose());
}
return this;
},
connect: function() {
if (state.isConnecting || state.isIntentionallyClosed) {
log('Connection attempt blocked - already connecting or intentionally closed');
@ -87,7 +87,7 @@ const WebSocketManager = (function() {
try {
const wsPort = determineWebSocketPort();
if (!wsPort) {
state.isConnecting = false;
return false;
@ -129,7 +129,7 @@ const WebSocketManager = (function() {
log('Cannot send message - not connected');
return false;
}
try {
ws.send(JSON.stringify(message));
return true;
@ -143,13 +143,13 @@ const WebSocketManager = (function() {
if (!state.messageHandlers[type]) {
state.messageHandlers[type] = {};
}
const handlerId = generateHandlerId();
state.messageHandlers[type][handlerId] = handler;
return handlerId;
},
removeMessageHandler: function(type, handlerId) {
if (state.messageHandlers[type] && state.messageHandlers[type][handlerId]) {
delete state.messageHandlers[type][handlerId];
@ -158,7 +158,7 @@ const WebSocketManager = (function() {
cleanup: function() {
log('Cleaning up WebSocket resources');
clearTimeout(state.connectTimeout);
stopHealthCheck();
@ -211,11 +211,11 @@ const WebSocketManager = (function() {
resume: function() {
log('WebSocketManager resumed');
state.isIntentionallyClosed = false;
if (!this.isConnected()) {
this.connect();
}
startHealthCheck();
}
};
@ -264,16 +264,16 @@ const WebSocketManager = (function() {
log('WebSocket closed:', event);
state.isConnecting = false;
window.ws = null;
if (typeof updateConnectionStatus === 'function') {
updateConnectionStatus('disconnected');
}
notifyHandlers('disconnect', {
code: event.code,
reason: event.reason
notifyHandlers('disconnect', {
code: event.code,
reason: event.reason
});
if (!state.isIntentionallyClosed) {
handleReconnect();
}
@ -292,12 +292,12 @@ const WebSocketManager = (function() {
document.addEventListener('visibilitychange', visibilityChangeHandler);
state.listeners.visibilityChange = visibilityChangeHandler;
}
function handlePageHidden() {
log('Page hidden');
state.isPageHidden = true;
stopHealthCheck();
if (ws && ws.readyState === WebSocket.OPEN) {
state.isIntentionallyClosed = true;
ws.close(1000, 'Page hidden');
@ -308,7 +308,7 @@ const WebSocketManager = (function() {
log('Page visible');
state.isPageHidden = false;
state.isIntentionallyClosed = false;
setTimeout(() => {
if (!publicAPI.isConnected()) {
publicAPI.connect();
@ -323,7 +323,7 @@ const WebSocketManager = (function() {
performHealthCheck();
}, 30000);
}
function stopHealthCheck() {
if (state.healthCheckInterval) {
clearInterval(state.healthCheckInterval);
@ -340,7 +340,7 @@ const WebSocketManager = (function() {
const now = Date.now();
const lastCheck = state.lastHealthCheck;
if (lastCheck && (now - lastCheck) > 60000) {
log('Health check failed - too long since last check');
handleReconnect();
@ -401,10 +401,10 @@ const WebSocketManager = (function() {
function cleanup() {
log('Cleaning up WebSocket resources');
clearTimeout(state.connectTimeout);
stopHealthCheck();
if (state.reconnectTimeout) {
clearTimeout(state.reconnectTimeout);
state.reconnectTimeout = null;

View file

@ -61,7 +61,7 @@ const Ajax = {
if (xhr.status === 200) {
if (onSuccess) {
try {
const response = xhr.responseText.startsWith('{') ?
const response = xhr.responseText.startsWith('{') ?
JSON.parse(xhr.responseText) : xhr.responseText;
onSuccess(response);
} catch (e) {
@ -153,10 +153,10 @@ const RateManager = {
const params = 'coin_from=' + selectedCoin + '&coin_to=' + coinTo;
Ajax.post('/json/rates', params,
Ajax.post('/json/rates', params,
(response) => {
if (ratesDisplay) {
ratesDisplay.innerHTML = typeof response === 'string' ?
ratesDisplay.innerHTML = typeof response === 'string' ?
response : '<pre><code>' + JSON.stringify(response, null, ' ') + '</code></pre>';
}
},
@ -167,7 +167,7 @@ const RateManager = {
}
);
},
getRateInferred: (event) => {
if (event) event.preventDefault();
@ -180,12 +180,12 @@ const RateManager = {
return;
}
const params = 'coin_from=' + encodeURIComponent(coinFrom) +
const params = 'coin_from=' + encodeURIComponent(coinFrom) +
'&coin_to=' + encodeURIComponent(coinTo);
DOM.setValue('rate', 'Loading...');
Ajax.post('/json/rates', params,
Ajax.post('/json/rates', params,
(response) => {
if (response.coingecko && response.coingecko.rate_inferred) {
DOM.setValue('rate', response.coingecko.rate_inferred);
@ -213,7 +213,7 @@ const RateManager = {
swapType: DOM.get('swap_type')
};
if (!elements.coinFrom || !elements.coinTo ||
if (!elements.coinFrom || !elements.coinTo ||
!elements.amtFrom || !elements.amtTo || !elements.rate) {
console.log('Required elements for setRate not found');
return;
@ -225,7 +225,7 @@ const RateManager = {
amtFrom: elements.amtFrom.value,
amtTo: elements.amtTo.value,
rate: elements.rate.value,
lockRate: elements.rate.value == '' ? false :
lockRate: elements.rate.value == '' ? false :
(elements.rateLock ? elements.rateLock.checked : false)
};
@ -236,8 +236,8 @@ const RateManager = {
if (elements.swapType) {
SwapTypeManager.setSwapTypeEnabled(
values.coinFrom,
values.coinTo,
values.coinFrom,
values.coinTo,
elements.swapType
);
}
@ -248,8 +248,8 @@ const RateManager = {
let params = 'coin_from=' + values.coinFrom + '&coin_to=' + values.coinTo;
if (valueChanged == 'rate' ||
(values.lockRate && valueChanged == 'amt_from') ||
if (valueChanged == 'rate' ||
(values.lockRate && valueChanged == 'amt_from') ||
(values.amtTo == '' && valueChanged == 'amt_from')) {
if (values.rate == '' || (values.amtFrom == '' && values.amtTo == '')) {
@ -274,7 +274,7 @@ const RateManager = {
params += '&amt_from=' + values.amtFrom + '&amt_to=' + values.amtTo;
}
Ajax.post('/json/rate', params,
Ajax.post('/json/rate', params,
(response) => {
if (response.hasOwnProperty('rate')) {
DOM.setValue('rate', response.rate);
@ -314,13 +314,13 @@ const SwapTypeManager = {
coinFrom = String(coinFrom);
coinTo = String(coinTo);
if (SwapTypeManager.adaptor_sig_only_coins.includes(coinFrom) ||
if (SwapTypeManager.adaptor_sig_only_coins.includes(coinFrom) ||
SwapTypeManager.adaptor_sig_only_coins.includes(coinTo)) {
swapTypeElement.disabled = true;
swapTypeElement.value = 'xmr_swap';
makeHidden = true;
swapTypeElement.classList.add('select-disabled');
} else if (SwapTypeManager.secret_hash_only_coins.includes(coinFrom) ||
} else if (SwapTypeManager.secret_hash_only_coins.includes(coinFrom) ||
SwapTypeManager.secret_hash_only_coins.includes(coinTo)) {
swapTypeElement.disabled = true;
swapTypeElement.value = 'seller_first';
@ -426,7 +426,7 @@ const UIEnhancer = {
const name = selectedOption.textContent.trim();
selectCache[select.id] = { image, name };
}
function setSelectData(select) {
if (!select || !select.options || select.selectedIndex === undefined) return;
@ -457,9 +457,9 @@ const UIEnhancer = {
const options = select.querySelectorAll('option');
const selectIcon = select.parentElement?.querySelector('.select-icon');
const selectImage = select.parentElement?.querySelector('.select-image');
if (!options || !selectIcon || !selectImage) return;
options.forEach(option => {
const image = option.getAttribute('data-image');
if (image) {
@ -476,7 +476,7 @@ const UIEnhancer = {
setSelectData(select);
Storage.setRaw(select.name, select.value);
});
setSelectData(select);
selectIcon.style.display = 'none';
selectImage.style.display = 'none';

View file

@ -145,7 +145,7 @@ const api = {
const apiResponse = await Api.fetchCoinGeckoData({
coinGecko: window.config.getAPIKeys().coinGecko
});
if (!apiResponse || !apiResponse.rates) {
if (fallbackData) {
return fallbackData;
@ -174,7 +174,7 @@ const api = {
const wowResponse = await Api.fetchCoinPrices("wownero", {
coinGecko: window.config.getAPIKeys().coinGecko
});
if (wowResponse && wowResponse.rates && wowResponse.rates.wownero) {
transformedData['wow'] = {
current_price: wowResponse.rates.wownero,
@ -189,9 +189,9 @@ const api = {
console.error('Error fetching WOW price:', wowError);
}
const missingCoins = window.config.coins.filter(coin =>
!transformedData[coin.symbol.toLowerCase()] &&
fallbackData &&
const missingCoins = window.config.coins.filter(coin =>
!transformedData[coin.symbol.toLowerCase()] &&
fallbackData &&
fallbackData[coin.symbol.toLowerCase()]
);
@ -203,11 +203,11 @@ const api = {
});
CacheManager.set(cacheKey, transformedData, 'prices');
if (NetworkManager.getReconnectAttempts() > 0) {
NetworkManager.resetReconnectAttempts();
}
return transformedData;
} catch (error) {
console.error('Error fetching coin data:', error);
@ -250,8 +250,8 @@ const api = {
}
const historicalData = await Api.fetchHistoricalData(
coinSymbols,
window.config.currentResolution,
coinSymbols,
window.config.currentResolution,
{
cryptoCompare: window.config.getAPIKeys().cryptoCompare
}
@ -260,7 +260,7 @@ const api = {
Object.keys(historicalData).forEach(coin => {
if (historicalData[coin]) {
results[coin] = historicalData[coin];
const cacheKey = `historical_${coin}_${window.config.currentResolution}`;
CacheManager.set(cacheKey, historicalData[coin], 'historical');
}
@ -279,7 +279,7 @@ const api = {
results[coin] = cachedData.value;
}
}
return results;
}
},
@ -317,7 +317,7 @@ const rateLimiter = {
try {
await this.requestQueue[apiName];
const executeRequest = async () => {
const waitTime = this.getWaitTime(apiName);
if (waitTime > 0) {
@ -335,7 +335,7 @@ const rateLimiter = {
return this.queueRequest(apiName, requestFn, retryCount + 1);
}
if ((error.message.includes('timeout') || error.name === 'NetworkError') &&
if ((error.message.includes('timeout') || error.name === 'NetworkError') &&
retryCount < this.retryDelays.length) {
const delay = this.retryDelays[retryCount];
logger.warn(`Request failed, retrying in ${delay/1000} seconds...`);
@ -350,12 +350,12 @@ const rateLimiter = {
this.requestQueue[apiName] = executeRequest();
return await this.requestQueue[apiName];
} catch (error) {
if (error.message.includes('429') ||
error.message.includes('timeout') ||
if (error.message.includes('429') ||
error.message.includes('timeout') ||
error.name === 'NetworkError') {
NetworkManager.handleNetworkError(error);
const cachedData = CacheManager.get(`coinData_${apiName}`);
if (cachedData) {
return cachedData.value;
@ -375,7 +375,7 @@ const ui = {
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)}`;
}
@ -490,8 +490,8 @@ const ui = {
if (priceChange === null || priceChange === undefined) {
container.innerHTML = 'N/A';
} else {
container.innerHTML = priceChange >= 0 ?
ui.positivePriceChangeHTML(priceChange) :
container.innerHTML = priceChange >= 0 ?
ui.positivePriceChangeHTML(priceChange) :
ui.negativePriceChangeHTML(priceChange);
}
}
@ -504,7 +504,7 @@ const ui = {
lastRefreshedElement.textContent = `Last Refreshed: ${formattedTime}`;
}
},
updateConnectionStatus: () => {
const statusElement = document.getElementById('connection-status');
if (statusElement) {
@ -599,12 +599,12 @@ const ui = {
NetworkManager.manualReconnect();
};
const buttonContainer = errorOverlay.querySelector('.button-container') ||
const buttonContainer = errorOverlay.querySelector('.button-container') ||
document.createElement('div');
buttonContainer.className = "button-container mt-4";
buttonContainer.innerHTML = '';
buttonContainer.appendChild(reconnectBtn);
if (!errorOverlay.querySelector('.button-container')) {
errorOverlay.querySelector('div').appendChild(buttonContainer);
}
@ -701,7 +701,7 @@ const chartModule = {
const gradient = ctx.createLinearGradient(0, 0, 0, 400);
gradient.addColorStop(0, 'rgba(77, 132, 240, 0.2)');
gradient.addColorStop(1, 'rgba(77, 132, 240, 0)');
chartModule.chart = new Chart(ctx, {
type: 'line',
data: {
@ -897,7 +897,7 @@ const chartModule = {
}
rawDataPoints.sort((a, b) => a.time - b.time);
let preparedData = [];
if (window.config.currentResolution === 'day') {
@ -918,7 +918,7 @@ const chartModule = {
closestPoint = point;
}
}
if (closestPoint) {
preparedData.push({
x: hourUnix,
@ -940,7 +940,7 @@ const chartModule = {
y: point.close
}));
}
if (preparedData.length === 0 && rawDataPoints.length > 0) {
preparedData = rawDataPoints.map(point => ({
x: point.time,
@ -965,7 +965,7 @@ const chartModule = {
if (data.length > 0) {
const closestDataPoint = data.reduce((prev, curr) =>
Math.abs(new Date(curr.x).getTime() - targetTime.getTime()) <
Math.abs(new Date(curr.x).getTime() - targetTime.getTime()) <
Math.abs(new Date(prev.x).getTime() - targetTime.getTime()) ? curr : prev
, data[0]);
hourlyData.push({
@ -989,7 +989,7 @@ const chartModule = {
}
chartModule.loadStartTime = Date.now();
const cacheKey = `chartData_${coinSymbol}_${window.config.currentResolution}`;
let cachedData = !forceRefresh ? CacheManager.get(cacheKey) : null;
const cachedData = !forceRefresh ? CacheManager.get(cacheKey) : null;
let data;
if (cachedData && Object.keys(cachedData.value).length > 0) {
data = cachedData.value;
@ -1001,7 +1001,7 @@ const chartModule = {
const allData = await api.fetchHistoricalDataXHR([coinSymbol]);
data = allData[coinSymbol];
if (!data || Object.keys(data).length === 0) {
throw new Error(`No data returned for ${coinSymbol}`);
}
@ -1009,7 +1009,7 @@ const chartModule = {
CacheManager.set(cacheKey, data, 'chart');
} catch (error) {
NetworkManager.handleNetworkError(error);
if (error.message.includes('429') && currentChartData.length > 0) {
console.warn(`Rate limit hit for ${coinSymbol}, maintaining current chart`);
chartModule.hideChartLoader();
@ -1041,7 +1041,7 @@ const chartModule = {
chartModule.chart.options.scales.x.time.unit = 'hour';
} else {
const resolution = window.config.chartConfig.resolutions[window.config.currentResolution];
chartModule.chart.options.scales.x.time.unit =
chartModule.chart.options.scales.x.time.unit =
resolution && resolution.interval === 'hourly' ? 'hour' :
window.config.currentResolution === 'year' ? 'month' : 'day';
}
@ -1086,7 +1086,7 @@ const chartModule = {
loader.classList.add('hidden');
chart.classList.remove('hidden');
},
cleanup: function() {
this.destroyChart();
this.currentCoin = null;
@ -1181,7 +1181,7 @@ const app = {
0
);
});
return app;
},
@ -1223,13 +1223,13 @@ const app = {
}
}
},
loadAllCoinData: async function() {
try {
if (!NetworkManager.isOnline()) {
throw new Error('Network is offline');
}
const allCoinData = await api.fetchCoinGeckoDataXHR();
if (allCoinData.error) {
throw new Error(allCoinData.error);
@ -1242,7 +1242,7 @@ const app = {
for (const coin of window.config.coins) {
const coinData = allCoinData[coin.symbol.toLowerCase()];
if (coinData) {
coinData.displayName = coin.displayName || coin.symbol;
@ -1409,7 +1409,7 @@ const app = {
const lastGeckoRequest = rateLimiter.lastRequestTime['coingecko'] || 0;
const timeSinceLastRequest = Date.now() - lastGeckoRequest;
const waitTime = Math.max(0, rateLimiter.minRequestInterval.coingecko - timeSinceLastRequest);
if (waitTime > 0) {
const seconds = Math.ceil(waitTime / 1000);
ui.displayErrorMessage(`Rate limit: Please wait ${seconds} seconds before refreshing`);
@ -1480,7 +1480,7 @@ const app = {
if (cachedData && cachedData.value && cachedData.value.total_volume) {
coinData.total_volume = cachedData.value.total_volume;
}
if (cachedData && cachedData.value && cachedData.value.price_change_percentage_24h &&
if (cachedData && cachedData.value && cachedData.value.price_change_percentage_24h &&
!coinData.price_change_percentage_24h) {
coinData.price_change_percentage_24h = cachedData.value.price_change_percentage_24h;
}
@ -1541,7 +1541,7 @@ const app = {
let countdown = 10;
ui.displayErrorMessage(`Refresh failed: ${error.message}. Please try again later. (${countdown}s)`);
const countdownInterval = setInterval(() => {
countdown--;
if (countdown > 0) {
@ -1652,7 +1652,7 @@ const app = {
if (!NetworkManager.isOnline()) {
throw new Error('Network is offline');
}
const response = await Api.fetchCoinPrices("bitcoin");
if (response && response.rates && response.rates.bitcoin) {
@ -1715,7 +1715,7 @@ resolutionButtons.forEach(button => {
button.addEventListener('click', () => {
const resolution = button.id.split('-')[1];
const currentCoin = chartModule.currentCoin;
if (currentCoin !== 'WOW' || resolution === 'day') {
window.config.currentResolution = resolution;
chartModule.updateChart(currentCoin, true);
@ -1726,12 +1726,12 @@ resolutionButtons.forEach(button => {
function cleanup() {
console.log('Starting cleanup process');
try {
if (window.MemoryManager) {
MemoryManager.forceCleanup();
}
if (chartModule) {
CleanupManager.registerResource('chartModule', chartModule, (cm) => {
cm.cleanup();
@ -1752,7 +1752,7 @@ function cleanup() {
const cleanupCounts = CleanupManager.clearAll();
console.log('All resources cleaned up:', cleanupCounts);
} catch (error) {
console.error('Error during cleanup:', error);
CleanupManager.clearAll();
@ -1801,7 +1801,7 @@ document.addEventListener('DOMContentLoaded', () => {
NetworkManager.initialize({
connectionTestEndpoint: '/json',
connectionTestTimeout: 3000,
reconnectDelay: 5000,
reconnectDelay: 5000,
maxReconnectAttempts: 5
});
window.networkManagerInitialized = true;

View file

@ -85,7 +85,7 @@ const getStatusClass = (status, tx_a, tx_b) => {
const getTxStatusClass = (status) => {
if (!status || status === 'None') return 'text-gray-400';
if (status.includes('Complete') || status.includes('Confirmed')) {
return 'text-green-500';
}
@ -545,12 +545,12 @@ async function updateSwapsTable(options = {}) {
const data = await response.json();
//console.log('Received swap data:', data);
state.swapsData = Array.isArray(data)
state.swapsData = Array.isArray(data)
? data.filter(swap => {
const isActive = isActiveSwap(swap);
//console.log(`Swap ${swap.bid_id}: ${isActive ? 'Active' : 'Inactive'}`, swap.bid_state);
return isActive;
})
})
: [];
//console.log('Filtered active swaps:', state.swapsData);
@ -570,7 +570,7 @@ async function updateSwapsTable(options = {}) {
}
const totalPages = Math.ceil(state.swapsData.length / PAGE_SIZE);
if (resetPage && state.swapsData.length > 0) {
state.currentPage = 1;
}
@ -631,18 +631,18 @@ async function updateSwapsTable(options = {}) {
function isActiveSwap(swap) {
const activeStates = [
'InProgress',
'Accepted',
'Delaying',
'InProgress',
'Accepted',
'Delaying',
'Auto accept delay',
'Request accepted',
//'Received',
'Script coin locked',
'Script coin locked',
'Scriptless coin locked',
'Script coin lock released',
'SendingInitialTx',
'SendingInitialTx',
'SendingPaymentTx',
'Exchanged script lock tx sigs msg',

View file

@ -62,7 +62,7 @@
this._handleOutsideClick = this._handleOutsideClick.bind(this);
dropdownInstances.push(this);
this.init();
}
@ -73,7 +73,7 @@
this._targetEl.style.position = 'fixed';
this._targetEl.style.zIndex = '40';
this._targetEl.classList.add('dropdown-menu');
this._setupEventListeners();
this._initialized = true;
}
@ -120,8 +120,8 @@
}
_handleOutsideClick(e) {
if (this._visible &&
!this._targetEl.contains(e.target) &&
if (this._visible &&
!this._targetEl.contains(e.target) &&
!this._triggerEl.contains(e.target)) {
this.hide();
}