From 43578d23664368cc63201ae89317fd68465dd00e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 28 Nov 2017 22:16:53 +0000 Subject: [PATCH 01/15] make FilteredList controlled, such that it can externally persist filter Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../views/dialogs/DevtoolsDialog.js | 87 +++++++++++++------ 1 file changed, 60 insertions(+), 27 deletions(-) diff --git a/src/components/views/dialogs/DevtoolsDialog.js b/src/components/views/dialogs/DevtoolsDialog.js index a7155ad12d..85ab40292d 100644 --- a/src/components/views/dialogs/DevtoolsDialog.js +++ b/src/components/views/dialogs/DevtoolsDialog.js @@ -244,6 +244,8 @@ class SendAccountData extends GenericEditor { class FilteredList extends React.Component { static propTypes = { children: PropTypes.any, + query: PropTypes.string, + onChange: PropTypes.func, }; constructor(props, context) { @@ -251,12 +253,17 @@ class FilteredList extends React.Component { this.onQuery = this.onQuery.bind(this); this.state = { - query: '', + query: this.props.query, }; } + componentWillReceiveProps(nextProps) { + if (this.state.query !== nextProps.query) this.setState({ query: nextProps.query }); + } + onQuery(ev) { this.setState({ query: ev.target.value }); + if (this.props.onChange) this.props.onChange(ev.target.value); } filterChildren() { @@ -295,11 +302,16 @@ class RoomStateExplorer extends DevtoolsComponent { this.onBack = this.onBack.bind(this); this.editEv = this.editEv.bind(this); + this.onQueryEventType = this.onQueryEventType.bind(this); + this.onQueryStateKey = this.onQueryStateKey.bind(this); this.state = { eventType: null, event: null, editing: false, + + queryEventType: '', + queryStateKey: '', }; } @@ -331,6 +343,14 @@ class RoomStateExplorer extends DevtoolsComponent { this.setState({ editing: true }); } + onQueryEventType(filterEventType) { + this.setState({ queryEventType: filterEventType }); + } + + onQueryStateKey(filterStateKey) { + this.setState({ queryStateKey: filterStateKey }); + } + render() { if (this.state.event) { if (this.state.editing) { @@ -352,41 +372,47 @@ class RoomStateExplorer extends DevtoolsComponent { ; } - const rows = []; + let list = null; const classes = 'mx_DevTools_RoomStateExplorer_button'; if (this.state.eventType === null) { - Object.keys(this.roomStateEvents).forEach((evType) => { - const stateGroup = this.roomStateEvents[evType]; - const stateKeys = Object.keys(stateGroup); + list = + { + Object.keys(this.roomStateEvents).map((evType) => { + const stateGroup = this.roomStateEvents[evType]; + const stateKeys = Object.keys(stateGroup); - let onClickFn; - if (stateKeys.length > 1) { - onClickFn = this.browseEventType(evType); - } else if (stateKeys.length === 1) { - onClickFn = this.onViewSourceClick(stateGroup[stateKeys[0]]); + let onClickFn; + if (stateKeys.length > 1) { + onClickFn = this.browseEventType(evType); + } else if (stateKeys.length === 1) { + onClickFn = this.onViewSourceClick(stateGroup[stateKeys[0]]); + } + + return ; + }) } - - rows.push(); - }); + ; } else { - const evType = this.state.eventType; - const stateGroup = this.roomStateEvents[evType]; - Object.keys(stateGroup).forEach((stateKey) => { - const ev = stateGroup[stateKey]; - rows.push(); - }); + const stateGroup = this.roomStateEvents[this.state.eventType]; + + list = + { + Object.keys(stateGroup).map((stateKey) => { + const ev = stateGroup[stateKey]; + return ; + }) + } + ; } return
- - { rows } - + { list }
@@ -408,11 +434,14 @@ class AccountDataExplorer extends DevtoolsComponent { this.onBack = this.onBack.bind(this); this.editEv = this.editEv.bind(this); this._onChange = this._onChange.bind(this); + this.onQueryEventType = this.onQueryEventType.bind(this); this.state = { isRoomAccountData: false, event: null, editing: false, + + queryEventType: '', }; } @@ -448,6 +477,10 @@ class AccountDataExplorer extends DevtoolsComponent { this.setState({ editing: true }); } + onQueryEventType(queryEventType) { + this.setState({ queryEventType }); + } + render() { if (this.state.event) { if (this.state.editing) { @@ -482,7 +515,7 @@ class AccountDataExplorer extends DevtoolsComponent { return
- + { rows }
From 8a7477f50cba19d98d901007b87561a52a181382 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 20 Dec 2017 20:40:41 +0000 Subject: [PATCH 02/15] Highlight ViewSource and Devtools ViewSource Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/ViewSource.js | 15 +++--- .../views/dialogs/DevtoolsDialog.js | 9 +++- src/components/views/elements/Highlight.js | 51 +++++++++++++++++++ src/skins/vector/css/_components.scss | 1 + .../vector-web/views/elements/_Highlight.scss | 21 ++++++++ 5 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 src/components/views/elements/Highlight.js create mode 100644 src/skins/vector/css/vector-web/views/elements/_Highlight.scss diff --git a/src/components/structures/ViewSource.js b/src/components/structures/ViewSource.js index a0e198cecc..8f60ae886c 100644 --- a/src/components/structures/ViewSource.js +++ b/src/components/structures/ViewSource.js @@ -16,14 +16,17 @@ limitations under the License. 'use strict'; -var React = require('react'); +import React from 'react'; +import PropTypes from 'prop-types'; +import Highlight from '../views/elements/Highlight'; + module.exports = React.createClass({ displayName: 'ViewSource', propTypes: { - content: React.PropTypes.object.isRequired, - onFinished: React.PropTypes.func.isRequired, + content: PropTypes.object.isRequired, + onFinished: PropTypes.func.isRequired, }, componentDidMount: function() { @@ -45,9 +48,9 @@ module.exports = React.createClass({ render: function() { return (
-
-                    {JSON.stringify(this.props.content, null, 2)}
-                
+ + { JSON.stringify(this.props.content, null, 2) } +
); } diff --git a/src/components/views/dialogs/DevtoolsDialog.js b/src/components/views/dialogs/DevtoolsDialog.js index 5d9168f5c2..1b2af377c3 100644 --- a/src/components/views/dialogs/DevtoolsDialog.js +++ b/src/components/views/dialogs/DevtoolsDialog.js @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import sdk from 'matrix-react-sdk'; +import Highlight from '../elements/Highlight'; import { _t } from 'matrix-react-sdk/lib/languageHandler'; import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg'; @@ -343,7 +344,9 @@ class RoomStateExplorer extends DevtoolsComponent { return
-
{ JSON.stringify(this.state.event.event, null, 2) }
+ + { JSON.stringify(this.state.event.event, null, 2) } +
@@ -459,7 +462,9 @@ class AccountDataExplorer extends DevtoolsComponent { return
-
{ JSON.stringify(this.state.event.event, null, 2) }
+ + { JSON.stringify(this.state.event.event, null, 2) } +
diff --git a/src/components/views/elements/Highlight.js b/src/components/views/elements/Highlight.js new file mode 100644 index 0000000000..1251264e37 --- /dev/null +++ b/src/components/views/elements/Highlight.js @@ -0,0 +1,51 @@ +/* +Copyright 2017 Michael Telatynski <7t3chguy@gmail.com> + +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'; + +import React from 'react'; +import PropTypes from 'prop-types'; +import {highlightBlock} from 'highlight.js'; + +export default class Highlight extends React.Component { + static propTypes = { + className: PropTypes.string, + children: PropTypes.node, + }; + + constructor(props, context) { + super(props, context); + + this._ref = this._ref.bind(this); + } + + componentDidUpdate() { + if (this._el) highlightBlock(this._el); + } + + _ref(el) { + this._el = el; + this.componentDidUpdate(); + } + + render() { + const { className, children } = this.props; + + return
+            { children }
+        
; + } +} diff --git a/src/skins/vector/css/_components.scss b/src/skins/vector/css/_components.scss index 0dd6a1b1b7..c01a7dcf85 100644 --- a/src/skins/vector/css/_components.scss +++ b/src/skins/vector/css/_components.scss @@ -91,6 +91,7 @@ @import "./vector-web/views/dialogs/_SetEmailDialog.scss"; @import "./vector-web/views/dialogs/_SetPasswordDialog.scss"; @import "./vector-web/views/directory/_NetworkDropdown.scss"; +@import "./vector-web/views/elements/_Highlight.scss"; @import "./vector-web/views/elements/_ImageView.scss"; @import "./vector-web/views/elements/_InlineSpinner.scss"; @import "./vector-web/views/elements/_Spinner.scss"; diff --git a/src/skins/vector/css/vector-web/views/elements/_Highlight.scss b/src/skins/vector/css/vector-web/views/elements/_Highlight.scss new file mode 100644 index 0000000000..9b35844ffa --- /dev/null +++ b/src/skins/vector/css/vector-web/views/elements/_Highlight.scss @@ -0,0 +1,21 @@ +/* +Copyright 2017 Michael Telatynski <7t3chguy@gmail.com> + +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_Highlight { + /* inhibit hljs styling */ + background: none !important; + color: $light-fg-color !important; +} From 3788fde711d5d5a0f761c9b853000f5d1a4692bb Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 5 Jan 2018 23:16:21 +0000 Subject: [PATCH 03/15] Add a tooltip to members button and badge with actual count Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/RightPanel.js | 11 ++++++----- src/i18n/strings/en_EN.json | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index 2a19794fe0..778c01149f 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -266,6 +266,7 @@ module.exports = React.createClass({ let inviteGroup; let membersBadge; + let membersTitle = _t('Members'); if ((this.state.phase == this.Phase.RoomMemberList || this.state.phase === this.Phase.RoomMemberInfo) && this.props.roomId ) { @@ -273,10 +274,10 @@ module.exports = React.createClass({ const room = cli.getRoom(this.props.roomId); let userIsInRoom; if (room) { - membersBadge = formatCount(room.getJoinedMembers().length); - userIsInRoom = room.hasMembershipState( - this.context.matrixClient.credentials.userId, 'join', - ); + const numMembers = room.getJoinedMembers().length; + membersTitle = _t('%(numMembers)s Members', { numMembers }); + membersBadge =
{ formatCount(numMembers) }
; + userIsInRoom = room.hasMembershipState(this.context.matrixClient.credentials.userId, 'join'); } if (userIsInRoom) { @@ -298,7 +299,7 @@ module.exports = React.createClass({ let headerButtons = []; if (this.props.roomId) { headerButtons = [ - Date: Fri, 5 Jan 2018 23:19:43 +0000 Subject: [PATCH 04/15] delint Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/RightPanel.js | 58 ++++++++++++------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index 778c01149f..da1e711741 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -24,7 +24,7 @@ import sdk from 'matrix-react-sdk'; import dis from 'matrix-react-sdk/lib/dispatcher'; import { MatrixClient } from 'matrix-js-sdk'; import Analytics from 'matrix-react-sdk/lib/Analytics'; -import rate_limited_func from 'matrix-react-sdk/lib/ratelimitedfunc'; +import RateLimitedFunc from 'matrix-react-sdk/lib/ratelimitedfunc'; import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton'; import { showGroupInviteDialog, showGroupAddRoomDialog } from 'matrix-react-sdk/lib/GroupAddressPicker'; import GroupStoreCache from 'matrix-react-sdk/lib/stores/GroupStoreCache'; @@ -58,8 +58,8 @@ class HeaderButton extends React.Component {
{ this.props.badge ? this.props.badge :   }
- - { this.props.isHighlighted ?
:
} + + { this.props.isHighlighted ?
:
} ; } @@ -184,18 +184,17 @@ module.exports = React.createClass({ onRoomStateMember: function(ev, state, member) { // redraw the badge on the membership list - if (this.state.phase == this.Phase.RoomMemberList && member.roomId === this.props.roomId) { + if (this.state.phase === this.Phase.RoomMemberList && member.roomId === this.props.roomId) { this._delayedUpdate(); - } - else if (this.state.phase === this.Phase.RoomMemberInfo && member.roomId === this.props.roomId && + } else if (this.state.phase === this.Phase.RoomMemberInfo && member.roomId === this.props.roomId && member.userId === this.state.member.userId) { // refresh the member info (e.g. new power level) this._delayedUpdate(); } }, - _delayedUpdate: new rate_limited_func(function() { - this.forceUpdate(); + _delayedUpdate: new RateLimitedFunc(function() { + this.forceUpdate(); // eslint-disable-line babel/no-invalid-this }, 500), onAction: function(payload) { @@ -267,7 +266,7 @@ module.exports = React.createClass({ let membersBadge; let membersTitle = _t('Members'); - if ((this.state.phase == this.Phase.RoomMemberList || this.state.phase === this.Phase.RoomMemberInfo) + if ((this.state.phase === this.Phase.RoomMemberList || this.state.phase === this.Phase.RoomMemberInfo) && this.props.roomId ) { const cli = this.context.matrixClient; @@ -282,7 +281,7 @@ module.exports = React.createClass({ if (userIsInRoom) { inviteGroup = - +
@@ -293,7 +292,7 @@ module.exports = React.createClass({ const isPhaseGroup = [ this.Phase.GroupMemberInfo, - this.Phase.GroupMemberList + this.Phase.GroupMemberList, ].includes(this.state.phase); let headerButtons = []; @@ -337,54 +336,54 @@ module.exports = React.createClass({ // button on these 2 screens or you won't be able to re-expand the panel. headerButtons.push(
- +
, ); } let panel =
; if (!this.props.collapsed) { - if (this.props.roomId && this.state.phase == this.Phase.RoomMemberList) { + if (this.props.roomId && this.state.phase === this.Phase.RoomMemberList) { panel = ; - } else if (this.props.groupId && this.state.phase == this.Phase.GroupMemberList) { + } else if (this.props.groupId && this.state.phase === this.Phase.GroupMemberList) { panel = ; } else if (this.state.phase === this.Phase.GroupRoomList) { panel = ; - } else if (this.state.phase == this.Phase.RoomMemberInfo) { + } else if (this.state.phase === this.Phase.RoomMemberInfo) { panel = ; - } else if (this.state.phase == this.Phase.GroupMemberInfo) { + } else if (this.state.phase === this.Phase.GroupMemberInfo) { panel = ; - } else if (this.state.phase == this.Phase.GroupRoomInfo) { + } else if (this.state.phase === this.Phase.GroupRoomInfo) { panel = ; - } else if (this.state.phase == this.Phase.NotificationPanel) { + } else if (this.state.phase === this.Phase.NotificationPanel) { panel = ; - } else if (this.state.phase == this.Phase.FilePanel) { + } else if (this.state.phase === this.Phase.FilePanel) { panel = ; } } if (!panel) { - panel =
; + panel =
; } if (this.props.groupId && this.state.isUserPrivilegedInGroup) { inviteGroup = isPhaseGroup ? ( - +
{ _t('Invite to this community') }
) : ( - +
@@ -393,19 +392,16 @@ module.exports = React.createClass({ ); } - let classes = classNames( - "mx_RightPanel", "mx_fadable", - { - "collapsed": this.props.collapsed, - "mx_fadable_faded": this.props.disabled, - } - ); + const classes = classNames("mx_RightPanel", "mx_fadable", { + "collapsed": this.props.collapsed, + "mx_fadable_faded": this.props.disabled, + }); return (