From 48dcfb0aa91f26cd06eeed2d67de7ec745a48762 Mon Sep 17 00:00:00 2001 From: C0ffeeCode Date: Thu, 12 May 2022 09:57:41 +0200 Subject: [PATCH 1/4] seems stable --- src/app/templates/client/Client.jsx | 6 +++ src/util/uriFragments.js | 81 +++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 src/util/uriFragments.js diff --git a/src/app/templates/client/Client.jsx b/src/app/templates/client/Client.jsx index 8610b62ccd..f42d79573c 100644 --- a/src/app/templates/client/Client.jsx +++ b/src/app/templates/client/Client.jsx @@ -3,6 +3,7 @@ import './Client.scss'; import { initHotkeys } from '../../../client/event/hotkeys'; import { initRoomListListener } from '../../../client/event/roomList'; +import { handleUriFragmentChange, destructUrlHandling } from '../../../util/uriFragments'; import Text from '../../atoms/text/Text'; import Spinner from '../../atoms/spinner/Spinner'; @@ -67,8 +68,13 @@ function Client() { initHotkeys(); initRoomListListener(initMatrix.roomList); changeLoading(false); + handleUriFragmentChange(); }); initMatrix.init(); + + return () => { + destructUrlHandling(); + }; }, []); if (isLoading) { diff --git a/src/util/uriFragments.js b/src/util/uriFragments.js new file mode 100644 index 0000000000..4c90065579 --- /dev/null +++ b/src/util/uriFragments.js @@ -0,0 +1,81 @@ +import { + selectRoom, selectSpace, + } from '../client/action/navigation'; + import matrixClient from '../client/initMatrix'; + + import navigation from '../client/state/navigation'; + import cons from '../client/state/cons'; + + async function joinRoom(roomAlias) { + const room = await matrixClient.matrixClient.getRoomSummary(roomAlias); + // TODO: Check if already joined, replace this confirm + if (!confirm(`Do you want to join ${room.name} (${roomAlias})?`)) return; + await matrixClient.matrixClient.joinRoom(roomAlias); + const state = await matrixClient.matrixClient.roomState(room.room_id); + const isSpace = state.find((e) => e.type === 'm.room.create').content.type === 'm.space'; + if (isSpace) selectSpace(room.room_id); + else selectRoom(room.room_id); + } + + const listeners = []; + + export function handleUriFragmentChange() { + if (window.location.hash === '' + || window.location.hash === '#' + || window.location.hash === '#/') return; + + // Room must be selected AFTER client finished loading + const a = window.location.hash.split('/'); + // a[0] always is # + // if no trailing '/' would be used for hash we would have to remove it + // relevant array items start at index 1 + + if (a[1] === 'join') { + joinRoom(a[2]); + return; + } + + // /... + if (a.length >= 2) { + if (a[1] === 'room' || a[1][0] !== '!') a[1] = cons.tabs.HOME; + + selectSpace(a[1]); + } + + // /// + if (a.length >= 3) { + if (a[2][0] !== '!') selectRoom(null); + else if (a[3] && a[3][0] === '$') selectRoom(a[2], a[3]); + else selectRoom(a[2]); + } + } + + listeners.push( + window.addEventListener('hashchange', handleUriFragmentChange), + + navigation.on(cons.events.navigation.ROOM_SELECTED, (selectedRoom, _previousRoom, eventId) => { + const a = window.location.hash.split('/'); + if (!eventId) a.length = 3; + else a[3] = eventId; + if (!selectRoom) a.length = 2; + else a[2] = selectedRoom; + window.location.hash = a.join('/'); + }), + + navigation.on(cons.events.navigation.SPACE_SELECTED, (spaceSelected) => { + const strp = window.location.hash.split('/'); + strp[1] = spaceSelected ?? 'room'; + window.location.hash = strp.join('/'); + }), + + navigation.on(cons.actions.navigation.OPEN_NAVIGATION, () => { + const h = window.location.hash.split('/'); + h.length = 2; + window.location.hash = h.join('/'); + }), + ); + + export function destructUrlHandling() { + listeners.forEach((l) => navigation.removeListener(l)); + } + \ No newline at end of file From 473d97312ed136082bc4f3a613b3e41d29214ebd Mon Sep 17 00:00:00 2001 From: C0ffeeCode Date: Thu, 12 May 2022 10:37:17 +0200 Subject: [PATCH 2/4] - Use proper openJoinAlias - Avoid requests to join the just joined room --- src/util/uriFragments.js | 144 ++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 76 deletions(-) diff --git a/src/util/uriFragments.js b/src/util/uriFragments.js index 4c90065579..7c8d31a25f 100644 --- a/src/util/uriFragments.js +++ b/src/util/uriFragments.js @@ -1,81 +1,73 @@ import { - selectRoom, selectSpace, - } from '../client/action/navigation'; - import matrixClient from '../client/initMatrix'; - - import navigation from '../client/state/navigation'; - import cons from '../client/state/cons'; - - async function joinRoom(roomAlias) { - const room = await matrixClient.matrixClient.getRoomSummary(roomAlias); - // TODO: Check if already joined, replace this confirm - if (!confirm(`Do you want to join ${room.name} (${roomAlias})?`)) return; - await matrixClient.matrixClient.joinRoom(roomAlias); - const state = await matrixClient.matrixClient.roomState(room.room_id); - const isSpace = state.find((e) => e.type === 'm.room.create').content.type === 'm.space'; - if (isSpace) selectSpace(room.room_id); - else selectRoom(room.room_id); - } - - const listeners = []; - - export function handleUriFragmentChange() { - if (window.location.hash === '' + selectRoom, selectSpace, openJoinAlias, +} from '../client/action/navigation'; + +import navigation from '../client/state/navigation'; +import cons from '../client/state/cons'; + +async function joinRoom(roomAlias) { + openJoinAlias(roomAlias); +} + +const listeners = []; + +export function handleUriFragmentChange() { + if (window.location.hash === '' || window.location.hash === '#' || window.location.hash === '#/') return; - - // Room must be selected AFTER client finished loading - const a = window.location.hash.split('/'); - // a[0] always is # - // if no trailing '/' would be used for hash we would have to remove it - // relevant array items start at index 1 - - if (a[1] === 'join') { - joinRoom(a[2]); - return; - } - - // /... - if (a.length >= 2) { - if (a[1] === 'room' || a[1][0] !== '!') a[1] = cons.tabs.HOME; - - selectSpace(a[1]); - } - - // /// - if (a.length >= 3) { - if (a[2][0] !== '!') selectRoom(null); - else if (a[3] && a[3][0] === '$') selectRoom(a[2], a[3]); - else selectRoom(a[2]); - } + + // Room must be selected AFTER client finished loading + const a = window.location.hash.split('/'); + // a[0] always is # + // if no trailing '/' would be used for hash we would have to remove it + // relevant array items start at index 1 + + if (a[1] === 'join') { + joinRoom(a[2]); + return; } - - listeners.push( - window.addEventListener('hashchange', handleUriFragmentChange), - - navigation.on(cons.events.navigation.ROOM_SELECTED, (selectedRoom, _previousRoom, eventId) => { - const a = window.location.hash.split('/'); - if (!eventId) a.length = 3; - else a[3] = eventId; - if (!selectRoom) a.length = 2; - else a[2] = selectedRoom; - window.location.hash = a.join('/'); - }), - - navigation.on(cons.events.navigation.SPACE_SELECTED, (spaceSelected) => { - const strp = window.location.hash.split('/'); - strp[1] = spaceSelected ?? 'room'; - window.location.hash = strp.join('/'); - }), - - navigation.on(cons.actions.navigation.OPEN_NAVIGATION, () => { - const h = window.location.hash.split('/'); - h.length = 2; - window.location.hash = h.join('/'); - }), - ); - - export function destructUrlHandling() { - listeners.forEach((l) => navigation.removeListener(l)); + + // /... + if (a.length >= 2) { + if (a[1] === 'room' || a[1][0] !== '!') a[1] = cons.tabs.HOME; + + selectSpace(a[1]); } - \ No newline at end of file + + // /// + if (a.length >= 3) { + if (a[2][0] !== '!') selectRoom(null); + else if (a[3] && a[3][0] === '$') selectRoom(a[2], a[3]); + else selectRoom(a[2]); + } +} + +listeners.push( + window.addEventListener('hashchange', handleUriFragmentChange), + + navigation.on(cons.events.navigation.ROOM_SELECTED, (selectedRoom, _previousRoom, eventId) => { + const a = window.location.hash.split('/'); + if (!eventId) a.length = 3; + else a[3] = eventId; + if (!selectRoom) a.length = 2; + else a[2] = selectedRoom; + if (a[1] === 'join') a[1] = cons.tabs.HOME; + window.location.hash = a.join('/'); + }), + + navigation.on(cons.events.navigation.SPACE_SELECTED, (spaceSelected) => { + const strp = window.location.hash.split('/'); + strp[1] = spaceSelected ?? 'room'; + window.location.hash = strp.join('/'); + }), + + navigation.on(cons.actions.navigation.OPEN_NAVIGATION, () => { + const h = window.location.hash.split('/'); + h.length = 2; + window.location.hash = h.join('/'); + }), +); + +export function destructUrlHandling() { + listeners.forEach((l) => navigation.removeListener(l)); +} From 7f892ca499aa233f10b04f7cb156f434d4e6d873 Mon Sep 17 00:00:00 2001 From: C0ffeeCode Date: Thu, 12 May 2022 10:46:16 +0200 Subject: [PATCH 3/4] Improve code quality --- src/util/uriFragments.js | 54 ++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/src/util/uriFragments.js b/src/util/uriFragments.js index 7c8d31a25f..c8f61eb779 100644 --- a/src/util/uriFragments.js +++ b/src/util/uriFragments.js @@ -5,40 +5,34 @@ import { import navigation from '../client/state/navigation'; import cons from '../client/state/cons'; -async function joinRoom(roomAlias) { - openJoinAlias(roomAlias); -} - const listeners = []; export function handleUriFragmentChange() { - if (window.location.hash === '' - || window.location.hash === '#' - || window.location.hash === '#/') return; + if (!window.location.hash.startsWith('/#')) return; // Room must be selected AFTER client finished loading - const a = window.location.hash.split('/'); + const pieces = window.location.hash.split('/'); // a[0] always is # // if no trailing '/' would be used for hash we would have to remove it // relevant array items start at index 1 - if (a[1] === 'join') { - joinRoom(a[2]); + if (pieces[1] === 'join') { + openJoinAlias(pieces[2]); return; } // /... - if (a.length >= 2) { - if (a[1] === 'room' || a[1][0] !== '!') a[1] = cons.tabs.HOME; + if (pieces.length >= 2) { + if (pieces[1] === 'room' || pieces[1][0] !== '!') pieces[1] = cons.tabs.HOME; - selectSpace(a[1]); + selectSpace(pieces[1]); } // /// - if (a.length >= 3) { - if (a[2][0] !== '!') selectRoom(null); - else if (a[3] && a[3][0] === '$') selectRoom(a[2], a[3]); - else selectRoom(a[2]); + if (pieces.length >= 3) { + if (pieces[2][0] !== '!') selectRoom(null); + else if (pieces[3] && pieces[3][0] === '$') selectRoom(pieces[2], pieces[3]); + else selectRoom(pieces[2]); } } @@ -46,25 +40,25 @@ listeners.push( window.addEventListener('hashchange', handleUriFragmentChange), navigation.on(cons.events.navigation.ROOM_SELECTED, (selectedRoom, _previousRoom, eventId) => { - const a = window.location.hash.split('/'); - if (!eventId) a.length = 3; - else a[3] = eventId; - if (!selectRoom) a.length = 2; - else a[2] = selectedRoom; - if (a[1] === 'join') a[1] = cons.tabs.HOME; - window.location.hash = a.join('/'); + const pieces = window.location.hash.split('/'); + if (!eventId) pieces.length = 3; + else pieces[3] = eventId; + if (!selectRoom) pieces.length = 2; + else pieces[2] = selectedRoom; + if (pieces[1] === 'join') pieces[1] = cons.tabs.HOME; + window.location.hash = pieces.join('/'); }), navigation.on(cons.events.navigation.SPACE_SELECTED, (spaceSelected) => { - const strp = window.location.hash.split('/'); - strp[1] = spaceSelected ?? 'room'; - window.location.hash = strp.join('/'); + const pieces = window.location.hash.split('/'); + pieces[1] = spaceSelected ?? 'room'; + window.location.hash = pieces.join('/'); }), navigation.on(cons.actions.navigation.OPEN_NAVIGATION, () => { - const h = window.location.hash.split('/'); - h.length = 2; - window.location.hash = h.join('/'); + const pieces = window.location.hash.split('/'); + pieces.length = 2; + window.location.hash = pieces.join('/'); }), ); From b8c8c14b3537a0819b06a90240050b535277bce8 Mon Sep 17 00:00:00 2001 From: C0ffeeCode Date: Wed, 30 Aug 2023 17:45:11 +0200 Subject: [PATCH 4/4] Fix typo/bug & avoid loop of self-triggering updates --- src/util/uriFragments.js | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/util/uriFragments.js b/src/util/uriFragments.js index c8f61eb779..51202c4e9f 100644 --- a/src/util/uriFragments.js +++ b/src/util/uriFragments.js @@ -7,8 +7,22 @@ import cons from '../client/state/cons'; const listeners = []; +/** + * Old `window.location.hash` value + * @type {string} + */ +let oldHash; + export function handleUriFragmentChange() { - if (!window.location.hash.startsWith('/#')) return; + // If there is no fragment, there is no need to proceed here + if (!window.location.hash.startsWith('/#') && !window.location.hash.startsWith('#')) return; + + // Avoid falling into loops of self-triggering + // by detecting hashchange events which are not actually a change + if (window.location.hash === oldHash) { + return; + } + oldHash = window.location.hash; // Room must be selected AFTER client finished loading const pieces = window.location.hash.split('/'); @@ -16,13 +30,14 @@ export function handleUriFragmentChange() { // if no trailing '/' would be used for hash we would have to remove it // relevant array items start at index 1 + // /join/ if (pieces[1] === 'join') { openJoinAlias(pieces[2]); return; } // /... - if (pieces.length >= 2) { + if (pieces.length >= 2) { if (pieces[1] === 'room' || pieces[1][0] !== '!') pieces[1] = cons.tabs.HOME; selectSpace(pieces[1]); @@ -41,9 +56,14 @@ listeners.push( navigation.on(cons.events.navigation.ROOM_SELECTED, (selectedRoom, _previousRoom, eventId) => { const pieces = window.location.hash.split('/'); + + if (_previousRoom === selectedRoom) { + return; + } + if (!eventId) pieces.length = 3; else pieces[3] = eventId; - if (!selectRoom) pieces.length = 2; + if (!selectedRoom) pieces.length = 2; else pieces[2] = selectedRoom; if (pieces[1] === 'join') pieces[1] = cons.tabs.HOME; window.location.hash = pieces.join('/');