Change chalkboard to pre tag for people who do not have write access because some screen readers seem to have problems with read only edit boxes.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
# shellcheck shell=bash disable=SC2034,SC2154
|
||||
|
||||
pkgname=skald-git
|
||||
pkgver=0.0.0.r1540.g26c7808
|
||||
pkgver=0.0.0.r1541.gd8817f6
|
||||
pkgrel=1
|
||||
pkgdesc='Audio-only hall-based conferencing server'
|
||||
arch=('x86_64' 'aarch64')
|
||||
|
||||
@@ -75,13 +75,12 @@ than navigating the user interface. Commands start with a slash character
|
||||
message to a given user. Type `/help` to display the list of available
|
||||
commands.
|
||||
|
||||
Below the chat input is a session-only virtual chalkboard. It is a
|
||||
multiline text area suitable for commands, code, and notes that should be
|
||||
visible to everyone in the hall. Operators and administrators may edit
|
||||
the chalkboard and may grant or revoke chalkboard editing for connected
|
||||
users with `/chalkboard user` and `/unchalkboard user`. Users without
|
||||
edit permission can read and focus the chalkboard, but it is marked
|
||||
read-only and does not trap the Tab key.
|
||||
Below the chat input is a session-only virtual chalkboard suitable for
|
||||
commands, code, and notes that should be visible to everyone in the hall.
|
||||
Operators and administrators edit it as a multiline text area and may grant
|
||||
or revoke chalkboard editing for connected users with `/chalkboard user`
|
||||
and `/unchalkboard user`. Users without edit permission can read and focus
|
||||
the chalkboard as preformatted text.
|
||||
|
||||
### Inviting users
|
||||
|
||||
|
||||
+23
-3
@@ -829,14 +829,33 @@ h1 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#chalkboard {
|
||||
#chalkboard,
|
||||
#chalkboard-view {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 8rem;
|
||||
}
|
||||
|
||||
#chalkboard {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
#chalkboard-view {
|
||||
border: 1px solid #767676;
|
||||
border-radius: 2px;
|
||||
font-family: monospace;
|
||||
margin: 0;
|
||||
overflow: auto;
|
||||
padding: 2px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
#chalkboard[hidden],
|
||||
#chalkboard-view[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#chalkboard-copy {
|
||||
margin-top: 0.35rem;
|
||||
}
|
||||
@@ -845,11 +864,12 @@ h1 {
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
#chalkboard[readonly] {
|
||||
#chalkboard-view {
|
||||
background: #f3f3f3;
|
||||
}
|
||||
|
||||
#chalkboard:focus {
|
||||
#chalkboard:focus,
|
||||
#chalkboard-view:focus {
|
||||
outline: 2px solid #0066cc;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
<div id="chalkboard-area">
|
||||
<h2 id="chalkboard-heading">Virtual chalkboard</h2>
|
||||
<textarea id="chalkboard" aria-labelledby="chalkboard-heading"></textarea>
|
||||
<pre id="chalkboard-view" tabindex="0" role="region" aria-labelledby="chalkboard-heading" hidden></pre>
|
||||
<button id="chalkboard-copy" type="button" class="btn btn-default" disabled>Copy to clipboard</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+82
-36
@@ -2678,6 +2678,36 @@ let chalkboardAnnouncementTimer = null;
|
||||
let chalkboardHasPendingAnnouncement = false;
|
||||
let chalkboardPendingHasText = false;
|
||||
let chalkboardLocalTextPending = null;
|
||||
let chalkboardText = '';
|
||||
|
||||
function getChalkboardEditor() {
|
||||
return /** @type {HTMLTextAreaElement} */
|
||||
(document.getElementById('chalkboard'));
|
||||
}
|
||||
|
||||
function getChalkboardView() {
|
||||
return document.getElementById('chalkboard-view');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
*/
|
||||
function setChalkboardText(text) {
|
||||
chalkboardText = text;
|
||||
|
||||
let editor = getChalkboardEditor();
|
||||
if(editor && editor.value !== text)
|
||||
editor.value = text;
|
||||
|
||||
let view = getChalkboardView();
|
||||
if(view && view.textContent !== text)
|
||||
view.textContent = text;
|
||||
}
|
||||
|
||||
function chalkboardHasFocus() {
|
||||
let active = document.activeElement;
|
||||
return active === getChalkboardEditor() || active === getChalkboardView();
|
||||
}
|
||||
|
||||
function clearChalkboardAnnouncementTimer() {
|
||||
if(chalkboardAnnouncementTimer) {
|
||||
@@ -2695,28 +2725,29 @@ function canEditChalkboard() {
|
||||
}
|
||||
|
||||
function updateChalkboardAccess() {
|
||||
let chalkboard = /** @type {HTMLTextAreaElement} */
|
||||
(document.getElementById('chalkboard'));
|
||||
if(!chalkboard)
|
||||
let editor = getChalkboardEditor();
|
||||
let view = getChalkboardView();
|
||||
if(!editor || !view)
|
||||
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',
|
||||
);
|
||||
let active = document.activeElement;
|
||||
editor.hidden = !canEdit;
|
||||
view.hidden = canEdit;
|
||||
editor.setAttribute('aria-label', 'Virtual chalkboard');
|
||||
view.setAttribute('aria-label', 'Virtual chalkboard, read only');
|
||||
if(active === editor && !canEdit)
|
||||
view.focus();
|
||||
else if(active === view && canEdit)
|
||||
editor.focus();
|
||||
updateChalkboardCopyButton();
|
||||
}
|
||||
|
||||
function updateChalkboardCopyButton() {
|
||||
let chalkboard = /** @type {HTMLTextAreaElement} */
|
||||
(document.getElementById('chalkboard'));
|
||||
let copyButton = /** @type {HTMLButtonElement} */
|
||||
(document.getElementById('chalkboard-copy'));
|
||||
if(!chalkboard || !copyButton)
|
||||
if(!copyButton)
|
||||
return;
|
||||
copyButton.disabled = chalkboard.value.length === 0;
|
||||
copyButton.disabled = chalkboardText.length === 0;
|
||||
}
|
||||
|
||||
function resetChalkboard() {
|
||||
@@ -2729,25 +2760,37 @@ function resetChalkboard() {
|
||||
clearTimeout(chalkboardSendTimer);
|
||||
chalkboardSendTimer = null;
|
||||
}
|
||||
let chalkboard = /** @type {HTMLTextAreaElement} */
|
||||
(document.getElementById('chalkboard'));
|
||||
if(chalkboard)
|
||||
chalkboard.value = '';
|
||||
setChalkboardText('');
|
||||
updateChalkboardAccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
*/
|
||||
function copyTextWithExecCommand(text) {
|
||||
let fallback = document.createElement('textarea');
|
||||
fallback.value = text;
|
||||
fallback.readOnly = true;
|
||||
fallback.style.position = 'fixed';
|
||||
fallback.style.left = '-9999px';
|
||||
fallback.style.top = '0';
|
||||
document.body.appendChild(fallback);
|
||||
try {
|
||||
fallback.focus();
|
||||
fallback.select();
|
||||
return document.execCommand('copy');
|
||||
} finally {
|
||||
document.body.removeChild(fallback);
|
||||
}
|
||||
}
|
||||
|
||||
async function copyChalkboardToClipboard() {
|
||||
let chalkboard = /** @type {HTMLTextAreaElement} */
|
||||
(document.getElementById('chalkboard'));
|
||||
if(!chalkboard || chalkboard.value.length === 0)
|
||||
if(chalkboardText.length === 0)
|
||||
return;
|
||||
try {
|
||||
if(navigator.clipboard && navigator.clipboard.writeText) {
|
||||
await navigator.clipboard.writeText(chalkboard.value);
|
||||
} else {
|
||||
chalkboard.focus();
|
||||
chalkboard.select();
|
||||
if(!document.execCommand('copy'))
|
||||
await navigator.clipboard.writeText(chalkboardText);
|
||||
} else if(!copyTextWithExecCommand(chalkboardText)) {
|
||||
throw new Error('copy command failed');
|
||||
}
|
||||
announceChat('Chalkboard copied to clipboard');
|
||||
@@ -2771,14 +2814,12 @@ function announcePendingChalkboardUpdate() {
|
||||
}
|
||||
|
||||
function scheduleChalkboardUpdateAnnouncement(hasText) {
|
||||
let chalkboard = /** @type {HTMLTextAreaElement} */
|
||||
(document.getElementById('chalkboard'));
|
||||
if(!chalkboard)
|
||||
if(!getChalkboardEditor() || !getChalkboardView())
|
||||
return;
|
||||
|
||||
chalkboardHasPendingAnnouncement = true;
|
||||
chalkboardPendingHasText = hasText;
|
||||
if(document.activeElement === chalkboard)
|
||||
if(chalkboardHasFocus())
|
||||
return;
|
||||
|
||||
clearChalkboardAnnouncementTimer();
|
||||
@@ -2802,16 +2843,14 @@ function applyChalkboardUpdate(message) {
|
||||
return;
|
||||
|
||||
chalkboardRevision = revision;
|
||||
let chalkboard = /** @type {HTMLTextAreaElement} */
|
||||
(document.getElementById('chalkboard'));
|
||||
if(!chalkboard)
|
||||
if(!getChalkboardEditor() || !getChalkboardView())
|
||||
return;
|
||||
let isLocalEcho =
|
||||
chalkboardLocalTextPending !== null &&
|
||||
text === chalkboardLocalTextPending;
|
||||
if(chalkboard.value !== text) {
|
||||
if(chalkboardText !== text) {
|
||||
applyingChalkboardUpdate = true;
|
||||
chalkboard.value = text;
|
||||
setChalkboardText(text);
|
||||
applyingChalkboardUpdate = false;
|
||||
if(isLocalEcho) {
|
||||
chalkboardLocalTextPending = null;
|
||||
@@ -2831,10 +2870,10 @@ function scheduleChalkboardSend() {
|
||||
clearTimeout(chalkboardSendTimer);
|
||||
chalkboardSendTimer = setTimeout(() => {
|
||||
chalkboardSendTimer = null;
|
||||
let chalkboard = /** @type {HTMLTextAreaElement} */
|
||||
(document.getElementById('chalkboard'));
|
||||
let chalkboard = getChalkboardEditor();
|
||||
if(!chalkboard || !serverConnection || !serverConnection.socket)
|
||||
return;
|
||||
chalkboardText = chalkboard.value;
|
||||
chalkboardLocalTextPending = chalkboard.value;
|
||||
serverConnection.hallAction('chalkboard', {
|
||||
text: chalkboard.value,
|
||||
@@ -3826,6 +3865,9 @@ document.getElementById('input').onkeypress = function(e) {
|
||||
document.getElementById('chalkboard').addEventListener('input', function(e) {
|
||||
if(applyingChalkboardUpdate)
|
||||
return;
|
||||
let chalkboard = getChalkboardEditor();
|
||||
if(chalkboard)
|
||||
setChalkboardText(chalkboard.value);
|
||||
updateChalkboardCopyButton();
|
||||
scheduleChalkboardSend();
|
||||
});
|
||||
@@ -3839,6 +3881,10 @@ document.getElementById('chalkboard').addEventListener('focus', function(e) {
|
||||
announcePendingChalkboardUpdate();
|
||||
});
|
||||
|
||||
document.getElementById('chalkboard-view').addEventListener('focus', function(e) {
|
||||
announcePendingChalkboardUpdate();
|
||||
});
|
||||
|
||||
document.getElementById('chalkboard-copy').addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
copyChalkboardToClipboard();
|
||||
|
||||
Reference in New Issue
Block a user