Zum Inhalt springen

Platzhalter-System

Das Platzhalter-System ermöglicht es Lesern, IP-Adressen, ASNs und andere bereitstellungsspezifische Werte in der gesamten Dokumentation anzupassen. Autoren schreiben Tokens in ihrem Markdown; der Browser ersetzt diese zur Laufzeit durch benutzerdefinierte Werte.

Tokens folgen dem Regex-Muster:

x([A-Z][A-Z0-9_]+)x

Ein Token beginnt und endet mit einem kleingeschriebenen x und enthält einen Bezeichner in Großbuchstaben. Zum Beispiel referenziert xCUSTOMER_ASNx den Platzhalter CUSTOMER_ASN.

Der reguläre Ausdruck ist in src/scripts/placeholder-dom.ts definiert:

const PH_REGEX = /x([A-Z][A-Z0-9_]+)x/g;

Alle Platzhalter werden in src/data/placeholders.json deklariert. Jeder Eintrag hat folgende Struktur:

{
"CUSTOMER_ASN": {
"type": "text",
"default": "64496",
"description": "Your public ASN (registered with ARIN/RIR)"
}
}
FeldErforderlichBeschreibung
typeja"text" für Freitext-Eingabe, "dropdown" für Auswahlmenüs
defaultjaAnfangswert, der angezeigt wird, bevor der Leser etwas ändert
descriptionjaBeschriftung, die im Formular angezeigt wird
optionsnur für DropdownArray der zulässigen Werte

src/lib/placeholder-store.ts verwaltet den gesamten Platzhalter-Zustand.

Werte werden im localStorage unter dem Schlüssel f5xc-placeholders persistiert. Der Store stellt vier Funktionen bereit:

FunktionZweck
getDefaults()Gibt eine Map aller Platzhalter-Schlüssel mit ihren default-Werten aus der JSON-Datei zurück
loadValues()Liest aus dem localStorage, fällt auf getDefaults() zurück
saveValues(values)Schreibt die aktuelle Map in den localStorage
clearValues()Entfernt den localStorage-Eintrag

FIELD_GROUPS organisiert Platzhalter-Schlüssel in beschriftete Abschnitte für die Formular-Oberfläche:

export const FIELD_GROUPS: FieldGroup[] = [
{ label: 'Data Center & Scrubbing Centers', keys: ['DC_NAME', 'CENTER_1', 'CENTER_2'] },
{ label: 'Protected Prefixes', keys: ['PROTECTED_CIDR_V4', 'PROTECTED_NET_V4', ...] },
{ label: 'BGP', keys: ['CUSTOMER_ASN', 'F5_XC_ASN', 'BGP_PASSWORD'] },
// ... weitere Gruppen
];

Einige Werte werden aus Benutzereingaben abgeleitet, anstatt direkt eingegeben zu werden. getComputedValues() berechnet diese aus Nachschlagetabellen:

const cidrToMask: Record<string, string> = {
'/24 (256 IPs)': '255.255.255.0',
'/23 (512 IPs)': '255.255.254.0',
// ...
};

Zwei berechnete Platzhalter werden erzeugt:

Berechneter SchlüsselAbgeleitet vonBeispiel
PROTECTED_MASK_V4PROTECTED_CIDR_V4 über cidrToMask-Nachschlagetabelle255.255.255.0
PROTECTED_PREFIX_V4PROTECTED_NET_V4 + PROTECTED_CIDR_V4 über cidrToShort192.0.2.0/24

getAllValues() führt benutzerdefinierte Werte mit berechneten Werten zusammen und liefert eine vollständige Map für die Ersetzung.

emitChange() sendet ein placeholder-change CustomEvent auf document mit der vollständigen Werte-Map als detail:

export function emitChange(values: Record<string, string>) {
document.dispatchEvent(
new CustomEvent('placeholder-change', { detail: getAllValues(values) }),
);
}

Dieses Ereignis steuert sowohl die DOM-Span-Aktualisierungen als auch das Mermaid-Neurendering.

