From fd7fd996b1c7135ea4c0477af8414ec8620e447b Mon Sep 17 00:00:00 2001 From: ma91n Date: Tue, 8 Sep 2026 00:39:58 +0900 Subject: [PATCH] =?UTF-8?q?=E5=90=8C=E3=81=98=E5=88=97=E5=90=8D=E3=81=AE?= =?UTF-8?q?=E8=A1=A8=E3=81=8C=E4=B8=A6=E3=82=93=E3=81=A7=E3=82=82=E5=8F=97?= =?UTF-8?q?=E3=81=91=E7=9A=BF=E3=81=AE=E8=AA=AD=E3=81=BF=E4=B8=8A=E3=81=92?= =?UTF-8?q?=E5=90=8D=E3=81=8C=E9=87=8D=E8=A4=87=E3=81=97=E3=81=AA=E3=81=84?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B=20(#3231)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 表を包む .scroll[role=region] の aria-label を見出し行から作っていたため、同じ列名の表が1ページに複数あると名前が同じになり、axe の landmark-unique に当たっていた。2つ目以降は直前の見出しを先に置き、見出しが無いか足しても重なるときだけ連番に落とす。 Co-Authored-By: Claude Fable 5.1 --- scripts/table_filter.js | 47 +++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/scripts/table_filter.js b/scripts/table_filter.js index 0b43745b4272..a9498942d58a 100644 --- a/scripts/table_filter.js +++ b/scripts/table_filter.js @@ -6,8 +6,17 @@ // もとの markd を参考に拡張する // https://github.com/markedjs/marked/blob/e5796ecc435a30f96939e6a7b2229c14264b4bf8/src/Renderer.js#L92 hexo.extend.filter.register('marked:renderer', function (renderer) { + // renderer は1ページの描画ごとに作り直されるので、直前の見出しと既出のラベルを + // ここに持てばページ単位で数えられる (#3231) + const heading = renderer.heading; + renderer.heading = function (text, level, ...rest) { + this._lastHeading = plainText(text); + return heading.call(this, text, level, ...rest); + }; renderer.table = function (header, body) { - return `
${table(header, body)}
\n`; + this._tableLabels ||= new Set(); + const label = uniqueLabel(regionLabel(header), this._lastHeading, this._tableLabels); + return `
${table(header, body)}
\n`; }; }); @@ -17,6 +26,12 @@ const table = (header, body) => { return '\n' + '\n' + header + '\n' + body + '
'; }; +const plainText = (html) => + html + .replace(/<[^>]*>/g, '') + .replace(/\s+/g, ' ') + .trim(); + /** * 横スクロールする器の読み上げ名を、1行目の見出しから組む (#2961)。 * @@ -33,18 +48,28 @@ const table = (header, body) => { * 名前を列名から作るのは、1ページに複数の表があると「表」だけでは区別できないため。 */ const regionLabel = (header) => { - const names = (header.match(/]*>([\s\S]*?)<\/th>/g) || []) - .map((cell) => - cell - .replace(/<[^>]*>/g, '') - .replace(/\s+/g, ' ') - .trim(), - ) - .filter(Boolean); + const names = (header.match(/]*>([\s\S]*?)<\/th>/g) || []).map(plainText).filter(Boolean); if (!names.length) return '表'; // 長い見出しが並ぶ表もあるので頭を取る。 + const joined = names.join(' / ').slice(0, 60); + return `表 ${joined}`; +}; + +/** + * 同じ列名の表が同じページに並ぶと名前が重複する (#3231。axe landmark-unique)。 + * 2つ目以降は直前の見出しを先に置く。連番は順序しか言わないが、見出しは + * どの節の表かを言う。見出しが無いか、足しても重なるときだけ連番に落とす。 + */ +const uniqueLabel = (base, heading, used) => { + const candidates = [base]; + if (heading) candidates.push(`${heading.slice(0, 40)}の${base}`); + let label = candidates.find((c) => !used.has(c)); + for (let n = 2; !label; n++) { + const numbered = `${candidates.at(-1)}(${n})`; + if (!used.has(numbered)) label = numbered; + } + used.add(label); // **& は再エスケープしない。** header は marked が出した HTML で、本文の & は // すでに & になっている。もう一度潰すと &amp; になって読み上げに出る - const joined = names.join(' / ').slice(0, 60); - return `表 ${joined}`.replace(/"/g, '"').replace(/