佔位符系統
佔位符系統讓讀者可以在整份文件中自訂 IP 位址、ASN 及其他部署特定的值。作者在 Markdown 中撰寫 token;瀏覽器會在執行時將其替換為使用者提供的值。
Token 格式
Section titled “Token 格式”Token 遵循以下正規表達式模式:
x([A-Z][A-Z0-9_]+)xToken 以小寫的 x 開頭和結尾,中間包含大寫識別符。例如,xCUSTOMER_ASNx 參照的是 CUSTOMER_ASN 佔位符。
此正規表達式定義在 src/scripts/placeholder-dom.ts 中:
const PH_REGEX = /x([A-Z][A-Z0-9_]+)x/g;所有佔位符都宣告在 src/data/placeholders.json 中。每個項目具有以下結構:
{ "CUSTOMER_ASN": { "type": "text", "default": "64496", "description": "Your public ASN (registered with ARIN/RIR)" }}| 欄位 | 必填 | 說明 |
|---|---|---|
type | 是 | "text" 表示自由輸入,"dropdown" 表示下拉選單 |
default | 是 | 讀者變更前顯示的初始值 |
description | 是 | 表單中顯示的標籤 |
options | 僅下拉選單需要 | 允許值的陣列 |
src/lib/placeholder-store.ts 處理所有佔位符狀態。
值透過 localStorage 持久化,使用的鍵為 f5xc-placeholders。儲存區公開四個函式:
| 函式 | 用途 |
|---|---|
getDefaults() | 從 JSON 回傳每個佔位符鍵對應其 default 值的映射 |
loadValues() | 從 localStorage 讀取,失敗時退回到 getDefaults() |
saveValues(values) | 將目前的映射寫入 localStorage |
clearValues() | 移除 localStorage 項目 |
FIELD_GROUPS 將佔位符鍵組織為帶有標籤的區段,用於表單 UI:
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'] }, // ... 更多群組];某些值是由使用者輸入推導而來,而非直接輸入。getComputedValues() 從查詢表計算這些值:
const cidrToMask: Record<string, string> = { '/24 (256 IPs)': '255.255.255.0', '/23 (512 IPs)': '255.255.254.0', // ...};產生兩個計算佔位符:
| 計算鍵 | 來源 | 範例 |
|---|---|---|
PROTECTED_MASK_V4 | 透過 cidrToMask 查詢從 PROTECTED_CIDR_V4 推導 | 255.255.255.0 |
PROTECTED_PREFIX_V4 | 透過 cidrToShort 從 PROTECTED_NET_V4 + PROTECTED_CIDR_V4 推導 | 192.0.2.0/24 |
getAllValues() 將使用者輸入的值與計算值合併,提供完整的替換映射。
emitChange() 在 document 上發送一個 placeholder-change CustomEvent,以完整的值映射作為 detail:
export function emitChange(values: Record<string, string>) { document.dispatchEvent( new CustomEvent('placeholder-change', { detail: getAllValues(values) }), );}此事件驅動 DOM span 更新和 Mermaid 重新繪製。
React 表單元件
Section titled “React 表單元件”src/components/PlaceholderForm.tsx 提供編輯 UI。
- 狀態:
useState以loadValues()初始化 - 掛載時:
useEffect呼叫emitChange()觸發初始 DOM 替換 - handleChange:更新 React 狀態,呼叫
saveValues()和emitChange() - handleReset:呼叫
clearValues(),將狀態重設為getDefaults(),發送變更事件 - 繪製:遍歷
FIELD_GROUPS,每個群組繪製一個<fieldset>。每個鍵根據類型取得<input>(text 類型)或<select>(dropdown 類型) - 版面配置:表單包裹在
<details>元素中,預設為摺疊狀態
Astro 包裝器
Section titled “Astro 包裝器”src/components/PlaceholderFormWrapper.astro 將 React 元件連接到 Astro 頁面:
<PlaceholderForm client:only="react" />
<script> import '../scripts/placeholder-dom.ts';</script>client:only="react" 告知 Astro 僅在客戶端進行元件水合(不進行 SSR)。<script> 標籤匯入 DOM 遍歷器,使其在每個包含此包裝器的頁面上執行。
此包裝器也注入表單樣式的全域 CSS(.ph-form-wrapper、.ph-grid、.ph-value 等)。
DOM 遍歷器
Section titled “DOM 遍歷器”src/scripts/placeholder-dom.ts 處理客戶端的 token 替換。
頁面載入時,init() 執行:
- 選取
.sl-markdown-content作為根節點(退回到document.body) - 呼叫
walkTextNodes(root, values),使用document.createTreeWalker搭配NodeFilter.SHOW_TEXT - 對於每個匹配 token 正規表達式的文字節點,將其分割為由純文字節點和
<span data-ph="KEY" class="ph-value">元素組成的文件片段 - 以此片段替換原始文字節點
遍歷完成後,DOM 中包含帶有 data-ph 屬性的 span,取代了原始 token。
當表單發送 placeholder-change 事件時,updateSpans() 執行:
document.querySelectorAll<HTMLSpanElement>('span[data-ph]').forEach((span) => { const name = span.getAttribute('data-ph')!; if (values[name] !== undefined) { span.textContent = values[name]; }});這避免了重新遍歷整棵樹——直接更新 span 的文字內容。
此腳本註冊兩個監聽器:
| 事件 | 處理函式 | 用途 |
|---|---|---|
placeholder-change | handleChange | 更新 span 並重新繪製 Mermaid 圖表 |
astro:page-load | init | 在 Astro 客戶端導航後重新遍歷 DOM |
操作指南:新增佔位符
Section titled “操作指南:新增佔位符”-
在
src/data/placeholders.json中新增 JSON 項目:"MY_NEW_VALUE": {"type": "text","default": "example","description": "Description shown in the form"} -
在
src/lib/placeholder-store.ts中將鍵加入欄位群組。將其加入現有群組的keys陣列中,或在FIELD_GROUPS中建立新群組。 -
在內容中使用 token:在任何
.mdx檔案中撰寫xMY_NEW_VALUEx。DOM 遍歷器會在執行時替換它。
操作指南:新增計算值
Section titled “操作指南:新增計算值”計算值是從其他佔位符推導而來的。新增步驟如下:
-
在
src/lib/placeholder-store.ts中新增查詢表(如需要),遵循cidrToMask的模式。 -
擴展
getComputedValues()以包含新的推導鍵:export function getComputedValues(values: Record<string, string>): Record<string, string> {// ... 現有邏輯return {PROTECTED_MASK_V4: mask,PROTECTED_PREFIX_V4: `${net}${short}`,MY_COMPUTED: derivedValue, // 在此新增};} -
在內容中像其他 token 一樣使用
xMY_COMPUTEDx。計算值不需要placeholders.json項目或欄位群組——它們對表單是不可見的。