mirror of
https://github.com/brianshea2/meshmap.net.git
synced 2025-03-05 21:00:01 -08:00
handle special characters (e.g., newlines) in node data (#31)
This commit is contained in:
parent
92dcb58981
commit
ca2b7b3dd1
|
@ -97,7 +97,9 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<div><a href="https://meshmap.net/" title="A nearly live map of Meshtastic nodes seen by the official Meshtastic MQTT server">MeshMap</a></div>
|
<div>
|
||||||
|
<a href="https://meshmap.net/" title="A nearly live map of Meshtastic nodes seen by the official Meshtastic MQTT server">MeshMap</a>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
|
@ -126,8 +128,10 @@
|
||||||
182, 91, 46, 23, 11, 6, 3, 1,
|
182, 91, 46, 23, 11, 6, 3, 1,
|
||||||
1, 0, 0, 0, 0, 0, 0, 0
|
1, 0, 0, 0, 0, 0, 0, 0
|
||||||
]
|
]
|
||||||
// encodes html reserved characters
|
// encodes html reserved characters and ascii control characters
|
||||||
const html = str => str?.replace(/["&<>]/g, match => `&#${match.charCodeAt(0)};`)
|
const html = str => str
|
||||||
|
?.replace(/[\x00-\x1F]/g, c => `\\x${c.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0')}`)
|
||||||
|
.replace(/["&<>]/g, c => `&#${c.charCodeAt(0)};`)
|
||||||
// makes more human-readable time duration strings
|
// makes more human-readable time duration strings
|
||||||
const duration = d => {
|
const duration = d => {
|
||||||
let s = ''
|
let s = ''
|
||||||
|
@ -232,22 +236,23 @@
|
||||||
<div class="title">${html(longName)} (${html(shortName)})</div>
|
<div class="title">${html(longName)} (${html(shortName)})</div>
|
||||||
<div>${nodeLink(nodeNum, id)} | ${html(role)} | ${html(hwModel)}</div>
|
<div>${nodeLink(nodeNum, id)} | ${html(role)} | ${html(hwModel)}</div>
|
||||||
<table><tbody>
|
<table><tbody>
|
||||||
${fwVersion ? `<tr><th>Firmware</th><td>${html(fwVersion)}</td></tr>` : ''}
|
${fwVersion ? `<tr><th>Firmware</th><td>${html(fwVersion)}</td></tr>` : ''}
|
||||||
${region ? `<tr><th>Region</th><td>${html(region)}</td></tr>` : ''}
|
${region ? `<tr><th>Region</th><td>${html(region)}</td></tr>` : ''}
|
||||||
${modemPreset ? `<tr><th>Modem preset</th><td>${html(modemPreset)}</td></tr>` : ''}
|
${modemPreset ? `<tr><th>Modem preset</th><td>${html(modemPreset)}</td></tr>` : ''}
|
||||||
${hasDefaultCh ? `<tr><th>Has default channel</th><td>True</td></tr>` : ''}
|
${hasDefaultCh ? `<tr><th>Has default channel</th><td>True</td></tr>` : ''}
|
||||||
${onlineLocalNodes ? `<tr><th>Online local nodes</th><td>${onlineLocalNodes}</td></tr>` : ''}
|
${onlineLocalNodes ? `<tr><th>Online local nodes</th><td>${onlineLocalNodes}</td></tr>` : ''}
|
||||||
${batteryLevel ? `<tr><th>Power</th><td>${batteryLevel > 100 ? 'Plugged in' : `${batteryLevel}%`}${voltage ? ` (${voltage.toFixed(2)}V)` : ''}</td></tr>` : ''}
|
${batteryLevel ? `<tr><th>Power</th><td>${batteryLevel > 100 ? 'Plugged in' : `${batteryLevel}%`}` +
|
||||||
${chUtil ? `<tr><th>ChUtil</th><td>${chUtil.toFixed(2)}%</td></tr>` : ''}
|
`${voltage ? ` (${voltage.toFixed(2)}V)` : ''}</td></tr>` : ''}
|
||||||
${airUtilTx ? `<tr><th>AirUtilTX</th><td>${airUtilTx.toFixed(2)}%</td></tr>` : ''}
|
${chUtil ? `<tr><th>ChUtil</th><td>${chUtil.toFixed(2)}%</td></tr>` : ''}
|
||||||
${uptime ? `<tr><th>Uptime</th><td>${duration(uptime)}</td></tr>` : ''}
|
${airUtilTx ? `<tr><th>AirUtilTX</th><td>${airUtilTx.toFixed(2)}%</td></tr>` : ''}
|
||||||
${temperature ? `<tr><th>Temperature</th><td>${temperature.toFixed(1)}℃ / ${(temperature * 1.8 + 32).toFixed(1)}℉</td></tr>` : ''}
|
${uptime ? `<tr><th>Uptime</th><td>${duration(uptime)}</td></tr>` : ''}
|
||||||
${relativeHumidity ? `<tr><th>Relative Humidity</th><td>${Math.round(relativeHumidity)}%</td></tr>` : ''}
|
${temperature ? `<tr><th>Temperature</th><td>${temperature.toFixed(1)}℃ / ` +
|
||||||
|
`${(temperature * 1.8 + 32).toFixed(1)}℉</td></tr>` : ''}
|
||||||
|
${relativeHumidity ? `<tr><th>Relative Humidity</th><td>${Math.round(relativeHumidity)}%</td></tr>` : ''}
|
||||||
${barometricPressure ? `<tr><th>Barometric Pressure</th><td>${Math.round(barometricPressure)} hPa</td></tr>` : ''}
|
${barometricPressure ? `<tr><th>Barometric Pressure</th><td>${Math.round(barometricPressure)} hPa</td></tr>` : ''}
|
||||||
${altitude ? `<tr><th>Altitude</th><td>${altitude.toLocaleString()} m above MSL</td></tr>` : ''}
|
${altitude ? `<tr><th>Altitude</th><td>${altitude.toLocaleString()} m above MSL</td></tr>` : ''}
|
||||||
${precision && precisionMargins[precision-1] ?
|
${precision && precisionMargins[precision-1] ? "<tr><th>Location precision</th><td>±" +
|
||||||
`<tr><th>Location precision</th><td>± ${precisionMargins[precision-1].toLocaleString()} m (orange circle)</td></tr>` : ''
|
`${precisionMargins[precision-1].toLocaleString()} m (orange circle)</td></tr>` : ''}
|
||||||
}
|
|
||||||
</tbody></table>
|
</tbody></table>
|
||||||
<table><thead>
|
<table><thead>
|
||||||
<tr><th>Last seen</th><th>via</th><th>root topic</th><th>channel</th></tr>
|
<tr><th>Last seen</th><th>via</th><th>root topic</th><th>channel</th></tr>
|
||||||
|
@ -255,7 +260,9 @@
|
||||||
${Array.from(
|
${Array.from(
|
||||||
new Map(
|
new Map(
|
||||||
Object.entries(seenBy)
|
Object.entries(seenBy)
|
||||||
.map(([topic, seen]) => (m => ({seen, via: m[3] ?? id, root: m[1], chan: m[2]}))(topic.match(/^(.*)(?:\/2\/e\/(.*)\/(![0-9a-f]+)|\/2\/map\/)$/)))
|
.map(([topic, seen]) => (m => ({seen, via: m[3] ?? id, root: m[1], chan: m[2]}))(
|
||||||
|
topic.match(/^(.*)(?:\/2\/e\/(.*)\/(![0-9a-f]+)|\/2\/map\/)$/s)
|
||||||
|
))
|
||||||
.sort((a, b) => a.seen - b.seen)
|
.sort((a, b) => a.seen - b.seen)
|
||||||
.map(v => [v.via, v])
|
.map(v => [v.via, v])
|
||||||
).values(),
|
).values(),
|
||||||
|
|
Loading…
Reference in a new issue