diff --git a/web/react/components/edit_channel_purpose_modal.jsx b/web/react/components/edit_channel_purpose_modal.jsx index 4cb96a3ff0..65e8183de8 100644 --- a/web/react/components/edit_channel_purpose_modal.jsx +++ b/web/react/components/edit_channel_purpose_modal.jsx @@ -3,6 +3,8 @@ const AsyncClient = require('../utils/async_client.jsx'); const Client = require('../utils/client.jsx'); +const Utils = require('../utils/utils.jsx'); + const Modal = ReactBootstrap.Modal; export default class EditChannelPurposeModal extends React.Component { @@ -75,11 +77,6 @@ export default class EditChannelPurposeModal extends React.Component { title = {'Edit Purpose for '}{this.props.channel.display_name}; } - let channelTerm = 'Channel'; - if (this.props.channel.channelType === 'P') { - channelTerm = 'Group'; - } - return ( - {`Describe how this ${channelTerm} should be used.`} + {`Describe how this ${Utils.getChannelTerm(this.props.channel.channelType)} should be used.`} 0)) { this.setState({ @@ -111,15 +126,7 @@ export default class SearchAutocomplete extends React.Component { } else if (e.which === KeyCodes.ENTER || e.which === KeyCodes.SPACE) { e.preventDefault(); - this.completeSelectedWord(); - } - } - - completeSelectedWord() { - if (this.state.mode === 'channels') { - this.completeWord(this.state.suggestions[this.state.selection].name); - } else if (this.state.mode === 'users') { - this.completeWord(this.state.suggestions[this.state.selection].username); + this.completeWord(this.getSelection()); } } @@ -135,6 +142,40 @@ export default class SearchAutocomplete extends React.Component { }); } + getSelection() { + if (this.state.mode === 'channels') { + return this.state.suggestions[this.state.selection].name; + } else if (this.state.mode === 'users') { + return this.state.suggestions[this.state.selection].username; + } + + return ''; + } + + scrollToItem(itemName) { + const content = $(ReactDOM.findDOMNode(this.refs.searchPopover)).find('.popover-content'); + const visibleContentHeight = content[0].clientHeight; + const actualContentHeight = content[0].scrollHeight; + + if (this.state.suggestions.length > 0 && visibleContentHeight < actualContentHeight) { + const contentTop = content.scrollTop(); + const contentTopPadding = parseInt(content.css('padding-top'), 10); + const contentBottomPadding = parseInt(content.css('padding-top'), 10); + + const item = $(this.refs[itemName]); + const itemTop = item[0].offsetTop - parseInt(item.css('margin-top'), 10); + const itemBottom = item[0].offsetTop + item.height() + parseInt(item.css('margin-bottom'), 10); + + if (itemTop - contentTopPadding < contentTop) { + // the item is off the top of the visible space + content.scrollTop(itemTop - contentTopPadding); + } else if (itemBottom + contentTopPadding + contentBottomPadding > contentTop + visibleContentHeight) { + // the item has gone off the bottom of the visible space + content.scrollTop(itemBottom - visibleContentHeight + contentTopPadding + contentBottomPadding); + } + } + } + updateSuggestions(mode, filter) { let suggestions = []; @@ -193,6 +234,46 @@ export default class SearchAutocomplete extends React.Component { }); } + renderChannelSuggestion(channel) { + let className = 'search-autocomplete__item'; + if (channel.name === this.getSelection()) { + className += ' selected'; + } + + return ( + + {channel.name} + + ); + } + + renderUserSuggestion(user) { + let className = 'search-autocomplete__item'; + if (user.username === this.getSelection()) { + className += ' selected'; + } + + return ( + + + {user.username} + + ); + } + render() { if (!this.state.show || this.state.suggestions.length === 0) { return null; @@ -201,45 +282,33 @@ export default class SearchAutocomplete extends React.Component { let suggestions = []; if (this.state.mode === 'channels') { - suggestions = this.state.suggestions.map((channel, index) => { - let className = 'search-autocomplete__item'; - if (this.state.selection === index) { - className += ' selected'; - } - - return ( + const publicChannels = this.state.suggestions.filter((channel) => channel.type === Constants.OPEN_CHANNEL); + if (publicChannels.length > 0) { + suggestions.push( - {channel.name} + {'Public ' + Utils.getChannelTerm(Constants.OPEN_CHANNEL) + 's'} ); - }); + suggestions = suggestions.concat(publicChannels.map(this.renderChannelSuggestion)); + } + + const privateChannels = this.state.suggestions.filter((channel) => channel.type === Constants.PRIVATE_CHANNEL); + if (privateChannels.length > 0) { + suggestions.push( + + {'Private ' + Utils.getChannelTerm(Constants.PRIVATE_CHANNEL) + 's'} + + ); + suggestions = suggestions.concat(privateChannels.map(this.renderChannelSuggestion)); + } } else if (this.state.mode === 'users') { - suggestions = this.state.suggestions.map((user, index) => { - let className = 'search-autocomplete__item'; - if (this.state.selection === index) { - className += ' selected'; - } - - return ( - - - {user.username} - - ); - }); + suggestions = this.state.suggestions.map(this.renderUserSuggestion); } return ( diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 9ce7ca1e8b..5a3000dffa 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -1129,3 +1129,12 @@ export function sortByDisplayName(a, b) { } return 0; } + +export function getChannelTerm(channelType) { + let channelTerm = 'Channel'; + if (channelType === Constants.PRIVATE_CHANNEL) { + channelTerm = 'Group'; + } + + return channelTerm; +}
{`Describe how this ${channelTerm} should be used.`}
{`Describe how this ${Utils.getChannelTerm(this.props.channel.channelType)} should be used.`}