-
Verify email
-
+
+
+ Verify email
+
+
- {'Please check your email '}
+ {"Please check your email "}
{`(${email})`}
- {' and validate before continuing further.'}
+ {" and validate before continuing further."}
-
+
);
@@ -671,11 +958,7 @@ EmailVerify.propTypes = {
};
function ProcessWrapper({ children }) {
- return (
-
- {children}
-
- );
+ return
{children}
;
}
ProcessWrapper.propTypes = {
children: PropTypes.node.isRequired,
diff --git a/src/app/templates/auth/Auth.scss b/src/app/templates/auth/Auth.scss
index 956a2700..ae785d5a 100644
--- a/src/app/templates/auth/Auth.scss
+++ b/src/app/templates/auth/Auth.scss
@@ -1,12 +1,15 @@
-@use '../../partials/flex';
-@use '../../partials/dir';
+@use "../../partials/flex";
+@use "../../partials/dir";
.auth__base {
--pattern-size: 48px;
min-height: 100%;
background-color: var(--bg-surface-low);
- background-image: radial-gradient(rgba(0, 0, 0, 6%) 2px, rgba(0, 0, 0, 0%) 2px);
+ background-image: radial-gradient(
+ rgba(0, 0, 0, 6%) 2px,
+ rgba(0, 0, 0, 0%) 2px
+ );
background-size: var(--pattern-size) var(--pattern-size);
display: flex;
@@ -31,7 +34,9 @@
}
& a {
color: var(--tc-surface-normal);
- &:hover { text-decoration: underline; }
+ &:hover {
+ text-decoration: underline;
+ }
}
}
.auth-card {
@@ -42,7 +47,8 @@
overflow: hidden;
&__content {
- padding: var(--sp-extra-loose) calc(var(--sp-normal) + var(--sp-extra-loose));
+ padding: var(--sp-extra-loose)
+ calc(var(--sp-normal) + var(--sp-extra-loose));
}
&__switch {
margin-top: var(--sp-loose) !important;
@@ -65,19 +71,21 @@
& .input {
background-color: var(--bg-surface);
@include dir.prop(border-right-width, 0, 1px);
- @include dir.prop(border-left-width, 1px, 0 );
- @include dir.prop(border-radius,
+ @include dir.prop(border-left-width, 1px, 0);
+ @include dir.prop(
+ border-radius,
var(--bo-radius) 0 0 var(--bo-radius),
- 0 var(--bo-radius) var(--bo-radius) 0,
+ 0 var(--bo-radius) var(--bo-radius) 0
);
}
}
& .ic-btn {
height: 46px;
border: 1px solid var(--bg-surface-border);
- @include dir.prop(border-radius,
+ @include dir.prop(
+ border-radius,
0 var(--bo-radius) var(--bo-radius) 0,
- var(--bo-radius) 0 0 var(--bo-radius),
+ var(--bo-radius) 0 0 var(--bo-radius)
);
}
@@ -101,7 +109,7 @@
&__pass-eye-wrapper {
margin: var(--sp-tight) 0 var(--sp-ultra-tight);
}
-
+
&__heading {
display: flex;
justify-content: space-between;
@@ -113,7 +121,7 @@
& .ic-btn {
position: absolute;
@include dir.prop(right, 6px, unset);
- @include dir.prop(left, unset, 6px );
+ @include dir.prop(left, unset, 6px);
bottom: 6px;
border-radius: 4px;
}
@@ -141,7 +149,7 @@
&::before,
&::after {
flex: 1;
- content: '';
+ content: "";
margin: var(--sp-tight);
border-bottom: 1px solid var(--bg-surface-border);
}
@@ -164,10 +172,10 @@
min-height: 100%;
width: 100%;
background-color: var(--bg-surface-low);
- opacity: .96;
+ opacity: 0.96;
position: fixed;
top: 0;
left: 0;
z-index: 999;
-}
\ No newline at end of file
+}
diff --git a/src/app/templates/client/Client.jsx b/src/app/templates/client/Client.jsx
index d83845b8..b6241b0a 100644
--- a/src/app/templates/client/Client.jsx
+++ b/src/app/templates/client/Client.jsx
@@ -1,32 +1,32 @@
-import React, { useState, useEffect, useRef } from 'react';
-import './Client.scss';
+import React, { useState, useEffect, useRef } from "react";
+import "./Client.scss";
-import { initHotkeys } from '../../../client/event/hotkeys';
-import { initRoomListListener } from '../../../client/event/roomList';
+import { initHotkeys } from "../../../client/event/hotkeys";
+import { initRoomListListener } from "../../../client/event/roomList";
-import Text from '../../atoms/text/Text';
-import Spinner from '../../atoms/spinner/Spinner';
-import Navigation from '../../organisms/navigation/Navigation';
-import ContextMenu, { MenuItem } from '../../atoms/context-menu/ContextMenu';
-import IconButton from '../../atoms/button/IconButton';
-import ReusableContextMenu from '../../atoms/context-menu/ReusableContextMenu';
-import Room from '../../organisms/room/Room';
-import Windows from '../../organisms/pw/Windows';
-import Dialogs from '../../organisms/pw/Dialogs';
-import EmojiBoardOpener from '../../organisms/emoji-board/EmojiBoardOpener';
+import Text from "../../atoms/text/Text";
+import Spinner from "../../atoms/spinner/Spinner";
+import Navigation from "../../organisms/navigation/Navigation";
+import ContextMenu, { MenuItem } from "../../atoms/context-menu/ContextMenu";
+import IconButton from "../../atoms/button/IconButton";
+import ReusableContextMenu from "../../atoms/context-menu/ReusableContextMenu";
+import Room from "../../organisms/room/Room";
+import Windows from "../../organisms/pw/Windows";
+import Dialogs from "../../organisms/pw/Dialogs";
+import EmojiBoardOpener from "../../organisms/emoji-board/EmojiBoardOpener";
-import initMatrix from '../../../client/initMatrix';
-import navigation from '../../../client/state/navigation';
-import cons from '../../../client/state/cons';
-import DragDrop from '../../organisms/drag-drop/DragDrop';
+import initMatrix from "../../../client/initMatrix";
+import navigation from "../../../client/state/navigation";
+import cons from "../../../client/state/cons";
+import DragDrop from "../../organisms/drag-drop/DragDrop";
-import VerticalMenuIC from '../../../../public/res/ic/outlined/vertical-menu.svg';
+import VerticalMenuIC from "../../../../public/res/ic/outlined/vertical-menu.svg";
function Client() {
const [isLoading, changeLoading] = useState(true);
- const [loadingMsg, setLoadingMsg] = useState('Heating up');
+ const [loadingMsg, setLoadingMsg] = useState("Heating up");
const [dragCounter, setDragCounter] = useState(0);
- const classNameHidden = 'client__item-hidden';
+ const classNameHidden = "client__item-hidden";
const navWrapperRef = useRef(null);
const roomWrapperRef = useRef(null);
@@ -42,20 +42,29 @@ function Client() {
useEffect(() => {
navigation.on(cons.events.navigation.ROOM_SELECTED, onRoomSelected);
- navigation.on(cons.events.navigation.NAVIGATION_OPENED, onNavigationSelected);
+ navigation.on(
+ cons.events.navigation.NAVIGATION_OPENED,
+ onNavigationSelected
+ );
- return (() => {
- navigation.removeListener(cons.events.navigation.ROOM_SELECTED, onRoomSelected);
- navigation.removeListener(cons.events.navigation.NAVIGATION_OPENED, onNavigationSelected);
- });
+ return () => {
+ navigation.removeListener(
+ cons.events.navigation.ROOM_SELECTED,
+ onRoomSelected
+ );
+ navigation.removeListener(
+ cons.events.navigation.NAVIGATION_OPENED,
+ onNavigationSelected
+ );
+ };
}, []);
useEffect(() => {
let counter = 0;
const iId = setInterval(() => {
const msgList = [
- 'Almost there...',
- 'Looks like you have a lot of stuff to heat up!',
+ "Almost there...",
+ "Looks like you have a lot of stuff to heat up!",
];
if (counter === msgList.length - 1) {
setLoadingMsg(msgList[msgList.length - 1]);
@@ -65,7 +74,7 @@ function Client() {
setLoadingMsg(msgList[counter]);
counter += 1;
}, 15000);
- initMatrix.once('init_loading_finished', () => {
+ initMatrix.once("init_loading_finished", () => {
clearInterval(iId);
initHotkeys();
initRoomListListener(initMatrix.roomList);
@@ -80,22 +89,32 @@ function Client() {
>
+ }
+ render={(toggle) => (
+
)}
- render={(toggle) => }
/>
-
{loadingMsg}
+
+ {loadingMsg}
+
- Cinny
+
+ Cinny
+
);
@@ -105,7 +124,7 @@ function Client() {
if (!e.dataTransfer.types) return false;
for (let i = 0; i < e.dataTransfer.types.length; i += 1) {
- if (e.dataTransfer.types[i] === 'Files') return true;
+ if (e.dataTransfer.types[i] === "Files") return true;
}
return false;
}
@@ -120,7 +139,7 @@ function Client() {
e.preventDefault();
if (!navigation.selectedRoomId || modalOpen()) {
- e.dataTransfer.dropEffect = 'none';
+ e.dataTransfer.dropEffect = "none";
}
}
diff --git a/src/app/templates/client/Client.scss b/src/app/templates/client/Client.scss
index cdb8fcc9..1f249e75 100644
--- a/src/app/templates/client/Client.scss
+++ b/src/app/templates/client/Client.scss
@@ -1,4 +1,4 @@
-@use '../../partials/screen';
+@use "../../partials/screen";
.client-container {
display: flex;
@@ -7,7 +7,7 @@
.navigation__wrapper {
width: var(--navigation-width);
-
+
@include screen.smallerThan(mobileBreakpoint) {
width: 100%;
}
diff --git a/src/client/action/accountData.js b/src/client/action/accountData.js
index 1fb49fbf..135727b3 100644
--- a/src/client/action/accountData.js
+++ b/src/client/action/accountData.js
@@ -1,5 +1,5 @@
-import appDispatcher from '../dispatcher';
-import cons from '../state/cons';
+import appDispatcher from "../dispatcher";
+import cons from "../state/cons";
/**
* @param {string | string[]} roomId - room id or array of them to add into shortcuts
diff --git a/src/client/action/auth.js b/src/client/action/auth.js
index f9be13bc..c8bd25a9 100644
--- a/src/client/action/auth.js
+++ b/src/client/action/auth.js
@@ -1,5 +1,5 @@
-import * as sdk from 'matrix-js-sdk';
-import cons from '../state/cons';
+import * as sdk from "matrix-js-sdk";
+import cons from "../state/cons";
function updateLocalStore(accessToken, deviceId, userId, baseUrl) {
localStorage.setItem(cons.secretKey.ACCESS_TOKEN, accessToken);
@@ -15,62 +15,78 @@ function createTemporaryClient(baseUrl) {
async function startSsoLogin(baseUrl, type, idpId) {
const client = createTemporaryClient(baseUrl);
localStorage.setItem(cons.secretKey.BASE_URL, client.baseUrl);
- window.location.href = client.getSsoLoginUrl(window.location.href, type, idpId);
+ window.location.href = client.getSsoLoginUrl(
+ window.location.href,
+ type,
+ idpId
+ );
}
async function login(baseUrl, username, email, password) {
const identifier = {};
if (username) {
- identifier.type = 'm.id.user';
+ identifier.type = "m.id.user";
identifier.user = username;
} else if (email) {
- identifier.type = 'm.id.thirdparty';
- identifier.medium = 'email';
+ identifier.type = "m.id.thirdparty";
+ identifier.medium = "email";
identifier.address = email;
- } else throw new Error('Bad Input');
+ } else throw new Error("Bad Input");
const client = createTemporaryClient(baseUrl);
- const res = await client.login('m.login.password', {
+ const res = await client.login("m.login.password", {
identifier,
password,
initial_device_display_name: cons.DEVICE_DISPLAY_NAME,
});
- const myBaseUrl = res?.well_known?.['m.homeserver']?.base_url || client.baseUrl;
+ const myBaseUrl =
+ res?.well_known?.["m.homeserver"]?.base_url || client.baseUrl;
updateLocalStore(res.access_token, res.device_id, res.user_id, myBaseUrl);
}
async function loginWithToken(baseUrl, token) {
const client = createTemporaryClient(baseUrl);
- const res = await client.login('m.login.token', {
+ const res = await client.login("m.login.token", {
token,
initial_device_display_name: cons.DEVICE_DISPLAY_NAME,
});
- const myBaseUrl = res?.well_known?.['m.homeserver']?.base_url || client.baseUrl;
+ const myBaseUrl =
+ res?.well_known?.["m.homeserver"]?.base_url || client.baseUrl;
updateLocalStore(res.access_token, res.device_id, res.user_id, myBaseUrl);
}
// eslint-disable-next-line camelcase
-async function verifyEmail(baseUrl, email, client_secret, send_attempt, next_link) {
- const res = await fetch(`${baseUrl}/_matrix/client/r0/register/email/requestToken`, {
- method: 'POST',
- body: JSON.stringify({
- email, client_secret, send_attempt, next_link,
- }),
- headers: {
- 'Content-Type': 'application/json; charset=utf-8',
- },
- credentials: 'same-origin',
- });
+async function verifyEmail(
+ baseUrl,
+ email,
+ client_secret,
+ send_attempt,
+ next_link
+) {
+ const res = await fetch(
+ `${baseUrl}/_matrix/client/r0/register/email/requestToken`,
+ {
+ method: "POST",
+ body: JSON.stringify({
+ email,
+ client_secret,
+ send_attempt,
+ next_link,
+ }),
+ headers: {
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ credentials: "same-origin",
+ }
+ );
const data = await res.json();
return data;
}
-async function completeRegisterStage(
- baseUrl, username, password, auth,
-) {
+async function completeRegisterStage(baseUrl, username, password, auth) {
const tempClient = createTemporaryClient(baseUrl);
try {
@@ -83,7 +99,12 @@ async function completeRegisterStage(
const data = { completed: result.completed || [] };
if (result.access_token) {
data.done = true;
- updateLocalStore(result.access_token, result.device_id, result.user_id, baseUrl);
+ updateLocalStore(
+ result.access_token,
+ result.device_id,
+ result.user_id,
+ baseUrl
+ );
}
return data;
} catch (e) {
@@ -91,14 +112,22 @@ async function completeRegisterStage(
const data = { completed: result.completed || [] };
if (result.access_token) {
data.done = true;
- updateLocalStore(result.access_token, result.device_id, result.user_id, baseUrl);
+ updateLocalStore(
+ result.access_token,
+ result.device_id,
+ result.user_id,
+ baseUrl
+ );
}
return data;
}
}
export {
- createTemporaryClient, login, verifyEmail,
- loginWithToken, startSsoLogin,
+ createTemporaryClient,
+ login,
+ verifyEmail,
+ loginWithToken,
+ startSsoLogin,
completeRegisterStage,
};
diff --git a/src/client/action/navigation.js b/src/client/action/navigation.js
index 4ee78a63..a6d0d6ad 100644
--- a/src/client/action/navigation.js
+++ b/src/client/action/navigation.js
@@ -1,5 +1,5 @@
-import appDispatcher from '../dispatcher';
-import cons from '../state/cons';
+import appDispatcher from "../dispatcher";
+import cons from "../state/cons";
export function selectTab(tabId) {
appDispatcher.dispatch({
diff --git a/src/client/action/notifications.js b/src/client/action/notifications.js
index a869632a..4561be01 100644
--- a/src/client/action/notifications.js
+++ b/src/client/action/notifications.js
@@ -1,4 +1,4 @@
-import initMatrix from '../initMatrix';
+import initMatrix from "../initMatrix";
// eslint-disable-next-line import/prefer-default-export
export async function markAsRead(roomId) {
diff --git a/src/client/action/room.js b/src/client/action/room.js
index 996c2680..7cb449e7 100644
--- a/src/client/action/room.js
+++ b/src/client/action/room.js
@@ -1,7 +1,7 @@
-import initMatrix from '../initMatrix';
-import appDispatcher from '../dispatcher';
-import cons from '../state/cons';
-import { getIdServer } from '../../util/matrixUtil';
+import initMatrix from "../initMatrix";
+import appDispatcher from "../dispatcher";
+import cons from "../state/cons";
+import { getIdServer } from "../../util/matrixUtil";
/**
* https://github.com/matrix-org/matrix-react-sdk/blob/1e6c6e9d800890c732d60429449bc280de01a647/src/Rooms.js#L73
@@ -11,10 +11,11 @@ import { getIdServer } from '../../util/matrixUtil';
*/
function addRoomToMDirect(roomId, userId) {
const mx = initMatrix.matrixClient;
- const mDirectsEvent = mx.getAccountData('m.direct');
+ const mDirectsEvent = mx.getAccountData("m.direct");
let userIdToRoomIds = {};
- if (typeof mDirectsEvent !== 'undefined') userIdToRoomIds = mDirectsEvent.getContent();
+ if (typeof mDirectsEvent !== "undefined")
+ userIdToRoomIds = mDirectsEvent.getContent();
// remove it from the lists of any others users
// (it can only be a DM room for one person)
@@ -38,7 +39,7 @@ function addRoomToMDirect(roomId, userId) {
userIdToRoomIds[userId] = roomIds;
}
- return mx.setAccountData('m.direct', userIdToRoomIds);
+ return mx.setAccountData("m.direct", userIdToRoomIds);
}
/**
@@ -58,7 +59,10 @@ function guessDMRoomTargetId(room, myUserId) {
room.getJoinedMembers().forEach((member) => {
if (member.userId === myUserId) return;
- if (typeof oldestMemberTs === 'undefined' || (member.events.member && member.events.member.getTs() < oldestMemberTs)) {
+ if (
+ typeof oldestMemberTs === "undefined" ||
+ (member.events.member && member.events.member.getTs() < oldestMemberTs)
+ ) {
oldestMember = member;
oldestMemberTs = member.events.member.getTs();
}
@@ -69,13 +73,16 @@ function guessDMRoomTargetId(room, myUserId) {
room.currentState.getMembers().forEach((member) => {
if (member.userId === myUserId) return;
- if (typeof oldestMemberTs === 'undefined' || (member.events.member && member.events.member.getTs() < oldestMemberTs)) {
+ if (
+ typeof oldestMemberTs === "undefined" ||
+ (member.events.member && member.events.member.getTs() < oldestMemberTs)
+ ) {
oldestMember = member;
oldestMemberTs = member.events.member.getTs();
}
});
- if (typeof oldestMember === 'undefined') return myUserId;
+ if (typeof oldestMember === "undefined") return myUserId;
return oldestMember.userId;
}
@@ -97,14 +104,17 @@ function convertToRoom(roomId) {
*/
async function join(roomIdOrAlias, isDM = false, via = undefined) {
const mx = initMatrix.matrixClient;
- const roomIdParts = roomIdOrAlias.split(':');
+ const roomIdParts = roomIdOrAlias.split(":");
const viaServers = via || [roomIdParts[1]];
try {
const resultRoom = await mx.joinRoom(roomIdOrAlias, { viaServers });
if (isDM) {
- const targetUserId = guessDMRoomTargetId(mx.getRoom(resultRoom.roomId), mx.getUserId());
+ const targetUserId = guessDMRoomTargetId(
+ mx.getRoom(resultRoom.roomId),
+ mx.getUserId()
+ );
await addRoomToMDirect(resultRoom.roomId, targetUserId);
}
appDispatcher.dispatch({
@@ -134,7 +144,7 @@ async function leave(roomId) {
isDM,
});
} catch {
- console.error('Unable to leave room.');
+ console.error("Unable to leave room.");
}
}
@@ -142,7 +152,7 @@ async function create(options, isDM = false) {
const mx = initMatrix.matrixClient;
try {
const result = await mx.createRoom(options);
- if (isDM && typeof options.invite?.[0] === 'string') {
+ if (isDM && typeof options.invite?.[0] === "string") {
await addRoomToMDirect(result.room_id, options.invite[0]);
}
appDispatcher.dispatch({
@@ -152,11 +162,17 @@ async function create(options, isDM = false) {
});
return result;
} catch (e) {
- const errcodes = ['M_UNKNOWN', 'M_BAD_JSON', 'M_ROOM_IN_USE', 'M_INVALID_ROOM_STATE', 'M_UNSUPPORTED_ROOM_VERSION'];
+ const errcodes = [
+ "M_UNKNOWN",
+ "M_BAD_JSON",
+ "M_ROOM_IN_USE",
+ "M_INVALID_ROOM_STATE",
+ "M_UNSUPPORTED_ROOM_VERSION",
+ ];
if (errcodes.includes(e.errcode)) {
throw new Error(e);
}
- throw new Error('Something went wrong!');
+ throw new Error("Something went wrong!");
}
}
@@ -164,16 +180,16 @@ async function createDM(userIdOrIds, isEncrypted = true) {
const options = {
is_direct: true,
invite: Array.isArray(userIdOrIds) ? userIdOrIds : [userIdOrIds],
- visibility: 'private',
- preset: 'trusted_private_chat',
+ visibility: "private",
+ preset: "trusted_private_chat",
initial_state: [],
};
if (isEncrypted) {
options.initial_state.push({
- type: 'm.room.encryption',
- state_key: '',
+ type: "m.room.encryption",
+ state_key: "",
content: {
- algorithm: 'm.megolm.v1.aes-sha2',
+ algorithm: "m.megolm.v1.aes-sha2",
},
});
}
@@ -193,7 +209,7 @@ async function createRoom(opts) {
const blockFederation = opts.blockFederation ?? false;
const mx = initMatrix.matrixClient;
- const visibility = joinRule === 'public' ? 'public' : 'private';
+ const visibility = joinRule === "public" ? "public" : "private";
const options = {
creation_content: undefined,
name,
@@ -204,17 +220,17 @@ async function createRoom(opts) {
power_level_content_override: undefined,
};
if (isSpace) {
- options.creation_content = { type: 'm.space' };
+ options.creation_content = { type: "m.space" };
}
if (blockFederation) {
- options.creation_content = { 'm.federate': false };
+ options.creation_content = { "m.federate": false };
}
if (isEncrypted) {
options.initial_state.push({
- type: 'm.room.encryption',
- state_key: '',
+ type: "m.room.encryption",
+ state_key: "",
content: {
- algorithm: 'm.megolm.v1.aes-sha2',
+ algorithm: "m.megolm.v1.aes-sha2",
},
});
}
@@ -227,7 +243,7 @@ async function createRoom(opts) {
}
if (parentId) {
options.initial_state.push({
- type: 'm.space.parent',
+ type: "m.space.parent",
state_key: parentId,
content: {
canonical: true,
@@ -235,22 +251,24 @@ async function createRoom(opts) {
},
});
}
- if (parentId && joinRule === 'restricted') {
+ if (parentId && joinRule === "restricted") {
const caps = await mx.getCapabilities();
- if (caps['m.room_versions'].available?.['9'] !== 'stable') {
+ if (caps["m.room_versions"].available?.["9"] !== "stable") {
throw new Error("ERROR: The server doesn't support restricted rooms");
}
- if (Number(caps['m.room_versions'].default) < 9) {
- options.room_version = '9';
+ if (Number(caps["m.room_versions"].default) < 9) {
+ options.room_version = "9";
}
options.initial_state.push({
- type: 'm.room.join_rules',
+ type: "m.room.join_rules",
content: {
- join_rule: 'restricted',
- allow: [{
- type: 'm.room_membership',
- room_id: parentId,
- }],
+ join_rule: "restricted",
+ allow: [
+ {
+ type: "m.room_membership",
+ room_id: parentId,
+ },
+ ],
},
});
}
@@ -258,11 +276,16 @@ async function createRoom(opts) {
const result = await create(options);
if (parentId) {
- await mx.sendStateEvent(parentId, 'm.space.child', {
- auto_join: false,
- suggested: false,
- via: [getIdServer(mx.getUserId())],
- }, result.room_id);
+ await mx.sendStateEvent(
+ parentId,
+ "m.space.child",
+ {
+ auto_join: false,
+ suggested: false,
+ via: [getIdServer(mx.getUserId())],
+ },
+ result.room_id
+ );
}
return result;
@@ -315,43 +338,73 @@ async function setPowerLevel(roomId, userId, powerLevel) {
const mx = initMatrix.matrixClient;
const room = mx.getRoom(roomId);
- const powerlevelEvent = room.currentState.getStateEvents('m.room.power_levels')[0];
+ const powerlevelEvent = room.currentState.getStateEvents(
+ "m.room.power_levels"
+ )[0];
- const result = await mx.setPowerLevel(roomId, userId, powerLevel, powerlevelEvent);
+ const result = await mx.setPowerLevel(
+ roomId,
+ userId,
+ powerLevel,
+ powerlevelEvent
+ );
return result;
}
async function setMyRoomNick(roomId, nick) {
const mx = initMatrix.matrixClient;
const room = mx.getRoom(roomId);
- const mEvent = room.currentState.getStateEvents('m.room.member', mx.getUserId());
+ const mEvent = room.currentState.getStateEvents(
+ "m.room.member",
+ mx.getUserId()
+ );
const content = mEvent?.getContent();
if (!content) return;
- await mx.sendStateEvent(roomId, 'm.room.member', {
- ...content,
- displayname: nick,
- }, mx.getUserId());
+ await mx.sendStateEvent(
+ roomId,
+ "m.room.member",
+ {
+ ...content,
+ displayname: nick,
+ },
+ mx.getUserId()
+ );
}
async function setMyRoomAvatar(roomId, mxc) {
const mx = initMatrix.matrixClient;
const room = mx.getRoom(roomId);
- const mEvent = room.currentState.getStateEvents('m.room.member', mx.getUserId());
+ const mEvent = room.currentState.getStateEvents(
+ "m.room.member",
+ mx.getUserId()
+ );
const content = mEvent?.getContent();
if (!content) return;
- await mx.sendStateEvent(roomId, 'm.room.member', {
- ...content,
- avatar_url: mxc,
- }, mx.getUserId());
+ await mx.sendStateEvent(
+ roomId,
+ "m.room.member",
+ {
+ ...content,
+ avatar_url: mxc,
+ },
+ mx.getUserId()
+ );
}
export {
convertToDm,
convertToRoom,
- join, leave,
- createDM, createRoom,
- invite, kick, ban, unban,
- ignore, unignore,
+ join,
+ leave,
+ createDM,
+ createRoom,
+ invite,
+ kick,
+ ban,
+ unban,
+ ignore,
+ unignore,
setPowerLevel,
- setMyRoomNick, setMyRoomAvatar,
+ setMyRoomNick,
+ setMyRoomAvatar,
};
diff --git a/src/client/action/roomTimeline.js b/src/client/action/roomTimeline.js
index 41c62d4f..a8ad450d 100644
--- a/src/client/action/roomTimeline.js
+++ b/src/client/action/roomTimeline.js
@@ -1,10 +1,15 @@
-import initMatrix from '../initMatrix';
+import initMatrix from "../initMatrix";
async function redactEvent(roomId, eventId, reason) {
const mx = initMatrix.matrixClient;
try {
- await mx.redactEvent(roomId, eventId, undefined, typeof reason === 'undefined' ? undefined : { reason });
+ await mx.redactEvent(
+ roomId,
+ eventId,
+ undefined,
+ typeof reason === "undefined" ? undefined : { reason }
+ );
return true;
} catch (e) {
throw new Error(e);
@@ -14,21 +19,18 @@ async function redactEvent(roomId, eventId, reason) {
async function sendReaction(roomId, toEventId, reaction, shortcode) {
const mx = initMatrix.matrixClient;
const content = {
- 'm.relates_to': {
+ "m.relates_to": {
event_id: toEventId,
key: reaction,
- rel_type: 'm.annotation',
+ rel_type: "m.annotation",
},
};
- if (typeof shortcode === 'string') content.shortcode = shortcode;
+ if (typeof shortcode === "string") content.shortcode = shortcode;
try {
- await mx.sendEvent(roomId, 'm.reaction', content);
+ await mx.sendEvent(roomId, "m.reaction", content);
} catch (e) {
throw new Error(e);
}
}
-export {
- redactEvent,
- sendReaction,
-};
+export { redactEvent, sendReaction };
diff --git a/src/client/action/settings.js b/src/client/action/settings.js
index 7b539c8d..0b2a1ce9 100644
--- a/src/client/action/settings.js
+++ b/src/client/action/settings.js
@@ -1,5 +1,5 @@
-import appDispatcher from '../dispatcher';
-import cons from '../state/cons';
+import appDispatcher from "../dispatcher";
+import cons from "../state/cons";
export function toggleSystemTheme() {
appDispatcher.dispatch({
diff --git a/src/client/dispatcher.js b/src/client/dispatcher.js
index 12a48721..9f6c70c3 100644
--- a/src/client/dispatcher.js
+++ b/src/client/dispatcher.js
@@ -1,4 +1,4 @@
-import { Dispatcher } from 'flux';
+import { Dispatcher } from "flux";
const appDispatcher = new Dispatcher();
export default appDispatcher;
diff --git a/src/client/event/hotkeys.js b/src/client/event/hotkeys.js
index e59ce3d7..e3ae8cb6 100644
--- a/src/client/event/hotkeys.js
+++ b/src/client/event/hotkeys.js
@@ -1,6 +1,6 @@
-import { openSearch, toggleRoomSettings } from '../action/navigation';
-import navigation from '../state/navigation';
-import { markAsRead } from '../action/notifications';
+import { openSearch, toggleRoomSettings } from "../action/navigation";
+import navigation from "../state/navigation";
+import { markAsRead } from "../action/notifications";
function shouldFocusMessageField(code) {
// do not focus on F keys
@@ -8,18 +8,18 @@ function shouldFocusMessageField(code) {
// do not focus on numlock/scroll lock
if (
- code.metaKey
- || code.startsWith('OS')
- || code.startsWith('Meta')
- || code.startsWith('Shift')
- || code.startsWith('Alt')
- || code.startsWith('Control')
- || code.startsWith('Arrow')
- || code === 'Tab'
- || code === 'Space'
- || code === 'Enter'
- || code === 'NumLock'
- || code === 'ScrollLock'
+ code.metaKey ||
+ code.startsWith("OS") ||
+ code.startsWith("Meta") ||
+ code.startsWith("Shift") ||
+ code.startsWith("Alt") ||
+ code.startsWith("Control") ||
+ code.startsWith("Arrow") ||
+ code === "Tab" ||
+ code === "Space" ||
+ code === "Enter" ||
+ code === "NumLock" ||
+ code === "ScrollLock"
) {
return false;
}
@@ -31,20 +31,22 @@ function listenKeyboard(event) {
// Ctrl/Cmd +
if (event.ctrlKey || event.metaKey) {
// open search modal
- if (event.key === 'k') {
+ if (event.key === "k") {
event.preventDefault();
if (navigation.isRawModalVisible) return;
openSearch();
}
// focus message field on paste
- if (event.key === 'v') {
+ if (event.key === "v") {
if (navigation.isRawModalVisible) return;
- const msgTextarea = document.getElementById('message-textarea');
+ const msgTextarea = document.getElementById("message-textarea");
const { activeElement } = document;
- if (activeElement !== msgTextarea
- && ['input', 'textarea'].includes(activeElement.tagName.toLowerCase())
- ) return;
+ if (
+ activeElement !== msgTextarea &&
+ ["input", "textarea"].includes(activeElement.tagName.toLowerCase())
+ )
+ return;
msgTextarea?.focus();
}
}
@@ -52,7 +54,7 @@ function listenKeyboard(event) {
if (!event.ctrlKey && !event.altKey && !event.metaKey) {
if (navigation.isRawModalVisible) return;
- if (event.key === 'Escape') {
+ if (event.key === "Escape") {
if (navigation.isRoomSettings) {
toggleRoomSettings();
return;
@@ -63,25 +65,29 @@ function listenKeyboard(event) {
}
}
- if (['input', 'textarea'].includes(document.activeElement.tagName.toLowerCase())) {
+ if (
+ ["input", "textarea"].includes(
+ document.activeElement.tagName.toLowerCase()
+ )
+ ) {
return;
}
// focus the text field on most keypresses
if (shouldFocusMessageField(event.code)) {
// press any key to focus and type in message field
- const msgTextarea = document.getElementById('message-textarea');
+ const msgTextarea = document.getElementById("message-textarea");
msgTextarea?.focus();
}
}
}
function initHotkeys() {
- document.body.addEventListener('keydown', listenKeyboard);
+ document.body.addEventListener("keydown", listenKeyboard);
}
function removeHotkeys() {
- document.body.removeEventListener('keydown', listenKeyboard);
+ document.body.removeEventListener("keydown", listenKeyboard);
}
export { initHotkeys, removeHotkeys };
diff --git a/src/client/event/roomList.js b/src/client/event/roomList.js
index 6592d67f..5cbfa2d8 100644
--- a/src/client/event/roomList.js
+++ b/src/client/event/roomList.js
@@ -1,6 +1,6 @@
-import cons from '../state/cons';
-import navigation from '../state/navigation';
-import { selectTab, selectSpace, selectRoom } from '../action/navigation';
+import cons from "../state/cons";
+import navigation from "../state/navigation";
+import { selectTab, selectSpace, selectRoom } from "../action/navigation";
function initRoomListListener(roomList) {
const listenRoomLeave = (roomId) => {
diff --git a/src/client/initMatrix.js b/src/client/initMatrix.js
index 420f3154..6efcb620 100644
--- a/src/client/initMatrix.js
+++ b/src/client/initMatrix.js
@@ -1,15 +1,15 @@
-import EventEmitter from 'events';
-import * as sdk from 'matrix-js-sdk';
-import Olm from '@matrix-org/olm';
+import EventEmitter from "events";
+import * as sdk from "matrix-js-sdk";
+import Olm from "@matrix-org/olm";
// import { logger } from 'matrix-js-sdk/lib/logger';
-import { secret } from './state/auth';
-import RoomList from './state/RoomList';
-import AccountData from './state/AccountData';
-import RoomsInput from './state/RoomsInput';
-import Notifications from './state/Notifications';
-import { cryptoCallbacks } from './state/secretStorageKeys';
-import navigation from './state/navigation';
+import { secret } from "./state/auth";
+import RoomList from "./state/RoomList";
+import AccountData from "./state/AccountData";
+import RoomsInput from "./state/RoomsInput";
+import Notifications from "./state/Notifications";
+import { cryptoCallbacks } from "./state/secretStorageKeys";
+import navigation from "./state/navigation";
global.Olm = Olm;
@@ -32,7 +32,7 @@ class InitMatrix extends EventEmitter {
const indexedDBStore = new sdk.IndexedDBStore({
indexedDB: global.indexedDB,
localStorage: global.localStorage,
- dbName: 'web-sync-store',
+ dbName: "web-sync-store",
});
await indexedDBStore.startup();
@@ -41,13 +41,14 @@ class InitMatrix extends EventEmitter {
accessToken: secret.accessToken,
userId: secret.userId,
store: indexedDBStore,
- cryptoStore: new sdk.IndexedDBCryptoStore(global.indexedDB, 'crypto-store'),
+ cryptoStore: new sdk.IndexedDBCryptoStore(
+ global.indexedDB,
+ "crypto-store"
+ ),
deviceId: secret.deviceId,
timelineSupport: true,
cryptoCallbacks,
- verificationMethods: [
- 'm.sas.v1',
- ],
+ verificationMethods: ["m.sas.v1"],
});
await this.matrixClient.initCrypto();
@@ -61,14 +62,14 @@ class InitMatrix extends EventEmitter {
setupSync() {
const sync = {
NULL: () => {
- console.log('NULL state');
+ console.log("NULL state");
},
SYNCING: () => {
- console.log('SYNCING state');
+ console.log("SYNCING state");
},
PREPARED: (prevState) => {
- console.log('PREPARED state');
- console.log('Previous state: ', prevState);
+ console.log("PREPARED state");
+ console.log("Previous state: ", prevState);
// TODO: remove global.initMatrix at end
global.initMatrix = this;
if (prevState === null) {
@@ -76,30 +77,30 @@ class InitMatrix extends EventEmitter {
this.accountData = new AccountData(this.roomList);
this.roomsInput = new RoomsInput(this.matrixClient, this.roomList);
this.notifications = new Notifications(this.roomList);
- this.emit('init_loading_finished');
+ this.emit("init_loading_finished");
this.notifications._initNoti();
} else {
this.notifications?._initNoti();
}
},
RECONNECTING: () => {
- console.log('RECONNECTING state');
+ console.log("RECONNECTING state");
},
CATCHUP: () => {
- console.log('CATCHUP state');
+ console.log("CATCHUP state");
},
ERROR: () => {
- console.log('ERROR state');
+ console.log("ERROR state");
},
STOPPED: () => {
- console.log('STOPPED state');
+ console.log("STOPPED state");
},
};
- this.matrixClient.on('sync', (state, prevState) => sync[state](prevState));
+ this.matrixClient.on("sync", (state, prevState) => sync[state](prevState));
}
listenEvents() {
- this.matrixClient.on('Session.logged_out', async () => {
+ this.matrixClient.on("Session.logged_out", async () => {
this.matrixClient.stopClient();
await this.matrixClient.clearStores();
window.localStorage.clear();
diff --git a/src/client/state/AccountData.js b/src/client/state/AccountData.js
index 6fc811a3..b5b1a652 100644
--- a/src/client/state/AccountData.js
+++ b/src/client/state/AccountData.js
@@ -1,6 +1,6 @@
-import EventEmitter from 'events';
-import appDispatcher from '../dispatcher';
-import cons from './cons';
+import EventEmitter from "events";
+import appDispatcher from "../dispatcher";
+import cons from "./cons";
class AccountData extends EventEmitter {
constructor(roomList) {
@@ -22,7 +22,9 @@ class AccountData extends EventEmitter {
}
_getAccountData() {
- return this.matrixClient.getAccountData(cons.IN_CINNY_SPACES)?.getContent() || {};
+ return (
+ this.matrixClient.getAccountData(cons.IN_CINNY_SPACES)?.getContent() || {}
+ );
}
_populateSpaceShortcut() {
@@ -81,13 +83,19 @@ class AccountData extends EventEmitter {
addRoomId(action.roomId);
}
this._updateSpaceShortcutData([...this.spaceShortcut]);
- this.emit(cons.events.accountData.SPACE_SHORTCUT_UPDATED, action.roomId);
+ this.emit(
+ cons.events.accountData.SPACE_SHORTCUT_UPDATED,
+ action.roomId
+ );
},
[cons.actions.accountData.DELETE_SPACE_SHORTCUT]: () => {
if (!this.spaceShortcut.has(action.roomId)) return;
this.spaceShortcut.delete(action.roomId);
this._updateSpaceShortcutData([...this.spaceShortcut]);
- this.emit(cons.events.accountData.SPACE_SHORTCUT_UPDATED, action.roomId);
+ this.emit(
+ cons.events.accountData.SPACE_SHORTCUT_UPDATED,
+ action.roomId
+ );
},
[cons.actions.accountData.MOVE_SPACE_SHORTCUTS]: () => {
const { roomId, toIndex } = action;
@@ -104,20 +112,26 @@ class AccountData extends EventEmitter {
if (this.categorizedSpaces.has(action.roomId)) return;
this.categorizedSpaces.add(action.roomId);
this._updateCategorizedSpacesData([...this.categorizedSpaces]);
- this.emit(cons.events.accountData.CATEGORIZE_SPACE_UPDATED, action.roomId);
+ this.emit(
+ cons.events.accountData.CATEGORIZE_SPACE_UPDATED,
+ action.roomId
+ );
},
[cons.actions.accountData.UNCATEGORIZE_SPACE]: () => {
if (!this.categorizedSpaces.has(action.roomId)) return;
this.categorizedSpaces.delete(action.roomId);
this._updateCategorizedSpacesData([...this.categorizedSpaces]);
- this.emit(cons.events.accountData.CATEGORIZE_SPACE_UPDATED, action.roomId);
+ this.emit(
+ cons.events.accountData.CATEGORIZE_SPACE_UPDATED,
+ action.roomId
+ );
},
};
actions[action.type]?.();
}
_listenEvents() {
- this.matrixClient.on('accountData', (event) => {
+ this.matrixClient.on("accountData", (event) => {
if (event.getType() !== cons.IN_CINNY_SPACES) return;
this._populateSpaceShortcut();
this.emit(cons.events.accountData.SPACE_SHORTCUT_UPDATED);
diff --git a/src/client/state/Notifications.js b/src/client/state/Notifications.js
index db4610a3..e30b95c4 100644
--- a/src/client/state/Notifications.js
+++ b/src/client/state/Notifications.js
@@ -1,37 +1,39 @@
-import EventEmitter from 'events';
-import renderAvatar from '../../app/atoms/avatar/render';
-import { cssColorMXID } from '../../util/colorMXID';
-import { selectRoom } from '../action/navigation';
-import cons from './cons';
-import navigation from './navigation';
-import settings from './settings';
-import { setFavicon } from '../../util/common';
+import EventEmitter from "events";
+import renderAvatar from "../../app/atoms/avatar/render";
+import { cssColorMXID } from "../../util/colorMXID";
+import { selectRoom } from "../action/navigation";
+import cons from "./cons";
+import navigation from "./navigation";
+import settings from "./settings";
+import { setFavicon } from "../../util/common";
-import LogoSVG from '../../../public/res/svg/cinny.svg';
-import LogoUnreadSVG from '../../../public/res/svg/cinny-unread.svg';
-import LogoHighlightSVG from '../../../public/res/svg/cinny-highlight.svg';
-import { html, plain } from '../../util/markdown';
+import LogoSVG from "../../../public/res/svg/cinny.svg";
+import LogoUnreadSVG from "../../../public/res/svg/cinny-unread.svg";
+import LogoHighlightSVG from "../../../public/res/svg/cinny-highlight.svg";
+import { html, plain } from "../../util/markdown";
function isNotifEvent(mEvent) {
const eType = mEvent.getType();
if (!cons.supportEventTypes.includes(eType)) return false;
- if (eType === 'm.room.member') return false;
+ if (eType === "m.room.member") return false;
if (mEvent.isRedacted()) return false;
- if (mEvent.getRelation()?.rel_type === 'm.replace') return false;
+ if (mEvent.getRelation()?.rel_type === "m.replace") return false;
return true;
}
function isMutedRule(rule) {
- return rule.actions[0] === 'dont_notify' && rule.conditions[0].kind === 'event_match';
+ return (
+ rule.actions[0] === "dont_notify" &&
+ rule.conditions[0].kind === "event_match"
+ );
}
function findMutedRule(overrideRules, roomId) {
- return overrideRules.find((rule) => (
- rule.rule_id === roomId
- && isMutedRule(rule)
- ));
+ return overrideRules.find(
+ (rule) => rule.rule_id === roomId && isMutedRule(rule)
+ );
}
class Notifications extends EventEmitter {
@@ -63,8 +65,8 @@ class Notifications extends EventEmitter {
if (this.getNotiType(room.roomId) === cons.notifs.MUTE) return;
if (this.doesRoomHaveUnread(room) === false) return;
- const total = room.getUnreadNotificationCount('total');
- const highlight = room.getUnreadNotificationCount('highlight');
+ const total = room.getUnreadNotificationCount("total");
+ const highlight = room.getUnreadNotificationCount("highlight");
this._setNoti(room.roomId, total ?? 0, highlight ?? 0);
};
[...this.roomList.rooms].forEach(addNoti);
@@ -95,25 +97,28 @@ class Notifications extends EventEmitter {
const mx = this.matrixClient;
let pushRule;
try {
- pushRule = mx.getRoomPushRule('global', roomId);
+ pushRule = mx.getRoomPushRule("global", roomId);
} catch {
pushRule = undefined;
}
if (pushRule === undefined) {
- const overrideRules = mx.getAccountData('m.push_rules')?.getContent()?.global?.override;
+ const overrideRules = mx.getAccountData("m.push_rules")?.getContent()
+ ?.global?.override;
if (overrideRules === undefined) return cons.notifs.DEFAULT;
const isMuted = findMutedRule(overrideRules, roomId);
return isMuted ? cons.notifs.MUTE : cons.notifs.DEFAULT;
}
- if (pushRule.actions[0] === 'notify') return cons.notifs.ALL_MESSAGES;
+ if (pushRule.actions[0] === "notify") return cons.notifs.ALL_MESSAGES;
return cons.notifs.MENTIONS_AND_KEYWORDS;
}
getNoti(roomId) {
- return this.roomIdToNoti.get(roomId) || { total: 0, highlight: 0, from: null };
+ return (
+ this.roomIdToNoti.get(roomId) || { total: 0, highlight: 0, from: null }
+ );
}
getTotalNoti(roomId) {
@@ -179,7 +184,12 @@ class Notifications extends EventEmitter {
noti.from.add(fromId);
}
this.roomIdToNoti.set(id, noti);
- this.emit(cons.events.notifications.NOTI_CHANGED, id, noti.total, prevTotal);
+ this.emit(
+ cons.events.notifications.NOTI_CHANGED,
+ id,
+ noti.total,
+ prevTotal
+ );
};
const noti = this.getNoti(roomId);
@@ -216,7 +226,12 @@ class Notifications extends EventEmitter {
this.emit(cons.events.notifications.NOTI_CHANGED, id, null, prevTotal);
} else {
this.roomIdToNoti.set(id, noti);
- this.emit(cons.events.notifications.NOTI_CHANGED, id, noti.total, prevTotal);
+ this.emit(
+ cons.events.notifications.NOTI_CHANGED,
+ id,
+ noti.total,
+ prevTotal
+ );
}
};
@@ -234,7 +249,11 @@ class Notifications extends EventEmitter {
const actions = this.matrixClient.getPushActionsForEvent(mEvent);
if (!actions?.notify) return;
- if (navigation.selectedRoomId === room.roomId && document.visibilityState === 'visible') return;
+ if (
+ navigation.selectedRoomId === room.roomId &&
+ document.visibilityState === "visible"
+ )
+ return;
if (mEvent.isEncrypted()) {
await mEvent.attemptDecryption(this.matrixClient.crypto);
@@ -252,7 +271,12 @@ class Notifications extends EventEmitter {
const icon = await renderAvatar({
text: mEvent.sender.name,
bgColor: cssColorMXID(mEvent.getSender()),
- imageSrc: mEvent.sender?.getAvatarUrl(this.matrixClient.baseUrl, iconSize, iconSize, 'crop'),
+ imageSrc: mEvent.sender?.getAvatarUrl(
+ this.matrixClient.baseUrl,
+ iconSize,
+ iconSize,
+ "crop"
+ ),
size: iconSize,
borderRadius: 8,
scale: 8,
@@ -260,9 +284,9 @@ class Notifications extends EventEmitter {
const content = mEvent.getContent();
- const state = { kind: 'notification', onlyPlain: true };
+ const state = { kind: "notification", onlyPlain: true };
let body;
- if (content.format === 'org.matrix.custom.html') {
+ if (content.format === "org.matrix.custom.html") {
body = html(content.formatted_body, state);
} else {
body = plain(content.body, state);
@@ -305,20 +329,20 @@ class Notifications extends EventEmitter {
_playNotiSound() {
if (!this._notiAudio) {
- this._notiAudio = document.getElementById('notificationSound');
+ this._notiAudio = document.getElementById("notificationSound");
}
this._notiAudio.play();
}
_playInviteSound() {
if (!this._inviteAudio) {
- this._inviteAudio = document.getElementById('inviteSound');
+ this._inviteAudio = document.getElementById("inviteSound");
}
this._inviteAudio.play();
}
_listenEvents() {
- this.matrixClient.on('Room.timeline', (mEvent, room) => {
+ this.matrixClient.on("Room.timeline", (mEvent, room) => {
if (mEvent.isRedaction()) this._deletePopupNoti(mEvent.event.redacts);
if (room.isSpaceRoom()) return;
@@ -330,8 +354,8 @@ class Notifications extends EventEmitter {
if (lastTimelineEvent.getId() !== mEvent.getId()) return;
if (mEvent.getSender() === this.matrixClient.getUserId()) return;
- const total = room.getUnreadNotificationCount('total');
- const highlight = room.getUnreadNotificationCount('highlight');
+ const total = room.getUnreadNotificationCount("total");
+ const highlight = room.getUnreadNotificationCount("highlight");
if (this.getNotiType(room.roomId) === cons.notifs.MUTE) {
this.deleteNoti(room.roomId, total ?? 0, highlight ?? 0);
@@ -340,13 +364,13 @@ class Notifications extends EventEmitter {
this._setNoti(room.roomId, total ?? 0, highlight ?? 0);
- if (this.matrixClient.getSyncState() === 'SYNCING') {
+ if (this.matrixClient.getSyncState() === "SYNCING") {
this._displayPopupNoti(mEvent, room);
}
});
- this.matrixClient.on('accountData', (mEvent, oldMEvent) => {
- if (mEvent.getType() === 'm.push_rules') {
+ this.matrixClient.on("accountData", (mEvent, oldMEvent) => {
+ if (mEvent.getType() === "m.push_rules") {
const override = mEvent?.getContent()?.global?.override;
const oldOverride = oldMEvent?.getContent()?.global?.override;
if (!override || !oldOverride) return;
@@ -364,30 +388,38 @@ class Notifications extends EventEmitter {
return true;
};
- const mutedRules = override.filter((rule) => isMuteToggled(rule, oldOverride));
- const unMutedRules = oldOverride.filter((rule) => isMuteToggled(rule, override));
+ const mutedRules = override.filter((rule) =>
+ isMuteToggled(rule, oldOverride)
+ );
+ const unMutedRules = oldOverride.filter((rule) =>
+ isMuteToggled(rule, override)
+ );
mutedRules.forEach((rule) => {
this.emit(cons.events.notifications.MUTE_TOGGLED, rule.rule_id, true);
this.deleteNoti(rule.rule_id);
});
unMutedRules.forEach((rule) => {
- this.emit(cons.events.notifications.MUTE_TOGGLED, rule.rule_id, false);
+ this.emit(
+ cons.events.notifications.MUTE_TOGGLED,
+ rule.rule_id,
+ false
+ );
const room = this.matrixClient.getRoom(rule.rule_id);
if (!this.doesRoomHaveUnread(room)) return;
- const total = room.getUnreadNotificationCount('total');
- const highlight = room.getUnreadNotificationCount('highlight');
+ const total = room.getUnreadNotificationCount("total");
+ const highlight = room.getUnreadNotificationCount("highlight");
this._setNoti(room.roomId, total ?? 0, highlight ?? 0);
});
}
});
- this.matrixClient.on('Room.receipt', (mEvent, room) => {
- if (mEvent.getType() === 'm.receipt') {
+ this.matrixClient.on("Room.receipt", (mEvent, room) => {
+ if (mEvent.getType() === "m.receipt") {
if (room.isSpaceRoom()) return;
const content = mEvent.getContent();
const readedEventId = Object.keys(content)[0];
- const readerUserId = Object.keys(content[readedEventId]['m.read'])[0];
+ const readerUserId = Object.keys(content[readedEventId]["m.read"])[0];
if (readerUserId !== this.matrixClient.getUserId()) return;
this.deleteNoti(room.roomId);
@@ -396,11 +428,11 @@ class Notifications extends EventEmitter {
}
});
- this.matrixClient.on('Room.myMembership', (room, membership) => {
- if (membership === 'leave' && this.hasNoti(room.roomId)) {
+ this.matrixClient.on("Room.myMembership", (room, membership) => {
+ if (membership === "leave" && this.hasNoti(room.roomId)) {
this.deleteNoti(room.roomId);
}
- if (membership === 'invite') {
+ if (membership === "invite") {
this._playInviteSound();
}
});
diff --git a/src/client/state/RoomList.js b/src/client/state/RoomList.js
index a1570480..cb068cc9 100644
--- a/src/client/state/RoomList.js
+++ b/src/client/state/RoomList.js
@@ -1,9 +1,12 @@
-import EventEmitter from 'events';
-import appDispatcher from '../dispatcher';
-import cons from './cons';
+import EventEmitter from "events";
+import appDispatcher from "../dispatcher";
+import cons from "./cons";
function isMEventSpaceChild(mEvent) {
- return mEvent.getType() === 'm.space.child' && Object.keys(mEvent.getContent()).length > 0;
+ return (
+ mEvent.getType() === "m.space.child" &&
+ Object.keys(mEvent.getContent()).length > 0
+ );
}
/**
@@ -13,9 +16,10 @@ function isMEventSpaceChild(mEvent) {
*/
async function waitFor(callback, timeout = 400, maxTry = -1) {
if (maxTry === 0) return false;
- const isOver = async () => new Promise((resolve) => {
- setTimeout(() => resolve(callback()), timeout);
- });
+ const isOver = async () =>
+ new Promise((resolve) => {
+ setTimeout(() => resolve(callback()), timeout);
+ });
if (await isOver()) return true;
return waitFor(callback, timeout, maxTry - 1);
@@ -52,11 +56,15 @@ class RoomList extends EventEmitter {
}
getOrphanSpaces() {
- return [...this.spaces].filter((roomId) => !this.roomIdToParents.has(roomId));
+ return [...this.spaces].filter(
+ (roomId) => !this.roomIdToParents.has(roomId)
+ );
}
getOrphanRooms() {
- return [...this.rooms].filter((roomId) => !this.roomIdToParents.has(roomId));
+ return [...this.rooms].filter(
+ (roomId) => !this.roomIdToParents.has(roomId)
+ );
}
getOrphans() {
@@ -67,7 +75,7 @@ class RoomList extends EventEmitter {
getSpaceChildren(roomId) {
const space = this.matrixClient.getRoom(roomId);
if (space === null) return null;
- const mSpaceChild = space?.currentState.getStateEvents('m.space.child');
+ const mSpaceChild = space?.currentState.getStateEvents("m.space.child");
const children = [];
mSpaceChild.forEach((mEvent) => {
@@ -89,7 +97,7 @@ class RoomList extends EventEmitter {
child.forEach((childId) => {
const room = this.matrixClient.getRoom(childId);
- if (room === null || room.getMyMembership() !== 'join') return;
+ if (room === null || room.getMyMembership() !== "join") return;
if (room.isSpaceRoom()) categorizeSpace(childId);
else mappedChild.add(childId);
});
@@ -172,7 +180,7 @@ class RoomList extends EventEmitter {
this.processingRooms.set(action.roomId, {
roomId: action.roomId,
isDM: action.isDM,
- task: 'JOIN',
+ task: "JOIN",
});
}
},
@@ -187,7 +195,7 @@ class RoomList extends EventEmitter {
this.processingRooms.set(action.roomId, {
roomId: action.roomId,
isDM: action.isDM,
- task: 'CREATE',
+ task: "CREATE",
});
}
},
@@ -197,11 +205,9 @@ class RoomList extends EventEmitter {
getMDirects() {
const mDirectsId = new Set();
- const mDirect = this.matrixClient
- .getAccountData('m.direct')
- ?.getContent();
+ const mDirect = this.matrixClient.getAccountData("m.direct")?.getContent();
- if (typeof mDirect === 'undefined') return mDirectsId;
+ if (typeof mDirect === "undefined") return mDirectsId;
Object.keys(mDirect).forEach((direct) => {
mDirect[direct].forEach((directId) => mDirectsId.add(directId));
@@ -220,21 +226,23 @@ class RoomList extends EventEmitter {
this.inviteRooms.clear();
this.matrixClient.getRooms().forEach((room) => {
const { roomId } = room;
- const tombstone = room.currentState.events.get('m.room.tombstone');
- if (tombstone?.get('') !== undefined) {
- const repRoomId = tombstone.get('').getContent().replacement_room;
- const repRoomMembership = this.matrixClient.getRoom(repRoomId)?.getMyMembership();
- if (repRoomMembership === 'join') return;
+ const tombstone = room.currentState.events.get("m.room.tombstone");
+ if (tombstone?.get("") !== undefined) {
+ const repRoomId = tombstone.get("").getContent().replacement_room;
+ const repRoomMembership = this.matrixClient
+ .getRoom(repRoomId)
+ ?.getMyMembership();
+ if (repRoomMembership === "join") return;
}
- if (room.getMyMembership() === 'invite') {
+ if (room.getMyMembership() === "invite") {
if (this._isDMInvite(room)) this.inviteDirects.add(roomId);
else if (room.isSpaceRoom()) this.inviteSpaces.add(roomId);
else this.inviteRooms.add(roomId);
return;
}
- if (room.getMyMembership() !== 'join') return;
+ if (room.getMyMembership() !== "join") return;
if (this.mDirects.has(roomId)) this.directs.add(roomId);
else if (room.isSpaceRoom()) this.addToSpaces(roomId);
@@ -246,13 +254,13 @@ class RoomList extends EventEmitter {
if (this.mDirects.has(room.roomId)) return true;
const me = room.getMember(this.matrixClient.getUserId());
const myEventContent = me.events.member.getContent();
- return myEventContent.membership === 'invite' && myEventContent.is_direct;
+ return myEventContent.membership === "invite" && myEventContent.is_direct;
}
_listenEvents() {
// Update roomList when m.direct changes
- this.matrixClient.on('accountData', (event) => {
- if (event.getType() !== 'm.direct') return;
+ this.matrixClient.on("accountData", (event) => {
+ if (event.getType() !== "m.direct") return;
const latestMDirects = this.getMDirects();
@@ -262,7 +270,7 @@ class RoomList extends EventEmitter {
const myRoom = this.matrixClient.getRoom(directId);
if (myRoom === null) return;
- if (myRoom.getMyMembership() === 'join') {
+ if (myRoom.getMyMembership() === "join") {
this.directs.add(directId);
this.rooms.delete(directId);
this.emit(cons.events.roomList.ROOMLIST_UPDATED);
@@ -275,7 +283,7 @@ class RoomList extends EventEmitter {
const myRoom = this.matrixClient.getRoom(directId);
if (myRoom === null) return;
- if (myRoom.getMyMembership() === 'join') {
+ if (myRoom.getMyMembership() === "join") {
this.directs.delete(directId);
this.rooms.add(directId);
this.emit(cons.events.roomList.ROOMLIST_UPDATED);
@@ -283,13 +291,13 @@ class RoomList extends EventEmitter {
});
});
- this.matrixClient.on('Room.name', (room) => {
+ this.matrixClient.on("Room.name", (room) => {
this.emit(cons.events.roomList.ROOMLIST_UPDATED);
this.emit(cons.events.roomList.ROOM_PROFILE_UPDATED, room.roomId);
});
- this.matrixClient.on('RoomState.events', (mEvent, state) => {
- if (mEvent.getType() === 'm.space.child') {
+ this.matrixClient.on("RoomState.events", (mEvent, state) => {
+ if (mEvent.getType() === "m.space.child") {
const roomId = mEvent.event.room_id;
const childId = mEvent.event.state_key;
if (isMEventSpaceChild(mEvent)) {
@@ -304,86 +312,94 @@ class RoomList extends EventEmitter {
this.emit(cons.events.roomList.ROOMLIST_UPDATED);
return;
}
- if (mEvent.getType() === 'm.room.join_rules') {
+ if (mEvent.getType() === "m.room.join_rules") {
this.emit(cons.events.roomList.ROOMLIST_UPDATED);
return;
}
- if (['m.room.avatar', 'm.room.topic'].includes(mEvent.getType())) {
- if (mEvent.getType() === 'm.room.avatar') {
+ if (["m.room.avatar", "m.room.topic"].includes(mEvent.getType())) {
+ if (mEvent.getType() === "m.room.avatar") {
this.emit(cons.events.roomList.ROOMLIST_UPDATED);
}
this.emit(cons.events.roomList.ROOM_PROFILE_UPDATED, state.roomId);
}
});
- this.matrixClient.on('Room.myMembership', async (room, membership, prevMembership) => {
- // room => prevMembership = null | invite | join | leave | kick | ban | unban
- // room => membership = invite | join | leave | kick | ban | unban
- const { roomId } = room;
- const isRoomReady = () => this.matrixClient.getRoom(roomId) !== null;
- if (['join', 'invite'].includes(membership) && isRoomReady() === false) {
- if (await waitFor(isRoomReady, 200, 100) === false) return;
+ this.matrixClient.on(
+ "Room.myMembership",
+ async (room, membership, prevMembership) => {
+ // room => prevMembership = null | invite | join | leave | kick | ban | unban
+ // room => membership = invite | join | leave | kick | ban | unban
+ const { roomId } = room;
+ const isRoomReady = () => this.matrixClient.getRoom(roomId) !== null;
+ if (
+ ["join", "invite"].includes(membership) &&
+ isRoomReady() === false
+ ) {
+ if ((await waitFor(isRoomReady, 200, 100)) === false) return;
+ }
+
+ if (membership === "unban") return;
+
+ if (membership === "invite") {
+ if (this._isDMInvite(room)) this.inviteDirects.add(roomId);
+ else if (room.isSpaceRoom()) this.inviteSpaces.add(roomId);
+ else this.inviteRooms.add(roomId);
+
+ this.emit(cons.events.roomList.INVITELIST_UPDATED, roomId);
+ return;
+ }
+
+ if (prevMembership === "invite") {
+ if (this.inviteDirects.has(roomId)) this.inviteDirects.delete(roomId);
+ else if (this.inviteSpaces.has(roomId))
+ this.inviteSpaces.delete(roomId);
+ else this.inviteRooms.delete(roomId);
+
+ this.emit(cons.events.roomList.INVITELIST_UPDATED, roomId);
+ }
+
+ if (["leave", "kick", "ban"].includes(membership)) {
+ if (this.directs.has(roomId)) this.directs.delete(roomId);
+ else if (this.spaces.has(roomId)) this.deleteFromSpaces(roomId);
+ else this.rooms.delete(roomId);
+ this.emit(cons.events.roomList.ROOM_LEAVED, roomId);
+ this.emit(cons.events.roomList.ROOMLIST_UPDATED);
+ return;
+ }
+
+ // when user create room/DM OR accept room/dm invite from this client.
+ // we will update this.rooms/this.directs with user action
+ if (membership === "join" && this.processingRooms.has(roomId)) {
+ const procRoomInfo = this.processingRooms.get(roomId);
+
+ if (procRoomInfo.isDM) this.directs.add(roomId);
+ else if (room.isSpaceRoom()) this.addToSpaces(roomId);
+ else this.rooms.add(roomId);
+
+ if (procRoomInfo.task === "CREATE")
+ this.emit(cons.events.roomList.ROOM_CREATED, roomId);
+ this.emit(cons.events.roomList.ROOM_JOINED, roomId);
+ this.emit(cons.events.roomList.ROOMLIST_UPDATED);
+
+ this.processingRooms.delete(roomId);
+ return;
+ }
+
+ if (this.mDirects.has(roomId) && membership === "join") {
+ this.directs.add(roomId);
+ this.emit(cons.events.roomList.ROOM_JOINED, roomId);
+ this.emit(cons.events.roomList.ROOMLIST_UPDATED);
+ return;
+ }
+
+ if (membership === "join") {
+ if (room.isSpaceRoom()) this.addToSpaces(roomId);
+ else this.rooms.add(roomId);
+ this.emit(cons.events.roomList.ROOM_JOINED, roomId);
+ this.emit(cons.events.roomList.ROOMLIST_UPDATED);
+ }
}
-
- if (membership === 'unban') return;
-
- if (membership === 'invite') {
- if (this._isDMInvite(room)) this.inviteDirects.add(roomId);
- else if (room.isSpaceRoom()) this.inviteSpaces.add(roomId);
- else this.inviteRooms.add(roomId);
-
- this.emit(cons.events.roomList.INVITELIST_UPDATED, roomId);
- return;
- }
-
- if (prevMembership === 'invite') {
- if (this.inviteDirects.has(roomId)) this.inviteDirects.delete(roomId);
- else if (this.inviteSpaces.has(roomId)) this.inviteSpaces.delete(roomId);
- else this.inviteRooms.delete(roomId);
-
- this.emit(cons.events.roomList.INVITELIST_UPDATED, roomId);
- }
-
- if (['leave', 'kick', 'ban'].includes(membership)) {
- if (this.directs.has(roomId)) this.directs.delete(roomId);
- else if (this.spaces.has(roomId)) this.deleteFromSpaces(roomId);
- else this.rooms.delete(roomId);
- this.emit(cons.events.roomList.ROOM_LEAVED, roomId);
- this.emit(cons.events.roomList.ROOMLIST_UPDATED);
- return;
- }
-
- // when user create room/DM OR accept room/dm invite from this client.
- // we will update this.rooms/this.directs with user action
- if (membership === 'join' && this.processingRooms.has(roomId)) {
- const procRoomInfo = this.processingRooms.get(roomId);
-
- if (procRoomInfo.isDM) this.directs.add(roomId);
- else if (room.isSpaceRoom()) this.addToSpaces(roomId);
- else this.rooms.add(roomId);
-
- if (procRoomInfo.task === 'CREATE') this.emit(cons.events.roomList.ROOM_CREATED, roomId);
- this.emit(cons.events.roomList.ROOM_JOINED, roomId);
- this.emit(cons.events.roomList.ROOMLIST_UPDATED);
-
- this.processingRooms.delete(roomId);
- return;
- }
-
- if (this.mDirects.has(roomId) && membership === 'join') {
- this.directs.add(roomId);
- this.emit(cons.events.roomList.ROOM_JOINED, roomId);
- this.emit(cons.events.roomList.ROOMLIST_UPDATED);
- return;
- }
-
- if (membership === 'join') {
- if (room.isSpaceRoom()) this.addToSpaces(roomId);
- else this.rooms.add(roomId);
- this.emit(cons.events.roomList.ROOM_JOINED, roomId);
- this.emit(cons.events.roomList.ROOMLIST_UPDATED);
- }
- });
+ );
}
}
export default RoomList;
diff --git a/src/client/state/RoomTimeline.js b/src/client/state/RoomTimeline.js
index 57d91c14..726f3199 100644
--- a/src/client/state/RoomTimeline.js
+++ b/src/client/state/RoomTimeline.js
@@ -1,15 +1,15 @@
-import EventEmitter from 'events';
-import initMatrix from '../initMatrix';
-import cons from './cons';
+import EventEmitter from "events";
+import initMatrix from "../initMatrix";
+import cons from "./cons";
-import settings from './settings';
+import settings from "./settings";
function isEdited(mEvent) {
- return mEvent.getRelation()?.rel_type === 'm.replace';
+ return mEvent.getRelation()?.rel_type === "m.replace";
}
function isReaction(mEvent) {
- return mEvent.getType() === 'm.reaction';
+ return mEvent.getType() === "m.reaction";
}
function hideMemberEvents(mEvent) {
@@ -17,11 +17,16 @@ function hideMemberEvents(mEvent) {
const prevContent = mEvent.getPrevContent();
const { membership } = content;
if (settings.hideMembershipEvents) {
- if (membership === 'invite' || membership === 'ban' || membership === 'leave') return true;
- if (prevContent.membership !== 'join') return true;
+ if (
+ membership === "invite" ||
+ membership === "ban" ||
+ membership === "leave"
+ )
+ return true;
+ if (prevContent.membership !== "join") return true;
}
if (settings.hideNickAvatarEvents) {
- if (membership === 'join' && prevContent.membership === 'join') return true;
+ if (membership === "join" && prevContent.membership === "join") return true;
}
return false;
}
@@ -36,7 +41,7 @@ function addToMap(myMap, mEvent) {
if (relateToId === null) return null;
const mEventId = mEvent.getId();
- if (typeof myMap.get(relateToId) === 'undefined') myMap.set(relateToId, []);
+ if (typeof myMap.get(relateToId) === "undefined") myMap.set(relateToId, []);
const mEvents = myMap.get(relateToId);
if (mEvents.find((ev) => ev.getId() === mEventId)) return mEvent;
mEvents.push(mEvent);
@@ -107,9 +112,9 @@ class RoomTimeline extends EventEmitter {
}
canPaginateBackward() {
- if (this.timeline[0]?.getType() === 'm.room.create') return false;
+ if (this.timeline[0]?.getType() === "m.room.create") return false;
const tm = getFirstLinkedTimeline(this.activeTimeline);
- return tm.getPaginationToken('b') !== null;
+ return tm.getPaginationToken("b") !== null;
}
canPaginateForward() {
@@ -125,7 +130,7 @@ class RoomTimeline extends EventEmitter {
}
addToTimeline(mEvent) {
- if (mEvent.getType() === 'm.room.member' && hideMemberEvents(mEvent)) {
+ if (mEvent.getType() === "m.room.member" && hideMemberEvents(mEvent)) {
return;
}
if (mEvent.isRedacted()) return;
@@ -154,7 +159,8 @@ class RoomTimeline extends EventEmitter {
}
async _reset() {
- if (this.isEncrypted()) await this.decryptAllEventsOfTimeline(this.activeTimeline);
+ if (this.isEncrypted())
+ await this.decryptAllEventsOfTimeline(this.activeTimeline);
this._populateTimelines();
if (!this.initialized) {
this.initialized = true;
@@ -173,7 +179,10 @@ class RoomTimeline extends EventEmitter {
// we use first unfiltered EventTimelineSet for room pagination.
const timelineSet = this.getUnfilteredTimelineSet();
try {
- const eventTimeline = await this.matrixClient.getEventTimeline(timelineSet, eventId);
+ const eventTimeline = await this.matrixClient.getEventTimeline(
+ timelineSet,
+ eventId
+ );
this.activeTimeline = eventTimeline;
await this._reset();
this.emit(cons.events.roomTimeline.READY, eventId);
@@ -193,7 +202,7 @@ class RoomTimeline extends EventEmitter {
? getFirstLinkedTimeline(this.activeTimeline)
: getLastLinkedTimeline(this.activeTimeline);
- if (timelineToPaginate.getPaginationToken(backwards ? 'b' : 'f') === null) {
+ if (timelineToPaginate.getPaginationToken(backwards ? "b" : "f") === null) {
this.emit(cons.events.roomTimeline.PAGINATED, backwards, 0);
this.isOngoingPagination = false;
return false;
@@ -201,9 +210,13 @@ class RoomTimeline extends EventEmitter {
const oldSize = this.timeline.length;
try {
- await this.matrixClient.paginateEventTimeline(timelineToPaginate, { backwards, limit });
+ await this.matrixClient.paginateEventTimeline(timelineToPaginate, {
+ backwards,
+ limit,
+ });
- if (this.isEncrypted()) await this.decryptAllEventsOfTimeline(this.activeTimeline);
+ if (this.isEncrypted())
+ await this.decryptAllEventsOfTimeline(this.activeTimeline);
this._populateTimelines();
const loaded = this.timeline.length - oldSize;
@@ -222,7 +235,9 @@ class RoomTimeline extends EventEmitter {
.getEvents()
.filter((event) => event.isEncrypted() && !event.clearEvent)
.reverse()
- .map((event) => event.attemptDecryption(this.matrixClient.crypto, { isRetry: true }));
+ .map((event) =>
+ event.attemptDecryption(this.matrixClient.crypto, { isRetry: true })
+ );
return Promise.allSettled(decryptionPromises);
}
@@ -244,7 +259,11 @@ class RoomTimeline extends EventEmitter {
if (!mEvent) return [];
for (let i = liveEvents.length - 1; i >= 0; i -= 1) {
- readers.splice(readers.length, 0, ...this.room.getUsersReadUpTo(liveEvents[i]));
+ readers.splice(
+ readers.length,
+ 0,
+ ...this.room.getUsersReadUpTo(liveEvents[i])
+ );
if (mEvent === liveEvents[i]) break;
}
@@ -256,15 +275,17 @@ class RoomTimeline extends EventEmitter {
const getLatestVisibleEvent = () => {
for (let i = liveEvents.length - 1; i >= 0; i -= 1) {
const mEvent = liveEvents[i];
- if (mEvent.getType() === 'm.room.member' && hideMemberEvents(mEvent)) {
+ if (mEvent.getType() === "m.room.member" && hideMemberEvents(mEvent)) {
// eslint-disable-next-line no-continue
continue;
}
- if (!mEvent.isRedacted()
- && !isReaction(mEvent)
- && !isEdited(mEvent)
- && cons.supportEventTypes.includes(mEvent.getType())
- ) return mEvent;
+ if (
+ !mEvent.isRedacted() &&
+ !isReaction(mEvent) &&
+ !isEdited(mEvent) &&
+ cons.supportEventTypes.includes(mEvent.getType())
+ )
+ return mEvent;
}
return liveEvents[liveEvents.length - 1];
};
@@ -296,7 +317,10 @@ class RoomTimeline extends EventEmitter {
return this.timeline.findIndex((mEvent) => mEvent.getId() === eventId);
}
- findEventByIdInTimelineSet(eventId, eventTimelineSet = this.getUnfilteredTimelineSet()) {
+ findEventByIdInTimelineSet(
+ eventId,
+ eventTimelineSet = this.getUnfilteredTimelineSet()
+ ) {
return eventTimelineSet.findEventById(eventId);
}
@@ -311,7 +335,13 @@ class RoomTimeline extends EventEmitter {
}
_listenEvents() {
- this._listenRoomTimeline = (event, room, toStartOfTimeline, removed, data) => {
+ this._listenRoomTimeline = (
+ event,
+ room,
+ toStartOfTimeline,
+ removed,
+ data
+ ) => {
if (room.roomId !== this.roomId) return;
if (this.isOngoingPagination) return;
@@ -369,7 +399,10 @@ class RoomTimeline extends EventEmitter {
const isTyping = member.typing;
if (isTyping) this.typingMembers.add(member.userId);
else this.typingMembers.delete(member.userId);
- this.emit(cons.events.roomTimeline.TYPING_MEMBERS_UPDATED, new Set([...this.typingMembers]));
+ this.emit(
+ cons.events.roomTimeline.TYPING_MEMBERS_UPDATED,
+ new Set([...this.typingMembers])
+ );
};
this._listenReciptEvent = (event, room) => {
// we only process receipt for latest message here.
@@ -381,26 +414,32 @@ class RoomTimeline extends EventEmitter {
const lastEventId = lastMEvent.getId();
const lastEventRecipt = receiptContent[lastEventId];
- if (typeof lastEventRecipt === 'undefined') return;
- if (lastEventRecipt['m.read']) {
+ if (typeof lastEventRecipt === "undefined") return;
+ if (lastEventRecipt["m.read"]) {
this.emit(cons.events.roomTimeline.LIVE_RECEIPT);
}
};
- this.matrixClient.on('Room.timeline', this._listenRoomTimeline);
- this.matrixClient.on('Room.redaction', this._listenRedaction);
- this.matrixClient.on('Event.decrypted', this._listenDecryptEvent);
- this.matrixClient.on('RoomMember.typing', this._listenTypingEvent);
- this.matrixClient.on('Room.receipt', this._listenReciptEvent);
+ this.matrixClient.on("Room.timeline", this._listenRoomTimeline);
+ this.matrixClient.on("Room.redaction", this._listenRedaction);
+ this.matrixClient.on("Event.decrypted", this._listenDecryptEvent);
+ this.matrixClient.on("RoomMember.typing", this._listenTypingEvent);
+ this.matrixClient.on("Room.receipt", this._listenReciptEvent);
}
removeInternalListeners() {
if (!this.initialized) return;
- this.matrixClient.removeListener('Room.timeline', this._listenRoomTimeline);
- this.matrixClient.removeListener('Room.redaction', this._listenRedaction);
- this.matrixClient.removeListener('Event.decrypted', this._listenDecryptEvent);
- this.matrixClient.removeListener('RoomMember.typing', this._listenTypingEvent);
- this.matrixClient.removeListener('Room.receipt', this._listenReciptEvent);
+ this.matrixClient.removeListener("Room.timeline", this._listenRoomTimeline);
+ this.matrixClient.removeListener("Room.redaction", this._listenRedaction);
+ this.matrixClient.removeListener(
+ "Event.decrypted",
+ this._listenDecryptEvent
+ );
+ this.matrixClient.removeListener(
+ "RoomMember.typing",
+ this._listenTypingEvent
+ );
+ this.matrixClient.removeListener("Room.receipt", this._listenReciptEvent);
}
}
diff --git a/src/client/state/RoomsHierarchy.js b/src/client/state/RoomsHierarchy.js
index f3ffb1fc..538d5bb0 100644
--- a/src/client/state/RoomsHierarchy.js
+++ b/src/client/state/RoomsHierarchy.js
@@ -1,4 +1,4 @@
-import { RoomHierarchy } from 'matrix-js-sdk/lib/room-hierarchy';
+import { RoomHierarchy } from "matrix-js-sdk/lib/room-hierarchy";
class RoomsHierarchy {
constructor(matrixClient, limit = 20, maxDepth = 1, suggestedOnly = false) {
@@ -32,7 +32,7 @@ class RoomsHierarchy {
{ roomId, client: this.matrixClient },
limit,
this._maxDepth,
- this._suggestedOnly,
+ this._suggestedOnly
);
this.roomIdToHierarchy.set(roomId, roomHierarchy);
}
diff --git a/src/client/state/RoomsInput.js b/src/client/state/RoomsInput.js
index d1e0aedb..864c00f8 100644
--- a/src/client/state/RoomsInput.js
+++ b/src/client/state/RoomsInput.js
@@ -1,20 +1,20 @@
-import EventEmitter from 'events';
-import encrypt from 'browser-encrypt-attachment';
-import { encode } from 'blurhash';
-import { getShortcodeToEmoji } from '../../app/organisms/emoji-board/custom-emoji';
-import { getBlobSafeMimeType } from '../../util/mimetypes';
-import { sanitizeText } from '../../util/sanitize';
-import cons from './cons';
-import settings from './settings';
-import { markdown, plain } from '../../util/markdown';
+import EventEmitter from "events";
+import encrypt from "browser-encrypt-attachment";
+import { encode } from "blurhash";
+import { getShortcodeToEmoji } from "../../app/organisms/emoji-board/custom-emoji";
+import { getBlobSafeMimeType } from "../../util/mimetypes";
+import { sanitizeText } from "../../util/sanitize";
+import cons from "./cons";
+import settings from "./settings";
+import { markdown, plain } from "../../util/markdown";
-const blurhashField = 'xyz.amorgan.blurhash';
+const blurhashField = "xyz.amorgan.blurhash";
function encodeBlurhash(img) {
- const canvas = document.createElement('canvas');
+ const canvas = document.createElement("canvas");
canvas.width = 100;
canvas.height = 100;
- const context = canvas.getContext('2d');
+ const context = canvas.getContext("2d");
context.drawImage(img, 0, 0, canvas.width, canvas.height);
const data = context.getImageData(0, 0, canvas.width, canvas.height);
return encode(data.data, data.width, data.height, 4, 4);
@@ -31,8 +31,8 @@ function loadImage(url) {
function loadVideo(videoFile) {
return new Promise((resolve, reject) => {
- const video = document.createElement('video');
- video.preload = 'metadata';
+ const video = document.createElement("video");
+ video.preload = "metadata";
video.playsInline = true;
video.muted = true;
@@ -55,8 +55,10 @@ function loadVideo(videoFile) {
reader.onerror = (e) => {
reject(e);
};
- if (videoFile.type === 'video/quicktime') {
- const quicktimeVideoFile = new File([videoFile], videoFile.name, { type: 'video/mp4' });
+ if (videoFile.type === "video/quicktime") {
+ const quicktimeVideoFile = new File([videoFile], videoFile.name, {
+ type: "video/mp4",
+ });
reader.readAsDataURL(quicktimeVideoFile);
} else {
reader.readAsDataURL(videoFile);
@@ -78,10 +80,10 @@ function getVideoThumbnail(video, width, height, mimeType) {
targetWidth = MAX_WIDTH;
}
- const canvas = document.createElement('canvas');
+ const canvas = document.createElement("canvas");
canvas.width = targetWidth;
canvas.height = targetHeight;
- const context = canvas.getContext('2d');
+ const context = canvas.getContext("2d");
context.drawImage(video, 0, 0, targetWidth, targetHeight);
canvas.toBlob((thumbnail) => {
@@ -109,9 +111,10 @@ class RoomsInput extends EventEmitter {
cleanEmptyEntry(roomId) {
const input = this.getInput(roomId);
- const isEmpty = typeof input.attachment === 'undefined'
- && typeof input.replyTo === 'undefined'
- && (typeof input.message === 'undefined' || input.message === '');
+ const isEmpty =
+ typeof input.attachment === "undefined" &&
+ typeof input.replyTo === "undefined" &&
+ (typeof input.message === "undefined" || input.message === "");
if (isEmpty) {
this.roomIdToInput.delete(roomId);
}
@@ -125,12 +128,12 @@ class RoomsInput extends EventEmitter {
const input = this.getInput(roomId);
input.message = message;
this.roomIdToInput.set(roomId, input);
- if (message === '') this.cleanEmptyEntry(roomId);
+ if (message === "") this.cleanEmptyEntry(roomId);
}
getMessage(roomId) {
const input = this.getInput(roomId);
- if (typeof input.message === 'undefined') return '';
+ if (typeof input.message === "undefined") return "";
return input.message;
}
@@ -142,13 +145,13 @@ class RoomsInput extends EventEmitter {
getReplyTo(roomId) {
const input = this.getInput(roomId);
- if (typeof input.replyTo === 'undefined') return null;
+ if (typeof input.replyTo === "undefined") return null;
return input.replyTo;
}
cancelReplyTo(roomId) {
const input = this.getInput(roomId);
- if (typeof input.replyTo === 'undefined') return;
+ if (typeof input.replyTo === "undefined") return;
delete input.replyTo;
this.roomIdToInput.set(roomId, input);
}
@@ -163,13 +166,13 @@ class RoomsInput extends EventEmitter {
getAttachment(roomId) {
const input = this.getInput(roomId);
- if (typeof input.attachment === 'undefined') return null;
+ if (typeof input.attachment === "undefined") return null;
return input.attachment.file;
}
cancelAttachment(roomId) {
const input = this.getInput(roomId);
- if (typeof input.attachment === 'undefined') return;
+ if (typeof input.attachment === "undefined") return;
const { uploadingPromise } = input.attachment;
@@ -188,15 +191,20 @@ class RoomsInput extends EventEmitter {
}
getContent(roomId, options, message, reply, edit) {
- const msgType = options?.msgType || 'm.text';
+ const msgType = options?.msgType || "m.text";
const autoMarkdown = options?.autoMarkdown ?? true;
const room = this.matrixClient.getRoom(roomId);
const userNames = room.currentState.userIdsToDisplayNames;
const parentIds = this.roomList.getAllParentSpaces(room.roomId);
- const parentRooms = [...parentIds].map((id) => this.matrixClient.getRoom(id));
- const emojis = getShortcodeToEmoji(this.matrixClient, [room, ...parentRooms]);
+ const parentRooms = [...parentIds].map((id) =>
+ this.matrixClient.getRoom(id)
+ );
+ const emojis = getShortcodeToEmoji(this.matrixClient, [
+ room,
+ ...parentRooms,
+ ]);
const output = settings.isMarkdown && autoMarkdown ? markdown : plain;
const body = output(message, { userNames, emojis });
@@ -207,49 +215,60 @@ class RoomsInput extends EventEmitter {
};
if (!body.onlyPlain || reply) {
- content.format = 'org.matrix.custom.html';
+ content.format = "org.matrix.custom.html";
content.formatted_body = body.html;
}
if (edit) {
- content['m.new_content'] = { ...content };
- content['m.relates_to'] = {
+ content["m.new_content"] = { ...content };
+ content["m.relates_to"] = {
event_id: edit.getId(),
- rel_type: 'm.replace',
+ rel_type: "m.replace",
};
- const isReply = edit.getWireContent()['m.relates_to']?.['m.in_reply_to'];
+ const isReply = edit.getWireContent()["m.relates_to"]?.["m.in_reply_to"];
if (isReply) {
- content.format = 'org.matrix.custom.html';
+ content.format = "org.matrix.custom.html";
content.formatted_body = body.html;
}
content.body = ` * ${content.body}`;
- if (content.formatted_body) content.formatted_body = ` * ${content.formatted_body}`;
+ if (content.formatted_body)
+ content.formatted_body = ` * ${content.formatted_body}`;
if (isReply) {
const eBody = edit.getContent().body;
- const replyHead = eBody.substring(0, eBody.indexOf('\n\n'));
+ const replyHead = eBody.substring(0, eBody.indexOf("\n\n"));
if (replyHead) content.body = `${replyHead}\n\n${content.body}`;
const eFBody = edit.getContent().formatted_body;
- const fReplyHead = eFBody.substring(0, eFBody.indexOf(''));
- if (fReplyHead) content.formatted_body = `${fReplyHead}${content.formatted_body}`;
+ const fReplyHead = eFBody.substring(0, eFBody.indexOf(""));
+ if (fReplyHead)
+ content.formatted_body = `${fReplyHead}${content.formatted_body}`;
}
}
if (reply) {
- content['m.relates_to'] = {
- 'm.in_reply_to': {
+ content["m.relates_to"] = {
+ "m.in_reply_to": {
event_id: reply.eventId,
},
};
- content.body = `> <${reply.userId}> ${reply.body.replace(/\n/g, '\n> ')}\n\n${content.body}`;
+ content.body = `> <${reply.userId}> ${reply.body.replace(
+ /\n/g,
+ "\n> "
+ )}\n\n${content.body}`;
- const replyToLink = `
In reply to`;
- const userLink = `
${sanitizeText(reply.userId)}`;
- const fallback = `
${replyToLink}${userLink}
${reply.formattedBody || sanitizeText(reply.body)}
`;
+ const replyToLink = `
In reply to`;
+ const userLink = `
${sanitizeText(reply.userId)}`;
+ const fallback = `
${replyToLink}${userLink}
${
+ reply.formattedBody || sanitizeText(reply.body)
+ }
`;
content.formatted_body = fallback + content.formatted_body;
}
@@ -265,8 +284,13 @@ class RoomsInput extends EventEmitter {
if (!this.isSending(roomId)) return;
}
- if (this.getMessage(roomId).trim() !== '') {
- const content = this.getContent(roomId, options, input.message, input.replyTo);
+ if (this.getMessage(roomId).trim() !== "") {
+ const content = this.getContent(
+ roomId,
+ options,
+ input.message,
+ input.replyTo
+ );
this.matrixClient.sendMessage(roomId, content);
}
@@ -294,7 +318,7 @@ class RoomsInput extends EventEmitter {
// send sticker without info
}
- this.matrixClient.sendEvent(roomId, 'm.sticker', {
+ this.matrixClient.sendEvent(roomId, "m.sticker", {
body,
url,
info,
@@ -303,7 +327,10 @@ class RoomsInput extends EventEmitter {
}
async sendFile(roomId, file) {
- const fileType = getBlobSafeMimeType(file.type).slice(0, file.type.indexOf('/'));
+ const fileType = getBlobSafeMimeType(file.type).slice(
+ 0,
+ file.type.indexOf("/")
+ );
const info = {
mimetype: file.type,
size: file.size,
@@ -311,18 +338,18 @@ class RoomsInput extends EventEmitter {
const content = { info };
let uploadData = null;
- if (fileType === 'image') {
+ if (fileType === "image") {
const img = await loadImage(URL.createObjectURL(file));
info.w = img.width;
info.h = img.height;
info[blurhashField] = encodeBlurhash(img);
- content.msgtype = 'm.image';
- content.body = file.name || 'Image';
- } else if (fileType === 'video') {
- content.msgtype = 'm.video';
- content.body = file.name || 'Video';
+ content.msgtype = "m.image";
+ content.body = file.name || "Image";
+ } else if (fileType === "video") {
+ content.msgtype = "m.video";
+ content.body = file.name || "Video";
try {
const video = await loadVideo(file);
@@ -331,8 +358,16 @@ class RoomsInput extends EventEmitter {
info.h = video.videoHeight;
info[blurhashField] = encodeBlurhash(video);
- const thumbnailData = await getVideoThumbnail(video, video.videoWidth, video.videoHeight, 'image/jpeg');
- const thumbnailUploadData = await this.uploadFile(roomId, thumbnailData.thumbnail);
+ const thumbnailData = await getVideoThumbnail(
+ video,
+ video.videoWidth,
+ video.videoHeight,
+ "image/jpeg"
+ );
+ const thumbnailUploadData = await this.uploadFile(
+ roomId,
+ thumbnailData.thumbnail
+ );
info.thumbnail_info = thumbnailData.info;
if (this.matrixClient.isRoomEncrypted(roomId)) {
info.thumbnail_file = thumbnailUploadData.file;
@@ -343,12 +378,12 @@ class RoomsInput extends EventEmitter {
this.emit(cons.events.roomsInput.FILE_UPLOAD_CANCELED, roomId);
return;
}
- } else if (fileType === 'audio') {
- content.msgtype = 'm.audio';
- content.body = file.name || 'Audio';
+ } else if (fileType === "audio") {
+ content.msgtype = "m.audio";
+ content.body = file.name || "Audio";
} else {
- content.msgtype = 'm.file';
- content.body = file.name || 'File';
+ content.msgtype = "m.file";
+ content.body = file.name || "File";
}
try {
@@ -378,18 +413,23 @@ class RoomsInput extends EventEmitter {
if (isEncryptedRoom) {
const dataBuffer = await file.arrayBuffer();
- if (typeof this.getInput(roomId).attachment === 'undefined') throw new Error('Attachment canceled');
+ if (typeof this.getInput(roomId).attachment === "undefined")
+ throw new Error("Attachment canceled");
const encryptedResult = await encrypt.encryptAttachment(dataBuffer);
- if (typeof this.getInput(roomId).attachment === 'undefined') throw new Error('Attachment canceled');
+ if (typeof this.getInput(roomId).attachment === "undefined")
+ throw new Error("Attachment canceled");
encryptInfo = encryptedResult.info;
encryptBlob = new Blob([encryptedResult.data]);
}
- const uploadingPromise = this.matrixClient.uploadContent(isEncryptedRoom ? encryptBlob : file, {
- // don't send filename if room is encrypted.
- includeFilename: !isEncryptedRoom,
- progressHandler,
- });
+ const uploadingPromise = this.matrixClient.uploadContent(
+ isEncryptedRoom ? encryptBlob : file,
+ {
+ // don't send filename if room is encrypted.
+ includeFilename: !isEncryptedRoom,
+ progressHandler,
+ }
+ );
const input = this.getInput(roomId);
input.attachment.uploadingPromise = uploadingPromise;
@@ -414,7 +454,7 @@ class RoomsInput extends EventEmitter {
{ msgType: mEvent.getWireContent().msgtype },
editedBody,
null,
- mEvent,
+ mEvent
);
this.matrixClient.sendMessage(roomId, content);
}
diff --git a/src/client/state/auth.js b/src/client/state/auth.js
index fbc23f6f..19c3fe8e 100644
--- a/src/client/state/auth.js
+++ b/src/client/state/auth.js
@@ -1,4 +1,4 @@
-import cons from './cons';
+import cons from "./cons";
function getSecret(key) {
return localStorage.getItem(key);
@@ -13,7 +13,4 @@ const secret = {
baseUrl: getSecret(cons.secretKey.BASE_URL),
};
-export {
- isAuthenticated,
- secret,
-};
+export { isAuthenticated, secret };
diff --git a/src/client/state/cons.js b/src/client/state/cons.js
index 8d9fda54..d759b653 100644
--- a/src/client/state/cons.js
+++ b/src/client/state/cons.js
@@ -1,155 +1,155 @@
const cons = {
- version: '2.2.6',
+ version: "2.2.6",
secretKey: {
- ACCESS_TOKEN: 'cinny_access_token',
- DEVICE_ID: 'cinny_device_id',
- USER_ID: 'cinny_user_id',
- BASE_URL: 'cinny_hs_base_url',
+ ACCESS_TOKEN: "cinny_access_token",
+ DEVICE_ID: "cinny_device_id",
+ USER_ID: "cinny_user_id",
+ BASE_URL: "cinny_hs_base_url",
},
- DEVICE_DISPLAY_NAME: 'Cinny Web',
- IN_CINNY_SPACES: 'in.cinny.spaces',
+ DEVICE_DISPLAY_NAME: "Cinny Web",
+ IN_CINNY_SPACES: "in.cinny.spaces",
tabs: {
- HOME: 'home',
- DIRECTS: 'dm',
+ HOME: "home",
+ DIRECTS: "dm",
},
supportEventTypes: [
- 'm.room.create',
- 'm.room.message',
- 'm.room.encrypted',
- 'm.room.member',
- 'm.sticker',
+ "m.room.create",
+ "m.room.message",
+ "m.room.encrypted",
+ "m.room.member",
+ "m.sticker",
],
notifs: {
- DEFAULT: 'default',
- ALL_MESSAGES: 'all_messages',
- MENTIONS_AND_KEYWORDS: 'mentions_and_keywords',
- MUTE: 'mute',
+ DEFAULT: "default",
+ ALL_MESSAGES: "all_messages",
+ MENTIONS_AND_KEYWORDS: "mentions_and_keywords",
+ MUTE: "mute",
},
status: {
- PRE_FLIGHT: 'pre-flight',
- IN_FLIGHT: 'in-flight',
- SUCCESS: 'success',
- ERROR: 'error',
+ PRE_FLIGHT: "pre-flight",
+ IN_FLIGHT: "in-flight",
+ SUCCESS: "success",
+ ERROR: "error",
},
actions: {
navigation: {
- SELECT_TAB: 'SELECT_TAB',
- SELECT_SPACE: 'SELECT_SPACE',
- SELECT_ROOM: 'SELECT_ROOM',
- OPEN_SPACE_SETTINGS: 'OPEN_SPACE_SETTINGS',
- OPEN_SPACE_MANAGE: 'OPEN_SPACE_MANAGE',
- OPEN_SPACE_ADDEXISTING: 'OPEN_SPACE_ADDEXISTING',
- TOGGLE_ROOM_SETTINGS: 'TOGGLE_ROOM_SETTINGS',
- OPEN_SHORTCUT_SPACES: 'OPEN_SHORTCUT_SPACES',
- OPEN_INVITE_LIST: 'OPEN_INVITE_LIST',
- OPEN_PUBLIC_ROOMS: 'OPEN_PUBLIC_ROOMS',
- OPEN_CREATE_ROOM: 'OPEN_CREATE_ROOM',
- OPEN_JOIN_ALIAS: 'OPEN_JOIN_ALIAS',
- OPEN_INVITE_USER: 'OPEN_INVITE_USER',
- OPEN_PROFILE_VIEWER: 'OPEN_PROFILE_VIEWER',
- OPEN_SETTINGS: 'OPEN_SETTINGS',
- OPEN_EMOJIBOARD: 'OPEN_EMOJIBOARD',
- OPEN_READRECEIPTS: 'OPEN_READRECEIPTS',
- OPEN_VIEWSOURCE: 'OPEN_VIEWSOURCE',
- CLICK_REPLY_TO: 'CLICK_REPLY_TO',
- OPEN_SEARCH: 'OPEN_SEARCH',
- OPEN_REUSABLE_CONTEXT_MENU: 'OPEN_REUSABLE_CONTEXT_MENU',
- OPEN_NAVIGATION: 'OPEN_NAVIGATION',
- OPEN_REUSABLE_DIALOG: 'OPEN_REUSABLE_DIALOG',
- OPEN_EMOJI_VERIFICATION: 'OPEN_EMOJI_VERIFICATION',
+ SELECT_TAB: "SELECT_TAB",
+ SELECT_SPACE: "SELECT_SPACE",
+ SELECT_ROOM: "SELECT_ROOM",
+ OPEN_SPACE_SETTINGS: "OPEN_SPACE_SETTINGS",
+ OPEN_SPACE_MANAGE: "OPEN_SPACE_MANAGE",
+ OPEN_SPACE_ADDEXISTING: "OPEN_SPACE_ADDEXISTING",
+ TOGGLE_ROOM_SETTINGS: "TOGGLE_ROOM_SETTINGS",
+ OPEN_SHORTCUT_SPACES: "OPEN_SHORTCUT_SPACES",
+ OPEN_INVITE_LIST: "OPEN_INVITE_LIST",
+ OPEN_PUBLIC_ROOMS: "OPEN_PUBLIC_ROOMS",
+ OPEN_CREATE_ROOM: "OPEN_CREATE_ROOM",
+ OPEN_JOIN_ALIAS: "OPEN_JOIN_ALIAS",
+ OPEN_INVITE_USER: "OPEN_INVITE_USER",
+ OPEN_PROFILE_VIEWER: "OPEN_PROFILE_VIEWER",
+ OPEN_SETTINGS: "OPEN_SETTINGS",
+ OPEN_EMOJIBOARD: "OPEN_EMOJIBOARD",
+ OPEN_READRECEIPTS: "OPEN_READRECEIPTS",
+ OPEN_VIEWSOURCE: "OPEN_VIEWSOURCE",
+ CLICK_REPLY_TO: "CLICK_REPLY_TO",
+ OPEN_SEARCH: "OPEN_SEARCH",
+ OPEN_REUSABLE_CONTEXT_MENU: "OPEN_REUSABLE_CONTEXT_MENU",
+ OPEN_NAVIGATION: "OPEN_NAVIGATION",
+ OPEN_REUSABLE_DIALOG: "OPEN_REUSABLE_DIALOG",
+ OPEN_EMOJI_VERIFICATION: "OPEN_EMOJI_VERIFICATION",
},
room: {
- JOIN: 'JOIN',
- LEAVE: 'LEAVE',
- CREATE: 'CREATE',
+ JOIN: "JOIN",
+ LEAVE: "LEAVE",
+ CREATE: "CREATE",
},
accountData: {
- CREATE_SPACE_SHORTCUT: 'CREATE_SPACE_SHORTCUT',
- DELETE_SPACE_SHORTCUT: 'DELETE_SPACE_SHORTCUT',
- MOVE_SPACE_SHORTCUTS: 'MOVE_SPACE_SHORTCUTS',
- CATEGORIZE_SPACE: 'CATEGORIZE_SPACE',
- UNCATEGORIZE_SPACE: 'UNCATEGORIZE_SPACE',
+ CREATE_SPACE_SHORTCUT: "CREATE_SPACE_SHORTCUT",
+ DELETE_SPACE_SHORTCUT: "DELETE_SPACE_SHORTCUT",
+ MOVE_SPACE_SHORTCUTS: "MOVE_SPACE_SHORTCUTS",
+ CATEGORIZE_SPACE: "CATEGORIZE_SPACE",
+ UNCATEGORIZE_SPACE: "UNCATEGORIZE_SPACE",
},
settings: {
- TOGGLE_SYSTEM_THEME: 'TOGGLE_SYSTEM_THEME',
- TOGGLE_MARKDOWN: 'TOGGLE_MARKDOWN',
- TOGGLE_PEOPLE_DRAWER: 'TOGGLE_PEOPLE_DRAWER',
- TOGGLE_MEMBERSHIP_EVENT: 'TOGGLE_MEMBERSHIP_EVENT',
- TOGGLE_NICKAVATAR_EVENT: 'TOGGLE_NICKAVATAR_EVENT',
- TOGGLE_NOTIFICATIONS: 'TOGGLE_NOTIFICATIONS',
- TOGGLE_NOTIFICATION_SOUNDS: 'TOGGLE_NOTIFICATION_SOUNDS',
+ TOGGLE_SYSTEM_THEME: "TOGGLE_SYSTEM_THEME",
+ TOGGLE_MARKDOWN: "TOGGLE_MARKDOWN",
+ TOGGLE_PEOPLE_DRAWER: "TOGGLE_PEOPLE_DRAWER",
+ TOGGLE_MEMBERSHIP_EVENT: "TOGGLE_MEMBERSHIP_EVENT",
+ TOGGLE_NICKAVATAR_EVENT: "TOGGLE_NICKAVATAR_EVENT",
+ TOGGLE_NOTIFICATIONS: "TOGGLE_NOTIFICATIONS",
+ TOGGLE_NOTIFICATION_SOUNDS: "TOGGLE_NOTIFICATION_SOUNDS",
},
},
events: {
navigation: {
- TAB_SELECTED: 'TAB_SELECTED',
- SPACE_SELECTED: 'SPACE_SELECTED',
- ROOM_SELECTED: 'ROOM_SELECTED',
- SPACE_SETTINGS_OPENED: 'SPACE_SETTINGS_OPENED',
- SPACE_MANAGE_OPENED: 'SPACE_MANAGE_OPENED',
- SPACE_ADDEXISTING_OPENED: 'SPACE_ADDEXISTING_OPENED',
- ROOM_SETTINGS_TOGGLED: 'ROOM_SETTINGS_TOGGLED',
- SHORTCUT_SPACES_OPENED: 'SHORTCUT_SPACES_OPENED',
- INVITE_LIST_OPENED: 'INVITE_LIST_OPENED',
- PUBLIC_ROOMS_OPENED: 'PUBLIC_ROOMS_OPENED',
- CREATE_ROOM_OPENED: 'CREATE_ROOM_OPENED',
- JOIN_ALIAS_OPENED: 'JOIN_ALIAS_OPENED',
- INVITE_USER_OPENED: 'INVITE_USER_OPENED',
- SETTINGS_OPENED: 'SETTINGS_OPENED',
- PROFILE_VIEWER_OPENED: 'PROFILE_VIEWER_OPENED',
- EMOJIBOARD_OPENED: 'EMOJIBOARD_OPENED',
- READRECEIPTS_OPENED: 'READRECEIPTS_OPENED',
- VIEWSOURCE_OPENED: 'VIEWSOURCE_OPENED',
- REPLY_TO_CLICKED: 'REPLY_TO_CLICKED',
- SEARCH_OPENED: 'SEARCH_OPENED',
- REUSABLE_CONTEXT_MENU_OPENED: 'REUSABLE_CONTEXT_MENU_OPENED',
- NAVIGATION_OPENED: 'NAVIGATION_OPENED',
- REUSABLE_DIALOG_OPENED: 'REUSABLE_DIALOG_OPENED',
- EMOJI_VERIFICATION_OPENED: 'EMOJI_VERIFICATION_OPENED',
+ TAB_SELECTED: "TAB_SELECTED",
+ SPACE_SELECTED: "SPACE_SELECTED",
+ ROOM_SELECTED: "ROOM_SELECTED",
+ SPACE_SETTINGS_OPENED: "SPACE_SETTINGS_OPENED",
+ SPACE_MANAGE_OPENED: "SPACE_MANAGE_OPENED",
+ SPACE_ADDEXISTING_OPENED: "SPACE_ADDEXISTING_OPENED",
+ ROOM_SETTINGS_TOGGLED: "ROOM_SETTINGS_TOGGLED",
+ SHORTCUT_SPACES_OPENED: "SHORTCUT_SPACES_OPENED",
+ INVITE_LIST_OPENED: "INVITE_LIST_OPENED",
+ PUBLIC_ROOMS_OPENED: "PUBLIC_ROOMS_OPENED",
+ CREATE_ROOM_OPENED: "CREATE_ROOM_OPENED",
+ JOIN_ALIAS_OPENED: "JOIN_ALIAS_OPENED",
+ INVITE_USER_OPENED: "INVITE_USER_OPENED",
+ SETTINGS_OPENED: "SETTINGS_OPENED",
+ PROFILE_VIEWER_OPENED: "PROFILE_VIEWER_OPENED",
+ EMOJIBOARD_OPENED: "EMOJIBOARD_OPENED",
+ READRECEIPTS_OPENED: "READRECEIPTS_OPENED",
+ VIEWSOURCE_OPENED: "VIEWSOURCE_OPENED",
+ REPLY_TO_CLICKED: "REPLY_TO_CLICKED",
+ SEARCH_OPENED: "SEARCH_OPENED",
+ REUSABLE_CONTEXT_MENU_OPENED: "REUSABLE_CONTEXT_MENU_OPENED",
+ NAVIGATION_OPENED: "NAVIGATION_OPENED",
+ REUSABLE_DIALOG_OPENED: "REUSABLE_DIALOG_OPENED",
+ EMOJI_VERIFICATION_OPENED: "EMOJI_VERIFICATION_OPENED",
},
roomList: {
- ROOMLIST_UPDATED: 'ROOMLIST_UPDATED',
- INVITELIST_UPDATED: 'INVITELIST_UPDATED',
- ROOM_JOINED: 'ROOM_JOINED',
- ROOM_LEAVED: 'ROOM_LEAVED',
- ROOM_CREATED: 'ROOM_CREATED',
- ROOM_PROFILE_UPDATED: 'ROOM_PROFILE_UPDATED',
+ ROOMLIST_UPDATED: "ROOMLIST_UPDATED",
+ INVITELIST_UPDATED: "INVITELIST_UPDATED",
+ ROOM_JOINED: "ROOM_JOINED",
+ ROOM_LEAVED: "ROOM_LEAVED",
+ ROOM_CREATED: "ROOM_CREATED",
+ ROOM_PROFILE_UPDATED: "ROOM_PROFILE_UPDATED",
},
accountData: {
- SPACE_SHORTCUT_UPDATED: 'SPACE_SHORTCUT_UPDATED',
- CATEGORIZE_SPACE_UPDATED: 'CATEGORIZE_SPACE_UPDATED',
+ SPACE_SHORTCUT_UPDATED: "SPACE_SHORTCUT_UPDATED",
+ CATEGORIZE_SPACE_UPDATED: "CATEGORIZE_SPACE_UPDATED",
},
notifications: {
- NOTI_CHANGED: 'NOTI_CHANGED',
- FULL_READ: 'FULL_READ',
- MUTE_TOGGLED: 'MUTE_TOGGLED',
+ NOTI_CHANGED: "NOTI_CHANGED",
+ FULL_READ: "FULL_READ",
+ MUTE_TOGGLED: "MUTE_TOGGLED",
},
roomTimeline: {
- READY: 'READY',
- EVENT: 'EVENT',
- PAGINATED: 'PAGINATED',
- TYPING_MEMBERS_UPDATED: 'TYPING_MEMBERS_UPDATED',
- LIVE_RECEIPT: 'LIVE_RECEIPT',
- EVENT_REDACTED: 'EVENT_REDACTED',
- AT_BOTTOM: 'AT_BOTTOM',
- SCROLL_TO_LIVE: 'SCROLL_TO_LIVE',
+ READY: "READY",
+ EVENT: "EVENT",
+ PAGINATED: "PAGINATED",
+ TYPING_MEMBERS_UPDATED: "TYPING_MEMBERS_UPDATED",
+ LIVE_RECEIPT: "LIVE_RECEIPT",
+ EVENT_REDACTED: "EVENT_REDACTED",
+ AT_BOTTOM: "AT_BOTTOM",
+ SCROLL_TO_LIVE: "SCROLL_TO_LIVE",
},
roomsInput: {
- MESSAGE_SENT: 'MESSAGE_SENT',
- ATTACHMENT_SET: 'ATTACHMENT_SET',
- FILE_UPLOADED: 'FILE_UPLOADED',
- UPLOAD_PROGRESS_CHANGES: 'UPLOAD_PROGRESS_CHANGES',
- FILE_UPLOAD_CANCELED: 'FILE_UPLOAD_CANCELED',
- ATTACHMENT_CANCELED: 'ATTACHMENT_CANCELED',
+ MESSAGE_SENT: "MESSAGE_SENT",
+ ATTACHMENT_SET: "ATTACHMENT_SET",
+ FILE_UPLOADED: "FILE_UPLOADED",
+ UPLOAD_PROGRESS_CHANGES: "UPLOAD_PROGRESS_CHANGES",
+ FILE_UPLOAD_CANCELED: "FILE_UPLOAD_CANCELED",
+ ATTACHMENT_CANCELED: "ATTACHMENT_CANCELED",
},
settings: {
- SYSTEM_THEME_TOGGLED: 'SYSTEM_THEME_TOGGLED',
- MARKDOWN_TOGGLED: 'MARKDOWN_TOGGLED',
- PEOPLE_DRAWER_TOGGLED: 'PEOPLE_DRAWER_TOGGLED',
- MEMBERSHIP_EVENTS_TOGGLED: 'MEMBERSHIP_EVENTS_TOGGLED',
- NICKAVATAR_EVENTS_TOGGLED: 'NICKAVATAR_EVENTS_TOGGLED',
- NOTIFICATIONS_TOGGLED: 'NOTIFICATIONS_TOGGLED',
- NOTIFICATION_SOUNDS_TOGGLED: 'NOTIFICATION_SOUNDS_TOGGLED',
+ SYSTEM_THEME_TOGGLED: "SYSTEM_THEME_TOGGLED",
+ MARKDOWN_TOGGLED: "MARKDOWN_TOGGLED",
+ PEOPLE_DRAWER_TOGGLED: "PEOPLE_DRAWER_TOGGLED",
+ MEMBERSHIP_EVENTS_TOGGLED: "MEMBERSHIP_EVENTS_TOGGLED",
+ NICKAVATAR_EVENTS_TOGGLED: "NICKAVATAR_EVENTS_TOGGLED",
+ NOTIFICATIONS_TOGGLED: "NOTIFICATIONS_TOGGLED",
+ NOTIFICATION_SOUNDS_TOGGLED: "NOTIFICATION_SOUNDS_TOGGLED",
},
},
};
diff --git a/src/client/state/navigation.js b/src/client/state/navigation.js
index 07231cd4..52642188 100644
--- a/src/client/state/navigation.js
+++ b/src/client/state/navigation.js
@@ -1,6 +1,6 @@
-import EventEmitter from 'events';
-import appDispatcher from '../dispatcher';
-import cons from './cons';
+import EventEmitter from "events";
+import appDispatcher from "../dispatcher";
+import cons from "./cons";
class Navigation extends EventEmitter {
constructor() {
@@ -22,7 +22,7 @@ class Navigation extends EventEmitter {
}
_addToSpacePath(roomId, asRoot) {
- if (typeof roomId !== 'string') {
+ if (typeof roomId !== "string") {
this.selectedSpacePath = [cons.tabs.HOME];
return;
}
@@ -41,9 +41,9 @@ class Navigation extends EventEmitter {
_mapRoomToSpace(roomId) {
const { roomList, accountData } = this.initMatrix;
if (
- this.selectedTab === cons.tabs.HOME
- && roomList.rooms.has(roomId)
- && !roomList.roomIdToParents.has(roomId)
+ this.selectedTab === cons.tabs.HOME &&
+ roomList.rooms.has(roomId) &&
+ !roomList.roomIdToParents.has(roomId)
) {
this.spaceToRoom.set(cons.tabs.HOME, {
roomId,
@@ -51,7 +51,10 @@ class Navigation extends EventEmitter {
});
return;
}
- if (this.selectedTab === cons.tabs.DIRECTS && roomList.directs.has(roomId)) {
+ if (
+ this.selectedTab === cons.tabs.DIRECTS &&
+ roomList.directs.has(roomId)
+ ) {
this.spaceToRoom.set(cons.tabs.DIRECTS, {
roomId,
timestamp: Date.now(),
@@ -85,15 +88,18 @@ class Navigation extends EventEmitter {
this.removeRecentRoom(prevSelectedRoomId);
this.addRecentRoom(prevSelectedRoomId);
this.removeRecentRoom(this.selectedRoomId);
- if (this.isRoomSettings && typeof this.selectedRoomId === 'string') {
+ if (this.isRoomSettings && typeof this.selectedRoomId === "string") {
this.isRoomSettings = !this.isRoomSettings;
- this.emit(cons.events.navigation.ROOM_SETTINGS_TOGGLED, this.isRoomSettings);
+ this.emit(
+ cons.events.navigation.ROOM_SETTINGS_TOGGLED,
+ this.isRoomSettings
+ );
}
this.emit(
cons.events.navigation.ROOM_SELECTED,
this.selectedRoomId,
prevSelectedRoomId,
- eventId,
+ eventId
);
}
@@ -127,7 +133,9 @@ class Navigation extends EventEmitter {
}
}
- const spaceInPath = [...this.selectedSpacePath].reverse().find((sId) => parents.has(sId));
+ const spaceInPath = [...this.selectedSpacePath]
+ .reverse()
+ .find((sId) => parents.has(sId));
if (spaceInPath) {
this._selectSpace(spaceInPath, false, false);
return;
@@ -212,7 +220,9 @@ class Navigation extends EventEmitter {
if (categorizedSpaces.has(spaceId)) {
const categories = roomList.getCategorizedSpaces([spaceId]);
- const latestSelectedRoom = this._getLatestSelectedRoomId([...categories.keys()]);
+ const latestSelectedRoom = this._getLatestSelectedRoomId([
+ ...categories.keys(),
+ ]);
if (latestSelectedRoom) {
this._selectRoom(latestSelectedRoom);
@@ -248,7 +258,10 @@ class Navigation extends EventEmitter {
this._selectRoom(data.roomId);
return;
}
- const children = tabId === cons.tabs.HOME ? roomList.getOrphanRooms() : [...roomList.directs];
+ const children =
+ tabId === cons.tabs.HOME
+ ? roomList.getOrphanRooms()
+ : [...roomList.directs];
this._selectRoom(this._getLatestActiveRoomId(children));
return;
}
@@ -256,7 +269,7 @@ class Navigation extends EventEmitter {
}
removeRecentRoom(roomId) {
- if (typeof roomId !== 'string') return;
+ if (typeof roomId !== "string") return;
const roomIdIndex = this.recentRooms.indexOf(roomId);
if (roomIdIndex >= 0) {
this.recentRooms.splice(roomIdIndex, 1);
@@ -264,7 +277,7 @@ class Navigation extends EventEmitter {
}
addRecentRoom(roomId) {
- if (typeof roomId !== 'string') return;
+ if (typeof roomId !== "string") return;
this.recentRooms.push(roomId);
if (this.recentRooms.length > 10) {
@@ -284,9 +297,10 @@ class Navigation extends EventEmitter {
navigate(action) {
const actions = {
[cons.actions.navigation.SELECT_TAB]: () => {
- const roomId = (
+ const roomId =
action.tabId !== cons.tabs.HOME && action.tabId !== cons.tabs.DIRECTS
- ) ? action.tabId : null;
+ ? action.tabId
+ : null;
this._selectSpace(roomId, true);
this._selectTab(action.tabId);
@@ -299,20 +313,27 @@ class Navigation extends EventEmitter {
this._selectRoom(action.roomId, action.eventId);
},
[cons.actions.navigation.OPEN_SPACE_SETTINGS]: () => {
- this.emit(cons.events.navigation.SPACE_SETTINGS_OPENED, action.roomId, action.tabText);
+ this.emit(
+ cons.events.navigation.SPACE_SETTINGS_OPENED,
+ action.roomId,
+ action.tabText
+ );
},
[cons.actions.navigation.OPEN_SPACE_MANAGE]: () => {
this.emit(cons.events.navigation.SPACE_MANAGE_OPENED, action.roomId);
},
[cons.actions.navigation.OPEN_SPACE_ADDEXISTING]: () => {
- this.emit(cons.events.navigation.SPACE_ADDEXISTING_OPENED, action.roomId);
+ this.emit(
+ cons.events.navigation.SPACE_ADDEXISTING_OPENED,
+ action.roomId
+ );
},
[cons.actions.navigation.TOGGLE_ROOM_SETTINGS]: () => {
this.isRoomSettings = !this.isRoomSettings;
this.emit(
cons.events.navigation.ROOM_SETTINGS_TOGGLED,
this.isRoomSettings,
- action.tabText,
+ action.tabText
);
},
[cons.actions.navigation.OPEN_SHORTCUT_SPACES]: () => {
@@ -322,26 +343,34 @@ class Navigation extends EventEmitter {
this.emit(cons.events.navigation.INVITE_LIST_OPENED);
},
[cons.actions.navigation.OPEN_PUBLIC_ROOMS]: () => {
- this.emit(cons.events.navigation.PUBLIC_ROOMS_OPENED, action.searchTerm);
+ this.emit(
+ cons.events.navigation.PUBLIC_ROOMS_OPENED,
+ action.searchTerm
+ );
},
[cons.actions.navigation.OPEN_CREATE_ROOM]: () => {
this.emit(
cons.events.navigation.CREATE_ROOM_OPENED,
action.isSpace,
- action.parentId,
+ action.parentId
);
},
[cons.actions.navigation.OPEN_JOIN_ALIAS]: () => {
- this.emit(
- cons.events.navigation.JOIN_ALIAS_OPENED,
- action.term,
- );
+ this.emit(cons.events.navigation.JOIN_ALIAS_OPENED, action.term);
},
[cons.actions.navigation.OPEN_INVITE_USER]: () => {
- this.emit(cons.events.navigation.INVITE_USER_OPENED, action.roomId, action.searchTerm);
+ this.emit(
+ cons.events.navigation.INVITE_USER_OPENED,
+ action.roomId,
+ action.searchTerm
+ );
},
[cons.actions.navigation.OPEN_PROFILE_VIEWER]: () => {
- this.emit(cons.events.navigation.PROFILE_VIEWER_OPENED, action.userId, action.roomId);
+ this.emit(
+ cons.events.navigation.PROFILE_VIEWER_OPENED,
+ action.userId,
+ action.roomId
+ );
},
[cons.actions.navigation.OPEN_SETTINGS]: () => {
this.emit(cons.events.navigation.SETTINGS_OPENED, action.tabText);
@@ -353,21 +382,18 @@ class Navigation extends EventEmitter {
this.emit(
cons.events.navigation.EMOJIBOARD_OPENED,
action.cords,
- action.requestEmojiCallback,
+ action.requestEmojiCallback
);
},
[cons.actions.navigation.OPEN_READRECEIPTS]: () => {
this.emit(
cons.events.navigation.READRECEIPTS_OPENED,
action.roomId,
- action.userIds,
+ action.userIds
);
},
[cons.actions.navigation.OPEN_VIEWSOURCE]: () => {
- this.emit(
- cons.events.navigation.VIEWSOURCE_OPENED,
- action.event,
- );
+ this.emit(cons.events.navigation.VIEWSOURCE_OPENED, action.event);
},
[cons.actions.navigation.CLICK_REPLY_TO]: () => {
this.emit(
@@ -375,14 +401,11 @@ class Navigation extends EventEmitter {
action.userId,
action.eventId,
action.body,
- action.formattedBody,
+ action.formattedBody
);
},
[cons.actions.navigation.OPEN_SEARCH]: () => {
- this.emit(
- cons.events.navigation.SEARCH_OPENED,
- action.term,
- );
+ this.emit(cons.events.navigation.SEARCH_OPENED, action.term);
},
[cons.actions.navigation.OPEN_REUSABLE_CONTEXT_MENU]: () => {
this.emit(
@@ -390,7 +413,7 @@ class Navigation extends EventEmitter {
action.placement,
action.cords,
action.render,
- action.afterClose,
+ action.afterClose
);
},
[cons.actions.navigation.OPEN_REUSABLE_DIALOG]: () => {
@@ -398,14 +421,14 @@ class Navigation extends EventEmitter {
cons.events.navigation.REUSABLE_DIALOG_OPENED,
action.title,
action.render,
- action.afterClose,
+ action.afterClose
);
},
[cons.actions.navigation.OPEN_EMOJI_VERIFICATION]: () => {
this.emit(
cons.events.navigation.EMOJI_VERIFICATION_OPENED,
action.request,
- action.targetDevice,
+ action.targetDevice
);
},
};
diff --git a/src/client/state/secretStorageKeys.js b/src/client/state/secretStorageKeys.js
index 7439e7a5..512322df 100644
--- a/src/client/state/secretStorageKeys.js
+++ b/src/client/state/secretStorageKeys.js
@@ -2,7 +2,7 @@ const secretStorageKeys = new Map();
export function storePrivateKey(keyId, privateKey) {
if (privateKey instanceof Uint8Array === false) {
- throw new Error('Unable to store, privateKey is invalid.');
+ throw new Error("Unable to store, privateKey is invalid.");
}
secretStorageKeys.set(keyId, privateKey);
}
diff --git a/src/client/state/settings.js b/src/client/state/settings.js
index 32f55fcc..b88a7634 100644
--- a/src/client/state/settings.js
+++ b/src/client/state/settings.js
@@ -1,10 +1,10 @@
-import EventEmitter from 'events';
-import appDispatcher from '../dispatcher';
+import EventEmitter from "events";
+import appDispatcher from "../dispatcher";
-import cons from './cons';
+import cons from "./cons";
function getSettings() {
- const settings = localStorage.getItem('settings');
+ const settings = localStorage.getItem("settings");
if (settings === null) return null;
return JSON.parse(settings);
}
@@ -13,14 +13,14 @@ function setSettings(key, value) {
let settings = getSettings();
if (settings === null) settings = {};
settings[key] = value;
- localStorage.setItem('settings', JSON.stringify(settings));
+ localStorage.setItem("settings", JSON.stringify(settings));
}
class Settings extends EventEmitter {
constructor() {
super();
- this.themes = ['', 'silver-theme', 'dark-theme', 'butter-theme'];
+ this.themes = ["", "silver-theme", "dark-theme", "butter-theme"];
this.themeIndex = this.getThemeIndex();
this.useSystemTheme = this.getUseSystemTheme();
@@ -31,15 +31,18 @@ class Settings extends EventEmitter {
this._showNotifications = this.getShowNotifications();
this.isNotificationSounds = this.getIsNotificationSounds();
- this.isTouchScreenDevice = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0);
+ this.isTouchScreenDevice =
+ "ontouchstart" in window ||
+ navigator.maxTouchPoints > 0 ||
+ navigator.msMaxTouchPoints > 0;
}
getThemeIndex() {
- if (typeof this.themeIndex === 'number') return this.themeIndex;
+ if (typeof this.themeIndex === "number") return this.themeIndex;
const settings = getSettings();
if (settings === null) return 0;
- if (typeof settings.themeIndex === 'undefined') return 0;
+ if (typeof settings.themeIndex === "undefined") return 0;
// eslint-disable-next-line radix
return parseInt(settings.themeIndex);
}
@@ -49,9 +52,9 @@ class Settings extends EventEmitter {
}
_clearTheme() {
- document.body.classList.remove('system-theme');
+ document.body.classList.remove("system-theme");
this.themes.forEach((themeName) => {
- if (themeName === '') return;
+ if (themeName === "") return;
document.body.classList.remove(themeName);
});
}
@@ -59,7 +62,7 @@ class Settings extends EventEmitter {
applyTheme() {
this._clearTheme();
if (this.useSystemTheme) {
- document.body.classList.add('system-theme');
+ document.body.classList.add("system-theme");
} else if (this.themes[this.themeIndex]) {
document.body.classList.add(this.themes[this.themeIndex]);
}
@@ -67,83 +70,87 @@ class Settings extends EventEmitter {
setTheme(themeIndex) {
this.themeIndex = themeIndex;
- setSettings('themeIndex', this.themeIndex);
+ setSettings("themeIndex", this.themeIndex);
this.applyTheme();
}
toggleUseSystemTheme() {
this.useSystemTheme = !this.useSystemTheme;
- setSettings('useSystemTheme', this.useSystemTheme);
+ setSettings("useSystemTheme", this.useSystemTheme);
this.applyTheme();
this.emit(cons.events.settings.SYSTEM_THEME_TOGGLED, this.useSystemTheme);
}
getUseSystemTheme() {
- if (typeof this.useSystemTheme === 'boolean') return this.useSystemTheme;
+ if (typeof this.useSystemTheme === "boolean") return this.useSystemTheme;
const settings = getSettings();
if (settings === null) return true;
- if (typeof settings.useSystemTheme === 'undefined') return true;
+ if (typeof settings.useSystemTheme === "undefined") return true;
return settings.useSystemTheme;
}
getIsMarkdown() {
- if (typeof this.isMarkdown === 'boolean') return this.isMarkdown;
+ if (typeof this.isMarkdown === "boolean") return this.isMarkdown;
const settings = getSettings();
if (settings === null) return true;
- if (typeof settings.isMarkdown === 'undefined') return true;
+ if (typeof settings.isMarkdown === "undefined") return true;
return settings.isMarkdown;
}
getHideMembershipEvents() {
- if (typeof this.hideMembershipEvents === 'boolean') return this.hideMembershipEvents;
+ if (typeof this.hideMembershipEvents === "boolean")
+ return this.hideMembershipEvents;
const settings = getSettings();
if (settings === null) return false;
- if (typeof settings.hideMembershipEvents === 'undefined') return false;
+ if (typeof settings.hideMembershipEvents === "undefined") return false;
return settings.hideMembershipEvents;
}
getHideNickAvatarEvents() {
- if (typeof this.hideNickAvatarEvents === 'boolean') return this.hideNickAvatarEvents;
+ if (typeof this.hideNickAvatarEvents === "boolean")
+ return this.hideNickAvatarEvents;
const settings = getSettings();
if (settings === null) return true;
- if (typeof settings.hideNickAvatarEvents === 'undefined') return true;
+ if (typeof settings.hideNickAvatarEvents === "undefined") return true;
return settings.hideNickAvatarEvents;
}
getIsPeopleDrawer() {
- if (typeof this.isPeopleDrawer === 'boolean') return this.isPeopleDrawer;
+ if (typeof this.isPeopleDrawer === "boolean") return this.isPeopleDrawer;
const settings = getSettings();
if (settings === null) return true;
- if (typeof settings.isPeopleDrawer === 'undefined') return true;
+ if (typeof settings.isPeopleDrawer === "undefined") return true;
return settings.isPeopleDrawer;
}
get showNotifications() {
- if (window.Notification?.permission !== 'granted') return false;
+ if (window.Notification?.permission !== "granted") return false;
return this._showNotifications;
}
getShowNotifications() {
- if (typeof this._showNotifications === 'boolean') return this._showNotifications;
+ if (typeof this._showNotifications === "boolean")
+ return this._showNotifications;
const settings = getSettings();
if (settings === null) return true;
- if (typeof settings.showNotifications === 'undefined') return true;
+ if (typeof settings.showNotifications === "undefined") return true;
return settings.showNotifications;
}
getIsNotificationSounds() {
- if (typeof this.isNotificationSounds === 'boolean') return this.isNotificationSounds;
+ if (typeof this.isNotificationSounds === "boolean")
+ return this.isNotificationSounds;
const settings = getSettings();
if (settings === null) return true;
- if (typeof settings.isNotificationSounds === 'undefined') return true;
+ if (typeof settings.isNotificationSounds === "undefined") return true;
return settings.isNotificationSounds;
}
@@ -154,37 +161,52 @@ class Settings extends EventEmitter {
},
[cons.actions.settings.TOGGLE_MARKDOWN]: () => {
this.isMarkdown = !this.isMarkdown;
- setSettings('isMarkdown', this.isMarkdown);
+ setSettings("isMarkdown", this.isMarkdown);
this.emit(cons.events.settings.MARKDOWN_TOGGLED, this.isMarkdown);
},
[cons.actions.settings.TOGGLE_PEOPLE_DRAWER]: () => {
this.isPeopleDrawer = !this.isPeopleDrawer;
- setSettings('isPeopleDrawer', this.isPeopleDrawer);
- this.emit(cons.events.settings.PEOPLE_DRAWER_TOGGLED, this.isPeopleDrawer);
+ setSettings("isPeopleDrawer", this.isPeopleDrawer);
+ this.emit(
+ cons.events.settings.PEOPLE_DRAWER_TOGGLED,
+ this.isPeopleDrawer
+ );
},
[cons.actions.settings.TOGGLE_MEMBERSHIP_EVENT]: () => {
this.hideMembershipEvents = !this.hideMembershipEvents;
- setSettings('hideMembershipEvents', this.hideMembershipEvents);
- this.emit(cons.events.settings.MEMBERSHIP_EVENTS_TOGGLED, this.hideMembershipEvents);
+ setSettings("hideMembershipEvents", this.hideMembershipEvents);
+ this.emit(
+ cons.events.settings.MEMBERSHIP_EVENTS_TOGGLED,
+ this.hideMembershipEvents
+ );
},
[cons.actions.settings.TOGGLE_NICKAVATAR_EVENT]: () => {
this.hideNickAvatarEvents = !this.hideNickAvatarEvents;
- setSettings('hideNickAvatarEvents', this.hideNickAvatarEvents);
- this.emit(cons.events.settings.NICKAVATAR_EVENTS_TOGGLED, this.hideNickAvatarEvents);
+ setSettings("hideNickAvatarEvents", this.hideNickAvatarEvents);
+ this.emit(
+ cons.events.settings.NICKAVATAR_EVENTS_TOGGLED,
+ this.hideNickAvatarEvents
+ );
},
[cons.actions.settings.TOGGLE_NOTIFICATIONS]: async () => {
- if (window.Notification?.permission !== 'granted') {
+ if (window.Notification?.permission !== "granted") {
this._showNotifications = false;
} else {
this._showNotifications = !this._showNotifications;
}
- setSettings('showNotifications', this._showNotifications);
- this.emit(cons.events.settings.NOTIFICATIONS_TOGGLED, this._showNotifications);
+ setSettings("showNotifications", this._showNotifications);
+ this.emit(
+ cons.events.settings.NOTIFICATIONS_TOGGLED,
+ this._showNotifications
+ );
},
[cons.actions.settings.TOGGLE_NOTIFICATION_SOUNDS]: () => {
this.isNotificationSounds = !this.isNotificationSounds;
- setSettings('isNotificationSounds', this.isNotificationSounds);
- this.emit(cons.events.settings.NOTIFICATION_SOUNDS_TOGGLED, this.isNotificationSounds);
+ setSettings("isNotificationSounds", this.isNotificationSounds);
+ this.emit(
+ cons.events.settings.NOTIFICATION_SOUNDS_TOGGLED,
+ this.isNotificationSounds
+ );
},
};
diff --git a/src/font.js b/src/font.js
index 94b1f478..153a26e5 100644
--- a/src/font.js
+++ b/src/font.js
@@ -1,5 +1,5 @@
-import '@fontsource/roboto/300.css';
-import '@fontsource/roboto/400.css';
-import '@fontsource/roboto/500.css';
-import '@fontsource/roboto/700.css';
-import '@fontsource/inter/variable.css';
+import "@fontsource/roboto/300.css";
+import "@fontsource/roboto/400.css";
+import "@fontsource/roboto/500.css";
+import "@fontsource/roboto/700.css";
+import "@fontsource/inter/variable.css";
diff --git a/src/index.jsx b/src/index.jsx
index a252f6f0..b399968a 100644
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -1,12 +1,12 @@
-import React from 'react';
-import ReactDom from 'react-dom';
-import './font';
-import './index.scss';
+import React from "react";
+import ReactDom from "react-dom";
+import "./font";
+import "./index.scss";
-import settings from './client/state/settings';
+import settings from "./client/state/settings";
-import App from './app/pages/App';
+import App from "./app/pages/App";
settings.applyTheme();
-ReactDom.render(
, document.getElementById('root'));
+ReactDom.render(
, document.getElementById("root"));
diff --git a/src/index.scss b/src/index.scss
index 39d0612b..9c5f705b 100644
--- a/src/index.scss
+++ b/src/index.scss
@@ -1,14 +1,13 @@
-@use './app/partials/screen';
+@use "./app/partials/screen";
:root {
-
/* background color | --bg-[background type]: value */
- --bg-surface: #FFFFFF;
- --bg-surface-transparent: #FFFFFF00;
- --bg-surface-low: #F6F6F6;
- --bg-surface-low-transparent: #F6F6F600;
- --bg-surface-extra-low: #F6F6F6;
- --bg-surface-extra-low-transparent: #F6F6F600;
+ --bg-surface: #ffffff;
+ --bg-surface-transparent: #ffffff00;
+ --bg-surface-low: #f6f6f6;
+ --bg-surface-low-transparent: #f6f6f600;
+ --bg-surface-extra-low: #f6f6f6;
+ --bg-surface-extra-low-transparent: #f6f6f600;
--bg-surface-hover: rgba(0, 0, 0, 3%);
--bg-surface-active: rgba(0, 0, 0, 5%);
--bg-surface-border: rgba(0, 0, 0, 6%);
@@ -22,7 +21,7 @@
--bg-positive-hover: rgba(69, 184, 59, 8%);
--bg-positive-active: rgba(69, 184, 59, 15%);
--bg-positive-border: rgba(69, 184, 59, 40%);
-
+
--bg-caution: rgb(255, 179, 0);
--bg-caution-hover: rgba(255, 179, 0, 8%);
--bg-caution-active: rgba(255, 179, 0, 15%);
@@ -37,18 +36,18 @@
--bg-badge: #989898;
--bg-ping: hsla(137deg, 100%, 68%, 40%);
--bg-ping-hover: hsla(137deg, 100%, 68%, 50%);
- --bg-divider: hsla(0, 0%, 0%, .1);
+ --bg-divider: hsla(0, 0%, 0%, 0.1);
/* text color | --tc-[background type]-[priority]: value */
--tc-surface-high: #000000;
--tc-surface-normal: rgba(0, 0, 0, 78%);
--tc-surface-normal-low: rgba(0, 0, 0, 60%);
--tc-surface-low: rgba(0, 0, 0, 48%);
-
+
--tc-primary-high: #ffffff;
--tc-primary-normal: rgba(255, 255, 255, 68%);
--tc-primary-low: rgba(255, 255, 255, 40%);
-
+
--tc-positive-high: var(--bg-positive);
--tc-positive-normal: rgb(69, 184, 59, 80%);
--tc-positive-low: rgb(69, 184, 59, 60%);
@@ -56,7 +55,7 @@
--tc-caution-high: var(--bg-caution);
--tc-caution-normal: rgb(255, 179, 0, 80%);
--tc-caution-low: rgb(255, 179, 0, 60%);
-
+
--tc-danger-high: var(--bg-danger);
--tc-danger-normal: rgba(240, 71, 71, 88%);
--tc-danger-low: rgba(240, 71, 71, 60%);
@@ -66,7 +65,6 @@
--tc-tooltip: white;
--tc-badge: white;
-
/* system icons | --ic-[background type]-[priority]: value */
--ic-surface-high: #272727;
--ic-surface-normal: #626262;
@@ -102,7 +100,6 @@
--av-small: 36px;
--av-extra-small: 24px;
-
/* shadow and overlay */
--bg-overlay: rgba(0, 0, 0, 20%);
--bg-overlay-low: rgba(0, 0, 0, 50%);
@@ -124,11 +121,9 @@
--bs-danger-border: inset 0 0 0 1px var(--bg-danger-border);
--bs-danger-outline: 0 0 0 2px var(--bg-danger-border);
-
/* border */
--bo-radius: 8px;
-
/* font styles: font-size, letter-spacing, line-hight */
--fs-h1: 36px;
--ls-h1: -1.5px;
@@ -160,7 +155,6 @@
--fw-medium: 500;
--fw-bold: 700;
-
/* spacing | --sp-[space]: value */
--sp-none: 0px;
--sp-ultra-tight: 4px;
@@ -170,17 +164,18 @@
--sp-loose: 20px;
--sp-extra-loose: 32px;
-
/* other */
--border-width: 1px;
--header-height: 54px;
--navigation-sidebar-width: calc(64px + var(--border-width));
--navigation-drawer-width: calc(280px + var(--border-width));
- --navigation-width: calc(var(--navigation-sidebar-width) + var(--navigation-drawer-width));
+ --navigation-width: calc(
+ var(--navigation-sidebar-width) + var(--navigation-drawer-width)
+ );
--people-drawer-width: calc(268px - var(--border-width));
--popup-window-drawer-width: 280px;
-
+
@include screen.smallerThan(tabletBreakpoint) {
--navigation-drawer-width: calc(240px + var(--border-width));
--people-drawer-width: calc(256px - var(--border-width));
@@ -191,11 +186,10 @@
--fluid-push: cubic-bezier(0, 0.8, 0.67, 0.97);
--fluid-slide-down: cubic-bezier(0.02, 0.82, 0.4, 0.96);
--fluid-slide-up: cubic-bezier(0.13, 0.56, 0.25, 0.99);
-
- --font-primary: 'Roboto', sans-serif;
- --font-secondary: 'Roboto', sans-serif;
-}
+ --font-primary: "Roboto", sans-serif;
+ --font-secondary: "Roboto", sans-serif;
+}
.silver-theme {
/* background color | --bg-[background type]: value */
@@ -228,15 +222,14 @@
--bg-badge: hsl(0, 0%, 75%);
--bg-ping: hsla(137deg, 100%, 38%, 40%);
--bg-ping-hover: hsla(137deg, 100%, 38%, 50%);
- --bg-divider: hsla(0, 0%, 100%, .1);
-
+ --bg-divider: hsla(0, 0%, 100%, 0.1);
/* text color | --tc-[background type]-[priority]: value */
--tc-surface-high: rgba(255, 255, 255, 98%);
--tc-surface-normal: rgba(255, 255, 255, 94%);
--tc-surface-normal-low: rgba(255, 255, 255, 60%);
--tc-surface-low: rgba(255, 255, 255, 58%);
-
+
--tc-primary-high: #ffffff;
--tc-primary-normal: rgba(255, 255, 255, 0.68);
--tc-primary-low: rgba(255, 255, 255, 0.4);
@@ -262,7 +255,7 @@
--mx-uc-7: hsl(243, 100%, 74%);
--mx-uc-8: hsl(94, 66%, 50%);
}
-
+
/* shadow and overlay */
--bg-overlay: rgba(0, 0, 0, 60%);
--bg-overlay-low: rgba(0, 0, 0, 80%);
@@ -274,7 +267,7 @@
--bs-primary-border: inset 0 0 0 1px var(--bg-primary-border);
--bs-primary-outline: 0 0 0 2px var(--bg-primary-border);
-
+
/* font styles: font-size, letter-spacing, line-hight */
--fs-h1: 35.6px;
@@ -292,7 +285,7 @@
/* override normal font weight for dark mode */
--fw-normal: 350;
- --font-secondary: 'InterVariable', 'Roboto', sans-serif;
+ --font-secondary: "InterVariable", "Roboto", sans-serif;
}
.dark-theme,
@@ -317,14 +310,12 @@
--bg-badge: #c4c1ab;
-
/* text color | --tc-[background type]-[priority]: value */
--tc-surface-high: rgb(255, 251, 222, 94%);
--tc-surface-normal: rgba(255, 251, 222, 94%);
- --tc-surface-normal-low: rgba(255, 251, 222, 60%);
+ --tc-surface-normal-low: rgba(255, 251, 222, 60%);
--tc-surface-low: rgba(255, 251, 222, 58%);
-
/* system icons | --ic-[background type]-[priority]: value */
--ic-surface-high: rgb(255, 251, 222);
--ic-surface-normal: rgba(255, 251, 222, 84%);
@@ -387,9 +378,11 @@ body {
height: 100%;
}
-*, *::before, *::after {
+*,
+*::before,
+*::after {
box-sizing: border-box;
- -webkit-tap-highlight-color: rgba(0,0,0,0);
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-tap-highlight-color: transparent;
}
a {
@@ -428,16 +421,16 @@ button {
textarea,
input,
input[type],
-input[type=text],
-input[type=username],
-input[type=password],
-input[type=email],
-input[type=checkbox] {
+input[type="text"],
+input[type="username"],
+input[type="password"],
+input[type="email"],
+input[type="checkbox"] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
-input[type=checkbox] {
+input[type="checkbox"] {
margin: 0;
padding: 0;
width: 20px;
@@ -468,11 +461,11 @@ textarea {
}
.noselect {
-webkit-touch-callout: none; /* iOS Safari */
- -webkit-user-select: none; /* Safari */
- -khtml-user-select: none; /* Konqueror HTML */
- -moz-user-select: none; /* Old versions of Firefox */
- -ms-user-select: none; /* Internet Explorer/Edge */
- user-select: none; /* Non-prefixed version, currently
+ -webkit-user-select: none; /* Safari */
+ -khtml-user-select: none; /* Konqueror HTML */
+ -moz-user-select: none; /* Old versions of Firefox */
+ -ms-user-select: none; /* Internet Explorer/Edge */
+ user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
}
@@ -484,4 +477,4 @@ audio:not([controls]) {
display: flex;
justify-content: center;
align-items: center;
-}
\ No newline at end of file
+}
diff --git a/src/util/AsyncSearch.js b/src/util/AsyncSearch.js
index d0a2130e..af961a4d 100644
--- a/src/util/AsyncSearch.js
+++ b/src/util/AsyncSearch.js
@@ -1,4 +1,4 @@
-import EventEmitter from 'events';
+import EventEmitter from "events";
class AsyncSearch extends EventEmitter {
constructor() {
@@ -6,7 +6,7 @@ class AsyncSearch extends EventEmitter {
this._reset();
- this.RESULT_SENT = 'RESULT_SENT';
+ this.RESULT_SENT = "RESULT_SENT";
}
_reset() {
@@ -59,7 +59,7 @@ class AsyncSearch extends EventEmitter {
this._softReset();
this.term = this._normalize(term);
- if (this.term === '') {
+ if (this.term === "") {
this._sendFindings();
return;
}
@@ -78,7 +78,11 @@ class AsyncSearch extends EventEmitter {
) {
if (this._match(this.dataList[searchIndex])) {
this.findingList.push(this.dataList[searchIndex]);
- if (typeof this.limit === 'number' && this.findingList.length >= this.limit) break;
+ if (
+ typeof this.limit === "number" &&
+ this.findingList.length >= this.limit
+ )
+ break;
}
const calcFinishTime = window.performance.now();
@@ -93,20 +97,20 @@ class AsyncSearch extends EventEmitter {
}
}
- if (lastFindingCount !== this.findingList.length
- || lastFindingCount === 0) this._sendFindings();
+ if (lastFindingCount !== this.findingList.length || lastFindingCount === 0)
+ this._sendFindings();
this._softReset();
}
_match(item) {
- if (typeof item === 'string') {
+ if (typeof item === "string") {
return this._compare(item);
}
- if (typeof item === 'object') {
+ if (typeof item === "object") {
if (Array.isArray(this.searchKeys)) {
return !!this.searchKeys.find((key) => this._compare(item[key]));
}
- if (typeof this.searchKeys === 'string') {
+ if (typeof this.searchKeys === "string") {
return this._compare(item[this.searchKeys]);
}
}
@@ -114,16 +118,16 @@ class AsyncSearch extends EventEmitter {
}
_compare(item) {
- if (typeof item !== 'string') return false;
+ if (typeof item !== "string") return false;
const myItem = this._normalize(item);
if (this.isContain) return myItem.indexOf(this.term) !== -1;
return myItem.startsWith(this.term);
}
_normalize(item) {
- let myItem = item.normalize(this.normalizeUnicode ? 'NFKC' : 'NFC');
+ let myItem = item.normalize(this.normalizeUnicode ? "NFKC" : "NFC");
if (!this.isCaseSensitive) myItem = myItem.toLocaleLowerCase();
- if (this.ignoreWhitespace) myItem = myItem.replace(/\s/g, '');
+ if (this.ignoreWhitespace) myItem = myItem.replace(/\s/g, "");
return myItem;
}
diff --git a/src/util/Postie.js b/src/util/Postie.js
index 73c8f9e8..5d796931 100644
--- a/src/util/Postie.js
+++ b/src/util/Postie.js
@@ -15,7 +15,9 @@ class Postie {
const subscribers = this._getSubscribers(topic);
const inboxes = subscribers.get(address);
if (inboxes === undefined) {
- throw new Error(`Inbox on topic:"${topic}" at address:"${address}" doesn't exist.`);
+ throw new Error(
+ `Inbox on topic:"${topic}" at address:"${address}" doesn't exist.`
+ );
}
return inboxes;
}
@@ -30,9 +32,7 @@ class Postie {
}
hasTopicAndSubscriber(topic, address) {
- return (this.hasTopic(topic))
- ? this.hasSubscriber(topic, address)
- : false;
+ return this.hasTopic(topic) ? this.hasSubscriber(topic, address) : false;
}
/**
@@ -41,8 +41,8 @@ class Postie {
* @param {function} inbox - The inbox function to receive post data
*/
subscribe(topic, address, inbox) {
- if (typeof inbox !== 'function') {
- throw new TypeError('Inbox must be a function.');
+ if (typeof inbox !== "function") {
+ throw new TypeError("Inbox must be a function.");
}
if (this._topics.has(topic) === false) {
@@ -59,12 +59,19 @@ class Postie {
unsubscribe(topic, address, inbox) {
const subscribers = this._getSubscribers(topic);
- if (!subscribers) throw new Error(`Unable to unsubscribe. Topic: "${topic}" doesn't exist.`);
+ if (!subscribers)
+ throw new Error(
+ `Unable to unsubscribe. Topic: "${topic}" doesn't exist.`
+ );
const inboxes = subscribers.get(address);
- if (!inboxes) throw new Error(`Unable to unsubscribe. Subscriber on topic:"${topic}" at address:"${address}" doesn't exist`);
+ if (!inboxes)
+ throw new Error(
+ `Unable to unsubscribe. Subscriber on topic:"${topic}" at address:"${address}" doesn't exist`
+ );
- if (!inboxes.delete(inbox)) throw new Error('Unable to unsubscribe. Inbox doesn\'t exist');
+ if (!inboxes.delete(inbox))
+ throw new Error("Unable to unsubscribe. Inbox doesn't exist");
if (inboxes.size === 0) subscribers.delete(address);
if (subscribers.size === 0) this._topics.delete(topic);
@@ -78,12 +85,14 @@ class Postie {
post(topic, address, data) {
const sendPost = (inboxes, addr) => {
if (inboxes === undefined) {
- throw new Error(`Unable to post on topic:"${topic}" at address:"${addr}". Subscriber doesn't exist.`);
+ throw new Error(
+ `Unable to post on topic:"${topic}" at address:"${addr}". Subscriber doesn't exist.`
+ );
}
inboxes.forEach((inbox) => inbox(data));
};
- if (typeof address === 'string') {
+ if (typeof address === "string") {
sendPost(this._getInboxes(topic, address), address);
return;
}
diff --git a/src/util/colorMXID.js b/src/util/colorMXID.js
index 4d303aae..75c70a0d 100644
--- a/src/util/colorMXID.js
+++ b/src/util/colorMXID.js
@@ -10,7 +10,7 @@ export function hashCode(str) {
for (i = 0; i < str.length; i += 1) {
chr = str.charCodeAt(i);
// eslint-disable-next-line no-bitwise
- hash = ((hash << 5) - hash) + chr;
+ hash = (hash << 5) - hash + chr;
// eslint-disable-next-line no-bitwise
hash |= 0;
}
diff --git a/src/util/common.js b/src/util/common.js
index 2affe27d..f2e261c6 100644
--- a/src/util/common.js
+++ b/src/util/common.js
@@ -1,10 +1,10 @@
/* eslint-disable max-classes-per-file */
export function bytesToSize(bytes) {
- const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
- if (bytes === 0) return 'n/a';
+ const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
+ if (bytes === 0) return "n/a";
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10);
if (i === 0) return `${bytes} ${sizes[i]}`;
- return `${(bytes / (1024 ** i)).toFixed(1)} ${sizes[i]}`;
+ return `${(bytes / 1024 ** i).toFixed(1)} ${sizes[i]}`;
}
export function diffMinutes(dt2, dt1) {
@@ -15,9 +15,9 @@ export function diffMinutes(dt2, dt1) {
export function isInSameDay(dt2, dt1) {
return (
- dt2.getFullYear() === dt1.getFullYear()
- && dt2.getMonth() === dt1.getMonth()
- && dt2.getDate() === dt1.getDate()
+ dt2.getFullYear() === dt1.getFullYear() &&
+ dt2.getMonth() === dt1.getMonth() &&
+ dt2.getDate() === dt1.getDate()
);
}
@@ -48,7 +48,7 @@ export function getEventCords(ev, targetSelector) {
}
export function abbreviateNumber(number) {
- if (number > 99) return '99+';
+ if (number > 99) return "99+";
return number;
}
@@ -120,9 +120,9 @@ export function cssVar(name) {
}
export function setFavicon(url) {
- const favicon = document.querySelector('#favicon');
+ const favicon = document.querySelector("#favicon");
if (!favicon) return;
- favicon.setAttribute('href', url);
+ favicon.setAttribute("href", url);
}
export function copyToClipboard(text) {
@@ -130,15 +130,15 @@ export function copyToClipboard(text) {
navigator.clipboard.writeText(text);
} else {
const host = document.body;
- const copyInput = document.createElement('input');
- copyInput.style.position = 'fixed';
- copyInput.style.opacity = '0';
+ const copyInput = document.createElement("input");
+ copyInput.style.position = "fixed";
+ copyInput.style.opacity = "0";
copyInput.value = text;
host.append(copyInput);
copyInput.select();
copyInput.setSelectionRange(0, 99999);
- document.execCommand('Copy');
+ document.execCommand("Copy");
copyInput.remove();
}
}
@@ -189,10 +189,10 @@ export function scaleDownImage(imageFile, width, height) {
newWidth = width;
}
- const canvas = document.createElement('canvas');
+ const canvas = document.createElement("canvas");
canvas.width = newWidth;
canvas.height = newHeight;
- const ctx = canvas.getContext('2d');
+ const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, newWidth, newHeight);
canvas.toBlob((thumbnail) => {
@@ -212,7 +212,7 @@ export function scaleDownImage(imageFile, width, height) {
* @returns {RegExp}
*/
export function idRegex(sigil, flags, prefix) {
- const servername = '(?:[a-zA-Z0-9-.]*[a-zA-Z0-9]+|\\[\\S+?\\])(?::\\d+)?';
+ const servername = "(?:[a-zA-Z0-9-.]*[a-zA-Z0-9]+|\\[\\S+?\\])(?::\\d+)?";
return new RegExp(`${prefix}(${sigil}\\S+:${servername})`, flags);
}
diff --git a/src/util/cryptE2ERoomKeys.js b/src/util/cryptE2ERoomKeys.js
index 50254a3c..219c65be 100644
--- a/src/util/cryptE2ERoomKeys.js
+++ b/src/util/cryptE2ERoomKeys.js
@@ -17,7 +17,7 @@ function friendlyError(msg, friendlyText) {
}
function cryptoFailMsg() {
- return 'Your browser does not support the required cryptography extensions';
+ return "Your browser does not support the required cryptography extensions";
}
/**
* Derive the AES and HMAC-SHA-256 keys for the file
@@ -33,11 +33,11 @@ async function deriveKeys(salt, iterations, password) {
let key;
try {
key = await subtleCrypto.importKey(
- 'raw',
+ "raw",
new TextEncoder().encode(password),
- { name: 'PBKDF2' },
+ { name: "PBKDF2" },
false,
- ['deriveBits'],
+ ["deriveBits"]
);
} catch (e) {
throw friendlyError(`subtleCrypto.importKey failed: ${e}`, cryptoFailMsg());
@@ -47,46 +47,56 @@ async function deriveKeys(salt, iterations, password) {
try {
keybits = await subtleCrypto.deriveBits(
{
- name: 'PBKDF2',
+ name: "PBKDF2",
salt,
iterations,
- hash: 'SHA-512',
+ hash: "SHA-512",
},
key,
- 512,
+ 512
);
} catch (e) {
- throw friendlyError(`subtleCrypto.deriveBits failed: ${e}`, cryptoFailMsg());
+ throw friendlyError(
+ `subtleCrypto.deriveBits failed: ${e}`,
+ cryptoFailMsg()
+ );
}
const now = new Date();
- console.log(`E2e import/export: deriveKeys took ${(now - start)}ms`);
+ console.log(`E2e import/export: deriveKeys took ${now - start}ms`);
const aesKey = keybits.slice(0, 32);
const hmacKey = keybits.slice(32);
- const aesProm = subtleCrypto.importKey(
- 'raw',
- aesKey,
- { name: 'AES-CTR' },
- false,
- ['encrypt', 'decrypt'],
- ).catch((e) => {
- throw friendlyError(`subtleCrypto.importKey failed for AES key: ${e}`, cryptoFailMsg());
- });
+ const aesProm = subtleCrypto
+ .importKey("raw", aesKey, { name: "AES-CTR" }, false, [
+ "encrypt",
+ "decrypt",
+ ])
+ .catch((e) => {
+ throw friendlyError(
+ `subtleCrypto.importKey failed for AES key: ${e}`,
+ cryptoFailMsg()
+ );
+ });
- const hmacProm = subtleCrypto.importKey(
- 'raw',
- hmacKey,
- {
- name: 'HMAC',
- hash: { name: 'SHA-256' },
- },
- false,
- ['sign', 'verify'],
- ).catch((e) => {
- throw friendlyError(`subtleCrypto.importKey failed for HMAC key: ${e}`, cryptoFailMsg());
- });
+ const hmacProm = subtleCrypto
+ .importKey(
+ "raw",
+ hmacKey,
+ {
+ name: "HMAC",
+ hash: { name: "SHA-256" },
+ },
+ false,
+ ["sign", "verify"]
+ )
+ .catch((e) => {
+ throw friendlyError(
+ `subtleCrypto.importKey failed for HMAC key: ${e}`,
+ cryptoFailMsg()
+ );
+ });
// eslint-disable-next-line no-return-await
return await Promise.all([aesProm, hmacProm]);
@@ -121,8 +131,8 @@ function encodeBase64(uint8Array) {
return window.btoa(latin1String);
}
-const HEADER_LINE = '-----BEGIN MEGOLM SESSION DATA-----';
-const TRAILER_LINE = '-----END MEGOLM SESSION DATA-----';
+const HEADER_LINE = "-----BEGIN MEGOLM SESSION DATA-----";
+const TRAILER_LINE = "-----END MEGOLM SESSION DATA-----";
/**
* Unbase64 an ascii-armoured megolm key file
@@ -141,9 +151,9 @@ function unpackMegolmKeyFile(data) {
// look for the start line
let lineStart = 0;
while (1) {
- const lineEnd = fileStr.indexOf('\n', lineStart);
+ const lineEnd = fileStr.indexOf("\n", lineStart);
if (lineEnd < 0) {
- throw new Error('Header line not found');
+ throw new Error("Header line not found");
}
const line = fileStr.slice(lineStart, lineEnd).trim();
@@ -159,14 +169,16 @@ function unpackMegolmKeyFile(data) {
// look for the end line
while (1) {
- const lineEnd = fileStr.indexOf('\n', lineStart);
- const line = fileStr.slice(lineStart, lineEnd < 0 ? undefined : lineEnd).trim();
+ const lineEnd = fileStr.indexOf("\n", lineStart);
+ const line = fileStr
+ .slice(lineStart, lineEnd < 0 ? undefined : lineEnd)
+ .trim();
if (line === TRAILER_LINE) {
break;
}
if (lineEnd < 0) {
- throw new Error('Trailer line not found');
+ throw new Error("Trailer line not found");
}
// start the next line after the newline
@@ -177,7 +189,6 @@ function unpackMegolmKeyFile(data) {
return decodeBase64(fileStr.slice(dataStart, dataEnd));
}
-
/**
* ascii-armour a megolm key file
*
@@ -189,20 +200,20 @@ function unpackMegolmKeyFile(data) {
function packMegolmKeyFile(data) {
// we split into lines before base64ing, because encodeBase64 doesn't deal
// terribly well with large arrays.
- const LINE_LENGTH = ((72 * 4) / 3);
+ const LINE_LENGTH = (72 * 4) / 3;
const nLines = Math.ceil(data.length / LINE_LENGTH);
const lines = new Array(nLines + 3);
lines[0] = HEADER_LINE;
let o = 0;
let i;
for (i = 1; i <= nLines; i += 1) {
- lines[i] = encodeBase64(data.subarray(o, o+LINE_LENGTH));
+ lines[i] = encodeBase64(data.subarray(o, o + LINE_LENGTH));
o += LINE_LENGTH;
}
lines[i] = TRAILER_LINE;
i += 1;
- lines[i] = '';
- return (new TextEncoder().encode(lines.join('\n'))).buffer;
+ lines[i] = "";
+ return new TextEncoder().encode(lines.join("\n")).buffer;
}
export async function decryptMegolmKeyFile(data, password) {
@@ -210,22 +221,23 @@ export async function decryptMegolmKeyFile(data, password) {
// check we have a version byte
if (body.length < 1) {
- throw friendlyError('Invalid file: too short', 'Not a valid keyfile');
+ throw friendlyError("Invalid file: too short", "Not a valid keyfile");
}
const version = body[0];
if (version !== 1) {
- throw friendlyError('Unsupported version', 'Not a valid keyfile');
+ throw friendlyError("Unsupported version", "Not a valid keyfile");
}
const ciphertextLength = body.length - (1 + 16 + 16 + 4 + 32);
if (ciphertextLength < 0) {
- throw friendlyError('Invalid file: too short', 'Not a valid keyfile');
+ throw friendlyError("Invalid file: too short", "Not a valid keyfile");
}
const salt = body.subarray(1, 1 + 16);
const iv = body.subarray(17, 17 + 16);
- const iterations = body[33] << 24 | body[34] << 16 | body[35] << 8 | body[36];
+ const iterations =
+ (body[33] << 24) | (body[34] << 16) | (body[35] << 8) | body[36];
const ciphertext = body.subarray(37, 37 + ciphertextLength);
const hmac = body.subarray(-32);
@@ -235,28 +247,31 @@ export async function decryptMegolmKeyFile(data, password) {
let isValid;
try {
isValid = await subtleCrypto.verify(
- { name: 'HMAC' },
+ { name: "HMAC" },
hmacKey,
hmac,
- toVerify,
+ toVerify
);
} catch (e) {
throw friendlyError(`subtleCrypto.verify failed: ${e}`, cryptoFailMsg());
}
if (!isValid) {
- throw friendlyError('hmac mismatch', 'Authentication check failed: Incorrect password?');
+ throw friendlyError(
+ "hmac mismatch",
+ "Authentication check failed: Incorrect password?"
+ );
}
let plaintext;
try {
plaintext = await subtleCrypto.decrypt(
{
- name: 'AES-CTR',
+ name: "AES-CTR",
counter: iv,
length: 64,
},
aesKey,
- ciphertext,
+ ciphertext
);
} catch (e) {
throw friendlyError(`subtleCrypto.decrypt failed: ${e}`, cryptoFailMsg());
@@ -297,41 +312,40 @@ export async function encryptMegolmKeyFile(data, password, options) {
try {
ciphertext = await subtleCrypto.encrypt(
{
- name: 'AES-CTR',
+ name: "AES-CTR",
counter: iv,
length: 64,
},
aesKey,
- encodedData,
+ encodedData
);
} catch (e) {
- throw friendlyError('subtleCrypto.encrypt failed: ' + e, cryptoFailMsg());
+ throw friendlyError("subtleCrypto.encrypt failed: " + e, cryptoFailMsg());
}
const cipherArray = new Uint8Array(ciphertext);
- const bodyLength = (1+salt.length+iv.length+4+cipherArray.length+32);
+ const bodyLength = 1 + salt.length + iv.length + 4 + cipherArray.length + 32;
const resultBuffer = new Uint8Array(bodyLength);
let idx = 0;
resultBuffer[idx++] = 1; // version
- resultBuffer.set(salt, idx); idx += salt.length;
- resultBuffer.set(iv, idx); idx += iv.length;
+ resultBuffer.set(salt, idx);
+ idx += salt.length;
+ resultBuffer.set(iv, idx);
+ idx += iv.length;
resultBuffer[idx++] = kdfRounds >> 24;
resultBuffer[idx++] = (kdfRounds >> 16) & 0xff;
resultBuffer[idx++] = (kdfRounds >> 8) & 0xff;
resultBuffer[idx++] = kdfRounds & 0xff;
- resultBuffer.set(cipherArray, idx); idx += cipherArray.length;
+ resultBuffer.set(cipherArray, idx);
+ idx += cipherArray.length;
const toSign = resultBuffer.subarray(0, idx);
let hmac;
try {
- hmac = await subtleCrypto.sign(
- { name: 'HMAC' },
- hmacKey,
- toSign,
- );
+ hmac = await subtleCrypto.sign({ name: "HMAC" }, hmacKey, toSign);
} catch (e) {
- throw friendlyError('subtleCrypto.sign failed: ' + e, cryptoFailMsg());
+ throw friendlyError("subtleCrypto.sign failed: " + e, cryptoFailMsg());
}
const hmacArray = new Uint8Array(hmac);
diff --git a/src/util/markdown.js b/src/util/markdown.js
index c6c1a490..f0001d1f 100644
--- a/src/util/markdown.js
+++ b/src/util/markdown.js
@@ -1,15 +1,21 @@
/* eslint-disable no-param-reassign */
/* eslint-disable no-use-before-define */
-import SimpleMarkdown from '@khanacademy/simple-markdown';
-import { idRegex, parseIdUri } from './common';
+import SimpleMarkdown from "@khanacademy/simple-markdown";
+import { idRegex, parseIdUri } from "./common";
const {
- defaultRules, parserFor, outputFor, anyScopeRegex, blockRegex, inlineRegex,
- sanitizeText, sanitizeUrl,
+ defaultRules,
+ parserFor,
+ outputFor,
+ anyScopeRegex,
+ blockRegex,
+ inlineRegex,
+ sanitizeText,
+ sanitizeUrl,
} = SimpleMarkdown;
function htmlTag(tagName, content, attributes, isClosed) {
- let s = '';
+ let s = "";
Object.entries(attributes || {}).forEach(([k, v]) => {
if (v !== undefined) {
s += ` ${sanitizeText(k)}`;
@@ -26,7 +32,9 @@ function htmlTag(tagName, content, attributes, isClosed) {
}
function mathHtml(wrap, node) {
- return htmlTag(wrap, htmlTag('code', sanitizeText(node.content)), { 'data-mx-maths': node.content });
+ return htmlTag(wrap, htmlTag("code", sanitizeText(node.content)), {
+ "data-mx-maths": node.content,
+ });
}
const emojiRegex = /^:([\w-]+):/;
@@ -38,23 +46,30 @@ const plainRules = {
},
userMention: {
order: defaultRules.em.order - 0.9,
- match: inlineRegex(idRegex('@', undefined, '^')),
+ match: inlineRegex(idRegex("@", undefined, "^")),
parse: (capture, _, state) => ({
- type: 'mention',
- content: state.userNames[capture[1]] ? `@${state.userNames[capture[1]]}` : capture[1],
+ type: "mention",
+ content: state.userNames[capture[1]]
+ ? `@${state.userNames[capture[1]]}`
+ : capture[1],
id: capture[1],
}),
},
roomMention: {
order: defaultRules.em.order - 0.8,
- match: inlineRegex(idRegex('#', undefined, '^')),
- parse: (capture) => ({ type: 'mention', content: capture[1], id: capture[1] }),
+ match: inlineRegex(idRegex("#", undefined, "^")),
+ parse: (capture) => ({
+ type: "mention",
+ content: capture[1],
+ id: capture[1],
+ }),
},
mention: {
- plain: (node, _, state) => (state.kind === 'edit' ? node.id : node.content),
- html: (node) => htmlTag('a', sanitizeText(node.content), {
- href: `https://matrix.to/#/${encodeURIComponent(node.id)}`,
- }),
+ plain: (node, _, state) => (state.kind === "edit" ? node.id : node.content),
+ html: (node) =>
+ htmlTag("a", sanitizeText(node.content), {
+ href: `https://matrix.to/#/${encodeURIComponent(node.id)}`,
+ }),
},
emoji: {
order: defaultRules.em.order - 0.1,
@@ -66,28 +81,35 @@ const plainRules = {
if (emoji) return capture;
return null;
},
- parse: (capture, _, state) => ({ content: capture[1], emoji: state.emojis.get(capture[1]) }),
- plain: ({ emoji }) => (emoji.mxc
- ? `:${emoji.shortcode}:`
- : emoji.unicode),
- html: ({ emoji }) => (emoji.mxc
- ? htmlTag('img', null, {
- 'data-mx-emoticon': null,
- src: emoji.mxc,
- alt: `:${emoji.shortcode}:`,
- title: `:${emoji.shortcode}:`,
- height: 32,
- }, false)
- : emoji.unicode),
+ parse: (capture, _, state) => ({
+ content: capture[1],
+ emoji: state.emojis.get(capture[1]),
+ }),
+ plain: ({ emoji }) => (emoji.mxc ? `:${emoji.shortcode}:` : emoji.unicode),
+ html: ({ emoji }) =>
+ emoji.mxc
+ ? htmlTag(
+ "img",
+ null,
+ {
+ "data-mx-emoticon": null,
+ src: emoji.mxc,
+ alt: `:${emoji.shortcode}:`,
+ title: `:${emoji.shortcode}:`,
+ height: 32,
+ },
+ false
+ )
+ : emoji.unicode,
},
newline: {
...defaultRules.newline,
- plain: () => '\n',
+ plain: () => "\n",
},
paragraph: {
...defaultRules.paragraph,
plain: (node, output, state) => `${output(node.content, state)}\n\n`,
- html: (node, output, state) => htmlTag('p', output(node.content, state)),
+ html: (node, output, state) => htmlTag("p", output(node.content, state)),
},
escape: {
...defaultRules.escape,
@@ -96,14 +118,17 @@ const plainRules = {
br: {
...defaultRules.br,
match: anyScopeRegex(/^ *\n/),
- plain: () => '\n',
+ plain: () => "\n",
},
text: {
...defaultRules.text,
- match: anyScopeRegex(/^[\s\S]+?(?=[^0-9A-Za-z\s\u00c0-\uffff]| *\n|\w+:\S|$)/),
- plain: (node, _, state) => (state.kind === 'edit'
- ? node.content.replace(/(\*|_|!\[|\[|\|\||\$\$?)/g, '\\$1')
- : node.content),
+ match: anyScopeRegex(
+ /^[\s\S]+?(?=[^0-9A-Za-z\s\u00c0-\uffff]| *\n|\w+:\S|$)/
+ ),
+ plain: (node, _, state) =>
+ state.kind === "edit"
+ ? node.content.replace(/(\*|_|!\[|\[|\|\||\$\$?)/g, "\\$1")
+ : node.content,
},
};
@@ -115,30 +140,41 @@ const markdownRules = {
match: blockRegex(/^ *(#{1,6})([^\n:]*?(?: [^\n]*?)?)#* *(?:\n *)*\n/),
plain: (node, output, state) => {
const out = output(node.content, state);
- if (state.kind === 'edit' || state.kind === 'notification' || node.level > 2) {
- return `${'#'.repeat(node.level)} ${out}\n\n`;
+ if (
+ state.kind === "edit" ||
+ state.kind === "notification" ||
+ node.level > 2
+ ) {
+ return `${"#".repeat(node.level)} ${out}\n\n`;
}
- return `${out}\n${(node.level === 1 ? '=' : '-').repeat(out.length)}\n\n`;
+ return `${out}\n${(node.level === 1 ? "=" : "-").repeat(out.length)}\n\n`;
},
},
hr: {
...defaultRules.hr,
- plain: () => '---\n\n',
+ plain: () => "---\n\n",
},
codeBlock: {
...defaultRules.codeBlock,
- plain: (node) => `\`\`\`${node.lang || ''}\n${node.content}\n\`\`\`\n`,
- html: (node) => htmlTag('pre', htmlTag('code', sanitizeText(node.content), {
- class: node.lang ? `language-${node.lang}` : undefined,
- })),
+ plain: (node) => `\`\`\`${node.lang || ""}\n${node.content}\n\`\`\`\n`,
+ html: (node) =>
+ htmlTag(
+ "pre",
+ htmlTag("code", sanitizeText(node.content), {
+ class: node.lang ? `language-${node.lang}` : undefined,
+ })
+ ),
},
fence: {
...defaultRules.fence,
- match: blockRegex(/^ *(`{3,}|~{3,}) *(?:(\S+) *)?\n([\s\S]+?)\n?\1 *(?:\n *)*\n/),
+ match: blockRegex(
+ /^ *(`{3,}|~{3,}) *(?:(\S+) *)?\n([\s\S]+?)\n?\1 *(?:\n *)*\n/
+ ),
},
blockQuote: {
...defaultRules.blockQuote,
- plain: (node, output, state) => `> ${output(node.content, state).trim().replace(/\n/g, '\n> ')}\n\n`,
+ plain: (node, output, state) =>
+ `> ${output(node.content, state).trim().replace(/\n/g, "\n> ")}\n\n`,
},
list: {
...defaultRules.list,
@@ -146,15 +182,20 @@ const markdownRules = {
const oldList = state._list;
state._list = true;
- let items = node.items.map((item, i) => {
- const prefix = node.ordered ? `${node.start + i}. ` : '* ';
- return prefix + output(item, state).replace(/\n/g, `\n${' '.repeat(prefix.length)}`);
- }).join('\n');
+ let items = node.items
+ .map((item, i) => {
+ const prefix = node.ordered ? `${node.start + i}. ` : "* ";
+ return (
+ prefix +
+ output(item, state).replace(/\n/g, `\n${" ".repeat(prefix.length)}`)
+ );
+ })
+ .join("\n");
state._list = oldList;
if (!state._list) {
- items += '\n\n';
+ items += "\n\n";
}
return items;
},
@@ -167,32 +208,34 @@ const markdownRules = {
const colWidth = node.align.map((align) => {
switch (align) {
- case 'left':
- case 'right':
+ case "left":
+ case "right":
return 2;
- case 'center':
+ case "center":
return 3;
default:
return 1;
}
});
header.forEach((s, i) => {
- if (s.length > colWidth[i])colWidth[i] = s.length;
+ if (s.length > colWidth[i]) colWidth[i] = s.length;
});
- const cells = node.cells.map((row) => row.map((content, i) => {
- const s = output(content, state);
- if (colWidth[i] === undefined || s.length > colWidth[i]) {
- colWidth[i] = s.length;
- }
- return s;
- }));
+ const cells = node.cells.map((row) =>
+ row.map((content, i) => {
+ const s = output(content, state);
+ if (colWidth[i] === undefined || s.length > colWidth[i]) {
+ colWidth[i] = s.length;
+ }
+ return s;
+ })
+ );
function pad(s, i) {
switch (node.align[i]) {
- case 'right':
+ case "right":
return s.padStart(colWidth[i]);
- case 'center':
+ case "center":
return s
.padStart(s.length + Math.floor((colWidth[i] - s.length) / 2))
.padEnd(colWidth[i]);
@@ -203,58 +246,60 @@ const markdownRules = {
const line = colWidth.map((len, i) => {
switch (node.align[i]) {
- case 'left':
- return `:${'-'.repeat(len - 1)}`;
- case 'center':
- return `:${'-'.repeat(len - 2)}:`;
- case 'right':
- return `${'-'.repeat(len - 1)}:`;
+ case "left":
+ return `:${"-".repeat(len - 1)}`;
+ case "center":
+ return `:${"-".repeat(len - 2)}:`;
+ case "right":
+ return `${"-".repeat(len - 1)}:`;
default:
- return '-'.repeat(len);
+ return "-".repeat(len);
}
});
const table = [
header.map(pad),
line,
- ...cells.map((row) => row.map(pad))];
+ ...cells.map((row) => row.map(pad)),
+ ];
- return table.map((row) => `| ${row.join(' | ')} |\n`).join('');
+ return table.map((row) => `| ${row.join(" | ")} |\n`).join("");
},
},
displayMath: {
order: defaultRules.table.order + 0.1,
match: blockRegex(/^ *\$\$ *\n?([\s\S]+?)\n?\$\$ *(?:\n *)*\n/),
parse: (capture) => ({ content: capture[1] }),
- plain: (node) => (node.content.includes('\n')
- ? `$$\n${node.content}\n$$\n`
- : `$$${node.content}$$\n`),
- html: (node) => mathHtml('div', node),
+ plain: (node) =>
+ node.content.includes("\n")
+ ? `$$\n${node.content}\n$$\n`
+ : `$$${node.content}$$\n`,
+ html: (node) => mathHtml("div", node),
},
shrug: {
order: defaultRules.escape.order - 0.1,
match: inlineRegex(/^¯\\_\(ツ\)_\/¯/),
- parse: (capture) => ({ type: 'text', content: capture[0] }),
+ parse: (capture) => ({ type: "text", content: capture[0] }),
},
tableSeparator: {
...defaultRules.tableSeparator,
- plain: () => ' | ',
+ plain: () => " | ",
},
link: {
...defaultRules.link,
plain: (node, output, state) => {
const out = output(node.content, state);
- const target = sanitizeUrl(node.target) || '';
+ const target = sanitizeUrl(node.target) || "";
if (out !== target || node.title) {
- return `[${out}](${target}${node.title ? ` "${node.title}"` : ''})`;
+ return `[${out}](${target}${node.title ? ` "${node.title}"` : ""})`;
}
return out;
},
html: (node, output, state) => {
const out = output(node.content, state);
- const target = sanitizeUrl(node.target) || '';
+ const target = sanitizeUrl(node.target) || "";
if (out !== target || node.title) {
- return htmlTag('a', out, {
+ return htmlTag("a", out, {
href: target,
title: node.title,
});
@@ -264,12 +309,21 @@ const markdownRules = {
},
image: {
...defaultRules.image,
- plain: (node) => `![${node.alt}](${sanitizeUrl(node.target) || ''}${node.title ? ` "${node.title}"` : ''})`,
- html: (node) => htmlTag('img', '', {
- src: sanitizeUrl(node.target) || '',
- alt: node.alt,
- title: node.title,
- }, false),
+ plain: (node) =>
+ `![${node.alt}](${sanitizeUrl(node.target) || ""}${
+ node.title ? ` "${node.title}"` : ""
+ })`,
+ html: (node) =>
+ htmlTag(
+ "img",
+ "",
+ {
+ src: sanitizeUrl(node.target) || "",
+ alt: node.alt,
+ title: node.title,
+ },
+ false
+ ),
},
reflink: undefined,
refimage: undefined,
@@ -302,55 +356,62 @@ const markdownRules = {
reason: capture[2],
}),
plain: (node, output, state) => {
- const warning = `spoiler${node.reason ? `: ${node.reason}` : ''}`;
+ const warning = `spoiler${node.reason ? `: ${node.reason}` : ""}`;
switch (state.kind) {
- case 'edit':
- return `||${output(node.content, state)}||${node.reason ? `(${node.reason})` : ''}`;
- case 'notification':
+ case "edit":
+ return `||${output(node.content, state)}||${
+ node.reason ? `(${node.reason})` : ""
+ }`;
+ case "notification":
return `<${warning}>`;
default:
return `[${warning}](${output(node.content, state)})`;
}
},
- html: (node, output, state) => htmlTag(
- 'span',
- output(node.content, state),
- { 'data-mx-spoiler': node.reason || null },
- ),
+ html: (node, output, state) =>
+ htmlTag("span", output(node.content, state), {
+ "data-mx-spoiler": node.reason || null,
+ }),
},
inlineMath: {
order: defaultRules.del.order + 0.2,
match: inlineRegex(/^\$(\S[\s\S]+?\S|\S)\$(?!\d)/),
parse: (capture) => ({ content: capture[1] }),
plain: (node) => `$${node.content}$`,
- html: (node) => mathHtml('span', node),
+ html: (node) => mathHtml("span", node),
},
};
function mapElement(el) {
switch (el.tagName) {
- case 'MX-REPLY':
+ case "MX-REPLY":
return [];
- case 'P':
- return [{ type: 'paragraph', content: mapChildren(el) }];
- case 'BR':
- return [{ type: 'br' }];
+ case "P":
+ return [{ type: "paragraph", content: mapChildren(el) }];
+ case "BR":
+ return [{ type: "br" }];
- case 'H1':
- case 'H2':
- case 'H3':
- case 'H4':
- case 'H5':
- case 'H6':
- return [{ type: 'heading', level: Number(el.tagName[1]), content: mapChildren(el) }];
- case 'HR':
- return [{ type: 'hr' }];
- case 'PRE': {
+ case "H1":
+ case "H2":
+ case "H3":
+ case "H4":
+ case "H5":
+ case "H6":
+ return [
+ {
+ type: "heading",
+ level: Number(el.tagName[1]),
+ content: mapChildren(el),
+ },
+ ];
+ case "HR":
+ return [{ type: "hr" }];
+ case "PRE": {
let lang;
if (el.firstChild) {
Array.from(el.firstChild.classList).some((c) => {
- const langPrefix = 'language-';
+ const langPrefix = "language-";
if (c.startsWith(langPrefix)) {
lang = c.slice(langPrefix.length);
return true;
@@ -358,94 +419,117 @@ function mapElement(el) {
return false;
});
}
- return [{ type: 'codeBlock', lang, content: el.innerText }];
+ return [{ type: "codeBlock", lang, content: el.innerText }];
}
- case 'BLOCKQUOTE':
- return [{ type: 'blockQuote', content: mapChildren(el) }];
- case 'UL':
- return [{ type: 'list', items: Array.from(el.childNodes).map(mapNode) }];
- case 'OL':
- return [{
- type: 'list',
- ordered: true,
- start: Number(el.getAttribute('start')),
- items: Array.from(el.childNodes).map(mapNode),
- }];
- case 'TABLE': {
- const headerEl = Array.from(el.querySelector('thead > tr').childNodes);
- const align = headerEl.map((childE) => childE.style['text-align']);
- return [{
- type: 'table',
- header: headerEl.map(mapChildren),
- align,
- cells: Array.from(el.querySelectorAll('tbody > tr')).map((rowEl) => Array.from(rowEl.childNodes).map((childEl, i) => {
- if (align[i] === undefined) align[i] = childEl.style['text-align'];
- return mapChildren(childEl);
- })),
- }];
+ case "BLOCKQUOTE":
+ return [{ type: "blockQuote", content: mapChildren(el) }];
+ case "UL":
+ return [{ type: "list", items: Array.from(el.childNodes).map(mapNode) }];
+ case "OL":
+ return [
+ {
+ type: "list",
+ ordered: true,
+ start: Number(el.getAttribute("start")),
+ items: Array.from(el.childNodes).map(mapNode),
+ },
+ ];
+ case "TABLE": {
+ const headerEl = Array.from(el.querySelector("thead > tr").childNodes);
+ const align = headerEl.map((childE) => childE.style["text-align"]);
+ return [
+ {
+ type: "table",
+ header: headerEl.map(mapChildren),
+ align,
+ cells: Array.from(el.querySelectorAll("tbody > tr")).map((rowEl) =>
+ Array.from(rowEl.childNodes).map((childEl, i) => {
+ if (align[i] === undefined)
+ align[i] = childEl.style["text-align"];
+ return mapChildren(childEl);
+ })
+ ),
+ },
+ ];
}
- case 'A': {
- const href = el.getAttribute('href');
+ case "A": {
+ const href = el.getAttribute("href");
const id = parseIdUri(href);
- if (id) return [{ type: 'mention', content: el.innerText, id }];
+ if (id) return [{ type: "mention", content: el.innerText, id }];
- return [{
- type: 'link',
- target: el.getAttribute('href'),
- title: el.getAttribute('title'),
- content: mapChildren(el),
- }];
+ return [
+ {
+ type: "link",
+ target: el.getAttribute("href"),
+ title: el.getAttribute("title"),
+ content: mapChildren(el),
+ },
+ ];
}
- case 'IMG': {
- const src = el.getAttribute('src');
- let title = el.getAttribute('title');
- if (el.hasAttribute('data-mx-emoticon')) {
- if (title.length > 2 && title.startsWith(':') && title.endsWith(':')) {
+ case "IMG": {
+ const src = el.getAttribute("src");
+ let title = el.getAttribute("title");
+ if (el.hasAttribute("data-mx-emoticon")) {
+ if (title.length > 2 && title.startsWith(":") && title.endsWith(":")) {
title = title.slice(1, -1);
}
- return [{
- type: 'emoji',
- content: title,
- emoji: {
- mxc: src,
- shortcode: title,
+ return [
+ {
+ type: "emoji",
+ content: title,
+ emoji: {
+ mxc: src,
+ shortcode: title,
+ },
},
- }];
+ ];
}
- return [{
- type: 'image',
- alt: el.getAttribute('alt'),
- target: src,
- title,
- }];
+ return [
+ {
+ type: "image",
+ alt: el.getAttribute("alt"),
+ target: src,
+ title,
+ },
+ ];
}
- case 'EM':
- case 'I':
- return [{ type: 'em', content: mapChildren(el) }];
- case 'STRONG':
- case 'B':
- return [{ type: 'strong', content: mapChildren(el) }];
- case 'U':
- return [{ type: 'u', content: mapChildren(el) }];
- case 'DEL':
- case 'STRIKE':
- return [{ type: 'del', content: mapChildren(el) }];
- case 'CODE':
- return [{ type: 'inlineCode', content: el.innerText }];
+ case "EM":
+ case "I":
+ return [{ type: "em", content: mapChildren(el) }];
+ case "STRONG":
+ case "B":
+ return [{ type: "strong", content: mapChildren(el) }];
+ case "U":
+ return [{ type: "u", content: mapChildren(el) }];
+ case "DEL":
+ case "STRIKE":
+ return [{ type: "del", content: mapChildren(el) }];
+ case "CODE":
+ return [{ type: "inlineCode", content: el.innerText }];
- case 'DIV':
- if (el.hasAttribute('data-mx-maths')) {
- return [{ type: 'displayMath', content: el.getAttribute('data-mx-maths') }];
+ case "DIV":
+ if (el.hasAttribute("data-mx-maths")) {
+ return [
+ { type: "displayMath", content: el.getAttribute("data-mx-maths") },
+ ];
}
return mapChildren(el);
- case 'SPAN':
- if (el.hasAttribute('data-mx-spoiler')) {
- return [{ type: 'spoiler', reason: el.getAttribute('data-mx-spoiler'), content: mapChildren(el) }];
+ case "SPAN":
+ if (el.hasAttribute("data-mx-spoiler")) {
+ return [
+ {
+ type: "spoiler",
+ reason: el.getAttribute("data-mx-spoiler"),
+ content: mapChildren(el),
+ },
+ ];
}
- if (el.hasAttribute('data-mx-maths')) {
- return [{ type: 'inlineMath', content: el.getAttribute('data-mx-maths') }];
+ if (el.hasAttribute("data-mx-maths")) {
+ return [
+ { type: "inlineMath", content: el.getAttribute("data-mx-maths") },
+ ];
}
return mapChildren(el);
default:
@@ -456,7 +540,7 @@ function mapElement(el) {
function mapNode(n) {
switch (n.nodeType) {
case Node.TEXT_NODE:
- return [{ type: 'text', content: n.textContent }];
+ return [{ type: "text", content: n.textContent }];
case Node.ELEMENT_NODE:
return mapElement(n);
default:
@@ -473,7 +557,7 @@ function mapChildren(n) {
function render(content, state, plainOut, htmlOut) {
let c = content;
- if (content.length === 1 && content[0].type === 'paragraph') {
+ if (content.length === 1 && content[0].type === "paragraph") {
c = c[0].content;
}
@@ -482,7 +566,10 @@ function render(content, state, plainOut, htmlOut) {
const htmlStr = htmlOut(c, state);
- const plainHtml = htmlStr.replace(/
/g, '\n').replace(/<\/p>
/g, '\n\n').replace(/<\/?p>/g, '');
+ const plainHtml = htmlStr
+ .replace(/
/g, "\n")
+ .replace(/<\/p>
/g, "\n\n")
+ .replace(/<\/?p>/g, "");
const onlyPlain = sanitizeText(plainStr) === plainHtml;
return {
@@ -493,12 +580,12 @@ function render(content, state, plainOut, htmlOut) {
}
const plainParser = parserFor(plainRules);
-const plainPlainOut = outputFor(plainRules, 'plain');
-const plainHtmlOut = outputFor(plainRules, 'html');
+const plainPlainOut = outputFor(plainRules, "plain");
+const plainHtmlOut = outputFor(plainRules, "html");
const mdParser = parserFor(markdownRules);
-const mdPlainOut = outputFor(markdownRules, 'plain');
-const mdHtmlOut = outputFor(markdownRules, 'html');
+const mdPlainOut = outputFor(markdownRules, "plain");
+const mdHtmlOut = outputFor(markdownRules, "html");
export function plain(source, state) {
return render(plainParser(source, state), state, plainPlainOut, plainHtmlOut);
@@ -509,7 +596,7 @@ export function markdown(source, state) {
}
export function html(source, state) {
- const el = document.createElement('template');
+ const el = document.createElement("template");
el.innerHTML = source;
return render(mapChildren(el.content), state, mdPlainOut, mdHtmlOut);
}
diff --git a/src/util/matrixUtil.js b/src/util/matrixUtil.js
index 54ee31bb..6c5b4c6f 100644
--- a/src/util/matrixUtil.js
+++ b/src/util/matrixUtil.js
@@ -1,22 +1,24 @@
-import initMatrix from '../client/initMatrix';
+import initMatrix from "../client/initMatrix";
-import HashIC from '../../public/res/ic/outlined/hash.svg';
-import HashGlobeIC from '../../public/res/ic/outlined/hash-globe.svg';
-import HashLockIC from '../../public/res/ic/outlined/hash-lock.svg';
-import SpaceIC from '../../public/res/ic/outlined/space.svg';
-import SpaceGlobeIC from '../../public/res/ic/outlined/space-globe.svg';
-import SpaceLockIC from '../../public/res/ic/outlined/space-lock.svg';
+import HashIC from "../../public/res/ic/outlined/hash.svg";
+import HashGlobeIC from "../../public/res/ic/outlined/hash-globe.svg";
+import HashLockIC from "../../public/res/ic/outlined/hash-lock.svg";
+import SpaceIC from "../../public/res/ic/outlined/space.svg";
+import SpaceGlobeIC from "../../public/res/ic/outlined/space-globe.svg";
+import SpaceLockIC from "../../public/res/ic/outlined/space-lock.svg";
-const WELL_KNOWN_URI = '/.well-known/matrix/client';
+const WELL_KNOWN_URI = "/.well-known/matrix/client";
export async function getBaseUrl(servername) {
- let protocol = 'https://';
- if (servername.match(/^https?:\/\//) !== null) protocol = '';
+ let protocol = "https://";
+ if (servername.match(/^https?:\/\//) !== null) protocol = "";
const serverDiscoveryUrl = `${protocol}${servername}${WELL_KNOWN_URI}`;
try {
- const result = await (await fetch(serverDiscoveryUrl, { method: 'GET' })).json();
+ const result = await (
+ await fetch(serverDiscoveryUrl, { method: "GET" })
+ ).json();
- const baseUrl = result?.['m.homeserver']?.base_url;
+ const baseUrl = result?.["m.homeserver"]?.base_url;
if (baseUrl === undefined) throw new Error();
return baseUrl;
} catch (e) {
@@ -29,7 +31,7 @@ export function getUsername(userId) {
const user = mx.getUser(userId);
if (user === null) return userId;
let username = user.displayName;
- if (typeof username === 'undefined') {
+ if (typeof username === "undefined") {
username = userId;
}
return username;
@@ -45,29 +47,29 @@ export async function isRoomAliasAvailable(alias) {
if (result.room_id) return false;
return false;
} catch (e) {
- if (e.errcode === 'M_NOT_FOUND') return true;
+ if (e.errcode === "M_NOT_FOUND") return true;
return false;
}
}
export function getPowerLabel(powerLevel) {
- if (powerLevel > 9000) return 'Goku';
- if (powerLevel > 100) return 'Founder';
- if (powerLevel === 100) return 'Admin';
- if (powerLevel >= 50) return 'Mod';
+ if (powerLevel > 9000) return "Goku";
+ if (powerLevel > 100) return "Founder";
+ if (powerLevel === 100) return "Admin";
+ if (powerLevel >= 50) return "Mod";
return null;
}
export function parseReply(rawBody) {
- if (rawBody?.indexOf('>') !== 0) return null;
- let body = rawBody.slice(rawBody.indexOf('<') + 1);
- const user = body.slice(0, body.indexOf('>'));
+ if (rawBody?.indexOf(">") !== 0) return null;
+ let body = rawBody.slice(rawBody.indexOf("<") + 1);
+ const user = body.slice(0, body.indexOf(">"));
- body = body.slice(body.indexOf('>') + 2);
- const replyBody = body.slice(0, body.indexOf('\n\n'));
- body = body.slice(body.indexOf('\n\n') + 2);
+ body = body.slice(body.indexOf(">") + 2);
+ const replyBody = body.slice(0, body.indexOf("\n\n"));
+ body = body.slice(body.indexOf("\n\n") + 2);
- if (user === '') return null;
+ if (user === "") return null;
const isUserId = user.match(/^@.+:.+/);
@@ -81,7 +83,7 @@ export function parseReply(rawBody) {
export function trimHTMLReply(html) {
if (!html) return html;
- const suffix = '';
+ const suffix = "";
const i = html.indexOf(suffix);
if (i < 0) {
return html;
@@ -104,17 +106,21 @@ export function hasDMWith(userId) {
}
export function joinRuleToIconSrc(joinRule, isSpace) {
- return ({
- restricted: () => (isSpace ? SpaceIC : HashIC),
- knock: () => (isSpace ? SpaceLockIC : HashLockIC),
- invite: () => (isSpace ? SpaceLockIC : HashLockIC),
- public: () => (isSpace ? SpaceGlobeIC : HashGlobeIC),
- }[joinRule]?.() || null);
+ return (
+ {
+ restricted: () => (isSpace ? SpaceIC : HashIC),
+ knock: () => (isSpace ? SpaceLockIC : HashLockIC),
+ invite: () => (isSpace ? SpaceLockIC : HashLockIC),
+ public: () => (isSpace ? SpaceGlobeIC : HashGlobeIC),
+ }[joinRule]?.() || null
+ );
}
// NOTE: it gives userId with minimum power level 50;
function getHighestPowerUserId(room) {
- const userIdToPower = room.currentState.getStateEvents('m.room.power_levels', '')?.getContent().users;
+ const userIdToPower = room.currentState
+ .getStateEvents("m.room.power_levels", "")
+ ?.getContent().users;
let powerUserId = null;
if (!userIdToPower) return powerUserId;
@@ -132,7 +138,7 @@ function getHighestPowerUserId(room) {
}
export function getIdServer(userId) {
- const idParts = userId.split(':');
+ const idParts = userId.split(":");
return idParts[1];
}
@@ -163,7 +169,7 @@ export function genRoomVia(room) {
}
const serverToPop = getServerToPopulation(room);
const sortedServers = Object.keys(serverToPop).sort(
- (svrA, svrB) => serverToPop[svrB] - serverToPop[svrA],
+ (svrA, svrB) => serverToPop[svrB] - serverToPop[svrA]
);
const mostPop3 = sortedServers.slice(0, 3);
if (via.length === 0) return mostPop3;
@@ -178,7 +184,12 @@ export function isCrossVerified(deviceId) {
const mx = initMatrix.matrixClient;
const crossSignInfo = mx.getStoredCrossSigningForUser(mx.getUserId());
const deviceInfo = mx.getStoredDevice(mx.getUserId(), deviceId);
- const deviceTrust = crossSignInfo.checkDeviceTrust(crossSignInfo, deviceInfo, false, true);
+ const deviceTrust = crossSignInfo.checkDeviceTrust(
+ crossSignInfo,
+ deviceInfo,
+ false,
+ true
+ );
return deviceTrust.isCrossSigningVerified();
} catch {
// device does not support encryption
@@ -188,14 +199,14 @@ export function isCrossVerified(deviceId) {
export function hasCrossSigningAccountData() {
const mx = initMatrix.matrixClient;
- const masterKeyData = mx.getAccountData('m.cross_signing.master');
+ const masterKeyData = mx.getAccountData("m.cross_signing.master");
return !!masterKeyData;
}
export function getDefaultSSKey() {
const mx = initMatrix.matrixClient;
try {
- return mx.getAccountData('m.secret_storage.default_key').getContent().key;
+ return mx.getAccountData("m.secret_storage.default_key").getContent().key;
} catch {
return undefined;
}
@@ -214,10 +225,14 @@ export async function hasDevices(userId) {
const mx = initMatrix.matrixClient;
try {
const usersDeviceMap = await mx.downloadKeys([userId, mx.getUserId()]);
- return Object.values(usersDeviceMap)
- .every((userDevices) => (Object.keys(userDevices).length > 0));
+ return Object.values(usersDeviceMap).every(
+ (userDevices) => Object.keys(userDevices).length > 0
+ );
} catch (e) {
- console.error("Error determining if it's possible to encrypt to all users: ", e);
+ console.error(
+ "Error determining if it's possible to encrypt to all users: ",
+ e
+ );
return false;
}
}
diff --git a/src/util/mimetypes.js b/src/util/mimetypes.js
index bf7efbce..2fa7be22 100644
--- a/src/util/mimetypes.js
+++ b/src/util/mimetypes.js
@@ -1,39 +1,39 @@
// https://github.com/matrix-org/matrix-react-sdk/blob/cd15e08fc285da42134817cce50de8011809cd53/src/utils/blobs.ts
export const ALLOWED_BLOB_MIMETYPES = [
- 'image/jpeg',
- 'image/gif',
- 'image/png',
- 'image/apng',
- 'image/webp',
- 'image/avif',
+ "image/jpeg",
+ "image/gif",
+ "image/png",
+ "image/apng",
+ "image/webp",
+ "image/avif",
- 'video/mp4',
- 'video/webm',
- 'video/ogg',
- 'video/quicktime',
+ "video/mp4",
+ "video/webm",
+ "video/ogg",
+ "video/quicktime",
- 'audio/mp4',
- 'audio/webm',
- 'audio/aac',
- 'audio/mpeg',
- 'audio/ogg',
- 'audio/wave',
- 'audio/wav',
- 'audio/x-wav',
- 'audio/x-pn-wav',
- 'audio/flac',
- 'audio/x-flac',
+ "audio/mp4",
+ "audio/webm",
+ "audio/aac",
+ "audio/mpeg",
+ "audio/ogg",
+ "audio/wave",
+ "audio/wav",
+ "audio/x-wav",
+ "audio/x-pn-wav",
+ "audio/flac",
+ "audio/x-flac",
];
export function getBlobSafeMimeType(mimetype) {
- if (typeof mimetype !== 'string') return 'application/octet-stream';
- const [type] = mimetype.split(';');
+ if (typeof mimetype !== "string") return "application/octet-stream";
+ const [type] = mimetype.split(";");
if (!ALLOWED_BLOB_MIMETYPES.includes(type)) {
- return 'application/octet-stream';
+ return "application/octet-stream";
}
// Required for Chromium browsers
- if (type === 'video/quicktime') {
- return 'video/mp4';
+ if (type === "video/quicktime") {
+ return "video/mp4";
}
return type;
}
diff --git a/src/util/sanitize.js b/src/util/sanitize.js
index 79cc0418..4d9c2fde 100644
--- a/src/util/sanitize.js
+++ b/src/util/sanitize.js
@@ -1,26 +1,67 @@
-import sanitizeHtml from 'sanitize-html';
+import sanitizeHtml from "sanitize-html";
const MAX_TAG_NESTING = 100;
let mx = null;
const permittedHtmlTags = [
- 'font', 'del', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
- 'blockquote', 'p', 'a', 'ul', 'ol', 'sup', 'sub',
- 'li', 'b', 'i', 'u', 'strong', 'em', 'strike', 'code',
- 'hr', 'br', 'div', 'table', 'thead', 'tbody', 'tr', 'th',
- 'td', 'caption', 'pre', 'span', 'img', 'details', 'summary',
+ "font",
+ "del",
+ "h1",
+ "h2",
+ "h3",
+ "h4",
+ "h5",
+ "h6",
+ "blockquote",
+ "p",
+ "a",
+ "ul",
+ "ol",
+ "sup",
+ "sub",
+ "li",
+ "b",
+ "i",
+ "u",
+ "strong",
+ "em",
+ "strike",
+ "code",
+ "hr",
+ "br",
+ "div",
+ "table",
+ "thead",
+ "tbody",
+ "tr",
+ "th",
+ "td",
+ "caption",
+ "pre",
+ "span",
+ "img",
+ "details",
+ "summary",
];
-const urlSchemes = ['https', 'http', 'ftp', 'mailto', 'magnet'];
+const urlSchemes = ["https", "http", "ftp", "mailto", "magnet"];
const permittedTagToAttributes = {
- font: ['style', 'data-mx-bg-color', 'data-mx-color', 'color'],
- span: ['style', 'data-mx-bg-color', 'data-mx-color', 'data-mx-spoiler', 'data-mx-maths', 'data-mx-pill', 'data-mx-ping'],
- div: ['data-mx-maths'],
- a: ['name', 'target', 'href', 'rel'],
- img: ['width', 'height', 'alt', 'title', 'src', 'data-mx-emoticon'],
- ol: ['start'],
- code: ['class'],
+ font: ["style", "data-mx-bg-color", "data-mx-color", "color"],
+ span: [
+ "style",
+ "data-mx-bg-color",
+ "data-mx-color",
+ "data-mx-spoiler",
+ "data-mx-maths",
+ "data-mx-pill",
+ "data-mx-ping",
+ ],
+ div: ["data-mx-maths"],
+ a: ["name", "target", "href", "rel"],
+ img: ["width", "height", "alt", "title", "src", "data-mx-emoticon"],
+ ol: ["start"],
+ code: ["class"],
};
function transformFontTag(tagName, attribs) {
@@ -28,7 +69,7 @@ function transformFontTag(tagName, attribs) {
tagName,
attribs: {
...attribs,
- style: `background-color: ${attribs['data-mx-bg-color']}; color: ${attribs['data-mx-color']}`,
+ style: `background-color: ${attribs["data-mx-bg-color"]}; color: ${attribs["data-mx-color"]}`,
},
};
}
@@ -38,51 +79,57 @@ function transformSpanTag(tagName, attribs) {
tagName,
attribs: {
...attribs,
- style: `background-color: ${attribs['data-mx-bg-color']}; color: ${attribs['data-mx-color']}`,
+ style: `background-color: ${attribs["data-mx-bg-color"]}; color: ${attribs["data-mx-color"]}`,
},
};
}
function transformATag(tagName, attribs) {
- const userLink = decodeURIComponent(attribs.href).match(/^https?:\/\/matrix.to\/#\/(@.+:.+)/);
+ const userLink = decodeURIComponent(attribs.href).match(
+ /^https?:\/\/matrix.to\/#\/(@.+:.+)/
+ );
if (userLink !== null) {
// convert user link to pill
const userId = userLink[1];
const pill = {
- tagName: 'span',
+ tagName: "span",
attribs: {
- 'data-mx-pill': userId,
+ "data-mx-pill": userId,
},
};
if (userId === mx?.getUserId()) {
- pill.attribs['data-mx-ping'] = undefined;
+ pill.attribs["data-mx-ping"] = undefined;
}
return pill;
}
- const rex = /[\u{1f300}-\u{1f5ff}\u{1f900}-\u{1f9ff}\u{1f600}-\u{1f64f}\u{1f680}-\u{1f6ff}\u{2600}-\u{26ff}\u{2700}-\u{27bf}\u{1f1e6}-\u{1f1ff}\u{1f191}-\u{1f251}\u{1f004}\u{1f0cf}\u{1f170}-\u{1f171}\u{1f17e}-\u{1f17f}\u{1f18e}\u{3030}\u{2b50}\u{2b55}\u{2934}-\u{2935}\u{2b05}-\u{2b07}\u{2b1b}-\u{2b1c}\u{3297}\u{3299}\u{303d}\u{00a9}\u{00ae}\u{2122}\u{23f3}\u{24c2}\u{23e9}-\u{23ef}\u{25b6}\u{23f8}-\u{23fa}]/ug;
- const newHref = attribs.href.replace(rex, (match) => `[e-${match.codePointAt(0).toString(16)}]`);
+ const rex =
+ /[\u{1f300}-\u{1f5ff}\u{1f900}-\u{1f9ff}\u{1f600}-\u{1f64f}\u{1f680}-\u{1f6ff}\u{2600}-\u{26ff}\u{2700}-\u{27bf}\u{1f1e6}-\u{1f1ff}\u{1f191}-\u{1f251}\u{1f004}\u{1f0cf}\u{1f170}-\u{1f171}\u{1f17e}-\u{1f17f}\u{1f18e}\u{3030}\u{2b50}\u{2b55}\u{2934}-\u{2935}\u{2b05}-\u{2b07}\u{2b1b}-\u{2b1c}\u{3297}\u{3299}\u{303d}\u{00a9}\u{00ae}\u{2122}\u{23f3}\u{24c2}\u{23e9}-\u{23ef}\u{25b6}\u{23f8}-\u{23fa}]/gu;
+ const newHref = attribs.href.replace(
+ rex,
+ (match) => `[e-${match.codePointAt(0).toString(16)}]`
+ );
return {
tagName,
attribs: {
...attribs,
href: newHref,
- rel: 'noopener',
- target: '_blank',
+ rel: "noopener",
+ target: "_blank",
},
};
}
function transformImgTag(tagName, attribs) {
const { src } = attribs;
- if (src.startsWith('mxc://') === false) {
+ if (src.startsWith("mxc://") === false) {
return {
- tagName: 'a',
+ tagName: "a",
attribs: {
href: src,
- rel: 'noopener',
- target: '_blank',
+ rel: "noopener",
+ target: "_blank",
},
text: attribs.alt || src,
};
@@ -101,20 +148,20 @@ export function sanitizeCustomHtml(matrixClient, body) {
return sanitizeHtml(body, {
allowedTags: permittedHtmlTags,
allowedAttributes: permittedTagToAttributes,
- disallowedTagsMode: 'discard',
+ disallowedTagsMode: "discard",
allowedSchemes: urlSchemes,
allowedSchemesByTag: {
a: urlSchemes,
},
- allowedSchemesAppliedToAttributes: ['href'],
+ allowedSchemesAppliedToAttributes: ["href"],
allowProtocolRelative: false,
allowedClasses: {
- code: ['language-*'],
+ code: ["language-*"],
},
allowedStyles: {
- '*': {
+ "*": {
color: [/^#(?:[0-9a-fA-F]{3}){1,2}$/],
- 'background-color': [/^#(?:[0-9a-fA-F]{3}){1,2}$/],
+ "background-color": [/^#(?:[0-9a-fA-F]{3}){1,2}$/],
},
},
transformTags: {
@@ -123,18 +170,25 @@ export function sanitizeCustomHtml(matrixClient, body) {
a: transformATag,
img: transformImgTag,
},
- nonTextTags: ['style', 'script', 'textarea', 'option', 'noscript', 'mx-reply'],
+ nonTextTags: [
+ "style",
+ "script",
+ "textarea",
+ "option",
+ "noscript",
+ "mx-reply",
+ ],
nestingLimit: MAX_TAG_NESTING,
});
}
export function sanitizeText(body) {
const tagsToReplace = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- "'": ''',
+ "&": "&",
+ "<": "<",
+ ">": ">",
+ '"': """,
+ "'": "'",
};
return body.replace(/[&<>'"]/g, (tag) => tagsToReplace[tag] || tag);
}
diff --git a/src/util/sort.js b/src/util/sort.js
index f9a0b790..832b40ee 100644
--- a/src/util/sort.js
+++ b/src/util/sort.js
@@ -1,4 +1,4 @@
-import initMatrix from '../client/initMatrix';
+import initMatrix from "../client/initMatrix";
export function roomIdByActivity(id1, id2) {
const room1 = initMatrix.matrixClient.getRoom(id1);
@@ -13,8 +13,8 @@ export function roomIdByAtoZ(aId, bId) {
// remove "#" from the room name
// To ignore it in sorting
- aName = aName.replace(/#/g, '');
- bName = bName.replace(/#/g, '');
+ aName = aName.replace(/#/g, "");
+ bName = bName.replace(/#/g, "");
if (aName.toLowerCase() < bName.toLowerCase()) {
return -1;
diff --git a/src/util/twemojify.jsx b/src/util/twemojify.jsx
index abe82a66..b795db60 100644
--- a/src/util/twemojify.jsx
+++ b/src/util/twemojify.jsx
@@ -1,18 +1,19 @@
/* eslint-disable import/prefer-default-export */
-import React, { lazy, Suspense } from 'react';
+import React, { lazy, Suspense } from "react";
-import linkifyHtml from 'linkify-html';
-import parse from 'html-react-parser';
-import twemoji from 'twemoji';
-import { sanitizeText } from './sanitize';
+import linkifyHtml from "linkify-html";
+import parse from "html-react-parser";
+import twemoji from "twemoji";
+import { sanitizeText } from "./sanitize";
-export const TWEMOJI_BASE_URL = 'https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/';
+export const TWEMOJI_BASE_URL =
+ "https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/";
-const Math = lazy(() => import('../app/atoms/math/Math'));
+const Math = lazy(() => import("../app/atoms/math/Math"));
const mathOptions = {
replace: (node) => {
- const maths = node.attribs?.['data-mx-maths'];
+ const maths = node.attribs?.["data-mx-maths"];
if (maths) {
return (
{maths}}>
@@ -20,7 +21,7 @@ const mathOptions = {
content={maths}
throwOnError={false}
errorColor="var(--tc-danger-normal)"
- displayMode={node.name === 'div'}
+ displayMode={node.name === "div"}
/>
);
@@ -37,8 +38,14 @@ const mathOptions = {
* @param {boolean} [maths=false] - render maths (default: false)
* @returns React component
*/
-export function twemojify(text, opts, linkify = false, sanitize = true, maths = false) {
- if (typeof text !== 'string') return text;
+export function twemojify(
+ text,
+ opts,
+ linkify = false,
+ sanitize = true,
+ maths = false
+) {
+ if (typeof text !== "string") return text;
let content = text;
const options = opts ?? { base: TWEMOJI_BASE_URL };
if (!options.base) {
@@ -52,8 +59,8 @@ export function twemojify(text, opts, linkify = false, sanitize = true, maths =
content = twemoji.parse(content, options);
if (linkify) {
content = linkifyHtml(content, {
- target: '_blank',
- rel: 'noreferrer noopener',
+ target: "_blank",
+ rel: "noreferrer noopener",
});
}
return parse(content, maths ? mathOptions : null);
diff --git a/vite.config.js b/vite.config.js
index 979e9aa0..88e851c5 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -1,68 +1,61 @@
-import { defineConfig } from 'vite';
-import react from '@vitejs/plugin-react';
-import { wasm } from '@rollup/plugin-wasm';
-import { viteStaticCopy } from 'vite-plugin-static-copy';
-import { NodeGlobalsPolyfillPlugin } from '@esbuild-plugins/node-globals-polyfill';
-import inject from '@rollup/plugin-inject';
-import { svgLoader } from './viteSvgLoader';
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
+import { wasm } from "@rollup/plugin-wasm";
+import { viteStaticCopy } from "vite-plugin-static-copy";
+import { NodeGlobalsPolyfillPlugin } from "@esbuild-plugins/node-globals-polyfill";
+import inject from "@rollup/plugin-inject";
+import { svgLoader } from "./viteSvgLoader";
const copyFiles = {
targets: [
{
- src: 'node_modules/@matrix-org/olm/olm.wasm',
- dest: '',
+ src: "node_modules/@matrix-org/olm/olm.wasm",
+ dest: "",
},
{
- src: '_redirects',
- dest: '',
+ src: "_redirects",
+ dest: "",
},
{
- src: 'config.json',
- dest: '',
+ src: "config.json",
+ dest: "",
},
{
- src: 'public/res/android',
- dest: 'public/',
- }
+ src: "public/res/android",
+ dest: "public/",
+ },
],
-}
+};
export default defineConfig({
- appType: 'spa',
+ appType: "spa",
publicDir: false,
base: "",
server: {
port: 8080,
host: true,
},
- plugins: [
- viteStaticCopy(copyFiles),
- svgLoader(),
- wasm(),
- react(),
- ],
+ plugins: [viteStaticCopy(copyFiles), svgLoader(), wasm(), react()],
optimizeDeps: {
esbuildOptions: {
- define: {
- global: 'globalThis'
- },
- plugins: [
- // Enable esbuild polyfill plugins
- NodeGlobalsPolyfillPlugin({
- process: false,
- buffer: true,
- }),
- ]
- }
+ define: {
+ global: "globalThis",
+ },
+ plugins: [
+ // Enable esbuild polyfill plugins
+ NodeGlobalsPolyfillPlugin({
+ process: false,
+ buffer: true,
+ }),
+ ],
+ },
},
build: {
- outDir: 'dist',
+ outDir: "dist",
sourcemap: true,
copyPublicDir: false,
rollupOptions: {
- plugins: [
- inject({ Buffer: ['buffer', 'Buffer'] })
- ]
- }
+ plugins: [inject({ Buffer: ["buffer", "Buffer"] })],
+ },
},
});
diff --git a/viteSvgLoader.ts b/viteSvgLoader.ts
index a119e3ed..c81161d1 100644
--- a/viteSvgLoader.ts
+++ b/viteSvgLoader.ts
@@ -1,13 +1,13 @@
-import svgToMiniDataURI from 'mini-svg-data-uri';
-import type { Plugin } from 'rollup';
-import fs from 'fs';
+import svgToMiniDataURI from "mini-svg-data-uri";
+import type { Plugin } from "rollup";
+import fs from "fs";
// TODO: remove this once https://github.com/vitejs/vite/pull/2909 gets merged
export const svgLoader = (): Plugin => ({
- name: 'vite-svg-patch-plugin',
+ name: "vite-svg-patch-plugin",
transform: (code, id) => {
- if (id.endsWith('.svg')) {
- const extractedSvg = fs.readFileSync(id, 'utf8');
+ if (id.endsWith(".svg")) {
+ const extractedSvg = fs.readFileSync(id, "utf8");
const datauri = svgToMiniDataURI.toSrcset(extractedSvg);
return `export default "${datauri}"`;
}