Turns what a person types or drags in a Properties row into the number handed to the app.
How the precision is kept
A number row hands the app the 64-bit value of the typed text, or the value the app's own parser returns, limited to the row's minimum and maximum and not rounded. The box then shows that value with String, the shortest text that reads back to the same number. A slider row rounds its value to the decimals of its step plus two, at most 8.
Calculations under this policy
3 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.
app-propgrid.jsShared shell, every app64-bit3 calculationsReviewed
Tests bin/test-app-propgrid.mjs
Value of a number row
64-bit
The number handed to the app when a person changes a number box.
v = min(max, max(min, typed value))
The typed text is converted with Number, or by the row's own parser when it has one, and only limited to the row's range. No rounding is applied, and the box is refilled with String(v).
app-propgrid.js
lines 214 to 229
ni.addEventListener('change', function () {
var v;
if (r.parse) {
var pr = null;
try { pr = ni.value.trim() === '' ? { ok: false, empty: true } : r.parse(ni.value); } catch (e) { pr = { ok: false }; }
if (!pr || !pr.ok || !isFinite(pr.value)) { ni.setAttribute('aria-invalid', 'true'); try { onInvalid(r.id, pr, ni.value); } catch (e) { if (window.console) console.error(e); } return; }
ni.removeAttribute('aria-invalid');
v = Number(pr.value);
} else {
v = Number(ni.value);
if (ni.value === '' || !isFinite(v)) { ni.value = r.value == null ? '' : String(r.value); return; }
}
if (r.min != null) v = Math.max(r.min, v);
if (r.max != null) v = Math.min(r.max, v);
ni.value = String(v); emit(r, v);
});
Rounding of a slider value
64-bit
Removes binary noise such as 0.30000000000000004 from a slider's value.
v = round to (decimals of the step + 2) decimals, at most 8
Rounds with toFixed and converts back with Number, so the value handed on has at most 8 decimals. The decimals are counted in String(step); a step below 1e-6 prints in exponent form with no decimal point and counts as 0, giving 2 decimals.
app-propgrid.js
lines 56 to 59
function fix(v, step) { // no 0.30000000000000004 in a box
var dec = String(step || 1).indexOf('.') === -1 ? 0 : String(step).split('.')[1].length;
return Number(Number(v).toFixed(Math.min(dec + 2, 8)));
}
Value of a slider row
64-bit
The number handed to the app while a slider is dragged or its box is changed.
v = fix(clamp(value, min, max), step)
A value typed in the box is limited to the slider's range and then rounded by fix; a dragged value is rounded by fix. The rounded value is what the app receives, not the raw one.
app-propgrid.js
lines 194 to 203
var put = function (v) { if (v == null) { sl.value = r.min; nb.value = ''; } else { sl.value = v; nb.value = String(fix(v, r.step)); } };
put(r.mixed ? null : r.value);
if (r.mixed) nb.placeholder = T('shell.propgrid.varies');
sl.addEventListener('input', function () { var v = fix(sl.value, r.step); nb.value = String(v); emit(r, v, true); });
sl.addEventListener('change', function () { emit(r, fix(sl.value, r.step)); });
nb.addEventListener('change', function () {
var v = Number(nb.value);
if (nb.value === '' || !isFinite(v)) { put(r.value); return; }
v = fix(clamp(v, r.min, r.max), r.step); put(v); emit(r, v);
});
In detail
Method
Number row: Number(text) or the row's parse function, then max(min, …) and min(max, …). Slider row: clamp, then toFixed(decimals of the step + 2, at most 8).
Number types
64-bit numbers.
Limits
A slider's value carries at most 8 decimals. A slider step that JavaScript writes in exponent form (below 1e-6) is read as having no decimals, so its values are rounded to 2 decimals.
Approach: 64-bit, direct
Every value is a 64-bit number from input to result. Formulas are closed form or a direct solve, and every comparison uses a stated tolerance.