/* 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( "
| ×base | name |
|---|