docs: Pass C —— 長英文段 lang 包裝
CHANGELOG 記新項:Pass C 預設啟用之動機(避開原模板 wbr 每 6 字元亂 插之兩個觀感問題:斷點位置與音節無關、斷處不顯連字符),實作要點, 與字型陷阱(CJK serif 把 U+2010 設計為全形 1 em,須消費端加 hyphenate-character: "-" 強制 U+002D)。 index 加 Pass C 完整章節(演算法、消費端 CSS、選取潔淨性、不在範圍 之識別符 / URL);lede 與 attribution 段同步更新雙 pass → 三 pass。
This commit is contained in:
+39
-2
@@ -23,7 +23,7 @@
|
||||
|
||||
<main>
|
||||
|
||||
<p class="lede">Pangu.js v7.2.1 之規則 port,加上「跨樣式標籤透明 + 行內塊邊界」雙 pass 架構。工廠函式設計,由消費端注入 pill 選擇器、樣式 / 段落 / skip 標籤集等配置。輸出 <code><span class="cjk-autospace" aria-hidden="true">(空白)</span></code>,靠 CSS <code>user-select: none</code> 讓選取與剪貼板跳過。textContent 不變 → Copy 與序列化都乾淨。</p>
|
||||
<p class="lede">Pangu.js v7.2.1 之規則 port,加上「跨樣式標籤透明 + 行內塊邊界」雙 pass 架構,再加 Pass C 之「長英文段 <code><span lang></code> 包裝」(給瀏覽器原生 <code>hyphens: auto</code> 用)。工廠函式設計,由消費端注入 pill 選擇器、樣式 / 段落 / skip 標籤集等配置。輸出 <code><span class="cjk-autospace" aria-hidden="true">(空白)</span></code>,靠 CSS <code>user-select: none</code> 讓選取與剪貼板跳過。textContent 不變 → Copy 與序列化都乾淨。</p>
|
||||
|
||||
<h2>Quick start</h2>
|
||||
|
||||
@@ -141,6 +141,42 @@ autospace.apply(document.body);
|
||||
|
||||
<p>結果:<code>命令<span class="cjk-autospace"> </span><code>git</code><span class="cjk-autospace"> </span>更新</code></p>
|
||||
|
||||
<h2>Pass C — long English word wrap(預設啟用)</h2>
|
||||
|
||||
<p>解 CJK 兩端對齊正文中「行末長英文詞」之斷行問題:原靠 <code><wbr></code> 每 N 字元亂插之路徑會產生「斷點位置與音節無關 + 斷處不顯連字符」兩個觀感問題。Pass C 改採 <code><span lang="en"></code> 包裝,把斷字決定權交給瀏覽器原生 <code>hyphens: auto</code> 用內建英文字典處理。</p>
|
||||
|
||||
<ol>
|
||||
<li>對 root 內所有 text node 走 TreeWalker(SHOW_TEXT)</li>
|
||||
<li>對每個 node:先 <code>isSkipped</code>(共用 Pass A / B 之 skip 鏈:CODE / KBD / PRE / SAMP / TT / VAR / SCRIPT / STYLE / TEXTAREA / INPUT / SVG / contentEditable / <code>data-md-key</code>)+ 冪等檢查(parent 為 <code><span lang></code> → skip)</li>
|
||||
<li>對通過篩選之 node:用 <code>[A-Za-z]{minLength,}</code> 收所有匹配,把每個匹配位置之子串裹進 <code><span lang="en"></code>(其餘原文保留為純 text node),整個用 fragment 一次性 replaceChild</li>
|
||||
</ol>
|
||||
|
||||
<h3>消費端 CSS(與 lib 解耦但必須配套)</h3>
|
||||
|
||||
<pre><code>[lang|="en"] {
|
||||
hyphens: auto;
|
||||
-webkit-hyphens: auto;
|
||||
hyphenate-limit-chars: 6 3 3; /* 詞長 / 前 / 後最少字符 */
|
||||
hyphenate-character: "-"; /* 強制 U+002D,避免 CJK 字型把 U+2010 渲成全形 */
|
||||
-webkit-hyphenate-character: "-";
|
||||
}</code></pre>
|
||||
|
||||
<div class="callout warn">
|
||||
<span class="label">字型陷阱</span> Noto Serif CJK SC 等 CJK serif 字型把 U+2010 HYPHEN 設計為全形 1 em(與漢字同寬),以服務 CJK 範圍表達;而 <code>hyphens: auto</code> 預設正是插 U+2010。直接用會看到全形連字符突兀地接在英文詞末。<code>hyphenate-character: "-"</code> 強制改用 U+002D(同字型內為窄拉丁,與作者鍵入的 <code>-</code> 一致),仍為純視覺渲染、DOM 內不存在。
|
||||
</div>
|
||||
|
||||
<h3>選取 / 複製潔淨性</h3>
|
||||
|
||||
<p>連字符純由 CSS 渲染(不存在於 DOM),<code>Selection.toString()</code> 與 <code>Cmd+C</code> 返回原文無污染。包裝 span 本身是 inline,<code>textContent</code> 視為原樣,序列化 / 複製不受影響。</p>
|
||||
|
||||
<h3>不在範圍</h3>
|
||||
|
||||
<ul>
|
||||
<li><strong>CamelCase / 標識符</strong>(<code>getUserByEmailAddress</code>、<code>OpenAIWhisperAPI</code>):不在英文字典 → 瀏覽器不斷詞;本實作未開 <code>overflow-wrap: anywhere</code> fallback(會破壞「連字符必須存在」之原則),故識別符 overflow 時整塊保留</li>
|
||||
<li><strong>URL / 純數字串</strong>:同上,<code>https://example.com/very/long/path</code> 此類超長 token 不被處理</li>
|
||||
<li><strong>非英文之 ASCII 拉丁變體</strong>(café、naïve):正則 <code>[A-Za-z]</code> 不匹配重音字符;如需擴充可自訂 <code>longWordWrap.minLength</code> 之外再 patch lib</li>
|
||||
</ul>
|
||||
|
||||
<h2>空白規則</h2>
|
||||
|
||||
<p>所有觸發點(Pangu 命中或 PILL 邊界),對「插入位置之原有空白」的處理一致:</p>
|
||||
@@ -172,6 +208,7 @@ autospace.apply(document.body);
|
||||
<tr><td><code>skipTags</code></td><td><code>["CODE", "KBD", "PRE", "SAMP", "TT", "VAR", "SCRIPT", "STYLE", "TEXTAREA", "INPUT"]</code></td><td>整 subtree skip,連祖先 chain 一併判斷</td></tr>
|
||||
<tr><td><code>autospaceClass</code></td><td><code>"cjk-autospace"</code></td><td>marker span 之 class 名</td></tr>
|
||||
<tr><td><code>skipAttribute</code></td><td><code>"data-md-key"</code></td><td>任一祖先帶此屬性 → 整 subtree skip</td></tr>
|
||||
<tr><td><code>longWordWrap</code></td><td><code>true</code>(預設啟用)</td><td>Pass C 開關。傳 <code>false</code> 顯式關閉;<code>{ minLength, lang }</code> 自訂粒度與標語;<code>true</code> / 省略等同 <code>{ minLength: 6, lang: "en" }</code></td></tr>
|
||||
<tr><td><code>isSkipped</code></td><td>(無)</td><td>自訂 callback;先於內建判定執行;回傳 true 即 skip</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -273,7 +310,7 @@ obs.observe(document.body, { childList: true, subtree: true, characterData: true
|
||||
|
||||
<h2>授權與來源</h2>
|
||||
|
||||
<p>規則表 port 自 <a href="https://github.com/vinta/pangu.js">Pangu.js v7.2.1</a>(MIT 授權)。本 lib 之雙 pass 架構(樣式透明 + 行內塊邊界)為原創設計,解決 Pangu.js 原版「text-node walker 看不到跨元素邊界」之問題。</p>
|
||||
<p>規則表 port 自 <a href="https://github.com/vinta/pangu.js">Pangu.js v7.2.1</a>(MIT 授權)。本 lib 之三 pass 架構(樣式透明 + 行內塊邊界 + 長英文 lang 包裝)為原創設計,前兩 pass 解決 Pangu.js 原版「text-node walker 看不到跨元素邊界」之問題;Pass C 把 CJK 兩端對齊正文中之斷英文詞責任交給瀏覽器原生 <code>hyphens: auto</code>。</p>
|
||||
|
||||
</main>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user