Merge pull request #383 from rgarmsen2295/mm-1584b
MM-1584 Private message channels no longer do a page refresh on creation/first use
Этот коммит содержится в:
@@ -3,67 +3,102 @@
|
|||||||
|
|
||||||
var ChannelStore = require('../stores/channel_store.jsx');
|
var ChannelStore = require('../stores/channel_store.jsx');
|
||||||
var TeamStore = require('../stores/team_store.jsx');
|
var TeamStore = require('../stores/team_store.jsx');
|
||||||
|
var Client = require('../utils/client.jsx');
|
||||||
|
var AsyncClient = require('../utils/async_client.jsx');
|
||||||
var utils = require('../utils/utils.jsx');
|
var utils = require('../utils/utils.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
|
displayName: 'MoreDirectChannels',
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) {
|
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function showModal(e) {
|
||||||
var button = e.relatedTarget;
|
var button = e.relatedTarget;
|
||||||
self.setState({ channels: $(button).data('channels') });
|
self.setState({channels: $(button).data('channels')});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return { channels: [] };
|
return {channels: [], loadingDMChannel: -1};
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var directMessageItems = this.state.channels.map(function(channel) {
|
var directMessageItems = this.state.channels.map(function mapActivityToChannel(channel, index) {
|
||||||
var badge = "";
|
var badge = '';
|
||||||
var titleClass = ""
|
var titleClass = '';
|
||||||
|
var active = '';
|
||||||
|
var handleClick = null;
|
||||||
|
|
||||||
if (!channel.fake) {
|
if (!channel.fake) {
|
||||||
var active = channel.id === ChannelStore.getCurrentId() ? "active" : "";
|
if (channel.id === ChannelStore.getCurrentId()) {
|
||||||
|
active = 'active';
|
||||||
|
}
|
||||||
|
|
||||||
if (channel.unread) {
|
if (channel.unread) {
|
||||||
badge = <span className="badge pull-right small">{channel.unread}</span>;
|
badge = <span className='badge pull-right small'>{channel.unread}</span>;
|
||||||
badgesActive = true;
|
titleClass = 'unread-title';
|
||||||
titleClass = "unread-title"
|
|
||||||
}
|
}
|
||||||
return (
|
|
||||||
<li key={channel.name} className={active}><a className={"sidebar-channel " + titleClass} href="#" onClick={function(e){e.preventDefault(); utils.switchChannel(channel, channel.teammate_username); $(self.refs.modal.getDOMNode()).modal('hide')}}>{badge}{channel.display_name}</a></li>
|
handleClick = function clickHandler(e) {
|
||||||
);
|
e.preventDefault();
|
||||||
|
utils.switchChannel(channel, channel.teammate_username);
|
||||||
|
$(self.refs.modal.getDOMNode()).modal('hide');
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
return (
|
// It's a direct message channel that doesn't exist yet so let's create it now
|
||||||
<li key={channel.name} className={active}><a className={"sidebar-channel " + titleClass} href={TeamStore.getCurrentTeamUrl() + "/channels/"+channel.name}>{badge}{channel.display_name}</a></li>
|
var otherUserId = utils.getUserIdFromChannelName(channel);
|
||||||
);
|
|
||||||
|
if (self.state.loadingDMChannel === index) {
|
||||||
|
badge = <img className='channel-loading-gif pull-right' src='/static/images/load.gif'/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.state.loadingDMChannel === -1) {
|
||||||
|
handleClick = function clickHandler(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
self.setState({loadingDMChannel: index});
|
||||||
|
|
||||||
|
Client.createDirectChannel(channel, otherUserId,
|
||||||
|
function success(data) {
|
||||||
|
$(self.refs.modal.getDOMNode()).modal('hide');
|
||||||
|
self.setState({loadingDMChannel: -1});
|
||||||
|
AsyncClient.getChannel(data.id);
|
||||||
|
utils.switchChannel(data);
|
||||||
|
},
|
||||||
|
function error() {
|
||||||
|
self.setState({loadingDMChannel: -1});
|
||||||
|
window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/' + channel.name;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li key={channel.name} className={active}><a className={'sidebar-channel ' + titleClass} href='#' onClick={handleClick}>{badge}{channel.display_name}</a></li>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="modal fade" id="more_direct_channels" ref="modal" tabIndex="-1" role="dialog" aria-hidden="true">
|
<div className='modal fade' id='more_direct_channels' ref='modal' tabIndex='-1' role='dialog' aria-hidden='true'>
|
||||||
<div className="modal-dialog">
|
<div className='modal-dialog'>
|
||||||
<div className="modal-content">
|
<div className='modal-content'>
|
||||||
<div className="modal-header">
|
<div className='modal-header'>
|
||||||
<button type="button" className="close" data-dismiss="modal">
|
<button type='button' className='close' data-dismiss='modal'>
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden='true'>×</span>
|
||||||
<span className="sr-only">Close</span>
|
<span className='sr-only'>Close</span>
|
||||||
</button>
|
</button>
|
||||||
<h4 className="modal-title">More Private Messages</h4>
|
<h4 className='modal-title'>More Private Messages</h4>
|
||||||
</div>
|
</div>
|
||||||
<div className="modal-body">
|
<div className='modal-body'>
|
||||||
<ul className="nav nav-pills nav-stacked">
|
<ul className='nav nav-pills nav-stacked'>
|
||||||
{directMessageItems}
|
{directMessageItems}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className="modal-footer">
|
<div className='modal-footer'>
|
||||||
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
|
<button type='button' className='btn btn-default' data-dismiss='modal'>Close</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
|
|
||||||
var ChannelStore = require('../stores/channel_store.jsx');
|
var ChannelStore = require('../stores/channel_store.jsx');
|
||||||
|
var Client = require('../utils/client.jsx');
|
||||||
var AsyncClient = require('../utils/async_client.jsx');
|
var AsyncClient = require('../utils/async_client.jsx');
|
||||||
var SocketStore = require('../stores/socket_store.jsx');
|
var SocketStore = require('../stores/socket_store.jsx');
|
||||||
var UserStore = require('../stores/user_store.jsx');
|
var UserStore = require('../stores/user_store.jsx');
|
||||||
@@ -11,9 +11,7 @@ var BrowserStore = require('../stores/browser_store.jsx');
|
|||||||
var utils = require('../utils/utils.jsx');
|
var utils = require('../utils/utils.jsx');
|
||||||
var SidebarHeader = require('./sidebar_header.jsx');
|
var SidebarHeader = require('./sidebar_header.jsx');
|
||||||
var SearchBox = require('./search_bar.jsx');
|
var SearchBox = require('./search_bar.jsx');
|
||||||
|
|
||||||
var Constants = require('../utils/constants.jsx');
|
var Constants = require('../utils/constants.jsx');
|
||||||
var ActionTypes = Constants.ActionTypes;
|
|
||||||
|
|
||||||
function getStateFromStores() {
|
function getStateFromStores() {
|
||||||
var members = ChannelStore.getAllMembers();
|
var members = ChannelStore.getAllMembers();
|
||||||
@@ -70,13 +68,14 @@ function getStateFromStores() {
|
|||||||
tempChannel.status = UserStore.getStatus(teammate.id);
|
tempChannel.status = UserStore.getStatus(teammate.id);
|
||||||
tempChannel.last_post_at = 0;
|
tempChannel.last_post_at = 0;
|
||||||
tempChannel.total_msg_count = 0;
|
tempChannel.total_msg_count = 0;
|
||||||
|
tempChannel.type = 'D';
|
||||||
readDirectChannels.push(tempChannel);
|
readDirectChannels.push(tempChannel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't have MAX_DMS unread channels, sort the read list by last_post_at
|
// If we don't have MAX_DMS unread channels, sort the read list by last_post_at
|
||||||
if (showDirectChannels.length < Constants.MAX_DMS) {
|
if (showDirectChannels.length < Constants.MAX_DMS) {
|
||||||
readDirectChannels.sort(function(a, b) {
|
readDirectChannels.sort(function sortByLastPost(a, b) {
|
||||||
// sort by last_post_at first
|
// sort by last_post_at first
|
||||||
if (a.last_post_at > b.last_post_at) {
|
if (a.last_post_at > b.last_post_at) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -124,6 +123,10 @@ function getStateFromStores() {
|
|||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
displayName: 'Sidebar',
|
displayName: 'Sidebar',
|
||||||
|
propTypes: {
|
||||||
|
teamType: React.PropTypes.string,
|
||||||
|
teamDisplayName: React.PropTypes.string
|
||||||
|
},
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
ChannelStore.addChangeListener(this.onChange);
|
ChannelStore.addChangeListener(this.onChange);
|
||||||
UserStore.addChangeListener(this.onChange);
|
UserStore.addChangeListener(this.onChange);
|
||||||
@@ -244,17 +247,17 @@ module.exports = React.createClass({
|
|||||||
var channel = ChannelStore.getCurrent();
|
var channel = ChannelStore.getCurrent();
|
||||||
if (channel) {
|
if (channel) {
|
||||||
if (channel.type === 'D') {
|
if (channel.type === 'D') {
|
||||||
var teammate_username = utils.getDirectTeammate(channel.id).username;
|
var teammateUsername = utils.getDirectTeammate(channel.id).username;
|
||||||
document.title = teammate_username + ' ' + document.title.substring(document.title.lastIndexOf('-'));
|
document.title = teammateUsername + ' ' + document.title.substring(document.title.lastIndexOf('-'));
|
||||||
} else {
|
} else {
|
||||||
document.title = channel.display_name + ' ' + document.title.substring(document.title.lastIndexOf('-'));
|
document.title = channel.display_name + ' ' + document.title.substring(document.title.lastIndexOf('-'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onScroll: function(e) {
|
onScroll: function() {
|
||||||
this.updateUnreadIndicators();
|
this.updateUnreadIndicators();
|
||||||
},
|
},
|
||||||
onResize: function(e) {
|
onResize: function() {
|
||||||
this.updateUnreadIndicators();
|
this.updateUnreadIndicators();
|
||||||
},
|
},
|
||||||
updateUnreadIndicators: function() {
|
updateUnreadIndicators: function() {
|
||||||
@@ -282,7 +285,10 @@ module.exports = React.createClass({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return getStateFromStores();
|
var newState = getStateFromStores();
|
||||||
|
newState.loadingDMChannel = -1;
|
||||||
|
|
||||||
|
return newState;
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
var members = this.state.members;
|
var members = this.state.members;
|
||||||
@@ -294,8 +300,9 @@ module.exports = React.createClass({
|
|||||||
this.firstUnreadChannel = null;
|
this.firstUnreadChannel = null;
|
||||||
this.lastUnreadChannel = null;
|
this.lastUnreadChannel = null;
|
||||||
|
|
||||||
function createChannelElement(channel) {
|
function createChannelElement(channel, index) {
|
||||||
var channelMember = members[channel.id];
|
var channelMember = members[channel.id];
|
||||||
|
var msgCount;
|
||||||
|
|
||||||
var linkClass = '';
|
var linkClass = '';
|
||||||
if (channel.id === activeId) {
|
if (channel.id === activeId) {
|
||||||
@@ -304,7 +311,7 @@ module.exports = React.createClass({
|
|||||||
|
|
||||||
var unread = false;
|
var unread = false;
|
||||||
if (channelMember) {
|
if (channelMember) {
|
||||||
var msgCount = channel.total_msg_count - channelMember.msg_count;
|
msgCount = channel.total_msg_count - channelMember.msg_count;
|
||||||
unread = (msgCount > 0 && channelMember.notify_level !== 'quiet') || channelMember.mention_count > 0;
|
unread = (msgCount > 0 && channelMember.notify_level !== 'quiet') || channelMember.mention_count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +329,7 @@ module.exports = React.createClass({
|
|||||||
if (channelMember) {
|
if (channelMember) {
|
||||||
if (channel.type === 'D') {
|
if (channel.type === 'D') {
|
||||||
// direct message channels show badges for any number of unread posts
|
// direct message channels show badges for any number of unread posts
|
||||||
var msgCount = channel.total_msg_count - channelMember.msg_count;
|
msgCount = channel.total_msg_count - channelMember.msg_count;
|
||||||
if (msgCount > 0) {
|
if (msgCount > 0) {
|
||||||
badge = <span className='badge pull-right small'>{msgCount}</span>;
|
badge = <span className='badge pull-right small'>{msgCount}</span>;
|
||||||
badgesActive = true;
|
badgesActive = true;
|
||||||
@@ -332,6 +339,8 @@ module.exports = React.createClass({
|
|||||||
badge = <span className='badge pull-right small'>{channelMember.mention_count}</span>;
|
badge = <span className='badge pull-right small'>{channelMember.mention_count}</span>;
|
||||||
badgesActive = true;
|
badgesActive = true;
|
||||||
}
|
}
|
||||||
|
} else if (self.state.loadingDMChannel === index && channel.type === 'D') {
|
||||||
|
badge = <img className='channel-loading-gif pull-right' src='/static/images/load.gif'/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set up status icon for direct message channels
|
// set up status icon for direct message channels
|
||||||
@@ -349,39 +358,59 @@ module.exports = React.createClass({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set up click handler to switch channels (or create a new channel for non-existant ones)
|
// set up click handler to switch channels (or create a new channel for non-existant ones)
|
||||||
var clickHandler = null;
|
var handleClick = null;
|
||||||
var href = '#';
|
var href = '#';
|
||||||
var teamURL = TeamStore.getCurrentTeamUrl();
|
var teamURL = TeamStore.getCurrentTeamUrl();
|
||||||
|
|
||||||
if (!channel.fake) {
|
if (!channel.fake) {
|
||||||
clickHandler = function(e) {
|
handleClick = function clickHandler(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
utils.switchChannel(channel);
|
utils.switchChannel(channel);
|
||||||
};
|
};
|
||||||
}
|
} else if (channel.fake && teamURL) {
|
||||||
if (channel.fake && teamURL){
|
// It's a direct message channel that doesn't exist yet so let's create it now
|
||||||
href = teamURL + '/channels/' + channel.name;
|
var otherUserId = utils.getUserIdFromChannelName(channel);
|
||||||
|
|
||||||
|
if (self.state.loadingDMChannel === -1) {
|
||||||
|
handleClick = function clickHandler(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
self.setState({loadingDMChannel: index});
|
||||||
|
|
||||||
|
Client.createDirectChannel(channel, otherUserId,
|
||||||
|
function success(data) {
|
||||||
|
self.setState({loadingDMChannel: -1});
|
||||||
|
AsyncClient.getChannel(data.id);
|
||||||
|
utils.switchChannel(data);
|
||||||
|
},
|
||||||
|
function error() {
|
||||||
|
self.setState({loadingDMChannel: -1});
|
||||||
|
window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/' + channel.name;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li key={channel.name} ref={channel.name} className={linkClass}>
|
<li key={channel.name} ref={channel.name} className={linkClass}>
|
||||||
<a className={'sidebar-channel ' + titleClass} href={href} onClick={clickHandler}>
|
<a className={'sidebar-channel ' + titleClass} href={href} onClick={handleClick}>
|
||||||
{status}
|
{status}
|
||||||
{channel.display_name}
|
{channel.display_name}
|
||||||
{badge}
|
{badge}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
// create elements for all 3 types of channels
|
// create elements for all 3 types of channels
|
||||||
var channelItems = this.state.channels.filter(
|
var channelItems = this.state.channels.filter(
|
||||||
function(channel) {
|
function filterPublicChannels(channel) {
|
||||||
return channel.type === 'O';
|
return channel.type === 'O';
|
||||||
}
|
}
|
||||||
).map(createChannelElement);
|
).map(createChannelElement);
|
||||||
|
|
||||||
var privateChannelItems = this.state.channels.filter(
|
var privateChannelItems = this.state.channels.filter(
|
||||||
function(channel) {
|
function filterPrivateChannels(channel) {
|
||||||
return channel.type === 'P';
|
return channel.type === 'P';
|
||||||
}
|
}
|
||||||
).map(createChannelElement);
|
).map(createChannelElement);
|
||||||
@@ -410,7 +439,7 @@ module.exports = React.createClass({
|
|||||||
directMessageMore = (
|
directMessageMore = (
|
||||||
<li>
|
<li>
|
||||||
<a href='#' data-toggle='modal' className='nav-more' data-target='#more_direct_channels' data-channels={JSON.stringify(this.state.hideDirectChannels)}>
|
<a href='#' data-toggle='modal' className='nav-more' data-target='#more_direct_channels' data-channels={JSON.stringify(this.state.hideDirectChannels)}>
|
||||||
{'More ('+this.state.hideDirectChannels.length+')'}
|
{'More (' + this.state.hideDirectChannels.length + ')'}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -438,6 +438,23 @@ module.exports.createChannel = function(channel, success, error) {
|
|||||||
module.exports.track('api', 'api_channels_create', channel.type, 'name', channel.name);
|
module.exports.track('api', 'api_channels_create', channel.type, 'name', channel.name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports.createDirectChannel = function(channel, userId, success, error) {
|
||||||
|
$.ajax({
|
||||||
|
url: '/api/v1/channels/create_direct',
|
||||||
|
dataType: 'json',
|
||||||
|
contentType: 'application/json',
|
||||||
|
type: 'POST',
|
||||||
|
data: JSON.stringify({user_id: userId}),
|
||||||
|
success: success,
|
||||||
|
error: function(xhr, status, err) {
|
||||||
|
var e = handleError('createDirectChannel', xhr, status, err);
|
||||||
|
error(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports.track('api', 'api_channels_create_direct', channel.type, 'name', channel.name);
|
||||||
|
};
|
||||||
|
|
||||||
module.exports.updateChannel = function(channel, success, error) {
|
module.exports.updateChannel = function(channel, success, error) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "/api/v1/channels/update",
|
url: "/api/v1/channels/update",
|
||||||
|
|||||||
@@ -968,4 +968,17 @@ module.exports.generateId = function() {
|
|||||||
|
|
||||||
module.exports.isBrowserFirefox = function() {
|
module.exports.isBrowserFirefox = function() {
|
||||||
return navigator && navigator.userAgent && navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
return navigator && navigator.userAgent && navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// Used to get the id of the other user from a DM channel
|
||||||
|
module.exports.getUserIdFromChannelName = function(channel) {
|
||||||
|
var ids = channel.name.split('__');
|
||||||
|
var otherUserId = '';
|
||||||
|
if (ids[0] === UserStore.getCurrentId()) {
|
||||||
|
otherUserId = ids[1];
|
||||||
|
} else {
|
||||||
|
otherUserId = ids[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return otherUserId;
|
||||||
|
};
|
||||||
|
|||||||
@@ -122,3 +122,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.channel-loading-gif {
|
||||||
|
height:15px;
|
||||||
|
width:15px;
|
||||||
|
margin-top:2px;
|
||||||
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user