Switch things to typescript, use @types/modernizr, fix global.d.ts. Move mobile_guide redirect to index.ts
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
093b7bbf72
commit
b1575524aa
8 changed files with 92 additions and 72 deletions
|
@ -96,6 +96,7 @@
|
||||||
"@babel/preset-typescript": "^7.7.4",
|
"@babel/preset-typescript": "^7.7.4",
|
||||||
"@babel/register": "^7.7.4",
|
"@babel/register": "^7.7.4",
|
||||||
"@babel/runtime": "^7.7.6",
|
"@babel/runtime": "^7.7.6",
|
||||||
|
"@types/modernizr": "^3.5.3",
|
||||||
"@types/react": "16.9",
|
"@types/react": "16.9",
|
||||||
"@types/react-dom": "^16.9.4",
|
"@types/react-dom": "^16.9.4",
|
||||||
"autoprefixer": "^9.7.3",
|
"autoprefixer": "^9.7.3",
|
||||||
|
|
24
src/@types/global.d.ts
vendored
24
src/@types/global.d.ts
vendored
|
@ -14,12 +14,22 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type ReactNode = import("react").ReactNode;
|
import {ReactNode} from "react";
|
||||||
|
import "modernizr";
|
||||||
|
|
||||||
interface Window {
|
declare global {
|
||||||
Olm: {
|
interface Window {
|
||||||
init: () => Promise<void>;
|
Modernizr: ModernizrAPI & FeatureDetects;
|
||||||
};
|
Olm: {
|
||||||
mxSendRageshake: (text: string, withLogs?: boolean) => void;
|
init: () => Promise<void>;
|
||||||
matrixChat: ReactNode;
|
};
|
||||||
|
|
||||||
|
mxSendRageshake: (text: string, withLogs?: boolean) => void;
|
||||||
|
matrixChat: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// workaround for https://github.com/microsoft/TypeScript/issues/30933
|
||||||
|
interface ObjectConstructor {
|
||||||
|
fromEntries?(xs: [string|number|symbol, any][]): object
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,41 +44,6 @@ import {loadConfig, preparePlatform, loadLanguage, loadOlm} from "./init";
|
||||||
|
|
||||||
let lastLocationHashSet = null;
|
let lastLocationHashSet = null;
|
||||||
|
|
||||||
function checkBrowserFeatures() {
|
|
||||||
if (!window.Modernizr) {
|
|
||||||
console.error("Cannot check features - Modernizr global is missing.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// custom checks atop Modernizr because it doesn't have ES2018/ES2019 checks in it for some features we depend on,
|
|
||||||
// Modernizr requires rules to be lowercase with no punctuation:
|
|
||||||
// ES2018: http://www.ecma-international.org/ecma-262/9.0/#sec-promise.prototype.finally
|
|
||||||
window.Modernizr.addTest("promiseprototypefinally", () =>
|
|
||||||
window.Promise && window.Promise.prototype && typeof window.Promise.prototype.finally === "function");
|
|
||||||
// ES2019: http://www.ecma-international.org/ecma-262/10.0/#sec-object.fromentries
|
|
||||||
window.Modernizr.addTest("objectfromentries", () =>
|
|
||||||
window.Object && typeof window.Object.fromEntries === "function");
|
|
||||||
|
|
||||||
const featureList = Object.keys(window.Modernizr);
|
|
||||||
|
|
||||||
let featureComplete = true;
|
|
||||||
for (let i = 0; i < featureList.length; i++) {
|
|
||||||
if (window.Modernizr[featureList[i]] === undefined) {
|
|
||||||
console.error(
|
|
||||||
"Looked for feature '%s' but Modernizr has no results for this. " +
|
|
||||||
"Has it been configured correctly?", featureList[i],
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (window.Modernizr[featureList[i]] === false) {
|
|
||||||
console.error("Browser missing feature: '%s'", featureList[i]);
|
|
||||||
// toggle flag rather than return early so we log all missing features rather than just the first.
|
|
||||||
featureComplete = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return featureComplete;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the given window.location and return parameters that can be used when calling
|
// Parse the given window.location and return parameters that can be used when calling
|
||||||
// MatrixChat.showScreen(screen, params)
|
// MatrixChat.showScreen(screen, params)
|
||||||
function getScreenFromLocation(location) {
|
function getScreenFromLocation(location) {
|
||||||
|
@ -163,7 +128,7 @@ function onTokenLoginCompleted() {
|
||||||
window.location.href = formatted;
|
window.location.href = formatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadApp() {
|
export async function loadApp(fragParams: {}, acceptBrowser: boolean) {
|
||||||
// XXX: the way we pass the path to the worker script from webpack via html in body's dataset is a hack
|
// XXX: the way we pass the path to the worker script from webpack via html in body's dataset is a hack
|
||||||
// but alternatives seem to require changing the interface to passing Workers to js-sdk
|
// but alternatives seem to require changing the interface to passing Workers to js-sdk
|
||||||
const vectorIndexeddbWorkerScript = document.body.dataset.vectorIndexeddbWorkerScript;
|
const vectorIndexeddbWorkerScript = document.body.dataset.vectorIndexeddbWorkerScript;
|
||||||
|
@ -191,26 +156,8 @@ export async function loadApp() {
|
||||||
// Load language after loading config.json so that settingsDefaults.language can be applied
|
// Load language after loading config.json so that settingsDefaults.language can be applied
|
||||||
await loadLanguage();
|
await loadLanguage();
|
||||||
|
|
||||||
const fragparts = parseQsFromFragment(window.location);
|
|
||||||
const params = parseQs(window.location);
|
const params = parseQs(window.location);
|
||||||
|
|
||||||
// don't try to redirect to the native apps if we're
|
|
||||||
// verifying a 3pid (but after we've loaded the config)
|
|
||||||
// or if the user is following a deep link
|
|
||||||
// (https://github.com/vector-im/riot-web/issues/7378)
|
|
||||||
const preventRedirect = fragparts.params.client_secret || fragparts.location.length > 0;
|
|
||||||
|
|
||||||
if (!preventRedirect) {
|
|
||||||
const isIos = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
|
|
||||||
const isAndroid = /Android/.test(navigator.userAgent);
|
|
||||||
if (isIos || isAndroid) {
|
|
||||||
if (document.cookie.indexOf("riot_mobile_redirect_to_guide=false") === -1) {
|
|
||||||
window.location = "mobile_guide/";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// as quickly as we possibly can, set a default theme...
|
// as quickly as we possibly can, set a default theme...
|
||||||
await setTheme();
|
await setTheme();
|
||||||
|
|
||||||
|
@ -237,17 +184,13 @@ export async function loadApp() {
|
||||||
return <GenericErrorPage message={errorMessage} title={_t("Your Riot is misconfigured")} />;
|
return <GenericErrorPage message={errorMessage} title={_t("Your Riot is misconfigured")} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const validBrowser = checkBrowserFeatures();
|
|
||||||
|
|
||||||
const acceptInvalidBrowser = window.localStorage && window.localStorage.getItem('mx_accepts_unsupported_browser');
|
|
||||||
|
|
||||||
const urlWithoutQuery = window.location.protocol + '//' + window.location.host + window.location.pathname;
|
const urlWithoutQuery = window.location.protocol + '//' + window.location.host + window.location.pathname;
|
||||||
console.log("Vector starting at " + urlWithoutQuery);
|
console.log("Vector starting at " + urlWithoutQuery);
|
||||||
if (configError) {
|
if (configError) {
|
||||||
return <div className="error">
|
return <div className="error">
|
||||||
Unable to load config file: please refresh the page to try again.
|
Unable to load config file: please refresh the page to try again.
|
||||||
</div>;
|
</div>;
|
||||||
} else if (validBrowser || acceptInvalidBrowser) {
|
} else if (acceptBrowser) {
|
||||||
platform.startUpdater();
|
platform.startUpdater();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -260,7 +203,7 @@ export async function loadApp() {
|
||||||
ConferenceHandler={VectorConferenceHandler}
|
ConferenceHandler={VectorConferenceHandler}
|
||||||
config={config}
|
config={config}
|
||||||
realQueryParams={params}
|
realQueryParams={params}
|
||||||
startingFragmentQueryParams={fragparts.params}
|
startingFragmentQueryParams={fragParams}
|
||||||
enableGuest={!config.disable_guests}
|
enableGuest={!config.disable_guests}
|
||||||
onTokenLoginCompleted={onTokenLoginCompleted}
|
onTokenLoginCompleted={onTokenLoginCompleted}
|
||||||
initialScreenAfterLogin={getScreenFromLocation(window.location)}
|
initialScreenAfterLogin={getScreenFromLocation(window.location)}
|
||||||
|
|
|
@ -25,6 +25,7 @@ require('gfm.css/gfm.css');
|
||||||
require('highlight.js/styles/github.css');
|
require('highlight.js/styles/github.css');
|
||||||
|
|
||||||
// These are things that can run before the skin loads - be careful not to reference the react-sdk though.
|
// These are things that can run before the skin loads - be careful not to reference the react-sdk though.
|
||||||
|
import {parseQsFromFragment} from "./url_utils";
|
||||||
import './modernizr';
|
import './modernizr';
|
||||||
|
|
||||||
// load service worker if available on this platform
|
// load service worker if available on this platform
|
||||||
|
@ -40,6 +41,41 @@ async function settled(prom: Promise<any>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkBrowserFeatures() {
|
||||||
|
if (!window.Modernizr) {
|
||||||
|
console.error("Cannot check features - Modernizr global is missing.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// custom checks atop Modernizr because it doesn't have ES2018/ES2019 checks in it for some features we depend on,
|
||||||
|
// Modernizr requires rules to be lowercase with no punctuation:
|
||||||
|
// ES2018: http://www.ecma-international.org/ecma-262/9.0/#sec-promise.prototype.finally
|
||||||
|
window.Modernizr.addTest("promiseprototypefinally", () =>
|
||||||
|
window.Promise && window.Promise.prototype && typeof window.Promise.prototype.finally === "function");
|
||||||
|
// ES2019: http://www.ecma-international.org/ecma-262/10.0/#sec-object.fromentries
|
||||||
|
window.Modernizr.addTest("objectfromentries", () =>
|
||||||
|
window.Object && typeof window.Object.fromEntries === "function");
|
||||||
|
|
||||||
|
const featureList = Object.keys(window.Modernizr);
|
||||||
|
|
||||||
|
let featureComplete = true;
|
||||||
|
for (let i = 0; i < featureList.length; i++) {
|
||||||
|
if (window.Modernizr[featureList[i]] === undefined) {
|
||||||
|
console.error(
|
||||||
|
"Looked for feature '%s' but Modernizr has no results for this. " +
|
||||||
|
"Has it been configured correctly?", featureList[i],
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (window.Modernizr[featureList[i]] === false) {
|
||||||
|
console.error("Browser missing feature: '%s'", featureList[i]);
|
||||||
|
// toggle flag rather than return early so we log all missing features rather than just the first.
|
||||||
|
featureComplete = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return featureComplete;
|
||||||
|
}
|
||||||
|
|
||||||
// React depends on Map & Set which we check for using modernizr's es6collections
|
// React depends on Map & Set which we check for using modernizr's es6collections
|
||||||
// if modernizr fails we may not have a functional react to show the error message.
|
// if modernizr fails we may not have a functional react to show the error message.
|
||||||
// try in react but fallback to an `alert`
|
// try in react but fallback to an `alert`
|
||||||
|
@ -52,11 +88,35 @@ async function start() {
|
||||||
|
|
||||||
await settled(rageshakePromise); // give rageshake a chance to load/fail
|
await settled(rageshakePromise); // give rageshake a chance to load/fail
|
||||||
|
|
||||||
|
const fragparts = parseQsFromFragment(window.location);
|
||||||
|
|
||||||
|
// don't try to redirect to the native apps if we're
|
||||||
|
// verifying a 3pid (but after we've loaded the config)
|
||||||
|
// or if the user is following a deep link
|
||||||
|
// (https://github.com/vector-im/riot-web/issues/7378)
|
||||||
|
const preventRedirect = fragparts.params.client_secret || fragparts.location.length > 0;
|
||||||
|
|
||||||
|
if (!preventRedirect) {
|
||||||
|
const isIos = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
|
||||||
|
const isAndroid = /Android/.test(navigator.userAgent);
|
||||||
|
if (isIos || isAndroid) {
|
||||||
|
if (document.cookie.indexOf("riot_mobile_redirect_to_guide=false") === -1) {
|
||||||
|
window.location.href = "mobile_guide/";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await loadSkin();
|
await loadSkin();
|
||||||
|
|
||||||
|
let acceptBrowser = checkBrowserFeatures();
|
||||||
|
if (!acceptBrowser && window.localStorage) {
|
||||||
|
acceptBrowser = Boolean(window.localStorage.getItem("mx_accepts_unsupported_browser"));
|
||||||
|
}
|
||||||
|
|
||||||
// Finally, load the app. All of the other react-sdk imports are in this file which causes the skinner to
|
// Finally, load the app. All of the other react-sdk imports are in this file which causes the skinner to
|
||||||
// run on the components. We use `require` here to make sure webpack doesn't optimize this into an async
|
// run on the components. We use `require` here to make sure webpack doesn't optimize this into an async
|
||||||
// import and thus running before the skin can load.
|
// import and thus running before the skin can load.
|
||||||
await loadApp();
|
await loadApp(fragparts.params, acceptBrowser);
|
||||||
}
|
}
|
||||||
start();
|
start();
|
||||||
|
|
|
@ -138,11 +138,12 @@ export async function loadSkin() {
|
||||||
console.log("Skin loaded!");
|
console.log("Skin loaded!");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadApp() {
|
export async function loadApp(fragParams: {}, acceptBrowser: boolean) {
|
||||||
// load app.js async so that its code is not executed immediately and we can catch any exceptions
|
// load app.js async so that its code is not executed immediately and we can catch any exceptions
|
||||||
const module = await import(
|
const module = await import(
|
||||||
/* webpackChunkName: "riot-web-app" */
|
/* webpackChunkName: "riot-web-app" */
|
||||||
/* webpackPreload: true */
|
/* webpackPreload: true */
|
||||||
"./app");
|
"./app");
|
||||||
window.matrixChat = ReactDOM.render(await module.loadApp(), document.getElementById('matrixchat'));
|
window.matrixChat = ReactDOM.render(await module.loadApp(fragParams, acceptBrowser),
|
||||||
|
document.getElementById('matrixchat'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ export function parseQsFromFragment(location: Location) {
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
location: decodeURIComponent(hashparts[0]),
|
location: decodeURIComponent(hashparts[0]),
|
||||||
params: {},
|
params: <qs.ParsedUrlQuery>{},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (hashparts.length > 1) {
|
if (hashparts.length > 1) {
|
||||||
|
|
|
@ -31,7 +31,7 @@ module.exports = (env, argv) => {
|
||||||
...development,
|
...development,
|
||||||
|
|
||||||
entry: {
|
entry: {
|
||||||
"bundle": "./src/vector/index.js",
|
"bundle": "./src/vector/index.ts",
|
||||||
"indexeddb-worker": "./src/vector/indexeddb-worker.js",
|
"indexeddb-worker": "./src/vector/indexeddb-worker.js",
|
||||||
"mobileguide": "./src/vector/mobile_guide/index.js",
|
"mobileguide": "./src/vector/mobile_guide/index.js",
|
||||||
"jitsi": "./src/vector/jitsi/index.ts",
|
"jitsi": "./src/vector/jitsi/index.ts",
|
||||||
|
|
|
@ -1245,6 +1245,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
||||||
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
||||||
|
|
||||||
|
"@types/modernizr@^3.5.3":
|
||||||
|
version "3.5.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/modernizr/-/modernizr-3.5.3.tgz#8ef99e6252191c1d88647809109dc29884ba6d7a"
|
||||||
|
integrity sha512-jhMOZSS0UGYTS9pqvt6q3wtT3uvOSve5piTEmTMx3zzTuBLvSIMxSIBIc3d5lajVD5h4xc41AMZD2M5orN3PxA==
|
||||||
|
|
||||||
"@types/node@*":
|
"@types/node@*":
|
||||||
version "13.9.0"
|
version "13.9.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.0.tgz#5b6ee7a77faacddd7de719017d0bc12f52f81589"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.0.tgz#5b6ee7a77faacddd7de719017d0bc12f52f81589"
|
||||||
|
|
Loading…
Reference in a new issue