mirror of
https://github.com/basicswap/basicswap.git
synced 2025-04-06 14:27:30 +00:00
js: eslints
This commit is contained in:
parent
d15466f656
commit
eeade736a4
18 changed files with 284 additions and 284 deletions
basicswap/static/js
bids_sentreceived.jsbids_sentreceived_export.jsglobal.js
modules
api-manager.jscache-manager.jscleanup-manager.jsconfig-manager.jsidentity-manager.jsmemory-manager.jsnetwork-manager.jssummary-manager.jstooltips-manager.jswallet-manager.jswebsocket-manager.js
new_offer.jspricechart.jsswaps_in_progress.jsui
|
@ -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';
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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 = {};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
},
|
||||
|
|
|
@ -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;
|
||||
})();
|
||||
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
|
|
|
@ -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'}`;
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
},
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue