From 97ce84c8e36eaf20c0306242a4700c03e9419ef6 Mon Sep 17 00:00:00 2001 From: Aidan Gauland Date: Sun, 11 Feb 2018 16:14:17 +1300 Subject: [PATCH 1/8] Add display name to the read receipt view Show the user's display name (aka nick) in the ReadReceiptMarker title (mouseover text), and then the user ID in parentheses. --- src/components/views/rooms/ReadReceiptMarker.js | 6 ++++-- src/i18n/strings/en_EN.json | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/views/rooms/ReadReceiptMarker.js b/src/components/views/rooms/ReadReceiptMarker.js index 5dd62ff6b7..d5436efc76 100644 --- a/src/components/views/rooms/ReadReceiptMarker.js +++ b/src/components/views/rooms/ReadReceiptMarker.js @@ -186,8 +186,10 @@ module.exports = React.createClass({ let title; if (this.props.timestamp) { title = _t( - "Seen by %(userName)s at %(dateTime)s", - {userName: this.props.member.userId, dateTime: formatDate(new Date(this.props.timestamp), this.props.showTwelveHour)}, + "Seen by %(displayName)s (%(userName)s) at %(dateTime)s", + {displayName: this.props.member.name, + userName: this.props.member.userId, + dateTime: formatDate(new Date(this.props.timestamp), this.props.showTwelveHour)}, ); } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 6139ac2a91..2be4bf2e48 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -360,7 +360,7 @@ "Offline": "Offline", "Unknown": "Unknown", "Replying": "Replying", - "Seen by %(userName)s at %(dateTime)s": "Seen by %(userName)s at %(dateTime)s", + "Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "Seen by %(displayName)s (%(userName)s) at %(dateTime)s", "No rooms to show": "No rooms to show", "Unnamed room": "Unnamed room", "World readable": "World readable", From 0fd9b3e9b2d89965bb3966839d8f55700e17e7b9 Mon Sep 17 00:00:00 2001 From: Aidan Gauland Date: Sun, 11 Feb 2018 16:27:07 +1300 Subject: [PATCH 2/8] Avoid doubling up username in read receipt view In the ReadReceiptMarker title, use the RoomMember.rawDisplayName because RoomMember.name may already include the username, which we are going to add ourselves. --- src/components/views/rooms/ReadReceiptMarker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/ReadReceiptMarker.js b/src/components/views/rooms/ReadReceiptMarker.js index d5436efc76..8dc3c0f7d0 100644 --- a/src/components/views/rooms/ReadReceiptMarker.js +++ b/src/components/views/rooms/ReadReceiptMarker.js @@ -187,7 +187,7 @@ module.exports = React.createClass({ if (this.props.timestamp) { title = _t( "Seen by %(displayName)s (%(userName)s) at %(dateTime)s", - {displayName: this.props.member.name, + {displayName: this.props.member.rawDisplayName, userName: this.props.member.userId, dateTime: formatDate(new Date(this.props.timestamp), this.props.showTwelveHour)}, ); From 3d4feac75b63cef7b688492fb096f10236fcf3fc Mon Sep 17 00:00:00 2001 From: Aidan Gauland Date: Fri, 23 Mar 2018 17:14:29 +1300 Subject: [PATCH 3/8] Don't try to show unset display name In the ReadReceiptMarker title, show the display name only when it is not the same as the user ID. --- .../views/rooms/ReadReceiptMarker.js | 22 ++++++++++++++----- src/i18n/strings/en_EN.json | 1 + 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/components/views/rooms/ReadReceiptMarker.js b/src/components/views/rooms/ReadReceiptMarker.js index 8dc3c0f7d0..8b66cfd808 100644 --- a/src/components/views/rooms/ReadReceiptMarker.js +++ b/src/components/views/rooms/ReadReceiptMarker.js @@ -185,12 +185,22 @@ module.exports = React.createClass({ let title; if (this.props.timestamp) { - title = _t( - "Seen by %(displayName)s (%(userName)s) at %(dateTime)s", - {displayName: this.props.member.rawDisplayName, - userName: this.props.member.userId, - dateTime: formatDate(new Date(this.props.timestamp), this.props.showTwelveHour)}, - ); + const dateString = formatDate(new Date(this.props.timestamp), this.props.showTwelveHour); + if (this.props.member.userId === this.props.member.rawDisplayName) { + title = _t( + "Seen by %(userName)s at %(dateTime)s", + {userName: this.props.member.userId, + dateTime: dateString}, + ); + } + else { + title = _t( + "Seen by %(displayName)s (%(userName)s) at %(dateTime)s", + {displayName: this.props.member.rawDisplayName, + userName: this.props.member.userId, + dateTime: dateString}, + ); + } } return ( diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 2754880ed7..2d3ef836e0 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -389,6 +389,7 @@ "Offline": "Offline", "Unknown": "Unknown", "Replying": "Replying", + "Seen by %(userName)s at %(dateTime)s": "Seen by %(userName)s at %(dateTime)s", "Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "Seen by %(displayName)s (%(userName)s) at %(dateTime)s", "No rooms to show": "No rooms to show", "Unnamed room": "Unnamed room", From 0a920ae8012b69f9363a8463aa12e9a97521fedc Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 26 Mar 2018 13:33:47 +0100 Subject: [PATCH 4/8] Indenting fix --- src/components/views/rooms/ReadReceiptMarker.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/views/rooms/ReadReceiptMarker.js b/src/components/views/rooms/ReadReceiptMarker.js index 8b66cfd808..0029395d3d 100644 --- a/src/components/views/rooms/ReadReceiptMarker.js +++ b/src/components/views/rooms/ReadReceiptMarker.js @@ -192,8 +192,7 @@ module.exports = React.createClass({ {userName: this.props.member.userId, dateTime: dateString}, ); - } - else { + } else { title = _t( "Seen by %(displayName)s (%(userName)s) at %(dateTime)s", {displayName: this.props.member.rawDisplayName, From b80568b1c50351d5571ac9fcd2157c9ba0c87499 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 21 Mar 2018 12:00:56 +0000 Subject: [PATCH 5/8] Wrap GeminiScrollbar in a component, enabled forceGemini Fixes https://github.com/vector-im/riot-web/issues/6294 --- src/components/structures/GroupView.js | 6 ++-- src/components/structures/MyGroups.js | 7 ++-- src/components/structures/ScrollPanel.js | 6 ++-- src/components/structures/TagPanel.js | 7 ++-- src/components/structures/UserSettings.js | 9 ++--- .../views/dialogs/UnknownDeviceDialog.js | 5 +-- .../views/elements/GeminiScrollbarWrapper.js | 36 +++++++++++++++++++ .../views/groups/GroupMemberInfo.js | 6 ++-- .../views/groups/GroupMemberList.js | 6 ++-- src/components/views/groups/GroupRoomInfo.js | 6 ++-- src/components/views/groups/GroupRoomList.js | 6 ++-- src/components/views/rooms/MemberInfo.js | 6 ++-- src/components/views/rooms/MemberList.js | 6 ++-- src/components/views/rooms/RoomList.js | 8 ++--- .../views/rooms/SearchableEntityList.js | 6 ++-- 15 files changed, 83 insertions(+), 43 deletions(-) create mode 100644 src/components/views/elements/GeminiScrollbarWrapper.js diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 30e897e5dc..2b5b3d5353 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -31,7 +31,6 @@ import GroupStoreCache from '../../stores/GroupStoreCache'; import GroupStore from '../../stores/GroupStore'; import FlairStore from '../../stores/FlairStore'; import { showGroupAddRoomDialog } from '../../GroupAddressPicker'; -import GeminiScrollbar from 'react-gemini-scrollbar'; import {makeGroupPermalink, makeUserPermalink} from "../../matrix-to"; const LONG_DESC_PLACEHOLDER = _td( @@ -969,6 +968,7 @@ export default React.createClass({ const GroupAvatar = sdk.getComponent("avatars.GroupAvatar"); const Spinner = sdk.getComponent("elements.Spinner"); const TintableSvg = sdk.getComponent("elements.TintableSvg"); + const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); if (this.state.summaryLoading && this.state.error === null || this.state.saving) { return ; @@ -1119,9 +1119,9 @@ export default React.createClass({ { rightButtons } - + { bodyNodes } - + ); } else if (this.state.error) { diff --git a/src/components/structures/MyGroups.js b/src/components/structures/MyGroups.js index da7bebd16a..7a93cfb886 100644 --- a/src/components/structures/MyGroups.js +++ b/src/components/structures/MyGroups.js @@ -16,7 +16,6 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import GeminiScrollbar from 'react-gemini-scrollbar'; import sdk from '../../index'; import { _t } from '../../languageHandler'; import dis from '../../dispatcher'; @@ -63,6 +62,8 @@ export default withMatrixClient(React.createClass({ const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader'); const TintableSvg = sdk.getComponent("elements.TintableSvg"); const GroupTile = sdk.getComponent("groups.GroupTile"); + const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); + let content; let contentHeader; @@ -73,7 +74,7 @@ export default withMatrixClient(React.createClass({ }); contentHeader = groupNodes.length > 0 ?

{ _t('Your Communities') }

:
; content = groupNodes.length > 0 ? - +

{ _t( @@ -92,7 +93,7 @@ export default withMatrixClient(React.createClass({

{ groupNodes }
- : + :
{ _t( "You're not currently a member of any communities.", diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index cbb6001d5f..722dc2251f 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -17,7 +17,6 @@ limitations under the License. const React = require("react"); const ReactDOM = require("react-dom"); import PropTypes from 'prop-types'; -const GeminiScrollbar = require('react-gemini-scrollbar'); import Promise from 'bluebird'; import { KeyCode } from '../../Keyboard'; @@ -669,10 +668,11 @@ module.exports = React.createClass({ }, render: function() { + const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); // TODO: the classnames on the div and ol could do with being updated to // reflect the fact that we don't necessarily contain a list of messages. // it's not obvious why we have a separate div and ol anyway. - return (
@@ -680,7 +680,7 @@ module.exports = React.createClass({ { this.props.children }
-
+ ); }, }); diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js index 7a187e4298..790c497a67 100644 --- a/src/components/structures/TagPanel.js +++ b/src/components/structures/TagPanel.js @@ -17,7 +17,6 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import { MatrixClient } from 'matrix-js-sdk'; -import GeminiScrollbar from 'react-gemini-scrollbar'; import TagOrderStore from '../../stores/TagOrderStore'; import GroupActions from '../../actions/GroupActions'; @@ -102,6 +101,8 @@ const TagPanel = React.createClass({ const DNDTagTile = sdk.getComponent('elements.DNDTagTile'); const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); const TintableSvg = sdk.getComponent('elements.TintableSvg'); + const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); + const tags = this.state.orderedTags.map((tag, index) => { return
- ) } - +
diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index f6629b4b09..85223c4eef 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -30,7 +30,6 @@ import Promise from 'bluebird'; const packageJson = require('../../../package.json'); const UserSettingsStore = require('../../UserSettingsStore'); const CallMediaHandler = require('../../CallMediaHandler'); -const GeminiScrollbar = require('react-gemini-scrollbar'); const Email = require('../../email'); const AddThreepid = require('../../AddThreepid'); const SdkConfig = require('../../SdkConfig'); @@ -1118,6 +1117,7 @@ module.exports = React.createClass({ const ChangeAvatar = sdk.getComponent('settings.ChangeAvatar'); const Notifications = sdk.getComponent("settings.Notifications"); const EditableText = sdk.getComponent('elements.EditableText'); + const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); const avatarUrl = ( this.state.avatarUrl ? MatrixClientPeg.get().mxcUrlToHttp(this.state.avatarUrl) : null @@ -1213,8 +1213,9 @@ module.exports = React.createClass({ onCancelClick={this.props.onClose} /> - +

{ _t("Profile") }

@@ -1327,7 +1328,7 @@ module.exports = React.createClass({ { this._renderDeactivateAccount() } -
+
); }, diff --git a/src/components/views/dialogs/UnknownDeviceDialog.js b/src/components/views/dialogs/UnknownDeviceDialog.js index 26aa5d3ecb..07f8b6187f 100644 --- a/src/components/views/dialogs/UnknownDeviceDialog.js +++ b/src/components/views/dialogs/UnknownDeviceDialog.js @@ -146,6 +146,7 @@ export default React.createClass({ }, render: function() { + const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); if (this.props.devices === null) { const Spinner = sdk.getComponent("elements.Spinner"); return ; @@ -191,7 +192,7 @@ export default React.createClass({ title={_t('Room contains unknown devices')} contentId='mx_Dialog_content' > - +

{ _t('"%(RoomName)s" contains devices that you haven\'t seen before.', {RoomName: this.props.room.name}) }

@@ -199,7 +200,7 @@ export default React.createClass({ { _t("Unknown devices") }: -
+ diff --git a/src/components/views/elements/GeminiScrollbarWrapper.js b/src/components/views/elements/GeminiScrollbarWrapper.js new file mode 100644 index 0000000000..1de82bebc2 --- /dev/null +++ b/src/components/views/elements/GeminiScrollbarWrapper.js @@ -0,0 +1,36 @@ +/* +Copyright 2018 New Vector 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 React from 'react'; +import GeminiScrollbar from 'react-gemini-scrollbar'; + +class GeminiScrollbarWrapper extends React.Component { + render() { + // Enable forceGemini so that gemini is always enabled. This is + // to avoid future issues where a feature is implemented without + // doing QA on every OS/browser combination. + // + // By default GeminiScrollbar allows native scrollbars to be used + // on macOS. Use forceGemini to enable Gemini's non-native + // scrollbars on all OSs. + return + { this.props.children } + ; + } +} + +export default GeminiScrollbarWrapper; + diff --git a/src/components/views/groups/GroupMemberInfo.js b/src/components/views/groups/GroupMemberInfo.js index 097fb1f7db..4970a26e5b 100644 --- a/src/components/views/groups/GroupMemberInfo.js +++ b/src/components/views/groups/GroupMemberInfo.js @@ -25,7 +25,6 @@ import { _t } from '../../../languageHandler'; import { GroupMemberType } from '../../../groups'; import GroupStoreCache from '../../../stores/GroupStoreCache'; import AccessibleButton from '../elements/AccessibleButton'; -import GeminiScrollbar from 'react-gemini-scrollbar'; module.exports = React.createClass({ displayName: 'GroupMemberInfo', @@ -180,9 +179,10 @@ module.exports = React.createClass({ ); const EmojiText = sdk.getComponent('elements.EmojiText'); + const GeminiScrollbarWrapper = sdk.getComponent('elements.GeminiScrollbarWrapper'); return (
- + @@ -199,7 +199,7 @@ module.exports = React.createClass({
{ adminTools } - +
); }, diff --git a/src/components/views/groups/GroupMemberList.js b/src/components/views/groups/GroupMemberList.js index 71c168f5e6..17a91d83fa 100644 --- a/src/components/views/groups/GroupMemberList.js +++ b/src/components/views/groups/GroupMemberList.js @@ -18,7 +18,6 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import sdk from '../../../index'; import GroupStoreCache from '../../../stores/GroupStoreCache'; -import GeminiScrollbar from 'react-gemini-scrollbar'; import PropTypes from 'prop-types'; const INITIAL_LOAD_NUM_MEMBERS = 30; @@ -134,6 +133,7 @@ export default React.createClass({ }, render: function() { + const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); if (this.state.fetching || this.state.fetchingInvitedMembers) { const Spinner = sdk.getComponent("elements.Spinner"); return (
@@ -162,10 +162,10 @@ export default React.createClass({ return (
{ inputBox } - + { joined } { invited } - +
); }, diff --git a/src/components/views/groups/GroupRoomInfo.js b/src/components/views/groups/GroupRoomInfo.js index fa4ed89ae0..2d2b4e655c 100644 --- a/src/components/views/groups/GroupRoomInfo.js +++ b/src/components/views/groups/GroupRoomInfo.js @@ -22,7 +22,6 @@ import Modal from '../../../Modal'; import sdk from '../../../index'; import { _t } from '../../../languageHandler'; import GroupStoreCache from '../../../stores/GroupStoreCache'; -import GeminiScrollbar from 'react-gemini-scrollbar'; module.exports = React.createClass({ displayName: 'GroupRoomInfo', @@ -157,6 +156,7 @@ module.exports = React.createClass({ const EmojiText = sdk.getComponent('elements.EmojiText'); const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); const InlineSpinner = sdk.getComponent('elements.InlineSpinner'); + const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); if (this.state.groupRoomRemoveLoading || !this.state.groupRoom) { const Spinner = sdk.getComponent("elements.Spinner"); return
@@ -216,7 +216,7 @@ module.exports = React.createClass({ const avatar = ; return (
- + @@ -233,7 +233,7 @@ module.exports = React.createClass({
{ adminTools } - +
); }, diff --git a/src/components/views/groups/GroupRoomList.js b/src/components/views/groups/GroupRoomList.js index 189fa944e2..0515865c6b 100644 --- a/src/components/views/groups/GroupRoomList.js +++ b/src/components/views/groups/GroupRoomList.js @@ -17,7 +17,6 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import sdk from '../../../index'; import GroupStoreCache from '../../../stores/GroupStoreCache'; -import GeminiScrollbar from 'react-gemini-scrollbar'; import PropTypes from 'prop-types'; const INITIAL_LOAD_NUM_ROOMS = 30; @@ -120,16 +119,17 @@ export default React.createClass({ ); + const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); const TruncatedList = sdk.getComponent("elements.TruncatedList"); return (
{ inputBox } - + { this.makeGroupRoomTiles(this.state.searchQuery) } - +
); }, diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js index c449ad2683..2789c0e4cd 100644 --- a/src/components/views/rooms/MemberInfo.js +++ b/src/components/views/rooms/MemberInfo.js @@ -39,7 +39,6 @@ import Unread from '../../../Unread'; import { findReadReceiptFromUserId } from '../../../utils/Receipt'; import withMatrixClient from '../../../wrappers/withMatrixClient'; import AccessibleButton from '../elements/AccessibleButton'; -import GeminiScrollbar from 'react-gemini-scrollbar'; import RoomViewStore from '../../../stores/RoomViewStore'; import SdkConfig from '../../../SdkConfig'; @@ -897,11 +896,12 @@ module.exports = withMatrixClient(React.createClass({
; } + const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); const MemberAvatar = sdk.getComponent('avatars.MemberAvatar'); const EmojiText = sdk.getComponent('elements.EmojiText'); return (
- +
@@ -925,7 +925,7 @@ module.exports = withMatrixClient(React.createClass({ { this._renderDevices() } { spinner } - +
); }, diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index 620cfe33fc..3dfcd38cbd 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -21,7 +21,6 @@ import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; const MatrixClientPeg = require("../../../MatrixClientPeg"); const sdk = require('../../../index'); -const GeminiScrollbar = require('react-gemini-scrollbar'); const rate_limited_func = require('../../../ratelimitedfunc'); const CallHandler = require("../../../CallHandler"); @@ -395,6 +394,7 @@ module.exports = React.createClass({ render: function() { const TruncatedList = sdk.getComponent("elements.TruncatedList"); + const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); let invitedSection = null; if (this._getChildCountInvited() > 0) { @@ -423,14 +423,14 @@ module.exports = React.createClass({ return (
{ inputBox } - + { invitedSection } - +
); }, diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 6ccf04c5d8..ef1a3adc1d 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -20,7 +20,6 @@ const React = require("react"); const ReactDOM = require("react-dom"); import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; -const GeminiScrollbar = require('react-gemini-scrollbar'); const MatrixClientPeg = require("../../../MatrixClientPeg"); const CallHandler = require('../../../CallHandler'); const dis = require("../../../dispatcher"); @@ -351,7 +350,7 @@ module.exports = React.createClass({ return Boolean(isRoomVisible[taggedRoom.roomId]); }); - + if (filteredRooms.length > 0 || tagName.match(STANDARD_TAGS_REGEX)) { filteredLists[tagName] = filteredRooms; } @@ -601,10 +600,11 @@ module.exports = React.createClass({ render: function() { const RoomSubList = sdk.getComponent('structures.RoomSubList'); + const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); const self = this; return ( -
-
+
); }, }); diff --git a/src/components/views/rooms/SearchableEntityList.js b/src/components/views/rooms/SearchableEntityList.js index ff75524a5d..321f365da7 100644 --- a/src/components/views/rooms/SearchableEntityList.js +++ b/src/components/views/rooms/SearchableEntityList.js @@ -19,7 +19,6 @@ const MatrixClientPeg = require("../../../MatrixClientPeg"); const Modal = require("../../../Modal"); const sdk = require("../../../index"); import { _t } from '../../../languageHandler'; -const GeminiScrollbar = require('react-gemini-scrollbar'); // A list capable of displaying entities which conform to the SearchableEntity // interface which is an object containing getJsx(): Jsx and matches(query: string): boolean @@ -164,11 +163,12 @@ const SearchableEntityList = React.createClass({
); } + const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); list = ( - { list } - + ); } From 39e9d52c042521aa430bc6a66a517887b598a6d8 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 21 Mar 2018 15:58:14 +0000 Subject: [PATCH 6/8] Make sure to proxy special prop `ref` --- src/components/structures/ScrollPanel.js | 17 ++++++++++++++--- .../views/elements/GeminiScrollbarWrapper.js | 2 +- src/components/views/rooms/RoomList.js | 9 +++++++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 722dc2251f..0fdbc9a349 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -19,6 +19,7 @@ const ReactDOM = require("react-dom"); import PropTypes from 'prop-types'; import Promise from 'bluebird'; import { KeyCode } from '../../Keyboard'; +import sdk from '../../index.js'; const DEBUG_SCROLL = false; // var DEBUG_SCROLL = true; @@ -223,7 +224,7 @@ module.exports = React.createClass({ onResize: function() { this.props.onResize(); this.checkScroll(); - this.refs.geminiPanel.forceUpdate(); + if (this._gemScroll) this._gemScroll.forceUpdate(); }, // after an update to the contents of the panel, check that the scroll is @@ -664,7 +665,17 @@ module.exports = React.createClass({ throw new Error("ScrollPanel._getScrollNode called when unmounted"); } - return this.refs.geminiPanel.scrollbar.getViewElement(); + if (!this._gemScroll) { + // Likewise, we should have the ref by this point, but if not + // turn the NPE into something meaningful. + throw new Error("ScrollPanel._getScrollNode called before gemini ref collected"); + } + + return this._gemScroll.scrollbar.getViewElement(); + }, + + _collectGeminiScroll: function(gemScroll) { + this._gemScroll = gemScroll; }, render: function() { @@ -672,7 +683,7 @@ module.exports = React.createClass({ // TODO: the classnames on the div and ol could do with being updated to // reflect the fact that we don't necessarily contain a list of messages. // it's not obvious why we have a separate div and ol anyway. - return (
diff --git a/src/components/views/elements/GeminiScrollbarWrapper.js b/src/components/views/elements/GeminiScrollbarWrapper.js index 1de82bebc2..c56ff67c9c 100644 --- a/src/components/views/elements/GeminiScrollbarWrapper.js +++ b/src/components/views/elements/GeminiScrollbarWrapper.js @@ -26,7 +26,7 @@ class GeminiScrollbarWrapper extends React.Component { // By default GeminiScrollbar allows native scrollbars to be used // on macOS. Use forceGemini to enable Gemini's non-native // scrollbars on all OSs. - return + return { this.props.children } ; } diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index ef1a3adc1d..acf04831e8 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -507,7 +507,8 @@ module.exports = React.createClass({ onShowMoreRooms: function() { // kick gemini in the balls to get it to wake up // XXX: uuuuuuugh. - this.refs.gemscroll.forceUpdate(); + if (!this._gemScroll) return; + this._gemScroll.forceUpdate(); }, _getEmptyContent: function(section) { @@ -598,6 +599,10 @@ module.exports = React.createClass({ return ret; }, + _collectGemini(gemScroll) { + this._gemScroll = gemScroll; + }, + render: function() { const RoomSubList = sdk.getComponent('structures.RoomSubList'); const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); @@ -605,7 +610,7 @@ module.exports = React.createClass({ const self = this; return ( + autoshow={true} onScroll={self._whenScrolling} wrappedRef={this._collectGemini}>
Date: Wed, 21 Mar 2018 16:00:50 +0000 Subject: [PATCH 7/8] Convert GeminiScrollbarWrapper to stateless component --- .../views/elements/GeminiScrollbarWrapper.js | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/components/views/elements/GeminiScrollbarWrapper.js b/src/components/views/elements/GeminiScrollbarWrapper.js index c56ff67c9c..445b1a2596 100644 --- a/src/components/views/elements/GeminiScrollbarWrapper.js +++ b/src/components/views/elements/GeminiScrollbarWrapper.js @@ -14,23 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; import GeminiScrollbar from 'react-gemini-scrollbar'; -class GeminiScrollbarWrapper extends React.Component { - render() { - // Enable forceGemini so that gemini is always enabled. This is - // to avoid future issues where a feature is implemented without - // doing QA on every OS/browser combination. - // - // By default GeminiScrollbar allows native scrollbars to be used - // on macOS. Use forceGemini to enable Gemini's non-native - // scrollbars on all OSs. - return - { this.props.children } - ; - } +function GeminiScrollbarWrapper(props) { + // Enable forceGemini so that gemini is always enabled. This is + // to avoid future issues where a feature is implemented without + // doing QA on every OS/browser combination. + // + // By default GeminiScrollbar allows native scrollbars to be used + // on macOS. Use forceGemini to enable Gemini's non-native + // scrollbars on all OSs. + return + { props.children } + ; } - export default GeminiScrollbarWrapper; From 944940057eb25b9af4a1d1f5628e5251aa9efcb0 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 21 Mar 2018 17:23:19 +0000 Subject: [PATCH 8/8] Remember that React needs React --- src/components/views/elements/GeminiScrollbarWrapper.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/views/elements/GeminiScrollbarWrapper.js b/src/components/views/elements/GeminiScrollbarWrapper.js index 445b1a2596..af801c0113 100644 --- a/src/components/views/elements/GeminiScrollbarWrapper.js +++ b/src/components/views/elements/GeminiScrollbarWrapper.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import React from 'react'; import GeminiScrollbar from 'react-gemini-scrollbar'; function GeminiScrollbarWrapper(props) {