import { render, html } from '/uhtml.js'; import loadMessages from '/message.js'; import loadSpace from '/space.js'; import loadStreams from '/stream.js'; function setVisibility() { document.getElementById('visibility').innerText = `${ window.currentThread.permissions.everyone.view.value ? 'this thread is visible to everyone' : 'members can view this thread'} ${window.currentThread.permissions.everyone.post.value ? 'anyone can post' : window.currentThread.permissions.members.post.value ? 'only members can post' : 'some members can post'}`; } function chooseThread() { const edit = document.getElementById('edit'); let thread = this.thread; if (window.currentThread) { window.currentThread.div.classList.remove('active'); let editform = document.getElementById('editthread'); if (editform) { editform.remove(); edit.textContent = 'edit'; } if (window.currentThread.id === thread.id) { document.getElementById('thread').classList.add('hidden'); window.currentThread = null; return; } } else document.getElementById('thread').classList.remove('hidden'); if (thread.permissions.admin) edit.classList.remove('hidden'); else edit.classList.add('hidden'); document.getElementById('threadname').textContent = thread.name; this.classList.add('active'); window.currentThread = thread; window.currentInstance = thread.instance; if (this.tab) { switchTab(document.getElementById(this.tab)); if (this.tab === 'messagetab') loadMessages(); else if (this.tab === 'spacetab') loadSpace(); } else // load first tab that has any content loadMessages(messages => { if (messages.length) switchTab(document.getElementById(this.tab = 'messagetab')); else loadSpace(spans => { if (spans.length) switchTab(document.getElementById(this.tab = 'spacetab')); else if (window.currentThread.streams.length) switchTab(document.getElementById(this.tab = 'streamtab')); else switchTab(document.getElementById( this.tab = spans.length ? 'spacetab' : window.currentThread.streams.length ? 'streamtab' : 'messagetab')); }); }); window.currentInstance.emit('get_thread', { thread: thread.id }, async msg => { if (!msg.success) { console.log('get_thread failed:', msg.message); return; } Object.assign(thread, msg.thread); loadStreams(); setVisibility(); document.getElementById('memberlist').replaceChildren( ...await Promise.all(msg.thread.members.map(async member => html.node`

${ member.name || (await window.getUser(member.id)).name }

`)) ); }); } function switchTab(tab) { document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active')); document.querySelectorAll('.tabcontent').forEach(tab => tab.classList.add('hidden')); tab.classList.add('active'); document.getElementById(tab.id.slice(0, -3)).classList.remove('hidden'); } function newThread() { let form = document.getElementById('createthread'); if (form) { form.remove(); for (let create of document.querySelectorAll('#newthread')) { create.textContent = 'create'; create.classList.remove('hidden'); } return; } const instancediv = this.parentElement.parentElement; let members = [{ id: String(window.id), name: window.name, permissions: { admin: 'true' } }]; if (instancediv.instance !== window.instancelist[0]) { members[0].id += '@' + location.host; members[0].name += '@' + location.host; } async function addMember() { const name = document.getElementById('membername'); if (!name.value) return; let at = name.value.split('@'); let url = at[1] || instancediv.instance.url; let user = await window.getUser('@' + url, at[0]); if (instancediv.instance.url !== url) { user.id += '@' + url; user.name += '@' + url; } if (members.find(member => member.name === user.value)) return; members.push(user); document.getElementById('newmembers') .append(html.node`

${user.name}

`); name.value = ''; } document.querySelector('#home + .separator').insertAdjacentElement('afterend', html.node`
{ event.preventDefault(); let name = document.getElementById('newthreadname').value; if (!name) { document.getElementById('newnameempty').classList.remove('hidden'); return; } const perms = document.querySelector( 'input[name="newpermissions"]:checked' ).value; let permissions; if (perms === 'public') permissions = { view_limited: false, post_limited: false }; else if (perms === 'private_post') permissions = { view_limited: false, post_limited: true }; else if (perms === 'private_view') { permissions = { view_limited: true, post_limited: true }; // todo: generate key and encrypt } instancediv.instance.emit('create_thread', { name, permissions, members }, msg => { if (!msg.success) { console.log('create_thread error:', msg.message); return; } // since the form exists, this will perform cleanup newThread(); chooseThread.call(instancediv.children['threads'].children['threadlist'] .children['thread' + msg.id]); document.getElementById('loadmore').classList.add('hidden'); } ); }}>

create thread

thread permissions




{ if (event.key === 'Enter') { event.preventDefault(); addMember(); } }} />

${members[0].name}


`); for (let create of document.querySelectorAll('#newthread')) { if (create === this) create.textContent = 'cancel'; else create.classList.add('hidden'); } } function editThread() { let form = document.getElementById('editthread'); if (form) { form.remove(); document.getElementById('edit').textContent = 'edit'; return; } form = html.node`
{ event.preventDefault(); let name = document.getElementById('editthreadname').value; if (!name) { document.getElementById('nameempty').classList.remove('hidden'); return; } const perms = document.querySelector( 'input[name="permissions"]:checked' ).value; let permissions; if (perms === 'public') permissions = { view_limited: false, post_limited: false }; else if (perms === 'private_post') permissions = { view_limited: false, post_limited: true }; else if (perms === 'private_view') { permissions = { view_limited: true, post_limited: true }; // todo: generate key and encrypt } window.currentInstance.emit('edit_thread', { id: window.currentThread.id, name, permissions }, msg => { if (!msg.success) { console.log('edit_thread failed: ', msg.message); return; } editThread(); }); }}>

thread permissions





`; form['editthreadname'].value = window.currentThread.name; if (window.currentThread.permissions.everyone.post.value) form['public'].checked = true; else if (window.currentThread.permissions.everyone.view.value) form['private_post'].checked = true; else form['private_view'].checked = true; document.querySelector('#thread').append(form); document.getElementById('edit').textContent = 'cancel'; } function clickedTab(event) { switchTab(this); document.getElementById(`thread${window.currentThread.id}`).tab = this.id; if (this.id === 'messagetab') loadMessages(); else if (this.id === 'spacetab') loadSpace(); } async function loadThreads(instancediv, select) { function makeThread(thread) { thread.instance = instancediv.instance; let node = html.node`
${ thread.name }
`; node.id = 'thread' + thread.id; node.thread = thread; thread.div = node; return node; } if (!document.getElementById('thread')) document.body.append(html.node` `); if (!instancediv.children['threads']) { instancediv.append(html.node`

threads

loading...
`); const threadlist = instancediv.children['threads'].children['threadlist']; instancediv.instance.emit('list_threads', {}, msg => { threadlist.replaceChildren(...msg.threads.map(makeThread)); if (select && msg.threads.length) chooseThread.call(threadlist.firstChild); }); instancediv.instance.socket.on('thread', thread => { let el = threadlist.children['thread' + thread.id]; if (el) { Object.assign(el.thread, thread); el.textContent = thread.name; if (window.currentThread?.id === thread.id) { Object.assign(window.currentThread, thread); document.getElementById('threadname').textContent = thread.name; setVisibility(); } return; } threadlist.prepend(makeThread(thread)); }); } } export default loadThreads;