From d3367834d0b2bbec83395059f7cf4804579dd89d Mon Sep 17 00:00:00 2001 From: Aaron Raimist Date: Fri, 21 Feb 2020 21:53:51 -0600 Subject: [PATCH 01/37] Fix redo keyboard shortcut on macOS I added the correct macOS shortcut for redo which is Cmd+Shift+Z. I had to reorder the if statement so redo is checked first, otherwise it would detect the undo first and never check that I was actually trying to redo. Signed-off-by: Aaron Raimist --- .../views/rooms/BasicMessageComposer.js | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/components/views/rooms/BasicMessageComposer.js b/src/components/views/rooms/BasicMessageComposer.js index a2a01f4444..2b0f9a7554 100644 --- a/src/components/views/rooms/BasicMessageComposer.js +++ b/src/components/views/rooms/BasicMessageComposer.js @@ -370,6 +370,17 @@ export default class BasicMessageEditor extends React.Component { } else if (modKey && event.key === Key.GREATER_THAN) { this._onFormatAction("quote"); handled = true; + // redo + } else if ((modKey && event.key === Key.Y) || + (IS_MAC && event.shiftKey && event.key === Key.Z)) { + debugger; + if (this.historyManager.canRedo()) { + const {parts, caret} = this.historyManager.redo(); + // pass matching inputType so historyManager doesn't push echo + // when invoked from rerender callback. + model.reset(parts, caret, "historyRedo"); + } + handled = true; // undo } else if (modKey && event.key === Key.Z) { if (this.historyManager.canUndo()) { @@ -379,15 +390,6 @@ export default class BasicMessageEditor extends React.Component { model.reset(parts, caret, "historyUndo"); } handled = true; - // redo - } else if (modKey && event.key === Key.Y) { - if (this.historyManager.canRedo()) { - const {parts, caret} = this.historyManager.redo(); - // pass matching inputType so historyManager doesn't push echo - // when invoked from rerender callback. - model.reset(parts, caret, "historyRedo"); - } - handled = true; // insert newline on Shift+Enter } else if (event.key === Key.ENTER && (event.shiftKey || (IS_MAC && event.altKey))) { this._insertText("\n"); From 42c6818f952af0dbb159eb56d41dc621d6ca5e67 Mon Sep 17 00:00:00 2001 From: Aaron Raimist Date: Fri, 21 Feb 2020 21:59:43 -0600 Subject: [PATCH 02/37] Remove debugger; Signed-off-by: Aaron Raimist --- src/components/views/rooms/BasicMessageComposer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/views/rooms/BasicMessageComposer.js b/src/components/views/rooms/BasicMessageComposer.js index 2b0f9a7554..dd6addd062 100644 --- a/src/components/views/rooms/BasicMessageComposer.js +++ b/src/components/views/rooms/BasicMessageComposer.js @@ -373,7 +373,6 @@ export default class BasicMessageEditor extends React.Component { // redo } else if ((modKey && event.key === Key.Y) || (IS_MAC && event.shiftKey && event.key === Key.Z)) { - debugger; if (this.historyManager.canRedo()) { const {parts, caret} = this.historyManager.redo(); // pass matching inputType so historyManager doesn't push echo From 550ee216c64bace5a4b728e77a705d745a5e9cc1 Mon Sep 17 00:00:00 2001 From: Aaron Raimist Date: Mon, 24 Feb 2020 18:22:07 -0600 Subject: [PATCH 03/37] Apply suggestions from code review Co-Authored-By: David Baker --- src/components/views/rooms/BasicMessageComposer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/BasicMessageComposer.js b/src/components/views/rooms/BasicMessageComposer.js index dd6addd062..52947aa6e2 100644 --- a/src/components/views/rooms/BasicMessageComposer.js +++ b/src/components/views/rooms/BasicMessageComposer.js @@ -371,8 +371,8 @@ export default class BasicMessageEditor extends React.Component { this._onFormatAction("quote"); handled = true; // redo - } else if ((modKey && event.key === Key.Y) || - (IS_MAC && event.shiftKey && event.key === Key.Z)) { + } else if ((!IS_MAC && modKey && event.key === Key.Y) || + (IS_MAC && modkey && event.shiftKey && event.key === Key.Z)) { if (this.historyManager.canRedo()) { const {parts, caret} = this.historyManager.redo(); // pass matching inputType so historyManager doesn't push echo From 5c582037ceb6522c4f1344c693af6a6a7cda5041 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 10 Mar 2020 23:11:48 +0000 Subject: [PATCH 04/37] Tweak padding to match Figma Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/structures/_RoomDirectory.scss | 6 +++--- src/components/structures/RoomDirectory.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/res/css/structures/_RoomDirectory.scss b/res/css/structures/_RoomDirectory.scss index 5ae8df7176..241c921f20 100644 --- a/res/css/structures/_RoomDirectory.scss +++ b/res/css/structures/_RoomDirectory.scss @@ -46,8 +46,8 @@ limitations under the License. .mx_RoomDirectory_listheader { display: flex; - margin-top: 12px; - margin-bottom: 12px; + margin-top: 13px; + margin-bottom: 13px; } .mx_RoomDirectory_searchbox { @@ -148,7 +148,7 @@ limitations under the License. padding: 0; } -.mx_RoomDirectory p { +.mx_RoomDirectory > span { font-size: 14px; margin-top: 0; diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index dd089a9776..3c3d67578e 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -628,7 +628,7 @@ export default createReactClass({ title={_t("Explore rooms")} >
-

{explanation}

+ {explanation}
{listHeader} {content} From 86e53ea2c31f99a60a6d0113584400b7fa87aff4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 00:02:50 +0000 Subject: [PATCH 05/37] Initial attempt to redesign explore servers in room directory Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/structures/_RoomDirectory.scss | 3 +- res/css/views/directory/_NetworkDropdown.scss | 180 +++++--- .../views/elements/_DirectorySearchBox.scss | 1 - src/components/structures/MatrixChat.js | 5 +- src/components/structures/RoomDirectory.js | 44 +- .../views/dialogs/TextInputDialog.js | 11 +- .../views/directory/NetworkDropdown.js | 383 +++++++++--------- src/i18n/strings/en_EN.json | 9 + src/settings/Settings.js | 4 + 9 files changed, 362 insertions(+), 278 deletions(-) diff --git a/res/css/structures/_RoomDirectory.scss b/res/css/structures/_RoomDirectory.scss index 241c921f20..d6ae0bb739 100644 --- a/res/css/structures/_RoomDirectory.scss +++ b/res/css/structures/_RoomDirectory.scss @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -45,7 +46,7 @@ limitations under the License. } .mx_RoomDirectory_listheader { - display: flex; + display: block; margin-top: 13px; margin-bottom: 13px; } diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index d402f6c48f..3dc3a99dd4 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,70 +16,143 @@ limitations under the License. */ .mx_NetworkDropdown { + height: 32px; position: relative; -} + width: max-content; + padding-right: 32px; + margin-left: auto; + margin-right: 9px; + margin-top: 12px; -.mx_NetworkDropdown_input { - position: relative; - border-radius: 3px; - border: 1px solid $strong-input-border-color; - font-weight: 300; - font-size: 13px; - user-select: none; -} - -.mx_NetworkDropdown_arrow { - border-color: $primary-fg-color transparent transparent; - border-style: solid; - border-width: 5px 5px 0; - display: block; - height: 0; - position: absolute; - right: 10px; - top: 16px; - width: 0; -} - -.mx_NetworkDropdown_networkoption { - height: 37px; - line-height: 37px; - padding-left: 8px; - padding-right: 8px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -.mx_NetworkDropdown_networkoption img { - margin: 5px; - width: 25px; - vertical-align: middle; -} - -input.mx_NetworkDropdown_networkoption, input.mx_NetworkDropdown_networkoption:focus { - border: 0; - padding-top: 0; - padding-bottom: 0; + .mx_AccessibleButton { + width: max-content; + } } .mx_NetworkDropdown_menu { - position: absolute; - left: -1px; - right: -1px; - top: 100%; - z-index: 2; + //position: absolute; + //left: -1px; + //right: -1px; + //top: 100%; + //z-index: 2; + width: 204px; margin: 0; - padding: 0px; - border-radius: 3px; + box-sizing: border-box; + border-radius: 4px; border: 1px solid $accent-color; background-color: $primary-bg-color; } -.mx_NetworkDropdown_menu .mx_NetworkDropdown_networkoption:hover { - background-color: $focus-bg-color; -} - .mx_NetworkDropdown_menu_network { font-weight: bold; } +.mx_NetworkDropdown_server { + padding: 12px 0; + border-bottom: 1px solid $input-darker-fg-color; + + .mx_NetworkDropdown_server_title { + padding: 0 10px; + font-size: 15px; + font-weight: 600; + line-height: 20px; + margin-bottom: 4px; + + // remove server button + .mx_AccessibleButton { + position: absolute; + display: inline; + right: 0; + + &::before { + content: ""; + position: absolute; + width: 16px; + height: 16px; + right: 12px; + top: 4px; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + mask-image: url('$(res)/img/feather-customised/x.svg'); + background-color: $notice-primary-color; + } + } + } + + .mx_NetworkDropdown_server_subtitle { + padding: 0 10px; + font-size: 10px; + line-height: 14px; + margin-top: -4px; + margin-bottom: 4px; + color: $muted-fg-color; + } + + .mx_NetworkDropdown_server_network { + font-size: 12px; + line-height: 16px; + padding: 4px 10px; + cursor: pointer; + position: relative; + + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + + &[aria-checked=true]::after { + content: ""; + position: absolute; + width: 16px; + height: 16px; + right: 10px; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + mask-image: url('$(res)/img/feather-customised/check.svg'); + background-color: $input-valid-border-color; + } + } +} + +.mx_NetworkDropdown_server_add, +.mx_NetworkDropdown_server_network { + &:hover { + background-color: $header-panel-bg-color; + } +} + +.mx_NetworkDropdown_server_add { + padding: 16px 10px 16px 32px; + position: relative; + + &::before { + content: ""; + position: absolute; + width: 16px; + height: 16px; + left: 7px; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + mask-image: url('$(res)/img/feather-customised/plus.svg'); + background-color: $muted-fg-color; + } +} + +.mx_NetworkDropdown_handle { + position: relative; + + &::after { + content: ""; + position: absolute; + width: 24px; + height: 24px; + right: -28px; // - (24 + 4) + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); + background-color: $primary-fg-color; + } +} diff --git a/res/css/views/elements/_DirectorySearchBox.scss b/res/css/views/elements/_DirectorySearchBox.scss index ef944f6fa0..75ef3fbabd 100644 --- a/res/css/views/elements/_DirectorySearchBox.scss +++ b/res/css/views/elements/_DirectorySearchBox.scss @@ -18,7 +18,6 @@ limitations under the License. display: flex; padding-left: 9px; padding-right: 9px; - margin: 0 5px 0 0 !important; } .mx_DirectorySearchBox_joinButton { diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index a0b9a8fe57..0099af8398 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -600,9 +600,8 @@ export default createReactClass({ break; case 'view_room_directory': { const RoomDirectory = sdk.getComponent("structures.RoomDirectory"); - Modal.createTrackedDialog('Room directory', '', RoomDirectory, { - config: this.props.config, - }, 'mx_RoomDirectory_dialogWrapper'); + Modal.createTrackedDialog('Room directory', '', RoomDirectory, {}, + 'mx_RoomDirectory_dialogWrapper', false, true); // View the welcome or home page if we need something to look at this._viewSomethingBehindModal(); diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index 3c3d67578e..ddc172fca7 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -28,6 +28,7 @@ import { _t } from '../../languageHandler'; import { instanceForInstanceId, protocolNameForInstanceId } from '../../utils/DirectoryUtils'; import Analytics from '../../Analytics'; import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo"; +import {ALL_ROOMS} from "../views/directory/NetworkDropdown"; const MAX_NAME_LENGTH = 80; const MAX_TOPIC_LENGTH = 160; @@ -40,25 +41,17 @@ export default createReactClass({ displayName: 'RoomDirectory', propTypes: { - config: PropTypes.object, onFinished: PropTypes.func.isRequired, }, - getDefaultProps: function() { - return { - config: {}, - }; - }, - getInitialState: function() { return { publicRooms: [], loading: true, protocolsLoading: true, error: null, - instanceId: null, - includeAll: false, - roomServer: null, + instanceId: undefined, + roomServer: MatrixClientPeg.getHomeserverName(), filterString: null, }; }, @@ -98,6 +91,10 @@ export default createReactClass({ }); }, + componentDidMount: function() { + this.refreshRoomList(); + }, + componentWillUnmount: function() { if (this.filterTimeout) { clearTimeout(this.filterTimeout); @@ -130,10 +127,10 @@ export default createReactClass({ if (my_server != MatrixClientPeg.getHomeserverName()) { opts.server = my_server; } - if (this.state.instanceId) { - opts.third_party_instance_id = this.state.instanceId; - } else if (this.state.includeAll) { + if (this.state.instanceId === ALL_ROOMS) { opts.include_all_networks = true; + } else if (this.state.instanceId) { + opts.third_party_instance_id = this.state.instanceId; } if (this.nextBatch) opts.since = this.nextBatch; if (my_filter_string) opts.filter = { generic_search_term: my_filter_string }; @@ -247,7 +244,7 @@ export default createReactClass({ } }, - onOptionChange: function(server, instanceId, includeAll) { + onOptionChange: function(server, instanceId) { // clear next batch so we don't try to load more rooms this.nextBatch = null; this.setState({ @@ -257,7 +254,6 @@ export default createReactClass({ publicRooms: [], roomServer: server, instanceId: instanceId, - includeAll: includeAll, error: null, }, this.refreshRoomList); // We also refresh the room list each time even though this @@ -305,7 +301,7 @@ export default createReactClass({ onJoinFromSearchClick: function(alias) { // If we don't have a particular instance id selected, just show that rooms alias - if (!this.state.instanceId) { + if (!this.state.instanceId || this.state.instanceId === ALL_ROOMS) { // If the user specified an alias without a domain, add on whichever server is selected // in the dropdown if (alias.indexOf(':') == -1) { @@ -587,7 +583,7 @@ export default createReactClass({ } let placeholder = _t('Find a room…'); - if (!this.state.instanceId) { + if (!this.state.instanceId || this.state.instanceId === ALL_ROOMS) { placeholder = _t("Find a room… (e.g. %(exampleRoom)s)", {exampleRoom: "#example:" + this.state.roomServer}); } else if (instance_expected_field_type) { placeholder = instance_expected_field_type.placeholder; @@ -604,10 +600,18 @@ export default createReactClass({ listHeader =
+ -
; } const explanation = diff --git a/src/components/views/dialogs/TextInputDialog.js b/src/components/views/dialogs/TextInputDialog.js index 0ffc072cc0..4b21e8206e 100644 --- a/src/components/views/dialogs/TextInputDialog.js +++ b/src/components/views/dialogs/TextInputDialog.js @@ -28,9 +28,11 @@ export default createReactClass({ PropTypes.string, ]), value: PropTypes.string, + placeholder: PropTypes.string, button: PropTypes.string, focus: PropTypes.bool, onFinished: PropTypes.func.isRequired, + hasCancel: PropTypes.bool, }, getDefaultProps: function() { @@ -39,6 +41,7 @@ export default createReactClass({ value: "", description: "", focus: true, + hasCancel: true, }; }, @@ -80,13 +83,17 @@ export default createReactClass({ className="mx_TextInputDialog_input" defaultValue={this.props.value} autoFocus={this.props.focus} + placeholder={this.props.placeholder} size="64" />
- + onCancel={this.onCancel} + hasCancel={this.props.hasCancel} + /> ); }, diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index cb6a015d86..229f80ef29 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -1,6 +1,7 @@ /* Copyright 2016 OpenMarket Ltd Copyright 2019 Michael Telatynski <7t3chguy@gmail.com> +Copyright 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,239 +18,225 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; + import {MatrixClientPeg} from '../../../MatrixClientPeg'; import {instanceForInstanceId} from '../../../utils/DirectoryUtils'; +import {ContextMenu, useContextMenu, ContextMenuButton, MenuItemRadio, MenuItem} from "../../structures/ContextMenu"; +import {_t} from "../../../languageHandler"; +import SdkConfig from "../../../SdkConfig"; +import {useSettingValue} from "../../../hooks/useSettings"; +import * as sdk from "../../../index"; +import Modal from "../../../Modal"; +import SettingsStore from "../../../settings/SettingsStore"; +import AccessibleButton from "../elements/AccessibleButton"; -const DEFAULT_ICON_URL = require("../../../../res/img/network-matrix.svg"); +export const ALL_ROOMS = Symbol("ALL_ROOMS"); -export default class NetworkDropdown extends React.Component { - constructor(props) { - super(props); +const SETTING_NAME = "room_directory_servers"; - this.dropdownRootElement = null; - this.ignoreEvent = null; +const inPlaceOf = (elementRect) => ({ + right: window.innerWidth - elementRect.right, + top: elementRect.top, + chevronOffset: 0, + chevronFace: "none", +}); - this.onInputClick = this.onInputClick.bind(this); - this.onRootClick = this.onRootClick.bind(this); - this.onDocumentClick = this.onDocumentClick.bind(this); - this.onMenuOptionClick = this.onMenuOptionClick.bind(this); - this.onInputKeyUp = this.onInputKeyUp.bind(this); - this.collectRoot = this.collectRoot.bind(this); - this.collectInputTextBox = this.collectInputTextBox.bind(this); +// This dropdown sources homeservers from three places: +// + your currently connected homeserver +// + homeservers in config.json["roomDirectory"] +// + homeservers in SettingsStore["room_directory_servers"] +// if a server exists in multiple, only keep the top-most entry. - this.inputTextBox = null; +const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, selectedInstanceId}) => { + const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu(); + const userDefinedServers = useSettingValue(SETTING_NAME); - const server = MatrixClientPeg.getHomeserverName(); - this.state = { - expanded: false, - selectedServer: server, - selectedInstanceId: null, - includeAllNetworks: false, + const handlerFactory = (server, instanceId) => { + return () => { + onOptionChange(server, instanceId); + closeMenu(); }; - } + }; - componentWillMount() { - // Listen for all clicks on the document so we can close the - // menu when the user clicks somewhere else - document.addEventListener('click', this.onDocumentClick, false); + // we either show the button or the dropdown in its place. + let content; + if (menuDisplayed) { + const config = SdkConfig.get(); + const roomDirectory = config.roomDirectory || {}; - // fire this now so the defaults can be set up - const {selectedServer, selectedInstanceId, includeAllNetworks} = this.state; - this.props.onOptionChange(selectedServer, selectedInstanceId, includeAllNetworks); - } + const hsName = MatrixClientPeg.getHomeserverName(); + const configServers = new Set(roomDirectory.servers); - componentWillUnmount() { - document.removeEventListener('click', this.onDocumentClick, false); - } - - componentDidUpdate() { - if (this.state.expanded && this.inputTextBox) { - this.inputTextBox.focus(); - } - } - - onDocumentClick(ev) { - // Close the dropdown if the user clicks anywhere that isn't - // within our root element - if (ev !== this.ignoreEvent) { - this.setState({ - expanded: false, - }); - } - } - - onRootClick(ev) { - // This captures any clicks that happen within our elements, - // such that we can then ignore them when they're seen by the - // click listener on the document handler, ie. not close the - // dropdown immediately after opening it. - // NB. We can't just stopPropagation() because then the event - // doesn't reach the React onClick(). - this.ignoreEvent = ev; - } - - onInputClick(ev) { - this.setState({ - expanded: !this.state.expanded, - }); - ev.preventDefault(); - } - - onMenuOptionClick(server, instance, includeAll) { - this.setState({ - expanded: false, - selectedServer: server, - selectedInstanceId: instance ? instance.instance_id : null, - includeAllNetworks: includeAll, - }); - this.props.onOptionChange(server, instance ? instance.instance_id : null, includeAll); - } - - onInputKeyUp(e) { - if (e.key === 'Enter') { - this.setState({ - expanded: false, - selectedServer: e.target.value, - selectedNetwork: null, - includeAllNetworks: false, - }); - this.props.onOptionChange(e.target.value, null); - } - } - - collectRoot(e) { - if (this.dropdownRootElement) { - this.dropdownRootElement.removeEventListener('click', this.onRootClick, false); - } - if (e) { - e.addEventListener('click', this.onRootClick, false); - } - this.dropdownRootElement = e; - } - - collectInputTextBox(e) { - this.inputTextBox = e; - } - - _getMenuOptions() { - const options = []; - const roomDirectory = this.props.config.roomDirectory || {}; - - let servers = []; - if (roomDirectory.servers) { - servers = servers.concat(roomDirectory.servers); - } - - if (!servers.includes(MatrixClientPeg.getHomeserverName())) { - servers.unshift(MatrixClientPeg.getHomeserverName()); - } + // configured servers take preference over user-defined ones, if one occurs in both ignore the latter one. + const removableServers = new Set(userDefinedServers.filter(s => !configServers.has(s) && s !== hsName)); + const servers = [ + // we always show our connected HS, this takes precedence over it being configured or user-defined + hsName, + ...Array.from(configServers).filter(s => s !== hsName).sort(), + ...Array.from(removableServers).sort(), + ]; // For our own HS, we can use the instance_ids given in the third party protocols // response to get the server to filter the room list by network for us. // We can't get thirdparty protocols for remote server yet though, so for those // we can only show the default room list. - for (const server of servers) { - options.push(this._makeMenuOption(server, null, true)); - if (server === MatrixClientPeg.getHomeserverName()) { - options.push(this._makeMenuOption(server, null, false)); - if (this.props.protocols) { - for (const proto of Object.keys(this.props.protocols)) { - if (!this.props.protocols[proto].instances) continue; + const options = servers.map(server => { + const serverSelected = server === selectedServerName; + const entries = []; - const sortedInstances = this.props.protocols[proto].instances; - sortedInstances.sort(function(x, y) { - const a = x.desc; - const b = y.desc; - if (a < b) { - return -1; - } else if (a > b) { - return 1; - } else { - return 0; - } - }); - - for (const instance of sortedInstances) { - if (!instance.instance_id) continue; - options.push(this._makeMenuOption(server, instance, false)); - } - } - } + const protocolsList = server === hsName ? Object.values(protocols) : []; + if (protocolsList.length > 0) { + // add a fake protocol with the ALL_ROOMS symbol + protocolsList.push({ + instances: [{ + instance_id: ALL_ROOMS, + desc: _t("All rooms"), + }], + }); } - } - return options; - } + protocolsList.forEach(({instances=[]}) => { + [...instances].sort((b, a) => { + return a.desc.localeCompare(b.desc); + }).forEach(({desc, instance_id: instanceId}) => { + entries.push( + + { desc } + ); + }); + }); - _makeMenuOption(server, instance, includeAll, handleClicks) { - if (handleClicks === undefined) handleClicks = true; + let subtitle; + if (server === hsName) { + subtitle = ( +
+ {_t("Your server")} +
+ ); + } - let icon; - let name; - let key; + let removeButton; + if (removableServers.has(server)) { + const onClick = async () => { + closeMenu(); + const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); + const {finished} = Modal.createTrackedDialog("Network Dropdown", "Remove server", QuestionDialog, { + title: _t("Are you sure?"), + description: _t("Are you sure you want to remove %(serverName)s", { + serverName: server, + }, { + b: serverName => { serverName }, + }), + button: _t("Remove"), + }); - if (!instance && includeAll) { - key = server; - name = server; - } else if (!instance) { - key = server + '_all'; - name = 'Matrix'; - icon = ; - } else { - key = server + '_inst_' + instance.instance_id; - const imgUrl = instance.icon ? - MatrixClientPeg.get().mxcUrlToHttp(instance.icon, 25, 25, 'crop', true) : - DEFAULT_ICON_URL; - icon = ; - name = instance.desc; - } + const [ok] = await finished; + if (!ok) return; - const clickHandler = handleClicks ? this.onMenuOptionClick.bind(this, server, instance, includeAll) : null; + // delete from setting + await SettingsStore.setValue(SETTING_NAME, null, "account", servers.filter(s => s !== server)); - return
- {icon} - {name} -
; - } + // the selected server is being removed, reset to our HS + if (serverSelected === server) { + onOptionChange(hsName, undefined); + } + }; + removeButton = ; + } - render() { - let currentValue; + return ( +
+
+ { server } + { removeButton } +
+ { subtitle } - let menu; - if (this.state.expanded) { - const menuOptions = this._getMenuOptions(); - menu =
- {menuOptions} -
; - currentValue = ; - } else { - const instance = instanceForInstanceId(this.props.protocols, this.state.selectedInstanceId); - currentValue = this._makeMenuOption( - this.state.selectedServer, instance, this.state.includeAllNetworks, false, + + {_t("Matrix")} + + { entries } +
); + }); + + const onClick = async () => { + closeMenu(); + const TextInputDialog = sdk.getComponent("dialogs.TextInputDialog"); + const { finished } = Modal.createTrackedDialog("Network Dropdown", "Add a new server", TextInputDialog, { + title: _t("Add a new server"), + description: _t("Enter the address of a new server you want to explore."), + button: _t("Add"), + hasCancel: false, + placeholder: _t("Server address"), + }); + + const [ok, newServer] = await finished; + if (!ok) return; + + if (!userDefinedServers.includes(newServer)) { + const servers = [...userDefinedServers, newServer]; + await SettingsStore.setValue(SETTING_NAME, null, "account", servers); + } + + onOptionChange(newServer); // change filter to the new server + }; + + const buttonRect = handle.current.getBoundingClientRect(); + content = +
+ {options} + + {_t("Add a new server...")} + +
+
; + } else { + let currentValue; + if (selectedInstanceId === ALL_ROOMS) { + currentValue = _t("All rooms"); + } else if (selectedInstanceId) { + const instance = instanceForInstanceId(protocols, selectedInstanceId); + currentValue = _t("%(networkName)s rooms", { + networkName: instance.desc, + }); + } else { + currentValue = _t("Matrix rooms"); } - return
-
+ content = + {currentValue} - - {menu} -
-
; + + ({selectedServerName}) + + ; } -} + + return
+ {content} +
; +}; NetworkDropdown.propTypes = { onOptionChange: PropTypes.func.isRequired, protocols: PropTypes.object, - // The room directory config. May have a 'servers' key that is a list of server names to include in the dropdown - config: PropTypes.object, }; -NetworkDropdown.defaultProps = { - protocols: {}, - config: {}, -}; +export default NetworkDropdown; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 2f8f5c48ad..a5763fe5c5 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1437,6 +1437,15 @@ "And %(count)s more...|other": "And %(count)s more...", "ex. @bob:example.com": "ex. @bob:example.com", "Add User": "Add User", + "All rooms": "All rooms", + "Your server": "Your server", + "Matrix": "Matrix", + "Add a new server": "Add a new server", + "Enter the address of a new server you want to explore.": "Enter the address of a new server you want to explore.", + "Server address": "Server address", + "Add a new server...": "Add a new server...", + "%(networkName)s rooms": "%(networkName)s rooms", + "Matrix rooms": "Matrix rooms", "Matrix ID": "Matrix ID", "Matrix Room ID": "Matrix Room ID", "email address": "email address", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index b77fb392e9..8024c411f7 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -324,6 +324,10 @@ export const SETTINGS = { supportedLevels: ['account'], default: [], }, + "room_directory_servers": { + supportedLevels: ['account'], + default: [], + }, "integrationProvisioning": { supportedLevels: ['account'], default: true, From dd4dc054aef404745299eb5838d6707eeb532360 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 00:06:41 +0000 Subject: [PATCH 06/37] i18n Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/i18n/strings/en_EN.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index a5763fe5c5..b7ba70b62f 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1439,6 +1439,7 @@ "Add User": "Add User", "All rooms": "All rooms", "Your server": "Your server", + "Are you sure you want to remove %(serverName)s": "Are you sure you want to remove %(serverName)s", "Matrix": "Matrix", "Add a new server": "Add a new server", "Enter the address of a new server you want to explore.": "Enter the address of a new server you want to explore.", From 343403f1efcdf8b4150d903e0a4d21e49b59d23d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 00:09:56 +0000 Subject: [PATCH 07/37] clean up Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 6 ------ 1 file changed, 6 deletions(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index 3dc3a99dd4..f3c2f4757a 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -1,5 +1,4 @@ /* -Copyright 2015, 2016 OpenMarket Ltd Copyright 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,11 +29,6 @@ limitations under the License. } .mx_NetworkDropdown_menu { - //position: absolute; - //left: -1px; - //right: -1px; - //top: 100%; - //z-index: 2; width: 204px; margin: 0; box-sizing: border-box; From 359b07b8efc667945d3f3476fbd9658dd1f8b21c Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 00:11:09 +0000 Subject: [PATCH 08/37] allow it to expand for longer content Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index f3c2f4757a..1f55531602 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -29,7 +29,7 @@ limitations under the License. } .mx_NetworkDropdown_menu { - width: 204px; + min-width: 204px; margin: 0; box-sizing: border-box; border-radius: 4px; From 642dd08ca25065237d157e5759efae77d94fe315 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 00:16:11 +0000 Subject: [PATCH 09/37] remove erroneous margin Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/structures/_RoomDirectory.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/res/css/structures/_RoomDirectory.scss b/res/css/structures/_RoomDirectory.scss index d6ae0bb739..b5ead78b8b 100644 --- a/res/css/structures/_RoomDirectory.scss +++ b/res/css/structures/_RoomDirectory.scss @@ -48,7 +48,6 @@ limitations under the License. .mx_RoomDirectory_listheader { display: block; margin-top: 13px; - margin-bottom: 13px; } .mx_RoomDirectory_searchbox { From 3628fd2ea26b12ee25d96ef453acd47edca3bc34 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 00:18:33 +0000 Subject: [PATCH 10/37] add missing asset Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/img/feather-customised/chevron-down.svg | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 res/img/feather-customised/chevron-down.svg diff --git a/res/img/feather-customised/chevron-down.svg b/res/img/feather-customised/chevron-down.svg new file mode 100644 index 0000000000..bcb185ede7 --- /dev/null +++ b/res/img/feather-customised/chevron-down.svg @@ -0,0 +1,3 @@ + + + From 5a27fa7d97eb6f85171730179cba4cdd3dc9b34f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 00:18:53 +0000 Subject: [PATCH 11/37] fix styling of server name in handle Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 5 +++++ src/components/views/directory/NetworkDropdown.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index 1f55531602..f017ed9dcd 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -149,4 +149,9 @@ limitations under the License. mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); background-color: $primary-fg-color; } + + .mx_NetworkDropdown_handle_server { + color: $muted-fg-color; + font-size: 12px; + } } diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index 229f80ef29..8369926fb4 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -223,7 +223,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se > {currentValue} - + ({selectedServerName}) ; From 9237cf956640f73d79ddb884b127b8cb46f2ad33 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 14:19:38 +0000 Subject: [PATCH 12/37] update font sizes Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/structures/_RoomDirectory.scss | 5 +++-- res/css/views/directory/_NetworkDropdown.scss | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/res/css/structures/_RoomDirectory.scss b/res/css/structures/_RoomDirectory.scss index b5ead78b8b..f3a7b0e243 100644 --- a/res/css/structures/_RoomDirectory.scss +++ b/res/css/structures/_RoomDirectory.scss @@ -64,7 +64,7 @@ limitations under the License. } .mx_RoomDirectory_table { - font-size: 14px; + font-size: 12px; color: $primary-fg-color; width: 100%; text-align: left; @@ -112,6 +112,7 @@ limitations under the License. .mx_RoomDirectory_name { display: inline-block; + font-size: 18px; font-weight: 600; } @@ -149,7 +150,7 @@ limitations under the License. } .mx_RoomDirectory > span { - font-size: 14px; + font-size: 15px; margin-top: 0; .mx_AccessibleButton { diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index f017ed9dcd..7e8a2e16d1 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -58,7 +58,7 @@ limitations under the License. display: inline; right: 0; - &::before { + &::after { content: ""; position: absolute; width: 16px; From af368a4736f546aec0ff24e29ead2aa16bf9b692 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 14:38:36 +0000 Subject: [PATCH 13/37] Improve accessibility Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 5 +++-- src/components/structures/ContextMenu.js | 3 +-- .../views/directory/NetworkDropdown.js | 20 +++++++++++++------ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index 7e8a2e16d1..28dd1ed628 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -56,14 +56,15 @@ limitations under the License. .mx_AccessibleButton { position: absolute; display: inline; - right: 0; + right: 12px; + height: 16px; + width: 16px; &::after { content: ""; position: absolute; width: 16px; height: 16px; - right: 12px; top: 4px; mask-repeat: no-repeat; mask-position: center; diff --git a/src/components/structures/ContextMenu.js b/src/components/structures/ContextMenu.js index 898991f4f2..b4647a6c30 100644 --- a/src/components/structures/ContextMenu.js +++ b/src/components/structures/ContextMenu.js @@ -350,7 +350,7 @@ export const ContextMenuButton = ({ label, isExpanded, children, ...props }) => }; ContextMenuButton.propTypes = { ...AccessibleButton.propTypes, - label: PropTypes.string.isRequired, + label: PropTypes.string, isExpanded: PropTypes.bool.isRequired, // whether or not the context menu is currently open }; @@ -377,7 +377,6 @@ export const MenuGroup = ({children, label, ...props}) => { ; }; MenuGroup.propTypes = { - ...AccessibleButton.propTypes, label: PropTypes.string.isRequired, className: PropTypes.string, // optional }; diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index 8369926fb4..637fb09c18 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -21,7 +21,14 @@ import PropTypes from 'prop-types'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import {instanceForInstanceId} from '../../../utils/DirectoryUtils'; -import {ContextMenu, useContextMenu, ContextMenuButton, MenuItemRadio, MenuItem} from "../../structures/ContextMenu"; +import { + ContextMenu, + useContextMenu, + ContextMenuButton, + MenuItemRadio, + MenuItem, + MenuGroup +} from "../../structures/ContextMenu"; import {_t} from "../../../languageHandler"; import SdkConfig from "../../../SdkConfig"; import {useSettingValue} from "../../../hooks/useSettings"; @@ -147,11 +154,13 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se onOptionChange(hsName, undefined); } }; - removeButton = ; + removeButton = ; } + // ARIA: in actual fact the entire menu is one large radio group but for better screen reader support + // we use group to notate server wrongly. return ( -
+
{ server } { removeButton } @@ -167,7 +176,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se {_t("Matrix")} { entries } -
+
); }); @@ -194,7 +203,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se }; const buttonRect = handle.current.getBoundingClientRect(); - content = + content =
{options} @@ -217,7 +226,6 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se content = From 401d85ea6fd156bd2f2f46ce7a86db694a4deeaf Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 14:42:19 +0000 Subject: [PATCH 14/37] delint Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/directory/NetworkDropdown.js | 3 +-- src/i18n/strings/en_EN.json | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index 637fb09c18..22f919b162 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -27,7 +27,7 @@ import { ContextMenuButton, MenuItemRadio, MenuItem, - MenuGroup + MenuGroup, } from "../../structures/ContextMenu"; import {_t} from "../../../languageHandler"; import SdkConfig from "../../../SdkConfig"; @@ -35,7 +35,6 @@ import {useSettingValue} from "../../../hooks/useSettings"; import * as sdk from "../../../index"; import Modal from "../../../Modal"; import SettingsStore from "../../../settings/SettingsStore"; -import AccessibleButton from "../elements/AccessibleButton"; export const ALL_ROOMS = Symbol("ALL_ROOMS"); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index b7ba70b62f..59bc643539 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1440,6 +1440,7 @@ "All rooms": "All rooms", "Your server": "Your server", "Are you sure you want to remove %(serverName)s": "Are you sure you want to remove %(serverName)s", + "Remove server": "Remove server", "Matrix": "Matrix", "Add a new server": "Add a new server", "Enter the address of a new server you want to explore.": "Enter the address of a new server you want to explore.", From 84332184b518b9609cda77e7becb75d4761d0bb7 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 14:50:41 +0000 Subject: [PATCH 15/37] no need to await here as settings take a while to effect, we watch them elsewhere Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 2 +- src/components/views/directory/NetworkDropdown.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index 28dd1ed628..61f9825143 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -59,13 +59,13 @@ limitations under the License. right: 12px; height: 16px; width: 16px; + margin-top: 4px; &::after { content: ""; position: absolute; width: 16px; height: 16px; - top: 4px; mask-repeat: no-repeat; mask-position: center; mask-size: contain; diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index 22f919b162..c4a70c112e 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -146,7 +146,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se if (!ok) return; // delete from setting - await SettingsStore.setValue(SETTING_NAME, null, "account", servers.filter(s => s !== server)); + SettingsStore.setValue(SETTING_NAME, null, "account", servers.filter(s => s !== server)); // the selected server is being removed, reset to our HS if (serverSelected === server) { @@ -195,7 +195,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se if (!userDefinedServers.includes(newServer)) { const servers = [...userDefinedServers, newServer]; - await SettingsStore.setValue(SETTING_NAME, null, "account", servers); + SettingsStore.setValue(SETTING_NAME, null, "account", servers); } onOptionChange(newServer); // change filter to the new server From 4de0e21a4b596a0ef6083c00afd860c407a14dda Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 15:28:22 +0000 Subject: [PATCH 16/37] fix styling mistakes Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index 61f9825143..b23af0b2a0 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -33,7 +33,7 @@ limitations under the License. margin: 0; box-sizing: border-box; border-radius: 4px; - border: 1px solid $accent-color; + border: 1px solid $dialog-close-fg-color; background-color: $primary-bg-color; } @@ -120,6 +120,7 @@ limitations under the License. .mx_NetworkDropdown_server_add { padding: 16px 10px 16px 32px; position: relative; + border-radius: 0 0 4px 4px; &::before { content: ""; From ee1659625cfa7affa8ec873279cca35d3b5cd518 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 17:32:02 +0000 Subject: [PATCH 17/37] Add Field validation to TextInputDialog Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../views/dialogs/TextInputDialog.js | 59 +++++++++++++++---- .../views/directory/NetworkDropdown.js | 30 ++++++++++ src/i18n/strings/en_EN.json | 3 + 3 files changed, 81 insertions(+), 11 deletions(-) diff --git a/src/components/views/dialogs/TextInputDialog.js b/src/components/views/dialogs/TextInputDialog.js index 4b21e8206e..e56e9f2b87 100644 --- a/src/components/views/dialogs/TextInputDialog.js +++ b/src/components/views/dialogs/TextInputDialog.js @@ -18,6 +18,7 @@ import React, {createRef} from 'react'; import createReactClass from 'create-react-class'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; +import Field from "../elements/Field"; export default createReactClass({ displayName: 'TextInputDialog', @@ -33,6 +34,7 @@ export default createReactClass({ focus: PropTypes.bool, onFinished: PropTypes.func.isRequired, hasCancel: PropTypes.bool, + validator: PropTypes.func, // result of withValidation }, getDefaultProps: function() { @@ -45,25 +47,57 @@ export default createReactClass({ }; }, + getInitialState: function() { + return { + value: this.props.value, + valid: false, + }; + }, + UNSAFE_componentWillMount: function() { - this._textinput = createRef(); + this._field = createRef(); }, componentDidMount: function() { if (this.props.focus) { // Set the cursor at the end of the text input - this._textinput.current.value = this.props.value; + // this._field.current.value = this.props.value; + this._field.current.focus(); } }, - onOk: function() { - this.props.onFinished(true, this._textinput.current.value); + onOk: async function(ev) { + ev.preventDefault(); + if (this.props.validator) { + await this._field.current.validate({ allowEmpty: false }); + + if (!this._field.current.state.valid) { + this._field.current.focus(); + this._field.current.validate({ allowEmpty: false, focused: true }); + return; + } + } + this.props.onFinished(true, this.state.value); }, onCancel: function() { this.props.onFinished(false); }, + onChange: function(ev) { + this.setState({ + value: ev.target.value, + }); + }, + + onValidate: async function(fieldState) { + const result = await this.props.validator(fieldState); + this.setState({ + valid: result.valid, + }); + return result; + }, + render: function() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); @@ -77,14 +111,17 @@ export default createReactClass({
- + ref={this._field} + type="text" + label={this.props.placeholder} + value={this.state.value} + onChange={this.onChange} + onValidate={this.props.validator ? this.onValidate : undefined} + size="64" + />
diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index c4a70c112e..6d1501ca57 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -35,6 +35,7 @@ import {useSettingValue} from "../../../hooks/useSettings"; import * as sdk from "../../../index"; import Modal from "../../../Modal"; import SettingsStore from "../../../settings/SettingsStore"; +import withValidation from "../elements/Validation"; export const ALL_ROOMS = Symbol("ALL_ROOMS"); @@ -47,6 +48,34 @@ const inPlaceOf = (elementRect) => ({ chevronFace: "none", }); +const validServer = withValidation({ + rules: [ + { + key: "required", + test: async ({ value }) => !!value, + invalid: () => _t("Enter a server address"), + }, { + key: "available", + final: true, + test: async ({ value }) => { + try { + const opts = { + limit: 1, + server: value, + }; + // check if we can successfully load this server's room directory + await MatrixClientPeg.get().publicRooms(opts); + return true; + } catch (e) { + return false; + } + }, + valid: () => _t("Looks good"), + invalid: () => _t("Can't find this server or its room list"), + }, + ], +}); + // This dropdown sources homeservers from three places: // + your currently connected homeserver // + homeservers in config.json["roomDirectory"] @@ -188,6 +217,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se button: _t("Add"), hasCancel: false, placeholder: _t("Server address"), + validator: validServer, }); const [ok, newServer] = await finished; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 59bc643539..3f20d4ec61 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1437,6 +1437,9 @@ "And %(count)s more...|other": "And %(count)s more...", "ex. @bob:example.com": "ex. @bob:example.com", "Add User": "Add User", + "Enter a server address": "Enter a server address", + "Looks good": "Looks good", + "Can't find this server or its room list": "Can't find this server or its room list", "All rooms": "All rooms", "Your server": "Your server", "Are you sure you want to remove %(serverName)s": "Are you sure you want to remove %(serverName)s", From 1347d61671e9939ccfd725c93c9da079996a2c85 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 23:22:13 +0000 Subject: [PATCH 18/37] Remove low hanging Gemini consumers Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/groups/GroupMemberInfo.js | 6 +++--- src/components/views/groups/GroupMemberList.js | 6 +++--- src/components/views/groups/GroupRoomInfo.js | 6 +++--- src/components/views/groups/GroupRoomList.js | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/components/views/groups/GroupMemberInfo.js b/src/components/views/groups/GroupMemberInfo.js index e659352b74..f70c769ad7 100644 --- a/src/components/views/groups/GroupMemberInfo.js +++ b/src/components/views/groups/GroupMemberInfo.js @@ -27,6 +27,7 @@ import { GroupMemberType } from '../../../groups'; import GroupStore from '../../../stores/GroupStore'; import AccessibleButton from '../elements/AccessibleButton'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; export default createReactClass({ displayName: 'GroupMemberInfo', @@ -182,10 +183,9 @@ export default createReactClass({ this.props.groupMember.displayname || this.props.groupMember.userId ); - const GeminiScrollbarWrapper = sdk.getComponent('elements.GeminiScrollbarWrapper'); return (
- + @@ -199,7 +199,7 @@ export default createReactClass({
{ adminTools } - + ); }, diff --git a/src/components/views/groups/GroupMemberList.js b/src/components/views/groups/GroupMemberList.js index 05af70b266..2853e70afa 100644 --- a/src/components/views/groups/GroupMemberList.js +++ b/src/components/views/groups/GroupMemberList.js @@ -26,6 +26,7 @@ import { showGroupInviteDialog } from '../../../GroupAddressPicker'; import AccessibleButton from '../elements/AccessibleButton'; import TintableSvg from '../elements/TintableSvg'; import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases"; +import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; const INITIAL_LOAD_NUM_MEMBERS = 30; @@ -172,7 +173,6 @@ export default createReactClass({ }, render: function() { - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); if (this.state.fetching || this.state.fetchingInvitedMembers) { const Spinner = sdk.getComponent("elements.Spinner"); return (
@@ -225,10 +225,10 @@ export default createReactClass({ return (
{ inviteButton } - + { joined } { invited } - + { inputBox }
); diff --git a/src/components/views/groups/GroupRoomInfo.js b/src/components/views/groups/GroupRoomInfo.js index 7b9f43f15f..91d84be4d1 100644 --- a/src/components/views/groups/GroupRoomInfo.js +++ b/src/components/views/groups/GroupRoomInfo.js @@ -24,6 +24,7 @@ import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import GroupStore from '../../../stores/GroupStore'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; export default createReactClass({ displayName: 'GroupRoomInfo', @@ -153,7 +154,6 @@ export default createReactClass({ render: function() { 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 @@ export default createReactClass({ const groupRoomName = this.state.groupRoom.displayname; return (
- + @@ -231,7 +231,7 @@ export default createReactClass({
{ adminTools } - +
); }, diff --git a/src/components/views/groups/GroupRoomList.js b/src/components/views/groups/GroupRoomList.js index 5fd8c9f31d..dee304e1f6 100644 --- a/src/components/views/groups/GroupRoomList.js +++ b/src/components/views/groups/GroupRoomList.js @@ -22,6 +22,7 @@ import PropTypes from 'prop-types'; import { showGroupAddRoomDialog } from '../../../GroupAddressPicker'; import AccessibleButton from '../elements/AccessibleButton'; import TintableSvg from '../elements/TintableSvg'; +import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; const INITIAL_LOAD_NUM_ROOMS = 30; @@ -150,17 +151,16 @@ export default createReactClass({ placeholder={_t('Filter community rooms')} autoComplete="off" /> ); - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); const TruncatedList = sdk.getComponent("elements.TruncatedList"); return (
{ inviteButton } - + { this.makeGroupRoomTiles(this.state.searchQuery) } - + { inputBox }
); From a9f414dafed7a00ffab9eec4494367c0ce1c1cc4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 23:23:23 +0000 Subject: [PATCH 19/37] Remove unused SearchableEntityList.js Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/_components.scss | 1 - .../views/rooms/_SearchableEntityList.scss | 77 -------- src/components/structures/RoomView.js | 15 -- .../views/rooms/SearchableEntityList.js | 186 ------------------ 4 files changed, 279 deletions(-) delete mode 100644 res/css/views/rooms/_SearchableEntityList.scss delete mode 100644 src/components/views/rooms/SearchableEntityList.js diff --git a/res/css/_components.scss b/res/css/_components.scss index bc636eb3c6..68322b9660 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -177,7 +177,6 @@ @import "./views/rooms/_RoomTile.scss"; @import "./views/rooms/_RoomUpgradeWarningBar.scss"; @import "./views/rooms/_SearchBar.scss"; -@import "./views/rooms/_SearchableEntityList.scss"; @import "./views/rooms/_SendMessageComposer.scss"; @import "./views/rooms/_Stickers.scss"; @import "./views/rooms/_TopUnreadMessagesBar.scss"; diff --git a/res/css/views/rooms/_SearchableEntityList.scss b/res/css/views/rooms/_SearchableEntityList.scss deleted file mode 100644 index 37a663123d..0000000000 --- a/res/css/views/rooms/_SearchableEntityList.scss +++ /dev/null @@ -1,77 +0,0 @@ -/* -Copyright 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. -*/ - -.mx_SearchableEntityList { - display: flex; - - flex-direction: column; -} - -.mx_SearchableEntityList_query { - font-family: $font-family; - border-radius: 3px; - border: 1px solid $input-border-color; - padding: 9px; - color: $primary-fg-color; - background-color: $primary-bg-color; - margin-left: 3px; - font-size: 15px; - margin-bottom: 8px; - width: 189px; -} - -.mx_SearchableEntityList_query::-moz-placeholder { - color: $primary-fg-color; - opacity: 0.5; - font-size: 12px; -} - -.mx_SearchableEntityList_query::-webkit-input-placeholder { - color: $primary-fg-color; - opacity: 0.5; - font-size: 12px; -} - -.mx_SearchableEntityList_listWrapper { - flex: 1; - - overflow-y: auto; -} - -.mx_SearchableEntityList_list { - display: table; - table-layout: fixed; - width: 100%; -} - -.mx_SearchableEntityList_list .mx_EntityTile_chevron { - display: none; -} - -.mx_SearchableEntityList_hrWrapper { - width: 100%; - flex: 0 0 auto; -} - -.mx_SearchableEntityList hr { - height: 1px; - border: 0px; - color: $primary-fg-color; - background-color: $primary-fg-color; - margin-right: 15px; - margin-top: 11px; - margin-bottom: 11px; -} diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 36e30343e4..17a496b037 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -405,21 +405,6 @@ export default createReactClass({ this.onResize(); document.addEventListener("keydown", this.onKeyDown); - - // XXX: EVIL HACK to autofocus inviting on empty rooms. - // We use the setTimeout to avoid racing with focus_composer. - if (this.state.room && - this.state.room.getJoinedMemberCount() == 1 && - this.state.room.getLiveTimeline() && - this.state.room.getLiveTimeline().getEvents() && - this.state.room.getLiveTimeline().getEvents().length <= 6) { - const inviteBox = document.getElementById("mx_SearchableEntityList_query"); - setTimeout(function() { - if (inviteBox) { - inviteBox.focus(); - } - }, 50); - } }, shouldComponentUpdate: function(nextProps, nextState) { diff --git a/src/components/views/rooms/SearchableEntityList.js b/src/components/views/rooms/SearchableEntityList.js deleted file mode 100644 index 807ddbf729..0000000000 --- a/src/components/views/rooms/SearchableEntityList.js +++ /dev/null @@ -1,186 +0,0 @@ -/* -Copyright 2015, 2016 OpenMarket Ltd -Copyright 2019 The Matrix.org Foundation C.I.C. - -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 PropTypes from 'prop-types'; -import createReactClass from 'create-react-class'; -import * as sdk from "../../../index"; -import { _t } from '../../../languageHandler'; - -// A list capable of displaying entities which conform to the SearchableEntity -// interface which is an object containing getJsx(): Jsx and matches(query: string): boolean -const SearchableEntityList = createReactClass({ - displayName: 'SearchableEntityList', - - propTypes: { - emptyQueryShowsAll: PropTypes.bool, - showInputBox: PropTypes.bool, - onQueryChanged: PropTypes.func, // fn(inputText) - onSubmit: PropTypes.func, // fn(inputText) - entities: PropTypes.array, - truncateAt: PropTypes.number, - }, - - getDefaultProps: function() { - return { - showInputBox: true, - entities: [], - emptyQueryShowsAll: false, - onSubmit: function() {}, - onQueryChanged: function(input) {}, - }; - }, - - getInitialState: function() { - return { - query: "", - focused: false, - truncateAt: this.props.truncateAt, - results: this.getSearchResults("", this.props.entities), - }; - }, - - componentWillReceiveProps: function(newProps) { - // recalculate the search results in case we got new entities - this.setState({ - results: this.getSearchResults(this.state.query, newProps.entities), - }); - }, - - componentWillUnmount: function() { - // pretend the query box was blanked out else filters could still be - // applied to other components which rely on onQueryChanged. - this.props.onQueryChanged(""); - }, - - /** - * Public-facing method to set the input query text to the given input. - * @param {string} input - */ - setQuery: function(input) { - this.setState({ - query: input, - results: this.getSearchResults(input, this.props.entities), - }); - }, - - onQueryChanged: function(ev) { - const q = ev.target.value; - this.setState({ - query: q, - // reset truncation if they back out the entire text - truncateAt: (q.length === 0 ? this.props.truncateAt : this.state.truncateAt), - results: this.getSearchResults(q, this.props.entities), - }, () => { - // invoke the callback AFTER we've flushed the new state. We need to - // do this because onQueryChanged can result in new props being passed - // to this component, which will then try to recalculate the search - // list. If we do this without flushing, we'll recalc with the last - // search term and not the current one! - this.props.onQueryChanged(q); - }); - }, - - onQuerySubmit: function(ev) { - ev.preventDefault(); - this.props.onSubmit(this.state.query); - }, - - getSearchResults: function(query, entities) { - if (!query || query.length === 0) { - return this.props.emptyQueryShowsAll ? entities : []; - } - return entities.filter(function(e) { - return e.matches(query); - }); - }, - - _showAll: function() { - this.setState({ - truncateAt: -1, - }); - }, - - _createOverflowEntity: function(overflowCount, totalCount) { - const EntityTile = sdk.getComponent("rooms.EntityTile"); - const BaseAvatar = sdk.getComponent("avatars.BaseAvatar"); - const text = _t("and %(count)s others...", { count: overflowCount }); - return ( - - } name={text} presenceState="online" suppressOnHover={true} - onClick={this._showAll} /> - ); - }, - - render: function() { - let inputBox; - - if (this.props.showInputBox) { - inputBox = ( -
- { this.setState({ focused: true }); }} - onBlur= {() => { this.setState({ focused: false }); }} - placeholder={_t("Search")} /> -
- ); - } - - let list; - if (this.state.results.length > 1 || this.state.focused) { - if (this.props.truncateAt) { // caller wants list truncated - const TruncatedList = sdk.getComponent("elements.TruncatedList"); - list = ( - - { this.state.results.map((entity) => { - return entity.getJsx(); - }) } - - ); - } else { - list = ( -
- { this.state.results.map((entity) => { - return entity.getJsx(); - }) } -
- ); - } - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); - list = ( - - { list } - - ); - } - - return ( -
- { inputBox } - { list } - { list ?

: '' } -
- ); - }, -}); - -export default SearchableEntityList; From 30d971b81970215cb3719afc343e3e5e1fa7c8b5 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 23:36:52 +0000 Subject: [PATCH 20/37] migrate MyGroups away from Gemini Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/structures/_MyGroups.scss | 8 +++++--- src/components/structures/MyGroups.js | 6 ++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/res/css/structures/_MyGroups.scss b/res/css/structures/_MyGroups.scss index d25789ab94..9556fd57e3 100644 --- a/res/css/structures/_MyGroups.scss +++ b/res/css/structures/_MyGroups.scss @@ -67,9 +67,6 @@ limitations under the License. } } - - - .mx_MyGroups_headerCard_header { font-weight: bold; margin-bottom: 10px; @@ -100,6 +97,11 @@ limitations under the License. flex-direction: column; } +.mx_MyGroups_content, +.mx_MyGroups_scrollable { + overflow-y: scroll; +} + .mx_MyGroups_placeholder { background-color: $info-plinth-bg-color; color: $info-plinth-fg-color; diff --git a/src/components/structures/MyGroups.js b/src/components/structures/MyGroups.js index b26ab5ff70..b7efa2d00a 100644 --- a/src/components/structures/MyGroups.js +++ b/src/components/structures/MyGroups.js @@ -62,8 +62,6 @@ export default createReactClass({ const Loader = sdk.getComponent("elements.Spinner"); const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader'); const GroupTile = sdk.getComponent("groups.GroupTile"); - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); - let content; let contentHeader; @@ -74,7 +72,7 @@ export default createReactClass({ }); contentHeader = groupNodes.length > 0 ?

{ _t('Your Communities') }

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

{ _t( @@ -93,7 +91,7 @@ export default createReactClass({

{ groupNodes }
- : +
:
{ _t( "You're not currently a member of any communities.", From c77ba71f895b3d87f42020bcfa2525ffa8b174f5 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 23:39:42 +0000 Subject: [PATCH 21/37] migrate EmbeddedPage away from Gemini Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/EmbeddedPage.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/structures/EmbeddedPage.js b/src/components/structures/EmbeddedPage.js index 6d734c3838..f854dc955f 100644 --- a/src/components/structures/EmbeddedPage.js +++ b/src/components/structures/EmbeddedPage.js @@ -23,11 +23,11 @@ import PropTypes from 'prop-types'; import request from 'browser-request'; import { _t } from '../../languageHandler'; import sanitizeHtml from 'sanitize-html'; -import * as sdk from '../../index'; import dis from '../../dispatcher'; import {MatrixClientPeg} from '../../MatrixClientPeg'; import classnames from 'classnames'; import MatrixClientContext from "../../contexts/MatrixClientContext"; +import AutoHideScrollbar from "./AutoHideScrollbar"; export default class EmbeddedPage extends React.PureComponent { static propTypes = { @@ -117,10 +117,9 @@ export default class EmbeddedPage extends React.PureComponent {
; if (this.props.scrollbar) { - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); - return + return {content} - ; + ; } else { return
{content} From b68d4583d19bcf0d5e6f3fcda3652a84faf32587 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 23:49:28 +0000 Subject: [PATCH 22/37] migrate UnknownDeviceDialog away from Gemini Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/dialogs/_UnknownDeviceDialog.scss | 1 + src/components/views/dialogs/UnknownDeviceDialog.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/res/css/views/dialogs/_UnknownDeviceDialog.scss b/res/css/views/dialogs/_UnknownDeviceDialog.scss index 02e0fb1fe5..4c3bb9bdd3 100644 --- a/res/css/views/dialogs/_UnknownDeviceDialog.scss +++ b/res/css/views/dialogs/_UnknownDeviceDialog.scss @@ -44,6 +44,7 @@ limitations under the License. .mx_UnknownDeviceDialog .mx_Dialog_content { margin-bottom: 24px; + overflow-y: scroll; } .mx_UnknownDeviceDialog_deviceList > li { diff --git a/src/components/views/dialogs/UnknownDeviceDialog.js b/src/components/views/dialogs/UnknownDeviceDialog.js index d58961f964..3d5300fe92 100644 --- a/src/components/views/dialogs/UnknownDeviceDialog.js +++ b/src/components/views/dialogs/UnknownDeviceDialog.js @@ -168,7 +168,7 @@ export default createReactClass({ title={_t('Room contains unknown sessions')} contentId='mx_Dialog_content' > - +

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

@@ -176,7 +176,7 @@ export default createReactClass({ { _t("Unknown sessions") }: - +
From 1b933b7bfebd78631b0f80bdf7399006409829e0 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 13 Mar 2020 23:54:13 +0000 Subject: [PATCH 23/37] remove UnknownDeviceDialog gemini specific css Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/dialogs/_UnknownDeviceDialog.scss | 8 -------- 1 file changed, 8 deletions(-) diff --git a/res/css/views/dialogs/_UnknownDeviceDialog.scss b/res/css/views/dialogs/_UnknownDeviceDialog.scss index 4c3bb9bdd3..2b0f8dceca 100644 --- a/res/css/views/dialogs/_UnknownDeviceDialog.scss +++ b/res/css/views/dialogs/_UnknownDeviceDialog.scss @@ -14,14 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -// CSS voodoo to support a gemini-scrollbar for the contents of the dialog -.mx_Dialog_unknownDevice .mx_Dialog { - // ideally we'd shrink the height to fit when needed, but in practice this - // is a pain in the ass. plus might as well make the dialog big given how - // important it is. - height: 100%; -} - .mx_UnknownDeviceDialog { height: 100%; display: flex; From 6f27c4c17af4e47272ff21815c57b35da9d23456 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 16 Mar 2020 11:45:51 +0000 Subject: [PATCH 24/37] s/Server address/Server name/ Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/directory/NetworkDropdown.js | 4 ++-- src/i18n/strings/en_EN.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index 6d1501ca57..e56cfcf185 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -53,7 +53,7 @@ const validServer = withValidation({ { key: "required", test: async ({ value }) => !!value, - invalid: () => _t("Enter a server address"), + invalid: () => _t("Enter a server name"), }, { key: "available", final: true, @@ -216,7 +216,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se description: _t("Enter the address of a new server you want to explore."), button: _t("Add"), hasCancel: false, - placeholder: _t("Server address"), + placeholder: _t("Server name"), validator: validServer, }); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 3f20d4ec61..e990f76519 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1437,7 +1437,7 @@ "And %(count)s more...|other": "And %(count)s more...", "ex. @bob:example.com": "ex. @bob:example.com", "Add User": "Add User", - "Enter a server address": "Enter a server address", + "Enter a server name": "Enter a server name", "Looks good": "Looks good", "Can't find this server or its room list": "Can't find this server or its room list", "All rooms": "All rooms", @@ -1447,7 +1447,7 @@ "Matrix": "Matrix", "Add a new server": "Add a new server", "Enter the address of a new server you want to explore.": "Enter the address of a new server you want to explore.", - "Server address": "Server address", + "Server name": "Server name", "Add a new server...": "Add a new server...", "%(networkName)s rooms": "%(networkName)s rooms", "Matrix rooms": "Matrix rooms", From 82a37ba0ad429c09c101e175dd0650773dd67a2d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 16 Mar 2020 12:00:56 +0000 Subject: [PATCH 25/37] Fix styling of NetworkDropdown dialogs Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 4 ++++ src/components/views/dialogs/QuestionDialog.js | 6 +++++- src/components/views/dialogs/TextInputDialog.js | 6 +++++- src/components/views/directory/NetworkDropdown.js | 6 ++++-- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index b23af0b2a0..e60c481e45 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -157,3 +157,7 @@ limitations under the License. font-size: 12px; } } + +.mx_NetworkDropdown_dialog .mx_Dialog { + width: 557px; +} diff --git a/src/components/views/dialogs/QuestionDialog.js b/src/components/views/dialogs/QuestionDialog.js index 8cb16dd88f..07a1eae5d5 100644 --- a/src/components/views/dialogs/QuestionDialog.js +++ b/src/components/views/dialogs/QuestionDialog.js @@ -33,6 +33,7 @@ export default createReactClass({ onFinished: PropTypes.func.isRequired, headerImage: PropTypes.string, quitOnly: PropTypes.bool, // quitOnly doesn't show the cancel button just the quit [x]. + fixedWidth: PropTypes.bool, }, getDefaultProps: function() { @@ -63,11 +64,14 @@ export default createReactClass({ primaryButtonClass = "danger"; } return ( -
{ this.props.description } diff --git a/src/components/views/dialogs/TextInputDialog.js b/src/components/views/dialogs/TextInputDialog.js index e56e9f2b87..b9f6f6ebce 100644 --- a/src/components/views/dialogs/TextInputDialog.js +++ b/src/components/views/dialogs/TextInputDialog.js @@ -35,6 +35,7 @@ export default createReactClass({ onFinished: PropTypes.func.isRequired, hasCancel: PropTypes.bool, validator: PropTypes.func, // result of withValidation + fixedWidth: PropTypes.bool, }, getDefaultProps: function() { @@ -102,8 +103,11 @@ export default createReactClass({ const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return ( -
diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index e56cfcf185..85d72e33f0 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -169,7 +169,8 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se b: serverName => { serverName }, }), button: _t("Remove"), - }); + fixedWidth: false, + }, "mx_NetworkDropdown_dialog"); const [ok] = await finished; if (!ok) return; @@ -218,7 +219,8 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se hasCancel: false, placeholder: _t("Server name"), validator: validServer, - }); + fixedWidth: false, + }, "mx_NetworkDropdown_dialog"); const [ok, newServer] = await finished; if (!ok) return; From 454b32400dbc9d190dc594ebf3115bfe9e8cb277 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 16 Mar 2020 12:12:59 +0000 Subject: [PATCH 26/37] improve width Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/directory/_NetworkDropdown.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index e60c481e45..106392f880 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -159,5 +159,5 @@ limitations under the License. } .mx_NetworkDropdown_dialog .mx_Dialog { - width: 557px; + width: 45vw; } From eabaf5801388e40cba45322335be01d765472cbb Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 16 Mar 2020 12:20:52 +0000 Subject: [PATCH 27/37] Add local-echo Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../views/directory/NetworkDropdown.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index 85d72e33f0..425b951929 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, {useEffect, useState} from 'react'; import PropTypes from 'prop-types'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; @@ -84,7 +84,8 @@ const validServer = withValidation({ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, selectedInstanceId}) => { const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu(); - const userDefinedServers = useSettingValue(SETTING_NAME); + const _userDefinedServers = useSettingValue(SETTING_NAME); + const [userDefinedServers, _setUserDefinedServers] = useState(_userDefinedServers); const handlerFactory = (server, instanceId) => { return () => { @@ -93,6 +94,15 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se }; }; + const setUserDefinedServers = servers => { + _setUserDefinedServers(servers); + SettingsStore.setValue(SETTING_NAME, null, "account", servers); + }; + // keep local echo up to date with external changes + useEffect(() => { + _setUserDefinedServers(_userDefinedServers); + }, [_userDefinedServers]); + // we either show the button or the dropdown in its place. let content; if (menuDisplayed) { @@ -176,7 +186,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se if (!ok) return; // delete from setting - SettingsStore.setValue(SETTING_NAME, null, "account", servers.filter(s => s !== server)); + setUserDefinedServers(servers.filter(s => s !== server)); // the selected server is being removed, reset to our HS if (serverSelected === server) { @@ -226,8 +236,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se if (!ok) return; if (!userDefinedServers.includes(newServer)) { - const servers = [...userDefinedServers, newServer]; - SettingsStore.setValue(SETTING_NAME, null, "account", servers); + setUserDefinedServers([...userDefinedServers, newServer]); } onOptionChange(newServer); // change filter to the new server From 78543da7f4bb989499bbfac56d7ec27d21164177 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 16 Mar 2020 12:28:20 +0000 Subject: [PATCH 28/37] Fix missed copy Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/directory/NetworkDropdown.js | 2 +- src/i18n/strings/en_EN.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index 425b951929..2fabda1a74 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -224,7 +224,7 @@ const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, se const TextInputDialog = sdk.getComponent("dialogs.TextInputDialog"); const { finished } = Modal.createTrackedDialog("Network Dropdown", "Add a new server", TextInputDialog, { title: _t("Add a new server"), - description: _t("Enter the address of a new server you want to explore."), + description: _t("Enter the name of a new server you want to explore."), button: _t("Add"), hasCancel: false, placeholder: _t("Server name"), diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index e990f76519..a14e275a51 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1446,7 +1446,7 @@ "Remove server": "Remove server", "Matrix": "Matrix", "Add a new server": "Add a new server", - "Enter the address of a new server you want to explore.": "Enter the address of a new server you want to explore.", + "Enter the name of a new server you want to explore.": "Enter the name of a new server you want to explore.", "Server name": "Server name", "Add a new server...": "Add a new server...", "%(networkName)s rooms": "%(networkName)s rooms", From 43f0013dda8a5c67e1e4eb7c15d6f6772986960c Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 17 Mar 2020 10:09:47 +0000 Subject: [PATCH 29/37] Migrate GroupView away from Gemini Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/structures/_GroupView.scss | 4 ++-- res/css/structures/_MainSplit.scss | 1 + src/components/structures/GroupView.js | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/res/css/structures/_GroupView.scss b/res/css/structures/_GroupView.scss index 517b8b1922..7072307b9d 100644 --- a/res/css/structures/_GroupView.scss +++ b/res/css/structures/_GroupView.scss @@ -341,8 +341,8 @@ limitations under the License. display: none; } -.mx_GroupView_body .gm-scroll-view > * { - margin: 11px 50px 0px 68px; +.mx_GroupView_body .mx_AutoHideScrollbar_offset > * { + margin: 11px 50px 50px 68px; } .mx_GroupView_groupDesc textarea { diff --git a/res/css/structures/_MainSplit.scss b/res/css/structures/_MainSplit.scss index 4d73953cd7..25e1153fce 100644 --- a/res/css/structures/_MainSplit.scss +++ b/res/css/structures/_MainSplit.scss @@ -18,6 +18,7 @@ limitations under the License. display: flex; flex-direction: row; min-width: 0; + height: 100%; } // move hit area 5px to the right so it doesn't overlap with the timeline scrollbar diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index af90fbbe83..cadc511fc3 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -39,6 +39,7 @@ import {makeGroupPermalink, makeUserPermalink} from "../../utils/permalinks/Perm import {Group} from "matrix-js-sdk"; import {allSettled, sleep} from "../../utils/promise"; import RightPanelStore from "../../stores/RightPanelStore"; +import AutoHideScrollbar from "./AutoHideScrollbar"; const LONG_DESC_PLACEHOLDER = _td( `

HTML for your community's page

@@ -1173,7 +1174,6 @@ export default createReactClass({ render: function() { const GroupAvatar = sdk.getComponent("avatars.GroupAvatar"); const Spinner = sdk.getComponent("elements.Spinner"); - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); if (this.state.summaryLoading && this.state.error === null || this.state.saving) { return ; @@ -1332,10 +1332,10 @@ export default createReactClass({
- + { this._getMembershipSection() } { this._getGroupSection() } - + ); From 8dfc15a3288d685fb3c6e664ce71e5deeeb1ee60 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 17 Mar 2020 10:23:12 +0000 Subject: [PATCH 30/37] Migrate TagPanel away from Gemini Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/structures/_TagPanel.scss | 2 ++ src/components/structures/TagPanel.js | 7 +++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/res/css/structures/_TagPanel.scss b/res/css/structures/_TagPanel.scss index dddd2e324c..77f016f05f 100644 --- a/res/css/structures/_TagPanel.scss +++ b/res/css/structures/_TagPanel.scss @@ -57,6 +57,8 @@ limitations under the License. .mx_TagPanel .mx_TagPanel_scroller { flex-grow: 1; + width: 100%; + height: 100vh; } .mx_TagPanel .mx_TagPanel_tagTileContainer { diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js index 622e63d8ce..f1a39d6fcf 100644 --- a/src/components/structures/TagPanel.js +++ b/src/components/structures/TagPanel.js @@ -28,6 +28,7 @@ import { _t } from '../../languageHandler'; import { Droppable } from 'react-beautiful-dnd'; import classNames from 'classnames'; import MatrixClientContext from "../../contexts/MatrixClientContext"; +import AutoHideScrollbar from "./AutoHideScrollbar"; const TagPanel = createReactClass({ displayName: 'TagPanel', @@ -106,7 +107,6 @@ const TagPanel = createReactClass({ const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); const ActionButton = sdk.getComponent('elements.ActionButton'); const TintableSvg = sdk.getComponent('elements.TintableSvg'); - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); const tags = this.state.orderedTags.map((tag, index) => { return
- ) } - +
; }, }); From 44b0aa2d88a3d30eba1c8fc44e9fa8397e7958c4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 17 Mar 2020 10:31:45 +0000 Subject: [PATCH 31/37] Remove remainders of gemini-scrollbar and react-gemini-scrollbar Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- package.json | 2 -- res/css/_common.scss | 31 ---------------- res/css/structures/_GroupView.scss | 2 +- res/css/structures/_MatrixChat.scss | 7 ---- res/themes/dark/css/_dark.scss | 4 --- src/components/structures/ScrollPanel.js | 2 +- .../views/dialogs/UnknownDeviceDialog.js | 1 - .../views/elements/GeminiScrollbarWrapper.js | 35 ------------------- yarn.lock | 10 ------ 9 files changed, 2 insertions(+), 92 deletions(-) delete mode 100644 src/components/views/elements/GeminiScrollbarWrapper.js diff --git a/package.json b/package.json index eeca614aa2..075295ba0e 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,6 @@ "flux": "2.1.1", "focus-visible": "^5.0.2", "fuse.js": "^2.2.0", - "gemini-scrollbar": "github:matrix-org/gemini-scrollbar#91e1e566", "gfm.css": "^1.1.1", "glob-to-regexp": "^0.4.1", "highlight.js": "^9.15.8", @@ -93,7 +92,6 @@ "react-beautiful-dnd": "^4.0.1", "react-dom": "^16.9.0", "react-focus-lock": "^2.2.1", - "react-gemini-scrollbar": "github:matrix-org/react-gemini-scrollbar#9cf17f63b7c0b0ec5f31df27da0f82f7238dc594", "resize-observer-polyfill": "^1.5.0", "sanitize-html": "^1.18.4", "text-encoding-utf-8": "^1.0.1", diff --git a/res/css/_common.scss b/res/css/_common.scss index a4ef603242..ad64aced50 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -207,37 +207,6 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { transition: opacity 0.2s ease-in-out; } -/* XXX: critical hack to GeminiScrollbar to allow them to work in FF 42 and Chrome 48. - Stop the scrollbar view from pushing out the container's overall sizing, which causes - flexbox to adapt to the new size and cause the view to keep growing. - */ -.gm-scrollbar-container .gm-scroll-view { - position: absolute; -} - -/* Expand thumbs on hoverover */ -.gm-scrollbar { - border-radius: 5px !important; -} -.gm-scrollbar.-vertical { - width: 6px; - transition: width 120ms ease-out !important; -} -.gm-scrollbar.-vertical:hover, -.gm-scrollbar.-vertical:active { - width: 8px; - transition: width 120ms ease-out !important; -} -.gm-scrollbar.-horizontal { - height: 6px; - transition: height 120ms ease-out !important; -} -.gm-scrollbar.-horizontal:hover, -.gm-scrollbar.-horizontal:active { - height: 8px; - transition: height 120ms ease-out !important; -} - // These are magic constants which are excluded from tinting, to let themes // (which only have CSS, unlike skins) tell the app what their non-tinted // colourscheme is by inspecting the stylesheet DOM. diff --git a/res/css/structures/_GroupView.scss b/res/css/structures/_GroupView.scss index 7072307b9d..6963f8a160 100644 --- a/res/css/structures/_GroupView.scss +++ b/res/css/structures/_GroupView.scss @@ -370,7 +370,7 @@ limitations under the License. padding: 40px 20px; } -.mx_GroupView .mx_MemberInfo .gm-scroll-view > :not(.mx_MemberInfo_avatar) { +.mx_GroupView .mx_MemberInfo .mx_AutoHideScrollbar_offset > :not(.mx_MemberInfo_avatar) { padding-left: 16px; padding-right: 16px; } diff --git a/res/css/structures/_MatrixChat.scss b/res/css/structures/_MatrixChat.scss index f2ce7e1d5c..c5a5d50068 100644 --- a/res/css/structures/_MatrixChat.scss +++ b/res/css/structures/_MatrixChat.scss @@ -76,13 +76,6 @@ limitations under the License. flex: 1 1 0; min-width: 0; - /* Experimental fix for https://github.com/vector-im/vector-web/issues/947 - and https://github.com/vector-im/vector-web/issues/946. - Empirically this stops the MessagePanel's width exploding outwards when - gemini is in 'prevented' mode - */ - overflow-x: auto; - /* To fix https://github.com/vector-im/riot-web/issues/3298 where Safari needed height 100% all the way down to the HomePage. Height does not have to be auto, empirically. diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index a3515a9d99..33670c39bf 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -219,10 +219,6 @@ $user-tile-hover-bg-color: $header-panel-bg-color; filter: invert(1); } -.gm-scrollbar .thumb { - filter: invert(1); -} - // markdown overrides: .mx_EventTile_content .markdown-body pre:hover { border-color: #808080 !important; // inverted due to rules below diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index b81b3ebede..c218fee5d6 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -782,7 +782,7 @@ export default createReactClass({ if (!this._divScroll) { // 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"); + throw new Error("ScrollPanel._getScrollNode called before AutoHideScrollbar ref collected"); } return this._divScroll; diff --git a/src/components/views/dialogs/UnknownDeviceDialog.js b/src/components/views/dialogs/UnknownDeviceDialog.js index 3d5300fe92..69ebb72a6f 100644 --- a/src/components/views/dialogs/UnknownDeviceDialog.js +++ b/src/components/views/dialogs/UnknownDeviceDialog.js @@ -122,7 +122,6 @@ export default createReactClass({ }, render: function() { - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); if (this.props.devices === null) { const Spinner = sdk.getComponent("elements.Spinner"); return ; diff --git a/src/components/views/elements/GeminiScrollbarWrapper.js b/src/components/views/elements/GeminiScrollbarWrapper.js deleted file mode 100644 index 13eb14ecc3..0000000000 --- a/src/components/views/elements/GeminiScrollbarWrapper.js +++ /dev/null @@ -1,35 +0,0 @@ -/* -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'; - -function GeminiScrollbarWrapper(props) { - const {wrappedRef, ...wrappedProps} = 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; - diff --git a/yarn.lock b/yarn.lock index 705b02e3e4..c6fd3432cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3902,10 +3902,6 @@ fuse.js@^2.2.0: resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-2.7.4.tgz#96e420fde7ef011ac49c258a621314fe576536f9" integrity sha1-luQg/efvARrEnCWKYhMU/ldlNvk= -"gemini-scrollbar@github:matrix-org/gemini-scrollbar#91e1e566", gemini-scrollbar@matrix-org/gemini-scrollbar#91e1e566: - version "1.4.3" - resolved "https://codeload.github.com/matrix-org/gemini-scrollbar/tar.gz/91e1e566fa33324188f278801baf4a79f9f554ab" - gensync@^1.0.0-beta.1: version "1.0.0-beta.1" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" @@ -6963,12 +6959,6 @@ react-focus-lock@^2.2.1: use-callback-ref "^1.2.1" use-sidecar "^1.0.1" -"react-gemini-scrollbar@github:matrix-org/react-gemini-scrollbar#9cf17f63b7c0b0ec5f31df27da0f82f7238dc594": - version "2.1.5" - resolved "https://codeload.github.com/matrix-org/react-gemini-scrollbar/tar.gz/9cf17f63b7c0b0ec5f31df27da0f82f7238dc594" - dependencies: - gemini-scrollbar matrix-org/gemini-scrollbar#91e1e566 - react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6, react-is@^16.9.0: version "16.13.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.0.tgz#0f37c3613c34fe6b37cd7f763a0d6293ab15c527" From 8fd3b96b7231661b1c5d8298933b69ace4ad0447 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 17 Mar 2020 11:53:19 +0000 Subject: [PATCH 32/37] fix styling/heights Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/structures/_GroupView.scss | 4 ---- res/css/structures/_MyGroups.scss | 5 +++++ res/css/structures/_TagPanel.scss | 2 +- src/components/structures/MyGroups.js | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/res/css/structures/_GroupView.scss b/res/css/structures/_GroupView.scss index 6963f8a160..2575169664 100644 --- a/res/css/structures/_GroupView.scss +++ b/res/css/structures/_GroupView.scss @@ -180,10 +180,6 @@ limitations under the License. line-height: 2em; } -.mx_GroupView > .mx_MainSplit { - flex: 1; -} - .mx_GroupView_body { flex-grow: 1; } diff --git a/res/css/structures/_MyGroups.scss b/res/css/structures/_MyGroups.scss index 9556fd57e3..47a5ea5a77 100644 --- a/res/css/structures/_MyGroups.scss +++ b/res/css/structures/_MyGroups.scss @@ -95,6 +95,11 @@ limitations under the License. display: flex; flex-direction: column; + overflow-y: auto; +} + +.mx_MyGroups_scrollable { + overflow-y: inherit; } .mx_MyGroups_content, diff --git a/res/css/structures/_TagPanel.scss b/res/css/structures/_TagPanel.scss index 77f016f05f..03f5ce230c 100644 --- a/res/css/structures/_TagPanel.scss +++ b/res/css/structures/_TagPanel.scss @@ -23,6 +23,7 @@ limitations under the License. flex-direction: column; align-items: center; justify-content: space-between; + height: 100%; } .mx_TagPanel_items_selected { @@ -58,7 +59,6 @@ limitations under the License. .mx_TagPanel .mx_TagPanel_scroller { flex-grow: 1; width: 100%; - height: 100vh; } .mx_TagPanel .mx_TagPanel_tagTileContainer { diff --git a/src/components/structures/MyGroups.js b/src/components/structures/MyGroups.js index b7efa2d00a..f75fc86fc8 100644 --- a/src/components/structures/MyGroups.js +++ b/src/components/structures/MyGroups.js @@ -72,7 +72,7 @@ export default createReactClass({ }); contentHeader = groupNodes.length > 0 ?

{ _t('Your Communities') }

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

{ _t( From 638629c2fa6fcba33080c77e9d83f4134217fbbb Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 17 Mar 2020 13:28:07 +0000 Subject: [PATCH 33/37] fix MyGroups scrollbar Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/structures/_MyGroups.scss | 5 ----- src/components/structures/MyGroups.js | 5 +++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/res/css/structures/_MyGroups.scss b/res/css/structures/_MyGroups.scss index 47a5ea5a77..36150c33a5 100644 --- a/res/css/structures/_MyGroups.scss +++ b/res/css/structures/_MyGroups.scss @@ -102,11 +102,6 @@ limitations under the License. overflow-y: inherit; } -.mx_MyGroups_content, -.mx_MyGroups_scrollable { - overflow-y: scroll; -} - .mx_MyGroups_placeholder { background-color: $info-plinth-bg-color; color: $info-plinth-fg-color; diff --git a/src/components/structures/MyGroups.js b/src/components/structures/MyGroups.js index f75fc86fc8..f1209b7b9e 100644 --- a/src/components/structures/MyGroups.js +++ b/src/components/structures/MyGroups.js @@ -22,6 +22,7 @@ import { _t } from '../../languageHandler'; import dis from '../../dispatcher'; import AccessibleButton from '../views/elements/AccessibleButton'; import MatrixClientContext from "../../contexts/MatrixClientContext"; +import AutoHideScrollbar from "./AutoHideScrollbar"; export default createReactClass({ displayName: 'MyGroups', @@ -72,7 +73,7 @@ export default createReactClass({ }); contentHeader = groupNodes.length > 0 ?

{ _t('Your Communities') }

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

{ _t( @@ -91,7 +92,7 @@ export default createReactClass({

{ groupNodes }
-
: +
:
{ _t( "You're not currently a member of any communities.", From af023a2d7c3788c107ad046126f0fd4a925862c3 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 17 Mar 2020 11:13:52 -0600 Subject: [PATCH 34/37] rename 'jump to bottom' to avoid ublock block --- src/components/views/rooms/JumpToBottomButton.js | 2 +- src/i18n/strings/en_EN.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/JumpToBottomButton.js b/src/components/views/rooms/JumpToBottomButton.js index 487071855f..d3305f498a 100644 --- a/src/components/views/rooms/JumpToBottomButton.js +++ b/src/components/views/rooms/JumpToBottomButton.js @@ -24,7 +24,7 @@ export default (props) => { } return (
{ badge } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index d92cf41f5b..bf46586651 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -955,7 +955,7 @@ "Encrypted by a deleted session": "Encrypted by a deleted session", "Please select the destination room for this message": "Please select the destination room for this message", "Invite only": "Invite only", - "Scroll to bottom of page": "Scroll to bottom of page", + "Scroll to most recent messages": "Scroll to most recent messages", "Close preview": "Close preview", "device id: ": "device id: ", "Disinvite": "Disinvite", From 84a8ca69828a5934e5ea077c86d83b8e0e4806e9 Mon Sep 17 00:00:00 2001 From: Aaron Raimist Date: Tue, 17 Mar 2020 13:18:22 -0500 Subject: [PATCH 35/37] Fix typo Signed-off-by: Aaron Raimist --- src/components/views/rooms/BasicMessageComposer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/BasicMessageComposer.js b/src/components/views/rooms/BasicMessageComposer.js index 52947aa6e2..3c5c698f51 100644 --- a/src/components/views/rooms/BasicMessageComposer.js +++ b/src/components/views/rooms/BasicMessageComposer.js @@ -372,7 +372,7 @@ export default class BasicMessageEditor extends React.Component { handled = true; // redo } else if ((!IS_MAC && modKey && event.key === Key.Y) || - (IS_MAC && modkey && event.shiftKey && event.key === Key.Z)) { + (IS_MAC && modKey && event.shiftKey && event.key === Key.Z)) { if (this.historyManager.canRedo()) { const {parts, caret} = this.historyManager.redo(); // pass matching inputType so historyManager doesn't push echo From 7b1b4cda14625fced42cf43641f00e175c8c5af7 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 17 Mar 2020 20:37:40 +0100 Subject: [PATCH 36/37] ensure local state for aliases doesn't get garbled up when removing another alias before the response of the first comes back --- src/components/views/room_settings/AliasSettings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/room_settings/AliasSettings.js b/src/components/views/room_settings/AliasSettings.js index f8e2151c4f..bdcb22342c 100644 --- a/src/components/views/room_settings/AliasSettings.js +++ b/src/components/views/room_settings/AliasSettings.js @@ -233,11 +233,11 @@ export default class AliasSettings extends React.Component { onLocalAliasDeleted = (index) => { const alias = this.state.localAliases[index]; + console.log("removing local alias", index, alias); // TODO: In future, we should probably be making sure that the alias actually belongs // to this room. See https://github.com/vector-im/riot-web/issues/7353 MatrixClientPeg.get().deleteAlias(alias).then(() => { - const localAliases = this.state.localAliases.slice(); - localAliases.splice(index, 1); + const localAliases = this.state.localAliases.filter(a => a !== alias); this.setState({localAliases}); if (this.state.canonicalAlias === alias) { From f8c6097c397438e9f8a3b70f530e0e1f05d9c9fe Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 18 Mar 2020 11:18:48 +0100 Subject: [PATCH 37/37] remove logging --- src/components/views/room_settings/AliasSettings.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/views/room_settings/AliasSettings.js b/src/components/views/room_settings/AliasSettings.js index bdcb22342c..857a80c34a 100644 --- a/src/components/views/room_settings/AliasSettings.js +++ b/src/components/views/room_settings/AliasSettings.js @@ -233,7 +233,6 @@ export default class AliasSettings extends React.Component { onLocalAliasDeleted = (index) => { const alias = this.state.localAliases[index]; - console.log("removing local alias", index, alias); // TODO: In future, we should probably be making sure that the alias actually belongs // to this room. See https://github.com/vector-im/riot-web/issues/7353 MatrixClientPeg.get().deleteAlias(alias).then(() => {