lint: handle js errors

dev
gravel 1 year ago
parent 09c96873a2
commit 31a68403aa
No known key found for this signature in database
GPG Key ID: CA95FFF4E0123903

@ -322,6 +322,7 @@ function createElement(tag, ...args) {
return element; return element;
} }
/** @type {Record<string, (...args: any | HTMLElement): HTMLElement>} */
export const element = new Proxy({}, { export const element = new Proxy({}, {
get(_, key) { get(_, key) {
return (...args) => createElement(key, ...args) return (...args) => createElement(key, ...args)

@ -15,7 +15,7 @@
// Import magic numbers and data // Import magic numbers and data
import { import {
dom, COLUMN, COLUMN_LITERAL, COMPARISON, ATTRIBUTES, dom, COMPARISON, ATTRIBUTES,
columnAscendingByDefault, columnIsSortable, COLUMN_TRANSFORMATION, columnAscendingByDefault, columnIsSortable, COLUMN_TRANSFORMATION,
element, JOIN_URL_PASTE, communityQRCodeURL, STAFF_ID_PASTE, IDENTIFIER_PASTE, DETAILS_LINK_PASTE, CLASSES, flagToLanguageAscii, RoomInfo, unreachable, workOnMainThread, onInteractive element, JOIN_URL_PASTE, communityQRCodeURL, STAFF_ID_PASTE, IDENTIFIER_PASTE, DETAILS_LINK_PASTE, CLASSES, flagToLanguageAscii, RoomInfo, unreachable, workOnMainThread, onInteractive
} from './js/util.js'; } from './js/util.js';
@ -64,7 +64,6 @@ let shownCommunityId = "";
/** /**
* Create an interactive version of the Community join link. * Create an interactive version of the Community join link.
* @param {string} join_link
* @returns {HTMLElement} * @returns {HTMLElement}
*/ */
const transformJoinURL = () => { const transformJoinURL = () => {
@ -153,6 +152,19 @@ function addInformativeInteractions() {
}); });
} }
function enableEnterClicks() {
Array.from(document.querySelectorAll('.enter-clicks')).forEach(element => {
if (!(element instanceof HTMLElement)) return;
element.addEventListener('keydown', (/** @type {KeyboardEvent} */ ev) => {
if (ev.key == "Enter") {
if (!(ev.currentTarget instanceof HTMLElement)) {
console.error(".enter-clicks could not find its currentTarget");
} else ev.currentTarget.click();
}
})
})
}
async function fetchTableRestFragment() { async function fetchTableRestFragment() {
if (location.pathname != "/") return; if (location.pathname != "/") return;
const request = await fetch("/_fragment/rest/"); const request = await fetch("/_fragment/rest/");
@ -182,14 +194,7 @@ async function onLoad() {
preloadImages(); preloadImages();
}, 60 * 60E3); }, 60 * 60E3);
addInformativeInteractions(); addInformativeInteractions();
Array.from(document.querySelectorAll('.enter-clicks')).forEach(element => { enableEnterClicks();
// @ts-ignore
element.addEventListener('keydown', (/** @type {KeyboardEvent} */ ev) => {
if (ev.key == "Enter") {
ev.currentTarget.click();
}
})
})
await RoomInfo.fetchRooms(); await RoomInfo.fetchRooms();
reactToURLParameters(); reactToURLParameters();
addServerIconInteractions(); addServerIconInteractions();
@ -200,7 +205,7 @@ async function onLoad() {
* Construct room tag DOM from its description. * Construct room tag DOM from its description.
* @param {Object} param0 * @param {Object} param0
* @param {string} param0.text Tag name * @param {string} param0.text Tag name
* @param {"user"|"reserved"} param0.type Tag classification * @param {string} param0.type Tag classification
* @param {string} param0.description Tag details * @param {string} param0.description Tag details
* @returns HTMLElement * @returns HTMLElement
*/ */
@ -253,15 +258,22 @@ function displayQRModal(communityID, pane = 0) {
const tagContainer = dom.details_modal_tag_container(); const tagContainer = dom.details_modal_tag_container();
tagContainer.innerHTML = ""; if (tagContainer) {
tagContainer.append( tagContainer.innerHTML = "";
...rowInfo.tags.map(tag => tagBody(tag))
);
dom.details_modal_qr_code().src = communityQRCodeURL(communityID); tagContainer.append(
...rowInfo.tags.map(tag => tagBody(tag))
);
} else console.error(`Could not find tag container for ${communityID}`);
document.getElementById('details-modal-panes').setAttribute('data-pane', pane); const qrCode = dom.details_modal_qr_code();
if (qrCode instanceof HTMLImageElement) {
qrCode.src = communityQRCodeURL(communityID);
} else console.error(`Could not find QR code <img>`);
document.getElementById('details-modal-panes')?.setAttribute('data-pane', `${pane}`);
location.hash=`#${communityID}`; location.hash=`#${communityID}`;
@ -272,7 +284,8 @@ function displayQRModal(communityID, pane = 0) {
* Hides the Community details modal. * Hides the Community details modal.
*/ */
function hideQRModal() { function hideQRModal() {
dom.details_modal().close(); const detailsModal = dom.details_modal();
if (detailsModal) detailsModal.close(); else console.error("hideQRModal(): detailsModal is null")
shownCommunityId = ""; shownCommunityId = "";
} }
@ -301,7 +314,7 @@ function addQRModalHandlers() {
displayQRModal(communityID); displayQRModal(communityID);
} }
) )
row.querySelector('.td_name').addEventListener( row.querySelector('.td_name')?.addEventListener(
'click', 'click',
(e) => { (e) => {
e.preventDefault(); e.preventDefault();
@ -311,17 +324,20 @@ function addQRModalHandlers() {
} }
const closeButton = const detailsModal = dom.details_modal();
dom.details_modal().querySelector('#details-modal-close');
closeButton.addEventListener( if (detailsModal) {
'click', const closeButton = detailsModal.querySelector('#details-modal-close');
() => hideQRModal() closeButton?.addEventListener(
); 'click',
dom.details_modal().addEventListener('click', function (e) { () => hideQRModal()
if (this == e.target) { );
this.close(); detailsModal.addEventListener('click', function (e) {
} if (this == e.target) {
}); this.close();
}
});
} else console.error("Could not find details modal");
for (const button of document.querySelectorAll('.details-modal-pane-button')) { for (const button of document.querySelectorAll('.details-modal-pane-button')) {
button.addEventListener( button.addEventListener(
@ -333,7 +349,7 @@ function addQRModalHandlers() {
) )
} }
document.querySelector('#details-modal-copy-button').addEventListener( document.querySelector('#details-modal-copy-button')?.addEventListener(
'click', 'click',
function () { function () {
copyToClipboard(this.getAttribute('data-href')); copyToClipboard(this.getAttribute('data-href'));
@ -391,7 +407,8 @@ function addQRModalHandlers() {
const increment = isLeftArrowKey ? -1 : 1; const increment = isLeftArrowKey ? -1 : 1;
const newRowIndex = (shownRowIndex + increment + communityRows.length) % communityRows.length; const newRowIndex = (shownRowIndex + increment + communityRows.length) % communityRows.length;
const newRowIdentifier = communityRows[newRowIndex].identifier; const newRowIdentifier = communityRows[newRowIndex].identifier;
displayQRModal(newRowIdentifier); if (newRowIdentifier === null) console.error("newRowIdentifier is null");
else displayQRModal(newRowIdentifier);
}) })
} }
@ -637,6 +654,7 @@ function compareAscending(fst, snd) {
// Triple equals to avoid "" == 0. // Triple equals to avoid "" == 0.
if (fst === "") return COMPARISON.GREATER; if (fst === "") return COMPARISON.GREATER;
if (snd === "") return COMPARISON.SMALLER; if (snd === "") return COMPARISON.SMALLER;
// @ts-ignore
return (fst > snd) - (fst < snd); return (fst > snd) - (fst < snd);
} }
@ -699,8 +717,16 @@ function getSortState(table) {
const directionState = table.getAttribute(ATTRIBUTES.SORTING.ASCENDING); const directionState = table.getAttribute(ATTRIBUTES.SORTING.ASCENDING);
// This is not pretty, but the least annoying. // This is not pretty, but the least annoying.
// Checking for classes would be more idiomatic. // Checking for classes would be more idiomatic.
if (directionState === null) {
console.error("directionState was null");
return null;
}
const ascending = directionState.toString() === "true"; const ascending = directionState.toString() === "true";
const columnState = table.getAttribute(ATTRIBUTES.SORTING.COLUMN); const columnState = table.getAttribute(ATTRIBUTES.SORTING.COLUMN);
if (columnState === null) {
console.error("columnState was null");
return null;
}
const column = parseInt(columnState); const column = parseInt(columnState);
if (!Number.isInteger(column)) { if (!Number.isInteger(column)) {
throw new Error(`Invalid column number read from table: ${columnState}`) throw new Error(`Invalid column number read from table: ${columnState}`)
@ -715,22 +741,23 @@ function getSortState(table) {
*/ */
function setSortState(table, { ascending, column }) { function setSortState(table, { ascending, column }) {
if (!table.hasAttribute(ATTRIBUTES.SORTING.ACTIVE)) { if (!table.hasAttribute(ATTRIBUTES.SORTING.ACTIVE)) {
table.setAttribute(ATTRIBUTES.SORTING.ACTIVE, true); table.setAttribute(ATTRIBUTES.SORTING.ACTIVE, `${true}`);
} }
table.setAttribute(ATTRIBUTES.SORTING.ASCENDING, ascending); table.setAttribute(ATTRIBUTES.SORTING.ASCENDING, `${ascending}`);
table.setAttribute(ATTRIBUTES.SORTING.COLUMN, column); table.setAttribute(ATTRIBUTES.SORTING.COLUMN, `${column}`);
// No way around this for brief CSS. // No way around this for brief CSS.
const headers = table.querySelectorAll("th"); const headers = table.querySelectorAll("th");
headers.forEach((th, colno) => { headers.forEach((th, colno) => {
th.removeAttribute(ATTRIBUTES.SORTING.ACTIVE); th.removeAttribute(ATTRIBUTES.SORTING.ACTIVE);
}); });
headers[column].setAttribute(ATTRIBUTES.SORTING.ACTIVE, true); headers[column].setAttribute(ATTRIBUTES.SORTING.ACTIVE, `${true}`);
} }
// This is best done in JS, as it would require <noscript> styles otherwise. // This is best done in JS, as it would require <noscript> styles otherwise.
function markSortableColumns() { function markSortableColumns() {
const table = dom.tbl_communities(); const table = dom.tbl_communities();
if (!table) throw new Error("markSortableColumns(): could not find table");
const header_cells = table.querySelectorAll('th'); const header_cells = table.querySelectorAll('th');
for (let colno = 0; colno < header_cells.length; colno++) { for (let colno = 0; colno < header_cells.length; colno++) {
if (!columnIsSortable(colno)) continue; if (!columnIsSortable(colno)) continue;

Loading…
Cancel
Save