Restore read-only chalkboard textarea

This commit is contained in:
Storm Dragon
2026-06-23 09:48:13 -04:00
parent 43d37b99be
commit 506c0530d9
6 changed files with 49 additions and 150 deletions
+37 -89
View File
@@ -2650,7 +2650,6 @@ function flushLiveRegion(elementId) {
let text = state.queue.shift();
if(text === undefined) {
announcement.replaceChildren();
state.active = false;
return;
}
@@ -2679,41 +2678,6 @@ 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');
}
function getChalkboardViewText() {
return document.getElementById('chalkboard-view-text');
}
/**
* @param {string} text
*/
function setChalkboardText(text) {
chalkboardText = text;
let editor = getChalkboardEditor();
if(editor && editor.value !== text)
editor.value = text;
let viewText = getChalkboardViewText();
if(viewText && viewText.textContent !== text)
viewText.textContent = text;
}
function chalkboardHasFocus() {
let active = document.activeElement;
return active === getChalkboardEditor() || active === getChalkboardView();
}
function clearChalkboardAnnouncementTimer() {
if(chalkboardAnnouncementTimer) {
@@ -2731,29 +2695,28 @@ function canEditChalkboard() {
}
function updateChalkboardAccess() {
let editor = getChalkboardEditor();
let view = getChalkboardView();
if(!editor || !view)
let chalkboard = /** @type {HTMLTextAreaElement} */
(document.getElementById('chalkboard'));
if(!chalkboard)
return;
let canEdit = canEditChalkboard();
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();
chalkboard.readOnly = !canEdit;
chalkboard.setAttribute('aria-readonly', canEdit ? 'false' : 'true');
chalkboard.setAttribute(
'aria-label',
canEdit ? 'Virtual chalkboard' : 'Virtual chalkboard, read only',
);
updateChalkboardCopyButton();
}
function updateChalkboardCopyButton() {
let chalkboard = /** @type {HTMLTextAreaElement} */
(document.getElementById('chalkboard'));
let copyButton = /** @type {HTMLButtonElement} */
(document.getElementById('chalkboard-copy'));
if(!copyButton)
if(!chalkboard || !copyButton)
return;
copyButton.disabled = chalkboardText.length === 0;
copyButton.disabled = chalkboard.value.length === 0;
}
function resetChalkboard() {
@@ -2766,38 +2729,26 @@ function resetChalkboard() {
clearTimeout(chalkboardSendTimer);
chalkboardSendTimer = null;
}
setChalkboardText('');
let chalkboard = /** @type {HTMLTextAreaElement} */
(document.getElementById('chalkboard'));
if(chalkboard)
chalkboard.value = '';
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() {
if(chalkboardText.length === 0)
let chalkboard = /** @type {HTMLTextAreaElement} */
(document.getElementById('chalkboard'));
if(!chalkboard || chalkboard.value.length === 0)
return;
try {
if(navigator.clipboard && navigator.clipboard.writeText) {
await navigator.clipboard.writeText(chalkboardText);
} else if(!copyTextWithExecCommand(chalkboardText)) {
throw new Error('copy command failed');
await navigator.clipboard.writeText(chalkboard.value);
} else {
chalkboard.focus();
chalkboard.select();
if(!document.execCommand('copy'))
throw new Error('copy command failed');
}
announceChat('Chalkboard copied to clipboard');
} catch(e) {
@@ -2820,12 +2771,14 @@ function announcePendingChalkboardUpdate() {
}
function scheduleChalkboardUpdateAnnouncement(hasText) {
if(!getChalkboardEditor() || !getChalkboardView())
let chalkboard = /** @type {HTMLTextAreaElement} */
(document.getElementById('chalkboard'));
if(!chalkboard)
return;
chalkboardHasPendingAnnouncement = true;
chalkboardPendingHasText = hasText;
if(chalkboardHasFocus())
if(document.activeElement === chalkboard)
return;
clearChalkboardAnnouncementTimer();
@@ -2849,14 +2802,16 @@ function applyChalkboardUpdate(message) {
return;
chalkboardRevision = revision;
if(!getChalkboardEditor() || !getChalkboardView())
let chalkboard = /** @type {HTMLTextAreaElement} */
(document.getElementById('chalkboard'));
if(!chalkboard)
return;
let isLocalEcho =
chalkboardLocalTextPending !== null &&
text === chalkboardLocalTextPending;
if(chalkboardText !== text) {
if(chalkboard.value !== text) {
applyingChalkboardUpdate = true;
setChalkboardText(text);
chalkboard.value = text;
applyingChalkboardUpdate = false;
if(isLocalEcho) {
chalkboardLocalTextPending = null;
@@ -2876,10 +2831,10 @@ function scheduleChalkboardSend() {
clearTimeout(chalkboardSendTimer);
chalkboardSendTimer = setTimeout(() => {
chalkboardSendTimer = null;
let chalkboard = getChalkboardEditor();
let chalkboard = /** @type {HTMLTextAreaElement} */
(document.getElementById('chalkboard'));
if(!chalkboard || !serverConnection || !serverConnection.socket)
return;
chalkboardText = chalkboard.value;
chalkboardLocalTextPending = chalkboard.value;
serverConnection.hallAction('chalkboard', {
text: chalkboard.value,
@@ -3871,9 +3826,6 @@ 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();
});
@@ -3887,10 +3839,6 @@ 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();