diff options
Diffstat (limited to 'web/react')
-rw-r--r-- | web/react/components/channel_notifications.jsx | 8 | ||||
-rw-r--r-- | web/react/components/create_post.jsx | 8 | ||||
-rw-r--r-- | web/react/components/post_body.jsx | 12 | ||||
-rw-r--r-- | web/react/components/rhs_comment.jsx | 11 | ||||
-rw-r--r-- | web/react/components/rhs_root_post.jsx | 14 | ||||
-rw-r--r-- | web/react/components/rhs_thread.jsx | 11 | ||||
-rw-r--r-- | web/react/components/setting_item_max.jsx | 2 | ||||
-rw-r--r-- | web/react/components/textbox.jsx | 9 | ||||
-rw-r--r-- | web/react/components/user_settings_notifications.jsx | 14 | ||||
-rw-r--r-- | web/react/package.json | 3 | ||||
-rw-r--r-- | web/react/utils/constants.jsx | 1 |
11 files changed, 59 insertions, 34 deletions
diff --git a/web/react/components/channel_notifications.jsx b/web/react/components/channel_notifications.jsx index 173646597..83067240d 100644 --- a/web/react/components/channel_notifications.jsx +++ b/web/react/components/channel_notifications.jsx @@ -162,6 +162,13 @@ export default class ChannelNotifications extends React.Component { e.preventDefault(); }.bind(this); + let curChannel = ChannelStore.get(this.state.channelId); + let extraInfo = (<span>These settings will override the global notification settings</span>); + + if (curChannel && curChannel.display_name) { + extraInfo = (<span>These settings will override the global notification settings for the <b>{curChannel.display_name}</b> channel</span>); + } + return ( <SettingItemMax title='Send desktop notifications' @@ -169,6 +176,7 @@ export default class ChannelNotifications extends React.Component { submit={this.handleUpdate} server_error={serverError} updateSection={handleUpdateSection} + extraInfo={extraInfo} /> ); } diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index 3d94e8933..871b72a43 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -117,7 +117,6 @@ export default class CreatePost extends React.Component { Client.createPost(post, channel, function handlePostSuccess(data) { - this.resizePostHolder(); AsyncClient.getPosts(); let member = ChannelStore.getMember(channel.id); @@ -129,7 +128,7 @@ export default class CreatePost extends React.Component { type: ActionTypes.RECIEVED_POST, post: data }); - }.bind(this), + }, function handlePostError(err) { let state = {}; @@ -149,9 +148,6 @@ export default class CreatePost extends React.Component { ); } } - componentDidUpdate() { - this.resizePostHolder(); - } postMsgKeyPress(e) { if (e.which === 13 && !e.shiftKey && !e.altKey) { e.preventDefault(); @@ -166,7 +162,6 @@ export default class CreatePost extends React.Component { } } handleUserInput(messageText) { - this.resizePostHolder(); this.setState({messageText: messageText}); let draft = PostStore.getCurrentDraft(); @@ -318,6 +313,7 @@ export default class CreatePost extends React.Component { <Textbox onUserInput={this.handleUserInput} onKeyPress={this.postMsgKeyPress} + onHeightChange={this.resizePostHolder} messageText={this.state.messageText} createMessage='Write a message...' channelId={this.state.channelId} diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx index 88fb9aec8..d9b8f20ce 100644 --- a/web/react/components/post_body.jsx +++ b/web/react/components/post_body.jsx @@ -5,14 +5,26 @@ const FileAttachmentList = require('./file_attachment_list.jsx'); const UserStore = require('../stores/user_store.jsx'); const Utils = require('../utils/utils.jsx'); const Constants = require('../utils/constants.jsx'); +const twemoji = require('twemoji'); export default class PostBody extends React.Component { constructor(props) { super(props); + this.parseEmojis = this.parseEmojis.bind(this); + const linkData = Utils.extractLinks(this.props.post.message); this.state = {links: linkData.links, message: linkData.text}; } + parseEmojis() { + twemoji.parse(React.findDOMNode(this), {size: Constants.EMOJI_SIZE}); + } + componentDidMount() { + this.parseEmojis(); + } + componentDidUpdate() { + this.parseEmojis(); + } componentWillReceiveProps(nextProps) { const linkData = Utils.extractLinks(nextProps.post.message); this.setState({links: linkData.links, message: linkData.text}); diff --git a/web/react/components/rhs_comment.jsx b/web/react/components/rhs_comment.jsx index 3e2cf04c8..f1a90102c 100644 --- a/web/react/components/rhs_comment.jsx +++ b/web/react/components/rhs_comment.jsx @@ -12,12 +12,14 @@ var FileAttachmentList = require('./file_attachment_list.jsx'); var Client = require('../utils/client.jsx'); var AsyncClient = require('../utils/async_client.jsx'); var ActionTypes = Constants.ActionTypes; +var twemoji = require('twemoji'); export default class RhsComment extends React.Component { constructor(props) { super(props); this.retryComment = this.retryComment.bind(this); + this.parseEmojis = this.parseEmojis.bind(this); this.state = {}; } @@ -51,6 +53,12 @@ export default class RhsComment extends React.Component { PostStore.updatePendingPost(post); this.forceUpdate(); } + parseEmojis() { + twemoji.parse(React.findDOMNode(this), {size: Constants.EMOJI_SIZE}); + } + componentDidMount() { + this.parseEmojis(); + } shouldComponentUpdate(nextProps) { if (!Utils.areStatesEqual(nextProps.post, this.props.post)) { return true; @@ -58,6 +66,9 @@ export default class RhsComment extends React.Component { return false; } + componentDidUpdate() { + this.parseEmojis(); + } render() { var post = this.props.post; diff --git a/web/react/components/rhs_root_post.jsx b/web/react/components/rhs_root_post.jsx index 5aed5e1b5..83b57b955 100644 --- a/web/react/components/rhs_root_post.jsx +++ b/web/react/components/rhs_root_post.jsx @@ -6,12 +6,23 @@ var UserProfile = require('./user_profile.jsx'); var UserStore = require('../stores/user_store.jsx'); var utils = require('../utils/utils.jsx'); var FileAttachmentList = require('./file_attachment_list.jsx'); +var twemoji = require('twemoji'); +var Constants = require('../utils/constants.jsx'); export default class RhsRootPost extends React.Component { constructor(props) { super(props); + + this.parseEmojis = this.parseEmojis.bind(this); + this.state = {}; } + parseEmojis() { + twemoji.parse(React.findDOMNode(this), {size: Constants.EMOJI_SIZE}); + } + componentDidMount() { + this.parseEmojis(); + } shouldComponentUpdate(nextProps) { if (!utils.areStatesEqual(nextProps.post, this.props.post)) { return true; @@ -19,6 +30,9 @@ export default class RhsRootPost extends React.Component { return false; } + componentDidUpdate() { + this.parseEmojis(); + } render() { var post = this.props.post; var message = utils.textToJsx(post.message); diff --git a/web/react/components/rhs_thread.jsx b/web/react/components/rhs_thread.jsx index 88e462c92..2f23d80d9 100644 --- a/web/react/components/rhs_thread.jsx +++ b/web/react/components/rhs_thread.jsx @@ -18,7 +18,6 @@ export default class RhsThread extends React.Component { this.onChange = this.onChange.bind(this); this.onChangeAll = this.onChangeAll.bind(this); - this.onTimeChange = this.onTimeChange.bind(this); this.state = this.getStateFromStores(); } @@ -44,7 +43,6 @@ export default class RhsThread extends React.Component { componentDidMount() { PostStore.addSelectedPostChangeListener(this.onChange); PostStore.addChangeListener(this.onChangeAll); - UserStore.addStatusesChangeListener(this.onTimeChange); this.resize(); $(window).resize(function resize() { this.resize(); @@ -58,7 +56,6 @@ export default class RhsThread extends React.Component { componentWillUnmount() { PostStore.removeSelectedPostChangeListener(this.onChange); PostStore.removeChangeListener(this.onChangeAll); - UserStore.removeStatusesChangeListener(this.onTimeChange); } onChange() { var newState = this.getStateFromStores(); @@ -96,14 +93,6 @@ export default class RhsThread extends React.Component { this.setState(newState); } } - onTimeChange() { - for (var id in this.state.postList.posts) { - if (!this.refs[id]) { - continue; - } - this.refs[id].forceUpdate(); - } - } resize() { var height = $(window).height() - $('#error_bar').outerHeight() - 100; $('.post-right__scroll').css('height', height + 'px'); diff --git a/web/react/components/setting_item_max.jsx b/web/react/components/setting_item_max.jsx index 48c5f160d..b1bab1d48 100644 --- a/web/react/components/setting_item_max.jsx +++ b/web/react/components/setting_item_max.jsx @@ -15,7 +15,7 @@ export default class SettingItemMax extends React.Component { var extraInfo = null; if (this.props.extraInfo) { - extraInfo = this.props.extraInfo; + extraInfo = (<div className='setting-list__hint'>{this.props.extraInfo}</div>); } var submit = ''; diff --git a/web/react/components/textbox.jsx b/web/react/components/textbox.jsx index 0408a262d..b4518fe80 100644 --- a/web/react/components/textbox.jsx +++ b/web/react/components/textbox.jsx @@ -121,7 +121,6 @@ export default class Textbox extends React.Component { } this.addedMention = false; this.refs.commands.getSuggestedCommands(nextProps.messageText); - this.resize(); } updateMentionTab(mentionText) { // using setTimeout so dispatch isn't called during an in progress dispatch @@ -135,7 +134,6 @@ export default class Textbox extends React.Component { } handleChange() { this.props.onUserInput(React.findDOMNode(this.refs.message).value); - this.resize(); } handleKeyPress(e) { const text = React.findDOMNode(this.refs.message).value; @@ -244,6 +242,8 @@ export default class Textbox extends React.Component { const e = React.findDOMNode(this.refs.message); const w = React.findDOMNode(this.refs.wrapper); + let prevHeight = $(e).height(); + const lht = parseInt($(e).css('lineHeight'), 10); const lines = e.scrollHeight / lht; let mod = 15; @@ -259,6 +259,10 @@ export default class Textbox extends React.Component { $(e).css({height: 'auto', 'overflow-y': 'scroll'}).height(167); $(w).css({height: 'auto'}).height(167); } + + if (prevHeight !== $(e).height()) { + this.props.onHeightChange(); + } } handleFocus() { const elm = React.findDOMNode(this.refs.message); @@ -316,5 +320,6 @@ Textbox.propTypes = { messageText: React.PropTypes.string.isRequired, onUserInput: React.PropTypes.func.isRequired, onKeyPress: React.PropTypes.func.isRequired, + onHeightChange: React.PropTypes.func.isRequired, createMessage: React.PropTypes.string.isRequired }; diff --git a/web/react/components/user_settings_notifications.jsx b/web/react/components/user_settings_notifications.jsx index 5fe6bbb4e..33db1a332 100644 --- a/web/react/components/user_settings_notifications.jsx +++ b/web/react/components/user_settings_notifications.jsx @@ -1,7 +1,6 @@ // 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 SettingItemMin = require('./setting_item_min.jsx'); var SettingItemMax = require('./setting_item_max.jsx'); @@ -69,11 +68,9 @@ function getNotificationsStateFromStores() { } } - var curChannel = ChannelStore.getCurrent().display_name; - return {notifyLevel: desktop, enableEmail: email, soundNeeded: soundNeeded, enableSound: sound, usernameKey: usernameKey, mentionKey: mentionKey, customKeys: customKeys, customKeysChecked: customKeys.length > 0, - firstNameKey: firstNameKey, allKey: allKey, channelKey: channelKey, curChannel: curChannel}; + firstNameKey: firstNameKey, allKey: allKey, channelKey: channelKey}; } export default class NotificationsTab extends React.Component { @@ -147,12 +144,10 @@ export default class NotificationsTab extends React.Component { } componentDidMount() { UserStore.addChangeListener(this.onListenerChange); - ChannelStore.addChangeListener(this.onListenerChange); $('#user_settings').on('hidden.bs.modal', this.handleClose); } componentWillUnmount() { UserStore.removeChangeListener(this.onListenerChange); - ChannelStore.removeChangeListener(this.onListenerChange); $('#user_settings').off('hidden.bs.modal', this.handleClose); this.props.updateSection(''); } @@ -271,12 +266,6 @@ export default class NotificationsTab extends React.Component { e.preventDefault(); }.bind(this); - let extraInfo = ( - <div className='setting-list__hint'> - These settings will override the global notification settings for the <b>{this.state.curChannel}</b> channel - </div> - ); - desktopSection = ( <SettingItemMax title='Send desktop notifications' @@ -284,7 +273,6 @@ export default class NotificationsTab extends React.Component { submit={this.handleSubmit} server_error={serverError} updateSection={handleUpdateDesktopSection} - extraInfo={extraInfo} /> ); } else { diff --git a/web/react/package.json b/web/react/package.json index 86563136f..da55dc2b8 100644 --- a/web/react/package.json +++ b/web/react/package.json @@ -8,7 +8,8 @@ "keymirror": "^0.1.1", "object-assign": "^3.0.0", "react": "^0.13.3", - "react-zeroclipboard-mixin": "^0.1.0" + "react-zeroclipboard-mixin": "^0.1.0", + "twemoji": "^1.4.1" }, "devDependencies": { "browserify": "^11.0.1", diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index 3a6ca1b89..18b7ff59c 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -103,6 +103,7 @@ module.exports = { MONTHS: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], MAX_DMS: 20, MAX_POST_LEN: 4000, + EMOJI_SIZE: 16, ONLINE_ICON_SVG: "<svg version='1.1' id='Layer_1' xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:cc='http://creativecommons.org/ns#' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:svg='http://www.w3.org/2000/svg' xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' sodipodi:docname='TRASH_1_4.svg' inkscape:version='0.48.4 r9939' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='12px' height='12px' viewBox='0 0 12 12' enable-background='new 0 0 12 12' xml:space='preserve'><sodipodi:namedview inkscape:cy='139.7898' inkscape:cx='26.358185' inkscape:zoom='1.18' showguides='true' showgrid='false' id='namedview6' guidetolerance='10' gridtolerance='10' objecttolerance='10' borderopacity='1' bordercolor='#666666' pagecolor='#ffffff' inkscape:current-layer='Layer_1' inkscape:window-maximized='1' inkscape:window-y='-8' inkscape:window-x='-8' inkscape:window-height='705' inkscape:window-width='1366' inkscape:guide-bbox='true' inkscape:pageshadow='2' inkscape:pageopacity='0'><sodipodi:guide position='50.036793,85.991376' orientation='1,0' id='guide2986'></sodipodi:guide><sodipodi:guide position='58.426196,66.216355' orientation='0,1' id='guide3047'></sodipodi:guide></sodipodi:namedview><g><g><path class='online--icon' d='M6,5.487c1.371,0,2.482-1.116,2.482-2.493c0-1.378-1.111-2.495-2.482-2.495S3.518,1.616,3.518,2.994C3.518,4.371,4.629,5.487,6,5.487z M10.452,8.545c-0.101-0.829-0.36-1.968-0.726-2.541C9.475,5.606,8.5,5.5,8.5,5.5S8.43,7.521,6,7.521C3.507,7.521,3.5,5.5,3.5,5.5S2.527,5.606,2.273,6.004C1.908,6.577,1.648,7.716,1.547,8.545C1.521,8.688,1.49,9.082,1.498,9.142c0.161,1.295,2.238,2.322,4.375,2.358C5.916,11.501,5.958,11.501,6,11.501c0.043,0,0.084,0,0.127-0.001c2.076-0.026,4.214-1.063,4.375-2.358C10.509,9.082,10.471,8.696,10.452,8.545z'/></g></g></svg>", OFFLINE_ICON_SVG: "<svg version='1.1' id='Layer_1' xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:cc='http://creativecommons.org/ns#' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:svg='http://www.w3.org/2000/svg' xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' sodipodi:docname='TRASH_1_4.svg' inkscape:version='0.48.4 r9939' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='12px' height='12px' viewBox='0 0 12 12' enable-background='new 0 0 12 12' xml:space='preserve'><sodipodi:namedview inkscape:cy='139.7898' inkscape:cx='26.358185' inkscape:zoom='1.18' showguides='true' showgrid='false' id='namedview6' guidetolerance='10' gridtolerance='10' objecttolerance='10' borderopacity='1' bordercolor='#666666' pagecolor='#ffffff' inkscape:current-layer='Layer_1' inkscape:window-maximized='1' inkscape:window-y='-8' inkscape:window-x='-8' inkscape:window-height='705' inkscape:window-width='1366' inkscape:guide-bbox='true' inkscape:pageshadow='2' inkscape:pageopacity='0'><sodipodi:guide position='50.036793,85.991376' orientation='1,0' id='guide2986'></sodipodi:guide><sodipodi:guide position='58.426196,66.216355' orientation='0,1' id='guide3047'></sodipodi:guide></sodipodi:namedview><g><g><path fill='#cccccc' d='M6.002,7.143C5.645,7.363,5.167,7.52,4.502,7.52c-2.493,0-2.5-2.02-2.5-2.02S1.029,5.607,0.775,6.004C0.41,6.577,0.15,7.716,0.049,8.545c-0.025,0.145-0.057,0.537-0.05,0.598c0.162,1.295,2.237,2.321,4.375,2.357c0.043,0.001,0.085,0.001,0.127,0.001c0.043,0,0.084,0,0.127-0.001c1.879-0.023,3.793-0.879,4.263-2h-2.89L6.002,7.143L6.002,7.143z M4.501,5.488c1.372,0,2.483-1.117,2.483-2.494c0-1.378-1.111-2.495-2.483-2.495c-1.371,0-2.481,1.117-2.481,2.495C2.02,4.371,3.13,5.488,4.501,5.488z M7.002,6.5v2h5v-2H7.002z'/></g></g></svg>", MENU_ICON: "<svg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px'width='4px' height='16px' viewBox='0 0 8 32' enable-background='new 0 0 8 32' xml:space='preserve'> <g> <circle cx='4' cy='4.062' r='4'/> <circle cx='4' cy='16' r='4'/> <circle cx='4' cy='28' r='4'/> </g> </svg>", |