More ui accessibility improvements.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
# shellcheck shell=bash disable=SC2034,SC2154
|
||||
|
||||
pkgname=skald-git
|
||||
pkgver=0.0.0.r1527.g47d1308
|
||||
pkgver=0.0.0.r1528.gaac197e
|
||||
pkgrel=1
|
||||
pkgdesc='Audio-only hall-based conferencing server'
|
||||
arch=('x86_64' 'aarch64')
|
||||
|
||||
+75
-21
@@ -1,6 +1,6 @@
|
||||
/* Accessibility: Visible focus indicators for keyboard navigation */
|
||||
button:focus,
|
||||
[role="button"]:focus,
|
||||
[role="separator"]:focus,
|
||||
select:focus,
|
||||
input:focus,
|
||||
textarea:focus,
|
||||
@@ -1003,38 +1003,50 @@ header .collapse:hover {
|
||||
}
|
||||
|
||||
#users .user-p {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding: 10px !important;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-top: 0;
|
||||
height: 40px;
|
||||
line-height: 18px;
|
||||
margin: 0 !important;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
white-space: pre;
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#left-sidebar.active #users > div {
|
||||
#left-sidebar.active #users > .user-p {
|
||||
padding: 10px 5px !important;
|
||||
}
|
||||
|
||||
#users > div:hover {
|
||||
#users > .user-p:hover,
|
||||
#users > .user-p:focus {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
#users > div::before {
|
||||
content: "\f111";
|
||||
font-family: 'Font Awesome 6 Free';
|
||||
#users .user-status-icon {
|
||||
color: #20b91e;
|
||||
margin-right: 5px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
#users > div.user-status-raisehand::before {
|
||||
#users .user-status-icon::before {
|
||||
content: "\f111";
|
||||
}
|
||||
|
||||
#users .user-status-raisehand .user-status-icon::before {
|
||||
content: "\f256";
|
||||
}
|
||||
|
||||
#users > div::after {
|
||||
#users .user-microphone-icon {
|
||||
font-family: 'Font Awesome 6 Free';
|
||||
color: #808080;
|
||||
margin-left: 5px;
|
||||
@@ -1042,7 +1054,7 @@ header .collapse:hover {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#users > div.user-status-microphone::after {
|
||||
#users .user-microphone-icon::before {
|
||||
content: "\f130";
|
||||
}
|
||||
|
||||
@@ -1187,21 +1199,63 @@ header .collapse:hover {
|
||||
}
|
||||
|
||||
:root {
|
||||
--contextualMenuBg: #eee;
|
||||
--contextualMenuShadow: 1px 1px 1px #444; */
|
||||
--contextualMenuRadius: 0px; */
|
||||
--contextualMenuText: black;
|
||||
|
||||
--contextualSubMenuBg: #eee;
|
||||
|
||||
--contextualHover: #ddd;
|
||||
|
||||
--contextualOverflowIcon: #999;
|
||||
--contextualSeperator: #999;
|
||||
--skald-menu-bg: #eee;
|
||||
--skald-menu-shadow: 1px 1px 1px #444;
|
||||
--skald-menu-radius: 0;
|
||||
--skald-menu-text: black;
|
||||
--skald-menu-hover: #ddd;
|
||||
--skald-menu-separator: #999;
|
||||
}
|
||||
|
||||
.contextualMenu{
|
||||
.skald-action-menu {
|
||||
position: absolute;
|
||||
z-index: 2999;
|
||||
margin: 0;
|
||||
padding: 8px 0;
|
||||
min-width: 14em;
|
||||
list-style: none;
|
||||
background: var(--skald-menu-bg);
|
||||
box-shadow: var(--skald-menu-shadow);
|
||||
border-radius: var(--skald-menu-radius);
|
||||
color: var(--skald-menu-text);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.skald-action-menu li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.skald-action-menu-item {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
padding: 5px 8px;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.skald-action-menu-item:focus,
|
||||
.skald-action-menu-item:hover {
|
||||
background: var(--skald-menu-hover);
|
||||
}
|
||||
|
||||
.skald-action-menu-separator {
|
||||
border-top: 1px solid var(--skald-menu-separator);
|
||||
margin: 5px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.message-actions {
|
||||
margin-left: 0.5em;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: #404064;
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.file-progress {
|
||||
|
||||
+1
-3
@@ -12,7 +12,6 @@
|
||||
<link rel="stylesheet" type="text/css" href="/third-party/fontawesome/css/solid.min.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/third-party/fontawesome/css/regular.min.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/third-party/toastify/toastify.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/third-party/contextual/contextual.css"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -82,7 +81,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="resizer" class="connected-only invisible" aria-hidden="true" tabindex="0" role="separator" aria-label="Chat resize handle" aria-orientation="vertical"></div>
|
||||
<div id="resizer" class="connected-only invisible" aria-hidden="true" tabindex="0" role="separator" aria-label="Chat resize handle" aria-orientation="vertical" aria-valuemin="0" aria-valuemax="100" aria-valuenow="50" aria-valuetext="Chat width 50 percent"></div>
|
||||
<div class="coln-right" id="right">
|
||||
<button class="chat-btn show-chat invisible" id="show-chat" aria-label="Show chat">
|
||||
<i class="far fa-comment-alt icon-chat" aria-hidden="true"></i>
|
||||
@@ -217,7 +216,6 @@
|
||||
|
||||
<script src="/protocol.js" defer></script>
|
||||
<script src="/third-party/toastify/toastify.js" defer></script>
|
||||
<script src="/third-party/contextual/contextual.js" defer></script>
|
||||
<script src="/skald.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+178
-127
@@ -449,6 +449,7 @@ function setConnected(connected) {
|
||||
connectionbox.classList.add('invisible');
|
||||
closeNav();
|
||||
setLeftPanelExpanded(true);
|
||||
updateChatResizerValueFromLayout();
|
||||
displayUsername();
|
||||
window.onresize = function(e) {
|
||||
scheduleReconsiderDownRate();
|
||||
@@ -1632,55 +1633,115 @@ document.getElementById('invite-dialog').onclose = function(e) {
|
||||
makeToken(template);
|
||||
};
|
||||
|
||||
let currentActionMenu = null;
|
||||
let currentActionMenuTrigger = null;
|
||||
|
||||
function closeActionMenu(restoreFocus) {
|
||||
document.removeEventListener('click', closeActionMenuOnOutside);
|
||||
if(currentActionMenu)
|
||||
currentActionMenu.remove();
|
||||
if(currentActionMenuTrigger)
|
||||
currentActionMenuTrigger.setAttribute('aria-expanded', 'false');
|
||||
if(restoreFocus && currentActionMenuTrigger)
|
||||
currentActionMenuTrigger.focus();
|
||||
currentActionMenu = null;
|
||||
currentActionMenuTrigger = null;
|
||||
}
|
||||
|
||||
function canModerateChat() {
|
||||
return !!(serverConnection && serverConnection.permissions &&
|
||||
serverConnection.permissions.indexOf('op') >= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds keyboard navigation to Contextual menu
|
||||
* @param {HTMLElement} menuElement
|
||||
* @param {{label?: string, type?: string, onClick?: function(): void}[]} items
|
||||
* @param {HTMLElement} trigger
|
||||
* @param {string} label
|
||||
*/
|
||||
function makeContextualMenuAccessible(menuElement) {
|
||||
// Find all menu items
|
||||
let menuItems = menuElement.querySelectorAll('.contextualMenuItem:not(.disabled)');
|
||||
if(menuItems.length === 0) return;
|
||||
function openActionMenu(items, trigger, label) {
|
||||
closeActionMenu(false);
|
||||
|
||||
let currentIndex = 0;
|
||||
let menu = document.createElement('ul');
|
||||
menu.classList.add('skald-action-menu');
|
||||
menu.setAttribute('role', 'menu');
|
||||
menu.setAttribute('aria-label', label);
|
||||
|
||||
// Make menu items focusable and add ARIA
|
||||
menuItems.forEach((item, index) => {
|
||||
item.setAttribute('role', 'menuitem');
|
||||
item.setAttribute('tabindex', index === 0 ? '0' : '-1');
|
||||
});
|
||||
|
||||
// Focus first item
|
||||
menuItems[0].focus();
|
||||
|
||||
// Add keyboard navigation
|
||||
menuElement.addEventListener('keydown', function(e) {
|
||||
if(e.key === 'Escape') {
|
||||
e.preventDefault();
|
||||
contextualCore.CloseMenu();
|
||||
let buttons = [];
|
||||
items.forEach(item => {
|
||||
let li = document.createElement('li');
|
||||
if(item.type === 'seperator') {
|
||||
li.classList.add('skald-action-menu-separator');
|
||||
li.setAttribute('role', 'separator');
|
||||
menu.appendChild(li);
|
||||
return;
|
||||
}
|
||||
|
||||
if(e.key === 'ArrowDown') {
|
||||
let button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.classList.add('skald-action-menu-item');
|
||||
button.setAttribute('role', 'menuitem');
|
||||
button.textContent = item.label || 'Action';
|
||||
button.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
closeActionMenu(true);
|
||||
if(item.onClick)
|
||||
item.onClick();
|
||||
});
|
||||
li.appendChild(button);
|
||||
menu.appendChild(li);
|
||||
buttons.push(button);
|
||||
});
|
||||
|
||||
if(buttons.length === 0)
|
||||
return;
|
||||
|
||||
menu.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
menu.addEventListener('keydown', function(e) {
|
||||
let index = buttons.indexOf(document.activeElement);
|
||||
if(e.key === 'Escape') {
|
||||
e.preventDefault();
|
||||
menuItems[currentIndex].setAttribute('tabindex', '-1');
|
||||
currentIndex = (currentIndex + 1) % menuItems.length;
|
||||
menuItems[currentIndex].setAttribute('tabindex', '0');
|
||||
menuItems[currentIndex].focus();
|
||||
closeActionMenu(true);
|
||||
} else if(e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
buttons[(index + 1 + buttons.length) % buttons.length].focus();
|
||||
} else if(e.key === 'ArrowUp') {
|
||||
e.preventDefault();
|
||||
menuItems[currentIndex].setAttribute('tabindex', '-1');
|
||||
currentIndex = currentIndex === 0 ? menuItems.length - 1 : currentIndex - 1;
|
||||
menuItems[currentIndex].setAttribute('tabindex', '0');
|
||||
menuItems[currentIndex].focus();
|
||||
} else if(e.key === 'Enter' || e.key === ' ') {
|
||||
buttons[(index - 1 + buttons.length) % buttons.length].focus();
|
||||
} else if(e.key === 'Home') {
|
||||
e.preventDefault();
|
||||
// Click the parent li element which has the actual click handler
|
||||
let parentLi = menuItems[currentIndex].parentElement;
|
||||
if(parentLi) {
|
||||
parentLi.click();
|
||||
}
|
||||
buttons[0].focus();
|
||||
} else if(e.key === 'End') {
|
||||
e.preventDefault();
|
||||
buttons[buttons.length - 1].focus();
|
||||
}
|
||||
});
|
||||
|
||||
document.body.appendChild(menu);
|
||||
currentActionMenu = menu;
|
||||
currentActionMenuTrigger = trigger;
|
||||
trigger.setAttribute('aria-haspopup', 'menu');
|
||||
trigger.setAttribute('aria-expanded', 'true');
|
||||
|
||||
let rect = trigger.getBoundingClientRect();
|
||||
let left = rect.left;
|
||||
let top = rect.bottom;
|
||||
if(left + menu.offsetWidth > window.innerWidth)
|
||||
left = Math.max(0, window.innerWidth - menu.offsetWidth);
|
||||
if(top + menu.offsetHeight > window.innerHeight)
|
||||
top = Math.max(0, rect.top - menu.offsetHeight);
|
||||
menu.style.left = `${left}px`;
|
||||
menu.style.top = `${top}px`;
|
||||
|
||||
window.setTimeout(() => {
|
||||
document.addEventListener('click', closeActionMenuOnOutside);
|
||||
}, 0);
|
||||
buttons[0].focus();
|
||||
}
|
||||
|
||||
function closeActionMenuOnOutside() {
|
||||
closeActionMenu(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1740,19 +1801,7 @@ function userMenu(elt) {
|
||||
}});
|
||||
}
|
||||
}
|
||||
/** @ts-ignore */
|
||||
new Contextual({
|
||||
items: items,
|
||||
});
|
||||
|
||||
// Add keyboard navigation after menu is created
|
||||
setTimeout(() => {
|
||||
let menu = document.querySelector('.contextualMenu');
|
||||
if(menu) {
|
||||
menu.setAttribute('role', 'menu');
|
||||
makeContextualMenuAccessible(menu);
|
||||
}
|
||||
}, 0);
|
||||
openActionMenu(items, elt, `Actions for ${user.username || 'participant'}`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1761,27 +1810,32 @@ function userMenu(elt) {
|
||||
*/
|
||||
function addUser(id, userinfo) {
|
||||
let div = document.getElementById('users');
|
||||
let user = document.createElement('div');
|
||||
let user = document.createElement('button');
|
||||
user.id = 'user-' + id;
|
||||
user.type = 'button';
|
||||
user.classList.add("user-p");
|
||||
user.setAttribute('role', 'button');
|
||||
user.setAttribute('tabindex', '0');
|
||||
user.setAttribute('aria-haspopup', 'menu');
|
||||
user.setAttribute('aria-expanded', 'false');
|
||||
let statusIcon = document.createElement('span');
|
||||
statusIcon.classList.add('user-status-icon', 'fas');
|
||||
statusIcon.setAttribute('aria-hidden', 'true');
|
||||
user.appendChild(statusIcon);
|
||||
let name = document.createElement('span');
|
||||
name.classList.add('user-name');
|
||||
user.appendChild(name);
|
||||
let microphoneIcon = document.createElement('span');
|
||||
microphoneIcon.classList.add('user-microphone-icon', 'fas');
|
||||
microphoneIcon.setAttribute('aria-hidden', 'true');
|
||||
microphoneIcon.hidden = true;
|
||||
user.appendChild(microphoneIcon);
|
||||
setUserStatus(id, user, userinfo, false);
|
||||
user.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
let elt = e.currentTarget;
|
||||
if(!elt || !(elt instanceof HTMLElement))
|
||||
throw new Error("Couldn't find user div");
|
||||
throw new Error("Couldn't find user button");
|
||||
userMenu(elt);
|
||||
});
|
||||
user.addEventListener('keydown', function(e) {
|
||||
if(e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
let elt = e.target;
|
||||
if(!elt || !(elt instanceof HTMLElement))
|
||||
throw new Error("Couldn't find user div");
|
||||
userMenu(elt);
|
||||
}
|
||||
});
|
||||
|
||||
let us = div.children;
|
||||
|
||||
@@ -1832,19 +1886,21 @@ function changeUser(id, userinfo) {
|
||||
*/
|
||||
function setUserStatus(id, elt, userinfo, notify) {
|
||||
let username = userinfo.username ? userinfo.username : '(anon)';
|
||||
elt.textContent = username;
|
||||
let name = elt.querySelector('.user-name');
|
||||
if(!name)
|
||||
throw new Error("Couldn't find user name span");
|
||||
if(name.textContent !== username)
|
||||
name.textContent = username;
|
||||
|
||||
let wasRaised = elt.classList.contains('user-status-raisehand');
|
||||
if(userinfo.data.raisehand) {
|
||||
elt.classList.add('user-status-raisehand');
|
||||
elt.setAttribute('aria-label', `${username} (hand raised)`);
|
||||
if(notify && !wasRaised) {
|
||||
announceUrgent(`${username}: hand raised`);
|
||||
playNotificationSound('hand-raised');
|
||||
}
|
||||
} else {
|
||||
elt.classList.remove('user-status-raisehand');
|
||||
elt.setAttribute('aria-label', username);
|
||||
if(notify && wasRaised) {
|
||||
announceUrgent(`${username}: hand lowered`);
|
||||
playNotificationSound('hand-lowered');
|
||||
@@ -1866,6 +1922,11 @@ function setUserStatus(id, elt, userinfo, notify) {
|
||||
|
||||
if(microphone)
|
||||
statusParts.push('microphone on');
|
||||
elt.classList.toggle('user-status-microphone', microphone);
|
||||
let microphoneIcon = elt.querySelector('.user-microphone-icon');
|
||||
if(!microphoneIcon)
|
||||
throw new Error("Couldn't find user microphone icon span");
|
||||
microphoneIcon.hidden = !microphone;
|
||||
elt.setAttribute('aria-label', statusParts.join(', '));
|
||||
}
|
||||
|
||||
@@ -2559,14 +2620,6 @@ function addToChatbox(id, peerId, dest, nick, time, privileged, history, kind, m
|
||||
if(peerId) {
|
||||
container.dataset.peerId = peerId;
|
||||
container.dataset.username = nick;
|
||||
container.addEventListener('click', function(e) {
|
||||
if(e.detail !== 2)
|
||||
return;
|
||||
let elt = e.currentTarget;
|
||||
if(!elt || !(elt instanceof HTMLElement))
|
||||
throw new Error("Couldn't find chat message div");
|
||||
chatMessageMenu(elt);
|
||||
});
|
||||
}
|
||||
|
||||
/** @type{HTMLElement} */
|
||||
@@ -2634,6 +2687,20 @@ function addToChatbox(id, peerId, dest, nick, time, privileged, history, kind, m
|
||||
lastMessage = {};
|
||||
}
|
||||
container.appendChild(footer);
|
||||
if(peerId && canModerateChat()) {
|
||||
let actions = document.createElement('button');
|
||||
actions.type = 'button';
|
||||
actions.classList.add('message-actions');
|
||||
actions.setAttribute('aria-haspopup', 'menu');
|
||||
actions.setAttribute('aria-expanded', 'false');
|
||||
actions.setAttribute('aria-label', `Actions for message from ${nick || '(anon)'}`);
|
||||
actions.textContent = 'Actions';
|
||||
actions.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
chatMessageMenu(container, actions);
|
||||
});
|
||||
footer.appendChild(actions);
|
||||
}
|
||||
|
||||
let box = document.getElementById('box');
|
||||
box.appendChild(row);
|
||||
@@ -2657,10 +2724,10 @@ function addToChatbox(id, peerId, dest, nick, time, privileged, history, kind, m
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} elt
|
||||
* @param {HTMLElement} trigger
|
||||
*/
|
||||
function chatMessageMenu(elt) {
|
||||
if(!(serverConnection && serverConnection.permissions &&
|
||||
serverConnection.permissions.indexOf('op') >= 0))
|
||||
function chatMessageMenu(elt, trigger) {
|
||||
if(!canModerateChat())
|
||||
return;
|
||||
|
||||
let messageId = elt.dataset.id;
|
||||
@@ -2691,19 +2758,7 @@ function chatMessageMenu(elt) {
|
||||
serverConnection.userAction('kick', peerId);
|
||||
}});
|
||||
|
||||
/** @ts-ignore */
|
||||
new Contextual({
|
||||
items: items,
|
||||
});
|
||||
|
||||
// Add keyboard navigation after menu is created
|
||||
setTimeout(() => {
|
||||
let menu = document.querySelector('.contextualMenu');
|
||||
if(menu) {
|
||||
menu.setAttribute('role', 'menu');
|
||||
makeContextualMenuAccessible(menu);
|
||||
}
|
||||
}, 0);
|
||||
openActionMenu(items, trigger, `Actions for message from ${u}`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3480,24 +3535,49 @@ document.getElementById('input').onkeypress = function(e) {
|
||||
}
|
||||
};
|
||||
|
||||
function updateChatResizerValue(leftPercent) {
|
||||
let resizer = document.getElementById('resizer');
|
||||
if(!resizer)
|
||||
return;
|
||||
let rounded = Math.round(leftPercent);
|
||||
resizer.setAttribute('aria-valuenow', rounded.toString());
|
||||
resizer.setAttribute('aria-valuetext', `Chat width ${rounded} percent`);
|
||||
}
|
||||
|
||||
function updateChatResizerValueFromLayout() {
|
||||
let mainrow = document.getElementById("mainrow");
|
||||
let left = document.getElementById("left");
|
||||
if(!mainrow || !left || mainrow.offsetWidth === 0)
|
||||
return;
|
||||
updateChatResizerValue(left.offsetWidth * 100 / mainrow.offsetWidth);
|
||||
}
|
||||
|
||||
function setChatWidth(leftPercent) {
|
||||
let full_width = document.getElementById("mainrow").offsetWidth;
|
||||
let left = document.getElementById("left");
|
||||
let right = document.getElementById("right");
|
||||
|
||||
let min_left_width = 300 * 100 / full_width;
|
||||
if(leftPercent < min_left_width)
|
||||
return false;
|
||||
|
||||
left.style.flex = leftPercent.toString();
|
||||
right.style.flex = (100 - leftPercent).toString();
|
||||
updateChatResizerValue(leftPercent);
|
||||
return true;
|
||||
}
|
||||
|
||||
function chatResizer(e) {
|
||||
e.preventDefault();
|
||||
let full_width = document.getElementById("mainrow").offsetWidth;
|
||||
let left = document.getElementById("left");
|
||||
let right = document.getElementById("right");
|
||||
|
||||
let start_x = e.clientX;
|
||||
let start_width = left.offsetWidth;
|
||||
|
||||
function start_drag(e) {
|
||||
let left_width = (start_width + e.clientX - start_x) * 100 / full_width;
|
||||
// set min chat width to 300px
|
||||
let min_left_width = 300 * 100 / full_width;
|
||||
if (left_width < min_left_width) {
|
||||
return;
|
||||
}
|
||||
left.style.flex = left_width.toString();
|
||||
right.style.flex = (100 - left_width).toString();
|
||||
setChatWidth(left_width);
|
||||
}
|
||||
function stop_drag(e) {
|
||||
document.documentElement.removeEventListener(
|
||||
@@ -3524,21 +3604,12 @@ document.getElementById('resizer').addEventListener('keydown', function(e) {
|
||||
e.preventDefault();
|
||||
let full_width = document.getElementById("mainrow").offsetWidth;
|
||||
let left = document.getElementById("left");
|
||||
let right = document.getElementById("right");
|
||||
let current_width = left.offsetWidth;
|
||||
let step = 20; // pixels per keypress
|
||||
|
||||
let new_width = e.key === 'ArrowLeft' ? current_width - step : current_width + step;
|
||||
let left_percent = new_width * 100 / full_width;
|
||||
|
||||
// set min chat width to 300px
|
||||
let min_left_width = 300 * 100 / full_width;
|
||||
if (left_percent < min_left_width) {
|
||||
return;
|
||||
}
|
||||
|
||||
left.style.flex = left_percent.toString();
|
||||
right.style.flex = (100 - left_percent).toString();
|
||||
setChatWidth(left_percent);
|
||||
}
|
||||
}, false);
|
||||
|
||||
@@ -3697,16 +3768,6 @@ document.getElementById('close-chat').onclick = function(e) {
|
||||
document.getElementById('show-chat').focus();
|
||||
};
|
||||
|
||||
document.getElementById('close-chat').onkeydown = function(e) {
|
||||
if(e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
setVisibility('left', false);
|
||||
setVisibility('show-chat', true);
|
||||
resizePeers();
|
||||
document.getElementById('show-chat').focus();
|
||||
}
|
||||
};
|
||||
|
||||
document.getElementById('show-chat').onclick = function(e) {
|
||||
e.preventDefault();
|
||||
setVisibility('left', true);
|
||||
@@ -3715,16 +3776,6 @@ document.getElementById('show-chat').onclick = function(e) {
|
||||
document.getElementById('close-chat').focus();
|
||||
};
|
||||
|
||||
document.getElementById('show-chat').onkeydown = function(e) {
|
||||
if(e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
setVisibility('left', true);
|
||||
setVisibility('show-chat', false);
|
||||
resizePeers();
|
||||
document.getElementById('close-chat').focus();
|
||||
}
|
||||
};
|
||||
|
||||
async function serverConnect() {
|
||||
if(serverConnection && serverConnection.socket)
|
||||
serverConnection.close();
|
||||
|
||||
Reference in New Issue
Block a user