Chalkboard feature added.
This commit is contained in:
+142
@@ -579,6 +579,7 @@ function gotClose(code, reason) {
|
||||
closeUpMedia();
|
||||
closeSafariStream();
|
||||
setConnected(false);
|
||||
resetChalkboard();
|
||||
if(code != 1000) {
|
||||
console.warn('Socket close', code, reason);
|
||||
}
|
||||
@@ -1802,6 +1803,19 @@ function userMenu(elt) {
|
||||
serverConnection.userAction('identify', id);
|
||||
}});
|
||||
}
|
||||
if(serverConnection.permissions.indexOf('op') >= 0 ||
|
||||
serverConnection.permissions.indexOf('admin') >= 0) {
|
||||
if(serverConnection.permissions.indexOf('op') < 0)
|
||||
items.push({type: 'seperator'}); // sic
|
||||
if(user.permissions.indexOf('chalkboard') >= 0)
|
||||
items.push({label: 'Forbid chalkboard editing', onClick: () => {
|
||||
serverConnection.userAction('unchalkboard', id);
|
||||
}});
|
||||
else
|
||||
items.push({label: 'Allow chalkboard editing', onClick: () => {
|
||||
serverConnection.userAction('chalkboard', id);
|
||||
}});
|
||||
}
|
||||
}
|
||||
openActionMenu(items, elt, `Actions for ${user.username || 'participant'}`);
|
||||
}
|
||||
@@ -1981,6 +1995,7 @@ function displayUsername() {
|
||||
document.getElementById('userspan').textContent = serverConnection.username;
|
||||
let op = serverConnection.permissions.indexOf('op') >= 0;
|
||||
let present = serverConnection.permissions.indexOf('present') >= 0;
|
||||
let chalkboard = canEditChalkboard();
|
||||
let text = '';
|
||||
if(op && present)
|
||||
text = '(op, presenter)';
|
||||
@@ -1988,6 +2003,8 @@ function displayUsername() {
|
||||
text = 'operator';
|
||||
else if(present)
|
||||
text = 'presenter';
|
||||
else if(chalkboard)
|
||||
text = 'chalkboard editor';
|
||||
document.getElementById('permspan').textContent = text;
|
||||
}
|
||||
|
||||
@@ -2098,6 +2115,7 @@ async function gotJoined(kind, hall, perms, status, data, error, message) {
|
||||
setTitle((status && status.displayName) || capitalise(hall));
|
||||
setConnected(true);
|
||||
displayUsername();
|
||||
updateChalkboardAccess();
|
||||
setButtonsVisibility();
|
||||
setChangePassword(pwAuth && !!hallStatus.canChangePassword &&
|
||||
serverConnection.username
|
||||
@@ -2404,6 +2422,13 @@ function gotUserMessage(id, dest, username, time, privileged, kind, error, messa
|
||||
clearChat(id, userId);
|
||||
break;
|
||||
}
|
||||
case 'chalkboard':
|
||||
if(!privileged) {
|
||||
console.error(`Got unprivileged message of kind ${kind}`);
|
||||
return;
|
||||
}
|
||||
applyChalkboardUpdate(message);
|
||||
break;
|
||||
case 'token':
|
||||
if(!privileged) {
|
||||
console.error(`Got unprivileged message of kind ${kind}`);
|
||||
@@ -2586,6 +2611,89 @@ function announceChat(text) {
|
||||
announceLiveRegion(text, 'chat-announcements');
|
||||
}
|
||||
|
||||
let chalkboardRevision = 0;
|
||||
let chalkboardSendTimer = null;
|
||||
let applyingChalkboardUpdate = false;
|
||||
|
||||
function canEditChalkboard() {
|
||||
if(!serverConnection || !serverConnection.permissions)
|
||||
return false;
|
||||
return serverConnection.permissions.indexOf('op') >= 0 ||
|
||||
serverConnection.permissions.indexOf('admin') >= 0 ||
|
||||
serverConnection.permissions.indexOf('chalkboard') >= 0;
|
||||
}
|
||||
|
||||
function updateChalkboardAccess() {
|
||||
let chalkboard = /** @type {HTMLTextAreaElement} */
|
||||
(document.getElementById('chalkboard'));
|
||||
if(!chalkboard)
|
||||
return;
|
||||
let canEdit = canEditChalkboard();
|
||||
chalkboard.readOnly = !canEdit;
|
||||
chalkboard.setAttribute('aria-readonly', canEdit ? 'false' : 'true');
|
||||
chalkboard.setAttribute(
|
||||
'aria-label',
|
||||
canEdit ? 'Virtual chalkboard' : 'Virtual chalkboard, read only',
|
||||
);
|
||||
}
|
||||
|
||||
function resetChalkboard() {
|
||||
chalkboardRevision = 0;
|
||||
if(chalkboardSendTimer) {
|
||||
clearTimeout(chalkboardSendTimer);
|
||||
chalkboardSendTimer = null;
|
||||
}
|
||||
let chalkboard = /** @type {HTMLTextAreaElement} */
|
||||
(document.getElementById('chalkboard'));
|
||||
if(chalkboard)
|
||||
chalkboard.value = '';
|
||||
updateChalkboardAccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} message
|
||||
*/
|
||||
function applyChalkboardUpdate(message) {
|
||||
if(!message || typeof message !== 'object') {
|
||||
console.warn('Unexpected chalkboard message', message);
|
||||
return;
|
||||
}
|
||||
let text = typeof message.text === 'string' ? message.text : '';
|
||||
let revision = Number(message.revision || 0);
|
||||
if(revision < chalkboardRevision)
|
||||
return;
|
||||
|
||||
chalkboardRevision = revision;
|
||||
let chalkboard = /** @type {HTMLTextAreaElement} */
|
||||
(document.getElementById('chalkboard'));
|
||||
if(!chalkboard)
|
||||
return;
|
||||
if(chalkboard.value !== text) {
|
||||
applyingChalkboardUpdate = true;
|
||||
chalkboard.value = text;
|
||||
applyingChalkboardUpdate = false;
|
||||
}
|
||||
updateChalkboardAccess();
|
||||
}
|
||||
|
||||
function scheduleChalkboardSend() {
|
||||
if(!canEditChalkboard())
|
||||
return;
|
||||
if(chalkboardSendTimer)
|
||||
clearTimeout(chalkboardSendTimer);
|
||||
chalkboardSendTimer = setTimeout(() => {
|
||||
chalkboardSendTimer = null;
|
||||
let chalkboard = /** @type {HTMLTextAreaElement} */
|
||||
(document.getElementById('chalkboard'));
|
||||
if(!chalkboard || !serverConnection || !serverConnection.socket)
|
||||
return;
|
||||
serverConnection.hallAction('chalkboard', {
|
||||
text: chalkboard.value,
|
||||
revision: chalkboardRevision,
|
||||
});
|
||||
}, 350);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
*/
|
||||
@@ -2866,6 +2974,14 @@ function operatorPredicate() {
|
||||
return 'You are not an operator';
|
||||
}
|
||||
|
||||
function chalkboardGrantPredicate() {
|
||||
if(serverConnection && serverConnection.permissions &&
|
||||
(serverConnection.permissions.indexOf('op') >= 0 ||
|
||||
serverConnection.permissions.indexOf('admin') >= 0))
|
||||
return null;
|
||||
return 'You are not allowed to grant chalkboard editing';
|
||||
}
|
||||
|
||||
function recordingPredicate() {
|
||||
if(serverConnection && serverConnection.permissions &&
|
||||
serverConnection.permissions.indexOf('record') >= 0)
|
||||
@@ -3311,6 +3427,20 @@ commands.unshutup = {
|
||||
f: userCommand,
|
||||
};
|
||||
|
||||
commands.chalkboard = {
|
||||
parameters: 'user',
|
||||
description: 'give the right to edit the virtual chalkboard',
|
||||
predicate: chalkboardGrantPredicate,
|
||||
f: userCommand,
|
||||
};
|
||||
|
||||
commands.unchalkboard = {
|
||||
parameters: 'user',
|
||||
description: 'revoke the right to edit the virtual chalkboard',
|
||||
predicate: chalkboardGrantPredicate,
|
||||
f: userCommand,
|
||||
};
|
||||
|
||||
commands.mute = {
|
||||
parameters: 'user',
|
||||
description: 'mute a remote user',
|
||||
@@ -3544,6 +3674,17 @@ document.getElementById('input').onkeypress = function(e) {
|
||||
}
|
||||
};
|
||||
|
||||
document.getElementById('chalkboard').addEventListener('input', function(e) {
|
||||
if(applyingChalkboardUpdate)
|
||||
return;
|
||||
scheduleChalkboardSend();
|
||||
});
|
||||
|
||||
document.getElementById('chalkboard').addEventListener('keydown', function(e) {
|
||||
if(e.key === 'Tab')
|
||||
return;
|
||||
});
|
||||
|
||||
function updateChatResizerValue(leftPercent) {
|
||||
let resizer = document.getElementById('resizer');
|
||||
if(!resizer)
|
||||
@@ -3981,4 +4122,5 @@ document.addEventListener('keydown', function(e) {
|
||||
}
|
||||
});
|
||||
|
||||
resetChalkboard();
|
||||
start();
|
||||
|
||||
Reference in New Issue
Block a user