fix: use semantic data-label keys for alt-IP table row labels

The JS used fragile numeric indices to look up localized labels from the
server-rendered table. When optional rows (ASN, Org, Country, City) were
missing for the primary IP, the indices shifted, causing 'Proxy' to appear
as the City label. Add data-label attributes to each <tr> in the template
and key the label map by name instead of position.
This commit is contained in:
NetworkCats
2026-03-22 16:23:14 +08:00
parent d078859c5c
commit bf3d96ac9c
2 changed files with 21 additions and 22 deletions
+13 -14
View File
@@ -218,10 +218,10 @@ function initCopyIp(wrap){
var labels={};
var rows=root.querySelectorAll(".info-table tbody tr");
for(var i=0;i<rows.length;i++){
var key=rows[i].getAttribute("data-label");
var th=rows[i].querySelector("th");
var td=rows[i].querySelector("td");
if(th&&td){
labels[i]={label:th.textContent.trim(),html:td.innerHTML};
if(key&&th){
labels[key]=th.textContent.trim();
}
}
return labels;
@@ -242,8 +242,8 @@ function initCopyIp(wrap){
return '<i class="icon-minus bool-false" aria-hidden="true"></i>';
}
function labelAt(index){
return existingLabels[index]?existingLabels[index].label:"";
function labelFor(key){
return existingLabels[key]||"";
}
function buildBlock(ip,info){
@@ -265,27 +265,26 @@ function initCopyIp(wrap){
if(asnNum){
var asnStr="AS"+asnNum;
html+='<tr><th scope="row">'+escapeHtml(labelAt(0))+'</th>';
html+='<tr><th scope="row">'+escapeHtml(labelFor("asn"))+'</th>';
html+='<td><a href="https://bgp.tools/as/'+asnNum+'" target="_blank" rel="noopener noreferrer">'+escapeHtml(asnStr)+'</a></td></tr>';
}
if(asnOrg){
html+='<tr><th scope="row">'+escapeHtml(labelAt(1))+'</th>';
html+='<tr><th scope="row">'+escapeHtml(labelFor("org"))+'</th>';
html+='<td>'+escapeHtml(asnOrg)+'</td></tr>';
}
if(countryName){
html+='<tr><th scope="row">'+escapeHtml(labelAt(2))+'</th>';
html+='<tr><th scope="row">'+escapeHtml(labelFor("country"))+'</th>';
html+='<td>'+escapeHtml(countryName)+'</td></tr>';
}
if(cityName){
html+='<tr><th scope="row">'+escapeHtml(labelAt(3))+'</th>';
html+='<tr><th scope="row">'+escapeHtml(labelFor("city"))+'</th>';
html+='<td>'+escapeHtml(cityName)+'</td></tr>';
}
var boolStart=Object.keys(existingLabels).length-4;
html+='<tr><th scope="row">'+escapeHtml(labelAt(boolStart))+'</th><td>'+boolHtml(proxy.is_proxy)+'</td></tr>';
html+='<tr><th scope="row">'+escapeHtml(labelAt(boolStart+1))+'</th><td>'+boolHtml(proxy.is_vpn)+'</td></tr>';
html+='<tr><th scope="row">'+escapeHtml(labelAt(boolStart+2))+'</th><td>'+boolHtml(proxy.is_hosting)+'</td></tr>';
html+='<tr><th scope="row">'+escapeHtml(labelAt(boolStart+3))+'</th><td>'+boolHtml(proxy.is_tor)+'</td></tr>';
html+='<tr><th scope="row">'+escapeHtml(labelFor("proxy"))+'</th><td>'+boolHtml(proxy.is_proxy)+'</td></tr>';
html+='<tr><th scope="row">'+escapeHtml(labelFor("vpn"))+'</th><td>'+boolHtml(proxy.is_vpn)+'</td></tr>';
html+='<tr><th scope="row">'+escapeHtml(labelFor("hosting"))+'</th><td>'+boolHtml(proxy.is_hosting)+'</td></tr>';
html+='<tr><th scope="row">'+escapeHtml(labelFor("tor"))+'</th><td>'+boolHtml(proxy.is_tor)+'</td></tr>';
html+='</tbody></table>';
return html;
+8 -8
View File
@@ -77,42 +77,42 @@
<table class="info-table" aria-label="{{ t_table_aria }}">
<tbody>
{% if !asn.is_empty() %}
<tr>
<tr data-label="asn">
<th scope="row">{{ t_asn }}</th>
<td>{% if let Some(n) = asn_number %}<a href="https://bgp.tools/as/{{ n }}" target="_blank" rel="noopener noreferrer">{{ asn }}</a>{% else %}{{ asn }}{% endif %}</td>
</tr>
{% endif %}
{% if !org.is_empty() %}
<tr>
<tr data-label="org">
<th scope="row">{{ t_org }}</th>
<td itemprop="publisher" itemscope itemtype="https://schema.org/Organization"><span itemprop="name">{{ org }}</span></td>
</tr>
{% endif %}
{% if !country.is_empty() %}
<tr itemprop="contentLocation" itemscope itemtype="https://schema.org/Place">
<tr data-label="country" itemprop="contentLocation" itemscope itemtype="https://schema.org/Place">
<th scope="row">{{ t_country }}</th>
<td itemprop="address" itemscope itemtype="https://schema.org/PostalAddress"><span itemprop="addressCountry">{{ country }}</span>{% if !country_code.is_empty() %}<meta itemprop="addressCountry" content="{{ country_code }}">{% endif %}</td>
</tr>
{% endif %}
{% if !city.is_empty() %}
<tr>
<tr data-label="city">
<th scope="row">{{ t_city }}</th>
<td itemprop="contentLocation" itemscope itemtype="https://schema.org/Place"><span itemprop="name">{{ city }}</span></td>
</tr>
{% endif %}
<tr>
<tr data-label="proxy">
<th scope="row">{{ t_proxy }}</th>
<td>{% if is_proxy %}<i class="icon-check bool-true" aria-hidden="true"></i><span class="sr-only">{{ t_yes }}</span>{% else %}<i class="icon-minus bool-false" aria-hidden="true"></i><span class="sr-only">{{ t_no }}</span>{% endif %}</td>
</tr>
<tr>
<tr data-label="vpn">
<th scope="row">{{ t_vpn }}</th>
<td>{% if is_vpn %}<i class="icon-check bool-true" aria-hidden="true"></i><span class="sr-only">{{ t_yes }}</span>{% else %}<i class="icon-minus bool-false" aria-hidden="true"></i><span class="sr-only">{{ t_no }}</span>{% endif %}</td>
</tr>
<tr>
<tr data-label="hosting">
<th scope="row">{{ t_hosting }}</th>
<td>{% if is_hosting %}<i class="icon-check bool-true" aria-hidden="true"></i><span class="sr-only">{{ t_yes }}</span>{% else %}<i class="icon-minus bool-false" aria-hidden="true"></i><span class="sr-only">{{ t_no }}</span>{% endif %}</td>
</tr>
<tr>
<tr data-label="tor">
<th scope="row">{{ t_tor }}</th>
<td>{% if is_tor %}<i class="icon-check bool-true" aria-hidden="true"></i><span class="sr-only">{{ t_yes }}</span>{% else %}<i class="icon-minus bool-false" aria-hidden="true"></i><span class="sr-only">{{ t_no }}</span>{% endif %}</td>
</tr>