From f85a37c667713803bd0eee133d8127c48d139f8b Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 3 Nov 2016 18:42:26 +0000 Subject: [PATCH 1/6] Factor out LoggedInView from MatrixChat The idea here is to make a layer which sits around for as long as we have a valid MatrixClient. Also it makes a plausible split for the render of MatrixChat, even if they are much too tightly bound for now. --- src/PageTypes.js | 24 +++ src/component-index.js | 2 + src/components/structures/LoggedInView.js | 240 ++++++++++++++++++++++ src/components/structures/MatrixChat.js | 225 +++----------------- 4 files changed, 292 insertions(+), 199 deletions(-) create mode 100644 src/PageTypes.js create mode 100644 src/components/structures/LoggedInView.js diff --git a/src/PageTypes.js b/src/PageTypes.js new file mode 100644 index 0000000000..b2e2ecf4bc --- /dev/null +++ b/src/PageTypes.js @@ -0,0 +1,24 @@ +/* +Copyright 2015, 2016 OpenMarket 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. +*/ + +/** The types of page which can be shown by the LoggedInView */ +export default { + RoomView: "room_view", + UserSettings: "user_settings", + CreateRoom: "create_room", + RoomDirectory: "room_directory", + UserView: "user_view", +}; diff --git a/src/component-index.js b/src/component-index.js index 8fbf655879..50a02e0862 100644 --- a/src/component-index.js +++ b/src/component-index.js @@ -31,6 +31,8 @@ import structures$CreateRoom from './components/structures/CreateRoom'; structures$CreateRoom && (module.exports.components['structures.CreateRoom'] = structures$CreateRoom); import structures$FilePanel from './components/structures/FilePanel'; structures$FilePanel && (module.exports.components['structures.FilePanel'] = structures$FilePanel); +import structures$LoggedInView from './components/structures/LoggedInView'; +structures$LoggedInView && (module.exports.components['structures.LoggedInView'] = structures$LoggedInView); import structures$MatrixChat from './components/structures/MatrixChat'; structures$MatrixChat && (module.exports.components['structures.MatrixChat'] = structures$MatrixChat); import structures$MessagePanel from './components/structures/MessagePanel'; diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js new file mode 100644 index 0000000000..739b74c6bf --- /dev/null +++ b/src/components/structures/LoggedInView.js @@ -0,0 +1,240 @@ +/* +Copyright 2015, 2016 OpenMarket 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 * as Matrix from 'matrix-js-sdk'; +import React from 'react'; + +import KeyCode from '../../KeyCode'; +import Notifier from '../../Notifier'; +import PageTypes from '../../PageTypes'; +import sdk from '../../index'; + +/** + * This is what our MatrixChat shows when we are logged in. The precise view is + * determined by the page_type property. + * + * Currently it's very tightly coupled with MatrixChat. We should try to do + * something about that. + */ +export default React.createClass({ + displayName: 'LoggedInView', + + propTypes: { + matrixClient: React.PropTypes.instanceOf(Matrix.MatrixClient).isRequired, + page_type: React.PropTypes.string.isRequired, + onRoomIdResolved: React.PropTypes.func, + onRoomCreated: React.PropTypes.func, + onUserSettingsClose: React.PropTypes.func, + + // and lots and lots of other stuff. + }, + + componentWillMount: function() { + // _scrollStateMap is a map from room id to the scroll state returned by + // RoomView.getScrollState() + this._scrollStateMap = {}; + + document.addEventListener('keydown', this._onKeyDown); + }, + + componentWillUnmount: function() { + document.removeEventListener('keydown', this._onKeyDown); + }, + + componentWillReceiveProps: function(nextProps) { + if (nextProps.page_type !== this.props.page_type || + nextProps.currentRoomAlias !== this.props.currentRoomAlias || + nextProps.currentRoomId !== this.props.currentRoomId + ) { + + // stash the scroll state before we change view + this._updateScrollMap(); + } + }, + + getScrollStateForRoom: function(roomId) { + return this._scrollStateMap[roomId]; + }, + + // update scrollStateMap according to the current scroll state of the + // room view. + _updateScrollMap: function() { + if (!this.refs.roomView) { + return; + } + var roomview = this.refs.roomView; + var roomId = this.refs.roomView.getRoomId(); + if (!roomId) { + return; + } + var state = roomview.getScrollState(); + this._scrollStateMap[roomId] = state; + }, + + _onKeyDown: function(ev) { + /* + // Remove this for now as ctrl+alt = alt-gr so this breaks keyboards which rely on alt-gr for numbers + // Will need to find a better meta key if anyone actually cares about using this. + if (ev.altKey && ev.ctrlKey && ev.keyCode > 48 && ev.keyCode < 58) { + dis.dispatch({ + action: 'view_indexed_room', + roomIndex: ev.keyCode - 49, + }); + ev.stopPropagation(); + ev.preventDefault(); + return; + } + */ + + var handled = false; + + switch (ev.keyCode) { + case KeyCode.UP: + case KeyCode.DOWN: + if (ev.altKey) { + var action = ev.keyCode == KeyCode.UP ? + 'view_prev_room' : 'view_next_room'; + dis.dispatch({action: action}); + handled = true; + } + break; + + case KeyCode.PAGE_UP: + case KeyCode.PAGE_DOWN: + this._onScrollKeyPressed(ev); + handled = true; + break; + + case KeyCode.HOME: + case KeyCode.END: + if (ev.ctrlKey) { + this._onScrollKeyPressed(ev); + handled = true; + } + break; + } + + if (handled) { + ev.stopPropagation(); + ev.preventDefault(); + } + }, + + /** dispatch a page-up/page-down/etc to the appropriate component */ + _onScrollKeyPressed: function(ev) { + if (this.refs.roomView) { + this.refs.roomView.handleScrollKey(ev); + } + }, + + render: function() { + var LeftPanel = sdk.getComponent('structures.LeftPanel'); + var RightPanel = sdk.getComponent('structures.RightPanel'); + var RoomView = sdk.getComponent('structures.RoomView'); + var UserSettings = sdk.getComponent('structures.UserSettings'); + var CreateRoom = sdk.getComponent('structures.CreateRoom'); + var RoomDirectory = sdk.getComponent('structures.RoomDirectory'); + var MatrixToolbar = sdk.getComponent('globals.MatrixToolbar'); + var GuestWarningBar = sdk.getComponent('globals.GuestWarningBar'); + var NewVersionBar = sdk.getComponent('globals.NewVersionBar'); + + var page_element; + var right_panel = ''; + + switch (this.props.page_type) { + case PageTypes.RoomView: + page_element = + if (!this.props.collapse_rhs) right_panel = + break; + + case PageTypes.UserSettings: + page_element = + if (!this.props.collapse_rhs) right_panel = + break; + + case PageTypes.CreateRoom: + page_element = + if (!this.props.collapse_rhs) right_panel = + break; + + case PageTypes.RoomDirectory: + page_element = + if (!this.props.collapse_rhs) right_panel = + break; + case PageTypes.UserView: + page_element = null; // deliberately null for now + right_panel = + break; + } + + var topBar; + if (this.props.hasNewVersion) { + topBar = ; + } + else if (this.props.matrixClient.isGuest()) { + topBar = ; + } + else if (Notifier.supportsDesktopNotifications() && !Notifier.isEnabled() && !Notifier.isToolbarHidden()) { + topBar = ; + } + + var bodyClasses = 'mx_MatrixChat'; + if (topBar) { + bodyClasses += ' mx_MatrixChat_toolbarShowing'; + } + + return ( +
+ {topBar} +
+ +
+ {page_element} +
+ {right_panel} +
+
+ ); + }, +}); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 8582b85d12..e31bb201de 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -22,7 +22,6 @@ var Matrix = require("matrix-js-sdk"); var MatrixClientPeg = require("../../MatrixClientPeg"); var PlatformPeg = require("../../PlatformPeg"); var SdkConfig = require("../../SdkConfig"); -var Notifier = require("../../Notifier"); var ContextualMenu = require("./ContextualMenu"); var RoomListSorter = require("../../RoomListSorter"); var UserActivity = require("../../UserActivity"); @@ -38,8 +37,8 @@ var Tinter = require("../../Tinter"); var sdk = require('../../index'); var Rooms = require('../../Rooms'); var linkifyMatrix = require("../../linkify-matrix"); -var KeyCode = require('../../KeyCode'); var Lifecycle = require('../../Lifecycle'); +var PageTypes = require('../../PageTypes'); var createRoom = require("../../createRoom"); @@ -67,14 +66,6 @@ module.exports = React.createClass({ defaultDeviceDisplayName: React.PropTypes.string, }, - PageTypes: { - RoomView: "room_view", - UserSettings: "user_settings", - CreateRoom: "create_room", - RoomDirectory: "room_directory", - UserView: "user_view", - }, - AuxPanel: { RoomSettings: "room_settings", }, @@ -192,10 +183,6 @@ module.exports = React.createClass({ this.dispatcherRef = dis.register(this.onAction); this.focusComposer = false; - // scrollStateMap is a map from room id to the scroll state returned by - // RoomView.getScrollState() - this.scrollStateMap = {}; - document.addEventListener("keydown", this.onKeyDown); window.addEventListener("focus", this.onFocus); // this can technically be done anywhere but doing this here keeps all @@ -234,7 +221,6 @@ module.exports = React.createClass({ componentWillUnmount: function() { Lifecycle.stopMatrixClient(); dis.unregister(this.dispatcherRef); - document.removeEventListener("keydown", this.onKeyDown); window.removeEventListener("focus", this.onFocus); window.removeEventListener('resize', this.handleResize); }, @@ -399,11 +385,11 @@ module.exports = React.createClass({ } break; case 'view_user_settings': - this._setPage(this.PageTypes.UserSettings); + this._setPage(PageTypes.UserSettings); this.notifyNewScreen('settings'); break; case 'view_create_room': - //this._setPage(this.PageTypes.CreateRoom); + //this._setPage(PageTypes.CreateRoom); //this.notifyNewScreen('new'); var TextInputDialog = sdk.getComponent("dialogs.TextInputDialog"); @@ -421,7 +407,7 @@ module.exports = React.createClass({ }); break; case 'view_room_directory': - this._setPage(this.PageTypes.RoomDirectory); + this._setPage(PageTypes.RoomDirectory); this.notifyNewScreen('directory'); break; case 'view_create_chat': @@ -481,9 +467,6 @@ module.exports = React.createClass({ }, _setPage: function(pageType) { - // record the scroll state if we're in a room view. - this._updateScrollMap(); - this.setState({ page_type: pageType, }); @@ -506,16 +489,13 @@ module.exports = React.createClass({ // that has been passed out-of-band (eg. // room name and avatar from an invite email) _viewRoom: function(room_info) { - // before we switch room, record the scroll state of the current room - this._updateScrollMap(); - this.focusComposer = true; var newState = { initialEventId: room_info.event_id, highlightedEventId: room_info.event_id, initialEventPixelOffset: undefined, - page_type: this.PageTypes.RoomView, + page_type: PageTypes.RoomView, thirdPartyInvite: room_info.third_party_invite, roomOobData: room_info.oob_data, currentRoomAlias: room_info.room_alias, @@ -528,8 +508,8 @@ module.exports = React.createClass({ // if we aren't given an explicit event id, look for one in the // scrollStateMap. - if (!room_info.event_id) { - var scrollState = this.scrollStateMap[room_info.room_id]; + if (!room_info.event_id && this.refs.loggedInView) { + var scrollState = this.refs.loggedInView.getScrollStateForRoom(room_info.room_id); if (scrollState) { newState.initialEventId = scrollState.focussedEvent; newState.initialEventPixelOffset = scrollState.pixelOffset; @@ -566,10 +546,6 @@ module.exports = React.createClass({ newState.ready = true; } this.setState(newState); - - if (this.refs.roomView && room_info.showSettings) { - this.refs.roomView.showSettings(true); - } }, _createChat: function() { @@ -589,21 +565,6 @@ module.exports = React.createClass({ }); }, - // update scrollStateMap according to the current scroll state of the - // room view. - _updateScrollMap: function() { - if (!this.refs.roomView) { - return; - } - var roomview = this.refs.roomView; - var roomId = this.refs.roomView.getRoomId(); - if (!roomId) { - return; - } - var state = roomview.getScrollState(); - this.scrollStateMap[roomId] = state; - }, - /** * Called when the sessionloader has finished */ @@ -664,12 +625,12 @@ module.exports = React.createClass({ firstRoom = RoomListSorter.mostRecentActivityFirst( cli.getRooms() )[0].roomId; - self.setState({ready: true, currentRoomId: firstRoom, page_type: self.PageTypes.RoomView}); + self.setState({ready: true, currentRoomId: firstRoom, page_type: PageTypes.RoomView}); } else { - self.setState({ready: true, page_type: self.PageTypes.RoomDirectory}); + self.setState({ready: true, page_type: PageTypes.RoomDirectory}); } } else { - self.setState({ready: true, page_type: self.PageTypes.RoomView}); + self.setState({ready: true, page_type: PageTypes.RoomView}); } // we notifyNewScreen now because now the room will actually be displayed, @@ -712,62 +673,6 @@ module.exports = React.createClass({ }); }, - onKeyDown: function(ev) { - /* - // Remove this for now as ctrl+alt = alt-gr so this breaks keyboards which rely on alt-gr for numbers - // Will need to find a better meta key if anyone actually cares about using this. - if (ev.altKey && ev.ctrlKey && ev.keyCode > 48 && ev.keyCode < 58) { - dis.dispatch({ - action: 'view_indexed_room', - roomIndex: ev.keyCode - 49, - }); - ev.stopPropagation(); - ev.preventDefault(); - return; - } - */ - - var handled = false; - - switch (ev.keyCode) { - case KeyCode.UP: - case KeyCode.DOWN: - if (ev.altKey) { - var action = ev.keyCode == KeyCode.UP ? - 'view_prev_room' : 'view_next_room'; - dis.dispatch({action: action}); - handled = true; - } - break; - - case KeyCode.PAGE_UP: - case KeyCode.PAGE_DOWN: - this._onScrollKeyPressed(ev); - handled = true; - break; - - case KeyCode.HOME: - case KeyCode.END: - if (ev.ctrlKey) { - this._onScrollKeyPressed(ev); - handled = true; - } - break; - } - - if (handled) { - ev.stopPropagation(); - ev.preventDefault(); - } - }, - - /** dispatch a page-up/page-down/etc to the appropriate component */ - _onScrollKeyPressed(ev) { - if (this.refs.roomView) { - this.refs.roomView.handleScrollKey(ev); - } - }, - onFocus: function(ev) { dis.dispatch({action: 'focus_composer'}); }, @@ -845,7 +750,7 @@ module.exports = React.createClass({ } else if (screen.indexOf('user/') == 0) { var userId = screen.substring(5); this.setState({ viewUserId: userId }); - this._setPage(this.PageTypes.UserView); + this._setPage(PageTypes.UserView); this.notifyNewScreen('user/' + userId); var member = new Matrix.RoomMember(null, userId); if (member) { @@ -958,7 +863,7 @@ module.exports = React.createClass({ // the page type still unset when the MatrixClient // is started and show the Room Directory instead. //this.showScreen("view_user_settings"); - this._setPage(this.PageTypes.UserSettings); + this._setPage(PageTypes.UserSettings); }, onFinishPostRegistration: function() { @@ -1025,16 +930,8 @@ module.exports = React.createClass({ }, render: function() { - var LeftPanel = sdk.getComponent('structures.LeftPanel'); - var RoomView = sdk.getComponent('structures.RoomView'); - var RightPanel = sdk.getComponent('structures.RightPanel'); - var UserSettings = sdk.getComponent('structures.UserSettings'); - var CreateRoom = sdk.getComponent('structures.CreateRoom'); - var RoomDirectory = sdk.getComponent('structures.RoomDirectory'); - var MatrixToolbar = sdk.getComponent('globals.MatrixToolbar'); - var GuestWarningBar = sdk.getComponent('globals.GuestWarningBar'); - var NewVersionBar = sdk.getComponent('globals.NewVersionBar'); var ForgotPassword = sdk.getComponent('structures.login.ForgotPassword'); + var LoggedInView = sdk.getComponent('structures.LoggedInView'); // console.log("rendering; loading="+this.state.loading+"; screen="+this.state.screen + // "; logged_in="+this.state.logged_in+"; ready="+this.state.ready); @@ -1053,90 +950,20 @@ module.exports = React.createClass({ ); - } - else if (this.state.logged_in && this.state.ready) { - var page_element; - var right_panel = ""; - - switch (this.state.page_type) { - case this.PageTypes.RoomView: - page_element = - if (!this.state.collapse_rhs) right_panel = - break; - case this.PageTypes.UserSettings: - page_element = - if (!this.state.collapse_rhs) right_panel = - break; - case this.PageTypes.CreateRoom: - page_element = - if (!this.state.collapse_rhs) right_panel = - break; - case this.PageTypes.RoomDirectory: - page_element = - if (!this.state.collapse_rhs) right_panel = - break; - case this.PageTypes.UserView: - page_element = null; // deliberately null for now - right_panel = - break; - } - - var topBar; - if (this.state.hasNewVersion) { - topBar = ; - } - else if (MatrixClientPeg.get().isGuest()) { - topBar = ; - } - else if (Notifier.supportsDesktopNotifications() && !Notifier.isEnabled() && !Notifier.isToolbarHidden()) { - topBar = ; - } - - var bodyClasses = "mx_MatrixChat"; - if (topBar) { - bodyClasses += " mx_MatrixChat_toolbarShowing"; - } - + } else if (this.state.logged_in && this.state.ready) { + /* for now, we stuff the entirety of our props and state into the LoggedInView. + * we should go through and figure out what we actually need to pass down, as well + * as using something like redux to avoid having a billion bits of state kicking around. + */ return ( -
- {topBar} -
- -
- {page_element} -
- {right_panel} -
-
- ); + + ) } else if (this.state.logged_in) { // we think we are logged in, but are still waiting for the /sync to complete var Spinner = sdk.getComponent('elements.Spinner'); From d3f20e1d9de4a88c59a37936442704853025487f Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 3 Nov 2016 18:54:30 +0000 Subject: [PATCH 2/6] Add the MatrixClient to the react context Because that's the reacty way --- src/components/structures/LoggedInView.js | 15 +++++++++ src/wrappers/WithMatrixClient.js | 39 +++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/wrappers/WithMatrixClient.js diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 739b74c6bf..64bb492672 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -28,6 +28,8 @@ import sdk from '../../index'; * * Currently it's very tightly coupled with MatrixChat. We should try to do * something about that. + * + * Components mounted below us can access the matrix client via the react context. */ export default React.createClass({ displayName: 'LoggedInView', @@ -42,7 +44,20 @@ export default React.createClass({ // and lots and lots of other stuff. }, + childContextTypes: { + matrixClient: React.PropTypes.instanceOf(Matrix.MatrixClient), + }, + + getChildContext: function() { + return { + matrixClient: this._matrixClient, + }; + }, + componentWillMount: function() { + // stash the MatrixClient in case we log out before we are unmounted + this._matrixClient = this.props.matrixClient; + // _scrollStateMap is a map from room id to the scroll state returned by // RoomView.getScrollState() this._scrollStateMap = {}; diff --git a/src/wrappers/WithMatrixClient.js b/src/wrappers/WithMatrixClient.js new file mode 100644 index 0000000000..d8ccb3ff2d --- /dev/null +++ b/src/wrappers/WithMatrixClient.js @@ -0,0 +1,39 @@ +/* +Copyright 2015, 2016 OpenMarket 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 * as Matrix from 'matrix-js-sdk'; +import React from 'react'; + +/** + * Wraps a react class, pulling the MatrixClient from the context and adding it + * as a 'matrixClient' property instead. + * + * This abstracts the use of the context API, so that we can use a different + * mechanism in future. + */ +export default function(WrappedComponent) { + return React.createClass({ + displayName: "MatrixClient<" + WrappedComponent.displayName + ">", + + contextTypes: { + matrixClient: React.PropTypes.instanceOf(Matrix.MatrixClient).isRequired, + }, + + render: function() { + return ; + }, + }); +}; From cb5b311e447aff87a6fce180d40ff3eac55c4992 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 4 Nov 2016 09:28:35 +0000 Subject: [PATCH 3/6] Move saveScrollState into RoomView It fits much more naturally here than in LoggedInView. --- src/components/structures/LoggedInView.js | 27 +--------- src/components/structures/MatrixChat.js | 2 + src/components/structures/RoomView.js | 60 +++++++++++++---------- 3 files changed, 37 insertions(+), 52 deletions(-) diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 739b74c6bf..ea3f46d3d1 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -54,36 +54,10 @@ export default React.createClass({ document.removeEventListener('keydown', this._onKeyDown); }, - componentWillReceiveProps: function(nextProps) { - if (nextProps.page_type !== this.props.page_type || - nextProps.currentRoomAlias !== this.props.currentRoomAlias || - nextProps.currentRoomId !== this.props.currentRoomId - ) { - - // stash the scroll state before we change view - this._updateScrollMap(); - } - }, - getScrollStateForRoom: function(roomId) { return this._scrollStateMap[roomId]; }, - // update scrollStateMap according to the current scroll state of the - // room view. - _updateScrollMap: function() { - if (!this.refs.roomView) { - return; - } - var roomview = this.refs.roomView; - var roomId = this.refs.roomView.getRoomId(); - if (!roomId) { - return; - } - var state = roomview.getScrollState(); - this._scrollStateMap[roomId] = state; - }, - _onKeyDown: function(ev) { /* // Remove this for now as ctrl+alt = alt-gr so this breaks keyboards which rely on alt-gr for numbers @@ -170,6 +144,7 @@ export default React.createClass({ opacity={this.props.middleOpacity} collapsedRhs={this.props.collapse_rhs} ConferenceHandler={this.props.ConferenceHandler} + scrollStateMap={this._scrollStateMap} /> if (!this.props.collapse_rhs) right_panel = break; diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index e31bb201de..945088106b 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -508,6 +508,8 @@ module.exports = React.createClass({ // if we aren't given an explicit event id, look for one in the // scrollStateMap. + // + // TODO: do this in RoomView rather than here if (!room_info.event_id && this.refs.loggedInView) { var scrollState = this.refs.loggedInView.getScrollStateForRoom(room_info.room_id); if (scrollState) { diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 9040e280f2..4e578d8d28 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -100,6 +100,21 @@ module.exports = React.createClass({ // is the RightPanel collapsed? collapsedRhs: React.PropTypes.bool, + + // a map from room id to scroll state, which will be updated on unmount. + // + // If there is no special scroll state (ie, we are following the live + // timeline), the scroll state is null. Otherwise, it is an object with + // the following properties: + // + // focussedEvent: the ID of the 'focussed' event. Typically this is + // the last event fully visible in the viewport, though if we + // have done an explicit scroll to an explicit event, it will be + // that event. + // + // pixelOffset: the number of pixels the window is scrolled down + // from the focussedEvent. + scrollStateMap: React.PropTypes.object, }, getInitialState: function() { @@ -307,6 +322,9 @@ module.exports = React.createClass({ // (We could use isMounted, but facebook have deprecated that.) this.unmounted = true; + // update the scroll map before we get unmounted + this._updateScrollMap(); + if (this.refs.roomView) { // disconnect the D&D event listeners from the room view. This // is really just for hygiene - we're going to be @@ -1203,22 +1221,25 @@ module.exports = React.createClass({ } }, + // update scrollStateMap on unmount + _updateScrollMap: function() { + if (!this.state.room) { + // we were instantiated on a room alias and haven't yet joined the room. + return; + } + if (!this.props.scrollStateMap) return; + + var roomId = this.state.room.roomId; + + var state = this._getScrollState(); + this.props.scrollStateMap[roomId] = state; + }, + + // get the current scroll position of the room, so that it can be // restored when we switch back to it. // - // If there is no special scroll state (ie, we are following the live - // timeline), returns null. Otherwise, returns an object with the following - // properties: - // - // focussedEvent: the ID of the 'focussed' event. Typically this is the - // last event fully visible in the viewport, though if we have done - // an explicit scroll to an explicit event, it will be that event. - // - // pixelOffset: the number of pixels the window is scrolled down from - // the focussedEvent. - // - // - getScrollState: function() { + _getScrollState: function() { var messagePanel = this.refs.messagePanel; if (!messagePanel) return null; @@ -1333,19 +1354,6 @@ module.exports = React.createClass({ } }, - /** - * Get the ID of the displayed room - * - * Returns null if the RoomView was instantiated on a room alias and - * we haven't yet joined the room. - */ - getRoomId: function() { - if (!this.state.room) { - return null; - } - return this.state.room.roomId; - }, - /** * get any current call for this room */ From fa967da2a9a6efd7536880ea0c055918b64451fe Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 4 Nov 2016 10:07:50 +0000 Subject: [PATCH 4/6] matrix-js-sdk 0.6.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e5cd2eab3b..7dc4664044 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "linkifyjs": "^2.1.3", "lodash": "^4.13.1", "marked": "^0.3.5", - "matrix-js-sdk": "0.6.4-rc.2", + "matrix-js-sdk": "0.6.4", "optimist": "^0.6.1", "q": "^1.4.1", "react": "^15.2.1", From d7bc40807004d934eaede5e865e978c931331bb8 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 4 Nov 2016 10:09:10 +0000 Subject: [PATCH 5/6] Prepare changelog for v0.7.5 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fefc2c73a..57d6c38d01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +Changes in [0.7.5](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.7.5) (2016-11-04) +=================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.7.5-rc.1...v0.7.5) + + * No changes + Changes in [0.7.5-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.7.5-rc.1) (2016-11-02) ============================================================================================================= [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.7.4...v0.7.5-rc.1) From 1368d90e66be311baa5975fd12fe6cc5a7827a5c Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 4 Nov 2016 10:09:11 +0000 Subject: [PATCH 6/6] v0.7.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7dc4664044..a7f65919a5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "0.7.5-rc.1", + "version": "0.7.5", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": {