🦄 Sync 2026-10-02 14:52:05

This commit is contained in:
github-actions[bot] committed 2026-10-02 14:52:05 +08:00
1 parent 4c85793342
commit 0bfe84f1e8
133 files changed
+7983 -3225

No files matched your search

@@ -2232,6 +2232,7 @@
维持原有排版与横向滚动。 */
var TBL_CLS = 'liquid-actions-overflow';
var tblTimer = null;
var tblRaf = 0;
/* 元素内容盒宽度:clientWidth 减掉左右 padding(表格比的是父级内容区) */
function contentBoxWidth(el) {
@@ -2256,50 +2257,156 @@
return w;
}
function tableOverflows(t) {
var doc = document.documentElement;
var parent = t.parentElement;
/* 1) 表格内容已超出表格盒(自身裁剪 / 内部横滚) */
if (t.scrollWidth > t.clientWidth + 1)
return true;
/* 2) 核心:需求宽(按钮横排放得下)> 可用宽 → 从按钮开始折 */
var need = needWidth(t);
var avail = parent ? contentBoxWidth(parent) : Infinity;
if (need > avail + 1 || need > doc.clientWidth + 1)
return true;
/* 3) 表格盒右缘已越出屏幕、且文档无法横向滚过去(被祖先裁切) */
var rect = t.getBoundingClientRect();
return rect.right > doc.clientWidth + 1 && doc.scrollWidth <= doc.clientWidth + 1;
/* 在“自然状态”(未折叠 + 操作列内联列宽为空)下执行 fn,随后原样还原。
所有样式改动与读数都发生在同一任务内,浏览器不会在中途绘制 ——
所以这套测量不会像“120ms 后再改样式”那样被肉眼看到(闪一下)。
内联列宽只在测量期间临时清空:量的才是“按钮横排放得下”的真实
需求宽(form.js stabilizeActionColumnWidth 写的值在折叠态下是
纵排后的 ~63px,会把需求宽算小)。 */
function inNaturalState(t, fn) {
var had = t.classList.contains(TBL_CLS);
if (had) t.classList.remove(TBL_CLS);
var acts = t.querySelectorAll('th.cbi-section-actions, td.cbi-section-actions');
var saved = [];
for (var i = 0; i < acts.length; i++) {
saved.push([acts[i], acts[i].style.width, acts[i].style.minWidth]);
acts[i].style.width = '';
acts[i].style.minWidth = '';
}
var ret = fn();
for (var k = 0; k < saved.length; k++) {
saved[k][0].style.width = saved[k][1];
saved[k][0].style.minWidth = saved[k][2];
}
if (had) t.classList.add(TBL_CLS);
return ret;
}
function updateOverflowTables() {
function tableOverflows(t) {
/* 全程在“自然状态”(未折叠 + 操作列内联宽为空)下判定:
类的摘挂、内联宽的清还都在同一任务内完成,浏览器中途不绘制
→ 测量本身不产生可见闪动 */
return inNaturalState(t, function () {
var doc = document.documentElement;
var parent = t.parentElement;
/* 1) 表格内容已超出表格盒(自身裁剪 / 内部横滚) */
if (t.scrollWidth > t.clientWidth + 1)
return true;
/* 2) 核心:需求宽(按钮横排放得下)> 可用宽 → 从按钮开始折 */
var need = needWidth(t);
var avail = parent ? contentBoxWidth(parent) : Infinity;
if (need > avail + 1 || need > doc.clientWidth + 1)
return true;
/* 3) 表格盒右缘已越出屏幕、且文档无法横向滚过去(被祖先裁切) */
var rect = t.getBoundingClientRect();
return rect.right > doc.clientWidth + 1 && doc.scrollWidth <= doc.clientWidth + 1;
});
}
/* form.js stabilizeActionColumnWidth 把操作列锁成内联 width/min-width;
折叠态下它量到的是“按钮纵排”宽(~63px),解除折叠后这个残留值会
卡住按钮 —— 只在“取消折叠”这一刻清掉,平时不动它(否则每次判定
都会改动列宽 → 页面闪一下) */
function clearActionInlineWidths(t) {
var acts = t.querySelectorAll('th.cbi-section-actions, td.cbi-section-actions');
for (var i = 0; i < acts.length; i++) {
if (acts[i].style.width || acts[i].style.minWidth) {
acts[i].style.width = '';
acts[i].style.minWidth = '';
}
}
}
/* 给多列表的单元格回填 data-title(文案取自同列表头 th)——窄屏"单元格
自带表头"(td::before { content: attr(data-title) },Argon 同款)依赖它。
概览 include 表(DHCP 租约 / DDNS / WiFi / UPnP …)与 DDNS 服务页的
自绘单元格都没有 data-title,这里统一补齐:只补缺失、不覆盖已有、
跳过操作列;轮询重绘出的新行下次判定时会补上。attribute 写入不触发
我们只监听 childList 的观察者 → 不会造成回调循环。 */
function backfillCellTitles() {
var tables = document.querySelectorAll('table.cbi-section-table, table.table');
for (var i = 0; i < tables.length; i++) {
var t = tables[i];
var head = t.querySelector(':scope > thead > tr, :scope > tbody > tr.table-titles, :scope > tbody > tr.cbi-section-table-titles, :scope > tr.table-titles');
if (!head) continue;
var ths = head.children;
var rows = t.querySelectorAll(':scope > tbody > tr');
for (var r = 0; r < rows.length; r++) {
var cells = rows[r].children;
for (var c = 0; c < ths.length && c < cells.length; c++) {
var cell = cells[c];
if (cell.tagName !== 'TD' || cell.hasAttribute('data-title') ||
cell.classList.contains('cbi-section-actions'))
continue;
var txt = (ths[c].innerText || ths[c].textContent || '')
.replace(/\s+/g, ' ').trim();
if (txt) cell.setAttribute('data-title', txt);
}
}
}
}
/* 多列表响应式打标:视口 ≤1100px 时给表格加 .liquid-grid(CSS 端据此
切到"一行三列 + 单元格自带表头")。断点放在这里(matchMedia 单一来源),
CSS 只认类、用 !important 压过 ≤854px 既有的 display:flex 规则。
1100px 是实测值:1150px 时中间列尚有 6.5 字/行,1100px 掉到 4.3;
移动端则是整表按内容宽撑开、只能横向滚动。 */
function syncGridView() {
var narrow = window.matchMedia
? window.matchMedia('(max-width: 1100px)').matches
: window.innerWidth <= 1100;
var list = document.querySelectorAll('table.cbi-section-table, table.table');
for (var i = 0; i < list.length; i++) {
var t = list[i];
t.classList.remove(TBL_CLS);
/* 清掉 form.js stabilizeActionColumnWidth 写死的内联列宽:
类还在时它量到的是“按钮纵排”的宽度(最宽按钮 ~63px),
窗口变宽、类移除后这个残留值会让 needWidth 少算一截、
判定漏折;清掉后列宽回归 auto 布局(= 按钮横排的
max-content,与 stabilize 结果一致),量到的才是
“按钮横排放得下”所需的真实宽度 */
var acts = t.querySelectorAll('th.cbi-section-actions, td.cbi-section-actions');
for (var j = 0; j < acts.length; j++) {
if (acts[j].style.width || acts[j].style.minWidth) {
acts[j].style.width = '';
acts[j].style.minWidth = '';
}
/* 两类有专属布局的表不打标(CSS 端同样排除,这里保持标记语义一致):
接口页表(td[data-name="_ifacebox"])、标签/值两列表(td[width="33%"]) */
var skip = t.querySelector('td[data-name="_ifacebox"], td[width="33%"]');
if (narrow && !skip && t.querySelector('td'))
t.classList.add('liquid-grid');
else
t.classList.remove('liquid-grid');
}
}
function updateOverflowTables() {
syncGridView();
backfillCellTitles();
var list = document.querySelectorAll('table.cbi-section-table, table.table');
for (var i = 0; i < list.length; i++) {
var t = list[i];
/* 无操作列的表(概览"系统/内存/存储/网络"等标签-值两列表)与
折叠逻辑无关:不判定、不写任何样式 —— 与标签-值换行新规则
零交集(那套规则只认 td[width="33%"]),稳态下零 DOM 写 */
if (!t.querySelector('.cbi-section-actions')) {
if (t.classList.contains(TBL_CLS))
t.classList.remove(TBL_CLS);
continue;
}
if (t.querySelector('.cbi-section-actions') && tableOverflows(t))
var want = tableOverflows(t);
var has = t.classList.contains(TBL_CLS);
if (want && !has) {
t.classList.add(TBL_CLS);
} else if (!want && has) {
t.classList.remove(TBL_CLS);
clearActionInlineWidths(t);
}
/* 其余两种情况(要折且已折 / 不折且未折)净变化为零,不动 DOM */
}
}
function scheduleOverflowTables() {
/* rAF:在下一帧绘制前完成判定 → 首帧即最终状态,不再看到
“先按一行绘制、再瞬间堆叠”的折叠过程(用户反馈的闪一下) */
if (!tblRaf) {
tblRaf = window.requestAnimationFrame(function () {
tblRaf = 0;
updateOverflowTables();
});
}
/* 仍在 form.js 的 setTimeout(stabilize 列宽) 与其 resize 处理之后
补一次校正,拿到的才是内联列宽写完后的稳定状态 */
if (tblTimer)
clearTimeout(tblTimer);
/* 延后 120ms:排在 form.js 的 setTimeout(stabilize 列宽) 与其
resize 处理之后量,拿到的才是内联列宽写完后的稳定状态 */
tblTimer = setTimeout(function () {
tblTimer = null;
updateOverflowTables();