🍕 Sync 2026-10-23 11:07:40

This commit is contained in:
github-actions[bot] committed 2026-10-23 11:07:40 +08:00
1 parent 56faba2308
commit 6fa3534628
11 files changed
+859 -815

No files matched your search

@@ -14,6 +14,9 @@
* Filter-aware helpers (require an onFilterClick callback):
* filterLink, addrFilterLink, ruleAdminLink, ifaceLink
*
* Focus identity (column slot is not the click field):
* stampFilterField, filterLinkIdentity, findFilterLinkByIdentity
*
* Constant path helper:
* ruleAdminPath
*
@@ -46,14 +49,82 @@ function firewallZonesLink(label) {
);
}
function stampFilterField(node, field, value) {
function stampFilterField(node, field, value, slot) {
if (node && typeof node === 'object') {
node._fwliveFilterField = String(field);
if (value != null) node._fwliveFilterValue = String(value);
if (slot != null && slot !== '') node._fwliveFilterSlot = String(slot);
}
return node;
}
function filterLinkRowId(node) {
if (!node) return null;
if (node._fwliveRowId != null) return String(node._fwliveRowId);
if (node.closest) {
const row = node.closest('tr');
if (row && row._fwliveRowId != null) return String(row._fwliveRowId);
}
return null;
}
function filterLinkIdentity(node) {
if (
!node ||
!node.classList ||
typeof node.classList.contains !== 'function' ||
!node.classList.contains('fwlive-filter-link') ||
node._fwliveFilterField == null
)
return null;
const rowId = filterLinkRowId(node);
if (rowId == null) return null;
const ident = { rowId: rowId, field: String(node._fwliveFilterField) };
if (node._fwliveFilterValue != null) ident.value = String(node._fwliveFilterValue);
if (node._fwliveFilterSlot != null) ident.slot = String(node._fwliveFilterSlot);
return ident;
}
function linkMatchesFilterIdentity(link, ident) {
if (!link || !ident) return false;
if (String(link._fwliveFilterField) !== ident.field) return false;
if (
ident.value != null &&
(link._fwliveFilterValue == null || String(link._fwliveFilterValue) !== ident.value)
)
return false;
if (
ident.slot != null &&
(link._fwliveFilterSlot == null || String(link._fwliveFilterSlot) !== ident.slot)
)
return false;
return filterLinkRowId(link) === ident.rowId;
}
function collectFilterLinks(node, out) {
if (!node) return;
if (
node.nodeType === 1 &&
node.classList &&
typeof node.classList.contains === 'function' &&
node.classList.contains('fwlive-filter-link')
)
out.push(node);
const kids = node.childNodes;
if (!kids) return;
for (let i = 0; i < kids.length; i++) collectFilterLinks(kids[i], out);
}
function findFilterLinkByIdentity(root, ident) {
if (!root || !ident) return null;
const links = [];
collectFilterLinks(root, links);
for (let i = 0; i < links.length; i++) {
if (linkMatchesFilterIdentity(links[i], ident)) return links[i];
}
return null;
}
/**
* @param {string} field - filter field name
* @param {string} value - filter value
@@ -157,8 +228,9 @@ function ruleAdminLink(hint, label, onFilterClick) {
/**
* @param {string} value - interface name
* @param {function} onFilterClick - callback(field, value, ev)
* @param {string} [slot] - focus identity (column id); click field stays interface
*/
function ifaceLink(value, onFilterClick) {
function ifaceLink(value, onFilterClick, slot) {
if (!value) return log.formatCell(value);
return stampFilterField(
@@ -175,7 +247,8 @@ function ifaceLink(value, onFilterClick) {
[value]
),
'interface',
value
value,
slot
);
}
@@ -188,5 +261,8 @@ return baseclass.extend({
addrFilterLink: addrFilterLink,
ruleAdminPath: ruleAdminPath,
ruleAdminLink: ruleAdminLink,
ifaceLink: ifaceLink
ifaceLink: ifaceLink,
stampFilterField: stampFilterField,
filterLinkIdentity: filterLinkIdentity,
findFilterLinkByIdentity: findFilterLinkByIdentity
});
@@ -207,14 +207,15 @@ function buildColumnCell(col, row, state, callbacks) {
}
case 'iface':
return E('td', { 'class': columnCellClass(col) }, [
links.ifaceLink(row.interface, onFilterClick)
links.ifaceLink(row.interface, onFilterClick, 'iface')
]);
case 'iface_in':
case 'iface_out':
return E('td', { 'class': columnCellClass(col) }, [
links.ifaceLink(
col === 'iface_in' ? row.interface_in : row.interface_out,
onFilterClick
onFilterClick,
col
)
]);
case 'dir':
@@ -16,6 +16,7 @@
'require fwlive.chips as chips';
'require fwlive.logging as logging';
'require fwlive.table as table';
'require fwlive.links as links';
'require fwlive.buffer as buffer';
'require fwlive.hostname as hostname';
'require fwlive.proto as proto';
@@ -132,29 +133,9 @@ function restoreExpansionFocus(body, rowId, previousFocus) {
return false;
}
function filterLinkIdentity(node) {
if (
!node ||
!node.classList ||
!node.classList.contains('fwlive-filter-link') ||
node._fwliveFilterField == null
)
return null;
let rowId = node._fwliveRowId;
if (rowId == null && node.closest) {
const row = node.closest('tr');
if (row && row._fwliveRowId != null) rowId = row._fwliveRowId;
}
if (rowId == null) return null;
const ident = { rowId: String(rowId), field: String(node._fwliveFilterField) };
if (node._fwliveFilterValue != null) ident.value = String(node._fwliveFilterValue);
return ident;
}
function restoreFilterLinkFocus(body, previousFocus) {
const ident = filterLinkIdentity(previousFocus);
if (!body || typeof body.querySelectorAll !== 'function' || !ident) return false;
const ident = links.filterLinkIdentity(previousFocus);
if (!body || !ident) return false;
const activeElement = typeof document !== 'undefined' ? document.activeElement : null;
if (
@@ -166,26 +147,11 @@ function restoreFilterLinkFocus(body, previousFocus) {
)
return false;
const links = body.querySelectorAll('a.fwlive-filter-link');
for (let i = 0; i < links.length; i++) {
const link = links[i];
if (String(link._fwliveFilterField) !== ident.field) continue;
if (
ident.value != null &&
(link._fwliveFilterValue == null || String(link._fwliveFilterValue) !== ident.value)
)
continue;
let rowId = link._fwliveRowId;
if (rowId == null && link.closest) {
const row = link.closest('tr');
if (row && row._fwliveRowId != null) rowId = row._fwliveRowId;
}
if (String(rowId) !== ident.rowId) continue;
if ((link !== previousFocus || activeElement !== link) && typeof link.focus === 'function')
link.focus();
return true;
}
return false;
const link = links.findFilterLinkByIdentity(body, ident);
if (!link) return false;
if ((link !== previousFocus || activeElement !== link) && typeof link.focus === 'function')
link.focus();
return true;
}
function isIpv4Address(addr) {