Archived
348 lines
18 KiB
HTML
348 lines
18 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Numeric Input | HiAPI-C# 2025 </title>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="title" content="Numeric Input | HiAPI-C# 2025 ">
|
|
|
|
|
|
<link rel="icon" href="../../img/HiAPI.favicon.ico">
|
|
<link rel="stylesheet" href="../../public/docfx.min.css">
|
|
<link rel="stylesheet" href="../../public/main.css">
|
|
<meta name="docfx:navrel" content="../../toc.html">
|
|
<meta name="docfx:tocrel" content="toc.html">
|
|
|
|
<meta name="docfx:rel" content="../../">
|
|
|
|
|
|
|
|
<meta name="loc:inThisArticle" content="In this article">
|
|
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
|
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
|
<meta name="loc:tocFilter" content="Filter by title">
|
|
<meta name="loc:nextArticle" content="Next">
|
|
<meta name="loc:prevArticle" content="Previous">
|
|
<meta name="loc:themeLight" content="Light">
|
|
<meta name="loc:themeDark" content="Dark">
|
|
<meta name="loc:themeAuto" content="Auto">
|
|
<meta name="loc:changeTheme" content="Change theme">
|
|
<meta name="loc:copy" content="Copy">
|
|
<meta name="loc:downloadPdf" content="Download PDF">
|
|
|
|
<script type="module" src="./../../public/docfx.min.js"></script>
|
|
|
|
<script>
|
|
const theme = localStorage.getItem('theme') || 'auto'
|
|
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
|
</script>
|
|
|
|
</head>
|
|
|
|
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
|
<header class="bg-body border-bottom">
|
|
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
|
<div class="container-xxl flex-nowrap">
|
|
<a class="navbar-brand" href="../../index.html">
|
|
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
|
|
|
|
</a>
|
|
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
|
<i class="bi bi-three-dots"></i>
|
|
</button>
|
|
<div class="collapse navbar-collapse" id="navpanel">
|
|
<div id="navbar">
|
|
<form class="search" role="search" id="search">
|
|
<i class="bi bi-search"></i>
|
|
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
|
|
<main class="container-xxl">
|
|
<div class="toc-offcanvas">
|
|
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
|
<div class="offcanvas-header">
|
|
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
|
</div>
|
|
<div class="offcanvas-body">
|
|
<nav class="toc" id="toc"></nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="content">
|
|
<div class="actionbar">
|
|
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
|
<i class="bi bi-list"></i>
|
|
</button>
|
|
|
|
<nav id="breadcrumb"></nav>
|
|
</div>
|
|
|
|
<article data-uid="Anatomy-NumericInput">
|
|
<h1 id="numeric-input">Numeric Input</h1>
|
|
|
|
<p>NumericInput is the single-value numeric field the rest of the web application embeds. It has no
|
|
route and no Control-Tree node of its own: it is reached only through the editors that host it,
|
|
and those span the equipment and mission trees, the Tool House tool editors, the transformer and
|
|
geometry editors and the Preference menu. The rule for carrying <code>NaN</code> and
|
|
the infinities across the JSON boundary is stated once in
|
|
<a class="xref" href="../conventions/numeric-io-utilities.html">Numeric Input/Output</a>; this page is the widget that implements
|
|
the client end of it.</p>
|
|
<h2 id="the-binding-contract">The Binding Contract</h2>
|
|
<p>The widget owns no value. It holds the raw text the user is typing and nothing else, and every
|
|
committed number is handed straight back to the host, which decides what to persist and when.</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Prop</th>
|
|
<th>Meaning</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>modelValue</code></td>
|
|
<td><code>number</code>, <code>null</code> or <code>undefined</code> — the value to show</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>label</code></td>
|
|
<td>the field's label, inside the outline; floats to the top of it once the field has content</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>hint</code></td>
|
|
<td>text below the field</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>unit</code></td>
|
|
<td>a display-only suffix inside the field</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>readonly</code> / <code>disable</code></td>
|
|
<td>passed through to the underlying field</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>min</code> / <code>max</code></td>
|
|
<td>inclusive bounds, checked on commit</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>allowEmpty</code></td>
|
|
<td>whether a blank field commits <code>null</code>; defaults to on</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>hideBottomSpace</code></td>
|
|
<td>stop holding space below the field; a hint or message still renders when there is one</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>rules</code></td>
|
|
<td>extra validation functions over the raw <strong>text</strong></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>Two events leave the widget.</p>
|
|
<ul>
|
|
<li><code>update:modelValue</code> carries a number or <code>null</code>. <code>null</code> is a real outcome rather than an error
|
|
signal, so a host that must not receive one either turns <code>allowEmpty</code> off or filters what it
|
|
gets: the cutter section panel returns early on <code>null</code> so that clearing a field cannot write a
|
|
zero into the profile, and the graphic-cache menu rejects <code>null</code> and every non-finite value
|
|
before it calls the server.</li>
|
|
<li><code>parseError</code> carries the raw text that failed to parse. No shipped host listens for it, so a
|
|
parse failure is visible only as the message under the field.</li>
|
|
</ul>
|
|
<h2 id="commit-semantics">Commit Semantics</h2>
|
|
<p>Typing changes nothing but the text in the box. The commit runs on blur and on Enter, and on
|
|
nothing else — there is no per-keystroke emit, no debounce and no timer. The underlying control is
|
|
a plain text field rather than a browser number input, so there is no spinner, no step and no
|
|
keystroke-level filtering: any text at all may sit in the box until the field is committed.</p>
|
|
<p>A commit parses the text once and then takes one of three exits. On success the error strip is
|
|
cleared, <code>update:modelValue</code> is emitted, and the box is rewritten from the parsed number. On text
|
|
that does not parse, <code>parseError</code> is emitted and a message appears. On a number outside the bounds,
|
|
a message appears. Neither failing exit emits <code>update:modelValue</code>, and neither rewrites the box.</p>
|
|
<p>Enter commits without moving focus, so the value is committed again when the field is finally left.
|
|
The widget carries no equality guard — it emits whenever the text parses and passes the bounds,
|
|
whether or not the result differs from <code>modelValue</code> — so that second commit reaches the host as a
|
|
second, identical write. Here the widget parts company with the vector and matrix editors, both of
|
|
which compare against the model before emitting.</p>
|
|
<h2 id="bounds-and-special-values">Bounds and Special Values</h2>
|
|
<p><code>min</code> and <code>max</code> are inclusive and are enforced inside the widget, before anything is emitted: a
|
|
number below <code>min</code> or above <code>max</code> is refused and the host never sees it.</p>
|
|
<p><strong>The bounds apply to finite numbers only.</strong> <code>Infinity</code>, <code>-Infinity</code>, <code>NaN</code> and the <code>null</code> a blank
|
|
field produces all skip the range check, so a field declared with a <code>min</code> of 0 still commits
|
|
<code>-Infinity</code> and <code>NaN</code>. Where that matters, the host filters what it receives.</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Typed</th>
|
|
<th>Committed</th>
|
|
<th>Shown afterwards</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>Infinity</code> in any case, or <code>∞</code></td>
|
|
<td><code>Infinity</code></td>
|
|
<td><code>Infinity</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>-Infinity</code> in any case, or <code>-∞</code></td>
|
|
<td><code>-Infinity</code></td>
|
|
<td><code>-Infinity</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>NaN</code> in any case</td>
|
|
<td><code>NaN</code></td>
|
|
<td><em>(empty)</em></td>
|
|
</tr>
|
|
<tr>
|
|
<td>blank, <code>allowEmpty</code> on</td>
|
|
<td><code>null</code></td>
|
|
<td><em>(empty)</em></td>
|
|
</tr>
|
|
<tr>
|
|
<td>blank, <code>allowEmpty</code> off</td>
|
|
<td>nothing — parse error</td>
|
|
<td>the blank stays</td>
|
|
</tr>
|
|
<tr>
|
|
<td>anything JavaScript's <code>Number()</code> reads as a finite number</td>
|
|
<td>that number</td>
|
|
<td>its default string form</td>
|
|
</tr>
|
|
<tr>
|
|
<td>anything else</td>
|
|
<td>nothing — parse error</td>
|
|
<td>the rejected text stays</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p><code>Number()</code> is the whole numeric parser, so exponent notation and the <code>0x</code>, <code>0b</code> and <code>0o</code> integer
|
|
literals are accepted alongside ordinary decimals, while a thousands separator is not. Its result
|
|
must also come back finite to be accepted, so a literal that overflows the double — <code>1e400</code> — is a
|
|
parse error rather than a second route to <code>Infinity</code>. The two spellings at the head of the table
|
|
are the only way to reach one.</p>
|
|
<p>Two consequences follow from <code>NaN</code> and <code>null</code> sharing the empty box. A <code>NaN</code> arriving from the
|
|
server is indistinguishable from a blank field; and because a blank field commits <code>null</code> under the
|
|
default, merely focusing such a field and leaving it replaces the <code>NaN</code> with <code>null</code>. With
|
|
<code>allowEmpty</code> turned off the same field instead fails to parse on every blur until something is
|
|
typed into it.</p>
|
|
<p>The infinity spellings the widget writes and reads are the same strings the API layer puts on the
|
|
wire for a non-finite number — see <a class="xref" href="../conventions/numeric-io-utilities.html">Numeric Input/Output</a>. The
|
|
widget itself never touches the wire: it emits a JavaScript number, and converting a non-finite one
|
|
into its string form belongs to the host's API module, as <code>wwwroot-src/src/api/mission.ts</code> does for
|
|
the mission commands. That conversion is not symmetric for <code>NaN</code>: the mission module writes all
|
|
three strings but recognises only the two infinity spellings when reading, so a <code>NaN</code> returned by
|
|
the endpoint becomes the caller's supplied default instead.</p>
|
|
<h2 id="unit-suffix-and-precision">Unit Suffix and Precision</h2>
|
|
<p><code>unit</code> is rendered as a suffix inside the field, to the right of the text. It is decoration only:
|
|
it is not part of the editable text, it is not parsed, and no unit conversion happens anywhere in
|
|
the widget — the number committed is in whatever unit the host's model already uses. Hosts pass
|
|
plain unit text, <code>mm</code> and <code>deg</code> being the common ones, alongside <code>mm/min</code>, <code>rpm</code>, <code>N</code>, <code>°C</code> and
|
|
<code>MB</code>.</p>
|
|
<p>There is no precision, decimals or step prop. A value is displayed through JavaScript's default
|
|
number-to-string conversion, so it shows at full precision and switches to exponent notation at the
|
|
magnitudes where that conversion does. Rounding, where a host wants it, is the host's own: the
|
|
graphic-cache current-size field rounds in its commit handler, after the widget has handed the
|
|
number over, while the two limit fields in the same menu send what they were given.</p>
|
|
<h2 id="validation-messages">Validation Messages</h2>
|
|
<p>Three messages can appear under the field, and all three are built inside the component in English:
|
|
<code>Invalid number: "…"</code> quoting the rejected text, <code>Must be ≥ …</code> and <code>Must be ≤ …</code> quoting the bound.
|
|
They are not keys and appear in no i18n bundle, so they do not follow the application's language
|
|
setting — unlike <code>label</code> and <code>hint</code>, which hosts pass in already translated.</p>
|
|
<p><code>rules</code> is a separate mechanism and differs in three ways: its functions receive the raw display
|
|
<strong>text</strong> rather than the parsed number, they run on the underlying field's own validation pass —
|
|
as the text changes, and again when focus leaves — rather than inside the commit, and <strong>they do
|
|
not gate the commit</strong>: a value failing a caller rule is still parsed, still bounds-checked and
|
|
still emitted. While the widget's own message is showing, it also masks the rule's.</p>
|
|
<p>No shipped host passes <code>rules</code>, and none fills the <code>append</code> slot, so both are available rather
|
|
than exercised. <code>hideBottomSpace</code> is the opposite — it is among the most-passed props on the
|
|
widget, set on nearly every field the SoftNc controller panels, the spindle contour editor and the
|
|
fluting span list drop into a table cell.</p>
|
|
<h2 id="when-the-box-and-the-model-disagree">When the Box and the Model Disagree</h2>
|
|
<p>A rejected commit leaves the typed text in the box. That text is replaced only when <code>modelValue</code>
|
|
changes to something whose formatted form differs from what is showing; the widget does not revert
|
|
on its own. That is the second thing the vector and matrix editors do that this one does not: both
|
|
reinstate the last valid value the moment a cell fails to parse. Two situations follow, and both
|
|
put a number on screen that was never stored:</p>
|
|
<ul>
|
|
<li>A number outside the bounds, or text that does not parse, stays in the box under its error
|
|
message. Nothing restores it until the host pushes a different value.</li>
|
|
<li>A commit the host accepts and the server then refuses leaves the box showing the refused number
|
|
unless the host had already applied it locally, because assigning the unchanged value back to
|
|
<code>modelValue</code> is not a change and moves nothing.</li>
|
|
</ul>
|
|
<p>The message is equally persistent: it is cleared only by the next successful commit, so it can
|
|
outlive the value that caused it and sit under a field the host has since repopulated.</p>
|
|
<h2 id="layout">Layout</h2>
|
|
<ul>
|
|
<li>Numeric Input Field
|
|
<ul>
|
|
<li>Label — the host's <code>label</code>, positioned inside the field's outline: on the input line while the
|
|
field is empty and unfocused, floated to the top of the outline once it has a value or the
|
|
focus; absent when none is given</li>
|
|
<li>Text Box — one line, free text until committed</li>
|
|
<li>Unit Suffix — the host's <code>unit</code>, inside the field at the right; display only</li>
|
|
<li>Append Slot — an optional trailing slot for a host-supplied control</li>
|
|
<li>Bottom Strip — the host's <code>hint</code>, replaced by the validation message while the field is in
|
|
error. <code>hideBottomSpace</code> stops space being held below the field but does not suppress the
|
|
strip: a hint or a validation message still renders, and with nothing reserved for it, it
|
|
grows the field instead of filling a gap already left below.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h2 id="source-code-path">Source Code Path</h2>
|
|
<p>See <a class="xref" href="../index.html">HiNC App Anatomy</a> for git repository links.</p>
|
|
<h3 id="web-application">Web Application</h3>
|
|
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
|
|
<ul>
|
|
<li><code>wwwroot-src/src/components/widgets/NumericInput.vue</code> — the widget: the raw-text buffer, the
|
|
local format and parse pair, the blur-and-Enter commit, the inclusive bounds check that skips
|
|
non-finite values, and the three English validation strings.</li>
|
|
<li><code>wwwroot-src/src/components/preference/GraphicCacheMenu.vue</code> — a compact host of three instances,
|
|
one of them bounded by the values of the other two; every handler rejects <code>null</code> and non-finite
|
|
numbers, and the current-size handler is the one that rounds before sending.</li>
|
|
<li><code>wwwroot-src/src/components/controlTree/toolhouse/CutterSectionPanel.vue</code> — a host that returns
|
|
early on the <code>null</code> a cleared field emits, so blanking a cutter dimension cannot write a zero.</li>
|
|
<li><code>wwwroot-src/src/components/spindle/SpindleContourEditor.vue</code> — a host that turns <code>allowEmpty</code>
|
|
off and keeps its own draft copy of the contour points around the blur commit.</li>
|
|
<li><code>wwwroot-src/src/api/mission.ts</code> — the module that turns a committed non-finite number into the
|
|
<code>Infinity</code>, <code>-Infinity</code> or <code>NaN</code> string the endpoint takes, and reads the two infinity spellings
|
|
back; a <code>NaN</code> arriving from the endpoint falls through to the caller's default instead.</li>
|
|
</ul>
|
|
<h2 id="see-also">See Also</h2>
|
|
<ul>
|
|
<li><a class="xref" href="../conventions/numeric-io-utilities.html">Numeric Input/Output</a> — the cross-boundary rule this widget implements the client half of, and how the three numeric inputs differ from one another</li>
|
|
<li><a class="xref" href="index.html">Widgets</a> — the other controls that pages embed rather than own</li>
|
|
<li><a class="xref" href="../general-setup/controller/editing-contract.html">Editing Contract</a> — the branch that embeds this field most heavily, and the
|
|
commit rules its panels inherit from it</li>
|
|
</ul>
|
|
|
|
</article>
|
|
|
|
<div class="contribution d-print-none">
|
|
</div>
|
|
|
|
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
|
|
|
</div>
|
|
|
|
<div class="affix">
|
|
<nav id="affix"></nav>
|
|
</div>
|
|
</main>
|
|
|
|
<div class="container-xxl search-results" id="search-results"></div>
|
|
|
|
<footer class="border-top text-secondary">
|
|
<div class="container-xxl">
|
|
<div class="flex-fill">
|
|
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
</body>
|
|
</html>
|