diff options
Diffstat (limited to 'web/react/components/channel_header.jsx')
-rw-r--r-- | web/react/components/channel_header.jsx | 436 |
1 files changed, 281 insertions, 155 deletions
diff --git a/web/react/components/channel_header.jsx b/web/react/components/channel_header.jsx index 0254d0e82..87b9cab04 100644 --- a/web/react/components/channel_header.jsx +++ b/web/react/components/channel_header.jsx @@ -1,139 +1,85 @@ // Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. // See License.txt for license information. -var ChannelStore = require('../stores/channel_store.jsx'); -var UserStore = require('../stores/user_store.jsx'); -var PostStore = require('../stores/post_store.jsx'); -var SocketStore = require('../stores/socket_store.jsx'); -var NavbarSearchBox = require('./search_bar.jsx'); -var AsyncClient = require('../utils/async_client.jsx'); -var Client = require('../utils/client.jsx'); -var utils = require('../utils/utils.jsx'); -var MessageWrapper = require('./message_wrapper.jsx'); - -var AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); -var Constants = require('../utils/constants.jsx'); -var ActionTypes = Constants.ActionTypes; - -var PopoverListMembers = React.createClass({ - componentDidMount: function() { - var originalLeave = $.fn.popover.Constructor.prototype.leave; - $.fn.popover.Constructor.prototype.leave = function(obj) { - var selfObj; - if (obj instanceof this.constructor) { - selfObj = obj; - } else { - selfObj = $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type); - } - originalLeave.call(this, obj); - - if (obj.currentTarget && selfObj.$tip) { - selfObj.$tip.one('mouseenter', function() { - clearTimeout(selfObj.timeout); - selfObj.$tip.one('mouseleave', function() { - $.fn.popover.Constructor.prototype.leave.call(selfObj, selfObj); - }); - }); - } - }; +const ChannelStore = require('../stores/channel_store.jsx'); +const UserStore = require('../stores/user_store.jsx'); +const PostStore = require('../stores/post_store.jsx'); +const SocketStore = require('../stores/socket_store.jsx'); +const NavbarSearchBox = require('./search_bar.jsx'); +const AsyncClient = require('../utils/async_client.jsx'); +const Client = require('../utils/client.jsx'); +const Utils = require('../utils/utils.jsx'); +const MessageWrapper = require('./message_wrapper.jsx'); +const PopoverListMembers = require('./popover_list_members.jsx'); - $('#member_popover').popover({placement: 'bottom', trigger: 'click', html: true}); - $('body').on('click', function(e) { - if ($(e.target.parentNode.parentNode)[0] !== $('#member_popover')[0] && $(e.target).parents('.popover.in').length === 0) { - $('#member_popover').popover('hide'); - } - }); - }, - - render: function() { - var popoverHtml = ''; - var members = this.props.members; - var count; - if (members.length > 20) { - count = '20+'; - } else { - count = members.length || '-'; - } +const AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); +const Constants = require('../utils/constants.jsx'); +const ActionTypes = Constants.ActionTypes; - if (members) { - members.sort(function(a, b) { - return a.username.localeCompare(b.username); - }); +export default class ChannelHeader extends React.Component { + constructor(props) { + super(props); - members.forEach(function(m) { - popoverHtml += "<div class='text--nowrap'>" + m.username + '</div>'; - }); - } + this.onListenerChange = this.onListenerChange.bind(this); + this.onSocketChange = this.onSocketChange.bind(this); + this.handleLeave = this.handleLeave.bind(this); + this.searchMentions = this.searchMentions.bind(this); - return ( - <div id='member_popover' data-toggle='popover' data-content={popoverHtml} data-original-title='Members' > - <div id='member_tooltip' data-placement='left' data-toggle='tooltip' title='View Channel Members'> - {count} <span className='glyphicon glyphicon-user' aria-hidden='true'></span> - </div> - </div> - ); + this.state = this.getStateFromStores(); } -}); - -function getStateFromStores() { - return { - channel: ChannelStore.getCurrent(), - memberChannel: ChannelStore.getCurrentMember(), - memberTeam: UserStore.getCurrentUser(), - users: ChannelStore.getCurrentExtraInfo().members, - searchVisible: PostStore.getSearchResults() != null - }; -} - -module.exports = React.createClass({ - displayName: 'ChannelHeader', - componentDidMount: function() { + getStateFromStores() { + return { + channel: ChannelStore.getCurrent(), + memberChannel: ChannelStore.getCurrentMember(), + memberTeam: UserStore.getCurrentUser(), + users: ChannelStore.getCurrentExtraInfo().members, + searchVisible: PostStore.getSearchResults() !== null + }; + } + componentDidMount() { ChannelStore.addChangeListener(this.onListenerChange); ChannelStore.addExtraInfoChangeListener(this.onListenerChange); PostStore.addSearchChangeListener(this.onListenerChange); UserStore.addChangeListener(this.onListenerChange); SocketStore.addChangeListener(this.onSocketChange); - }, - componentWillUnmount: function() { + } + componentWillUnmount() { ChannelStore.removeChangeListener(this.onListenerChange); ChannelStore.removeExtraInfoChangeListener(this.onListenerChange); PostStore.removeSearchChangeListener(this.onListenerChange); UserStore.addChangeListener(this.onListenerChange); - }, - onListenerChange: function() { - var newState = getStateFromStores(); - if (!utils.areStatesEqual(newState, this.state)) { + } + onListenerChange() { + const newState = this.getStateFromStores(); + if (!Utils.areStatesEqual(newState, this.state)) { this.setState(newState); } $('.channel-header__info .description').popover({placement: 'bottom', trigger: 'hover click', html: true, delay: {show: 500, hide: 500}}); - }, - onSocketChange: function(msg) { + } + onSocketChange(msg) { if (msg.action === 'new_user') { AsyncClient.getChannelExtraInfo(true); } - }, - getInitialState: function() { - return getStateFromStores(); - }, - handleLeave: function() { + } + handleLeave() { Client.leaveChannel(this.state.channel.id, - function() { - var townsquare = ChannelStore.getByName('town-square'); - utils.switchChannel(townsquare); + function handleLeaveSuccess() { + const townsquare = ChannelStore.getByName('town-square'); + Utils.switchChannel(townsquare); }, - function(err) { + function handleLeaveError(err) { AsyncClient.dispatchError(err, 'handleLeave'); } ); - }, - searchMentions: function(e) { + } + searchMentions(e) { e.preventDefault(); - var user = UserStore.getCurrentUser(); + const user = UserStore.getCurrentUser(); - var terms = ''; + let terms = ''; if (user.notify_props && user.notify_props.mention_keys) { - var termKeys = UserStore.getCurrentMentionKeys(); + let termKeys = UserStore.getCurrentMentionKeys(); if (user.notify_props.all === 'true' && termKeys.indexOf('@all') !== -1) { termKeys.splice(termKeys.indexOf('@all'), 1); } @@ -149,23 +95,23 @@ module.exports = React.createClass({ do_search: true, is_mention_search: true }); - }, - render: function() { - if (this.state.channel == null) { + } + render() { + if (this.state.channel === null) { return null; } - var channel = this.state.channel; - var description = utils.textToJsx(channel.description, {singleline: true, noMentionHighlight: true}); - var popoverContent = React.renderToString(<MessageWrapper message={channel.description}/>); - var channelTitle = channel.display_name; - var currentId = UserStore.getCurrentId(); - var isAdmin = this.state.memberChannel.roles.indexOf('admin') > -1 || this.state.memberTeam.roles.indexOf('admin') > -1; - var isDirect = (this.state.channel.type === 'D'); + const channel = this.state.channel; + const description = Utils.textToJsx(channel.description, {singleline: true, noMentionHighlight: true}); + const popoverContent = React.renderToString(<MessageWrapper message={channel.description}/>); + let channelTitle = channel.display_name; + const currentId = UserStore.getCurrentId(); + const isAdmin = this.state.memberChannel.roles.indexOf('admin') > -1 || this.state.memberTeam.roles.indexOf('admin') > -1; + const isDirect = (this.state.channel.type === 'D'); if (isDirect) { if (this.state.users.length > 1) { - var contact; + let contact; if (this.state.users[0].id === currentId) { contact = this.state.users[1]; } else { @@ -175,64 +121,244 @@ module.exports = React.createClass({ } } - var channelTerm = 'Channel'; + let channelTerm = 'Channel'; if (channel.type === 'P') { channelTerm = 'Group'; } + let dropdownContents = []; + if (!isDirect) { + dropdownContents.push( + <li + key='view_info' + role='presentation' + > + <a + role='menuitem' + data-toggle='modal' + data-target='#channel_info' + data-channelid={channel.id} + href='#' + > + View Info + </a> + </li> + ); + + if (!ChannelStore.isDefault(channel)) { + dropdownContents.push( + <li + key='add_members' + role='presentation' + > + <a + role='menuitem' + data-toggle='modal' + data-target='#channel_invite' + href='#' + > + Add Members + </a> + </li> + ); + + if (isAdmin) { + dropdownContents.push( + <li + key='manage_members' + role='presentation' + > + <a + role='menuitem' + data-toggle='modal' + data-target='#channel_members' + href='#' + > + Manage Members + </a> + </li> + ); + } + } + + dropdownContents.push( + <li + key='set_channel_description' + role='presentation' + > + <a + role='menuitem' + href='#' + data-toggle='modal' + data-target='#edit_channel' + data-desc={channel.description} + data-title={channel.display_name} + data-channelid={channel.id} + > + Set {channelTerm} Description... + </a> + </li> + ); + dropdownContents.push( + <li + key='notification_preferences' + role='presentation' + > + <a + role='menuitem' + href='#' + data-toggle='modal' + data-target='#channel_notifications' + data-title={channel.display_name} + data-channelid={channel.id} + > + Notification Preferences + </a> + </li> + ); + + if (!ChannelStore.isDefault(channel)) { + if (isAdmin) { + dropdownContents.push( + <li + key='rename_channel' + role='presentation' + > + <a + role='menuitem' + href='#' + data-toggle='modal' + data-target='#rename_channel' + data-display={channel.display_name} + data-name={channel.name} + data-channelid={channel.id} + > + Rename {channelTerm}... + </a> + </li> + ); + dropdownContents.push( + <li + key='delete_channel' + role='presentation' + > + <a + role='menuitem' + href='#' + data-toggle='modal' + data-target='#delete_channel' + data-title={channel.display_name} + data-channelid={channel.id} + > + Delete {channelTerm}... + </a> + </li> + ); + } + + dropdownContents.push( + <li + key='leave_channel' + role='presentation' + > + <a + role='menuitem' + href='#' + onClick={this.handleLeave} + > + Leave {channelTerm} + </a> + </li> + ); + } + } else { + dropdownContents.push( + <li + key='edit_description_direct' + role='presentation' + > + <a + role='menuitem' + href='#' + data-toggle='modal' + data-target='#edit_channel' + data-desc={channel.description} + data-title={channel.display_name} + data-channelid={channel.id} + > + Set Channel Description... + </a> + </li> + ); + } + return ( <table className='channel-header alt'> <tr> <th> <div className='channel-header__info'> <div className='dropdown'> - <a href='#' className='dropdown-toggle theme' type='button' id='channel_header_dropdown' data-toggle='dropdown' aria-expanded='true'> + <a + href='#' + className='dropdown-toggle theme' + type='button' + id='channel_header_dropdown' + data-toggle='dropdown' + aria-expanded='true' + > <strong className='heading'>{channelTitle} </strong> - <span className='glyphicon glyphicon-chevron-down header-dropdown__icon'></span> + <span className='glyphicon glyphicon-chevron-down header-dropdown__icon' /> </a> - {!isDirect ? - <ul className='dropdown-menu' role='menu' aria-labelledby='channel_header_dropdown'> - <li role='presentation'><a role='menuitem' data-toggle='modal' data-target='#channel_info' data-channelid={channel.id} href='#'>View Info</a></li> - {!ChannelStore.isDefault(channel) ? - <li role='presentation'><a role='menuitem' data-toggle='modal' data-target='#channel_invite' href='#'>Add Members</a></li> - : null - } - {isAdmin && !ChannelStore.isDefault(channel) ? - <li role='presentation'><a role='menuitem' data-toggle='modal' data-target='#channel_members' href='#'>Manage Members</a></li> - : null - } - <li role='presentation'><a role='menuitem' href='#' data-toggle='modal' data-target='#edit_channel' data-desc={channel.description} data-title={channel.display_name} data-channelid={channel.id}>Set {channelTerm} Description...</a></li> - <li role='presentation'><a role='menuitem' href='#' data-toggle='modal' data-target='#channel_notifications' data-title={channel.display_name} data-channelid={channel.id}>Notification Preferences</a></li> - {isAdmin && !ChannelStore.isDefault(channel) ? - <li role='presentation'><a role='menuitem' href='#' data-toggle='modal' data-target='#rename_channel' data-display={channel.display_name} data-name={channel.name} data-channelid={channel.id}>Rename {channelTerm}...</a></li> - : null - } - {isAdmin && !ChannelStore.isDefault(channel) ? - <li role='presentation'><a role='menuitem' href='#' data-toggle='modal' data-target='#delete_channel' data-title={channel.display_name} data-channelid={channel.id}>Delete {channelTerm}...</a></li> - : null - } - {!ChannelStore.isDefault(channel) ? - <li role='presentation'><a role='menuitem' href='#' onClick={this.handleLeave}>Leave {channelTerm}</a></li> - : null - } - </ul> - : - <ul className='dropdown-menu' role='menu' aria-labelledby='channel_header_dropdown'> - <li role='presentation'><a role='menuitem' href='#' data-toggle='modal' data-target='#edit_channel' data-desc={channel.description} data-title={channel.display_name} data-channelid={channel.id}>Set Channel Description...</a></li> + <ul + className='dropdown-menu' + role='menu' + aria-labelledby='channel_header_dropdown' + > + {dropdownContents} </ul> - } </div> - <div data-toggle='popover' data-content={popoverContent} className='description'>{description}</div> + <div + data-toggle='popover' + data-content={popoverContent} + className='description' + > + {description} + </div> </div> </th> - <th><PopoverListMembers members={this.state.users} channelId={channel.id} /></th> + <th> + <PopoverListMembers + members={this.state.users} + channelId={channel.id} + /> + </th> <th className='search-bar__container'><NavbarSearchBox /></th> <th> <div className='dropdown channel-header__links'> - <a href='#' className='dropdown-toggle theme' type='button' id='channel_header_right_dropdown' data-toggle='dropdown' aria-expanded='true'> - <span dangerouslySetInnerHTML={{__html: Constants.MENU_ICON}} /> </a> - <ul className='dropdown-menu dropdown-menu-right' role='menu' aria-labelledby='channel_header_right_dropdown'> - <li role='presentation'><a role='menuitem' href='#' onClick={this.searchMentions}>Recent Mentions</a></li> + <a + href='#' + className='dropdown-toggle theme' + type='button' + id='channel_header_right_dropdown' + data-toggle='dropdown' + aria-expanded='true' + > + <span dangerouslySetInnerHTML={{__html: Constants.MENU_ICON}} /> + </a> + <ul + className='dropdown-menu dropdown-menu-right' + role='menu' + aria-labelledby='channel_header_right_dropdown' + > + <li role='presentation'> + <a + role='menuitem' + href='#' + onClick={this.searchMentions} + > + Recent Mentions + </a> + </li> </ul> </div> </th> @@ -240,4 +366,4 @@ module.exports = React.createClass({ </table> ); } -}); +} |