Этот коммит содержится в:
enahum
2016-09-15 09:53:21 -03:00
коммит произвёл Joram Wilander
родитель b180bb46e3
Коммит 2659d19d05
5 изменённых файлов: 229 добавлений и 68 удалений

180
webapp/components/filtered_channel_list.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,180 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import $ from 'jquery';
import ReactDOM from 'react-dom';
import * as UserAgent from 'utils/user_agent.jsx';
import {localizeMessage} from 'utils/utils.jsx';
import {FormattedMessage} from 'react-intl';
import React from 'react';
import loadingGif from 'images/load.gif';
export default class FilteredChannelList extends React.Component {
constructor(props) {
super(props);
this.handleFilterChange = this.handleFilterChange.bind(this);
this.createChannelRow = this.createChannelRow.bind(this);
this.filterChannels = this.filterChannels.bind(this);
this.state = {
filter: '',
joiningChannel: '',
channels: this.filterChannels(props.channels)
};
}
componentWillReceiveProps(nextProps) {
// assume the channel list is immutable
if (this.props.channels !== nextProps.channels) {
this.setState({
channels: this.filterChannels(nextProps.channels)
});
}
}
componentDidMount() {
// only focus the search box on desktop so that we don't cause the keyboard to open on mobile
if (!UserAgent.isMobileApp()) {
ReactDOM.findDOMNode(this.refs.filter).focus();
}
}
componentDidUpdate(prevProps, prevState) {
if (prevState.filter !== this.state.filter) {
$(ReactDOM.findDOMNode(this.refs.channelList)).scrollTop(0);
}
}
handleJoin(channel) {
this.setState({joiningChannel: channel.id});
this.props.handleJoin(
channel,
() => {
this.setState({joiningChannel: ''});
});
}
createChannelRow(channel) {
let joinButton;
if (this.state.joiningChannel === channel.id) {
joinButton = (
<img
className='join-channel-loading-gif'
src={loadingGif}
/>
);
} else {
joinButton = (
<button
onClick={this.handleJoin.bind(this, channel)}
className='btn btn-primary'
>
<FormattedMessage
id='more_channels.join'
defaultMessage='Join'
/>
</button>
);
}
return (
<div
className='more-modal__row'
key={channel.id}
>
<div className='more-modal__details'>
<p className='more-modal__name'>{channel.display_name}</p>
<p className='more-modal__description'>{channel.purpose}</p>
</div>
<div className='more-modal__actions'>
{joinButton}
</div>
</div>
);
}
filterChannels(channels) {
if (!this.state || !this.state.filter) {
return channels;
}
return channels.filter((chan) => {
const filter = this.state.filter.toLowerCase();
return !!((chan.name.toLowerCase().indexOf(filter) !== -1 || chan.display_name.toLowerCase().indexOf(filter) !== -1) && chan.delete_at === 0);
});
}
handleFilterChange(e) {
this.setState({
filter: e.target.value
});
}
render() {
let channels = this.state.channels;
if (this.state.filter && this.state.filter.length > 0) {
channels = this.filterChannels(channels);
}
let count;
if (channels.length === this.props.channels.length) {
count = (
<FormattedMessage
id='filtered_channels_list.count'
defaultMessage='{count} {count, plural, =0 {0 channels} one {channel} other {channels}}'
values={{
count: channels.length
}}
/>
);
} else {
count = (
<FormattedMessage
id='filtered_channels_list.countTotal'
defaultMessage='{count} {count, plural, =0 {0 channels} one {channel} other {channels}} of {total} Total'
values={{
count: channels.length,
total: this.props.channels.length
}}
/>
);
}
return (
<div className='filtered-user-list'>
<div className='filter-row'>
<div className='col-sm-6'>
<input
ref='filter'
className='form-control filter-textbox'
placeholder={localizeMessage('filtered_channels_list.search', 'Search channels')}
onInput={this.handleFilterChange}
/>
</div>
<div className='col-sm-12'>
<span className='channel-count pull-left'>{count}</span>
</div>
</div>
<div
ref='channelList'
className='more-modal__list'
>
{channels.map(this.createChannelRow)}
</div>
</div>
);
}
}
FilteredChannelList.defaultProps = {
channels: []
};
FilteredChannelList.propTypes = {
channels: React.PropTypes.arrayOf(React.PropTypes.object),
handleJoin: React.PropTypes.func.isRequired
};

Просмотреть файл

