Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
Weblate 2017-06-15 16:35:46 +00:00
commit 81d0388021
16 changed files with 250 additions and 122 deletions

View file

@ -146,7 +146,6 @@ src/Roles.js
src/RoomListSorter.js
src/RoomNotifs.js
src/Rooms.js
src/RtsClient.js
src/ScalarAuthClient.js
src/ScalarMessaging.js
src/SdkConfig.js

View file

@ -1,3 +1,13 @@
Changes in [0.9.4](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.9.4) (2017-06-14)
===================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.9.3...v0.9.4)
* Ask for email address after setting password for the first time
[\#1090](https://github.com/matrix-org/matrix-react-sdk/pull/1090)
* DM guessing: prefer oldest joined member
[\#1087](https://github.com/matrix-org/matrix-react-sdk/pull/1087)
* More translations
Changes in [0.9.3](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.9.3) (2017-06-12)
===================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.9.3-rc.2...v0.9.3)

View file

@ -1,6 +1,6 @@
{
"name": "matrix-react-sdk",
"version": "0.9.3",
"version": "0.9.4",
"description": "SDK for matrix.org using React",
"author": "matrix.org",
"repository": {

View file

@ -19,6 +19,7 @@ import q from 'q';
import Matrix from 'matrix-js-sdk';
import MatrixClientPeg from './MatrixClientPeg';
import createMatrixClient from './utils/createMatrixClient';
import Analytics from './Analytics';
import Notifier from './Notifier';
import UserActivity from './UserActivity';
@ -34,9 +35,6 @@ import { _t } from './languageHandler';
* Called at startup, to attempt to build a logged-in Matrix session. It tries
* a number of things:
*
* 0. if it looks like we are in the middle of a registration process, it does
* nothing.
*
* 1. if we have a loginToken in the (real) query params, it uses that to log
* in.
*
@ -48,7 +46,7 @@ import { _t } from './languageHandler';
*
* 4. it attempts to auto-register as a guest user.
*
* If any of steps 1-4 are successful, it will call {setLoggedIn}, which in
* If any of steps 1-4 are successful, it will call {_doSetLoggedIn}, which in
* turn will raise on_logged_in and will_start_client events.
*
* @param {object} opts
@ -79,14 +77,6 @@ export function loadSession(opts) {
const guestIsUrl = opts.guestIsUrl;
const defaultDeviceDisplayName = opts.defaultDeviceDisplayName;
if (fragmentQueryParams.client_secret && fragmentQueryParams.sid) {
// this happens during email validation: the email contains a link to the
// IS, which in turn redirects back to vector. We let MatrixChat create a
// Registration component which completes the next stage of registration.
console.log("Not registering as guest: registration already in progress.");
return q();
}
if (!guestHsUrl) {
console.warn("Cannot enable guest access: can't determine HS URL to use");
enableGuest = false;
@ -105,14 +95,13 @@ export function loadSession(opts) {
fragmentQueryParams.guest_access_token
) {
console.log("Using guest access credentials");
setLoggedIn({
return _doSetLoggedIn({
userId: fragmentQueryParams.guest_user_id,
accessToken: fragmentQueryParams.guest_access_token,
homeserverUrl: guestHsUrl,
identityServerUrl: guestIsUrl,
guest: true,
});
return q();
}, true);
}
return _restoreFromLocalStorage().then((success) => {
@ -141,14 +130,14 @@ function _loginWithToken(queryParams, defaultDeviceDisplayName) {
},
).then(function(data) {
console.log("Logged in with token");
setLoggedIn({
return _doSetLoggedIn({
userId: data.user_id,
deviceId: data.device_id,
accessToken: data.access_token,
homeserverUrl: queryParams.homeserver,
identityServerUrl: queryParams.identityServer,
guest: false,
});
}, true);
}, (err) => {
console.error("Failed to log in with login token: " + err + " " +
err.data);
@ -172,14 +161,14 @@ function _registerAsGuest(hsUrl, isUrl, defaultDeviceDisplayName) {
},
}).then((creds) => {
console.log("Registered as guest: %s", creds.user_id);
setLoggedIn({
return _doSetLoggedIn({
userId: creds.user_id,
deviceId: creds.device_id,
accessToken: creds.access_token,
homeserverUrl: hsUrl,
identityServerUrl: isUrl,
guest: true,
});
}, true);
}, (err) => {
console.error("Failed to register as guest: " + err + " " + err.data);
});
@ -216,15 +205,14 @@ function _restoreFromLocalStorage() {
if (accessToken && userId && hsUrl) {
console.log("Restoring session for %s", userId);
try {
setLoggedIn({
return _doSetLoggedIn({
userId: userId,
deviceId: deviceId,
accessToken: accessToken,
homeserverUrl: hsUrl,
identityServerUrl: isUrl,
guest: isGuest,
});
return q(true);
}, false).then(() => true);
} catch (e) {
return _handleRestoreFailure(e);
}
@ -245,7 +233,7 @@ function _handleRestoreFailure(e) {
+ ' This is a once off; sorry for the inconvenience.',
);
_clearLocalStorage();
_clearStorage();
return q.reject(new Error(
_t('Unable to restore previous session') + ': ' + msg,
@ -266,7 +254,7 @@ function _handleRestoreFailure(e) {
return def.promise.then((success) => {
if (success) {
// user clicked continue.
_clearLocalStorage();
_clearStorage();
return false;
}
@ -277,17 +265,40 @@ function _handleRestoreFailure(e) {
let rtsClient = null;
export function initRtsClient(url) {
rtsClient = new RtsClient(url);
if (url) {
rtsClient = new RtsClient(url);
} else {
rtsClient = null;
}
}
/**
* Transitions to a logged-in state using the given credentials
* Transitions to a logged-in state using the given credentials.
*
* Starts the matrix client and all other react-sdk services that
* listen for events while a session is logged in.
*
* Also stops the old MatrixClient and clears old credentials/etc out of
* storage before starting the new client.
*
* @param {MatrixClientCreds} credentials The credentials to use
*/
export function setLoggedIn(credentials) {
credentials.guest = Boolean(credentials.guest);
stopMatrixClient();
_doSetLoggedIn(credentials, true);
}
Analytics.setGuest(credentials.guest);
/**
* fires on_logging_in, optionally clears localstorage, persists new credentials
* to localstorage, starts the new client.
*
* @param {MatrixClientCreds} credentials
* @param {Boolean} clearStorage
*
* returns a Promise which resolves once the client has been started
*/
async function _doSetLoggedIn(credentials, clearStorage) {
credentials.guest = Boolean(credentials.guest);
console.log(
"setLoggedIn: mxid:", credentials.userId,
@ -295,12 +306,19 @@ export function setLoggedIn(credentials) {
"guest:", credentials.guest,
"hs:", credentials.homeserverUrl,
);
// This is dispatched to indicate that the user is still in the process of logging in
// because `teamPromise` may take some time to resolve, breaking the assumption that
// `setLoggedIn` takes an "instant" to complete, and dispatch `on_logged_in` a few ms
// later than MatrixChat might assume.
dis.dispatch({action: 'on_logging_in'});
if (clearStorage) {
await _clearStorage();
}
Analytics.setGuest(credentials.guest);
// Resolves by default
let teamPromise = Promise.resolve(null);
@ -349,9 +367,6 @@ export function setLoggedIn(credentials) {
console.warn("No local storage available: can't persist session!");
}
// stop any running clients before we create a new one with these new credentials
stopMatrixClient();
MatrixClientPeg.replaceUsingCreds(credentials);
teamPromise.then((teamToken) => {
@ -400,7 +415,7 @@ export function logout() {
* Starts the matrix client and all other react-sdk services that
* listen for events while a session is logged in.
*/
export function startMatrixClient() {
function startMatrixClient() {
// dispatch this before starting the matrix client: it's used
// to add listeners for the 'sync' event so otherwise we'd have
// a race condition (and we need to dispatch synchronously for this
@ -416,34 +431,44 @@ export function startMatrixClient() {
}
/*
* Stops a running client and all related services, used after
* a session has been logged out / ended.
* Stops a running client and all related services, and clears persistent
* storage. Used after a session has been logged out.
*/
export function onLoggedOut() {
_clearLocalStorage();
stopMatrixClient();
_clearStorage().done();
dis.dispatch({action: 'on_logged_out'});
}
function _clearLocalStorage() {
/**
* @returns {Promise} promise which resolves once the stores have been cleared
*/
function _clearStorage() {
Analytics.logout();
if (!window.localStorage) {
return;
}
const hsUrl = window.localStorage.getItem("mx_hs_url");
const isUrl = window.localStorage.getItem("mx_is_url");
window.localStorage.clear();
// preserve our HS & IS URLs for convenience
// N.B. we cache them in hsUrl/isUrl and can't really inline them
// as getCurrentHsUrl() may call through to localStorage.
// NB. We do clear the device ID (as well as all the settings)
if (hsUrl) window.localStorage.setItem("mx_hs_url", hsUrl);
if (isUrl) window.localStorage.setItem("mx_is_url", isUrl);
if (window.localStorage) {
const hsUrl = window.localStorage.getItem("mx_hs_url");
const isUrl = window.localStorage.getItem("mx_is_url");
window.localStorage.clear();
// preserve our HS & IS URLs for convenience
// N.B. we cache them in hsUrl/isUrl and can't really inline them
// as getCurrentHsUrl() may call through to localStorage.
// NB. We do clear the device ID (as well as all the settings)
if (hsUrl) window.localStorage.setItem("mx_hs_url", hsUrl);
if (isUrl) window.localStorage.setItem("mx_is_url", isUrl);
}
// create a temporary client to clear out the persistent stores.
const cli = createMatrixClient({
// we'll never make any requests, so can pass a bogus HS URL
baseUrl: "",
});
return cli.clearStores();
}
/**
* Stop all the background processes related to the current client
* Stop all the background processes related to the current client.
*/
export function stopMatrixClient() {
Notifier.stop();
@ -454,7 +479,6 @@ export function stopMatrixClient() {
if (cli) {
cli.stopClient();
cli.removeAllListeners();
cli.store.deleteAllData();
MatrixClientPeg.unset();
}
}

View file

@ -16,12 +16,10 @@ limitations under the License.
'use strict';
import Matrix from 'matrix-js-sdk';
import utils from 'matrix-js-sdk/lib/utils';
import EventTimeline from 'matrix-js-sdk/lib/models/event-timeline';
import EventTimelineSet from 'matrix-js-sdk/lib/models/event-timeline-set';
const localStorage = window.localStorage;
import createMatrixClient from './utils/createMatrixClient';
interface MatrixClientCreds {
homeserverUrl: string,
@ -129,22 +127,7 @@ class MatrixClientPeg {
timelineSupport: true,
};
if (localStorage) {
opts.sessionStore = new Matrix.WebStorageSessionStore(localStorage);
}
if (window.indexedDB && localStorage) {
// FIXME: bodge to remove old database. Remove this after a few weeks.
window.indexedDB.deleteDatabase("matrix-js-sdk:default");
opts.store = new Matrix.IndexedDBStore({
indexedDB: window.indexedDB,
dbName: "riot-web-sync",
localStorage: localStorage,
workerScript: this.indexedDbWorkerScript,
});
}
this.matrixClient = Matrix.createClient(opts);
this.matrixClient = createMatrixClient(opts);
// we're going to add eventlisteners for each matrix event tile, so the
// potential number of event listeners is quite high.

View file

@ -144,7 +144,18 @@ export function guessDMRoomTarget(room, me) {
let oldestTs;
let oldestUser;
// Pick the user who's been here longest (and isn't us)
// Pick the joined user who's been here longest (and isn't us),
for (const user of room.getJoinedMembers()) {
if (user.userId == me.userId) continue;
if (oldestTs === undefined || user.events.member.getTs() < oldestTs) {
oldestUser = user;
oldestTs = user.events.member.getTs();
}
}
if (oldestUser) return oldestUser;
// if there are no joined members other than us, use the oldest member
for (const user of room.currentState.getMembers()) {
if (user.userId == me.userId) continue;

View file

@ -1,5 +1,7 @@
import 'whatwg-fetch';
let fetchFunction = fetch;
function checkStatus(response) {
if (!response.ok) {
return response.text().then((text) => {
@ -31,7 +33,7 @@ const request = (url, opts) => {
opts.body = JSON.stringify(opts.body);
opts.headers['Content-Type'] = 'application/json';
}
return fetch(url, opts)
return fetchFunction(url, opts)
.then(checkStatus)
.then(parseJson);
};
@ -64,7 +66,7 @@ export default class RtsClient {
client_secret: clientSecret,
},
method: 'POST',
}
},
);
}
@ -74,7 +76,7 @@ export default class RtsClient {
qs: {
team_token: teamToken,
},
}
},
);
}
@ -91,7 +93,12 @@ export default class RtsClient {
qs: {
user_id: userId,
},
}
},
);
}
// allow fetch to be replaced, for testing.
static setFetch(fn) {
fetchFunction = fn;
}
}

View file

@ -263,10 +263,22 @@ module.exports = React.createClass({
window.addEventListener('resize', this.handleResize);
this.handleResize();
if (this.props.config.teamServerConfig &&
this.props.config.teamServerConfig.teamServerURL
) {
Lifecycle.initRtsClient(this.props.config.teamServerConfig.teamServerURL);
const teamServerConfig = this.props.config.teamServerConfig || {};
Lifecycle.initRtsClient(teamServerConfig.teamServerURL);
// if the user has followed a login or register link, don't reanimate
// the old creds, but rather go straight to the relevant page
const firstScreen = this.state.screenAfterLogin ?
this.state.screenAfterLogin.screen : null;
if (firstScreen === 'login' ||
firstScreen === 'register' ||
firstScreen === 'forgot_password') {
this.props.onLoadCompleted();
this.setState({loading: false});
this._showScreenAfterLogin();
return;
}
// the extra q() ensures that synchronous exceptions hit the same codepath as
@ -840,14 +852,6 @@ module.exports = React.createClass({
_onLoadCompleted: function() {
this.props.onLoadCompleted();
this.setState({loading: false});
// Show screens (like 'register') that need to be shown without _onLoggedIn
// being called. 'register' needs to be routed here when the email confirmation
// link is clicked on.
if (this.state.screenAfterLogin &&
['register'].indexOf(this.state.screenAfterLogin.screen) !== -1) {
this._showScreenAfterLogin();
}
},
/**
@ -946,6 +950,7 @@ module.exports = React.createClass({
this.state.screenAfterLogin.screen,
this.state.screenAfterLogin.params,
);
// XXX: is this necessary? `showScreen` should do it for us.
this.notifyNewScreen(this.state.screenAfterLogin.screen);
this.setState({screenAfterLogin: null});
} else if (localStorage && localStorage.getItem('mx_last_room_id')) {
@ -1229,6 +1234,8 @@ module.exports = React.createClass({
onReturnToGuestClick: function() {
// reanimate our guest login
if (this.state.guestCreds) {
// TODO: this is probably a bit broken - we don't want to be
// clearing storage when we reanimate the guest creds.
Lifecycle.setLoggedIn(this.state.guestCreds);
this.setState({guestCreds: null});
}

View file

@ -170,6 +170,25 @@ module.exports = React.createClass({
isInitialEventHighlighted: RoomViewStore.isInitialEventHighlighted(),
};
// Temporary logging to diagnose https://github.com/vector-im/riot-web/issues/4307
console.log(
'RVS update:',
newState.roomId,
newState.roomAlias,
'loading?', newState.roomLoading,
'joining?', newState.joining,
);
// finished joining, start waiting for a room and show a spinner. See onRoom.
newState.waitingForRoom = this.state.joining && !newState.joining &&
!RoomViewStore.getJoinError();
// NB: This does assume that the roomID will not change for the lifetime of
// the RoomView instance
if (initial) {
newState.room = MatrixClientPeg.get().getRoom(newState.roomId);
}
// Clear the search results when clicking a search result (which changes the
// currently scrolled to event, this.state.initialEventId).
if (this.state.initialEventId !== newState.initialEventId) {
@ -185,8 +204,9 @@ module.exports = React.createClass({
this.setState(newState, () => {
// At this point, this.state.roomId could be null (e.g. the alias might not
// have been resolved yet) so anything called here must handle this case.
this._onHaveRoom();
this.onRoom(MatrixClientPeg.get().getRoom(this.state.roomId));
if (initial) {
this._onHaveRoom();
}
});
},
@ -202,25 +222,20 @@ module.exports = React.createClass({
// which must be by alias or invite wherever possible (peeking currently does
// not work over federation).
// NB. We peek if we are not in the room, although if we try to peek into
// a room in which we have a member event (ie. we've left) synapse will just
// send us the same data as we get in the sync (ie. the last events we saw).
const room = MatrixClientPeg.get().getRoom(this.state.roomId);
let isUserJoined = null;
// NB. We peek if we have never seen the room before (i.e. js-sdk does not know
// about it). We don't peek in the historical case where we were joined but are
// now not joined because the js-sdk peeking API will clobber our historical room,
// making it impossible to indicate a newly joined room.
const room = this.state.room;
if (room) {
isUserJoined = room.hasMembershipState(
MatrixClientPeg.get().credentials.userId, 'join',
);
this._updateAutoComplete(room);
this.tabComplete.loadEntries(room);
}
if (!isUserJoined && !this.state.joining && this.state.roomId) {
if (!this.state.joining && this.state.roomId) {
if (this.props.autoJoin) {
this.onJoinButtonClicked();
} else if (this.state.roomId) {
} else if (!room) {
console.log("Attempting to peek into room %s", this.state.roomId);
this.setState({
peekLoading: true,
});
@ -244,7 +259,8 @@ module.exports = React.createClass({
}
}).done();
}
} else if (isUserJoined) {
} else if (room) {
// Stop peeking because we have joined this room previously
MatrixClientPeg.get().stopPeeking();
this.setState({
unsentMessageError: this._getUnsentMessageError(room),
@ -607,6 +623,7 @@ module.exports = React.createClass({
}
this.setState({
room: room,
waitingForRoom: false,
}, () => {
this._onRoomLoaded(room);
});
@ -662,7 +679,14 @@ module.exports = React.createClass({
onRoomMemberMembership: function(ev, member, oldMembership) {
if (member.userId == MatrixClientPeg.get().credentials.userId) {
this.forceUpdate();
if (member.membership === 'join') {
this.setState({
waitingForRoom: false,
});
} else {
this.forceUpdate();
}
}
},
@ -1416,6 +1440,10 @@ module.exports = React.createClass({
const Loader = sdk.getComponent("elements.Spinner");
const TimelinePanel = sdk.getComponent("structures.TimelinePanel");
// Whether the preview bar spinner should be shown. We do this when joining or
// when waiting for a room to be returned by js-sdk when joining
const previewBarSpinner = this.state.joining || this.state.waitingForRoom;
if (!this.state.room) {
if (this.state.roomLoading || this.state.peekLoading) {
return (
@ -1449,7 +1477,7 @@ module.exports = React.createClass({
onRejectClick={ this.onRejectThreepidInviteButtonClicked }
canPreview={ false } error={ this.state.roomLoadError }
roomAlias={room_alias}
spinner={this.state.joining}
spinner={previewBarSpinner}
inviterName={inviterName}
invitedEmail={invitedEmail}
room={this.state.room}
@ -1492,7 +1520,7 @@ module.exports = React.createClass({
onRejectClick={ this.onRejectButtonClicked }
inviterName={ inviterName }
canPreview={ false }
spinner={this.state.joining}
spinner={previewBarSpinner}
room={this.state.room}
/>
</div>
@ -1568,7 +1596,7 @@ module.exports = React.createClass({
<RoomPreviewBar onJoinClick={this.onJoinButtonClicked}
onForgetClick={ this.onForgetClick }
onRejectClick={this.onRejectThreepidInviteButtonClicked}
spinner={this.state.joining}
spinner={previewBarSpinner}
inviterName={inviterName}
invitedEmail={invitedEmail}
canPreview={this.state.canPeek}

View file

@ -352,13 +352,14 @@ module.exports = React.createClass({
const tile = tiles[backwards ? i : tiles.length - 1 - i];
// Subtract height of tile as if it were unpaginated
excessHeight -= tile.clientHeight;
//If removing the tile would lead to future pagination, break before setting scroll token
if (tile.clientHeight > excessHeight) {
break;
}
// The tile may not have a scroll token, so guard it
if (tile.dataset.scrollTokens) {
markerScrollToken = tile.dataset.scrollTokens.split(',')[0];
}
if (tile.clientHeight > excessHeight) {
break;
}
}
if (markerScrollToken) {

View file

@ -14,15 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import q from 'q';
import React from 'react';
import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import classnames from 'classnames';
import KeyCode from '../../../KeyCode';
import Email from '../../../email';
import AddThreepid from '../../../AddThreepid';
import { _t, _tJsx } from '../../../languageHandler';
import { _t } from '../../../languageHandler';
import Modal from '../../../Modal';
@ -89,6 +85,10 @@ export default React.createClass({
this.setState({emailBusy: true});
},
onCancelled: function() {
this.props.onFinished(false);
},
onEmailDialogFinished: function(ok) {
if (ok) {
this.verifyEmailAddress();
@ -137,7 +137,7 @@ export default React.createClass({
return (
<BaseDialog className="mx_SetEmailDialog"
onFinished={this.props.onFinished}
onFinished={this.onCancelled}
title={this.props.title}
>
<div className="mx_Dialog_content">
@ -155,7 +155,7 @@ export default React.createClass({
<input
type="submit"
value={_t("Cancel")}
onClick={this.props.onFinished}
onClick={this.onCancelled}
/>
</div>
</BaseDialog>

View file

@ -223,7 +223,7 @@ module.exports = React.createClass({
const passwordLabel = this.state.cachedPassword ?
_t('Password') : _t('New Password');
return (
<div className={this.props.className}>
<form className={this.props.className} onSubmit={this.onClickChange}>
{ currentPassword }
<div className={rowClassName}>
<div className={rowLabelClassName}>
@ -246,7 +246,7 @@ module.exports = React.createClass({
element="button">
{ _t('Change Password') }
</AccessibleButton>
</div>
</form>
);
case this.Phases.Uploading:
var Loader = sdk.getComponent("elements.Spinner");

View file

@ -41,9 +41,6 @@ class MatrixDispatcher extends flux.Dispatcher {
}
}
// XXX this is a big anti-pattern, and makes testing hard. Because dispatches
// happen asynchronously, it is possible for actions dispatched in one thread
// to arrive in another, with *hilarious* consequences.
if (global.mxDispatcher === undefined) {
global.mxDispatcher = new MatrixDispatcher();
}

View file

@ -15,6 +15,7 @@ limitations under the License.
*/
import Skinner from './Skinner';
import RtsClient from './RtsClient';
module.exports.loadSkin = function(skinObject) {
Skinner.load(skinObject);
@ -27,3 +28,7 @@ module.exports.resetSkin = function() {
module.exports.getComponent = function(componentName) {
return Skinner.getComponent(componentName);
};
module.exports.setFetch = function(fetchFunction) {
RtsClient.setFetch(fetchFunction);
};

View file

@ -123,6 +123,7 @@ class RoomViewStore extends Store {
if (payload.room_id) {
const newState = {
roomId: payload.room_id,
roomAlias: payload.room_alias,
initialEventId: payload.event_id,
initialEventPixelOffset: undefined,
isInitialEventHighlighted: payload.highlighted,

View file

@ -0,0 +1,55 @@
/*
Copyright 2017 Vector Creations Ltd
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.
*/
import Matrix from 'matrix-js-sdk';
const localStorage = window.localStorage;
/**
* Create a new matrix client, with the persistent stores set up appropriately
* (using localstorage/indexeddb, etc)
*
* @param {Object} opts options to pass to Matrix.createClient. This will be
* extended with `sessionStore` and `store` members.
*
* @param {string} indexedDbWorkerScript Optional URL for a web worker script
* for IndexedDB store operations. If not given, indexeddb ops are done on
* the main thread.
*
* @returns {MatrixClient} the newly-created MatrixClient
*/
export default function createMatrixClient(opts, indexedDbWorkerScript) {
const storeOpts = {};
if (localStorage) {
storeOpts.sessionStore = new Matrix.WebStorageSessionStore(localStorage);
}
if (window.indexedDB && localStorage) {
// FIXME: bodge to remove old database. Remove this after a few weeks.
window.indexedDB.deleteDatabase("matrix-js-sdk:default");
storeOpts.store = new Matrix.IndexedDBStore({
indexedDB: window.indexedDB,
dbName: "riot-web-sync",
localStorage: localStorage,
workerScript: indexedDbWorkerScript,
});
}
opts = Object.assign(storeOpts, opts);
return Matrix.createClient(opts);
}