diff options
Diffstat (limited to 'web/react/components')
-rw-r--r-- | web/react/components/sidebar.jsx | 89 | ||||
-rw-r--r-- | web/react/components/unread_channel_indicators.jsx | 93 |
2 files changed, 112 insertions, 70 deletions
diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index 370250e4a..a16a0a8bb 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -11,6 +11,7 @@ var BrowserStore = require('../stores/browser_store.jsx'); var Utils = require('../utils/utils.jsx'); var SidebarHeader = require('./sidebar_header.jsx'); var SearchBox = require('./search_bar.jsx'); +var UnreadChannelIndicators = require('./unread_channel_indicators.jsx'); var Constants = require('../utils/constants.jsx'); var NewChannelFlow = require('./new_channel_flow.jsx'); @@ -19,13 +20,10 @@ export default class Sidebar extends React.Component { super(props); this.badgesActive = false; - this.firstUnreadChannel = null; - this.lastUnreadChannel = null; this.onChange = this.onChange.bind(this); this.onScroll = this.onScroll.bind(this); this.onResize = this.onResize.bind(this); - this.updateUnreadIndicators = this.updateUnreadIndicators.bind(this); this.createChannelElement = this.createChannelElement.bind(this); this.state = this.getStateFromStores(); @@ -149,13 +147,13 @@ export default class Sidebar extends React.Component { $('.nav-pills__container').perfectScrollbar(); this.updateTitle(); - this.updateUnreadIndicators(); + this.refs.unreadIndicators.onParentUpdate(this.refs); $(window).on('resize', this.onResize); } componentDidUpdate() { this.updateTitle(); - this.updateUnreadIndicators(); + this.refs.unreadIndicators.onParentUpdate(this.refs); } componentWillUnmount() { $(window).off('resize', this.onResize); @@ -268,41 +266,12 @@ export default class Sidebar extends React.Component { } } onScroll() { - this.updateUnreadIndicators(); + this.refs.unreadIndicators.onParentUpdate(this.refs); } onResize() { - this.updateUnreadIndicators(); + this.refs.unreadIndicators.onParentUpdate(this.refs); } - updateUnreadIndicators() { - const container = $(React.findDOMNode(this.refs.container)); - const topUnreadIndicator = $(React.findDOMNode(this.refs.topUnreadIndicator)); - const bottomUnreadIndicator = $(React.findDOMNode(this.refs.bottomUnreadIndicator)); - - if (this.firstUnreadChannel) { - var firstUnreadElement = $(React.findDOMNode(this.refs[this.firstUnreadChannel])); - - if (firstUnreadElement.position().top + firstUnreadElement.height() < 0) { - topUnreadIndicator.css('display', 'initial'); - } else { - topUnreadIndicator.css('display', 'none'); - } - } else { - topUnreadIndicator.css('display', 'none'); - } - - if (this.lastUnreadChannel) { - var lastUnreadElement = $(React.findDOMNode(this.refs[this.lastUnreadChannel])); - - if (lastUnreadElement.position().top > container.height()) { - bottomUnreadIndicator.css('display', 'initial'); - } else { - bottomUnreadIndicator.css('display', 'none'); - } - } else { - bottomUnreadIndicator.css('display', 'none'); - } - } - createChannelElement(channel, index) { + createChannelElement(unreadChannels, channel, index) { var members = this.state.members; var activeId = this.state.activeId; var channelMember = members[channel.id]; @@ -324,10 +293,7 @@ export default class Sidebar extends React.Component { titleClass = 'unread-title'; if (channel.id !== activeId) { - if (!this.firstUnreadChannel) { - this.firstUnreadChannel = channel.name; - } - this.lastUnreadChannel = channel.name; + unreadChannels.push(channel); } } @@ -433,24 +399,17 @@ export default class Sidebar extends React.Component { render() { this.badgesActive = false; - // keep track of the first and last unread channels so we can use them to set the unread indicators - this.firstUnreadChannel = null; - this.lastUnreadChannel = null; + // keep track of unread channels so we can use them to set the unread indicators + const unreadChannels = []; // create elements for all 3 types of channels - var channelItems = this.state.channels.filter( - function filterPublicChannels(channel) { - return channel.type === 'O'; - } - ).map(this.createChannelElement); + const publicChannels = this.state.channels.filter((channel) => channel.type === 'O'); + const publicChannelItems = publicChannels.map(this.createChannelElement.bind(this, unreadChannels)); - var privateChannelItems = this.state.channels.filter( - function filterPrivateChannels(channel) { - return channel.type === 'P'; - } - ).map(this.createChannelElement); + const privateChannels = this.state.channels.filter((channel) => channel.type === 'P'); + const privateChannelItems = privateChannels.map(this.createChannelElement.bind(this, unreadChannels)); - var directMessageItems = this.state.showDirectChannels.map(this.createChannelElement); + const directMessageItems = this.state.showDirectChannels.map(this.createChannelElement.bind(this, unreadChannels)); // update the favicon to show if there are any notifications var link = document.createElement('link'); @@ -504,20 +463,10 @@ export default class Sidebar extends React.Component { /> <SearchBox /> - <div - ref='topUnreadIndicator' - className='nav-pills__unread-indicator nav-pills__unread-indicator-top' - style={{display: 'none'}} - > - Unread post(s) above - </div> - <div - ref='bottomUnreadIndicator' - className='nav-pills__unread-indicator nav-pills__unread-indicator-bottom' - style={{display: 'none'}} - > - Unread post(s) below - </div> + <UnreadChannelIndicators + ref='unreadIndicators' + unreadChannels={unreadChannels} + /> <div ref='container' @@ -537,7 +486,7 @@ export default class Sidebar extends React.Component { </a> </h4> </li> - {channelItems} + {publicChannelItems} <li> <a href='#' diff --git a/web/react/components/unread_channel_indicators.jsx b/web/react/components/unread_channel_indicators.jsx new file mode 100644 index 000000000..852e0dbb7 --- /dev/null +++ b/web/react/components/unread_channel_indicators.jsx @@ -0,0 +1,93 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +// Indicators for the left sidebar which indicate if there's unread posts in a channel that is not shown +// because it is either above or below the screen +export default class UnreadChannelIndicators extends React.Component { + constructor(props) { + super(props); + + this.getFirstLastUnreadChannels = this.getFirstLastUnreadChannels.bind(this); + this.onParentUpdate = this.onParentUpdate.bind(this); + + this.state = this.getFirstLastUnreadChannels(props); + } + + getFirstLastUnreadChannels(props) { + let firstUnreadChannel = null; + let lastUnreadChannel = null; + + for (const unreadChannel of props.unreadChannels) { + if (!firstUnreadChannel) { + firstUnreadChannel = unreadChannel; + } + lastUnreadChannel = unreadChannel; + } + + return { + firstUnreadChannel, + lastUnreadChannel + }; + } + + onParentUpdate(parentRefs) { + const container = $(React.findDOMNode(parentRefs.container)); + const topUnreadIndicator = $(React.findDOMNode(this.refs.topIndicator)); + const bottomUnreadIndicator = $(React.findDOMNode(this.refs.bottomIndicator)); + + if (this.state.firstUnreadChannel) { + var firstUnreadElement = $(React.findDOMNode(parentRefs[this.state.firstUnreadChannel.name])); + + if (firstUnreadElement.position().top + firstUnreadElement.height() < 0) { + topUnreadIndicator.css('display', 'initial'); + } else { + topUnreadIndicator.css('display', 'none'); + } + } else { + topUnreadIndicator.css('display', 'none'); + } + + if (this.state.lastUnreadChannel) { + var lastUnreadElement = $(React.findDOMNode(parentRefs[this.state.lastUnreadChannel.name])); + + if (lastUnreadElement.position().top > container.height()) { + bottomUnreadIndicator.css('display', 'initial'); + } else { + bottomUnreadIndicator.css('display', 'none'); + } + } else { + bottomUnreadIndicator.css('display', 'none'); + } + } + + componentWillReceiveProps(nextProps) { + this.setState(this.getFirstLastUnreadChannels(nextProps)); + } + + render() { + return ( + <div> + <div + ref='topIndicator' + className='nav-pills__unread-indicator nav-pills__unread-indicator-top' + style={{display: 'none'}} + > + {'Unread post(s) above'} + </div> + <div + ref='bottomIndicator' + className='nav-pills__unread-indicator nav-pills__unread-indicator-bottom' + style={{display: 'none'}} + > + {'Unread post(s) below'} + </div> + </div> + ); + } +} + +UnreadChannelIndicators.propTypes = { + + // a list of the unread channels displayed in the parent + unreadChannels: React.PropTypes.array.isRequired +}; |