From 3cead032c2fe1a0b0034c2a3b2c06248ebc2c564 Mon Sep 17 00:00:00 2001 From: David Baker <dave@matrix.org> Date: Tue, 16 May 2017 16:27:58 +0100 Subject: [PATCH 1/6] Revert "Merge pull request #3804 from vector-im/dbkr/left_panel_for_newbies_2" This reverts commit e6133820a2f70f94e693f6352da71c03ef5a079a, reversing changes made to d1db602b3a3e735430016af2fc837841feafdb43. --- src/components/structures/BottomLeftMenu.js | 127 +++++++++++++++--- src/components/structures/RoomSubList.js | 19 ++- .../structures/RoomSubListHeader.js | 44 +++--- src/skins/vector/css/_components.scss | 1 - .../views/elements/_RoleButton.scss | 33 ----- .../views/rooms/_RoomList.scss | 23 ---- .../css/vector-web/structures/_LeftPanel.scss | 34 +++-- 7 files changed, 170 insertions(+), 111 deletions(-) delete mode 100644 src/skins/vector/css/matrix-react-sdk/views/elements/_RoleButton.scss diff --git a/src/components/structures/BottomLeftMenu.js b/src/components/structures/BottomLeftMenu.js index 63dfac60..f378cac6 100644 --- a/src/components/structures/BottomLeftMenu.js +++ b/src/components/structures/BottomLeftMenu.js @@ -1,6 +1,5 @@ /* Copyright 2015, 2016 OpenMarket Ltd -Copyright 2017 Vector Creations Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,8 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; -import sdk from 'matrix-react-sdk'; +'use strict'; + +var React = require('react'); +var ReactDOM = require('react-dom'); +var sdk = require('matrix-react-sdk') +var dis = require('matrix-react-sdk/lib/dispatcher'); +var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); module.exports = React.createClass({ displayName: 'BottomLeftMenu', @@ -26,28 +30,121 @@ module.exports = React.createClass({ teamToken: React.PropTypes.string, }, + getInitialState: function() { + return({ + directoryHover : false, + roomsHover : false, + homeHover: false, + peopleHover : false, + settingsHover : false, + }); + }, + + // Room events + onDirectoryClick: function() { + dis.dispatch({ action: 'view_room_directory' }); + }, + + onDirectoryMouseEnter: function() { + this.setState({ directoryHover: true }); + }, + + onDirectoryMouseLeave: function() { + this.setState({ directoryHover: false }); + }, + + onRoomsClick: function() { + dis.dispatch({ action: 'view_create_room' }); + }, + + onRoomsMouseEnter: function() { + this.setState({ roomsHover: true }); + }, + + onRoomsMouseLeave: function() { + this.setState({ roomsHover: false }); + }, + + // Home button events + onHomeClick: function() { + dis.dispatch({ action: 'view_home_page' }); + }, + + onHomeMouseEnter: function() { + this.setState({ homeHover: true }); + }, + + onHomeMouseLeave: function() { + this.setState({ homeHover: false }); + }, + + // People events + onPeopleClick: function() { + dis.dispatch({ action: 'view_create_chat' }); + }, + + onPeopleMouseEnter: function() { + this.setState({ peopleHover: true }); + }, + + onPeopleMouseLeave: function() { + this.setState({ peopleHover: false }); + }, + + // Settings events + onSettingsClick: function() { + dis.dispatch({ action: 'view_user_settings' }); + }, + + onSettingsMouseEnter: function() { + this.setState({ settingsHover: true }); + }, + + onSettingsMouseLeave: function() { + this.setState({ settingsHover: false }); + }, + + // Get the label/tooltip to show + getLabel: function(label, show) { + if (show) { + var RoomTooltip = sdk.getComponent("rooms.RoomTooltip"); + return <RoomTooltip className="mx_BottomLeftMenu_tooltip" label={label} />; + } + }, + render: function() { - const HomeButton = sdk.getComponent('elements.HomeButton'); - const StartChatButton = sdk.getComponent('elements.StartChatButton'); - const RoomDirectoryButton = sdk.getComponent('elements.RoomDirectoryButton'); - const CreateRoomButton = sdk.getComponent('elements.CreateRoomButton'); - const SettingsButton = sdk.getComponent('elements.SettingsButton'); + var TintableSvg = sdk.getComponent('elements.TintableSvg'); var homeButton; if (this.props.teamToken) { - homeButton = <HomeButton tooltip={true} />; + homeButton = ( + <AccessibleButton className="mx_BottomLeftMenu_homePage" onClick={ this.onHomeClick } onMouseEnter={ this.onHomeMouseEnter } onMouseLeave={ this.onHomeMouseLeave } > + <TintableSvg src="img/icons-home.svg" width="25" height="25" /> + { this.getLabel("Welcome page", this.state.homeHover) } + </AccessibleButton> + ); } return ( <div className="mx_BottomLeftMenu"> <div className="mx_BottomLeftMenu_options"> { homeButton } - <StartChatButton tooltip={true} /> - <RoomDirectoryButton tooltip={true} /> - <CreateRoomButton tooltip={true} /> - <span className="mx_BottomLeftMenu_settings"> - <SettingsButton tooltip={true} /> - </span> + <AccessibleButton className="mx_BottomLeftMenu_people" onClick={ this.onPeopleClick } onMouseEnter={ this.onPeopleMouseEnter } onMouseLeave={ this.onPeopleMouseLeave } > + <TintableSvg src="img/icons-people.svg" width="25" height="25" /> + { this.getLabel("Start chat", this.state.peopleHover) } + </AccessibleButton> + <AccessibleButton className="mx_BottomLeftMenu_directory" onClick={ this.onDirectoryClick } onMouseEnter={ this.onDirectoryMouseEnter } onMouseLeave={ this.onDirectoryMouseLeave } > + <TintableSvg src="img/icons-directory.svg" width="25" height="25"/> + { this.getLabel("Room directory", this.state.directoryHover) } + </AccessibleButton> + <AccessibleButton className="mx_BottomLeftMenu_createRoom" onClick={ this.onRoomsClick } onMouseEnter={ this.onRoomsMouseEnter } onMouseLeave={ this.onRoomsMouseLeave } > + <TintableSvg src="img/icons-create-room.svg" width="25" height="25" /> + { this.getLabel("Create new room", this.state.roomsHover) } + </AccessibleButton> + <AccessibleButton className="mx_BottomLeftMenu_settings" onClick={ this.onSettingsClick } onMouseEnter={ this.onSettingsMouseEnter } onMouseLeave={ this.onSettingsMouseLeave } > + <TintableSvg src="img/icons-settings.svg" width="25" height="25" /> + { this.getLabel("Settings", this.state.settingsHover) } + </AccessibleButton> </div> </div> ); diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index ab6c4422..c315ae46 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -1,5 +1,4 @@ /* -Copyright 2017 Vector Creations Ltd Copyright 2015, 2016 OpenMarket Ltd Licensed under the Apache License, Version 2.0 (the "License"); @@ -84,8 +83,6 @@ var RoomSubList = React.createClass({ incomingCall: React.PropTypes.object, onShowMoreRooms: React.PropTypes.func, searchFilter: React.PropTypes.string, - emptyContent: React.PropTypes.node, // content shown if the list is empty - headerItems: React.PropTypes.node, // content shown in the sublist header }, getInitialState: function() { @@ -472,15 +469,16 @@ var RoomSubList = React.createClass({ render: function() { var connectDropTarget = this.props.connectDropTarget; + var RoomDropTarget = sdk.getComponent('rooms.RoomDropTarget'); var TruncatedList = sdk.getComponent('elements.TruncatedList'); var label = this.props.collapsed ? null : this.props.label; - let content; - if (this.state.sortedList.length == 0) { - content = this.props.emptyContent; - } else { - content = this.makeRoomTiles(); + //console.log("render: " + JSON.stringify(this.state.sortedList)); + + var target; + if (this.state.sortedList.length == 0 && this.props.editable) { + target = <RoomDropTarget label={ 'Drop here to ' + this.props.verb }/>; } var roomCount = this.props.list.length > 0 ? this.props.list.length : ''; @@ -500,7 +498,8 @@ var RoomSubList = React.createClass({ if (!this.state.hidden) { subList = <TruncatedList className={ classes } truncateAt={this.state.truncateAt} createOverflowElement={this._createOverflowTile} > - { content } + { target } + { this.makeRoomTiles() } </TruncatedList>; } else { @@ -522,7 +521,6 @@ var RoomSubList = React.createClass({ roomNotificationCount={ this.roomNotificationCount() } onClick={ this.onClick } onHeaderClick={ this.props.onHeaderClick } - headerItems={this.props.headerItems} /> { subList } </div> @@ -544,7 +542,6 @@ var RoomSubList = React.createClass({ roomNotificationCount={ this.roomNotificationCount() } onClick={ this.onClick } onHeaderClick={ this.props.onHeaderClick } - headerItems={this.props.headerItems} /> : undefined } { (this.props.showSpinner && !this.state.hidden) ? <Loader /> : undefined } diff --git a/src/components/structures/RoomSubListHeader.js b/src/components/structures/RoomSubListHeader.js index 74094ae0..ad9aff5f 100644 --- a/src/components/structures/RoomSubListHeader.js +++ b/src/components/structures/RoomSubListHeader.js @@ -14,11 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; -import classNames from 'classnames'; -import sdk from 'matrix-react-sdk'; -import { formatCount } from 'matrix-react-sdk/lib/utils/FormattingUtils'; -import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton'; +'use strict'; + +var React = require('react'); +var ReactDOM = require('react-dom'); +var classNames = require('classnames'); +var sdk = require('matrix-react-sdk') +var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils'); +var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs'); +var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); +var ConstantTimeDispatcher = require('matrix-react-sdk/lib/ConstantTimeDispatcher'); module.exports = React.createClass({ displayName: 'RoomSubListHeader', @@ -37,7 +42,6 @@ module.exports = React.createClass({ hidden: React.PropTypes.bool, onClick: React.PropTypes.func, onHeaderClick: React.PropTypes.func, - headerItems: React.PropTypes.node, // content shown in the sublist header }, getDefaultProps: function() { @@ -59,34 +63,35 @@ module.exports = React.createClass({ // }, render: function() { - const TintableSvg = sdk.getComponent("elements.TintableSvg"); + var TintableSvg = sdk.getComponent("elements.TintableSvg"); - const subListNotifications = this.props.roomNotificationCount; - const subListNotifCount = subListNotifications[0]; - const subListNotifHighlight = subListNotifications[1]; + var subListNotifications = this.props.roomNotificationCount; + var subListNotifCount = subListNotifications[0]; + var subListNotifHighlight = subListNotifications[1]; - const chevronClasses = classNames({ + var chevronClasses = classNames({ 'mx_RoomSubList_chevron': true, 'mx_RoomSubList_chevronRight': this.props.hidden, 'mx_RoomSubList_chevronDown': !this.props.hidden, }); - const badgeClasses = classNames({ + var badgeClasses = classNames({ 'mx_RoomSubList_badge': true, 'mx_RoomSubList_badgeHighlight': subListNotifHighlight, }); - let badge; + var badge; if (subListNotifCount > 0) { - badge = <div className={badgeClasses}>{ formatCount(subListNotifCount) }</div>; - } else if (subListNotifHighlight) { + badge = <div className={badgeClasses}>{ FormattingUtils.formatCount(subListNotifCount) }</div>; + } + else if (subListNotifHighlight) { badge = <div className={badgeClasses}>!</div>; } // When collapsed, allow a long hover on the header to show user // the full tag name and room count - let title; - const roomCount = this.props.roomCount; + var title; + var roomCount = this.props.roomCount; if (this.props.collapsed) { title = this.props.label; if (roomCount !== '') { @@ -94,9 +99,9 @@ module.exports = React.createClass({ } } - let incomingCall; + var incomingCall; if (this.props.isIncomingCallRoom) { - const IncomingCallBox = sdk.getComponent("voip.IncomingCallBox"); + var IncomingCallBox = sdk.getComponent("voip.IncomingCallBox"); incomingCall = <IncomingCallBox className="mx_RoomSubList_incomingCall" incomingCall={ this.props.incomingCall }/>; } @@ -104,7 +109,6 @@ module.exports = React.createClass({ <div className="mx_RoomSubList_labelContainer" title={ title } ref="header"> <AccessibleButton onClick={ this.props.onClick } className="mx_RoomSubList_label" tabIndex="0"> { this.props.collapsed ? '' : this.props.label } - {this.props.headerItems} <div className="mx_RoomSubList_roomCount">{ roomCount }</div> <div className={chevronClasses}></div> { badge } diff --git a/src/skins/vector/css/_components.scss b/src/skins/vector/css/_components.scss index 5b23bb82..df3c4600 100644 --- a/src/skins/vector/css/_components.scss +++ b/src/skins/vector/css/_components.scss @@ -27,7 +27,6 @@ @import "./matrix-react-sdk/views/elements/_MemberEventListSummary.scss"; @import "./matrix-react-sdk/views/elements/_ProgressBar.scss"; @import "./matrix-react-sdk/views/elements/_RichText.scss"; -@import "./matrix-react-sdk/views/elements/_RoleButton.scss"; @import "./matrix-react-sdk/views/login/_InteractiveAuthEntryComponents.scss"; @import "./matrix-react-sdk/views/login/_ServerConfig.scss"; @import "./matrix-react-sdk/views/messages/_MEmoteBody.scss"; diff --git a/src/skins/vector/css/matrix-react-sdk/views/elements/_RoleButton.scss b/src/skins/vector/css/matrix-react-sdk/views/elements/_RoleButton.scss deleted file mode 100644 index 094e0b9b..00000000 --- a/src/skins/vector/css/matrix-react-sdk/views/elements/_RoleButton.scss +++ /dev/null @@ -1,33 +0,0 @@ -/* -Copyright 2107 Vector Creations Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -.mx_RoleButton { - margin-left: 4px; - margin-right: 4px; - cursor: pointer; - display: inline-block; -} - -.mx_RoleButton object { - pointer-events: none; -} - -.mx_RoleButton_tooltip { - display: inline-block; - position: relative; - top: -25px; - left: 6px; -} diff --git a/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomList.scss b/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomList.scss index 35787ca0..110dcd5b 100644 --- a/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomList.scss +++ b/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomList.scss @@ -1,6 +1,5 @@ /* Copyright 2015, 2016 OpenMarket Ltd -Copyright 2107 Vector Creations Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -38,25 +37,3 @@ limitations under the License. .mx_RoomList_scrollbar .gm-scrollbar.-vertical { z-index: 6; } - -.mx_RoomList_emptySubListTip { - font-size: 13px; - margin-left: 18px; - margin-right: 18px; - margin-top: 8px; - margin-bottom: 7px; - padding: 5px; - border: 1px dashed $accent-color; - color: $primary-fg-color; - background-color: $droptarget-bg-color; - border-radius: 4px; -} - -.mx_RoomList_emptySubListTip .mx_RoleButton { - vertical-align: -3px; -} - -.mx_RoomList_headerButtons { - position: absolute; - right: 60px; -} diff --git a/src/skins/vector/css/vector-web/structures/_LeftPanel.scss b/src/skins/vector/css/vector-web/structures/_LeftPanel.scss index f171591c..d3bbce1b 100644 --- a/src/skins/vector/css/vector-web/structures/_LeftPanel.scss +++ b/src/skins/vector/css/vector-web/structures/_LeftPanel.scss @@ -64,25 +64,43 @@ limitations under the License. pointer-events: none; } -.collapsed .mx_RoleButton { +.mx_LeftPanel .mx_BottomLeftMenu_homePage, +.mx_LeftPanel .mx_BottomLeftMenu_directory, +.mx_LeftPanel .mx_BottomLeftMenu_createRoom, +.mx_LeftPanel .mx_BottomLeftMenu_people, +.mx_LeftPanel .mx_BottomLeftMenu_settings { + display: inline-block; + cursor: pointer; +} + +.collapsed .mx_BottomLeftMenu_homePage, +.collapsed .mx_BottomLeftMenu_directory, +.collapsed .mx_BottomLeftMenu_createRoom, +.collapsed .mx_BottomLeftMenu_people, +.collapsed .mx_BottomLeftMenu_settings { margin-right: 0px ! important; padding-top: 3px ! important; padding-bottom: 3px ! important; } -.mx_BottomLeftMenu_options .mx_RoleButton { - margin-left: 0px; +.mx_LeftPanel .mx_BottomLeftMenu_homePage, +.mx_LeftPanel .mx_BottomLeftMenu_directory, +.mx_LeftPanel .mx_BottomLeftMenu_createRoom, +.mx_LeftPanel .mx_BottomLeftMenu_people { margin-right: 10px; } -.mx_BottomLeftMenu_options .mx_BottomLeftMenu_settings { +.mx_LeftPanel .mx_BottomLeftMenu_settings { float: right; } -.mx_BottomLeftMenu_options .mx_BottomLeftMenu_settings .mx_RoleButton { - margin-right: 0px; -} - .mx_LeftPanel.collapsed .mx_BottomLeftMenu_settings { float: none; } + +.mx_LeftPanel .mx_BottomLeftMenu_tooltip { + display: inline-block; + position: relative; + top: -25px; + left: 6px; +} From 03476705b1cccf03070bdc55af5139450dd1c1cc Mon Sep 17 00:00:00 2001 From: David Baker <dave@matrix.org> Date: Tue, 16 May 2017 16:35:06 +0100 Subject: [PATCH 2/6] Revert "better solution to incomingcallbox weirdness" This reverts commit be527874730d959fa980e81c897a658a03952aad. --- src/components/structures/RoomSubListHeader.js | 2 +- .../css/matrix-react-sdk/views/voip/_IncomingCallbox.scss | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/structures/RoomSubListHeader.js b/src/components/structures/RoomSubListHeader.js index ad9aff5f..eb73f721 100644 --- a/src/components/structures/RoomSubListHeader.js +++ b/src/components/structures/RoomSubListHeader.js @@ -112,8 +112,8 @@ module.exports = React.createClass({ <div className="mx_RoomSubList_roomCount">{ roomCount }</div> <div className={chevronClasses}></div> { badge } + { incomingCall } </AccessibleButton> - { incomingCall } </div> ); }, diff --git a/src/skins/vector/css/matrix-react-sdk/views/voip/_IncomingCallbox.scss b/src/skins/vector/css/matrix-react-sdk/views/voip/_IncomingCallbox.scss index 64eac25d..e63814f5 100644 --- a/src/skins/vector/css/matrix-react-sdk/views/voip/_IncomingCallbox.scss +++ b/src/skins/vector/css/matrix-react-sdk/views/voip/_IncomingCallbox.scss @@ -25,6 +25,8 @@ limitations under the License. margin-top: -3px; margin-left: -20px; width: 200px; + font-weight: initial; + text-transform: initial; } .mx_IncomingCallBox_chevron { From 9399b7ddf0cf7b272e527b9086fc6fe68db2e66d Mon Sep 17 00:00:00 2001 From: David Baker <dave@matrix.org> Date: Tue, 16 May 2017 16:35:17 +0100 Subject: [PATCH 3/6] Revert "fix incoming call box" This reverts commit b3431bb75008b068a2a1805803b91d0ff2616571. --- src/components/structures/RoomSubList.js | 1 - src/components/structures/RoomSubListHeader.js | 1 - .../vector/css/matrix-react-sdk/structures/_RoomView.scss | 4 ++-- .../css/matrix-react-sdk/views/voip/_IncomingCallbox.scss | 2 -- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index c315ae46..f741a30f 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -516,7 +516,6 @@ var RoomSubList = React.createClass({ roomCount={ roomCount } collapsed={ this.props.collapsed } hidden={ this.state.hidden } - incomingCall={ this.props.incomingCall } isIncomingCallRoom={ isIncomingCallRoom } roomNotificationCount={ this.roomNotificationCount() } onClick={ this.onClick } diff --git a/src/components/structures/RoomSubListHeader.js b/src/components/structures/RoomSubListHeader.js index eb73f721..5618b39b 100644 --- a/src/components/structures/RoomSubListHeader.js +++ b/src/components/structures/RoomSubListHeader.js @@ -36,7 +36,6 @@ module.exports = React.createClass({ React.PropTypes.number ]), collapsed: React.PropTypes.bool.isRequired, // is LeftPanel collapsed? - incomingCall: React.PropTypes.object, isIncomingCallRoom: React.PropTypes.bool, roomNotificationCount: React.PropTypes.array, hidden: React.PropTypes.bool, diff --git a/src/skins/vector/css/matrix-react-sdk/structures/_RoomView.scss b/src/skins/vector/css/matrix-react-sdk/structures/_RoomView.scss index e251ecd1..3d5fe029 100644 --- a/src/skins/vector/css/matrix-react-sdk/structures/_RoomView.scss +++ b/src/skins/vector/css/matrix-react-sdk/structures/_RoomView.scss @@ -172,7 +172,7 @@ hr.mx_RoomView_myReadMarker { max-height: 0px; background-color: $primary-bg-color; - z-index: 5; + z-index: 1000; overflow: hidden; -webkit-transition: all .2s ease-out; @@ -260,4 +260,4 @@ hr.mx_RoomView_myReadMarker { .mx_RoomView_ongoingConfCallNotification a { color: $accent-fg-color ! important; -} +} \ No newline at end of file diff --git a/src/skins/vector/css/matrix-react-sdk/views/voip/_IncomingCallbox.scss b/src/skins/vector/css/matrix-react-sdk/views/voip/_IncomingCallbox.scss index e63814f5..64eac25d 100644 --- a/src/skins/vector/css/matrix-react-sdk/views/voip/_IncomingCallbox.scss +++ b/src/skins/vector/css/matrix-react-sdk/views/voip/_IncomingCallbox.scss @@ -25,8 +25,6 @@ limitations under the License. margin-top: -3px; margin-left: -20px; width: 200px; - font-weight: initial; - text-transform: initial; } .mx_IncomingCallBox_chevron { From fdf326c9f0651c9766d55bc5aeddd60d5e0372d1 Mon Sep 17 00:00:00 2001 From: David Baker <dave@matrix.org> Date: Tue, 16 May 2017 17:13:39 +0100 Subject: [PATCH 4/6] Revert "Cancel quick-search on Escape, clearing it and returning focus to composer." This reverts commit 52a119244b2ff221c32c082166e77f9913833573. --- src/components/structures/SearchBox.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js index d0868b69..d79617c0 100644 --- a/src/components/structures/SearchBox.js +++ b/src/components/structures/SearchBox.js @@ -100,10 +100,6 @@ module.exports = React.createClass({ } switch (ev.keyCode) { - case KeyCode.ESCAPE: - this._clearSearch(); - dis.dispatch({action: 'focus_composer'}); - break; case KeyCode.KEY_K: if (ctrlCmdOnly) { if (this.refs.search) { From 844ea390c87eab83c9f287313d32e727c958a6fb Mon Sep 17 00:00:00 2001 From: David Baker <dave@matrix.org> Date: Tue, 16 May 2017 17:13:55 +0100 Subject: [PATCH 5/6] Revert "clear the searchbox after quick-search" This reverts commit ddd12edc064bdd81fffbad941e199eaa065e3ae0. --- src/components/structures/RoomSubList.js | 3 +-- src/components/structures/SearchBox.js | 6 +++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index f741a30f..a1291eeb 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -165,11 +165,10 @@ var RoomSubList = React.createClass({ } }, - onRoomTileClick(roomId, ev) { + onRoomTileClick(roomId) { dis.dispatch({ action: 'view_room', room_id: roomId, - clear_search: (ev && (ev.keyCode == 13 || ev.keyCode == 32)), }); }, diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js index d79617c0..a3848dcc 100644 --- a/src/components/structures/SearchBox.js +++ b/src/components/structures/SearchBox.js @@ -48,14 +48,18 @@ module.exports = React.createClass({ }, onAction: function(payload) { + // Disabling this as I find it really really annoying, and was used to the + // previous behaviour - see https://github.com/vector-im/riot-web/issues/3348 +/* switch (payload.action) { // Clear up the text field when a room is selected. case 'view_room': - if (payload.clear_search && this.refs.search) { + if (this.refs.search) { this._clearSearch(); } break; } +*/ }, onChange: function() { From 9fc9de3af53e6457a6f83e1305c1f2247ab95421 Mon Sep 17 00:00:00 2001 From: David Baker <dave@matrix.org> Date: Tue, 16 May 2017 17:21:49 +0100 Subject: [PATCH 6/6] Revert "Merge pull request #3654 from vector-im/matthew/quick-search" This reverts commit 8f20fcfa6b6828421d1278b169df663e80d2a743, reversing changes made to 751f715e77a73fa704298dd1dbad0035eb7a75e8. --- package.json | 3 +- src/components/structures/LeftPanel.js | 94 +---------- src/components/structures/RoomSubList.js | 147 ++++++++++-------- .../structures/RoomSubListHeader.js | 120 -------------- src/components/structures/SearchBox.js | 31 ---- 5 files changed, 86 insertions(+), 309 deletions(-) delete mode 100644 src/components/structures/RoomSubListHeader.js diff --git a/package.json b/package.json index a1f06b00..644e9309 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "favico.js": "^0.3.10", "filesize": "3.5.6", "flux": "~2.0.3", + "gemini-scrollbar": "matrix-org/gemini-scrollbar#b302279", "gfm.css": "^1.1.1", "highlight.js": "^9.0.0", "linkifyjs": "^2.1.3", @@ -73,7 +74,7 @@ "react-dnd": "^2.1.4", "react-dnd-html5-backend": "^2.1.2", "react-dom": "^15.4.0", - "react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#39d858c", + "react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#5e97aef", "sanitize-html": "^1.11.1", "ua-parser-js": "^0.7.10", "url": "^0.11.0" diff --git a/src/components/structures/LeftPanel.js b/src/components/structures/LeftPanel.js index 2d97313a..a9df37a8 100644 --- a/src/components/structures/LeftPanel.js +++ b/src/components/structures/LeftPanel.js @@ -19,11 +19,9 @@ limitations under the License. var React = require('react'); var DragDropContext = require('react-dnd').DragDropContext; var HTML5Backend = require('react-dnd-html5-backend'); -var KeyCode = require('matrix-react-sdk/lib/KeyCode'); var sdk = require('matrix-react-sdk') var dis = require('matrix-react-sdk/lib/dispatcher'); - var VectorConferenceHandler = require('../../VectorConferenceHandler'); var CallHandler = require("matrix-react-sdk/lib/CallHandler"); @@ -42,10 +40,6 @@ var LeftPanel = React.createClass({ }; }, - componentWillMount: function() { - this.focusedElement = null; - }, - componentDidMount: function() { this.dispatcherRef = dis.register(this.onAction); }, @@ -68,91 +62,6 @@ var LeftPanel = React.createClass({ } }, - _onFocus: function(ev) { - this.focusedElement = ev.target; - }, - - _onBlur: function(ev) { - this.focusedElement = null; - }, - - _onKeyDown: function(ev) { - if (!this.focusedElement) return; - let handled = false; - - switch (ev.keyCode) { - case KeyCode.UP: - this._onMoveFocus(true); - handled = true; - break; - case KeyCode.DOWN: - this._onMoveFocus(false); - handled = true; - break; - } - - if (handled) { - ev.stopPropagation(); - ev.preventDefault(); - } - }, - - _onMoveFocus: function(up) { - var element = this.focusedElement; - - // unclear why this isn't needed - // var descending = (up == this.focusDirection) ? this.focusDescending : !this.focusDescending; - // this.focusDirection = up; - - var descending = false; // are we currently descending or ascending through the DOM tree? - var classes; - - do { - var child = up ? element.lastElementChild : element.firstElementChild; - var sibling = up ? element.previousElementSibling : element.nextElementSibling; - - if (descending) { - if (child) { - element = child; - } - else if (sibling) { - element = sibling; - } - else { - descending = false; - element = element.parentElement; - } - } - else { - if (sibling) { - element = sibling; - descending = true; - } - else { - element = element.parentElement; - } - } - - if (element) { - classes = element.classList; - if (classes.contains("mx_LeftPanel")) { // we hit the top - element = up ? element.lastElementChild : element.firstElementChild; - descending = true; - } - } - - } while(element && !( - classes.contains("mx_RoomTile") || - classes.contains("mx_SearchBox_search") || - classes.contains("mx_RoomSubList_ellipsis"))); - - if (element) { - element.focus(); - this.focusedElement = element; - this.focusedDescending = descending; - } - }, - _recheckCallElement: function(selectedRoomId) { // if we aren't viewing a room with an ongoing call, but there is an // active call, show the call element - we need to do this to make @@ -211,8 +120,7 @@ var LeftPanel = React.createClass({ } return ( - <aside className={classes} style={{ opacity: this.props.opacity }} - onKeyDown={ this._onKeyDown } onFocus={ this._onFocus } onBlur={ this._onBlur }> + <aside className={classes} style={{ opacity: this.props.opacity }}> <SearchBox collapsed={ this.props.collapsed } onSearch={ this.onSearch } /> { collapseButton } { callPreview } diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index a1291eeb..6490e456 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -27,11 +27,9 @@ var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs'); var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils'); var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); -var ConstantTimeDispatcher = require('matrix-react-sdk/lib/ConstantTimeDispatcher'); -var RoomSubListHeader = require('./RoomSubListHeader.js'); import Modal from 'matrix-react-sdk/lib/Modal'; -// turn this on for drag & drop console debugging galore +// turn this on for drop & drag console debugging galore var debug = false; const TRUNCATE_AT = 10; @@ -74,12 +72,14 @@ var RoomSubList = React.createClass({ order: React.PropTypes.string.isRequired, + // undefined if no room is selected (eg we are showing settings) + selectedRoom: React.PropTypes.string, + startAsHidden: React.PropTypes.bool, showSpinner: React.PropTypes.bool, // true to show a spinner if 0 elements when expanded collapsed: React.PropTypes.bool.isRequired, // is LeftPanel collapsed? onHeaderClick: React.PropTypes.func, alwaysShowHeader: React.PropTypes.bool, - selectedRoom: React.PropTypes.string, incomingCall: React.PropTypes.object, onShowMoreRooms: React.PropTypes.func, searchFilter: React.PropTypes.string, @@ -101,31 +101,13 @@ var RoomSubList = React.createClass({ }, componentWillMount: function() { - constantTimeDispatcher.register("RoomSubList.sort", this.props.tagName, this.onSort); - constantTimeDispatcher.register("RoomSubList.refreshHeader", this.props.tagName, this.onRefresh); this.sortList(this.applySearchFilter(this.props.list, this.props.searchFilter), this.props.order); - this._fixUndefinedOrder(this.props.list); - }, - - componentWillUnmount: function() { - constantTimeDispatcher.unregister("RoomSubList.sort", this.props.tagName, this.onSort); - constantTimeDispatcher.unregister("RoomSubList.refreshHeader", this.props.tagName, this.onRefresh); }, componentWillReceiveProps: function(newProps) { // order the room list appropriately before we re-render //if (debug) console.log("received new props, list = " + newProps.list); this.sortList(this.applySearchFilter(newProps.list, newProps.searchFilter), newProps.order); - this._fixUndefinedOrder(newProps.list); - }, - - onSort: function() { - this.sortList(this.applySearchFilter(this.props.list, this.props.searchFilter), this.props.order); - // we deliberately don't waste time trying to fix undefined ordering here - }, - - onRefresh: function() { - this.forceUpdate(); }, applySearchFilter: function(list, filter) { @@ -138,7 +120,7 @@ var RoomSubList = React.createClass({ // The header is collapsable if it is hidden or not stuck // The dataset elements are added in the RoomList _initAndPositionStickyHeaders method isCollapsableOnClick: function() { - var stuck = this.refs.header.refs.header.dataset.stuck; + var stuck = this.refs.header.dataset.stuck; if (this.state.hidden || stuck === undefined || stuck === "none") { return true; } else { @@ -161,7 +143,7 @@ var RoomSubList = React.createClass({ this.props.onHeaderClick(isHidden); } else { // The header is stuck, so the click is to be interpreted as a scroll to the header - this.props.onHeaderClick(this.state.hidden, this.refs.header.refs.header.dataset.originalPosition); + this.props.onHeaderClick(this.state.hidden, this.refs.header.dataset.originalPosition); } }, @@ -230,6 +212,9 @@ var RoomSubList = React.createClass({ if (order === "manual") comparator = this.manualComparator; if (order === "recent") comparator = this.recentsComparator; + // Fix undefined orders here, and make sure the backend gets updated as well + this._fixUndefinedOrder(list); + //if (debug) console.log("sorting list for sublist " + this.props.label + " with length " + list.length + ", this.props.list = " + this.props.list); this.setState({ sortedList: list.sort(comparator) }); }, @@ -264,9 +249,10 @@ var RoomSubList = React.createClass({ if (badges) { result[0] += notificationCount; + if (highlight) { + result[1] = true; + } } - - result[1] |= highlight; } return result; }, [0, false]); @@ -374,6 +360,7 @@ var RoomSubList = React.createClass({ var self = this; var DNDRoomTile = sdk.getComponent("rooms.DNDRoomTile"); return this.state.sortedList.map(function(room) { + var selected = room.roomId == self.props.selectedRoom; // XXX: is it evil to pass in self as a prop to RoomTile? return ( <DNDRoomTile @@ -381,7 +368,9 @@ var RoomSubList = React.createClass({ roomSubList={ self } key={ room.roomId } collapsed={ self.props.collapsed || false} - selectedRoom={ self.props.selectedRoom } + selected={ selected } + unread={ Unread.doesRoomHaveUnreadMessages(room) } + highlight={ room.getUnreadNotificationCount('highlight') > 0 || self.props.label === 'Invites' } isInvite={ self.props.label === 'Invites' } refreshSubList={ self._updateSubListCount } incomingCall={ null } @@ -391,6 +380,70 @@ var RoomSubList = React.createClass({ }); }, + _getHeaderJsx: function() { + var TintableSvg = sdk.getComponent("elements.TintableSvg"); + + var subListNotifications = this.roomNotificationCount(); + var subListNotifCount = subListNotifications[0]; + var subListNotifHighlight = subListNotifications[1]; + + var roomCount = this.props.list.length > 0 ? this.props.list.length : ''; + + var chevronClasses = classNames({ + 'mx_RoomSubList_chevron': true, + 'mx_RoomSubList_chevronRight': this.state.hidden, + 'mx_RoomSubList_chevronDown': !this.state.hidden, + }); + + var badgeClasses = classNames({ + 'mx_RoomSubList_badge': true, + 'mx_RoomSubList_badgeHighlight': subListNotifHighlight, + }); + + var badge; + if (subListNotifCount > 0) { + badge = <div className={badgeClasses}>{ FormattingUtils.formatCount(subListNotifCount) }</div>; + } + + // When collapsed, allow a long hover on the header to show user + // the full tag name and room count + var title; + if (this.props.collapsed) { + title = this.props.label; + if (roomCount !== '') { + title += " [" + roomCount + "]"; + } + } + + var incomingCall; + if (this.props.incomingCall) { + var self = this; + // Check if the incoming call is for this section + var incomingCallRoom = this.props.list.filter(function(room) { + return self.props.incomingCall.roomId === room.roomId; + }); + + if (incomingCallRoom.length === 1) { + var IncomingCallBox = sdk.getComponent("voip.IncomingCallBox"); + incomingCall = <IncomingCallBox className="mx_RoomSubList_incomingCall" incomingCall={ this.props.incomingCall }/>; + } + } + + var tabindex = this.props.searchFilter === "" ? "0" : "-1"; + + return ( + <div className="mx_RoomSubList_labelContainer" title={ title } ref="header"> + <AccessibleButton onClick={ this.onClick } className="mx_RoomSubList_label" tabIndex={tabindex}> + { this.props.collapsed ? '' : this.props.label } + <div className="mx_RoomSubList_roomCount">{ roomCount }</div> + <div className={chevronClasses}></div> + { badge } + { incomingCall } + </AccessibleButton> + </div> + ); + }, + _createOverflowTile: function(overflowCount, totalCount) { var content = <div className="mx_RoomSubList_chevronDown"></div>; @@ -446,7 +499,7 @@ var RoomSubList = React.createClass({ // gets triggered and another list is passed in. Doing it one at a time means that // we always correctly calculate the highest order for the list - stops multiple // rooms getting the same order. This is only really relevant for the first time this - // is run with historical room tag data, after that there should only be one undefined + // is run with historical room tag data, after that there should only be undefined // in the list at a time anyway. for (let i = 0; i < list.length; i++) { if (list[i].tags[self.props.tagName] && list[i].tags[self.props.tagName].order === undefined) { @@ -480,16 +533,6 @@ var RoomSubList = React.createClass({ target = <RoomDropTarget label={ 'Drop here to ' + this.props.verb }/>; } - var roomCount = this.props.list.length > 0 ? this.props.list.length : ''; - - var isIncomingCallRoom; - if (this.props.incomingCall) { - // Check if the incoming call is for this section - isIncomingCallRoom = this.props.list.find(room=>{ - return this.props.incomingCall.roomId === room.roomId; - }) ? true : false; - } - if (this.state.sortedList.length > 0 || this.props.editable) { var subList; var classes = "mx_RoomSubList"; @@ -508,18 +551,7 @@ var RoomSubList = React.createClass({ return connectDropTarget( <div> - <RoomSubListHeader - ref='header' - label={ this.props.label } - tagName={ this.props.tagName } - roomCount={ roomCount } - collapsed={ this.props.collapsed } - hidden={ this.state.hidden } - isIncomingCallRoom={ isIncomingCallRoom } - roomNotificationCount={ this.roomNotificationCount() } - onClick={ this.onClick } - onHeaderClick={ this.props.onHeaderClick } - /> + { this._getHeaderJsx() } { subList } </div> ); @@ -528,20 +560,7 @@ var RoomSubList = React.createClass({ var Loader = sdk.getComponent("elements.Spinner"); return ( <div className="mx_RoomSubList"> - { this.props.alwaysShowHeader ? - <RoomSubListHeader - ref='header' - label={ this.props.label } - tagName={ this.props.tagName } - roomCount={ roomCount } - collapsed={ this.props.collapsed } - hidden={ this.state.hidden } - isIncomingCallRoom={ isIncomingCallRoom } - roomNotificationCount={ this.roomNotificationCount() } - onClick={ this.onClick } - onHeaderClick={ this.props.onHeaderClick } - /> - : undefined } + { this.props.alwaysShowHeader ? this._getHeaderJsx() : undefined } { (this.props.showSpinner && !this.state.hidden) ? <Loader /> : undefined } </div> ); diff --git a/src/components/structures/RoomSubListHeader.js b/src/components/structures/RoomSubListHeader.js deleted file mode 100644 index 5618b39b..00000000 --- a/src/components/structures/RoomSubListHeader.js +++ /dev/null @@ -1,120 +0,0 @@ -/* -Copyright 2017 Vector Creations Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -var React = require('react'); -var ReactDOM = require('react-dom'); -var classNames = require('classnames'); -var sdk = require('matrix-react-sdk') -var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils'); -var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs'); -var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); -var ConstantTimeDispatcher = require('matrix-react-sdk/lib/ConstantTimeDispatcher'); - -module.exports = React.createClass({ - displayName: 'RoomSubListHeader', - - propTypes: { - label: React.PropTypes.string.isRequired, - tagName: React.PropTypes.string, - roomCount: React.PropTypes.oneOfType([ - React.PropTypes.string, - React.PropTypes.number - ]), - collapsed: React.PropTypes.bool.isRequired, // is LeftPanel collapsed? - isIncomingCallRoom: React.PropTypes.bool, - roomNotificationCount: React.PropTypes.array, - hidden: React.PropTypes.bool, - onClick: React.PropTypes.func, - onHeaderClick: React.PropTypes.func, - }, - - getDefaultProps: function() { - return { - onHeaderClick: function() {}, // NOP - }; - }, - - componentWillMount: function() { - // constantTimeDispatcher.register("RoomSubList.refreshHeader", this.props.tagName, this.onRefresh); - }, - - componentWillUnmount: function() { - // constantTimeDispatcher.unregister("RoomSubList.refreshHeader", this.props.tagName, this.onRefresh); - }, - - // onRefresh: function() { - // this.forceUpdate(); - // }, - - render: function() { - var TintableSvg = sdk.getComponent("elements.TintableSvg"); - - var subListNotifications = this.props.roomNotificationCount; - var subListNotifCount = subListNotifications[0]; - var subListNotifHighlight = subListNotifications[1]; - - var chevronClasses = classNames({ - 'mx_RoomSubList_chevron': true, - 'mx_RoomSubList_chevronRight': this.props.hidden, - 'mx_RoomSubList_chevronDown': !this.props.hidden, - }); - - var badgeClasses = classNames({ - 'mx_RoomSubList_badge': true, - 'mx_RoomSubList_badgeHighlight': subListNotifHighlight, - }); - - var badge; - if (subListNotifCount > 0) { - badge = <div className={badgeClasses}>{ FormattingUtils.formatCount(subListNotifCount) }</div>; - } - else if (subListNotifHighlight) { - badge = <div className={badgeClasses}>!</div>; - } - - // When collapsed, allow a long hover on the header to show user - // the full tag name and room count - var title; - var roomCount = this.props.roomCount; - if (this.props.collapsed) { - title = this.props.label; - if (roomCount !== '') { - title += " [" + roomCount + "]"; - } - } - - var incomingCall; - if (this.props.isIncomingCallRoom) { - var IncomingCallBox = sdk.getComponent("voip.IncomingCallBox"); - incomingCall = <IncomingCallBox className="mx_RoomSubList_incomingCall" incomingCall={ this.props.incomingCall }/>; - } - - return ( - <div className="mx_RoomSubList_labelContainer" title={ title } ref="header"> - <AccessibleButton onClick={ this.props.onClick } className="mx_RoomSubList_label" tabIndex="0"> - { this.props.collapsed ? '' : this.props.label } - <div className="mx_RoomSubList_roomCount">{ roomCount }</div> - <div className={chevronClasses}></div> - { badge } - { incomingCall } - </AccessibleButton> - </div> - ); - }, -}); - diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js index a3848dcc..729e7ef7 100644 --- a/src/components/structures/SearchBox.js +++ b/src/components/structures/SearchBox.js @@ -21,7 +21,6 @@ var sdk = require('matrix-react-sdk') var dis = require('matrix-react-sdk/lib/dispatcher'); var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc'); var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); -var KeyCode = require('matrix-react-sdk/lib/KeyCode'); module.exports = React.createClass({ displayName: 'SearchBox', @@ -39,12 +38,10 @@ module.exports = React.createClass({ componentDidMount: function() { this.dispatcherRef = dis.register(this.onAction); - document.addEventListener('keydown', this._onKeyDown); }, componentWillUnmount: function() { dis.unregister(this.dispatcherRef); - document.removeEventListener('keydown', this._onKeyDown); }, onAction: function(payload) { @@ -93,34 +90,6 @@ module.exports = React.createClass({ this.onChange(); }, - _onKeyDown: function(ev) { - let handled = false; - const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; - let ctrlCmdOnly; - if (isMac) { - ctrlCmdOnly = ev.metaKey && !ev.altKey && !ev.ctrlKey && !ev.shiftKey; - } else { - ctrlCmdOnly = ev.ctrlKey && !ev.altKey && !ev.metaKey && !ev.shiftKey; - } - - switch (ev.keyCode) { - case KeyCode.KEY_K: - if (ctrlCmdOnly) { - if (this.refs.search) { - this.refs.search.focus(); - this.refs.search.select(); - } - handled = true; - } - break; - } - - if (handled) { - ev.stopPropagation(); - ev.preventDefault(); - } - }, - render: function() { var TintableSvg = sdk.getComponent('elements.TintableSvg');