@@ -4,6 +4,7 @@
import $ from 'jquery';
import LoadingScreen from './loading_screen.jsx';
import NewChannelFlow from './new_channel_flow.jsx';
import FilteredChannelList from './filtered_channel_list.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import UserStore from 'stores/user_store.jsx';
@@ -18,18 +19,8 @@ import {FormattedMessage} from 'react-intl';
import {browserHistory} from 'react-router/es6';
import React from 'react';
import ReactDOM from 'react-dom';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import loadingGif from 'images/load.gif';
function getStateFromStores() {
return {
channels: ChannelStore.getMoreAll(),
serverError: null
};
}
export default class MoreChannels extends React.Component {
constructor(props) {
super(props);
@@ -37,100 +28,78 @@ export default class MoreChannels extends React.Component {
this.onListenerChange = this.onListenerChange.bind(this);
this.handleJoin = this.handleJoin.bind(this);
this.handleNewChannel = this.handleNewChannel.bind(this);
this.createChannelRow = this.createChannelRow.bind(this);
this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
var initState = getStateFromStores();
const initState = this.getStateFromStores();
initState.channelType = '';
initState.joiningChannel = '';
initState.showNewChannelModal = false;
this.state = initState;
}
componentDidMount() {
const self = this;
ChannelStore.addMoreChangeListener(this.onListenerChange);
$(ReactDOM.findDOMNode(this.refs.modal)).on('shown.bs.modal', () => {
$(this.refs.modal).on('shown.bs.modal', () => {
AsyncClient.getMoreChannels(true);
});
var self = this;
$(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', (e) => {
var button = e.relatedTarget;
$(this.refs.modal).on('show.bs.modal', (e) => {
const button = e.relatedTarget;
self.setState({channelType: $(button).attr('data-channeltype')});
});
}
componentWillUnmount() {
ChannelStore.removeMoreChangeListener(this.onListenerChange);
}
getStateFromStores() {
return {
channels: ChannelStore.getMoreAll(),
serverError: null
};
}
onListenerChange() {
var newState = getStateFromStores();
const newState = this.getStateFromStores();
if (!Utils.areObjectsEqual(newState.channels, this.state.channels)) {
this.setState(newState);
}
}
handleJoin(channel) {
this.setState({joiningChannel: channel.id});
handleJoin(channel, done) {
GlobalActions.emitJoinChannelEvent(
channel,
() => {
$(ReactDOM.findDOMNode(this.refs.modal)).modal('hide');
$(this.refs.modal).modal('hide');
browserHistory.push(TeamStore.getCurrentTeamRelativeUrl() + '/channels/' + channel.name);
this.setState({joiningChannel: ''});
if (done) {
done();
}
},
(err) => {
this.setState({joiningChannel: '', serverError: err.message});
this.setState({serverError: err.message});
if (done) {
done();
}
}
);
}
handleNewChannel() {
$(ReactDOM.findDOMNode(this.refs.modal)).modal('hide');
$(this.refs.modal).modal('hide');
this.setState({showNewChannelModal: true});
}
createChannelRow(channel) {
let joinButton;
if (this.state.joiningChannel === channel.id) {
joinButton = (
<img
className='join-channel-loading-gif'
src={loadingGif}
/>
);
} else {
joinButton = (
<button
onClick={this.handleJoin.bind(self, channel)}
className='btn btn-primary'
>
<FormattedMessage
id='more_channels.join'
defaultMessage='Join'
/>
</button>
);
}
return (
<div
className='more-modal__row'
key={channel.id}
>
<div className='more-modal__details'>
<p className='more-modal__name'>{channel.display_name}</p>
<p className='more-modal__description'>{channel.purpose}</p>
</div>
<div className='more-modal__actions'>
{joinButton}
</div>
</div>
);
}
render() {
let maxHeight = 1000;
if (Utils.windowHeight() <= 1200) {
maxHeight = Utils.windowHeight() - 300;
}
var serverError;
let serverError;
if (this.state.serverError) {
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
}
@@ -170,7 +139,7 @@ export default class MoreChannels extends React.Component {
}
}
var moreChannels;
let moreChannels;
if (this.state.channels != null) {
var channels = this.state.channels;
@@ -178,9 +147,10 @@ export default class MoreChannels extends React.Component {
moreChannels = <LoadingScreen/>;
} else if (channels.length) {
moreChannels = (
<div className='more-modal__list'>
{channels.map(this.createChannelRow)}
</div>
<FilteredChannelList
channels={channels}
handleJoin={this.handleJoin}
/>
);
} else {
moreChannels = (

Просмотреть файл

@@ -1182,6 +1182,9 @@
"file_upload.filesAbove": "Files above {max}MB cannot be uploaded: {filenames}",
"file_upload.limited": "Uploads limited to {count} files maximum. Please use additional posts for more files.",
"file_upload.pasted": "Image Pasted at ",
"filtered_channels_list.count": "{count} {count, plural, =0 {0 channels} one {channel} other {channels}}",
"filtered_channels_list.countTotal": "{count} {count, plural, =0 {0 channels} one {channel} other {channels}} of {total} Total",
"filtered_channels_list.search": "Search channels",
"filtered_user_list.any_team": "All Users",
"filtered_user_list.count": "{count} {count, plural, =0 {0 members} one {member} other {members}}",
"filtered_user_list.countTotal": "{count} {count, plural, =0 {0 members} one {member} other {members}} of {total} Total",

Просмотреть файл

@@ -227,7 +227,14 @@
&.more-channel__modal {
.modal-body {
padding: 0;
overflow-x: hidden;
padding: 10px 0 20px;
}
.channel-count {
@include opacity(.8);
float: right;
margin-top: 5px;
}
}

Просмотреть файл

@@ -307,7 +307,8 @@
max-width: calc(100% - 10px);
}
.modal-direct-channels {
.modal-direct-channels,
.more-channel__modal {
.member-count {
display: block;
float: none;