mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-16 05:04:57 +08:00
Fix page reloading on initial update (#21410)
Remove the hash event listener before reloading the page, as the reload was being swallowed by our router. Along the way, refactor out routing logic form app.tsx to avoid causing a circular import.
This commit is contained in:
parent
1f97bc2325
commit
adad5e16c2
@ -29,70 +29,18 @@ import SdkConfig, { parseSsoRedirectOptions } from "matrix-react-sdk/src/SdkConf
|
|||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { createClient } from "matrix-js-sdk/src/matrix";
|
import { createClient } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import type MatrixChatType from "matrix-react-sdk/src/components/structures/MatrixChat";
|
import { parseQs } from './url_utils';
|
||||||
import { parseQs, parseQsFromFragment } from './url_utils';
|
|
||||||
import VectorBasePlatform from "./platform/VectorBasePlatform";
|
import VectorBasePlatform from "./platform/VectorBasePlatform";
|
||||||
|
import { getScreenFromLocation, init as initRouting, onNewScreen } from "./routing";
|
||||||
|
|
||||||
// add React and ReactPerf to the global namespace, to make them easier to access via the console
|
// add React and ReactPerf to the global namespace, to make them easier to access via the console
|
||||||
// this incidentally means we can forget our React imports in JSX files without penalty.
|
// this incidentally means we can forget our React imports in JSX files without penalty.
|
||||||
window.React = React;
|
window.React = React;
|
||||||
|
|
||||||
let lastLocationHashSet: string = null;
|
|
||||||
|
|
||||||
logger.log(`Application is running in ${process.env.NODE_ENV} mode`);
|
logger.log(`Application is running in ${process.env.NODE_ENV} mode`);
|
||||||
|
|
||||||
window.matrixLogger = logger;
|
window.matrixLogger = logger;
|
||||||
|
|
||||||
// Parse the given window.location and return parameters that can be used when calling
|
|
||||||
// MatrixChat.showScreen(screen, params)
|
|
||||||
function getScreenFromLocation(location: Location) {
|
|
||||||
const fragparts = parseQsFromFragment(location);
|
|
||||||
return {
|
|
||||||
screen: fragparts.location.substring(1),
|
|
||||||
params: fragparts.params,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Here, we do some crude URL analysis to allow
|
|
||||||
// deep-linking.
|
|
||||||
function routeUrl(location: Location) {
|
|
||||||
if (!window.matrixChat) return;
|
|
||||||
|
|
||||||
logger.log("Routing URL ", location.href);
|
|
||||||
const s = getScreenFromLocation(location);
|
|
||||||
(window.matrixChat as MatrixChatType).showScreen(s.screen, s.params);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onHashChange(ev: HashChangeEvent) {
|
|
||||||
if (decodeURIComponent(window.location.hash) === lastLocationHashSet) {
|
|
||||||
// we just set this: no need to route it!
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
routeUrl(window.location);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This will be called whenever the SDK changes screens,
|
|
||||||
// so a web page can update the URL bar appropriately.
|
|
||||||
function onNewScreen(screen: string, replaceLast = false) {
|
|
||||||
logger.log("newscreen " + screen);
|
|
||||||
const hash = '#/' + screen;
|
|
||||||
lastLocationHashSet = hash;
|
|
||||||
|
|
||||||
// if the new hash is a substring of the old one then we are stripping fields e.g `via` so replace history
|
|
||||||
if (screen.startsWith("room/") &&
|
|
||||||
window.location.hash.includes("/$") === hash.includes("/$") && // only if both did or didn't contain event link
|
|
||||||
window.location.hash.startsWith(hash)
|
|
||||||
) {
|
|
||||||
replaceLast = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (replaceLast) {
|
|
||||||
window.location.replace(hash);
|
|
||||||
} else {
|
|
||||||
window.location.assign(hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We use this to work out what URL the SDK should
|
// We use this to work out what URL the SDK should
|
||||||
// pass through when registering to allow the user to
|
// pass through when registering to allow the user to
|
||||||
// click back to the client having registered.
|
// click back to the client having registered.
|
||||||
@ -141,8 +89,7 @@ function onTokenLoginCompleted() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function loadApp(fragParams: {}) {
|
export async function loadApp(fragParams: {}) {
|
||||||
window.addEventListener('hashchange', onHashChange);
|
initRouting();
|
||||||
|
|
||||||
const platform = PlatformPeg.get();
|
const platform = PlatformPeg.get();
|
||||||
|
|
||||||
const params = parseQs(window.location);
|
const params = parseQs(window.location);
|
||||||
|
@ -28,6 +28,7 @@ import { logger } from "matrix-js-sdk/src/logger";
|
|||||||
|
|
||||||
import VectorBasePlatform from './VectorBasePlatform';
|
import VectorBasePlatform from './VectorBasePlatform';
|
||||||
import { parseQs } from "../url_utils";
|
import { parseQs } from "../url_utils";
|
||||||
|
import { reloadPage } from "../routing";
|
||||||
|
|
||||||
const POKE_RATE_MS = 10 * 60 * 1000; // 10 min
|
const POKE_RATE_MS = 10 * 60 * 1000; // 10 min
|
||||||
|
|
||||||
@ -128,9 +129,11 @@ export default class WebPlatform extends VectorBasePlatform {
|
|||||||
//
|
//
|
||||||
// Ideally, loading an old copy would be impossible with the
|
// Ideally, loading an old copy would be impossible with the
|
||||||
// cache-control: nocache HTTP header set, but Firefox doesn't always obey it :/
|
// cache-control: nocache HTTP header set, but Firefox doesn't always obey it :/
|
||||||
|
console.log("startUpdater, current version is " + this.getNormalizedAppVersion(process.env.VERSION));
|
||||||
this.pollForUpdate((version: string, newVersion: string) => {
|
this.pollForUpdate((version: string, newVersion: string) => {
|
||||||
const query = parseQs(location);
|
const query = parseQs(location);
|
||||||
if (query.updated === "1") {
|
if (query.updated === "1") {
|
||||||
|
console.log("Update reloaded but still on an old version, stopping");
|
||||||
// We just reloaded already and are still on the old version!
|
// We just reloaded already and are still on the old version!
|
||||||
// Show the toast rather than reload in a loop.
|
// Show the toast rather than reload in a loop.
|
||||||
showUpdateToast(version, newVersion);
|
showUpdateToast(version, newVersion);
|
||||||
@ -146,8 +149,7 @@ export default class WebPlatform extends VectorBasePlatform {
|
|||||||
suffix = "&" + suffix;
|
suffix = "&" + suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This line has the effect of loading the page at the new location
|
reloadPage(window.location.href + suffix);
|
||||||
window.location.href = window.location.href + suffix;
|
|
||||||
});
|
});
|
||||||
setInterval(() => this.pollForUpdate(showUpdateToast, hideUpdateToast), POKE_RATE_MS);
|
setInterval(() => this.pollForUpdate(showUpdateToast, hideUpdateToast), POKE_RATE_MS);
|
||||||
}
|
}
|
||||||
@ -165,10 +167,14 @@ export default class WebPlatform extends VectorBasePlatform {
|
|||||||
|
|
||||||
if (currentVersion !== mostRecentVersion) {
|
if (currentVersion !== mostRecentVersion) {
|
||||||
if (this.shouldShowUpdate(mostRecentVersion)) {
|
if (this.shouldShowUpdate(mostRecentVersion)) {
|
||||||
|
console.log("Update available to " + mostRecentVersion + ", will notify user");
|
||||||
showUpdate(currentVersion, mostRecentVersion);
|
showUpdate(currentVersion, mostRecentVersion);
|
||||||
|
} else {
|
||||||
|
console.log("Update available to " + mostRecentVersion + " but won't be shown");
|
||||||
}
|
}
|
||||||
return { status: UpdateCheckStatus.Ready };
|
return { status: UpdateCheckStatus.Ready };
|
||||||
} else {
|
} else {
|
||||||
|
console.log("No update available, already on " + mostRecentVersion);
|
||||||
showNoUpdate?.();
|
showNoUpdate?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
83
src/vector/routing.ts
Normal file
83
src/vector/routing.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Parse the given window.location and return parameters that can be used when calling
|
||||||
|
// MatrixChat.showScreen(screen, params)
|
||||||
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
import MatrixChatType from "matrix-react-sdk/src/components/structures/MatrixChat";
|
||||||
|
|
||||||
|
import { parseQsFromFragment } from "./url_utils";
|
||||||
|
|
||||||
|
let lastLocationHashSet: string = null;
|
||||||
|
|
||||||
|
export function getScreenFromLocation(location: Location) {
|
||||||
|
const fragparts = parseQsFromFragment(location);
|
||||||
|
return {
|
||||||
|
screen: fragparts.location.substring(1),
|
||||||
|
params: fragparts.params,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here, we do some crude URL analysis to allow
|
||||||
|
// deep-linking.
|
||||||
|
function routeUrl(location: Location) {
|
||||||
|
if (!window.matrixChat) return;
|
||||||
|
|
||||||
|
logger.log("Routing URL ", location.href);
|
||||||
|
const s = getScreenFromLocation(location);
|
||||||
|
(window.matrixChat as MatrixChatType).showScreen(s.screen, s.params);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onHashChange(ev: HashChangeEvent) {
|
||||||
|
if (decodeURIComponent(window.location.hash) === lastLocationHashSet) {
|
||||||
|
// we just set this: no need to route it!
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
routeUrl(window.location);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will be called whenever the SDK changes screens,
|
||||||
|
// so a web page can update the URL bar appropriately.
|
||||||
|
export function onNewScreen(screen: string, replaceLast = false) {
|
||||||
|
logger.log("newscreen " + screen);
|
||||||
|
const hash = '#/' + screen;
|
||||||
|
lastLocationHashSet = hash;
|
||||||
|
|
||||||
|
// if the new hash is a substring of the old one then we are stripping fields e.g `via` so replace history
|
||||||
|
if (screen.startsWith("room/") &&
|
||||||
|
window.location.hash.includes("/$") === hash.includes("/$") && // only if both did or didn't contain event link
|
||||||
|
window.location.hash.startsWith(hash)
|
||||||
|
) {
|
||||||
|
replaceLast = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (replaceLast) {
|
||||||
|
window.location.replace(hash);
|
||||||
|
} else {
|
||||||
|
window.location.assign(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reload the page to a different url
|
||||||
|
export function reloadPage(newUrl: string) {
|
||||||
|
console.log("reloadPage to " + newUrl);
|
||||||
|
window.removeEventListener('hashchange', onHashChange);
|
||||||
|
window.location.href = newUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function init() {
|
||||||
|
window.addEventListener('hashchange', onHashChange);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user