fediblock-instance/public/main.js

418 lines
22 KiB
JavaScript
Raw Normal View History

2024-09-15 17:44:53 +00:00
document.addEventListener('DOMContentLoaded', function () {
loading()
var hold = false,
external = false,
timeout = undefined,
ac = undefined,
last = undefined
document.getElementById('instance').addEventListener('keydown', function (event) {
if (event.key && ((event.key.length === 1 && /[a-z0-9.\-*:]/i.test(event.key)) || (event.key === 'Backspace' && event.target.value !== ''))) {
last = event.target.value
} else if (event.key === 'Backspace' && event.target.value === '') {
last = ''
} else {
event.preventDefault()
event.stopPropagation()
}
})
document.getElementById('instance').addEventListener('keyup', function (event) {
if (event.key && ((event.key.length === 1 && /[a-z0-9.\-*:]/i.test(event.key)) || (event.key === 'Backspace' && last !== ''))) {
keypress(event, event.target.value)
} else {
event.preventDefault()
event.stopPropagation()
}
})
var modal = document.getElementById('modal'),
closemodal = document.getElementById('closemodal'),
modalcontent = document.querySelector('.modal-content')
document.getElementById('reverse').addEventListener('click', function (event) {
var content = document.getElementById('instance').value
if (content && content.length > 0) {
loading()
fetch('/api/block_count/' + content).then(async function (result) {
var res = await result.json()
if (res && res.block_count >= 0) {
document.getElementById('blockcount').innerText = res.block_count
document.getElementById('blockinstance').innerText = 'ing ' + content
document.getElementById('blocktook').innerText = res.took
var list = document.getElementById('blocklist'),
download = document.getElementById('download')
download.removeAttribute('href')
download.removeAttribute('download')
download.style.display = 'none'
while (list.hasChildNodes()) {
list.removeChild(list.firstChild)
}
res.instances.map((instance, index) => {
var li = document.createElement('li'),
text = document.createTextNode((index + 1) + '. '),
link = '<a href="/' + (new URLSearchParams(window.location.search).has('matrix') ? '?matrix' : '') + '#' + instance.instance + '" onclick="window.location.href=this.href; window.location.reload(false);">' + instance.instance + '</a>',
text2 = document.createTextNode(instance.comment ? ' - ' + instance.comment : '')
li.appendChild(text)
li.insertAdjacentHTML('beforeend', link)
li.appendChild(text2)
blocklist.appendChild(li)
})
listinstance(content, new AbortController())
modalcontent.style.animationName = 'animatetop'
modal.style.display = 'block'
var locationsearch = !new URLSearchParams(window.location.search).has('reverse') ? window.location.search ? window.location.search + '&reverse' : '?reverse' : window.location.search
history.pushState({}, null, '/' + locationsearch + '#' + content)
if (new URLSearchParams(window.location.search).has('matrix')) {
var walker = document.createTreeWalker(list, NodeFilter.SHOW_TEXT)
while (walker.nextNode()) {
if (walker.currentNode.textContent.length > 1) {
new Messenger(walker.currentNode)
}
}
}
document.getElementById('loader-content').style.display = 'none'
}
})
}
})
document.body.addEventListener('click', function (event) {
if (event.target == modal) {
modalcontent.style.animationName = 'animatebottom'
}
})
closemodal.addEventListener('click', function (event) {
modalcontent.style.animationName = 'animatebottom'
})
modalcontent.addEventListener('animationend', function (event) {
if (event.animationName === 'animatebottom') {
modal.style.display = 'none'
}
})
document.getElementById('title').addEventListener('click', function (event) {
document.getElementById('instance').value = ''
if (new URLSearchParams(window.location.search).has('matrix')) {
window.location.href = '/?matrix'
} else {
window.location.href = '/'
}
event.preventDefault()
event.stopPropagation()
})
document.getElementById('capture').addEventListener('click', function (event) {
html2canvas(document.querySelector('.modal-body')).then(function (canvas) {
var a = document.createElement('a')
a.download = 'fediblock-' + Date.now() + '.png'
a.href = canvas.toDataURL({ type: 'image/png' })
a.type = 'image/png'
a.target = '_blank'
a.dispatchEvent(new MouseEvent('click'))
})
})
function keypress(event, content) {
loading()
if (timeout) {
clearTimeout(timeout)
}
if (ac && ac.signal) {
ac.abort()
}
ac = new AbortController()
if (content.length === 0) {
hold = true
ranking()
} else if (content.length > 0 && !hold) {
hold = true
listinstance(content, ac)
} else if (content.length > 0 && hold) {
timeout = setTimeout(() => {
listinstance(content, ac)
}, 300)
}
}
function listinstance(content, ac) {
loading()
var list = document.getElementById('instancelist')
fetch('/api/list/' + content, { signal: ac.signal }).then(async function (result) {
var res = await result.json()
if (res && Array.isArray(res.instances) && Array.isArray(res.suggests)) {
while (list.hasChildNodes()) {
list.removeChild(list.firstChild)
}
res.instances.map(r => {
var li = document.createElement('li')
li.innerHTML = r.domain + (r.blocks ? ' - ' + r.blocks + ' blocks' : '')
+ (r.nodeinfo ? ' <a href="/api/detail_nodeinfo/' + r.domain + '" title="Nodeinfo for ' + r.domain + '" target="_blank">&#9432;</a>' : '')
+ (r.api.title ? '<br /> <br />' + r.api.title + ' - ' + r.api.uri + '<br />'
+ (r.last ? 'Last update: ' + (new Date(r.last)).toLocaleString() + '<br />' : '')
+ (r.api.email ? 'Email: ' + r.api.email + '<br />' : '')
+ 'Registration: ' + (r.api.registrations ? 'open' : 'closed') + ' - Version: ' + r.api.version + '<br />'
+ (r.api.stats ? 'Users: ' + r.api.stats.user_count + ' - Statuses: ' + r.api.stats.status_count + ' - Domains: ' + r.api.stats.domain_count + '<br />' : '')
+ (r.api.description ? 'Description: ' + r.api.description + '<br />' : '')
+ (r.api.thumbnail ? '<img domain="' + r.domain + '" loading="lazy" src="' + r.api.thumbnail + '" /><br />' : '') : '')
li.setAttribute('data-domain', r.domain)
li.addEventListener('click', function (event) {
if (event.target.matches('a')) {
return true
}
loading()
var blocklist = document.getElementById('blocklist'),
download = document.getElementById('download'),
domain = event.target.getAttribute('data-domain')
while (blocklist.hasChildNodes()) {
blocklist.removeChild(blocklist.firstChild)
}
fetch('/api/detail/' + domain).then(async function (result) {
var res = await result.json()
if (res.blocks && Array.isArray(res.blocks) && res.blocks.length > 0) {
var csv = '#domain,#severity,#reject_media,#reject_reports,#public_comment,#obfuscate\n'
res.blocks.map((r, i) => {
var liblock = document.createElement('li'),
text = document.createTextNode((i + 1) + '. '),
link = '<a href="/' + (new URLSearchParams(window.location.search).has('matrix') ? '?matrix' : '') + '#' + r.domain + '" onclick="window.location.href=this.href; window.location.reload(false);">' + r.domain + '</a>',
textSeverity = document.createTextNode(r.severity ? ' - ' + r.severity : ''),
textComment = document.createTextNode(r.comment ? ' - ' + r.comment : '')
liblock.appendChild(text)
liblock.insertAdjacentHTML('beforeend', link)
liblock.appendChild(textSeverity)
liblock.appendChild(textComment)
blocklist.appendChild(liblock)
csv += !r.domain.match(/\*/) ? r.domain + ',' + (r.severity ? r.severity : '') + ',False,False,' + (r.comment ? '"' + r.comment + '"' : '') + ',False\n' : ''
})
modalcontent.style.animationName = 'animatetop'
modal.style.display = 'block'
document.getElementById('blockcount').innerText = res.blocks.length
document.getElementById('blockinstance').innerHTML = 'ed by ' + (res.api ? '<a href="/api/detail_api/' + res.instance + '" title="API info for ' + res.instance + '" target="_blank">'
+ res.instance + '</a>' : res.instance) + (res.nodeinfo ? '&nbsp;<a href="/api/detail_nodeinfo/' + res.instance + '" title="Nodeinfo for ' + res.instance + '" target="_blank">&#9432;</a>' : '')
+ '<br/>Last update: ' + (new Date(res.last)).toLocaleString()
document.getElementById('blocktook').innerText = res.took
if (csv.split('\n').length > 2) {
download.href = window.URL.createObjectURL(new Blob([csv], { type: 'text/csv' }))
download.download = 'fediblock-' + res.instance + '.csv'
download.style.display = 'inherit'
} else {
download.removeAttribute('href')
download.removeAttribute('download')
download.style.display = 'none'
}
if (new URLSearchParams(window.location.search).has('matrix')) {
var walker = document.createTreeWalker(blocklist, NodeFilter.SHOW_TEXT)
while (walker.nextNode()) {
if (walker.currentNode.textContent.length > 1) {
new Messenger(walker.currentNode)
}
}
}
} else {
var a = document.createElement('a')
a.href = '/api/detail_api/' + domain
a.title = 'API info for ' + domain
a.target = '_blank'
a.dispatchEvent(new MouseEvent('click'))
}
document.getElementById('loader-content').style.display = 'none'
})
window.location.hash = domain
document.getElementById('loader-content').style.display = 'none'
})
list.appendChild(li)
})
var placeholder = document.getElementById('placeholder')
if (res.suggests.length > 0) {
placeholder.innerHTML = res.suggests.map(instance => '<a href="/' + (new URLSearchParams(window.location.search).has('matrix') ? '?matrix' : '') + '#' + instance + '" onclick="suggest(this.innerText);">' + instance + '</a>').join(', ')
} else {
placeholder.innerText = ''
}
if (external) {
document.getElementById('instancelist').childNodes.forEach(function (node) {
if (node.textContent.split(' ')[0].trim() === content) {
node.dispatchEvent(new MouseEvent('click'))
}
})
external = false
}
if (new URLSearchParams(window.location.search).has('matrix')) {
var walker = document.createTreeWalker(list, NodeFilter.SHOW_TEXT)
while (walker.nextNode()) {
if (walker.currentNode.textContent.length > 1) {
new Messenger(walker.currentNode)
}
}
}
}
document.getElementById('loader-content').style.display = 'none'
hold = false
}).catch(err => {
// console.error(err)
document.getElementById('loader-content').style.display = 'none'
hold = false
})
}
function ranking() {
loading()
var list = document.getElementById('instancelist'),
placeholder = document.getElementById('placeholder')
fetch('/api/ranking').then(async function (result) {
var res = await result.json()
if (Array.isArray(res) && res.length > 0) {
while (list.hasChildNodes()) {
list.removeChild(list.firstChild)
}
var li = document.createElement('li'),
strong = document.createElement('strong'),
text = document.createTextNode('Top 100')
strong.appendChild(text)
li.appendChild(strong)
list.appendChild(li)
res.map((r, i) => {
var li = document.createElement('li'),
text = document.createTextNode(`${i + 1} - ${r.domain} - ${r.count} blocks`)
li.addEventListener('click', function (event) {
var instance = document.getElementById('instance'),
text = event.target.innerText.split(' - ')[1].trim()
instance.value = text
document.getElementById('reverse').click()
})
li.appendChild(text)
list.appendChild(li)
})
}
if (new URLSearchParams(window.location.search).has('matrix')) {
var walker = document.createTreeWalker(list, NodeFilter.SHOW_TEXT)
while (walker.nextNode()) {
if (walker.currentNode.textContent.length > 1) {
new Messenger(walker.currentNode)
}
}
}
placeholder.innerText = ''
hold = false
document.getElementById('loader-content').style.display = 'none'
}).catch(err => {
console.error(err)
hold = false
document.getElementById('loader-content').style.display = 'none'
})
}
function suggest(urlitem) {
var instance = document.getElementById('instance')
window.location.hash = urlitem
instance.value = urlitem
listinstance(urlitem, new AbortController())
}
function loading() {
var loader = document.getElementById('load'),
loaders = ['loader-pong', 'loader-pacman', 'loader-abyss', 'loader-jump', 'loader-loading', 'loader-avenger', 'loader-mario']
if (loader.classList.value) {
loader.classList.remove(loader.classList.value)
}
loader.classList.add(loaders[Math.floor(Math.random() * loaders.length)])
document.getElementById('loader-content').style.display = 'initial'
}
window.suggest = suggest
fetch('/api/count').then(async function (result) {
var res = await result.json()
if (res && res.count) {
fetch('/api/stats').then(async function (statsresult) {
var statsres = await statsresult.json()
if (statsres) {
document.getElementById('count').innerHTML = res.count + '<div id="tooltip">' +
'<u><strong><center>STATS</center></strong></u>' +
'<ul><li>Statuses AVG: ' + Math.round(statsres.status_avg) + '</li>' +
'<li>Statuses MAX: ' + statsres.status_max + '</li>' +
'<li>Domain AVG: ' + Math.round(statsres.domain_avg) + '</li>' +
'<li>Domain MAX: ' + statsres.domain_max + '</li>' +
'<li>Users AVG: ' + Math.round(statsres.user_avg) + '</li>' +
'<li>Users MAX: ' + statsres.user_max + '</li>' +
'<li>Stats Instances: ' + statsres.stats_filtered + '</li>' +
'<li>Total Instances: ' + statsres.instance_count + '</li>' +
'<li>Users by Instance: ' + (Math.round(statsres.user_avg) / statsres.instance_count).toFixed(2) + '</li>' +
'<li>Statuses by Domain: ' + (Math.round(statsres.status_avg) / Math.round(statsres.domain_avg)).toFixed(2) + '</li>' +
'<li>Statuses by User: ' + (Math.round(statsres.status_avg) / Math.round(statsres.user_avg)).toFixed(2) + '</li>' +
'</ul></div>'
} else {
document.getElementById('count').innerText = res.count
}
})
fetch('/api/outbox').then(async function (result) {
var res = await result.json()
if (res && res.length > 0) {
var bounce = document.getElementById('bounce'),
host = new URL(window.location.href).host
reg = '(<\/?p>|(https?:\/\/)?' + host + ')'
bounce.innerHTML = res.map(p => `${p.content.replace(new RegExp(reg, 'igm'), '')} ${dayjs().to(p.published)}`).join(' | ')
}
})
fetch('/api/served').then(async function (result) {
var res = await result.json()
if (res.served) {
var served = document.getElementById('served')
served.innerText = res.served
}
if (res.lastscan) {
var lastscan = document.getElementById('lastscan')
lastscan.innerText = res.lastscan
}
if (res.server) {
var server = document.getElementById('server')
server.innerHTML = '<a href="/' + (new URLSearchParams(window.location.search).has('matrix') ? '?matrix' : '') + '#' + res.server + '" onclick="window.location.href=this.href; window.location.reload(false);">' + res.server + '</a>'
}
if (res.instances) {
var instances = document.getElementById('instances')
instances.innerText = res.instances
}
if (res.peers) {
var peers = document.getElementById('peers')
peers.innerText = res.peers
}
if (res.created) {
var created = document.getElementById('created')
created.innerText = res.created
}
if (res.updated) {
var updated = document.getElementById('updated')
updated.innerText = res.updated
}
})
}
})
if (window.location.hash && window.location.hash !== null && window.location.hash !== '#') {
var instance = document.getElementById('instance'),
urlitem = window.location.hash.substring(1)
instance.value = urlitem
if (new URLSearchParams(window.location.search).has('reverse')) {
document.getElementById('reverse').click()
} else {
external = true
listinstance(urlitem, new AbortController())
}
} else {
ranking()
document.getElementById('instance').focus()
}
var source = new window.EventSource('/api/scan'),
scan = document.getElementById('scan')
source.onmessage = function (event) {
if (event.data) {
if (event.data.length > 0) {
scan.innerText = 'Async Scanning' + event.data
} else {
scan.innerText = 'Async Scanning...'
}
}
}
source.onerror = function (error) {
console.error(error)
}
if (new URLSearchParams(window.location.search).has('matrix')) {
var walker = document.createTreeWalker(document, NodeFilter.SHOW_TEXT)
while (walker.nextNode()) {
if (walker.currentNode.textContent.length > 1) {
new Messenger(walker.currentNode)
}
}
var matrix = document.getElementById('matrix')
matrix.href = '/'
matrix.innerText = 'matrix on'
} else {
var matrix = document.getElementById('matrix')
matrix.href = '/?matrix'
matrix.innerText = 'matrix off'
}
})