Merge branch 'develop' into luke/perf-tag-panel-selected
This commit is contained in:
commit
7606e60188
9 changed files with 99 additions and 151 deletions
|
@ -68,3 +68,12 @@ export function isOnlyCtrlOrCmdKeyEvent(ev) {
|
||||||
return ev.ctrlKey && !ev.altKey && !ev.metaKey && !ev.shiftKey;
|
return ev.ctrlKey && !ev.altKey && !ev.metaKey && !ev.shiftKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isOnlyCtrlOrCmdIgnoreShiftKeyEvent(ev) {
|
||||||
|
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
||||||
|
if (isMac) {
|
||||||
|
return ev.metaKey && !ev.altKey && !ev.ctrlKey;
|
||||||
|
} else {
|
||||||
|
return ev.ctrlKey && !ev.altKey && !ev.metaKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -333,7 +333,6 @@ const LoggedInView = React.createClass({
|
||||||
<div className={bodyClasses}>
|
<div className={bodyClasses}>
|
||||||
{ SettingsStore.isFeatureEnabled("feature_tag_panel") ? <TagPanel /> : <div /> }
|
{ SettingsStore.isFeatureEnabled("feature_tag_panel") ? <TagPanel /> : <div /> }
|
||||||
<LeftPanel
|
<LeftPanel
|
||||||
selectedRoom={this.props.currentRoomId}
|
|
||||||
collapsed={this.props.collapseLhs || false}
|
collapsed={this.props.collapseLhs || false}
|
||||||
disabled={this.props.leftDisabled}
|
disabled={this.props.leftDisabled}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { MatrixClient } from 'matrix-js-sdk';
|
import { MatrixClient } from 'matrix-js-sdk';
|
||||||
import FilterStore from '../../stores/FilterStore';
|
|
||||||
import TagOrderStore from '../../stores/TagOrderStore';
|
import TagOrderStore from '../../stores/TagOrderStore';
|
||||||
|
|
||||||
import GroupActions from '../../actions/GroupActions';
|
import GroupActions from '../../actions/GroupActions';
|
||||||
|
@ -44,20 +43,13 @@ const TagPanel = React.createClass({
|
||||||
this.unmounted = false;
|
this.unmounted = false;
|
||||||
this.context.matrixClient.on("Group.myMembership", this._onGroupMyMembership);
|
this.context.matrixClient.on("Group.myMembership", this._onGroupMyMembership);
|
||||||
|
|
||||||
this._filterStoreToken = FilterStore.addListener(() => {
|
|
||||||
if (this.unmounted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
selectedTags: FilterStore.getSelectedTags(),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this._tagOrderStoreToken = TagOrderStore.addListener(() => {
|
this._tagOrderStoreToken = TagOrderStore.addListener(() => {
|
||||||
if (this.unmounted) {
|
if (this.unmounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
orderedTags: TagOrderStore.getOrderedTags() || [],
|
orderedTags: TagOrderStore.getOrderedTags() || [],
|
||||||
|
selectedTags: TagOrderStore.getSelectedTags(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// This could be done by anything with a matrix client
|
// This could be done by anything with a matrix client
|
||||||
|
|
|
@ -20,7 +20,7 @@ import classNames from 'classnames';
|
||||||
import { MatrixClient } from 'matrix-js-sdk';
|
import { MatrixClient } from 'matrix-js-sdk';
|
||||||
import sdk from '../../../index';
|
import sdk from '../../../index';
|
||||||
import dis from '../../../dispatcher';
|
import dis from '../../../dispatcher';
|
||||||
import { isOnlyCtrlOrCmdKeyEvent } from '../../../Keyboard';
|
import { isOnlyCtrlOrCmdIgnoreShiftKeyEvent } from '../../../Keyboard';
|
||||||
|
|
||||||
import FlairStore from '../../../stores/FlairStore';
|
import FlairStore from '../../../stores/FlairStore';
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ export default React.createClass({
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'select_tag',
|
action: 'select_tag',
|
||||||
tag: this.props.tag,
|
tag: this.props.tag,
|
||||||
ctrlOrCmdKey: isOnlyCtrlOrCmdKeyEvent(e),
|
ctrlOrCmdKey: isOnlyCtrlOrCmdIgnoreShiftKeyEvent(e),
|
||||||
shiftKey: e.shiftKey,
|
shiftKey: e.shiftKey,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -41,7 +41,6 @@ import AccessibleButton from '../elements/AccessibleButton';
|
||||||
import GeminiScrollbar from 'react-gemini-scrollbar';
|
import GeminiScrollbar from 'react-gemini-scrollbar';
|
||||||
import RoomViewStore from '../../../stores/RoomViewStore';
|
import RoomViewStore from '../../../stores/RoomViewStore';
|
||||||
|
|
||||||
|
|
||||||
module.exports = withMatrixClient(React.createClass({
|
module.exports = withMatrixClient(React.createClass({
|
||||||
displayName: 'MemberInfo',
|
displayName: 'MemberInfo',
|
||||||
|
|
||||||
|
@ -713,6 +712,10 @@ module.exports = withMatrixClient(React.createClass({
|
||||||
|
|
||||||
if (this.props.member.userId !== this.props.matrixClient.credentials.userId) {
|
if (this.props.member.userId !== this.props.matrixClient.credentials.userId) {
|
||||||
const dmRoomMap = new DMRoomMap(this.props.matrixClient);
|
const dmRoomMap = new DMRoomMap(this.props.matrixClient);
|
||||||
|
// dmRooms will not include dmRooms that we have been invited into but did not join.
|
||||||
|
// Because DMRoomMap runs off account_data[m.direct] which is only set on join of dm room.
|
||||||
|
// XXX: we potentially want DMs we have been invited to, to also show up here :L
|
||||||
|
// especially as logic below concerns specially if we haven't joined but have been invited
|
||||||
const dmRooms = dmRoomMap.getDMRoomsForUserId(this.props.member.userId);
|
const dmRooms = dmRoomMap.getDMRoomsForUserId(this.props.member.userId);
|
||||||
|
|
||||||
const RoomTile = sdk.getComponent("rooms.RoomTile");
|
const RoomTile = sdk.getComponent("rooms.RoomTile");
|
||||||
|
@ -722,10 +725,15 @@ module.exports = withMatrixClient(React.createClass({
|
||||||
const room = this.props.matrixClient.getRoom(roomId);
|
const room = this.props.matrixClient.getRoom(roomId);
|
||||||
if (room) {
|
if (room) {
|
||||||
const me = room.getMember(this.props.matrixClient.credentials.userId);
|
const me = room.getMember(this.props.matrixClient.credentials.userId);
|
||||||
const highlight = (
|
|
||||||
room.getUnreadNotificationCount('highlight') > 0 ||
|
// not a DM room if we have are not joined
|
||||||
me.membership === "invite"
|
if (!me.membership || me.membership !== 'join') continue;
|
||||||
);
|
// not a DM room if they are not joined
|
||||||
|
const them = this.props.member;
|
||||||
|
if (!them.membership || them.membership !== 'join') continue;
|
||||||
|
|
||||||
|
const highlight = room.getUnreadNotificationCount('highlight') > 0 || me.membership === 'invite';
|
||||||
|
|
||||||
tiles.push(
|
tiles.push(
|
||||||
<RoomTile key={room.roomId} room={room}
|
<RoomTile key={room.roomId} room={room}
|
||||||
collapsed={false}
|
collapsed={false}
|
||||||
|
|
|
@ -512,7 +512,8 @@ export default class MessageComposerInput extends React.Component {
|
||||||
// composer. For some reason the editor won't scroll automatically if we paste
|
// composer. For some reason the editor won't scroll automatically if we paste
|
||||||
// blocks of text in or insert newlines.
|
// blocks of text in or insert newlines.
|
||||||
if (textContent.slice(selection.start).indexOf("\n") === -1) {
|
if (textContent.slice(selection.start).indexOf("\n") === -1) {
|
||||||
this.refs.editor.refs.editor.scrollTop = this.refs.editor.refs.editor.scrollHeight;
|
let editorRoot = this.refs.editor.refs.editor.parentNode.parentNode;
|
||||||
|
editorRoot.scrollTop = editorRoot.scrollHeight;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ const rate_limited_func = require('../../../ratelimitedfunc');
|
||||||
const Rooms = require('../../../Rooms');
|
const Rooms = require('../../../Rooms');
|
||||||
import DMRoomMap from '../../../utils/DMRoomMap';
|
import DMRoomMap from '../../../utils/DMRoomMap';
|
||||||
const Receipt = require('../../../utils/Receipt');
|
const Receipt = require('../../../utils/Receipt');
|
||||||
import FilterStore from '../../../stores/FilterStore';
|
import TagOrderStore from '../../../stores/TagOrderStore';
|
||||||
import GroupStoreCache from '../../../stores/GroupStoreCache';
|
import GroupStoreCache from '../../../stores/GroupStoreCache';
|
||||||
|
|
||||||
const HIDE_CONFERENCE_CHANS = true;
|
const HIDE_CONFERENCE_CHANS = true;
|
||||||
|
@ -96,8 +96,8 @@ module.exports = React.createClass({
|
||||||
// By default, set to `null` meaning "all rooms visible"
|
// By default, set to `null` meaning "all rooms visible"
|
||||||
this._visibleRooms = null;
|
this._visibleRooms = null;
|
||||||
// When the selected tags are changed, initialise a group store if necessary
|
// When the selected tags are changed, initialise a group store if necessary
|
||||||
this._filterStoreToken = FilterStore.addListener(() => {
|
this._tagStoreToken = TagOrderStore.addListener(() => {
|
||||||
FilterStore.getSelectedTags().forEach((tag) => {
|
TagOrderStore.getSelectedTags().forEach((tag) => {
|
||||||
if (tag[0] !== '+' || this._groupStores[tag]) {
|
if (tag[0] !== '+' || this._groupStores[tag]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -183,8 +183,8 @@ module.exports = React.createClass({
|
||||||
MatrixClientPeg.get().removeListener("Group.myMembership", this._onGroupMyMembership);
|
MatrixClientPeg.get().removeListener("Group.myMembership", this._onGroupMyMembership);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._filterStoreToken) {
|
if (this._tagStoreToken) {
|
||||||
this._filterStoreToken.remove();
|
this._tagStoreToken.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._groupStoreTokens.length > 0) {
|
if (this._groupStoreTokens.length > 0) {
|
||||||
|
@ -298,12 +298,11 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
// Update which rooms and users should appear according to which tags are selected
|
// Update which rooms and users should appear according to which tags are selected
|
||||||
updateVisibleRooms: function() {
|
updateVisibleRooms: function() {
|
||||||
const selectedTags = FilterStore.getSelectedTags();
|
const selectedTags = TagOrderStore.getSelectedTags();
|
||||||
|
const visibleGroupRooms = [];
|
||||||
let visibleGroupRooms = [];
|
|
||||||
selectedTags.forEach((tag) => {
|
selectedTags.forEach((tag) => {
|
||||||
visibleGroupRooms = visibleGroupRooms.concat(
|
(this._visibleRoomsForGroup[tag] || []).forEach(
|
||||||
this._visibleRoomsForGroup[tag] || [],
|
(roomId) => visibleGroupRooms.push(roomId),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -378,7 +377,6 @@ module.exports = React.createClass({
|
||||||
(me.membership === "leave" && me.events.member.getSender() !== me.events.member.getStateKey())) {
|
(me.membership === "leave" && me.events.member.getSender() !== me.events.member.getStateKey())) {
|
||||||
// Used to split rooms via tags
|
// Used to split rooms via tags
|
||||||
const tagNames = Object.keys(room.tags);
|
const tagNames = Object.keys(room.tags);
|
||||||
|
|
||||||
if (tagNames.length) {
|
if (tagNames.length) {
|
||||||
for (let i = 0; i < tagNames.length; i++) {
|
for (let i = 0; i < tagNames.length; i++) {
|
||||||
const tagName = tagNames[i];
|
const tagName = tagNames[i];
|
||||||
|
@ -672,7 +670,6 @@ module.exports = React.createClass({
|
||||||
editable={false}
|
editable={false}
|
||||||
order="recent"
|
order="recent"
|
||||||
isInvite={true}
|
isInvite={true}
|
||||||
selectedRoom={self.props.selectedRoom}
|
|
||||||
incomingCall={self.state.incomingCall}
|
incomingCall={self.state.incomingCall}
|
||||||
collapsed={self.props.collapsed}
|
collapsed={self.props.collapsed}
|
||||||
searchFilter={self.props.searchFilter}
|
searchFilter={self.props.searchFilter}
|
||||||
|
@ -686,7 +683,6 @@ module.exports = React.createClass({
|
||||||
emptyContent={this._getEmptyContent('m.favourite')}
|
emptyContent={this._getEmptyContent('m.favourite')}
|
||||||
editable={true}
|
editable={true}
|
||||||
order="manual"
|
order="manual"
|
||||||
selectedRoom={self.props.selectedRoom}
|
|
||||||
incomingCall={self.state.incomingCall}
|
incomingCall={self.state.incomingCall}
|
||||||
collapsed={self.props.collapsed}
|
collapsed={self.props.collapsed}
|
||||||
searchFilter={self.props.searchFilter}
|
searchFilter={self.props.searchFilter}
|
||||||
|
@ -700,7 +696,6 @@ module.exports = React.createClass({
|
||||||
headerItems={this._getHeaderItems('im.vector.fake.direct')}
|
headerItems={this._getHeaderItems('im.vector.fake.direct')}
|
||||||
editable={true}
|
editable={true}
|
||||||
order="recent"
|
order="recent"
|
||||||
selectedRoom={self.props.selectedRoom}
|
|
||||||
incomingCall={self.state.incomingCall}
|
incomingCall={self.state.incomingCall}
|
||||||
collapsed={self.props.collapsed}
|
collapsed={self.props.collapsed}
|
||||||
alwaysShowHeader={true}
|
alwaysShowHeader={true}
|
||||||
|
@ -714,7 +709,6 @@ module.exports = React.createClass({
|
||||||
emptyContent={this._getEmptyContent('im.vector.fake.recent')}
|
emptyContent={this._getEmptyContent('im.vector.fake.recent')}
|
||||||
headerItems={this._getHeaderItems('im.vector.fake.recent')}
|
headerItems={this._getHeaderItems('im.vector.fake.recent')}
|
||||||
order="recent"
|
order="recent"
|
||||||
selectedRoom={self.props.selectedRoom}
|
|
||||||
incomingCall={self.state.incomingCall}
|
incomingCall={self.state.incomingCall}
|
||||||
collapsed={self.props.collapsed}
|
collapsed={self.props.collapsed}
|
||||||
searchFilter={self.props.searchFilter}
|
searchFilter={self.props.searchFilter}
|
||||||
|
@ -730,7 +724,6 @@ module.exports = React.createClass({
|
||||||
emptyContent={this._getEmptyContent(tagName)}
|
emptyContent={this._getEmptyContent(tagName)}
|
||||||
editable={true}
|
editable={true}
|
||||||
order="manual"
|
order="manual"
|
||||||
selectedRoom={self.props.selectedRoom}
|
|
||||||
incomingCall={self.state.incomingCall}
|
incomingCall={self.state.incomingCall}
|
||||||
collapsed={self.props.collapsed}
|
collapsed={self.props.collapsed}
|
||||||
searchFilter={self.props.searchFilter}
|
searchFilter={self.props.searchFilter}
|
||||||
|
@ -745,7 +738,6 @@ module.exports = React.createClass({
|
||||||
emptyContent={this._getEmptyContent('m.lowpriority')}
|
emptyContent={this._getEmptyContent('m.lowpriority')}
|
||||||
editable={true}
|
editable={true}
|
||||||
order="recent"
|
order="recent"
|
||||||
selectedRoom={self.props.selectedRoom}
|
|
||||||
incomingCall={self.state.incomingCall}
|
incomingCall={self.state.incomingCall}
|
||||||
collapsed={self.props.collapsed}
|
collapsed={self.props.collapsed}
|
||||||
searchFilter={self.props.searchFilter}
|
searchFilter={self.props.searchFilter}
|
||||||
|
@ -756,7 +748,6 @@ module.exports = React.createClass({
|
||||||
label={_t('Historical')}
|
label={_t('Historical')}
|
||||||
editable={false}
|
editable={false}
|
||||||
order="recent"
|
order="recent"
|
||||||
selectedRoom={self.props.selectedRoom}
|
|
||||||
collapsed={self.props.collapsed}
|
collapsed={self.props.collapsed}
|
||||||
alwaysShowHeader={true}
|
alwaysShowHeader={true}
|
||||||
startAsHidden={true}
|
startAsHidden={true}
|
||||||
|
|
|
@ -1,115 +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.
|
|
||||||
*/
|
|
||||||
import {Store} from 'flux/utils';
|
|
||||||
import dis from '../dispatcher';
|
|
||||||
import Analytics from '../Analytics';
|
|
||||||
|
|
||||||
const INITIAL_STATE = {
|
|
||||||
allTags: [],
|
|
||||||
selectedTags: [],
|
|
||||||
// Last selected tag when shift was not being pressed
|
|
||||||
anchorTag: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class for storing application state for filtering via TagPanel.
|
|
||||||
*/
|
|
||||||
class FilterStore extends Store {
|
|
||||||
constructor() {
|
|
||||||
super(dis);
|
|
||||||
|
|
||||||
// Initialise state
|
|
||||||
this._state = INITIAL_STATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
_setState(newState) {
|
|
||||||
this._state = Object.assign(this._state, newState);
|
|
||||||
this.__emitChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
__onDispatch(payload) {
|
|
||||||
switch (payload.action) {
|
|
||||||
case 'all_tags' :
|
|
||||||
this._setState({
|
|
||||||
allTags: payload.tags,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case 'select_tag': {
|
|
||||||
let newTags = [];
|
|
||||||
// Shift-click semantics
|
|
||||||
if (payload.shiftKey) {
|
|
||||||
// Select range of tags
|
|
||||||
let start = this._state.allTags.indexOf(this._state.anchorTag);
|
|
||||||
let end = this._state.allTags.indexOf(payload.tag);
|
|
||||||
|
|
||||||
if (start === -1) {
|
|
||||||
start = end;
|
|
||||||
}
|
|
||||||
if (start > end) {
|
|
||||||
const temp = start;
|
|
||||||
start = end;
|
|
||||||
end = temp;
|
|
||||||
}
|
|
||||||
newTags = payload.ctrlOrCmdKey ? this._state.selectedTags : [];
|
|
||||||
newTags = [...new Set(
|
|
||||||
this._state.allTags.slice(start, end + 1).concat(newTags),
|
|
||||||
)];
|
|
||||||
} else {
|
|
||||||
if (payload.ctrlOrCmdKey) {
|
|
||||||
// Toggle individual tag
|
|
||||||
if (this._state.selectedTags.includes(payload.tag)) {
|
|
||||||
newTags = this._state.selectedTags.filter((t) => t !== payload.tag);
|
|
||||||
} else {
|
|
||||||
newTags = [...this._state.selectedTags, payload.tag];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Select individual tag
|
|
||||||
newTags = [payload.tag];
|
|
||||||
}
|
|
||||||
// Only set the anchor tag if the tag was previously unselected, otherwise
|
|
||||||
// the next range starts with an unselected tag.
|
|
||||||
if (!this._state.selectedTags.includes(payload.tag)) {
|
|
||||||
this._setState({
|
|
||||||
anchorTag: payload.tag,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this._setState({
|
|
||||||
selectedTags: newTags,
|
|
||||||
});
|
|
||||||
|
|
||||||
Analytics.trackEvent('FilterStore', 'select_tag');
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'deselect_tags':
|
|
||||||
this._setState({
|
|
||||||
selectedTags: [],
|
|
||||||
});
|
|
||||||
Analytics.trackEvent('FilterStore', 'deselect_tags');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getSelectedTags() {
|
|
||||||
return this._state.selectedTags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (global.singletonFilterStore === undefined) {
|
|
||||||
global.singletonFilterStore = new FilterStore();
|
|
||||||
}
|
|
||||||
export default global.singletonFilterStore;
|
|
|
@ -15,12 +15,17 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
import {Store} from 'flux/utils';
|
import {Store} from 'flux/utils';
|
||||||
import dis from '../dispatcher';
|
import dis from '../dispatcher';
|
||||||
|
import Analytics from '../Analytics';
|
||||||
|
|
||||||
const INITIAL_STATE = {
|
const INITIAL_STATE = {
|
||||||
orderedTags: null,
|
orderedTags: null,
|
||||||
orderedTagsAccountData: null,
|
orderedTagsAccountData: null,
|
||||||
hasSynced: false,
|
hasSynced: false,
|
||||||
joinedGroupIds: null,
|
joinedGroupIds: null,
|
||||||
|
|
||||||
|
selectedTags: [],
|
||||||
|
// Last selected tag when shift was not being pressed
|
||||||
|
anchorTag: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -93,6 +98,60 @@ class TagOrderStore extends Store {
|
||||||
this._setState({orderedTags});
|
this._setState({orderedTags});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'select_tag': {
|
||||||
|
let newTags = [];
|
||||||
|
// Shift-click semantics
|
||||||
|
if (payload.shiftKey) {
|
||||||
|
// Select range of tags
|
||||||
|
let start = this._state.orderedTags.indexOf(this._state.anchorTag);
|
||||||
|
let end = this._state.orderedTags.indexOf(payload.tag);
|
||||||
|
|
||||||
|
if (start === -1) {
|
||||||
|
start = end;
|
||||||
|
}
|
||||||
|
if (start > end) {
|
||||||
|
const temp = start;
|
||||||
|
start = end;
|
||||||
|
end = temp;
|
||||||
|
}
|
||||||
|
newTags = payload.ctrlOrCmdKey ? this._state.selectedTags : [];
|
||||||
|
newTags = [...new Set(
|
||||||
|
this._state.orderedTags.slice(start, end + 1).concat(newTags),
|
||||||
|
)];
|
||||||
|
} else {
|
||||||
|
if (payload.ctrlOrCmdKey) {
|
||||||
|
// Toggle individual tag
|
||||||
|
if (this._state.selectedTags.includes(payload.tag)) {
|
||||||
|
newTags = this._state.selectedTags.filter((t) => t !== payload.tag);
|
||||||
|
} else {
|
||||||
|
newTags = [...this._state.selectedTags, payload.tag];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Select individual tag
|
||||||
|
newTags = [payload.tag];
|
||||||
|
}
|
||||||
|
// Only set the anchor tag if the tag was previously unselected, otherwise
|
||||||
|
// the next range starts with an unselected tag.
|
||||||
|
if (!this._state.selectedTags.includes(payload.tag)) {
|
||||||
|
this._setState({
|
||||||
|
anchorTag: payload.tag,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._setState({
|
||||||
|
selectedTags: newTags,
|
||||||
|
});
|
||||||
|
|
||||||
|
Analytics.trackEvent('FilterStore', 'select_tag');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'deselect_tags':
|
||||||
|
this._setState({
|
||||||
|
selectedTags: [],
|
||||||
|
});
|
||||||
|
Analytics.trackEvent('FilterStore', 'deselect_tags');
|
||||||
|
break;
|
||||||
case 'on_logged_out': {
|
case 'on_logged_out': {
|
||||||
// Reset state without pushing an update to the view, which generally assumes that
|
// Reset state without pushing an update to the view, which generally assumes that
|
||||||
// the matrix client isn't `null` and so causing a re-render will cause NPEs.
|
// the matrix client isn't `null` and so causing a re-render will cause NPEs.
|
||||||
|
@ -129,6 +188,10 @@ class TagOrderStore extends Store {
|
||||||
getOrderedTags() {
|
getOrderedTags() {
|
||||||
return this._state.orderedTags;
|
return this._state.orderedTags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSelectedTags() {
|
||||||
|
return this._state.selectedTags;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global.singletonTagOrderStore === undefined) {
|
if (global.singletonTagOrderStore === undefined) {
|
||||||
|
|
Loading…
Reference in a new issue