🐛 Round the numbers of the compare dialog once a plugin has loaded

Sizes, positions and other numbers in the compare dialog showed every
decimal (162.99999952316284 × 42.99999808520081) as soon as a plugin
had loaded. The plugin runtime's SES lockdown turns
`Number.prototype.toLocaleString` into `toString`, which ignores the
two-decimal limit and the locale.

The numbers now go through `Intl.NumberFormat`, which the lockdown
leaves alone, and fall back to the default locale when none is set.
This commit is contained in:
elhombretecla 2026-10-28 09:50:32 +01:00
parent 876ab29ba9
commit d103805086
2 changed files with 22 additions and 4 deletions

View File

@ -190,11 +190,15 @@
(defn- fmt-number
"At most two decimals, trailing zeros stripped (89.99999 -> \"90\",
439.4999 -> \"439.5\", 386 -> \"386\"), grouped and punctuated the way
the active locale writes numbers (\"439,5\" in Spanish)."
the active locale writes numbers (\"439,5\" in Spanish). It goes
through `Intl.NumberFormat`: once a plugin has loaded, the SES lockdown
turns `Number.prototype.toLocaleString` into `toString`, options and
all."
[v]
(let [locale (-> i18n/*current-locale*
(str/replace "_" "-"))]
(.toLocaleString v locale #js {:maximumFractionDigits 2})))
(let [locale (or (some-> i18n/*current-locale*
(str/replace "_" "-"))
js/undefined)]
(.format (js/Intl.NumberFormat. locale #js {:maximumFractionDigits 2}) v)))
(defn- short-str
[v]

View File

@ -69,3 +69,17 @@
(t/is (= "439.5" (display-val 439.5)))
(t/is (= "90" (display-val 89.99999)) "at most two decimals")
(t/is (= "386" (display-val 386)))))
(t/deftest numbers-keep-two-decimals-under-the-plugin-lockdown
;; a loaded plugin's SES lockdown turns `toLocaleString` into
;; `toString`, which ignores the options
(let [proto (.-prototype js/Number)
original (.-toLocaleString proto)]
(set! (.-toLocaleString proto) (.-toString proto))
(try
(binding [i18n/*current-locale* "en"]
(t/is (= "163" (display-val 162.99999952316284))))
(binding [i18n/*current-locale* nil]
(t/is (= "1.5" (display-val 1.5)) "no locale falls back to the default"))
(finally
(set! (.-toLocaleString proto) original)))))