(function () { const ROOT_SELECTOR = '.js-alm-gold-root'; const NODE_SELECTOR = '.js-alm-gold-live'; const OUNCE_TO_GRAM = 31.1034768; const EPSILON = 0.0000001; const WS_URL = 'wss://ws.almurakib.com/forex'; const roots = Array.from(document.querySelectorAll(ROOT_SELECTOR)); if (!roots.length) return; const manager = window.__almGoldSocketManager || createManager(); window.__almGoldSocketManager = manager; roots.forEach((root) => { if (root.__almGoldBound) return; root.__almGoldBound = true; const items = Array.from(root.querySelectorAll(NODE_SELECTOR)); const currencies = new Set(['USD']); items.forEach((el) => { const currency = String(el.dataset.currency || 'USD').toUpperCase(); if (currency) currencies.add(currency); el.__almGoldLastValue = null; /* السهم فقط إذا كان السعر الرئيسي */ el.__almGoldArrow = el.dataset.main === "1" ? el.parentElement.querySelector('.js-alm-gold-arrow') : null; }); const widget = { root, items, currencies, update() { this.items.forEach((el) => { const base = String(el.dataset.base || 'ounce').toLowerCase(); const currency = String(el.dataset.currency || 'USD').toUpperCase(); const factor = Number(el.dataset.factor || 1); const weight = Number(el.dataset.weight || 1); const decimals = Number(el.dataset.decimals || 2); const value = manager.calcValue(base, currency, factor, weight); if (!Number.isFinite(value)) return; el.textContent = value.toFixed(decimals); /* تحديث السهم فقط للسعر الرئيسي */ if (el.__almGoldArrow) { updateArrow(el, value); } }); } }; manager.register(widget); widget.update(); }); /* ===== SOCKET MANAGER ===== */ function createManager() { return { socket: null, reconnectTimer: null, reconnectDelay: 1500, widgets: new Set(), scheduled: false, market: { XAUUSD: null, fx: Object.create(null) }, register(widget) { if (!this.widgets.has(widget)) { this.widgets.add(widget); } this.ensureSocket(); }, ensureSocket() { if ( this.socket && (this.socket.readyState === WebSocket.OPEN || this.socket.readyState === WebSocket.CONNECTING) ) { return; } try { this.socket = new WebSocket(WS_URL); } catch (error) { this.scheduleReconnect(); return; } this.socket.addEventListener('open', () => { this.reconnectDelay = 1500; }); this.socket.addEventListener('message', (event) => { this.onMessage(event.data); }); this.socket.addEventListener('close', () => { this.scheduleReconnect(); }); this.socket.addEventListener('error', () => { try { this.socket.close(); } catch (e) {} }); }, scheduleReconnect() { if (this.reconnectTimer || !this.widgets.size) return; this.reconnectTimer = window.setTimeout(() => { this.reconnectTimer = null; this.ensureSocket(); }, this.reconnectDelay); this.reconnectDelay = Math.min(this.reconnectDelay * 1.7, 12000); }, onMessage(raw) { let data; try { data = JSON.parse(raw); } catch (error) { return; } const ticker = String(data.ticker || '').toUpperCase(); const price = Number(data.price); if (!ticker || !Number.isFinite(price) || price <= 0) return; /* الذهب بالدولار */ if (ticker === 'XAUUSD') { this.market.XAUUSD = price; this.scheduleUpdate(); return; } /* تجاهل الأزواج غير المطلوبة */ if (!this.isNeededTicker(ticker)) return; this.market.fx[ticker] = price; this.scheduleUpdate(); }, isNeededTicker(ticker) { for (const widget of this.widgets) { for (const currency of widget.currencies) { if (currency === 'USD') continue; if ( ticker === 'USD' + currency || ticker === currency + 'USD' ) { return true; } } } return false; }, scheduleUpdate() { if (this.scheduled) return; this.scheduled = true; window.requestAnimationFrame(() => { this.scheduled = false; this.widgets.forEach((widget) => { widget.update(); }); }); }, getFxRate(currency) { currency = String(currency || '').toUpperCase(); if (!currency || currency === 'USD') { return 1; } const direct = 'USD' + currency; const inverse = currency + 'USD'; if (Number.isFinite(this.market.fx[direct])) { return this.market.fx[direct]; } if ( Number.isFinite(this.market.fx[inverse]) && this.market.fx[inverse] !== 0 ) { return 1 / this.market.fx[inverse]; } return null; }, calcValue(base, currency, factor, weight) { if (!Number.isFinite(this.market.XAUUSD)) { return null; } let usdValue = this.market.XAUUSD; if (base === 'gram') { usdValue = usdValue / OUNCE_TO_GRAM; } usdValue *= factor * weight; const fxRate = this.getFxRate(currency); if (!Number.isFinite(fxRate)) return null; return usdValue * fxRate; } }; } /* ===== ARROW SYSTEM ===== */ function updateArrow(el, newValue) { const arrow = el.__almGoldArrow; if (!arrow) { el.__almGoldLastValue = newValue; return; } const oldValue = el.__almGoldLastValue; el.__almGoldLastValue = newValue; if (typeof oldValue !== 'number') { setArrowState(arrow, 'flat'); return; } const diff = newValue - oldValue; if (Math.abs(diff) < EPSILON) { setArrowState(arrow, 'flat'); } else if (diff > 0) { setArrowState(arrow, 'up'); } else { setArrowState(arrow, 'down'); } } function setArrowState(arrow, state) { arrow.classList.remove('is-up', 'is-down', 'is-flat'); void arrow.offsetWidth; if (state === 'up') { arrow.textContent = '▲'; arrow.classList.add('is-up'); return; } if (state === 'down') { arrow.textContent = '▼'; arrow.classList.add('is-down'); return; } /* لا سهم عند عدم التغيير */ arrow.textContent = ''; arrow.classList.add('is-flat'); } })();