Added scrolling, move out of navbar (#3163)
Added magic number, removed jqueryi
Этот коммит содержится в:
коммит произвёл
Corey Hulen
родитель
2ea54b9d1e
Коммит
4b06362172
@@ -17,7 +17,6 @@ import ToggleModalButton from './toggle_modal_button.jsx';
|
|||||||
import UserStore from 'stores/user_store.jsx';
|
import UserStore from 'stores/user_store.jsx';
|
||||||
import ChannelStore from 'stores/channel_store.jsx';
|
import ChannelStore from 'stores/channel_store.jsx';
|
||||||
import TeamStore from 'stores/team_store.jsx';
|
import TeamStore from 'stores/team_store.jsx';
|
||||||
import PreferenceStore from 'stores/preference_store.jsx';
|
|
||||||
|
|
||||||
import Client from 'utils/web_client.jsx';
|
import Client from 'utils/web_client.jsx';
|
||||||
import * as AsyncClient from 'utils/async_client.jsx';
|
import * as AsyncClient from 'utils/async_client.jsx';
|
||||||
@@ -35,8 +34,6 @@ import {Link, browserHistory} from 'react-router';
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import * as ChannelActions from 'actions/channel_actions.jsx';
|
|
||||||
|
|
||||||
export default class Navbar extends React.Component {
|
export default class Navbar extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -53,11 +50,6 @@ export default class Navbar extends React.Component {
|
|||||||
this.createCollapseButtons = this.createCollapseButtons.bind(this);
|
this.createCollapseButtons = this.createCollapseButtons.bind(this);
|
||||||
this.createDropdown = this.createDropdown.bind(this);
|
this.createDropdown = this.createDropdown.bind(this);
|
||||||
|
|
||||||
this.navigateChannelShortcut = this.navigateChannelShortcut.bind(this);
|
|
||||||
this.navigateUnreadChannelShortcut = this.navigateUnreadChannelShortcut.bind(this);
|
|
||||||
this.getDisplayedChannels = this.getDisplayedChannels.bind(this);
|
|
||||||
this.compareByDisplayName = this.compareByDisplayName.bind(this);
|
|
||||||
|
|
||||||
const state = this.getStateFromStores();
|
const state = this.getStateFromStores();
|
||||||
state.showEditChannelPurposeModal = false;
|
state.showEditChannelPurposeModal = false;
|
||||||
state.showEditChannelHeaderModal = false;
|
state.showEditChannelHeaderModal = false;
|
||||||
@@ -80,14 +72,10 @@ export default class Navbar extends React.Component {
|
|||||||
ChannelStore.addChangeListener(this.onChange);
|
ChannelStore.addChangeListener(this.onChange);
|
||||||
ChannelStore.addExtraInfoChangeListener(this.onChange);
|
ChannelStore.addExtraInfoChangeListener(this.onChange);
|
||||||
$('.inner-wrap').click(this.hideSidebars);
|
$('.inner-wrap').click(this.hideSidebars);
|
||||||
document.addEventListener('keydown', this.navigateChannelShortcut);
|
|
||||||
document.addEventListener('keydown', this.navigateUnreadChannelShortcut);
|
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
ChannelStore.removeChangeListener(this.onChange);
|
ChannelStore.removeChangeListener(this.onChange);
|
||||||
ChannelStore.removeExtraInfoChangeListener(this.onChange);
|
ChannelStore.removeExtraInfoChangeListener(this.onChange);
|
||||||
document.removeEventListener('keydown', this.navigateChannelShortcut);
|
|
||||||
document.removeEventListener('keydown', this.navigateUnreadChannelShortcut);
|
|
||||||
}
|
}
|
||||||
handleSubmit(e) {
|
handleSubmit(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -162,93 +150,6 @@ export default class Navbar extends React.Component {
|
|||||||
showRenameChannelModal: false
|
showRenameChannelModal: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
navigateChannelShortcut(e) {
|
|
||||||
if (e.altKey && !e.shiftKey && (e.keyCode === Constants.KeyCodes.UP || e.keyCode === Constants.KeyCodes.DOWN)) {
|
|
||||||
e.preventDefault();
|
|
||||||
const allChannels = this.getDisplayedChannels();
|
|
||||||
const curChannel = this.state.channel;
|
|
||||||
let curIndex = -1;
|
|
||||||
for (let i = 0; i < allChannels.length; i++) {
|
|
||||||
if (allChannels[i].id === curChannel.id) {
|
|
||||||
curIndex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let nextChannel = curChannel;
|
|
||||||
let nextIndex = curIndex;
|
|
||||||
if (e.keyCode === Constants.KeyCodes.DOWN) {
|
|
||||||
nextIndex = curIndex + 1;
|
|
||||||
} else if (e.keyCode === Constants.KeyCodes.UP) {
|
|
||||||
nextIndex = curIndex - 1;
|
|
||||||
}
|
|
||||||
nextChannel = allChannels[Utils.mod(nextIndex, allChannels.length)];
|
|
||||||
ChannelActions.goToChannel(nextChannel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
navigateUnreadChannelShortcut(e) {
|
|
||||||
if (e.altKey && e.shiftKey && (e.keyCode === Constants.KeyCodes.UP || e.keyCode === Constants.KeyCodes.DOWN)) {
|
|
||||||
e.preventDefault();
|
|
||||||
const allChannels = this.getDisplayedChannels();
|
|
||||||
const curChannel = this.state.channel;
|
|
||||||
let curIndex = -1;
|
|
||||||
for (let i = 0; i < allChannels.length; i++) {
|
|
||||||
if (allChannels[i].id === curChannel.id) {
|
|
||||||
curIndex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let nextChannel = curChannel;
|
|
||||||
let nextIndex = curIndex;
|
|
||||||
let count = 0;
|
|
||||||
let increment = 0;
|
|
||||||
if (e.keyCode === Constants.KeyCodes.UP) {
|
|
||||||
increment = -1;
|
|
||||||
} else if (e.keyCode === Constants.KeyCodes.DOWN) {
|
|
||||||
increment = 1;
|
|
||||||
}
|
|
||||||
let unreadCounts = ChannelStore.getUnreadCount(allChannels[nextIndex].id);
|
|
||||||
while (count < allChannels.length && unreadCounts.msgs === 0 && unreadCounts.mentions === 0) {
|
|
||||||
nextIndex += increment;
|
|
||||||
count++;
|
|
||||||
nextIndex = Utils.mod(nextIndex, allChannels.length);
|
|
||||||
unreadCounts = ChannelStore.getUnreadCount(allChannels[nextIndex].id);
|
|
||||||
}
|
|
||||||
if (unreadCounts.msgs !== 0 || unreadCounts.mentions !== 0) {
|
|
||||||
nextChannel = allChannels[nextIndex];
|
|
||||||
ChannelActions.goToChannel(nextChannel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getDisplayedChannels() {
|
|
||||||
const allChannels = ChannelStore.getChannels().sort(this.compareByDisplayName);
|
|
||||||
const publicChannels = allChannels.filter((channel) => channel.type === Constants.OPEN_CHANNEL);
|
|
||||||
const privateChannels = allChannels.filter((channel) => channel.type === Constants.PRIVATE_CHANNEL);
|
|
||||||
|
|
||||||
const preferences = PreferenceStore.getCategory(Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW);
|
|
||||||
|
|
||||||
const directChannels = [];
|
|
||||||
const directNonTeamChannels = [];
|
|
||||||
for (const [name, value] of preferences) {
|
|
||||||
if (value !== 'true') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const directChannel = allChannels.find(Utils.isDirectChannelForUser.bind(null, name));
|
|
||||||
directChannel.display_name = Utils.displayUsername(name);
|
|
||||||
|
|
||||||
if (UserStore.hasTeamProfile(name)) {
|
|
||||||
directChannels.push(directChannel);
|
|
||||||
} else {
|
|
||||||
directNonTeamChannels.push(directChannel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
directChannels.sort(this.compareByDisplayName);
|
|
||||||
directNonTeamChannels.sort(this.compareByDisplayName);
|
|
||||||
|
|
||||||
return publicChannels.concat(privateChannels).concat(directChannels).concat(directNonTeamChannels);
|
|
||||||
}
|
|
||||||
compareByDisplayName(channelA, channelB) {
|
|
||||||
return channelA.display_name.localeCompare(channelB.display_name);
|
|
||||||
}
|
|
||||||
createDropdown(channel, channelTitle, isAdmin, isDirect, popoverContent) {
|
createDropdown(channel, channelTitle, isAdmin, isDirect, popoverContent) {
|
||||||
if (channel) {
|
if (channel) {
|
||||||
var viewInfoOption = (
|
var viewInfoOption = (
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import PreferenceStore from 'stores/preference_store.jsx';
|
|||||||
|
|
||||||
import * as AsyncClient from 'utils/async_client.jsx';
|
import * as AsyncClient from 'utils/async_client.jsx';
|
||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
|
import * as ChannelActions from 'actions/channel_actions.jsx';
|
||||||
|
|
||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
|
|
||||||
@@ -57,6 +58,11 @@ export default class Sidebar extends React.Component {
|
|||||||
this.createChannelElement = this.createChannelElement.bind(this);
|
this.createChannelElement = this.createChannelElement.bind(this);
|
||||||
this.updateTitle = this.updateTitle.bind(this);
|
this.updateTitle = this.updateTitle.bind(this);
|
||||||
|
|
||||||
|
this.navigateChannelShortcut = this.navigateChannelShortcut.bind(this);
|
||||||
|
this.navigateUnreadChannelShortcut = this.navigateUnreadChannelShortcut.bind(this);
|
||||||
|
this.getDisplayedChannels = this.getDisplayedChannels.bind(this);
|
||||||
|
this.updateScrollbarOnChannelChange = this.updateScrollbarOnChannelChange.bind(this);
|
||||||
|
|
||||||
this.isLeaving = new Map();
|
this.isLeaving = new Map();
|
||||||
|
|
||||||
const state = this.getStateFromStores();
|
const state = this.getStateFromStores();
|
||||||
@@ -155,6 +161,9 @@ export default class Sidebar extends React.Component {
|
|||||||
|
|
||||||
this.updateTitle();
|
this.updateTitle();
|
||||||
this.updateUnreadIndicators();
|
this.updateUnreadIndicators();
|
||||||
|
|
||||||
|
document.addEventListener('keydown', this.navigateChannelShortcut);
|
||||||
|
document.addEventListener('keydown', this.navigateUnreadChannelShortcut);
|
||||||
}
|
}
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
if (!Utils.areObjectsEqual(nextState, this.state)) {
|
if (!Utils.areObjectsEqual(nextState, this.state)) {
|
||||||
@@ -187,6 +196,8 @@ export default class Sidebar extends React.Component {
|
|||||||
UserStore.removeStatusesChangeListener(this.onChange);
|
UserStore.removeStatusesChangeListener(this.onChange);
|
||||||
TeamStore.removeChangeListener(this.onChange);
|
TeamStore.removeChangeListener(this.onChange);
|
||||||
PreferenceStore.removeChangeListener(this.onChange);
|
PreferenceStore.removeChangeListener(this.onChange);
|
||||||
|
document.removeEventListener('keydown', this.navigateChannelShortcut);
|
||||||
|
document.removeEventListener('keydown', this.navigateUnreadChannelShortcut);
|
||||||
}
|
}
|
||||||
onChange() {
|
onChange() {
|
||||||
this.setState(this.getStateFromStores());
|
this.setState(this.getStateFromStores());
|
||||||
@@ -243,7 +254,73 @@ export default class Sidebar extends React.Component {
|
|||||||
showBottomUnread
|
showBottomUnread
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
updateScrollbarOnChannelChange(channel) {
|
||||||
|
const curChannel = this.refs[channel.name].getBoundingClientRect();
|
||||||
|
if ((curChannel.top - Constants.CHANNEL_SCROLL_ADJUSTMENT < 0) || (curChannel.top + curChannel.height > this.refs.container.getBoundingClientRect().height)) {
|
||||||
|
this.refs.container.scrollTop = this.refs.container.scrollTop + (curChannel.top - Constants.CHANNEL_SCROLL_ADJUSTMENT);
|
||||||
|
$('.nav-pills__container').perfectScrollbar('update');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
navigateChannelShortcut(e) {
|
||||||
|
if (e.altKey && !e.shiftKey && (e.keyCode === Constants.KeyCodes.UP || e.keyCode === Constants.KeyCodes.DOWN)) {
|
||||||
|
e.preventDefault();
|
||||||
|
const allChannels = this.getDisplayedChannels();
|
||||||
|
const curChannelId = this.state.activeId;
|
||||||
|
let curIndex = -1;
|
||||||
|
for (let i = 0; i < allChannels.length; i++) {
|
||||||
|
if (allChannels[i].id === curChannelId) {
|
||||||
|
curIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let nextChannel = allChannels[curIndex];
|
||||||
|
let nextIndex = curIndex;
|
||||||
|
if (e.keyCode === Constants.KeyCodes.DOWN) {
|
||||||
|
nextIndex = curIndex + 1;
|
||||||
|
} else if (e.keyCode === Constants.KeyCodes.UP) {
|
||||||
|
nextIndex = curIndex - 1;
|
||||||
|
}
|
||||||
|
nextChannel = allChannels[Utils.mod(nextIndex, allChannels.length)];
|
||||||
|
ChannelActions.goToChannel(nextChannel);
|
||||||
|
this.updateScrollbarOnChannelChange(nextChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
navigateUnreadChannelShortcut(e) {
|
||||||
|
if (e.altKey && e.shiftKey && (e.keyCode === Constants.KeyCodes.UP || e.keyCode === Constants.KeyCodes.DOWN)) {
|
||||||
|
e.preventDefault();
|
||||||
|
const allChannels = this.getDisplayedChannels();
|
||||||
|
const curChannelId = this.state.activeId;
|
||||||
|
let curIndex = -1;
|
||||||
|
for (let i = 0; i < allChannels.length; i++) {
|
||||||
|
if (allChannels[i].id === curChannelId) {
|
||||||
|
curIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let nextChannel = allChannels[curIndex];
|
||||||
|
let nextIndex = curIndex;
|
||||||
|
let count = 0;
|
||||||
|
let increment = 0;
|
||||||
|
if (e.keyCode === Constants.KeyCodes.UP) {
|
||||||
|
increment = -1;
|
||||||
|
} else if (e.keyCode === Constants.KeyCodes.DOWN) {
|
||||||
|
increment = 1;
|
||||||
|
}
|
||||||
|
let unreadCounts = ChannelStore.getUnreadCount(allChannels[nextIndex].id);
|
||||||
|
while (count < allChannels.length && unreadCounts.msgs === 0 && unreadCounts.mentions === 0) {
|
||||||
|
nextIndex += increment;
|
||||||
|
count++;
|
||||||
|
nextIndex = Utils.mod(nextIndex, allChannels.length);
|
||||||
|
unreadCounts = ChannelStore.getUnreadCount(allChannels[nextIndex].id);
|
||||||
|
}
|
||||||
|
if (unreadCounts.msgs !== 0 || unreadCounts.mentions !== 0) {
|
||||||
|
nextChannel = allChannels[nextIndex];
|
||||||
|
ChannelActions.goToChannel(nextChannel);
|
||||||
|
this.updateScrollbarOnChannelChange(nextChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getDisplayedChannels() {
|
||||||
|
return this.state.publicChannels.concat(this.state.privateChannels).concat(this.state.directChannels).concat(this.state.directNonTeamChannels);
|
||||||
|
}
|
||||||
handleLeaveDirectChannel(e, channel) {
|
handleLeaveDirectChannel(e, channel) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
|||||||
@@ -746,6 +746,7 @@ export default {
|
|||||||
MAX_TRIGGER_LENGTH: 128,
|
MAX_TRIGGER_LENGTH: 128,
|
||||||
TIME_SINCE_UPDATE_INTERVAL: 30000,
|
TIME_SINCE_UPDATE_INTERVAL: 30000,
|
||||||
MIN_HASHTAG_LINK_LENGTH: 3,
|
MIN_HASHTAG_LINK_LENGTH: 3,
|
||||||
|
CHANNEL_SCROLL_ADJUSTMENT: 100,
|
||||||
EMOJI_PATH: '/static/emoji',
|
EMOJI_PATH: '/static/emoji',
|
||||||
DEFAULT_WEBHOOK_LOGO: logoWebhook,
|
DEFAULT_WEBHOOK_LOGO: logoWebhook,
|
||||||
MHPNS: 'https://push.mattermost.com',
|
MHPNS: 'https://push.mattermost.com',
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user