mirror of
https://github.com/basicswap/basicswap.git
synced 2025-01-05 10:19:25 +00:00
ui: Removed %, small fix.
This commit is contained in:
parent
1763dec981
commit
0ca5aefc12
1 changed files with 11 additions and 178 deletions
|
@ -64,7 +64,7 @@
|
||||||
<h4 class="text-xl font-bold dark:text-white">{{ w.name }}
|
<h4 class="text-xl font-bold dark:text-white">{{ w.name }}
|
||||||
<span class="inline-block font-medium text-xs text-gray-500 dark:text-white">({{ w.ticker }})</span>
|
<span class="inline-block font-medium text-xs text-gray-500 dark:text-white">({{ w.ticker }})</span>
|
||||||
</h4>
|
</h4>
|
||||||
<p class="text-xs text-gray-500 dark:text-gray-200">Version: {{ w.version }} {% if w.updating %} <span class="inline-block py-1 px-2 rounded-full bg-blue-100 text-xs text-black-500 dark:bg-gray-700 dark:hover:bg-gray-700">Updating..</span></p>
|
<p class="text-xs text-gray-500 dark:text-gray-200">Version: {{ w.version }} {% if w.updating %} <span class="hidden inline-block py-1 px-2 rounded-full bg-blue-100 text-xs text-black-500 dark:bg-gray-700 dark:hover:bg-gray-700">Updating..</span></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="p-6 bg-coolGray-100 dark:bg-gray-600">
|
<div class="p-6 bg-coolGray-100 dark:bg-gray-600">
|
||||||
|
@ -207,23 +207,17 @@
|
||||||
{% include 'footer.html' %}
|
{% include 'footer.html' %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Config
|
|
||||||
const CONFIG = {
|
const CONFIG = {
|
||||||
MAX_RETRIES: 3,
|
MAX_RETRIES: 3,
|
||||||
BASE_DELAY: 1000,
|
BASE_DELAY: 1000,
|
||||||
CACHE_EXPIRATION: 5 * 60 * 1000, // 5 minutes
|
CACHE_EXPIRATION: 5 * 60 * 1000,
|
||||||
PRICE_UPDATE_INTERVAL: 5 * 60 * 1000, // 5 minutes
|
PRICE_UPDATE_INTERVAL: 5 * 60 * 1000,
|
||||||
API_TIMEOUT: 30000,
|
API_TIMEOUT: 30000,
|
||||||
DEBOUNCE_DELAY: 500,
|
DEBOUNCE_DELAY: 500,
|
||||||
CACHE_MIN_INTERVAL: 60 * 1000, // Minimum 1 minute between API calls
|
CACHE_MIN_INTERVAL: 60 * 1000
|
||||||
MAX_PERCENTAGE_CHANGE: 50, // Max reasonable percentage change (50%)
|
|
||||||
MIN_VALUE_FOR_PERCENTAGE: 0.01 // Minimum value to calculate percentage changes
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const STATE_KEYS = {
|
const STATE_KEYS = {
|
||||||
PERCENTAGE_CHANGE: 'last-percentage-change',
|
|
||||||
PERCENTAGE_COLOR: 'percentage-change-color',
|
|
||||||
PERCENTAGE_ICON: 'percentage-change-icon',
|
|
||||||
LAST_UPDATE: 'last-update-time',
|
LAST_UPDATE: 'last-update-time',
|
||||||
PREVIOUS_TOTAL: 'previous-total-usd',
|
PREVIOUS_TOTAL: 'previous-total-usd',
|
||||||
CURRENT_TOTAL: 'current-total-usd',
|
CURRENT_TOTAL: 'current-total-usd',
|
||||||
|
@ -259,65 +253,46 @@ const SHORT_NAMES = {
|
||||||
'Bitcoin Cash': 'BCH'
|
'Bitcoin Cash': 'BCH'
|
||||||
};
|
};
|
||||||
|
|
||||||
// Cache
|
|
||||||
class Cache {
|
class Cache {
|
||||||
constructor(expirationTime) {
|
constructor(expirationTime) {
|
||||||
console.log(`Initializing cache with ${expirationTime/1000} seconds expiration time`);
|
|
||||||
this.data = null;
|
this.data = null;
|
||||||
this.timestamp = null;
|
this.timestamp = null;
|
||||||
this.expirationTime = expirationTime;
|
this.expirationTime = expirationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
isValid() {
|
isValid() {
|
||||||
console.log('Checking cache validity...');
|
return Boolean(
|
||||||
const isValid = Boolean(
|
|
||||||
this.data &&
|
this.data &&
|
||||||
this.timestamp &&
|
this.timestamp &&
|
||||||
(Date.now() - this.timestamp < this.expirationTime)
|
(Date.now() - this.timestamp < this.expirationTime)
|
||||||
);
|
);
|
||||||
console.log(`Cache validity check result: ${isValid}`);
|
|
||||||
if (this.timestamp) {
|
|
||||||
const age = (Date.now() - this.timestamp) / 1000;
|
|
||||||
console.log(`Cache age: ${age.toFixed(1)} seconds`);
|
|
||||||
}
|
|
||||||
return isValid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set(data) {
|
set(data) {
|
||||||
console.log('Updating cache with new data');
|
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.timestamp = Date.now();
|
this.timestamp = Date.now();
|
||||||
console.log('Cache updated successfully');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get() {
|
get() {
|
||||||
console.log('Attempting to retrieve data from cache');
|
|
||||||
if (this.isValid()) {
|
if (this.isValid()) {
|
||||||
console.log('Returning valid cached data');
|
|
||||||
return this.data;
|
return this.data;
|
||||||
}
|
}
|
||||||
console.log('No valid cached data available');
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
console.log('Clearing cache data');
|
|
||||||
this.data = null;
|
this.data = null;
|
||||||
this.timestamp = null;
|
this.timestamp = null;
|
||||||
console.log('Cache cleared successfully');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// API
|
|
||||||
class ApiClient {
|
class ApiClient {
|
||||||
constructor() {
|
constructor() {
|
||||||
console.log('Initializing API client');
|
|
||||||
this.cache = new Cache(CONFIG.CACHE_EXPIRATION);
|
this.cache = new Cache(CONFIG.CACHE_EXPIRATION);
|
||||||
this.lastFetchTime = 0;
|
this.lastFetchTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
makeRequest(url, headers = {}) {
|
makeRequest(url, headers = {}) {
|
||||||
console.log(`Making API request to: ${url}`);
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
xhr.open('POST', '/json/readurl');
|
xhr.open('POST', '/json/readurl');
|
||||||
|
@ -325,38 +300,30 @@ class ApiClient {
|
||||||
xhr.timeout = CONFIG.API_TIMEOUT;
|
xhr.timeout = CONFIG.API_TIMEOUT;
|
||||||
|
|
||||||
xhr.ontimeout = () => {
|
xhr.ontimeout = () => {
|
||||||
console.error('API request timed out');
|
|
||||||
reject(new Error('Request timed out'));
|
reject(new Error('Request timed out'));
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.onload = () => {
|
xhr.onload = () => {
|
||||||
if (xhr.status === 200) {
|
if (xhr.status === 200) {
|
||||||
console.log('Received 200 response from API');
|
|
||||||
try {
|
try {
|
||||||
const response = JSON.parse(xhr.responseText);
|
const response = JSON.parse(xhr.responseText);
|
||||||
if (response.Error) {
|
if (response.Error) {
|
||||||
console.error('Error in API response:', response.Error);
|
|
||||||
reject(new Error(response.Error));
|
reject(new Error(response.Error));
|
||||||
} else {
|
} else {
|
||||||
console.log('Successfully parsed API response');
|
|
||||||
resolve(response);
|
resolve(response);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to parse API response:', error);
|
|
||||||
reject(new Error(`Invalid JSON response: ${error.message}`));
|
reject(new Error(`Invalid JSON response: ${error.message}`));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error(`API request failed with status: ${xhr.status}`);
|
|
||||||
reject(new Error(`HTTP Error: ${xhr.status} ${xhr.statusText}`));
|
reject(new Error(`HTTP Error: ${xhr.status} ${xhr.statusText}`));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.onerror = () => {
|
xhr.onerror = () => {
|
||||||
console.error('Network error occurred during API request');
|
|
||||||
reject(new Error('Network error occurred'));
|
reject(new Error('Network error occurred'));
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('Sending API request...');
|
|
||||||
xhr.send(JSON.stringify({ url, headers }));
|
xhr.send(JSON.stringify({ url, headers }));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -366,10 +333,8 @@ class ApiClient {
|
||||||
const timeSinceLastFetch = now - this.lastFetchTime;
|
const timeSinceLastFetch = now - this.lastFetchTime;
|
||||||
|
|
||||||
if (!forceUpdate && timeSinceLastFetch < CONFIG.CACHE_MIN_INTERVAL) {
|
if (!forceUpdate && timeSinceLastFetch < CONFIG.CACHE_MIN_INTERVAL) {
|
||||||
console.log(`Skipping API call - only ${(timeSinceLastFetch/1000).toFixed(1)}s since last fetch`);
|
|
||||||
const cachedData = this.cache.get();
|
const cachedData = this.cache.get();
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
console.log('Using recent cached data');
|
|
||||||
return cachedData;
|
return cachedData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,21 +342,17 @@ class ApiClient {
|
||||||
let lastError = null;
|
let lastError = null;
|
||||||
for (let attempt = 0; attempt < CONFIG.MAX_RETRIES; attempt++) {
|
for (let attempt = 0; attempt < CONFIG.MAX_RETRIES; attempt++) {
|
||||||
try {
|
try {
|
||||||
console.log(`Attempting to fetch fresh prices (attempt ${attempt + 1}/${CONFIG.MAX_RETRIES})`);
|
|
||||||
const prices = await this.makeRequest(
|
const prices = await this.makeRequest(
|
||||||
'https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,bitcoin-cash,dash,dogecoin,decred,litecoin,particl,pivx,monero,zano,wownero,zcoin&vs_currencies=USD,BTC'
|
'https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,bitcoin-cash,dash,dogecoin,decred,litecoin,particl,pivx,monero,zano,wownero,zcoin&vs_currencies=USD,BTC'
|
||||||
);
|
);
|
||||||
console.log('Successfully fetched new prices, updating cache');
|
|
||||||
this.cache.set(prices);
|
this.cache.set(prices);
|
||||||
this.lastFetchTime = now;
|
this.lastFetchTime = now;
|
||||||
return prices;
|
return prices;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
lastError = error;
|
lastError = error;
|
||||||
console.error(`Price fetch attempt ${attempt + 1} failed:`, error);
|
|
||||||
|
|
||||||
if (attempt < CONFIG.MAX_RETRIES - 1) {
|
if (attempt < CONFIG.MAX_RETRIES - 1) {
|
||||||
const delay = Math.min(CONFIG.BASE_DELAY * Math.pow(2, attempt), 10000);
|
const delay = Math.min(CONFIG.BASE_DELAY * Math.pow(2, attempt), 10000);
|
||||||
console.log(`Waiting ${delay/1000} seconds before next retry...`);
|
|
||||||
await new Promise(resolve => setTimeout(resolve, delay));
|
await new Promise(resolve => setTimeout(resolve, delay));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -399,18 +360,15 @@ class ApiClient {
|
||||||
|
|
||||||
const cachedData = this.cache.get();
|
const cachedData = this.cache.get();
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
console.log('Using cached data after all fetch attempts failed');
|
|
||||||
return cachedData;
|
return cachedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.error('All fetch attempts failed and no cache available');
|
|
||||||
throw lastError || new Error('Failed to fetch prices');
|
throw lastError || new Error('Failed to fetch prices');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UiManager {
|
class UiManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
console.log('Initializing UI Manager');
|
|
||||||
this.api = new ApiClient();
|
this.api = new ApiClient();
|
||||||
this.toggleInProgress = false;
|
this.toggleInProgress = false;
|
||||||
this.toggleDebounceTimer = null;
|
this.toggleDebounceTimer = null;
|
||||||
|
@ -423,7 +381,6 @@ class UiManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
storeOriginalValues() {
|
storeOriginalValues() {
|
||||||
console.log('Storing original coin values');
|
|
||||||
document.querySelectorAll('.coinname-value').forEach(el => {
|
document.querySelectorAll('.coinname-value').forEach(el => {
|
||||||
const coinName = el.getAttribute('data-coinname');
|
const coinName = el.getAttribute('data-coinname');
|
||||||
const value = el.textContent?.trim() || '';
|
const value = el.textContent?.trim() || '';
|
||||||
|
@ -453,61 +410,9 @@ class UiManager {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
calculatePercentageChange(oldValue, newValue) {
|
|
||||||
if (!oldValue && !newValue) return 0;
|
|
||||||
|
|
||||||
oldValue = parseFloat(oldValue);
|
|
||||||
newValue = parseFloat(newValue);
|
|
||||||
|
|
||||||
if (isNaN(oldValue) || isNaN(newValue)) {
|
|
||||||
console.log('Invalid values for percentage calculation');
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldValue === 0 && newValue === 0) return 0;
|
|
||||||
if (oldValue === 0) return 100;
|
|
||||||
|
|
||||||
const change = ((newValue - oldValue) / oldValue) * 100;
|
|
||||||
|
|
||||||
if (Math.abs(change) > CONFIG.MAX_PERCENTAGE_CHANGE) {
|
|
||||||
console.log(`Capping extreme percentage change: ${change}%`);
|
|
||||||
return change > 0 ? CONFIG.MAX_PERCENTAGE_CHANGE : -CONFIG.MAX_PERCENTAGE_CHANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return change;
|
|
||||||
}
|
|
||||||
|
|
||||||
getPercentageChangeDisplay(percentageChange) {
|
|
||||||
let icon, iconColor, text;
|
|
||||||
const textColor = 'white';
|
|
||||||
|
|
||||||
if (percentageChange > 0) {
|
|
||||||
icon = '▲';
|
|
||||||
iconColor = 'rgb(34, 197, 94)';
|
|
||||||
text = `${Math.abs(percentageChange).toFixed(2)}%`;
|
|
||||||
} else if (percentageChange < 0) {
|
|
||||||
icon = '▼';
|
|
||||||
iconColor = 'rgb(239, 68, 68)';
|
|
||||||
text = `${Math.abs(percentageChange).toFixed(2)}%`;
|
|
||||||
} else {
|
|
||||||
icon = '→';
|
|
||||||
iconColor = 'white';
|
|
||||||
text = `0.00%`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
icon,
|
|
||||||
color: textColor,
|
|
||||||
text: `<span style="color: ${iconColor}">${icon}</span> ${text}`,
|
|
||||||
useHTML: true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async updatePrices(forceUpdate = false) {
|
async updatePrices(forceUpdate = false) {
|
||||||
console.log(`Starting price update (force update: ${forceUpdate})`);
|
|
||||||
try {
|
try {
|
||||||
const prices = await this.api.fetchPrices(forceUpdate);
|
const prices = await this.api.fetchPrices(forceUpdate);
|
||||||
const previousTotal = parseFloat(localStorage.getItem(STATE_KEYS.PREVIOUS_TOTAL) || '0');
|
|
||||||
let newTotal = 0;
|
let newTotal = 0;
|
||||||
|
|
||||||
const currentTime = Date.now();
|
const currentTime = Date.now();
|
||||||
|
@ -559,12 +464,10 @@ getPercentageChangeDisplay(percentageChange) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const percentageChange = this.calculatePercentageChange(previousTotal, newTotal);
|
this.updateTotalValues(newTotal, prices?.bitcoin?.usd);
|
||||||
this.updateTotalValues(newTotal, prices?.bitcoin?.usd, percentageChange);
|
|
||||||
|
|
||||||
localStorage.setItem(STATE_KEYS.PREVIOUS_TOTAL, localStorage.getItem(STATE_KEYS.CURRENT_TOTAL) || '0');
|
localStorage.setItem(STATE_KEYS.PREVIOUS_TOTAL, localStorage.getItem(STATE_KEYS.CURRENT_TOTAL) || '0');
|
||||||
localStorage.setItem(STATE_KEYS.CURRENT_TOTAL, newTotal.toString());
|
localStorage.setItem(STATE_KEYS.CURRENT_TOTAL, newTotal.toString());
|
||||||
localStorage.setItem(STATE_KEYS.PERCENTAGE_CHANGE, percentageChange.toString());
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -573,7 +476,7 @@ getPercentageChangeDisplay(percentageChange) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTotalValues(totalUsd, btcPrice, percentageChange) {
|
updateTotalValues(totalUsd, btcPrice) {
|
||||||
const totalUsdEl = document.getElementById('total-usd-value');
|
const totalUsdEl = document.getElementById('total-usd-value');
|
||||||
if (totalUsdEl) {
|
if (totalUsdEl) {
|
||||||
totalUsdEl.textContent = `$${totalUsd.toFixed(2)}`;
|
totalUsdEl.textContent = `$${totalUsd.toFixed(2)}`;
|
||||||
|
@ -589,20 +492,6 @@ getPercentageChangeDisplay(percentageChange) {
|
||||||
totalBtcEl.setAttribute('data-original-value', btcTotal.toString());
|
totalBtcEl.setAttribute('data-original-value', btcTotal.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let percentageChangeEl = document.querySelector('.percentage-change');
|
|
||||||
if (!percentageChangeEl) {
|
|
||||||
percentageChangeEl = this.createPercentageChangeElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (percentageChangeEl) {
|
|
||||||
const { color, text, useHTML } = this.getPercentageChangeDisplay(percentageChange);
|
|
||||||
if (useHTML) {
|
|
||||||
percentageChangeEl.innerHTML = text;
|
|
||||||
}
|
|
||||||
percentageChangeEl.style.color = color;
|
|
||||||
percentageChangeEl.style.display = 'inline';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async toggleBalances() {
|
async toggleBalances() {
|
||||||
|
@ -663,7 +552,7 @@ showBalances() {
|
||||||
document.querySelectorAll('.usd-value').forEach(el => {
|
document.querySelectorAll('.usd-value').forEach(el => {
|
||||||
const storedValue = el.getAttribute('data-original-value');
|
const storedValue = el.getAttribute('data-original-value');
|
||||||
if (storedValue) {
|
if (storedValue) {
|
||||||
el.textContent = `($${parseFloat(storedValue).toFixed(2)} USD)`;
|
el.textContent = `$${parseFloat(storedValue).toFixed(2)} USD`;
|
||||||
el.style.color = 'white';
|
el.style.color = 'white';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -680,18 +569,9 @@ showBalances() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const percentageChangeEl = document.querySelector('.percentage-change');
|
|
||||||
if (percentageChangeEl) {
|
|
||||||
const storedPercentage = parseFloat(localStorage.getItem(STATE_KEYS.PERCENTAGE_CHANGE) || '0');
|
|
||||||
const { text } = this.getPercentageChangeDisplay(storedPercentage);
|
|
||||||
percentageChangeEl.innerHTML = text;
|
|
||||||
percentageChangeEl.style.display = 'inline';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hideBalances() {
|
hideBalances() {
|
||||||
console.log('Hiding balances');
|
|
||||||
const usdText = document.getElementById('usd-text');
|
const usdText = document.getElementById('usd-text');
|
||||||
if (usdText) {
|
if (usdText) {
|
||||||
usdText.style.display = 'none';
|
usdText.style.display = 'none';
|
||||||
|
@ -708,53 +588,13 @@ showBalances() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const percentageChangeEl = document.querySelector('.percentage-change');
|
|
||||||
if (percentageChangeEl) {
|
|
||||||
percentageChangeEl.textContent = '****';
|
|
||||||
percentageChangeEl.style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
const totalUsdEl = document.getElementById('total-usd-value');
|
const totalUsdEl = document.getElementById('total-usd-value');
|
||||||
if (totalUsdEl) {
|
if (totalUsdEl) {
|
||||||
totalUsdEl.classList.remove('font-extrabold');
|
totalUsdEl.classList.remove('font-extrabold');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createPercentageChangeElement() {
|
|
||||||
const totalUsdEl = document.getElementById('total-usd-value');
|
|
||||||
if (totalUsdEl) {
|
|
||||||
const percentageChangeEl = document.createElement('span');
|
|
||||||
percentageChangeEl.className = 'ml-2 text-base percentage-change cursor-help';
|
|
||||||
totalUsdEl.parentNode.appendChild(percentageChangeEl);
|
|
||||||
|
|
||||||
const tooltipId = 'tooltip-percentage';
|
|
||||||
percentageChangeEl.setAttribute('data-tooltip-target', tooltipId);
|
|
||||||
|
|
||||||
if (!document.getElementById(tooltipId)) {
|
|
||||||
const tooltip = document.createElement('div');
|
|
||||||
tooltip.id = tooltipId;
|
|
||||||
tooltip.role = 'tooltip';
|
|
||||||
tooltip.className = 'inline-block absolute invisible z-50 py-2 px-3 text-sm font-medium text-white bg-gray-500 rounded-lg shadow-sm opacity-0 transition-opacity duration-300 tooltip';
|
|
||||||
tooltip.innerHTML = `
|
|
||||||
Price change since last update<br>
|
|
||||||
<span style="color: rgb(34, 197, 94);">▲ Green:</span><span> Price increased</span><br>
|
|
||||||
<span style="color: rgb(239, 68, 68);">▼ Red:</span><span> Price decreased</span><br>
|
|
||||||
<span style="color: white;">→ White:</span><span> No change</span>
|
|
||||||
`;
|
|
||||||
document.body.appendChild(tooltip);
|
|
||||||
|
|
||||||
if (typeof Tooltip !== 'undefined') {
|
|
||||||
new Tooltip(tooltip, percentageChangeEl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return percentageChangeEl;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
async initialize() {
|
async initialize() {
|
||||||
console.log('Initializing UI Manager...');
|
|
||||||
this.storeOriginalValues();
|
this.storeOriginalValues();
|
||||||
|
|
||||||
if (localStorage.getItem('balancesVisible') === null) {
|
if (localStorage.getItem('balancesVisible') === null) {
|
||||||
|
@ -789,27 +629,20 @@ createPercentageChangeElement() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
window.addEventListener('beforeunload', () => {
|
window.addEventListener('beforeunload', () => {
|
||||||
console.log('Page unloading, cleaning up...');
|
|
||||||
const uiManager = window.uiManager;
|
const uiManager = window.uiManager;
|
||||||
if (uiManager?.priceUpdateInterval) {
|
if (uiManager?.priceUpdateInterval) {
|
||||||
clearInterval(uiManager.priceUpdateInterval);
|
clearInterval(uiManager.priceUpdateInterval);
|
||||||
console.log('Cleared price update interval');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize
|
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
console.log('Page loaded, starting application initialization');
|
|
||||||
const uiManager = new UiManager();
|
const uiManager = new UiManager();
|
||||||
window.uiManager = uiManager; // Store reference for cleanup
|
window.uiManager = uiManager;
|
||||||
uiManager.initialize().catch(error => {
|
uiManager.initialize().catch(error => {
|
||||||
console.error('Failed to initialize application:', error);
|
console.error('Failed to initialize application:', error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('Loaded..');
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Reference in a new issue