幻跡百科:UI/JavaScript
更多操作
BenWiki UI JavaScript 是本站 application-level 前端互動元件的架構文件。
這一層負責在 MediaWiki、Page Forms、OOUI 與 Citizen 提供的基礎能力之上,補充 BenWiki 自己需要的通用互動。
架構原則
JavaScript 功能依 component 分離。
主入口不實作具體功能,只偵測目前頁面實際存在的 component,再透過 ResourceLoader 按需載入。
MediaWiki:Gadget-benwiki-ui.js
│
├─ ImagePicker
│ ↓
│ ImageLibrary
│
├─ Disclosure
│
├─ OrderedMultiple
│
└─ InfoboxCollection
(後續加入)
Bootstrap
入口:
對應 Gadget:
ext.gadget.benwiki-ui
這是 BenWiki UI JavaScript 中唯一預設載入的 bootstrap。
它只負責:
- 偵測 DOM component。
- 透過 ResourceLoader 載入對應 Gadget module。
不應直接包含:
- Page Forms persistence 邏輯
- OOUI Dialog
- MediaWiki API query
- multiple-instance 排序
- Infobox interaction
- 各 component 的 presentation 邏輯
ImagePicker
來源:
DOM contract:
.benwiki-ui-image-picker .benwiki-ui-image-picker__raw .benwiki-ui-image-picker__enhancement
負責:
- 選用既有圖片
- 上傳新圖片
- 移除圖片
- Page Forms image field synchronization
- Page Forms preview refresh
Page Forms 仍然是實際 persistence 與 upload engine。
ImageLibrary
來源:
負責:
- 查詢 Wiki 現有圖片
- 圖片搜尋
- 分頁載入
- OOUI 圖片選擇 Dialog
提供:
mw.libs.benwikiImageLibrary.open()
給 ImagePicker 使用。
ImageLibrary 不負責 Page Forms persistence。
Disclosure
來源:
用於表單 optional section 的 progressive disclosure。
DOM contract:
.benwiki-ui-disclosure .benwiki-ui-disclosure__header .benwiki-ui-disclosure__heading .benwiki-ui-disclosure__description .benwiki-ui-disclosure__action .benwiki-ui-disclosure__content
原則:
- JavaScript 不存在時,內容仍然可見。
- JavaScript 成功初始化後才啟用收合。
- 有既存值時自動展開。
- 無值時可以預設收合。
OrderedMultiple
來源:
用來同步 Page Forms multiple-template instance 的排列順序。
DOM contract:
.benwiki-ui-ordered-multiple input.benwiki-ui-order-input
預設排序值:
100 200 300 ...
在 instance 新增、刪除、重新排序與表單送出時重新同步。
InfoboxCollection
來源:
用於 Infobox repeatable collection 的 progressive disclosure。
JavaScript 不知道 SMW subobject。
是否可以收合、預設狀態與自動收合 threshold 都由 Infobox presentation schema 提供。
目前 DOM contract:
.benwiki-infobox-collection-heading .benwiki-infobox-collection-heading__label .benwiki-infobox-collection-heading__summary .benwiki-infobox-collection-heading__action .benwiki-infobox-collection-content
例如:
interaction = {
collapsible = true,
default = 'auto',
collapseThreshold = 5,
countLabel = ' 個帳號'
}
auto 模式會依 collection 實際 item 數量決定初始展開狀態。
沒有 JavaScript 時 collection 保持完整顯示,不會因互動元件失效而造成資料不可閱讀。
SMW Deferred collection 不應在初始 placeholder 階段計算資料筆數。
ext.smw.deferred 完成結果替換後會觸發:
mw.hook( 'smw.deferred.query' )
InfoboxCollection 使用此 lifecycle hook 重新同步實際 item 數量。
若 Gadget 載入時 deferred query 已經完成,則會直接檢查目前 DOM 並同步,不依賴事件先後順序。
ResourceLoader
Gadget registration 位於:
Bootstrap:
hidden default
各 component:
hidden 非 default
由 bootstrap 依目前頁面的 DOM 實際需要載入。
MutationObserver 原則
不要建立一個全站大型 MutationObserver。
只有確實需要處理動態 DOM 的 component 才建立 observer,而且監控範圍應盡量局部。
目前:
- ImagePicker
- 只需要處理表單內可能動態產生的圖片欄位。
- Disclosure
- server-rendered section 初始化一次即可,不需要長期 observer。
- OrderedMultiple
- 只監控 Page Forms multiple-instance 相關 root。
- InfoboxCollection
- 不使用 MutationObserver。
- 一般 server-rendered collection 可直接初始化。
- 若 collection 內容來自 Semantic MediaWiki Deferred,則透過 SMW 官方的
smw.deferred.queryhook,在 deferred query 完成後同步 collection item 數量與初始收合狀態。
Progressive enhancement
BenWiki UI JavaScript 應遵守:
沒有 JavaScript → 核心資料仍可閱讀或編輯 JavaScript 成功 → 提供額外便利互動
JavaScript failure 不應造成核心資料消失或無法操作。
新增 Component
新增前端 component 時:
- 建立獨立 Gadget JavaScript page。
- 在 MediaWiki:Gadgets-definition 註冊 hidden ResourceLoader module。
- 定義穩定的 DOM contract。
- 在 bootstrap registry 註冊 selector 與 module。
- 僅加入真正需要的 ResourceLoader dependency。
- 更新本頁架構文件。
不要把新功能重新塞回 bootstrap。
Rights
來源:
用於依 MediaWiki effective right 控制 BenWiki UI 入口的可見性。
DOM contract:
.benwiki-ui-requires-right data-benwiki-right="createpage"
例如:
<div
class="benwiki-ui-requires-right"
data-benwiki-right="createpage"
style="display:none"
>
...
</div>
元素在 server-rendered wikitext 中必須預設隱藏。
由於 MediaWiki wikitext sanitizer 不保留 hidden attribute,
此 component 使用 style="display:none" 作為安全的預設隱藏狀態。
JavaScript 取得目前使用者的 effective rights;
只有具備 data-benwiki-right 指定權限時,
才移除 display:none。
這只控制 UI 可見性,不作為授權機制。 實際操作權限仍由 MediaWiki server-side permission enforcement 負責。