From 8d0c69aec62a0b48db353f40769d3c4baded8e87 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Mon, 14 Sep 2015 16:56:20 -0400 Subject: Properly hide unread channel indicators when there are no unread channels --- web/react/components/sidebar.jsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'web/react') diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index 697fc09c9..370250e4a 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -274,26 +274,32 @@ export default class Sidebar extends React.Component { this.updateUnreadIndicators(); } updateUnreadIndicators() { - var container = $(React.findDOMNode(this.refs.container)); + 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) { - $(React.findDOMNode(this.refs.topUnreadIndicator)).css('display', 'initial'); + topUnreadIndicator.css('display', 'initial'); } else { - $(React.findDOMNode(this.refs.topUnreadIndicator)).css('display', 'none'); + 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()) { - $(React.findDOMNode(this.refs.bottomUnreadIndicator)).css('display', 'initial'); + bottomUnreadIndicator.css('display', 'initial'); } else { - $(React.findDOMNode(this.refs.bottomUnreadIndicator)).css('display', 'none'); + bottomUnreadIndicator.css('display', 'none'); } + } else { + bottomUnreadIndicator.css('display', 'none'); } } createChannelElement(channel, index) { -- cgit v1.2.3-1-g7c22 From 7e66a3d5be9a928b39c22756a5d83703b99648c4 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Tue, 15 Sep 2015 17:36:48 -0400 Subject: Moved unread channel indicators into their own React component and file --- web/react/components/sidebar.jsx | 89 +++++---------------- web/react/components/unread_channel_indicators.jsx | 93 ++++++++++++++++++++++ 2 files changed, 112 insertions(+), 70 deletions(-) create mode 100644 web/react/components/unread_channel_indicators.jsx (limited to 'web/react') 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 { /> -
- Unread post(s) above -
-
- Unread post(s) below -
+
- {channelItems} + {publicChannelItems}
  • 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 ( +
    +
    + {'Unread post(s) above'} +
    +
    + {'Unread post(s) below'} +
    +
    + ); + } +} + +UnreadChannelIndicators.propTypes = { + + // a list of the unread channels displayed in the parent + unreadChannels: React.PropTypes.array.isRequired +}; -- cgit v1.2.3-1-g7c22 From acf2fb64b49fea49774d31ab78b755fed43ae27f Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Wed, 16 Sep 2015 14:53:16 -0400 Subject: Cleaned up logic for the unread indicators --- web/react/components/sidebar.jsx | 80 +++++++++++++++---- web/react/components/unread_channel_indicator.jsx | 35 ++++++++ web/react/components/unread_channel_indicators.jsx | 93 ---------------------- 3 files changed, 100 insertions(+), 108 deletions(-) create mode 100644 web/react/components/unread_channel_indicator.jsx delete mode 100644 web/react/components/unread_channel_indicators.jsx (limited to 'web/react') diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index a16a0a8bb..87007edcc 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -11,19 +11,22 @@ 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'); +var UnreadChannelIndicator = require('./unread_channel_indicator.jsx'); export default class Sidebar extends React.Component { constructor(props) { 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(); @@ -147,13 +150,23 @@ export default class Sidebar extends React.Component { $('.nav-pills__container').perfectScrollbar(); this.updateTitle(); - this.refs.unreadIndicators.onParentUpdate(this.refs); + this.updateUnreadIndicators(); $(window).on('resize', this.onResize); } + shouldComponentUpdate(nextProps, nextState) { + if (!Utils.areStatesEqual(nextProps, this.props)) { + return true; + } + + if (!Utils.areStatesEqual(nextState, this.state)) { + return true; + } + return false; + } componentDidUpdate() { this.updateTitle(); - this.refs.unreadIndicators.onParentUpdate(this.refs); + this.updateUnreadIndicators(); } componentWillUnmount() { $(window).off('resize', this.onResize); @@ -266,12 +279,39 @@ export default class Sidebar extends React.Component { } } onScroll() { - this.refs.unreadIndicators.onParentUpdate(this.refs); + this.updateUnreadIndicators(); } onResize() { - this.refs.unreadIndicators.onParentUpdate(this.refs); + this.updateUnreadIndicators(); } - createChannelElement(unreadChannels, channel, index) { + updateUnreadIndicators() { + const container = $(React.findDOMNode(this.refs.container)); + + var showTopUnread = false; + var showBottomUnread = false; + + if (this.firstUnreadChannel) { + var firstUnreadElement = $(React.findDOMNode(this.refs[this.firstUnreadChannel])); + + if (firstUnreadElement.position().top + firstUnreadElement.height() < 0) { + showTopUnread = true; + } + } + + if (this.lastUnreadChannel) { + var lastUnreadElement = $(React.findDOMNode(this.refs[this.lastUnreadChannel])); + + if (lastUnreadElement.position().top > container.height()) { + showBottomUnread = true; + } + } + + this.setState({ + showTopUnread, + showBottomUnread + }); + } + createChannelElement(channel, index) { var members = this.state.members; var activeId = this.state.activeId; var channelMember = members[channel.id]; @@ -293,7 +333,10 @@ export default class Sidebar extends React.Component { titleClass = 'unread-title'; if (channel.id !== activeId) { - unreadChannels.push(channel); + if (!this.firstUnreadChannel) { + this.firstUnreadChannel = channel.name; + } + this.lastUnreadChannel = channel.name; } } @@ -399,17 +442,18 @@ export default class Sidebar extends React.Component { render() { this.badgesActive = false; - // keep track of unread channels so we can use them to set the unread indicators - const unreadChannels = []; + // 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; // create elements for all 3 types of channels const publicChannels = this.state.channels.filter((channel) => channel.type === 'O'); - const publicChannelItems = publicChannels.map(this.createChannelElement.bind(this, unreadChannels)); + const publicChannelItems = publicChannels.map(this.createChannelElement); const privateChannels = this.state.channels.filter((channel) => channel.type === 'P'); - const privateChannelItems = privateChannels.map(this.createChannelElement.bind(this, unreadChannels)); + const privateChannelItems = privateChannels.map(this.createChannelElement); - const directMessageItems = this.state.showDirectChannels.map(this.createChannelElement.bind(this, unreadChannels)); + const directMessageItems = this.state.showDirectChannels.map(this.createChannelElement); // update the favicon to show if there are any notifications var link = document.createElement('link'); @@ -463,9 +507,15 @@ export default class Sidebar extends React.Component { /> - +
    + {this.props.text} +
    + ); + } +} + +UnreadChannelIndicator.defaultProps = { + show: false, + extraClass: '', + text: '' +}; +UnreadChannelIndicator.propTypes = { + show: React.PropTypes.bool, + extraClass: React.PropTypes.string, + text: React.PropTypes.string +}; diff --git a/web/react/components/unread_channel_indicators.jsx b/web/react/components/unread_channel_indicators.jsx deleted file mode 100644 index 852e0dbb7..000000000 --- a/web/react/components/unread_channel_indicators.jsx +++ /dev/null @@ -1,93 +0,0 @@ -// 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 ( -
    -
    - {'Unread post(s) above'} -
    -
    - {'Unread post(s) below'} -
    -
    - ); - } -} - -UnreadChannelIndicators.propTypes = { - - // a list of the unread channels displayed in the parent - unreadChannels: React.PropTypes.array.isRequired -}; -- cgit v1.2.3-1-g7c22 From 8e848f38d5019269b75ff9814fc0e0772410a7b4 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Wed, 16 Sep 2015 23:22:15 -0700 Subject: PLT-40 adding experimental support for emojis --- web/react/components/post_body.jsx | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'web/react') diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx index df4ed3d57..5e460d686 100644 --- a/web/react/components/post_body.jsx +++ b/web/react/components/post_body.jsx @@ -17,19 +17,42 @@ export default class PostBody extends React.Component { const linkData = Utils.extractLinks(this.props.post.message); this.state = {links: linkData.links, message: linkData.text}; } + + getTextNodesIn(nodeIn) { + var textNodes = []; + + function getTextNodes(node) { + textNodes.push(node); + + for (var i = 0, len = node.childNodes.length; i < len; ++i) { + getTextNodes(node.childNodes[i]); + } + } + + getTextNodes(nodeIn); + return textNodes; + } + parseEmojis() { twemoji.parse(React.findDOMNode(this), {size: Constants.EMOJI_SIZE}); + this.getTextNodesIn(React.findDOMNode(this)).forEach((current) => { + global.window.emojify.run(current); + }); } + componentDidMount() { this.parseEmojis(); } + componentDidUpdate() { this.parseEmojis(); } + componentWillReceiveProps(nextProps) { const linkData = Utils.extractLinks(nextProps.post.message); this.setState({links: linkData.links, message: linkData.text}); } + render() { const post = this.props.post; const filenames = this.props.post.filenames; @@ -75,7 +98,7 @@ export default class PostBody extends React.Component { comment = (

    - Commented on {name}{apostrophe} message: + {'Commented on '}{name}{apostrophe}{' message:'} - Retry + {'Retry'} ); } else if (post.state === Constants.POST_LOADING) { @@ -133,6 +156,7 @@ export default class PostBody extends React.Component { {comment}

    {loading} -- cgit v1.2.3-1-g7c22 From 99d0db136cfaa88cf654c77e30fd1867136db9d5 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Wed, 16 Sep 2015 23:27:25 -0700 Subject: Fixing css --- web/react/components/post_body.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'web/react') diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx index 5e460d686..3be615bb9 100644 --- a/web/react/components/post_body.jsx +++ b/web/react/components/post_body.jsx @@ -18,7 +18,7 @@ export default class PostBody extends React.Component { this.state = {links: linkData.links, message: linkData.text}; } - getTextNodesIn(nodeIn) { + getAllChildNodes(nodeIn) { var textNodes = []; function getTextNodes(node) { @@ -35,7 +35,7 @@ export default class PostBody extends React.Component { parseEmojis() { twemoji.parse(React.findDOMNode(this), {size: Constants.EMOJI_SIZE}); - this.getTextNodesIn(React.findDOMNode(this)).forEach((current) => { + this.getAllChildNodes(React.findDOMNode(this)).forEach((current) => { global.window.emojify.run(current); }); } -- cgit v1.2.3-1-g7c22 From ce19b3c21197b57267804790c749769d2ddd1035 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Thu, 17 Sep 2015 07:46:38 -0400 Subject: Properly check if OAuth providing is enabled on the client. --- web/react/components/user_settings_modal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'web/react') diff --git a/web/react/components/user_settings_modal.jsx b/web/react/components/user_settings_modal.jsx index 1daf6ebb9..67a4d0041 100644 --- a/web/react/components/user_settings_modal.jsx +++ b/web/react/components/user_settings_modal.jsx @@ -35,7 +35,7 @@ export default class UserSettingsModal extends React.Component { tabs.push({name: 'security', uiName: 'Security', icon: 'glyphicon glyphicon-lock'}); tabs.push({name: 'notifications', uiName: 'Notifications', icon: 'glyphicon glyphicon-exclamation-sign'}); tabs.push({name: 'appearance', uiName: 'Appearance', icon: 'glyphicon glyphicon-wrench'}); - if (global.window.config.EnableOAuthServiceProvider) { + if (global.window.config.EnableOAuthServiceProvider === 'true') { tabs.push({name: 'developer', uiName: 'Developer', icon: 'glyphicon glyphicon-th'}); } -- cgit v1.2.3-1-g7c22