src/components/PlaceholderForm.tsx stellt die Bearbeitungsoberfläche bereit.

  • Zustand: useState initialisiert mit loadValues()
  • Beim Einbinden: useEffect ruft emitChange() auf, um die initiale DOM-Ersetzung auszulösen
  • handleChange: Aktualisiert den React-Zustand, ruft saveValues() und emitChange() auf
  • handleReset: Ruft clearValues() auf, setzt den Zustand auf getDefaults() zurück, löst ein Change-Ereignis aus
  • Rendering: Iteriert über FIELD_GROUPS und rendert ein <fieldset> pro Gruppe. Jeder Schlüssel erhält entweder ein <input> (Typ Text) oder ein <select> (Typ Dropdown)
  • Layout: Das Formular ist in ein <details>-Element eingebettet, standardmäßig eingeklappt

src/components/PlaceholderFormWrapper.astro verbindet die React-Komponente mit der Astro-Seite:

<PlaceholderForm client:only="react" />
<script>
import '../scripts/placeholder-dom.ts';
</script>

client:only="react" weist Astro an, die Komponente ausschließlich auf dem Client zu hydrieren (kein SSR). Das <script>-Tag importiert den DOM-Walker, damit dieser auf jeder Seite ausgeführt wird, die diesen Wrapper einbindet.

Der Wrapper injiziert außerdem globales CSS für das Formular-Styling (.ph-form-wrapper, .ph-grid, .ph-value usw.).

src/scripts/placeholder-dom.ts übernimmt die clientseitige Token-Ersetzung.

Beim Laden der Seite wird init() ausgeführt:

  1. Wählt .sl-markdown-content als Wurzelelement (fällt auf document.body zurück)
  2. Ruft walkTextNodes(root, values) auf, das document.createTreeWalker mit NodeFilter.SHOW_TEXT verwendet
  3. Für jeden Textknoten, der dem Token-Regex entspricht, wird dieser in ein Dokumentfragment aus einfachen Textknoten und <span data-ph="KEY" class="ph-value">-Elementen aufgeteilt
  4. Ersetzt den ursprünglichen Textknoten durch das Fragment

Nach dem Durchlauf enthält das DOM Spans mit data-ph-Attributen anstelle der rohen Tokens.

Wenn das Formular ein placeholder-change-Ereignis auslöst, wird updateSpans() ausgeführt:

document.querySelectorAll<HTMLSpanElement>('span[data-ph]').forEach((span) => {
const name = span.getAttribute('data-ph')!;
if (values[name] !== undefined) {
span.textContent = values[name];
}
});

Dies vermeidet ein erneutes Durchlaufen des Baums — es aktualisiert direkt den Textinhalt der Spans.

Das Skript registriert zwei Listener:

EreignisHandlerZweck
placeholder-changehandleChangeAktualisiert Spans und rendert Mermaid-Diagramme neu
astro:page-loadinitDurchläuft das DOM erneut nach clientseitiger Astro-Navigation
  1. JSON-Eintrag hinzufügen in src/data/placeholders.json:

    "MY_NEW_VALUE": {
    "type": "text",
    "default": "example",
    "description": "Description shown in the form"
    }
  2. Den Schlüssel einer Feldgruppe zuordnen in src/lib/placeholder-store.ts. Fügen Sie ihn entweder dem keys-Array einer bestehenden Gruppe hinzu oder erstellen Sie eine neue Gruppe in FIELD_GROUPS.

  3. Das Token im Inhalt verwenden: Schreiben Sie xMY_NEW_VALUEx in einer beliebigen .mdx-Datei. Der DOM-Walker ersetzt es zur Laufzeit.

Berechnete Werte werden aus anderen Platzhaltern abgeleitet. Um einen hinzuzufügen:

  1. Fügen Sie eine Nachschlagetabelle (falls erforderlich) in src/lib/placeholder-store.ts hinzu, nach dem Muster von cidrToMask.

  2. Erweitern Sie getComputedValues() um den neuen abgeleiteten Schlüssel:

    export function getComputedValues(values: Record<string, string>): Record<string, string> {
    // ... bestehende Logik
    return {
    PROTECTED_MASK_V4: mask,
    PROTECTED_PREFIX_V4: `${net}${short}`,
    MY_COMPUTED: derivedValue, // hier hinzufügen
    };
    }
  3. Verwenden Sie xMY_COMPUTEDx im Inhalt wie jedes andere Token. Berechnete Werte benötigen keinen placeholders.json-Eintrag und keine Feldgruppe — sie sind für das Formular unsichtbar.