feat: 垂懸字避免(方案 C,斷行層無測量,order 70)(§6.5.1)
段末行 CJK 實義字數 ≥ N(預設 2;標點/符號不計)。standalone 段落級 pass:
自段末向前數 N 個實義字,把「第 N 字起至段末」(含其間/尾隨標點)包入
<jz-orphan>(white-space:nowrap)。該整體不可斷 → 末行恒含之 ⇒ 末行實義字 ≥ N,
任意寬度/字型/瀏覽器成立,無需量測 layout。
要點:
- 邊界字定位跨 jz-jinze/行內元素攀爬:實義字落於行內元素內時綁定整個塊級
直接子(不切割 nowrap 群、revert 乾淨);僅裸文本直接子才精確切分(最小綁定)。
- 僅處理葉段落(無塊級後代);段落實義字 < N 不綁;單行段方案 C 本就無害。
- 選項 orphan?: boolean | { chars? };**預設開 chars=2**(§6.5.6 建議);
下游可 orphan:false 關閉。段落級,data-jz-level=text 子樹自動跳過。
- order=70:jinze(40)/spacing(50)/longWord(60) 後、layout pass(90/92) 前。
新增 _orphan.css(jz-orphan{white-space:nowrap});JzTag 加 jz-orphan。
9 項單元測試(末 N+尾標點、chars 選項、標點不計、實義字<N 不綁、跨 jinze、
關閉、冪等、revert、段落級閘)。共 85 測試全綠。
窄容器拖動「末行恒 ≥N」之 layout 驗證留待 demo(Step 4-5,瀏覽器)。
This commit is contained in:
@@ -702,3 +702,83 @@ test("分級:預設(無標記)塊級元素為段落級——禁則照常",
|
||||
createJuzhen().render(document.body);
|
||||
assert.ok(countTag(document.querySelector("p"), "jz-jinze") >= 1, "預設段落級,禁則綁定");
|
||||
});
|
||||
|
||||
// ----- 垂懸字避免(§6.5.1,方案 C)-----
|
||||
|
||||
test("垂懸字:末 N 實義字+尾隨標點包入 jz-orphan(預設 chars=2)", () =>
|
||||
{
|
||||
const { document } = setupDom('<p lang="zh-Hant">甲乙,丙丁。</p>');
|
||||
createJuzhen().render(document.body);
|
||||
const p = document.querySelector("p");
|
||||
const orphan = p.querySelector("jz-orphan");
|
||||
assert.ok(orphan, "應產生 jz-orphan");
|
||||
assert.equal(orphan.textContent, "丙丁。", "綁定末 2 實義字(丙丁)+尾隨句號");
|
||||
assert.equal(p.textContent, "甲乙,丙丁。", "textContent 不變");
|
||||
});
|
||||
|
||||
test("垂懸字:chars 選項可調(chars=3 綁末 3 實義字)", () =>
|
||||
{
|
||||
const { document } = setupDom('<p lang="zh-Hant">甲乙,丙丁。</p>');
|
||||
createJuzhen({ orphan: { chars: 3 } }).render(document.body);
|
||||
const orphan = document.querySelector("jz-orphan");
|
||||
assert.equal(orphan.textContent, "乙,丙丁。", "綁定末 3 實義字(乙丙丁)+其間/尾標點");
|
||||
});
|
||||
|
||||
test("垂懸字:標點/符號不計實義字數(逗號不計)", () =>
|
||||
{
|
||||
const { document } = setupDom('<p lang="zh-Hant">讀書,思考,寫作。</p>');
|
||||
createJuzhen().render(document.body);
|
||||
const orphan = document.querySelector("jz-orphan");
|
||||
// 實義字 讀書思考寫作(6),末 2=寫作;逗號不計入。
|
||||
assert.equal(orphan.textContent, "寫作。", "末 2 實義字=寫作,標點不計");
|
||||
});
|
||||
|
||||
test("垂懸字:段落實義字 < N 不綁(單字段)", () =>
|
||||
{
|
||||
const { document } = setupDom('<p lang="zh-Hant">嗯。</p>');
|
||||
createJuzhen().render(document.body);
|
||||
assert.equal(countTag(document.querySelector("p"), "jz-orphan"), 0, "實義字 1 < 2,不綁");
|
||||
});
|
||||
|
||||
test("垂懸字:邊界字落於 jz-jinze 內 → 綁定整個群組(跨 jinze 攀爬、不切割)", () =>
|
||||
{
|
||||
const { document } = setupDom('<p lang="zh-Hant">他說「好」</p>');
|
||||
createJuzhen({ orphan: { chars: 1 } }).render(document.body);
|
||||
const orphan = document.querySelector("jz-orphan");
|
||||
assert.equal(orphan.textContent, "「好」", "末 1 實義字 好 在 jz-jinze 內 → 綁整個 「好」");
|
||||
assert.equal(orphan.querySelectorAll("jz-jinze").length, 1, "jz-jinze 整體納入、未被切割");
|
||||
});
|
||||
|
||||
test("垂懸字:orphan:false 關閉(無 jz-orphan)", () =>
|
||||
{
|
||||
const { document } = setupDom('<p lang="zh-Hant">甲乙,丙丁。</p>');
|
||||
createJuzhen({ orphan: false }).render(document.body);
|
||||
assert.equal(countTag(document.querySelector("p"), "jz-orphan"), 0, "關閉時不產生 jz-orphan");
|
||||
});
|
||||
|
||||
test("垂懸字:冪等——重跑不重複包裹", () =>
|
||||
{
|
||||
const { document } = setupDom('<p lang="zh-Hant">甲乙,丙丁。</p>');
|
||||
const jz = createJuzhen();
|
||||
jz.render(document.body);
|
||||
const first = countTag(document.body, "jz-orphan");
|
||||
jz.render(document.body);
|
||||
assert.equal(countTag(document.body, "jz-orphan"), first, "第二次 render 不增加 jz-orphan");
|
||||
});
|
||||
|
||||
test("垂懸字:revert 還原(無 jz-orphan,textContent 回原樣)", () =>
|
||||
{
|
||||
const { document } = setupDom('<p lang="zh-Hant">甲乙,丙丁。</p>');
|
||||
const jz = createJuzhen();
|
||||
jz.render(document.body);
|
||||
jz.revert(document.body);
|
||||
assert.equal(countTag(document.body, "jz-orphan"), 0, "revert 清除 jz-orphan");
|
||||
assert.equal(document.querySelector("p").textContent, "甲乙,丙丁。", "文字回原樣");
|
||||
});
|
||||
|
||||
test("垂懸字:段落級——data-jz-level=text 子樹跳過", () =>
|
||||
{
|
||||
const { document } = setupDom('<p data-jz-level="text" lang="zh-Hant">甲乙,丙丁。</p>');
|
||||
createJuzhen().render(document.body);
|
||||
assert.equal(countTag(document.querySelector("p"), "jz-orphan"), 0, "text-level 不跑垂懸字");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user