- หน้าแรก
- ตัวสร้างเอกสาร
- ระบบ Placeholder
ระบบ Placeholder
ระบบ placeholder ช่วยให้ผู้อ่านสามารถปรับแต่งที่อยู่ IP, ASN และค่าเฉพาะของการใช้งานต่างๆ ตลอดทั้งเอกสาร ผู้เขียนจะเขียนโทเค็นใน Markdown ของตน จากนั้นเบราว์เซอร์จะแทนที่ด้วยค่าที่ผู้ใช้กำหนดขณะรันไทม์
รูปแบบโทเค็น
หัวข้อที่มีชื่อว่า “รูปแบบโทเค็น”โทเค็นเป็นไปตามรูปแบบ regex:
x([A-Z][A-Z0-9_]+)xโทเค็นเริ่มต้นและลงท้ายด้วยตัว x พิมพ์เล็ก และภายในเป็นตัวระบุตัวพิมพ์ใหญ่ ตัวอย่างเช่น xCUSTOMER_ASNx อ้างอิงถึง placeholder CUSTOMER_ASN
regex ถูกกำหนดไว้ใน src/scripts/placeholder-dom.ts:
const PH_REGEX = /x([A-Z][A-Z0-9_]+)x/g;คำจำกัดความของ Placeholder
หัวข้อที่มีชื่อว่า “คำจำกัดความของ Placeholder”Placeholder ทั้งหมดถูกประกาศไว้ใน src/data/placeholders.json แต่ละรายการมีรูปแบบดังนี้:
{ "CUSTOMER_ASN": { "type": "text", "default": "64496", "description": "Your public ASN (registered with ARIN/RIR)" }}| ฟิลด์ | จำเป็น | คำอธิบาย |
|---|---|---|
type | ใช่ | "text" สำหรับช่องกรอกข้อมูลอิสระ, "dropdown" สำหรับเมนูแบบเลือก |
default | ใช่ | ค่าเริ่มต้นที่แสดงก่อนที่ผู้อ่านจะเปลี่ยนแปลงอะไร |
description | ใช่ | ป้ายกำกับที่แสดงในฟอร์ม |
options | เฉพาะ dropdown | อาร์เรย์ของค่าที่อนุญาต |
การจัดการสถานะ
หัวข้อที่มีชื่อว่า “การจัดการสถานะ”src/lib/placeholder-store.ts จัดการสถานะ placeholder ทั้งหมด
การจัดเก็บ
หัวข้อที่มีชื่อว่า “การจัดเก็บ”ค่าต่างๆ ถูกบันทึกใน localStorage ภายใต้คีย์ f5xc-placeholders store เปิดเผยฟังก์ชันสี่ตัว:
| ฟังก์ชัน | วัตถุประสงค์ |
|---|---|
getDefaults() | คืนค่า map ของคีย์ placeholder ทุกตัวไปยังค่า default จาก JSON |
loadValues() | อ่านจาก localStorage, ใช้ getDefaults() เป็นค่าสำรอง |
saveValues(values) | เขียน map ปัจจุบันลง localStorage |
clearValues() | ลบรายการ localStorage |
กลุ่มฟิลด์
หัวข้อที่มีชื่อว่า “กลุ่มฟิลด์”FIELD_GROUPS จัดระเบียบคีย์ placeholder เป็นส่วนที่มีป้ายกำกับสำหรับ 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', // ...};Placeholder ที่คำนวณได้มีสองตัว:
| คีย์ที่คำนวณได้ | คำนวณจาก | ตัวอย่าง |
|---|---|---|
PROTECTED_MASK_V4 | PROTECTED_CIDR_V4 ผ่านตารางค้นหา cidrToMask | 255.255.255.0 |
PROTECTED_PREFIX_V4 | PROTECTED_NET_V4 + PROTECTED_CIDR_V4 ผ่าน cidrToShort | 192.0.2.0/24 |
getAllValues() รวมค่าที่ผู้ใช้กรอกกับค่าที่คำนวณได้ ให้ map ที่สมบูรณ์สำหรับการแทนที่
การส่งเหตุการณ์
หัวข้อที่มีชื่อว่า “การส่งเหตุการณ์”emitChange() ส่ง CustomEvent placeholder-change บน document พร้อมด้วย map ค่าทั้งหมดเป็น detail:
export function emitChange(values: Record<string, string>) { document.dispatchEvent( new CustomEvent('placeholder-change', { detail: getAllValues(values) }), );}เหตุการณ์นี้ขับเคลื่อนทั้งการอัปเดต DOM span และการเรนเดอร์ Mermaid ใหม่
คอมโพเนนต์ฟอร์ม React
หัวข้อที่มีชื่อว่า “คอมโพเนนต์ฟอร์ม React”src/components/PlaceholderForm.tsx ให้ UI สำหรับการแก้ไข
- สถานะ:
useStateเริ่มต้นจากloadValues() - เมื่อ mount:
useEffectเรียกemitChange()เพื่อทริกเกอร์การแทนที่ DOM เริ่มต้น - handleChange: อัปเดตสถานะ React, เรียก
saveValues()และemitChange() - handleReset: เรียก
clearValues(), รีเซ็ตสถานะเป็นgetDefaults(), ส่งเหตุการณ์เปลี่ยนแปลง - การเรนเดอร์: วนซ้ำ
FIELD_GROUPS, เรนเดอร์<fieldset>ต่อกลุ่ม แต่ละคีย์จะได้<input>(ประเภท text) หรือ<select>(ประเภท dropdown) - เลย์เอาต์: ฟอร์มถูกห่อด้วยอิลิเมนต์
<details>ซึ่งพับเก็บโดยค่าเริ่มต้น
Astro Wrapper
หัวข้อที่มีชื่อว่า “Astro Wrapper”src/components/PlaceholderFormWrapper.astro เชื่อมต่อคอมโพเนนต์ React กับหน้า Astro:
<PlaceholderForm client:only="react" />
<script> import '../scripts/placeholder-dom.ts';</script>client:only="react" บอก Astro ให้ hydrate คอมโพเนนต์บนฝั่งไคลเอนต์เท่านั้น (ไม่มี SSR) แท็ก <script> นำเข้า DOM walker เพื่อให้มันทำงานในทุกหน้าที่รวม wrapper นี้
Wrapper ยังฉีด CSS ทั่วไปสำหรับการจัดรูปแบบฟอร์ม (.ph-form-wrapper, .ph-grid, .ph-value เป็นต้น)
DOM Walker
หัวข้อที่มีชื่อว่า “DOM Walker”src/scripts/placeholder-dom.ts จัดการการแทนที่โทเค็นฝั่งไคลเอนต์
การเดินครั้งแรก
หัวข้อที่มีชื่อว่า “การเดินครั้งแรก”เมื่อโหลดหน้า init() จะทำงาน:
- เลือก
.sl-markdown-contentเป็น root (ใช้document.bodyเป็นค่าสำรอง) - เรียก
walkTextNodes(root, values)ซึ่งใช้document.createTreeWalkerกับNodeFilter.SHOW_TEXT - สำหรับแต่ละ text node ที่ตรงกับ regex ของโทเค็น จะแยกออกเป็น document fragment ของ text node ธรรมดาและอิลิเมนต์
<span data-ph="KEY" class="ph-value"> - แทนที่ text node เดิมด้วย fragment
หลังจากการเดิน DOM จะมี span ที่มีแอตทริบิวต์ data-ph แทนที่โทเค็นดิบ
การอัปเดตครั้งถัดไป
หัวข้อที่มีชื่อว่า “การอัปเดตครั้งถัดไป”เมื่อฟอร์มส่งเหตุการณ์ 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]; }});วิธีนี้หลีกเลี่ยงการเดิน tree ซ้ำ — มันอัปเดตเนื้อหาข้อความของ span โดยตรง
ตัวรับฟังเหตุการณ์
หัวข้อที่มีชื่อว่า “ตัวรับฟังเหตุการณ์”สคริปต์ลงทะเบียนตัวรับฟังสองตัว:
| เหตุการณ์ | ตัวจัดการ | วัตถุประสงค์ |
|---|---|---|
placeholder-change | handleChange | อัปเดต span และเรนเดอร์ไดอะแกรม Mermaid ใหม่ |
astro:page-load | init | เดิน DOM ใหม่หลังจากการนำทางฝั่งไคลเอนต์ของ Astro |
วิธีการ: เพิ่ม Placeholder ใหม่
หัวข้อที่มีชื่อว่า “วิธีการ: เพิ่ม Placeholder ใหม่”-
เพิ่มรายการ JSON ใน
src/data/placeholders.json:"MY_NEW_VALUE": {"type": "text","default": "example","description": "Description shown in the form"} -
เพิ่มคีย์ไปยังกลุ่มฟิลด์ ใน
src/lib/placeholder-store.tsสามารถเพิ่มไปยังอาร์เรย์keysของกลุ่มที่มีอยู่ หรือสร้างกลุ่มใหม่ในFIELD_GROUPS -
ใช้โทเค็นในเนื้อหา: เขียน
xMY_NEW_VALUExในไฟล์.mdxใดก็ได้ DOM walker จะแทนที่มันขณะรันไทม์
วิธีการ: เพิ่มค่าที่คำนวณได้
หัวข้อที่มีชื่อว่า “วิธีการ: เพิ่มค่าที่คำนวณได้”ค่าที่คำนวณได้ถูกคำนวณจาก placeholder อื่นๆ ในการเพิ่ม:
-
เพิ่มตารางค้นหา (หากจำเป็น) ใน
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, // เพิ่มตรงนี้};} -
ใช้
xMY_COMPUTEDxในเนื้อหาเช่นเดียวกับโทเค็นอื่นๆ ค่าที่คำนวณได้ไม่จำเป็นต้องมีรายการในplaceholders.jsonหรือกลุ่มฟิลด์ — มันจะมองไม่เห็นในฟอร์ม