Refaktorisierungs-Optionen und Fix für Zahlen-Parsing
This commit is contained in:
163
REFACTOR.md
Normal file
163
REFACTOR.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# Refactoring-Optionen
|
||||
|
||||
## 1. `prepareValue` reparieren + tote `parseNumber`-Funktion entfernen
|
||||
|
||||
**Dateien:** `hugo/static/js/converter.js`
|
||||
|
||||
`prepareValue()` macht `input.replace(/,/g, '.')`. Bei deutscher Eingabe `1.000,50` wird
|
||||
daraus der ungültige String `1.000.50` – `new Decimal()` wirft einen Fehler und die
|
||||
Reaktivität bricht. Die Funktion `parseNumber()` (wird nirgends verwendet) würde das
|
||||
korrekt parsen.
|
||||
|
||||
**Vorschlag:** Logik von `parseNumber` in `prepareValue` übernehmen, `parseNumber`
|
||||
löschen.
|
||||
|
||||
**Effekt:** Bugfix + Tote-Code-Eliminierung.
|
||||
|
||||
---
|
||||
|
||||
## 2. Überzähliges schließendes `</div>` in Conversion-Seite entfernen
|
||||
|
||||
**Datei:** `hugo/layouts/conversion/single.html`
|
||||
|
||||
Vor dem abschließenden `{{ end }}` steht ein `</div>` ohne zugehöriges öffnendes
|
||||
Element in dieser Template-Datei. Das erzeugt invalides HTML.
|
||||
|
||||
**Effekt:** HTML-Korrektheit, weniger Fragilität.
|
||||
|
||||
---
|
||||
|
||||
## 3. Toten `intermediate`-Engine-Zweig aus Formel-Template entfernen
|
||||
|
||||
**Datei:** `hugo/layouts/partials/conversion-formula.html`
|
||||
|
||||
Keine JSON-Datendatei verwendet `"conversion_engine": "intermediate"`. Der komplette
|
||||
`else if eq .Params.engine "intermediate"`-Block wird niemals ausgeführt.
|
||||
|
||||
**Effekt:** Reduziert Template-Logik um ~20 Zeilen toten Code.
|
||||
|
||||
---
|
||||
|
||||
## 4. Engine-Partial dynamisch statt per `if/else` laden
|
||||
|
||||
**Datei:** `hugo/layouts/conversion/single.html`
|
||||
|
||||
Statt dreier verschachtelter `if/else` zur Auswahl des Data-Partials:
|
||||
|
||||
```html
|
||||
{{ if eq $engine "currencies" }} ... {{ else if eq $engine "temperatures" }} ... {{ else }} ... {{ end }}
|
||||
```
|
||||
|
||||
reicht ein dynamischer Partial-Aufruf:
|
||||
|
||||
```html
|
||||
{{ partial (printf "conversion/%s-data" $engine) . }}
|
||||
```
|
||||
|
||||
**Effekt:** Entfaltet 3 Ebenen verschachtelte Template-Logik.
|
||||
|
||||
---
|
||||
|
||||
## 5. SVG-Ladepattern in eigenes Partial extrahieren
|
||||
|
||||
**Dateien:** `hugo/layouts/index.html`, `hugo/layouts/404.html`,
|
||||
`hugo/layouts/partials/unit-dropdown.html`
|
||||
|
||||
Diese drei Dateien wiederholen identisch:
|
||||
|
||||
```html
|
||||
{{ $svgPath := printf "img/%s.svg" $data.slug }}
|
||||
{{ $svgFile := readFile (printf "static/%s" $svgPath) }}
|
||||
{{ if $svgFile }}{{ $svgFile | safeHTML }}{{ else }}<span></span>{{ end }}
|
||||
```
|
||||
|
||||
**Vorschlag:** `hugo/layouts/partials/icon.html` mit `(dict "slug" $data.slug)`.
|
||||
|
||||
**Effekt:** DRY, Änderungen am Icon-Loading zentral.
|
||||
|
||||
---
|
||||
|
||||
## 6. Wiederholte Select-Optionen-Logik in Partial auslagern
|
||||
|
||||
**Datei:** `hugo/layouts/conversion/single.html`
|
||||
|
||||
Die Dropdowns für „von“ und „in“ enthalten nahezu identische `range`-Schleifen mit
|
||||
nur leicht unterschiedlichen Variablen.
|
||||
|
||||
**Vorschlag:** `hugo/layouts/partials/unit-options.html` via Parameter
|
||||
`(dict "mode" "from" ...)` steuern.
|
||||
|
||||
**Effekt:** Weniger Redundanz, geringere Fehleranfälligkeit bei Änderungen.
|
||||
|
||||
---
|
||||
|
||||
## 7. `category-url.html` entminifizieren
|
||||
|
||||
**Datei:** `hugo/layouts/partials/category-url.html`
|
||||
|
||||
Aktuell 1 Zeile, 260+ Zeichen ohne Umbrüche. Das ist die komplexeste Logik der
|
||||
Seite (Finden des ersten und zweiten verfügbaren Units), aber völlig unlesbar.
|
||||
|
||||
**Effekt:** Deutlich bessere mentale Parsbarkeit.
|
||||
|
||||
---
|
||||
|
||||
## 8. URL-Wert-Normalisierung deduplizieren + `0`-Inkonsistenz fixen
|
||||
|
||||
**Datei:** `hugo/static/js/converter.js`
|
||||
|
||||
`updateUrl` und `navigate` wiederholen die Komma-zu-Punkt-Ersetzung. Zudem verhält
|
||||
sich `updateUrl("0")` anders als `navigate(url, "0")` (ersteres setzt `?v=1`,
|
||||
letzteres `?v=0`).
|
||||
|
||||
**Vorschlag:** Eine gemeinsame Funktion `normalizeUrlValue(value)` extrahieren.
|
||||
|
||||
**Effekt:** DRY + Konsistenzfix.
|
||||
|
||||
---
|
||||
|
||||
## 9. Redundantes `new Decimal(v)` in linear-data entfernen
|
||||
|
||||
**Datei:** `hugo/layouts/partials/conversion/linear-data.html`
|
||||
|
||||
`convert: v => new Decimal(v).times(...)` – `v` kommt bereits als `Decimal` aus
|
||||
`prepareValue`. Temperaturen und Währungen nutzen `v` direkt.
|
||||
|
||||
**Effekt:** Konsistentes Verhalten über alle Engines.
|
||||
|
||||
---
|
||||
|
||||
## 10. `_content.gotmpl` in Teil-Partials splitten
|
||||
|
||||
**Datei:** `hugo/content/_content.gotmpl`
|
||||
|
||||
Die Datei ist 140+ Zeilen lang und mischt drei Konzerne:
|
||||
Währungs-Page-Generierung, Linear-Page-Generierung und Temperaturen-Page-Generierung.
|
||||
|
||||
**Vorschlag:**
|
||||
`hugo/layouts/partials/content-generators/currencies.html`,
|
||||
`linear.html`, `temperatures.html`.
|
||||
|
||||
**Effekt:** Besseres Verständnis des Bauprozesses, leichteres Testen einzelner
|
||||
Generatoren.
|
||||
|
||||
---
|
||||
|
||||
## 11. Stille Fehler bei Währungs-Fetch im Build loggen
|
||||
|
||||
**Datei:** `hugo/layouts/partials/available-currencies.html`
|
||||
|
||||
Der Fehlerfall von `resources.GetRemote` wird abgefangen, aber nicht geloggt
|
||||
(`{{ with .Err }}{{ end }}`). `_content.gotmpl` macht das besser mit `warnf`.
|
||||
|
||||
**Effekt:** Einfacheres Debuggen bei Build-Zeit-Fehlern.
|
||||
|
||||
---
|
||||
|
||||
## Nicht empfohlen
|
||||
|
||||
- **SEO-Text-Partials vereinheitlichen:** 155 Dateien unter `partials/texts/`.
|
||||
Die sind inhaltsgetrieben, keine Code-Redundanz.
|
||||
- **Alle `conversion_engine` Defaults aus JSON entfernen:** Theoretisch
|
||||
defaultbar, aber die explizite Deklaration in jeder Datei ist defensiver und
|
||||
selbsterklärend.
|
||||
@@ -1,7 +1,7 @@
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
image: umrechner:v1.0.6
|
||||
image: umrechner:v1.0.7
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POCKETBASE_URL={$POCKETBASE_URL}
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<div class="text-center sm:pt-6">
|
||||
<button type="button"
|
||||
@click="navigate(
|
||||
$el.dataset.swapUrl, prettyNumber(convert(prepareValue(inputValue))))"
|
||||
$el.dataset.swapUrl, prettyNumber(convert(parseNumber(inputValue))))"
|
||||
data-swap-url="/{{ .Params.to }}-in-{{ .Params.from }}/"
|
||||
class="inline-flex items-center text-sm
|
||||
font-medium text-primary
|
||||
@@ -145,7 +145,7 @@
|
||||
</label>
|
||||
<input type="text" id="result"
|
||||
disabled
|
||||
:value="prettyNumber(convert(prepareValue(inputValue)))"
|
||||
:value="prettyNumber(convert(parseNumber(inputValue)))"
|
||||
class="textinput mt-1 block w-full">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -44,32 +44,35 @@ function prettyNumber(num, minPrecision, maxPrecision) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a German number string.
|
||||
* Accepts both comma and dot as decimal separator.
|
||||
* @param {string} input
|
||||
* @returns {string} Normalized string with dot as decimal
|
||||
* Parses a number string for conversion.
|
||||
* Accepts both German (1.234,56) and US (1,234.56) notation.
|
||||
* The last dot or comma is always the decimal separator;
|
||||
* all preceding ones are treated as thousand separators and removed.
|
||||
* Invalid or empty input returns Decimal(0).
|
||||
* @param {string} input - User input from field
|
||||
* @returns {Decimal} Parsed Decimal value
|
||||
*/
|
||||
function parseNumber(input) {
|
||||
if (!input) return '0';
|
||||
const hasComma = input.indexOf(',') !== -1;
|
||||
const hasDot = input.indexOf('.') !== -1;
|
||||
if (hasComma && hasDot) {
|
||||
return input.replace(/\./g, '').replace(/,/g, '.') || '0';
|
||||
}
|
||||
return input.replace(/,/g, '.') || '0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares input value for conversion.
|
||||
* Returns a Decimal, or 1 if input is empty.
|
||||
* @param {string} input - User input from field
|
||||
* @returns {Decimal} Prepared value
|
||||
*/
|
||||
function prepareValue(input) {
|
||||
if (!input || input.trim() === '') {
|
||||
return new Decimal(1);
|
||||
return new Decimal(0);
|
||||
}
|
||||
const trimmed = input.trim();
|
||||
const lastDot = trimmed.lastIndexOf('.');
|
||||
const lastComma = trimmed.lastIndexOf(',');
|
||||
const lastSep = Math.max(lastDot, lastComma);
|
||||
let normalized;
|
||||
if (lastSep === -1) {
|
||||
normalized = trimmed;
|
||||
} else {
|
||||
const beforeSep = trimmed.slice(0, lastSep).replace(/[.,]/g, '');
|
||||
const afterSep = trimmed.slice(lastSep + 1);
|
||||
normalized = beforeSep + '.' + afterSep;
|
||||
}
|
||||
try {
|
||||
return new Decimal(normalized);
|
||||
} catch (e) {
|
||||
return new Decimal(0);
|
||||
}
|
||||
return new Decimal(input.replace(/,/g, '.'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user