2021-02-15 12:09:55 +01:00
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
2024-01-06 02:36:45 +01:00
|
|
|
|
function humanFileSize(size) {
|
|
|
|
|
if (size === 0) {
|
|
|
|
|
return "0 B";
|
|
|
|
|
}
|
|
|
|
|
if (size < 0) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
const base = Math.floor(Math.log2(size) / 10)
|
|
|
|
|
const unit = ["B", "KiB", "MiB", "GiB", "TiB"][base]
|
|
|
|
|
const relative = size / 2**(10*base)
|
|
|
|
|
return relative.toFixed(3) + " " + unit
|
2021-02-15 12:09:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function textToA(line) {
|
|
|
|
|
let outerElement = document.createElement('div')
|
|
|
|
|
outerElement.innerHTML = line
|
|
|
|
|
return outerElement.getElementsByTagName('a')[0]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function parseLine(line) {
|
|
|
|
|
const href = textToA(line).href
|
|
|
|
|
const filename = href.substr(-1) === '/' ? decodeURIComponent(href.split('/').slice(-2, -1)[0]) : decodeURIComponent(href.split('/').pop())
|
|
|
|
|
const size = line.split(' ').pop()
|
|
|
|
|
return {
|
|
|
|
|
href: href,
|
|
|
|
|
filename: filename,
|
|
|
|
|
size: size
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function processLine(line) {
|
|
|
|
|
meta = parseLine(line)
|
|
|
|
|
return `<tr><td><a href="${meta.href}">${meta.filename}</a></td><td>${meta.size === '-' ? '-' : humanFileSize(meta.size)}</td></tr>`
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-29 14:14:07 +02:00
|
|
|
|
function addZebraStripes(rows) {
|
|
|
|
|
// this should be done in CSS, but AFAIU it does not support limiting
|
|
|
|
|
// :nth-child to elements matching a previous :not selector
|
|
|
|
|
rows.forEach((row, idx) => {
|
|
|
|
|
if (idx % 2 === 0) {
|
|
|
|
|
row.classList.add("zebra-stripe")
|
|
|
|
|
} else {
|
|
|
|
|
row.classList.remove("zebra-stripe")
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-15 12:09:55 +01:00
|
|
|
|
const collator = new Intl.Collator('kn', {numeric: true})
|
|
|
|
|
|
|
|
|
|
// transform plain text to table
|
2021-08-29 14:13:35 +02:00
|
|
|
|
document.querySelector('pre').outerHTML = '<table><thead><tr><th>Name</th><th>Size</th></tr></thead><tbody><tr><td><a href="..">..</a></td><td>-</td></tr>' + document.querySelector('pre').innerHTML
|
2021-02-15 12:09:55 +01:00
|
|
|
|
.split('\n')
|
|
|
|
|
.filter(line => line !== '')
|
|
|
|
|
.filter(line => line !== '<a href="../">../</a>')
|
|
|
|
|
.map(processLine)
|
|
|
|
|
.sort(collator.compare)
|
2021-08-29 14:13:35 +02:00
|
|
|
|
.join('\n') + '</tbody></table>'
|
2021-02-15 12:09:55 +01:00
|
|
|
|
|
|
|
|
|
let searchField = document.createElement('input')
|
|
|
|
|
searchField.id = 'search-field'
|
|
|
|
|
searchField.autofocus = true
|
|
|
|
|
document.querySelector('body').insertBefore(searchField, document.querySelector('table'))
|
|
|
|
|
|
2021-08-30 22:09:00 +02:00
|
|
|
|
const rows = Array.from(document.querySelectorAll('tbody tr'))
|
2021-02-15 12:09:55 +01:00
|
|
|
|
|
2021-08-29 14:14:07 +02:00
|
|
|
|
addZebraStripes(rows)
|
|
|
|
|
|
2021-02-15 12:09:55 +01:00
|
|
|
|
document.querySelector('#search-field').addEventListener("input", e => {
|
|
|
|
|
const searchValue = e.target.value.toLowerCase()
|
|
|
|
|
rows.forEach(row => {
|
|
|
|
|
const file = row.querySelector('td:nth-child(1) a').innerText
|
|
|
|
|
if (!file.toLowerCase().includes(searchValue)) {
|
2021-08-29 14:14:07 +02:00
|
|
|
|
row.classList.add("hidden")
|
2021-02-15 12:09:55 +01:00
|
|
|
|
} else {
|
2021-08-29 14:14:07 +02:00
|
|
|
|
row.classList.remove("hidden")
|
2021-02-15 12:09:55 +01:00
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
2021-08-29 14:14:07 +02:00
|
|
|
|
const visibleRows = rows.filter(row => !row.classList.contains("hidden"))
|
2021-02-15 12:09:55 +01:00
|
|
|
|
if (visibleRows.length === 1) {
|
|
|
|
|
const target = visibleRows[0].querySelector('td a').href
|
|
|
|
|
if (target.substr(-1) === '/') {
|
|
|
|
|
window.location = target
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-29 14:14:07 +02:00
|
|
|
|
addZebraStripes(visibleRows)
|
2021-02-15 12:09:55 +01:00
|
|
|
|
})
|
|
|
|
|
})
|