diff --git a/src/Lifecycle.js b/src/Lifecycle.js index a3bec14492..bf7b25fd2b 100644 --- a/src/Lifecycle.js +++ b/src/Lifecycle.js @@ -237,7 +237,7 @@ function _handleRestoreFailure(e) { + ' This is a once off; sorry for the inconvenience.', ); - _clearStorage(); + _clearLocalStorage(); return q.reject(new Error( _t('Unable to restore previous session') + ': ' + msg, @@ -258,7 +258,7 @@ function _handleRestoreFailure(e) { return def.promise.then((success) => { if (success) { // user clicked continue. - _clearStorage(); + _clearLocalStorage(); return false; } @@ -332,10 +332,6 @@ export function setLoggedIn(credentials) { } // stop any running clients before we create a new one with these new credentials - // - // XXX: why do we have any running clients here? Maybe on sign-in after - // initial use as a guest? but what about our persistent storage? we need to - // be careful not to leak e2e data created as one user into another session. stopMatrixClient(); MatrixClientPeg.replaceUsingCreds(credentials); @@ -406,19 +402,13 @@ export function startMatrixClient() { * a session has been logged out / ended. */ export function onLoggedOut() { - stopMatrixClient(true); + _clearLocalStorage(); + stopMatrixClient(); dis.dispatch({action: 'on_logged_out'}); } -function _clearStorage() { +function _clearLocalStorage() { Analytics.logout(); - - const cli = MatrixClientPeg.get(); - if (cli) { - // TODO: *really* ought to wait for the promise to complete - cli.clearStores().done(); - } - if (!window.localStorage) { return; } @@ -435,13 +425,9 @@ function _clearStorage() { } /** - * Stop all the background processes related to the current client. - * - * Optionally clears persistent stores. - * - * @param {boolean} clearStores true to clear the persistent stores. + * Stop all the background processes related to the current client */ -export function stopMatrixClient(clearStores) { +export function stopMatrixClient() { Notifier.stop(); UserActivity.stop(); Presence.stop(); @@ -450,13 +436,7 @@ export function stopMatrixClient(clearStores) { if (cli) { cli.stopClient(); cli.removeAllListeners(); + cli.store.deleteAllData(); + MatrixClientPeg.unset(); } - - if (clearStores) { - // note that we have to do this *after* stopping the client, but - // *before* clearing the MatrixClientPeg. - _clearStorage(); - } - - MatrixClientPeg.unset(); } diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 0dedc02270..c4d3df03d3 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -292,7 +292,7 @@ module.exports = React.createClass({ }, componentWillUnmount: function() { - Lifecycle.stopMatrixClient(false); + Lifecycle.stopMatrixClient(); dis.unregister(this.dispatcherRef); UDEHandler.stopListening(); window.removeEventListener("focus", this.onFocus); @@ -364,7 +364,7 @@ module.exports = React.createClass({ // is completed in another browser, we'll be 401ed for using // a guest access token for a non-guest account. // It will be restarted in onReturnToGuestClick - Lifecycle.stopMatrixClient(false); + Lifecycle.stopMatrixClient(); this.notifyNewScreen('register'); break; @@ -507,7 +507,11 @@ module.exports = React.createClass({ this._onSetTheme(payload.value); break; case 'on_logging_in': - this.setState({loggingIn: true}); + // We are now logging in, so set the state to reflect that + // and also that we're not ready (we'll be marked as logged + // in once the login completes, then ready once the sync + // completes). + this.setState({loggingIn: true, ready: false}); break; case 'on_logged_in': this._onLoggedIn(payload.teamToken); diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 89debcb461..6cb262e79a 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -88,6 +88,10 @@ const SETTINGS_LABELS = [ id: 'hideRedactions', label: 'Hide removed messages', }, + { + id: 'disableMarkdown', + label: 'Disable markdown formatting', + }, /* { id: 'useFixedWidthFont', diff --git a/src/components/views/rooms/MessageComposerInputOld.js b/src/components/views/rooms/MessageComposerInputOld.js index f6af20c03b..80fb51e6b5 100644 --- a/src/components/views/rooms/MessageComposerInputOld.js +++ b/src/components/views/rooms/MessageComposerInputOld.js @@ -29,7 +29,6 @@ var Markdown = require("../../../Markdown"); var TYPING_USER_TIMEOUT = 10000; var TYPING_SERVER_TIMEOUT = 30000; -var MARKDOWN_ENABLED = true; export function onSendMessageFailed(err, room) { // XXX: temporary logging to try to diagnose @@ -77,7 +76,8 @@ export default React.createClass({ componentWillMount: function() { this.oldScrollHeight = 0; - this.markdownEnabled = MARKDOWN_ENABLED; + this.markdownEnabled = !UserSettingsStore.getSyncedSetting('disableMarkdown', false); + var self = this; this.sentHistory = { // The list of typed messages. Index 0 is more recent diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index f02f70b88b..3b43ea2b39 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -275,43 +275,6 @@ module.exports = React.createClass({ } }); - if (s.lists["im.vector.fake.direct"].length == 0 && - MatrixClientPeg.get().getAccountData('m.direct') === undefined && - !MatrixClientPeg.get().isGuest()) - { - // scan through the 'recents' list for any rooms which look like DM rooms - // and make them DM rooms - const oldRecents = s.lists["im.vector.fake.recent"]; - s.lists["im.vector.fake.recent"] = []; - - for (const room of oldRecents) { - const me = room.getMember(MatrixClientPeg.get().credentials.userId); - - if (me && Rooms.looksLikeDirectMessageRoom(room, me)) { - s.lists["im.vector.fake.direct"].push(room); - } else { - s.lists["im.vector.fake.recent"].push(room); - } - } - - // save these new guessed DM rooms into the account data - const newMDirectEvent = {}; - for (const room of s.lists["im.vector.fake.direct"]) { - const me = room.getMember(MatrixClientPeg.get().credentials.userId); - const otherPerson = Rooms.getOnlyOtherMember(room, me); - if (!otherPerson) continue; - - const roomList = newMDirectEvent[otherPerson.userId] || []; - roomList.push(room.roomId); - newMDirectEvent[otherPerson.userId] = roomList; - } - - // if this fails, fine, we'll just do the same thing next time we get the room lists - MatrixClientPeg.get().setAccountData('m.direct', newMDirectEvent).done(); - } - - //console.log("calculated new roomLists; im.vector.fake.recent = " + s.lists["im.vector.fake.recent"]); - // we actually apply the sorting to this when receiving the prop in RoomSubLists. return s; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 2bef4b8901..6a7c510544 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -241,6 +241,7 @@ "Direct chats": "Direct chats", "disabled": "disabled", "Disable inline URL previews by default": "Disable inline URL previews by default", + "Disable markdown formatting": "Disable markdown formatting", "Disinvite": "Disinvite", "Display name": "Display name", "Displays action": "Displays action", diff --git a/src/languageHandler.js b/src/languageHandler.js index 798798b6e5..68e8ca6172 100644 --- a/src/languageHandler.js +++ b/src/languageHandler.js @@ -35,6 +35,25 @@ counterpart.setFallbackLocale('en'); // just import counterpart and use it directly, we end up using a different // instance. export function _t(...args) { + // Horrible hack to avoid https://github.com/vector-im/riot-web/issues/4191 + // The interpolation library that counterpart uses does not support undefined/null + // values and instead will throw an error. This is a problem since everywhere else + // in JS land passing undefined/null will simply stringify instead, and when converting + // valid ES6 template strings to i18n strings it's extremely easy to pass undefined/null + // if there are no existing null guards. To avoid this making the app completely inoperable, + // we'll check all the values for undefined/null and stringify them here. + if (args[1] && typeof args[1] === 'object') { + Object.keys(args[1]).forEach((k) => { + if (args[1][k] === undefined) { + console.warn("_t called with undefined interpolation name: " + k); + args[1][k] = 'undefined'; + } + if (args[1][k] === null) { + console.warn("_t called with null interpolation name: " + k); + args[1][k] = 'null'; + } + }); + } return counterpart.translate(...args); }