Public bank/exchange/merchant landing stats and performance UI only. Secret goa-ui overlay stays on local/merchant-secret-ui (never push).
245 lines
7.1 KiB
JavaScript
245 lines
7.1 KiB
JavaScript
/* Compact GOA / CUR:amount display using SI-style alt units (kGOA, MGOA, …).
|
||
* Large values → "1.23 MGOA" (title = full GOA:n) so landing tiles fit.
|
||
*/
|
||
(function (global) {
|
||
"use strict";
|
||
|
||
var DEFAULT_ALT = {
|
||
"24": "YGOA",
|
||
"21": "ZGOA",
|
||
"18": "EGOA",
|
||
"15": "PGOA",
|
||
"12": "TGOA",
|
||
"9": "GGOA",
|
||
"6": "MGOA",
|
||
"3": "kGOA",
|
||
"0": "GOA",
|
||
"-1": "dGOA",
|
||
"-2": "cGOA",
|
||
"-3": "mGOA",
|
||
"-6": "µGOA",
|
||
"-7": "dµGOA",
|
||
"-8": "aGOA"
|
||
};
|
||
|
||
var LONG_TO_COMPACT = {
|
||
"yotta-goa": "YGOA",
|
||
"zetta-goa": "ZGOA",
|
||
"exa-goa": "EGOA",
|
||
"peta-goa": "PGOA",
|
||
"tera-goa": "TGOA",
|
||
"giga-goa": "GGOA",
|
||
"mega-goa": "MGOA",
|
||
"kilo-goa": "kGOA",
|
||
"goa": "GOA",
|
||
"deci-goa": "dGOA",
|
||
"centi-goa": "cGOA",
|
||
"milli-goa": "mGOA",
|
||
"micro-goa": "µGOA",
|
||
"deci-micro-goa": "dµGOA",
|
||
"atomic-goa": "aGOA"
|
||
};
|
||
|
||
var THRESHOLD = 1000;
|
||
|
||
function compactAlt(altMap) {
|
||
var out = {};
|
||
var src = altMap || DEFAULT_ALT;
|
||
Object.keys(DEFAULT_ALT).forEach(function (k) {
|
||
out[k] = DEFAULT_ALT[k];
|
||
});
|
||
Object.keys(src).forEach(function (k) {
|
||
var name = String(src[k] || "").trim();
|
||
var low = name.toLowerCase().replace(/\s+/g, "");
|
||
if (LONG_TO_COMPACT[low]) out[k] = LONG_TO_COMPACT[low];
|
||
else if (DEFAULT_ALT[k] && /goa/i.test(name)) out[k] = DEFAULT_ALT[k];
|
||
else out[k] = name || DEFAULT_ALT[k] || name;
|
||
});
|
||
return out;
|
||
}
|
||
|
||
function parseAmount(s) {
|
||
if (s == null || s === "") return { cur: "GOA", val: 0 };
|
||
if (typeof s === "number") return { cur: "GOA", val: s };
|
||
var t = String(s).trim();
|
||
var i = t.indexOf(":");
|
||
if (i < 0) return { cur: "GOA", val: parseFloat(t) || 0 };
|
||
return {
|
||
cur: t.slice(0, i) || "GOA",
|
||
val: parseFloat(t.slice(i + 1)) || 0
|
||
};
|
||
}
|
||
|
||
function fmtCoeff(v) {
|
||
if (!isFinite(v)) return "?";
|
||
var a = Math.abs(v);
|
||
if (Math.abs(a - Math.round(a)) < 1e-9) return String(Math.round(v));
|
||
var s = v.toFixed(4).replace(/\.?0+$/, "");
|
||
return s;
|
||
}
|
||
|
||
function baseStr(cur, val) {
|
||
if (!isFinite(val)) return String(cur) + ":?";
|
||
if (Math.abs(val - Math.round(val)) < 1e-9) return cur + ":" + Math.round(val);
|
||
return cur + ":" + String(val).replace(/(\.\d*?[1-9])0+$/, "$1").replace(/\.0+$/, "");
|
||
}
|
||
|
||
/**
|
||
* @param {string|number|object} amount
|
||
* @param {object} [altMap]
|
||
* @returns {{ display: string, title: string, raw: string, usedAlt: boolean }}
|
||
*/
|
||
function format(amount, altMap) {
|
||
if (amount == null || amount === "") {
|
||
return { display: "—", title: "", raw: "", usedAlt: false };
|
||
}
|
||
// Prefer re-format from canonical amount (keeps kGOA even if server sent Kilo-GOA)
|
||
if (typeof amount === "object" && amount) {
|
||
if (amount.amount) {
|
||
return format(amount.amount, altMap);
|
||
}
|
||
amount = amount.amount_full || amount.amount_alt || "";
|
||
}
|
||
|
||
var alt = compactAlt(altMap || global.__GOA_ALT_UNITS || DEFAULT_ALT);
|
||
var p = parseAmount(amount);
|
||
var raw = baseStr(p.cur, p.val);
|
||
var baseName = (alt && alt["0"]) || p.cur;
|
||
var curU = String(p.cur || "").toUpperCase();
|
||
var baseU = String(baseName || "").toUpperCase();
|
||
if (curU && curU !== "GOA" && (baseU === "GOA" || baseU.indexOf("GOA") !== -1)) {
|
||
return { display: raw, title: raw, raw: raw, usedAlt: false };
|
||
}
|
||
if (p.val === 0) {
|
||
return { display: raw, title: raw, raw: raw, usedAlt: false };
|
||
}
|
||
if (Math.abs(p.val) < THRESHOLD) {
|
||
return { display: raw, title: raw, raw: raw, usedAlt: false };
|
||
}
|
||
|
||
var scales = [];
|
||
Object.keys(alt || {}).forEach(function (k) {
|
||
var n = parseInt(k, 10);
|
||
if (!isNaN(n)) scales.push({ sc: n, name: String(alt[k]) });
|
||
});
|
||
scales.sort(function (a, b) {
|
||
return b.sc - a.sc;
|
||
});
|
||
|
||
var abs = Math.abs(p.val);
|
||
var chosen = null;
|
||
for (var i = 0; i < scales.length; i++) {
|
||
var unit = Math.pow(10, scales[i].sc);
|
||
if (!(unit > 0)) continue;
|
||
var coeff = abs / unit;
|
||
if (coeff >= 1) {
|
||
chosen = {
|
||
sc: scales[i].sc,
|
||
name: scales[i].name,
|
||
coeff: p.val >= 0 ? coeff : -coeff
|
||
};
|
||
break;
|
||
}
|
||
}
|
||
if (!chosen || chosen.sc === 0) {
|
||
return { display: raw, title: raw, raw: raw, usedAlt: false };
|
||
}
|
||
var short = fmtCoeff(chosen.coeff) + " " + chosen.name;
|
||
return {
|
||
display: short,
|
||
title: short + " (" + raw + ")",
|
||
raw: raw,
|
||
usedAlt: true
|
||
};
|
||
}
|
||
|
||
function setText(el, amount, altMap) {
|
||
if (!el) return;
|
||
var f = format(amount, altMap);
|
||
el.textContent = f.display;
|
||
if (f.title && f.title !== f.display) el.setAttribute("title", f.title);
|
||
else el.removeAttribute("title");
|
||
}
|
||
|
||
function setById(id, amount, altMap) {
|
||
setText(document.getElementById(id), amount, altMap);
|
||
}
|
||
|
||
/** Prefer formatting from amount field; fall back to amount_alt string. */
|
||
function pick(rowOrAmount, altMap) {
|
||
if (rowOrAmount && typeof rowOrAmount === "object") {
|
||
var a =
|
||
rowOrAmount.amount ||
|
||
rowOrAmount.total_amount ||
|
||
rowOrAmount.amount_paid_sum ||
|
||
rowOrAmount.amount_sum;
|
||
if (a) return format(a, altMap);
|
||
if (rowOrAmount.amount_alt) {
|
||
return {
|
||
display: String(rowOrAmount.amount_alt),
|
||
title: String(rowOrAmount.amount_full || rowOrAmount.amount_alt),
|
||
raw: String(rowOrAmount.amount_full || rowOrAmount.amount_alt),
|
||
usedAlt: true
|
||
};
|
||
}
|
||
return format("", altMap);
|
||
}
|
||
return format(rowOrAmount, altMap);
|
||
}
|
||
|
||
function rememberAlt(stats) {
|
||
if (stats && stats.alt_unit_names && typeof stats.alt_unit_names === "object") {
|
||
global.__GOA_ALT_UNITS = compactAlt(stats.alt_unit_names);
|
||
}
|
||
}
|
||
|
||
/** Small legend HTML (positive scales). */
|
||
function legendHtml(stats) {
|
||
var alt = compactAlt((stats && stats.alt_unit_names) || global.__GOA_ALT_UNITS || DEFAULT_ALT);
|
||
var rows = [];
|
||
Object.keys(alt)
|
||
.map(function (k) {
|
||
return parseInt(k, 10);
|
||
})
|
||
.filter(function (n) {
|
||
return !isNaN(n) && n > 0;
|
||
})
|
||
.sort(function (a, b) {
|
||
return a - b;
|
||
})
|
||
.forEach(function (sc) {
|
||
rows.push(
|
||
"<tr><td>10<sup>" +
|
||
sc +
|
||
"</sup></td><td><strong>" +
|
||
alt[String(sc)] +
|
||
"</strong></td></tr>"
|
||
);
|
||
});
|
||
if (!rows.length) return "";
|
||
return (
|
||
'<table class="unit-legend" aria-label="GOA unit names"><thead><tr><th>×base</th><th>name</th></tr></thead><tbody>' +
|
||
rows.join("") +
|
||
"</tbody></table>"
|
||
);
|
||
}
|
||
|
||
function fillLegend(elOrId, stats) {
|
||
var el = typeof elOrId === "string" ? document.getElementById(elOrId) : elOrId;
|
||
if (!el) return;
|
||
el.innerHTML = legendHtml(stats);
|
||
}
|
||
|
||
global.GoaAmount = {
|
||
format: format,
|
||
setText: setText,
|
||
setById: setById,
|
||
pick: pick,
|
||
rememberAlt: rememberAlt,
|
||
compactAlt: compactAlt,
|
||
legendHtml: legendHtml,
|
||
fillLegend: fillLegend,
|
||
DEFAULT_ALT: DEFAULT_ALT,
|
||
THRESHOLD: THRESHOLD
|
||
};
|
||
})(typeof window !== "undefined" ? window : globalThis);
|