various fixes

main
jerl 2024-06-19 22:57:57 -07:00
parent c87c193118
commit 3b288c9719
6 changed files with 93 additions and 70 deletions

View File

@ -69,8 +69,11 @@ window.getUser = async (id, name) => {
); );
}; };
window.makeUser = (user, url, removable) => { window.makeUser = (user, url, context) => {
removable &&= window.currentThread.permissions.admin && !user.permissions?.admin; let removable = context === 'user' ? false :
window.currentThread?.permissions.admin && !user.permissions?.admin &&
(context === 'member' ? true : Array.from(document.getElementById('memberlist').children)
.find(p => p.children[0].user?.id == user.id));
let span = html.node` let span = html.node`
<span class='user' onclick=${function(e) { <span class='user' onclick=${function(e) {
let member = document.getElementById('member'); let member = document.getElementById('member');
@ -134,7 +137,7 @@ function instanceClicked(event) {
instance.emit?.('list_users', {}, msg => instance.emit?.('list_users', {}, msg =>
userlist.replaceChildren(...msg.users.map(user => { userlist.replaceChildren(...msg.users.map(user => {
let p = document.createElement('p'); let p = document.createElement('p');
p.append(window.makeUser(user, instance.url)); p.append(window.makeUser(user, instance.url, 'user'));
return p; return p;
})) }))
); );
@ -192,32 +195,34 @@ document.body.append(html.node`
<input id='profilepublic' type='checkbox' oninput=${saveProfile}> <input id='profilepublic' type='checkbox' oninput=${saveProfile}>
<label for='profilepublic'>show profile in instance users</label> <label for='profilepublic'>show profile in instance users</label>
</p> </p>
<label class='heading'>authentication requests</label> <label class='heading'>authentication requests:</label>
<div id='authrequests'></div> <div id='authrequests'></div>
</div> </div>
<hr class='separator' color='#505050'> <hr class='separator' color='#505050'>
<div id='home' class='column'> <div id='home' class='column'>
<h3>vybe</h3>
<p id='instances'>instances:<button onclick=${e => {
let div = html.node`
<div>
<div class='instancetitle'>
<span></span>
<span onblur=${addInstance} onkeydown=${function(event) {
if (event.key === 'Enter') {
event.preventDefault();
addInstance.call(this);
}
}} class='title' contenteditable='true'>
</span>
</div>
</div>`;
document.getElementById('instancelist').append(div);
div.children[0].children[1].focus();
}}>add</button></p>
<div id='instancelist'> <div id='instancelist'>
<h3>vybe</h3>
<p id='instances'>instances:<button onclick=${() => {
let div = html.node`
<div>
<div class='instancetitle'>
<span></span>
<span onblur=${addInstance} onkeydown=${function(event) {
if (event.key === 'Enter') {
event.preventDefault();
addInstance.call(this);
}
}} class='title' contenteditable='true'>
</span>
</div>
</div>`;
document.getElementById('instancelist').append(div);
div.children[0].children[1].focus();
}}>add</button></p>
</div> </div>
<div id='user' onclick=${() => <div class='content'><!-- empty flex div to push instancelist up -->
</div>
<div id='user' onclick=${e =>
document.getElementById('profile').classList.toggle('hidden') document.getElementById('profile').classList.toggle('hidden')
}>${window.name}</div> }>${window.name}</div>
</div> </div>

View File

@ -174,7 +174,8 @@
.user { .user {
white-space: pre-wrap; white-space: pre-wrap;
&:hover { &:hover {
background-color: #444; background-color: #333;
border-bottom: 1px #bbb solid;
} }
} }
#profile { #profile {

View File

@ -72,8 +72,7 @@ function loadMessages(callback) {
} }
} }
let div = html.node`<div class='message'>: ${message.content}</div>`; let div = html.node`<div class='message'>: ${message.content}</div>`;
div.prepend(user ? window.makeUser(user, div.prepend(user ? window.makeUser(user, user.id.split?.('@')[1] || instance.url)
user.id.split?.('@')[1] || instance.url, true)
: html.node`<span>${message.user.id}</span>`); : html.node`<span>${message.user.id}</span>`);
messages.prepend(div); messages.prepend(div);
} }
@ -93,7 +92,7 @@ function loadMessages(callback) {
let scroll = messages.scrollTop + 10 >= messages.scrollHeight - messages.clientHeight; let scroll = messages.scrollTop + 10 >= messages.scrollHeight - messages.clientHeight;
let div = html.node`<div class='message'>: ${message.content}</div>`; let div = html.node`<div class='message'>: ${message.content}</div>`;
div.prepend(window.makeUser(message.user, div.prepend(window.makeUser(message.user,
message.user.id.split?.('@')[1] || instance.url, true)); message.user.id.split?.('@')[1] || instance.url));
messages.append(div); messages.append(div);
if (scroll) if (scroll)
messages.scroll(0, messages.scrollHeight - messages.clientHeight); messages.scroll(0, messages.scrollHeight - messages.clientHeight);

View File

@ -78,7 +78,7 @@ function loadStreams() {
let div = document.getElementById('stream'); let div = document.getElementById('stream');
div.innerHTML = ''; div.innerHTML = '';
if (window.currentThread.permissions.post) { if (window.currentThread?.permissions.post) {
// why doesn't html` work here? html.node` does // why doesn't html` work here? html.node` does
render(div, html.node` render(div, html.node`
<button id='streaming' onclick=${stream}> <button id='streaming' onclick=${stream}>
@ -92,7 +92,10 @@ function loadStreams() {
thread: window.currentThread.id, thread: window.currentThread.id,
name: this.value name: this.value
}); });
window.currentThread.streamname = this.value;
}}>`); }}>`);
if (window.currentThread.streamname)
document.getElementById('streamname').value = window.currentThread.streamname;
} }
div.insertAdjacentHTML('beforeend', ` div.insertAdjacentHTML('beforeend', `
<p>streams:</p> <p>streams:</p>
@ -123,8 +126,11 @@ function loadStreams() {
console.log('play stream failed: ', msg.message); console.log('play stream failed: ', msg.message);
}); });
}}>${instance.streaming[stream.id] ? '⏹' : '▶'}</button> }}>${instance.streaming[stream.id] ? '⏹' : '▶'}</button>
${stream.user}<span id='name'>${stream.name ? ` - ${stream.name}` : ''}</span> <span id='name'>${stream.name ? ` - ${stream.name}` : ''}</span>
</p>`; </p>`;
p.insertBefore(window.makeUser(stream.user,
stream.user.id.split?.('@')[1] || window.currentInstance.url),
p.children[1]);
p.id = 'stream' + stream.id; p.id = 'stream' + stream.id;
document.getElementById('streams').append(p); document.getElementById('streams').append(p);
} }
@ -167,8 +173,9 @@ function loadStreams() {
}); });
} }
for (let stream of window.currentThread.streams) if (window.currentThread)
addStream(stream); for (let stream of window.currentThread.streams)
addStream(stream);
} }
export default loadStreams; export default loadStreams;

View File

@ -39,26 +39,17 @@ function chooseThread() {
} }
else else
document.getElementById('thread').classList.remove('hidden'); document.getElementById('thread').classList.remove('hidden');
if (thread.permissions.admin) if (thread.permissions.admin) {
edit.classList.remove('hidden'); edit.classList.remove('hidden');
else document.getElementById('membersadd').classList.remove('hidden');
} else {
edit.classList.add('hidden'); edit.classList.add('hidden');
document.getElementById('membersadd').classList.add('hidden');
}
document.getElementById('threadname').textContent = thread.name; document.getElementById('threadname').textContent = thread.name;
this.classList.add('active'); this.classList.add('active');
window.currentThread = thread; window.currentThread = thread;
window.currentInstance = thread.instance; window.currentInstance = thread.instance;
let tab = url.searchParams.get('tab');
if (!['message', 'space', 'stream'].includes(tab))
tab = null;
if (tab || this.tab) {
if (tab)
this.tab = tab + 'tab';
switchTab(document.getElementById(this.tab));
if (this.tab === 'messagetab')
loadMessages();
else if (this.tab === 'spacetab')
loadSpace();
}
let div = this; let div = this;
window.currentInstance.emit('get_thread', { thread: thread.id }, async msg => { window.currentInstance.emit('get_thread', { thread: thread.id }, async msg => {
if (!msg.success) { if (!msg.success) {
@ -71,13 +62,13 @@ function chooseThread() {
...await Promise.all(msg.thread.members.map(async member => { ...await Promise.all(msg.thread.members.map(async member => {
let p = document.createElement('p'); let p = document.createElement('p');
if (member.name) if (member.name)
p.append(window.makeUser(member, window.currentInstance.url, true)); p.append(window.makeUser(member, window.currentInstance.url, 'member'));
else else
try { try {
let user = await window.getUser(member.id); let user = await window.getUser(member.id);
user.id = member.id; user.id = member.id;
user.permissions = member.permissions; user.permissions = member.permissions;
p.append(window.makeUser(user, user.id.split?.('@')[1], true)); p.append(window.makeUser(user, user.id.split?.('@')[1], 'member'));
} }
catch (e) { catch (e) {
console.log(`error getting user ${member.id}: ${e}`); console.log(`error getting user ${member.id}: ${e}`);
@ -87,9 +78,20 @@ function chooseThread() {
})) }))
); );
loadStreams(); loadStreams();
if (!div.tab) let tab = url.searchParams.get('tab');
if (!['message', 'space', 'stream'].includes(tab))
tab = null;
if (tab || this.tab) {
if (tab)
this.tab = tab + '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
await new Promise(resolve => { await new Promise(resolve => {
// load first tab that has any content
loadMessages(messages => { loadMessages(messages => {
if (messages.length) { if (messages.length) {
switchTab(document.getElementById(div.tab = 'messagetab')); switchTab(document.getElementById(div.tab = 'messagetab'));
@ -108,8 +110,13 @@ function chooseThread() {
}); });
}); });
}); });
url.searchParams.set('thread', thread.id); if (window.currentInstance === window.instancelist[0]) {
url.searchParams.set('tab', div.tab.substring(0, div.tab.length - 3)); url.searchParams.set('thread', thread.id);
url.searchParams.set('tab', div.tab.substring(0, div.tab.length - 3));
} else {
url.searchParams.delete('thread');
url.searchParams.delete('tab');
}
window.history.pushState(null, '', url.toString()); window.history.pushState(null, '', url.toString());
}); });
} }
@ -327,10 +334,8 @@ async function addMember() {
name.value = ''; name.value = '';
document.getElementById('addmember').classList.add('hidden'); document.getElementById('addmember').classList.add('hidden');
} }
if (!name.value) { if (!name.value)
close(); return close();
return;
}
let at = name.value.split('@'); let at = name.value.split('@');
let url = at[1] || window.currentInstance.url; let url = at[1] || window.currentInstance.url;
let user = await window.getUser('@' + url, at[0]); let user = await window.getUser('@' + url, at[0]);
@ -339,15 +344,11 @@ async function addMember() {
return; return;
} }
error.innerText = ''; error.innerText = '';
if (window.currentInstance.url !== url) { if (window.currentInstance.url !== url)
user.id += '@' + url; user.id += '@' + url;
user.name += '@' + url;
}
for (let p of document.getElementById('memberlist').children) for (let p of document.getElementById('memberlist').children)
if (p.children[0].user.id == user.id) { if (p.children[0].user.id == user.id)
close(); return close();
return;
}
window.currentInstance.emit('add_member', { window.currentInstance.emit('add_member', {
id: String(user.id), id: String(user.id),
thread: window.currentThread.id thread: window.currentThread.id
@ -359,7 +360,7 @@ async function addMember() {
} }
close(); close();
let p = document.createElement('p'); let p = document.createElement('p');
p.append(window.makeUser(user, url, true)); p.append(window.makeUser(user, url, 'member'));
document.getElementById('memberlist').append(p); document.getElementById('memberlist').append(p);
}); });
} }
@ -404,7 +405,7 @@ async function loadThreads(instancediv, select) {
<p id='visibility'></p> <p id='visibility'></p>
<div id='membershead'> <div id='membershead'>
<strong>members</strong> <strong>members</strong>
<button onclick=${e => { <button id='membersadd' onclick=${e => {
document.getElementById('addmember').classList.remove('hidden'); document.getElementById('addmember').classList.remove('hidden');
document.getElementById('addmembername').focus(); document.getElementById('addmembername').focus();
}}>add</button> }}>add</button>

View File

@ -26,8 +26,7 @@ async function stream(msg, respond, socket) {
socket.emit('stream', stream); socket.emit('stream', stream);
} else { } else {
for (let member of ( for (let member of (
await db.query( await db.query('select user from member where member.thread = ?', msg.thread)
'select user from member where member.thread = ?', msg.thread)
).rows) { ).rows) {
member = vybe.users[member.user]; member = vybe.users[member.user];
if (member) if (member)
@ -49,19 +48,30 @@ async function stream(msg, respond, socket) {
message: "stream doesn't belong to user" message: "stream doesn't belong to user"
}); });
if (msg.stop) { if (msg.stop) {
stream.stop(); await stream.stop();
return respond({ return respond({
success: true success: true
}); });
} }
stream = stream.stream; stream = stream.stream;
stream.name = msg.name; stream.name = msg.name;
stream.user.displayname = msg.auth_user.displayname;
} }
else { else {
stream = { stream = {
id: newstreamid++, id: newstreamid++,
thread: msg.thread, thread: msg.thread,
user: msg.auth_user.displayname, user: {
id: msg.auth_user.id,
name: msg.auth_user.name,
displayname: msg.auth_user.displayname,
permissions: Object.fromEntries((await db.query(
`select permission, value from permission
where type = 'user' and thread = ? and user = ?`,
[msg.thread, msg.auth_user.id])).rows.map(p =>
[p.permission, ['admin', 'post', 'view'].includes(p.permission)
? p.value === 'true' : p.value]))
},
name: msg.name name: msg.name
}; };
thread.streams.push(stream); thread.streams.push(stream);
@ -70,11 +80,11 @@ async function stream(msg, respond, socket) {
userid: msg.auth_user.id, userid: msg.auth_user.id,
listeners: {}, listeners: {},
socket: socket.id, socket: socket.id,
stop: () => { stop: async () => {
stream.stopped = true; stream.stopped = true;
thread.streams.splice(thread.streams.findIndex(s => s.id === stream.id), 1); thread.streams.splice(thread.streams.findIndex(s => s.id === stream.id), 1);
delete vybe.streams[stream.id]; delete vybe.streams[stream.id];
send(); await send();
} }
}; };
} }