fix: 修复行缘、切分还原与语言解析并同步文档
保留逐字 margin/jiya.bias 字体后备方案;补齐 demo 重排、量测边界说明及共享规则 1.0.1 反例向量。 验证:完整构建通过,Node 376 项、WKWebView 64 项及原生 demo 9 项通过;Firefox 仍暂缓。
This commit is contained in:
@@ -352,6 +352,97 @@
|
||||
});
|
||||
layoutJz.revert(layoutFixture);
|
||||
layoutJz.disconnect();
|
||||
var auditRoot = document.createElement("section");
|
||||
auditRoot.lang = "zh-Hant";
|
||||
auditRoot.style.cssText = "font-size:20px;width:600px;text-align:left";
|
||||
document.body.appendChild(auditRoot);
|
||||
[ false, true ].forEach(function (orphan)
|
||||
{
|
||||
auditRoot.innerHTML = '<p>前甲「乙丙」</p>';
|
||||
var edgeOwner = Juzhen.createJuzhen({ orphan: orphan, spacing: false, longWord: false });
|
||||
edgeOwner.render(auditRoot);
|
||||
record("同行 orphan 不製造行首,orphan=" + orphan,
|
||||
!auditRoot.querySelector(".bd-open").classList.contains("jz-half-le"));
|
||||
edgeOwner.revert(auditRoot);
|
||||
edgeOwner.disconnect();
|
||||
});
|
||||
[ "inline", "inline-block", "contents", "block" ].forEach(function (display)
|
||||
{
|
||||
auditRoot.innerHTML = '<p>前甲<x-box style="display:' + display + '">「乙」</x-box>丙</p>';
|
||||
var edgeOwner = Juzhen.createJuzhen({ isolateSelector: "x-box", orphan: false, spacing: false, longWord: false });
|
||||
edgeOwner.render(auditRoot);
|
||||
record("自訂隔離元素按物理行內流判斷,display=" + display,
|
||||
Array.from(auditRoot.querySelectorAll("jz-char")).every(function (char)
|
||||
{
|
||||
return char.classList.contains("jz-half-le") === (display === "block");
|
||||
}));
|
||||
edgeOwner.revert(auditRoot);
|
||||
edgeOwner.disconnect();
|
||||
});
|
||||
[ false, true ].forEach(function (hidden)
|
||||
{
|
||||
auditRoot.innerHTML = '<p>甲」<br' + (hidden ? ' style="display:none"' : '') + '>「乙</p>';
|
||||
var edgeOwner = Juzhen.createJuzhen({ orphan: false, spacing: false, longWord: false });
|
||||
edgeOwner.render(auditRoot);
|
||||
record("BR 是強制行緣,hidden=" + hidden,
|
||||
Array.from(auditRoot.querySelectorAll("jz-char")).every(function (char)
|
||||
{
|
||||
return char.classList.contains("jz-half-le") === !hidden;
|
||||
}));
|
||||
edgeOwner.revert(auditRoot);
|
||||
edgeOwner.disconnect();
|
||||
});
|
||||
auditRoot.innerHTML = '<p><strong class="original">甲乙丙</strong>,丁</p>';
|
||||
var splitOwner = Juzhen.createJuzhen({ orphan: false, spacing: false, longWord: false });
|
||||
splitOwner.render(auditRoot);
|
||||
var splitFragment = auditRoot.querySelector('[data-jz-kind="splitoff"]');
|
||||
var inserted = document.createElement("strong");
|
||||
inserted.className = "external";
|
||||
inserted.textContent = "新";
|
||||
splitFragment.before(inserted);
|
||||
splitOwner.revert(auditRoot);
|
||||
record("splitoff 不將邊界字移入外部同標籤兄弟",
|
||||
inserted.textContent === "新" && splitFragment.textContent === "丙"
|
||||
&& splitFragment.className === "original" && !splitFragment.hasAttribute("data-jz")
|
||||
&& auditRoot.textContent === "甲乙新丙,丁");
|
||||
splitOwner.disconnect();
|
||||
auditRoot.innerHTML = '<p lang="zh-Hans-x-hant">甲,乙</p><p lang="zh-TW-x-hans">甲,乙</p><p lang="">甲,乙</p>';
|
||||
var localeOwner = Juzhen.createJuzhen({ orphan: false, jinze: false });
|
||||
localeOwner.render(auditRoot);
|
||||
var localeChars = auditRoot.querySelectorAll("jz-char");
|
||||
record("語言私用部分不覆寫 script/region,空值為未知",
|
||||
localeChars[0].classList.contains("jz-half")
|
||||
&& !localeChars[1].classList.contains("jz-half")
|
||||
&& !localeChars[2].classList.contains("jz-half"));
|
||||
localeOwner.revert(auditRoot);
|
||||
localeOwner.disconnect();
|
||||
var splitMatrixPass = true;
|
||||
var splitOrders = [ [0,1,2], [0,2,1], [1,0,2], [1,2,0], [2,0,1], [2,1,0] ];
|
||||
[ '<strong>甲乙丙丁</strong>,戊己', '「<strong>甲乙丙丁</strong>」',
|
||||
'<strong><em>甲乙丙丁</em></strong>,戊己',
|
||||
'<strong class="author" style="color:red">甲乙丙丁</strong>,戊己',
|
||||
'<strong>甲乙𠀀\uDB40\uDD00丙丁</strong>,戊己',
|
||||
'<strong data-jz="author" data-jz-kind="author">甲乙丙丁</strong>,戊己'
|
||||
].forEach(function (html)
|
||||
{
|
||||
splitOrders.forEach(function (order)
|
||||
{
|
||||
auditRoot.innerHTML = '<p>' + html + '</p>';
|
||||
var p = auditRoot.firstElementChild;
|
||||
var original = p.innerHTML;
|
||||
var owners = [
|
||||
Juzhen.createJuzhen({ jiya: false, spacing: false, orphan: false, longWord: false }),
|
||||
Juzhen.createJuzhen({ jiya: false, spacing: false, jinze: false, longWord: false }),
|
||||
Juzhen.createJuzhen({ spacing: false, orphan: false, longWord: false })
|
||||
];
|
||||
owners.forEach(function (owner) { owner.render(p); });
|
||||
order.forEach(function (index) { owners[index].revert(p); });
|
||||
if (p.innerHTML !== original) { splitMatrixPass = false; }
|
||||
owners.forEach(function (owner) { owner.disconnect(); });
|
||||
});
|
||||
});
|
||||
record("私有切分來源鏈支援多實例六種回退順序,36 組合", splitMatrixPass);
|
||||
auditRoot.remove();
|
||||
var moduleFixture = document.getElementById("module-fixture");
|
||||
var splitSurrogate = document.getElementById("surrogate-spacing");
|
||||
[ "\uD840", "\uDC00", "\uDB40", "\uDD00" ].forEach(function (part, index)
|
||||
|
||||
+6
-5
@@ -16,8 +16,8 @@
|
||||
font-family: system-ui, sans-serif;
|
||||
}
|
||||
/* 字型類獨立於 .juzhen:A 用裸 .cn(瀏覽器原生排版),B/C 才掛 .juzhen
|
||||
(含 normalize 之 text-spacing-trim:space-all)。否則 A 之原生標點被 space-all
|
||||
撐開、顯得比 B 鬆,造成「B 似乎有效」之假象(實則 B 全形未擠、與真原文等寬)。 */
|
||||
(禁用原生 text-autospace)。聚珍不設定 text-spacing-trim;A 保留瀏覽器原生
|
||||
排版,B/C 使用相同受管基線以比較 halt 與 margin。 */
|
||||
/* 字型設於容器即可——聚珍不管字型(無 _lang.css)、亦不強制 jz-inner(`font:
|
||||
inherit`),故消費端字型經繼承正確套到標點字面(標點亦以 FZShuSong 渲染,halt
|
||||
確實缺席)。此即「字型由消費端負責」之示例。 */
|
||||
@@ -47,8 +47,9 @@
|
||||
<body>
|
||||
<h1>方正書宋 GBK · margin 後備模式</h1>
|
||||
<p class="meta">
|
||||
此字型僅含 <code>vert</code>、<b>無 <code>halt</code></b>,故 halt 模式之開明式擠壓「完全無效」(標點仍佔全形)。
|
||||
margin 後備模式以負 margin 依字形偏側收半形——本字型簡體點號(,、。;:!?)墨色皆偏左下,故收右側空白。
|
||||
本頁需本機安裝指定版本的方正書宋 GBK;若發生字型替代,下列比較不能作該字型驗收。
|
||||
已測版本僅含 <code>vert</code>、<b>無 <code>halt</code></b>,故 halt 模式之開明式擠壓「完全無效」(標點仍佔全形)。
|
||||
margin 後備模式以 0.5em 外盒收半形、內盒依墨色偏側定位——本字型簡體點號(,、。;:!?)墨色皆偏左下,故收右側空白。
|
||||
白底行盒寬度即直接反映效果:B 與 A 同寬(未擠),C 明顯窄一截(已擠)。
|
||||
</p>
|
||||
|
||||
@@ -78,7 +79,7 @@
|
||||
.render(document.getElementById("margin"));
|
||||
// A 面板留原文(不 render)。
|
||||
// 註:margin 模式以 width:0.5em+字身溢出定位,標點 advance 真為 0.5em;整句
|
||||
// 行寬 halt 24.0em → margin 19.5em(10 標點各收 0.5em),可於瀏覽器 devtools 量。
|
||||
// 整句行寬差取決於實際壓縮字符及目標字型,可於瀏覽器 devtools 量;不以固定 em 值驗收。
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+11
-1
@@ -108,24 +108,32 @@
|
||||
});
|
||||
}
|
||||
var jz = makeJz();
|
||||
var rendered = false;
|
||||
var statusEl = document.getElementById("status");
|
||||
function render()
|
||||
{
|
||||
jz.revert(document.body); // 先還原(重套政策時清除上次產物;首次為 no-op)
|
||||
jz = makeJz();
|
||||
jz.render(document.body);
|
||||
rendered = true;
|
||||
statusEl.textContent = "已 render(" + document.querySelectorAll("jz-hws").length + " 间隙、" + document.querySelectorAll("jz-char").length + " 标点原子;繁体政策:"
|
||||
+ (forceKaiming ? "开明式" : "全角式") + ")";
|
||||
}
|
||||
function revert()
|
||||
{
|
||||
jz.revert(document.body);
|
||||
rendered = false;
|
||||
statusEl.textContent = "已 revert(DOM 还原)";
|
||||
}
|
||||
function refreshLayout()
|
||||
{
|
||||
// 對齊/寬度改變不一定改變 body 尺寸,須顯式重算;revert 後保持停用。
|
||||
if (rendered) { jz.rerender(document.body); }
|
||||
}
|
||||
document.getElementById("force-kaiming").addEventListener("change", function (e)
|
||||
{
|
||||
forceKaiming = e.target.checked;
|
||||
render();
|
||||
if (rendered) { render(); }
|
||||
});
|
||||
// 量測每個 jz-char 之實際渲染寬度(em)。輸出純 ASCII(碼位+class+數值),
|
||||
// 並按 lang/codepoint/class 去重,便於回報診斷 halt 是否生效、收哪側。
|
||||
@@ -167,6 +175,7 @@
|
||||
document.getElementById("justify").addEventListener("change", function (e)
|
||||
{
|
||||
document.body.classList.toggle("justify", e.target.checked);
|
||||
refreshLayout();
|
||||
});
|
||||
document.getElementById("wide").addEventListener("change", function (e)
|
||||
{
|
||||
@@ -174,6 +183,7 @@
|
||||
{
|
||||
el.style.maxWidth = e.target.checked ? "none" : "";
|
||||
});
|
||||
refreshLayout();
|
||||
});
|
||||
render();
|
||||
</script>
|
||||
|
||||
@@ -76,14 +76,17 @@
|
||||
|
||||
<script src="../dist/juzhen.iife.js"></script>
|
||||
<script>
|
||||
// 全頁一次渲染(quanjiao 全角式,與下游回饋之政策一致);各框由其 lang 屬性
|
||||
// 驅動簡/繁字形。(標點懸掛已移除,見 ARCHITECTURE §6.5.6。)
|
||||
Juzhen.createJuzhen({ scope: { include: ".juzhen" }, lang: { style: "quanjiao" } })
|
||||
.render(document.body);
|
||||
// 各獨立拖曳框作為 render 根,讓 ResizeObserver 直接觀察其寬度。
|
||||
// quanjiao 全角式;各框由 lang 驅動簡/繁字形。
|
||||
var jz = Juzhen.createJuzhen({ scope: { include: ".juzhen" }, lang: { style: "quanjiao" } });
|
||||
var boxes = Array.from(document.querySelectorAll(".box.juzhen"));
|
||||
boxes.forEach(function (box) { jz.render(box); });
|
||||
|
||||
document.getElementById("t-justify").addEventListener("change", function (e)
|
||||
{
|
||||
document.body.classList.toggle("justify", e.target.checked);
|
||||
// 對齊改變未必產生 resize,不能只等 observer。
|
||||
boxes.forEach(function (box) { jz.rerender(box); });
|
||||
});
|
||||
document.getElementById("t-gaps").addEventListener("change", function (e)
|
||||
{
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@
|
||||
<p class="look">末行=「<strong>願意」。</strong>」——保 <strong>2 個實義字</strong>(願意);尾隨 <code>」。</code> 隨尾段綁入但不佔 N(開紫框見綁定範圍含標點,且整個 <code>「我願意」</code> 禁則群組跨 <code>jz-jinze</code> 不被切割)。</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="hint">邊界:段落實義字 < N(或單行段)→ 不綁、無副作用。極窄容器(<N 字寬)→ 該尾段可能溢出(罕見)。</p>
|
||||
<p class="hint">邊界:段落實義字 < N → 不綁。單行段仍可能建立尾段綁定,但不需拉字換行、效果無害。極窄容器(<N 字寬)→ 該尾段可能溢出(罕見)。</p>
|
||||
</div>
|
||||
|
||||
<!-- ===================== 三、標點懸掛(已移除) ===================== -->
|
||||
|
||||
Reference in New Issue
Block a user